diff options
| author | Vojtech Pavlik <vojtech@suse.cz> | 2002-11-11 11:29:50 +0100 |
|---|---|---|
| committer | Vojtech Pavlik <vojtech@suse.cz> | 2002-11-11 11:29:50 +0100 |
| commit | cdd78a965de150f55dc6bc2836995e5f8bc991a9 (patch) | |
| tree | 9bb3263b0110d8606c393810bf52e7911e59d3df | |
| parent | 20889760dda09fd104cfe859b03b3f63300faa83 (diff) | |
| parent | 5be2bc3c89f6813ab0ab21cdd27d6d0f2ee94d91 (diff) | |
Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input
61 files changed, 2275 insertions, 999 deletions
@@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 46 +SUBLEVEL = 47 EXTRAVERSION = # *DOCUMENTATION* diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 0705e47afa57..4f248bfb6a76 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -12,21 +12,22 @@ #include <linux/pagemap.h> #include <linux/smp_lock.h> #include <linux/slab.h> - +#include <linux/module.h> #include <asm/mman.h> #include <asm/pgalloc.h> #include <asm/tlb.h> #include <asm/tlbflush.h> -struct vm_operations_struct hugetlb_vm_ops; -struct list_head htlbpage_freelist; -spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; -extern long htlbpagemem; +static long htlbpagemem; +int htlbpage_max; +static long htlbzone_pages; -void zap_hugetlb_resources(struct vm_area_struct *); +struct vm_operations_struct hugetlb_vm_ops; +static LIST_HEAD(htlbpage_freelist); +static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; #define MAX_ID 32 -struct htlbpagekey { +static struct htlbpagekey { struct inode *in; int key; } htlbpagek[MAX_ID]; @@ -108,7 +109,7 @@ static int anon_get_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vm return page ? 1 : -1; } -int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) +static int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) { int write; struct mm_struct *mm = current->mm; @@ -143,7 +144,7 @@ int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) out_error: /* Error case, remove the partial lp_resources. */ if (addr > vma->vm_start) { vma->vm_end = addr; - zap_hugetlb_resources(vma); + zap_hugepage_range(vma, vma->vm_start, vma->vm_end - vma->vm_start); vma->vm_end = end; } spin_unlock(&mm->page_table_lock); @@ -296,30 +297,6 @@ void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigne spin_unlock(&mm->page_table_lock); } -void zap_hugetlb_resources(struct vm_area_struct *vma) -{ - zap_hugepage_range(vma, vma->vm_start, vma->vm_end); -} - -static void unlink_vma(struct vm_area_struct *mpnt) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - vma = mm->mmap; - if (vma == mpnt) { - mm->mmap = vma->vm_next; - } else { - while (vma->vm_next != mpnt) { - vma = vma->vm_next; - } - vma->vm_next = mpnt->vm_next; - } - rb_erase(&mpnt->vm_rb, &mm->mm_rb); - mm->mmap_cache = NULL; - mm->map_count--; -} - static struct inode *set_new_inode(unsigned long len, int prot, int flag, int key) { struct inode *inode; @@ -430,7 +407,7 @@ out: unsigned long raddr; raddr = vma->vm_end; vma->vm_end = addr; - zap_hugetlb_resources(vma); + zap_hugepage_range(vma, vma->vm_start, vma->vm_end - vma->vm_start); vma->vm_end = raddr; } spin_unlock(&mm->page_table_lock); @@ -569,6 +546,53 @@ int set_hugetlb_mem_size(int count) return (int) htlbzone_pages; } +int hugetlb_sysctl_handler(ctl_table *table, int write, struct file *file, void *buffer, size_t *length) +{ + proc_dointvec(table, write, file, buffer, length); + htlbpage_max = set_hugetlb_mem_size(htlbpage_max); + return 0; +} + +static int __init hugetlb_setup(char *s) +{ + if (sscanf(s, "%d", &htlbpage_max) <= 0) + htlbpage_max = 0; + return 1; +} +__setup("hugepages=", hugetlb_setup); + +static int __init hugetlb_init(void) +{ + int i, j; + struct page *page; + + for (i = 0; i < htlbpage_max; ++i) { + page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); + if (!page) + break; + for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j) + SetPageReserved(&page[j]); + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + spin_unlock(&htlbpage_lock); + } + htlbpage_max = htlbpagemem = htlbzone_pages = i; + printk("Total HugeTLB memory allocated, %ld\n", htlbpagemem); + return 0; +} +module_init(hugetlb_init); + +int hugetlb_report_meminfo(char *buf) +{ + return sprintf(buf, + "HugePages_Total: %5lu\n" + "HugePages_Free: %5lu\n" + "Hugepagesize: %5lu kB\n", + htlbzone_pages, + htlbpagemem, + HPAGE_SIZE/1024); +} + static struct page * hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int unused) { BUG(); diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 01f3fa7b856c..fe912c8b6b74 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -422,13 +422,6 @@ static void __init set_max_mapnr_init(void) extern void set_max_mapnr_init(void); #endif /* !CONFIG_DISCONTIGMEM */ -#ifdef CONFIG_HUGETLB_PAGE -long htlbpagemem = 0; -int htlbpage_max; -long htlbzone_pages; -extern struct list_head htlbpage_freelist; -#endif - void __init mem_init(void) { extern int ppro_with_ram_bug(void); @@ -497,30 +490,6 @@ void __init mem_init(void) #ifndef CONFIG_SMP zap_low_mappings(); #endif -#ifdef CONFIG_HUGETLB_PAGE - { - long i, j; - struct page *page, *map; - /*For now reserve quarter for hugetlb_pages.*/ - htlbzone_pages = (max_low_pfn >> ((HPAGE_SHIFT - PAGE_SHIFT) + 2)) ; - /*Will make this kernel command line. */ - INIT_LIST_HEAD(&htlbpage_freelist); - for (i=0; i<htlbzone_pages; i++) { - page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); - if (page == NULL) - break; - map = page; - for (j=0; j<(HPAGE_SIZE/PAGE_SIZE); j++) { - SetPageReserved(map); - map++; - } - list_add(&page->list, &htlbpage_freelist); - } - printk("Total Huge_TLB_Page memory pages allocated %ld\n", i); - htlbzone_pages = htlbpagemem = i; - htlbpage_max = i; - } -#endif } #if CONFIG_X86_PAE diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index c9d6d5b2b839..5bba83e69485 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -324,9 +324,16 @@ static ssize_t disk_size_read(struct gendisk * disk, { return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk)); } -static inline unsigned MSEC(unsigned x) + +static inline unsigned jiffies_to_msec(unsigned jif) { - return x * 1000 / HZ; +#if 1000 % HZ == 0 + return jif * (1000 / HZ); +#elif HZ % 1000 == 0 + return jif / (HZ / 1000); +#else + return (jif / HZ) * 1000 + (jif % HZ) * 1000 / HZ; +#endif } static ssize_t disk_stat_read(struct gendisk * disk, char *page, size_t count, loff_t off) @@ -338,11 +345,11 @@ static ssize_t disk_stat_read(struct gendisk * disk, "%8u %8u %8u" "\n", disk->reads, disk->read_merges, (u64)disk->read_sectors, - MSEC(disk->read_ticks), + jiffies_to_msec(disk->read_ticks), disk->writes, disk->write_merges, (u64)disk->write_sectors, - MSEC(disk->write_ticks), - disk->in_flight, MSEC(disk->io_ticks), - MSEC(disk->time_in_queue)); + jiffies_to_msec(disk->write_ticks), + disk->in_flight, jiffies_to_msec(disk->io_ticks), + jiffies_to_msec(disk->time_in_queue)); } static struct disk_attribute disk_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index bc7404143240..7698b794961d 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -28,11 +28,6 @@ #include <linux/slab.h> /* - * Disk stats - */ -struct disk_stat dkstat; - -/* * For the allocated request tables */ static kmem_cache_t *request_cachep; @@ -56,7 +51,6 @@ static int queue_nr_requests; static int batch_requests; unsigned long blk_max_low_pfn, blk_max_pfn; -atomic_t nr_iowait_tasks = ATOMIC_INIT(0); int blk_nohighio = 0; static struct congestion_state { @@ -115,27 +109,6 @@ static void set_queue_congested(request_queue_t *q, int rw) atomic_inc(&congestion_states[rw].nr_congested_queues); } -/* - * This task is about to go to sleep on IO. Increment nr_iowait_tasks so - * that process accounting knows that this is a task in IO wait state. - * - * But don't do that if it is a deliberate, throttling IO wait (this task - * has set its backing_dev_info: the queue against which it should throttle) - */ -void io_schedule(void) -{ - atomic_inc(&nr_iowait_tasks); - schedule(); - atomic_dec(&nr_iowait_tasks); -} - -void io_schedule_timeout(long timeout) -{ - atomic_inc(&nr_iowait_tasks); - schedule_timeout(timeout); - atomic_dec(&nr_iowait_tasks); -} - /** * blk_get_backing_dev_info - get the address of a queue's backing_dev_info * @dev: device @@ -1434,19 +1407,6 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) major = rq->rq_disk->major; index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift; - - if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - return; - - dkstat.drive[major][index] += new_io; - if (rw == READ) { - dkstat.drive_rio[major][index] += new_io; - dkstat.drive_rblk[major][index] += nr_sectors; - } else if (rw == WRITE) { - dkstat.drive_wio[major][index] += new_io; - dkstat.drive_wblk[major][index] += nr_sectors; - } else - printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); } /* diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 974cf6e876b7..8f8312227910 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1804,10 +1804,10 @@ static void vortex_tx_timeout(struct net_device *dev) inw(ioaddr + EL3_STATUS)); EL3WINDOW(4); printk(KERN_ERR " diagnostics: net %04x media %04x dma %08x fifo %04x\n", - (unsigned)inw(ioaddr + Wn4_NetDiag), - (unsigned)inw(ioaddr + Wn4_Media), - (unsigned)inl(ioaddr + PktStatus), - (unsigned)inw(ioaddr + Wn4_FIFODiag)); + inw(ioaddr + Wn4_NetDiag), + inw(ioaddr + Wn4_Media), + inl(ioaddr + PktStatus), + inw(ioaddr + Wn4_FIFODiag)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" @@ -2644,7 +2644,7 @@ dump_tx_ring(struct net_device *dev) vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", - (unsigned)inl(ioaddr + DownListPtr), + inl(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); issue_and_wait(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index d57179c44908..3e2e0afd6e3a 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -404,6 +404,14 @@ static void led_get_diskio_stats(int addvalue) int major, disk, total; total = 0; +#ifdef 0 + /* + * this section will no longer work in 2.5, as we no longer + * have either kstat.dk_drive nor DK_MAX_*. It can probably + * be rewritten to use the per-disk statistics now kept in the + * gendisk, but since I have no HP machines to test it on, I'm + * not really up to that. ricklind@us.ibm.com 11/7/02 + */ for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) total += dkstat.drive[major][disk]; @@ -417,6 +425,7 @@ static void led_get_diskio_stats(int addvalue) } else led_diskio_counter += CALC_ADD(total, diskio_max, addvalue); } +#endif diskio_total_last += total; } diff --git a/fs/buffer.c b/fs/buffer.c index 3c5a0d5d7080..a97e0dfe5f5d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -367,7 +367,7 @@ out: * succeeds, there is no need to take private_lock. (But if * private_lock is contended then so is mapping->page_lock). */ -struct buffer_head * +static struct buffer_head * __find_get_block_slow(struct block_device *bdev, sector_t block, int unused) { struct inode *bd_inode = bdev->bd_inode; @@ -1077,18 +1077,6 @@ grow_buffers(struct block_device *bdev, unsigned long block, int size) return 1; } -/* - * __getblk will locate (and, if necessary, create) the buffer_head - * which corresponds to the passed block_device, block and size. The - * returned buffer has its reference count incremented. - * - * __getblk() cannot fail - it just keeps trying. If you pass it an - * illegal block number, __getblk() will happily return a buffer_head - * which represents the non-existent block. Very weird. - * - * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() - * attempt is failing. FIXME, perhaps? - */ struct buffer_head * __getblk_slow(struct block_device *bdev, sector_t block, int size) { @@ -1096,10 +1084,8 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) struct buffer_head * bh; bh = __find_get_block(bdev, block, size); - if (bh) { - touch_buffer(bh); + if (bh) return bh; - } if (!grow_buffers(bdev, block, size)) free_more_memory(); @@ -1182,21 +1168,8 @@ void __bforget(struct buffer_head *bh) __brelse(bh); } -/** - * __bread() - reads a specified block and returns the bh - * @block: number of block - * @size: size (in bytes) to read - * - * Reads a specified block, and returns buffer head that contains it. - * It returns NULL if the block was unreadable. - */ -struct buffer_head * -__bread_slow(struct block_device *bdev, sector_t block, int size) +static struct buffer_head *__bread_slow(struct buffer_head *bh) { - struct buffer_head *bh = __getblk(bdev, block, size); - - if (buffer_uptodate(bh)) - return bh; lock_buffer(bh); if (buffer_uptodate(bh)) { unlock_buffer(bh); @@ -1260,9 +1233,6 @@ static void bh_lru_install(struct buffer_head *bh) struct buffer_head *evictee = NULL; struct bh_lru *lru; - if (bh == NULL) - return; - check_irqs_on(); bh_lru_lock(); lru = &per_cpu(bh_lrus, smp_processor_id()); @@ -1293,14 +1263,15 @@ static void bh_lru_install(struct buffer_head *bh) } bh_lru_unlock(); - if (evictee) { - touch_buffer(evictee); + if (evictee) __brelse(evictee); - } } +/* + * Look up the bh in this cpu's LRU. If it's there, move it to the head. + */ static inline struct buffer_head * -lookup_bh(struct block_device *bdev, sector_t block, int size) +lookup_bh_lru(struct block_device *bdev, sector_t block, int size) { struct buffer_head *ret = NULL; struct bh_lru *lru; @@ -1330,44 +1301,65 @@ lookup_bh(struct block_device *bdev, sector_t block, int size) return ret; } +/* + * Perform a pagecache lookup for the matching buffer. If it's there, refresh + * it in the LRU and mark it as accessed. If it is not present then return + * NULL + */ struct buffer_head * __find_get_block(struct block_device *bdev, sector_t block, int size) { - struct buffer_head *bh = lookup_bh(bdev, block, size); + struct buffer_head *bh = lookup_bh_lru(bdev, block, size); if (bh == NULL) { bh = __find_get_block_slow(bdev, block, size); - bh_lru_install(bh); + if (bh) + bh_lru_install(bh); } + if (bh) + touch_buffer(bh); return bh; } EXPORT_SYMBOL(__find_get_block); +/* + * __getblk will locate (and, if necessary, create) the buffer_head + * which corresponds to the passed block_device, block and size. The + * returned buffer has its reference count incremented. + * + * __getblk() cannot fail - it just keeps trying. If you pass it an + * illegal block number, __getblk() will happily return a buffer_head + * which represents the non-existent block. Very weird. + * + * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() + * attempt is failing. FIXME, perhaps? + */ struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size) { struct buffer_head *bh = __find_get_block(bdev, block, size); - if (bh == NULL) { + if (bh == NULL) bh = __getblk_slow(bdev, block, size); - bh_lru_install(bh); - } return bh; } EXPORT_SYMBOL(__getblk); +/** + * __bread() - reads a specified block and returns the bh + * @block: number of block + * @size: size (in bytes) to read + * + * Reads a specified block, and returns buffer head that contains it. + * It returns NULL if the block was unreadable. + */ struct buffer_head * __bread(struct block_device *bdev, sector_t block, int size) { struct buffer_head *bh = __getblk(bdev, block, size); - if (bh) { - if (buffer_uptodate(bh)) - return bh; - __brelse(bh); - } - bh = __bread_slow(bdev, block, size); - bh_lru_install(bh); + if (!buffer_uptodate(bh)) + bh = __bread_slow(bh); return bh; } EXPORT_SYMBOL(__bread); @@ -1565,7 +1557,7 @@ void unmap_underlying_metadata(struct block_device *bdev, sector_t block) { struct buffer_head *old_bh; - old_bh = __find_get_block(bdev, block, 0); + old_bh = __find_get_block_slow(bdev, block, 0); if (old_bh) { #if 0 /* This happens. Later. */ if (buffer_dirty(old_bh)) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 424f807dadb5..c081e426fd1f 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1021,6 +1021,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_mount_opt = 0; sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; + setup_ro_after(sb); blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); if (!blocksize) { diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 3a246ef01778..179a3893a945 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -29,4 +29,5 @@ int jfs_permission(struct inode *, int); int jfs_init_acl(struct inode *, struct inode *); int jfs_setattr(struct dentry *, struct iattr *); -#endif /* CONFIG_JFS_POSIX_ACL */ +#endif /* CONFIG_JFS_POSIX_ACL */ +#endif /* _H_JFS_ACL */ diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 8b6f9370d187..3f1db05f5445 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -40,7 +40,7 @@ #include <linux/times.h> #include <linux/profile.h> #include <linux/blkdev.h> - +#include <linux/hugetlb.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> @@ -199,19 +199,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, ps.nr_reverse_maps ); -#ifdef CONFIG_HUGETLB_PAGE - { - extern unsigned long htlbpagemem, htlbzone_pages; - len += sprintf(page + len, - "HugePages_Total: %5lu\n" - "HugePages_Free: %5lu\n" - "Hugepagesize: %5lu kB\n", - htlbzone_pages, - htlbpagemem, - HPAGE_SIZE/1024); - } + len += hugetlb_report_meminfo(page + len); -#endif return proc_calc_metrics(page, start, off, count, eof, len); #undef K } @@ -341,7 +330,6 @@ static int kstat_read_proc(char *page, char **start, off_t off, extern unsigned long total_forks; unsigned long jif = jiffies; unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0; - int major, disk; for (i = 0 ; i < NR_CPUS; i++) { int j; @@ -372,7 +360,7 @@ static int kstat_read_proc(char *page, char **start, off_t off, jiffies_to_clock_t(kstat_cpu(i).cpustat.nice), jiffies_to_clock_t(kstat_cpu(i).cpustat.system), jiffies_to_clock_t(kstat_cpu(i).cpustat.idle), - jiffies_to_clock_t(kstat_cpu(i).cpustat.idle)); + jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait)); } len += sprintf(page + len, "intr %u", sum); @@ -381,37 +369,17 @@ static int kstat_read_proc(char *page, char **start, off_t off, len += sprintf(page + len, " %u", kstat_irqs(i)); #endif - len += sprintf(page + len, "\ndisk_io: "); - - for (major = 0; major < DK_MAX_MAJOR; major++) { - for (disk = 0; disk < DK_MAX_DISK; disk++) { - int active = dkstat.drive[major][disk] + - dkstat.drive_rblk[major][disk] + - dkstat.drive_wblk[major][disk]; - if (active) - len += sprintf(page + len, - "(%u,%u):(%u,%u,%u,%u,%u) ", - major, disk, - dkstat.drive[major][disk], - dkstat.drive_rio[major][disk], - dkstat.drive_rblk[major][disk], - dkstat.drive_wio[major][disk], - dkstat.drive_wblk[major][disk] - ); - } - } - len += sprintf(page + len, "\nctxt %lu\n" "btime %lu\n" "processes %lu\n" "procs_running %lu\n" - "procs_blocked %u\n", + "procs_blocked %lu\n", nr_context_switches(), xtime.tv_sec - jif / HZ, total_forks, nr_running(), - atomic_read(&nr_iowait_tasks)); + nr_iowait()); return proc_calc_metrics(page, start, off, count, eof, len); } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 472432a57b06..a3927e6b6dee 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -11,22 +11,6 @@ #include <asm/scatterlist.h> -/* - * Disk stats ... - */ - -#define DK_MAX_MAJOR 16 -#define DK_MAX_DISK 16 - -struct disk_stat { - unsigned int drive[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int drive_rio[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int drive_wio[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int drive_rblk[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK]; -}; -extern struct disk_stat dkstat; - struct request_queue; typedef struct request_queue request_queue_t; struct elevator_s; @@ -470,9 +454,4 @@ static inline void put_dev_sector(Sector p) #endif - -extern atomic_t nr_iowait_tasks; -void io_schedule(void); -void io_schedule_timeout(long timeout); - #endif diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 30fa2437be15..37c3621b2f03 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -2,17 +2,25 @@ #define _LINUX_HUGETLB_H #ifdef CONFIG_HUGETLB_PAGE + +struct ctl_table; + static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) { return vma->vm_flags & VM_HUGETLB; } +int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void *, size_t *); int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); void zap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); int hugetlb_prefault(struct address_space *, struct vm_area_struct *); void huge_page_release(struct page *); +int hugetlb_report_meminfo(char *); + +extern int htlbpage_max; + #else /* !CONFIG_HUGETLB_PAGE */ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) { @@ -25,6 +33,7 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) #define zap_hugepage_range(vma, start, len) BUG() #define unmap_hugepage_range(vma, start, end) BUG() #define huge_page_release(page) BUG() +#define hugetlb_report_meminfo(buf) 0 #endif /* !CONFIG_HUGETLB_PAGE */ diff --git a/include/linux/sched.h b/include/linux/sched.h index c26b6d0d8d7a..93b1328d59e4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -88,6 +88,7 @@ extern int nr_threads; extern int last_pid; extern unsigned long nr_running(void); extern unsigned long nr_uninterruptible(void); +extern unsigned long nr_iowait(void); #include <linux/time.h> #include <linux/param.h> @@ -147,6 +148,8 @@ extern void show_trace(unsigned long *stack); extern void show_stack(unsigned long *stack); extern void show_regs(struct pt_regs *); +void io_schedule(void); +void io_schedule_timeout(long timeout); extern void cpu_init (void); extern void trap_init(void); diff --git a/include/sound/core.h b/include/sound/core.h index e21feca3b8c0..4ba70412cb79 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -241,11 +241,15 @@ void *snd_hidden_vmalloc(unsigned long size); void snd_hidden_vfree(void *obj); #define kmalloc(size, flags) snd_hidden_kmalloc(size, flags) #define kfree(obj) snd_hidden_kfree(obj) -#define kfree_nocheck(obj) snd_wrapper_kfree(obj) #define vmalloc(size) snd_hidden_vmalloc(size) #define vfree(obj) snd_hidden_vfree(obj) +#define kmalloc_nocheck(size, flags) snd_wrapper_kmalloc(size, flags) +#define vmalloc_nocheck(size) snd_wrapper_vmalloc(size) +#define kfree_nocheck(obj) snd_wrapper_kfree(obj) #define vfree_nocheck(obj) snd_wrapper_vfree(obj) #else +#define kmalloc_nocheck(size, flags) kmalloc(size, flags) +#define vmalloc_nocheck(size) vmalloc(size) #define kfree_nocheck(obj) kfree(obj) #define vfree_nocheck(obj) vfree(obj) #endif diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h index 610c2e94705b..75d1b588ee87 100644 --- a/include/sound/cs4231.h +++ b/include/sound/cs4231.h @@ -26,9 +26,24 @@ #include "pcm.h" #include "timer.h" +#ifdef CONFIG_SBUS +#define SBUS_SUPPORT +#include <asm/sbus.h> +#endif + +#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64) +#define EBUS_SUPPORT +#include <linux/pci.h> +#include <asm/ebus.h> +#endif + +#if !defined(SBUS_SUPPORT) && !defined(EBUS_SUPPORT) +#define LEGACY_SUPPORT +#endif + /* IO ports */ -#define CS4231P(chip, x) ((chip)->port + c_d_c_CS4231##x) +#define CS4231P(x) (c_d_c_CS4231##x) #define c_d_c_CS4231REGSEL 0 #define c_d_c_CS4231REG 1 @@ -221,17 +236,38 @@ typedef struct _snd_cs4231 cs4231_t; struct _snd_cs4231 { unsigned long port; /* base i/o port */ +#ifdef LEGACY_SUPPORT struct resource *res_port; unsigned long cport; /* control base i/o port (CS4236) */ struct resource *res_cport; int irq; /* IRQ line */ int dma1; /* playback DMA */ int dma2; /* record DMA */ +#endif unsigned short version; /* version of CODEC chip */ unsigned short mode; /* see to CS4231_MODE_XXXX */ unsigned short hardware; /* see to CS4231_HW_XXXX */ unsigned short hwshare; /* shared resources */ - unsigned short single_dma:1; /* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */ + unsigned short single_dma:1, /* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */ + ebus_flag:1; /* SPARC: EBUS present */ + +#ifdef EBUS_SUPPORT + struct ebus_dma_info eb2c; + struct ebus_dma_info eb2p; +#endif + +#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT) + union { +#ifdef SBUS_SUPPORT + struct sbus_dev *sdev; +#endif +#ifdef EBUS_SUPPORT + struct pci_dev *pdev; +#endif + } dev_u; + unsigned int p_periods_sent; + unsigned int c_periods_sent; +#endif snd_card_t *card; snd_pcm_t *pcm; @@ -245,8 +281,10 @@ struct _snd_cs4231 { int mce_bit; int calibrate_mute; int sw_3d_bit; +#ifdef LEGACY_SUPPORT unsigned int p_dma_size; unsigned int c_dma_size; +#endif spinlock_t reg_lock; struct semaphore mce_mutex; @@ -255,14 +293,17 @@ struct _snd_cs4231 { int (*rate_constraint) (snd_pcm_runtime_t *runtime); void (*set_playback_format) (cs4231_t *chip, snd_pcm_hw_params_t *hw_params, unsigned char pdfr); void (*set_capture_format) (cs4231_t *chip, snd_pcm_hw_params_t *hw_params, unsigned char cdfr); + void (*trigger) (cs4231_t *chip, unsigned int what, int start); #ifdef CONFIG_PM struct pm_dev *pm_dev; void (*suspend) (cs4231_t *chip); void (*resume) (cs4231_t *chip); #endif void *dma_private_data; +#ifdef LEGACY_SUPPORT int (*claim_dma) (cs4231_t *chip, void *dma_private_data, int dma); int (*release_dma) (cs4231_t *chip, void *dma_private_data, int dma); +#endif }; /* exported functions */ diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h index a9303d3a503c..09ae6c772aa0 100644 --- a/include/sound/cs46xx.h +++ b/include/sound/cs46xx.h @@ -196,80 +196,6 @@ #define BA1_OMNI_MEM 0x000E0000 - - -/* - * The following define the offsets of the AC97 shadow registers, which appear - * as a virtual extension to the base address register zero memory range. - */ -#define AC97_REG_OFFSET_MASK 0x0000007EL -#define AC97_CODEC_NUMBER_MASK 0x00003000L - -#define BA0_AC97_RESET 0x00001000L -#define BA0_AC97_MASTER_VOLUME 0x00001002L -#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L -#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L -#define BA0_AC97_MASTER_TONE 0x00001008L -#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL -#define BA0_AC97_PHONE_VOLUME 0x0000100CL -#define BA0_AC97_MIC_VOLUME 0x0000100EL -#define BA0_AC97_LINE_IN_VOLUME 0x00001010L -#define BA0_AC97_CD_VOLUME 0x00001012L -#define BA0_AC97_VIDEO_VOLUME 0x00001014L -#define BA0_AC97_AUX_VOLUME 0x00001016L -#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L -#define BA0_AC97_RECORD_SELECT 0x0000101AL -#define BA0_AC97_RECORD_GAIN 0x0000101CL -#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL -#define BA0_AC97_GENERAL_PURPOSE 0x00001020L -#define BA0_AC97_3D_CONTROL 0x00001022L -#define BA0_AC97_MODEM_RATE 0x00001024L -#define BA0_AC97_POWERDOWN 0x00001026L -#define BA0_AC97_EXT_AUDIO_ID 0x00001028L -#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL -#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL -#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL -#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L -#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L -#define BA0_AC97_MIC_ADC_RATE 0x00001034L -#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L -#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L -#define BA0_AC97_RESERVED_3A 0x0000103AL -#define BA0_AC97_EXT_MODEM_ID 0x0000103CL -#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL -#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L -#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L -#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L -#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L -#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L -#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL -#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL -#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL -#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L -#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L -#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L -#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L -#define BA0_AC97_RESERVED_58 0x00001058L -#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL -#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL -#define BA0_AC97_AC_MODE 0x0000105EL -#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L -#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L -#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L -#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L -#define BA0_AC97_SPDIF_CONTROL 0x00001068L -#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL -#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL -#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL -#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L -#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L -#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L -#define BA0_AC97_CAL_ADDRESS 0x00001076L -#define BA0_AC97_CAL_DATA 0x00001078L -#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL -#define BA0_AC97_VENDOR_ID1 0x0000107CL -#define BA0_AC97_VENDOR_ID2 0x0000107EL - /* * The following defines are for the flags in the host interrupt status * register. @@ -1790,6 +1716,7 @@ struct _snd_cs46xx { struct pci_dev *pci; snd_card_t *card; snd_pcm_t *pcm; + snd_rawmidi_t *rmidi; snd_rawmidi_substream_t *midi_input; snd_rawmidi_substream_t *midi_output; @@ -1814,12 +1741,15 @@ struct _snd_cs46xx { struct pm_dev *pm_dev; #endif #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO - int current_gpio; + int current_gpio; #endif #ifdef CONFIG_SND_CS46XX_NEW_DSP struct semaphore spos_mutex; dsp_spos_instance_t * dsp_spos_instance; + + snd_pcm_t *pcm_rear; + snd_pcm_t *pcm_iec958; #else /* for compatibility */ cs46xx_pcm_t *playback_pcm; unsigned int play_ctl; @@ -1832,8 +1762,11 @@ int snd_cs46xx_create(snd_card_t *card, cs46xx_t **rcodec); int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm); +int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm); +int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm); int snd_cs46xx_mixer(cs46xx_t *chip); int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi); +int snd_cs46xx_start_dsp(cs46xx_t *chip); void snd_cs46xx_gameport(cs46xx_t *chip); #ifdef CONFIG_PM diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h index 271e72f5c8c5..8366aefaff6b 100644 --- a/include/sound/cs46xx_dsp_spos.h +++ b/include/sound/cs46xx_dsp_spos.h @@ -36,24 +36,35 @@ #define SEGTYPE_SP_COEFFICIENT 0x00000004 #define DSP_SPOS_UU 0x0deadul /* unused */ -#define DSP_SPOS_DC 0x0badul /* dont care */ -#define DSP_SPOS_DC_DC 0x0bad0badul /* dont care */ +#define DSP_SPOS_DC 0x0badul /* dont care */ +#define DSP_SPOS_DC_DC 0x0bad0badul /* dont care */ #define DSP_SPOS_UUUU 0xdeadc0edul /* unused */ #define DSP_SPOS_UUHI 0xdeadul #define DSP_SPOS_UULO 0xc0edul -#define DSP_SPOS_DCDC 0x0badf1d0ul /* dont care */ +#define DSP_SPOS_DCDC 0x0badf1d0ul /* dont care */ #define DSP_SPOS_DCDCHI 0x0badul #define DSP_SPOS_DCDCLO 0xf1d0ul -#define DSP_MAX_TASK_NAME 60 +#define DSP_MAX_TASK_NAME 60 #define DSP_MAX_SYMBOL_NAME 100 -#define DSP_MAX_SCB_NAME 60 -#define DSP_MAX_SCB_DESC 200 -#define DSP_MAX_TASK_DESC 50 +#define DSP_MAX_SCB_NAME 60 +#define DSP_MAX_SCB_DESC 200 +#define DSP_MAX_TASK_DESC 50 #define DSP_MAX_PCM_CHANNELS 32 #define DSP_MAX_SRC_NR 6 +#define DSP_PCM_MAIN_CHANNEL 1 +#define DSP_PCM_REAR_CHANNEL 2 +#define DSP_PCM_CENTER_CHANNEL 3 +#define DSP_PCM_LFE_CHANNEL 4 +#define DSP_IEC958_CHANNEL 5 + +#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1 +#define DSP_SPDIF_STATUS_PLAYBACK_OPEN 2 +#define DSP_SPDIF_STATUS_HW_ENABLED 4 +#define DSP_SPDIF_STATUS_AC3_MODE 8 + struct _dsp_module_desc_t; typedef struct _symbol_entry_t { @@ -129,6 +140,8 @@ typedef struct _pcm_channel_descriptor_t { u32 unlinked; dsp_scb_descriptor_t * pcm_reader_scb; dsp_scb_descriptor_t * src_scb; + dsp_scb_descriptor_t * mixer_scb; + int pcm_channel_id; void * private_data; } pcm_channel_descriptor_t; @@ -141,8 +154,14 @@ typedef struct _dsp_spos_instance_t { segment_desc_t code; - /* PCM playback */ + /* Main PCM playback mixer */ dsp_scb_descriptor_t * master_mix_scb; + u16 dac_volume_right; + u16 dac_volume_left; + + /* Rear PCM playback mixer */ + dsp_scb_descriptor_t * rear_mix_scb; + int npcm_channels; int nsrc_scb; pcm_channel_descriptor_t pcm_channels[DSP_MAX_PCM_CHANNELS]; @@ -175,7 +194,8 @@ typedef struct _dsp_spos_instance_t { /* SPDIF status */ int spdif_status_out; int spdif_status_in; - u32 spdif_input_volume; + u16 spdif_input_volume_right; + u16 spdif_input_volume_left; /* SPDIF input sample rate converter */ dsp_scb_descriptor_t * spdif_in_src; @@ -191,6 +211,12 @@ typedef struct _dsp_spos_instance_t { /* reference snooper */ dsp_scb_descriptor_t * ref_snoop_scb; + /* SPDIF output PCM reference */ + dsp_scb_descriptor_t * spdif_pcm_input_scb; + + /* asynch TX task */ + dsp_scb_descriptor_t * asynch_tx_scb; + /* record sources */ dsp_scb_descriptor_t * pcm_input; dsp_scb_descriptor_t * adc_input; @@ -199,4 +225,3 @@ typedef struct _dsp_spos_instance_t { } dsp_spos_instance_t; #endif /* __DSP_SPOS_H__ */ - diff --git a/include/sound/info.h b/include/sound/info.h index b45b422063e2..6984c6e736dc 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -130,8 +130,9 @@ void snd_info_free_device(snd_info_entry_t * entry); int snd_info_store_text(snd_info_entry_t * entry); int snd_info_restore_text(snd_info_entry_t * entry); +int snd_info_card_create(snd_card_t * card); int snd_info_card_register(snd_card_t * card); -int snd_info_card_unregister(snd_card_t * card); +int snd_info_card_free(snd_card_t * card); int snd_info_register(snd_info_entry_t * entry); int snd_info_unregister(snd_info_entry_t * entry); diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2c329a00dcae..c7f41630c253 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -96,7 +96,7 @@ typedef struct _snd_pcm_ops { void *buf, snd_pcm_uframes_t count); int (*silence)(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count); - void *(*page)(snd_pcm_substream_t *substream, unsigned long offset); + struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset); } snd_pcm_ops_t; /* @@ -125,7 +125,7 @@ typedef struct _snd_pcm_ops { #define SNDRV_PCM_DMA_TYPE_PCI 2 /* PCI continuous */ #define SNDRV_PCM_DMA_TYPE_SBUS 3 /* SBUS continuous */ -/* If you change this don't forget to changed snd_pcm_rates table in pcm_lib.c */ +/* If you change this don't forget to change rates[] table in pcm_native.c */ #define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */ #define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */ #define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */ diff --git a/include/sound/pcm_sgbuf.h b/include/sound/pcm_sgbuf.h index 63eacc892da8..bc6474559c57 100644 --- a/include/sound/pcm_sgbuf.h +++ b/include/sound/pcm_sgbuf.h @@ -61,7 +61,7 @@ int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream); int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count); int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count); int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count); -void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset); +struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset); #endif /* __SOUND_PCM_SGBUF_H */ diff --git a/include/sound/version.h b/include/sound/version.h index de5e5218a7b4..acaac7181bbe 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated automatically by configure. */ #define CONFIG_SND_VERSION "0.9.0rc5" -#define CONFIG_SND_DATE " (Tue Oct 29 09:19:27 2002 UTC)" +#define CONFIG_SND_DATE " (Sun Nov 10 19:48:18 2002 UTC)" diff --git a/kernel/sched.c b/kernel/sched.c index 6821d73ff10b..35373ad017f5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -157,6 +157,7 @@ struct runqueue { task_t *migration_thread; struct list_head migration_queue; + atomic_t nr_iowait; } ____cacheline_aligned; static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; @@ -557,9 +558,11 @@ unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; - for (i = 0; i < NR_CPUS; i++) + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; sum += cpu_rq(i)->nr_uninterruptible; - + } return sum; } @@ -567,9 +570,23 @@ unsigned long nr_context_switches(void) { unsigned long i, sum = 0; - for (i = 0; i < NR_CPUS; i++) + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; sum += cpu_rq(i)->nr_switches; + } + return sum; +} + +unsigned long nr_iowait(void) +{ + unsigned long i, sum = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (!cpu_online(i)) + continue; + sum += atomic_read(&cpu_rq(i)->nr_iowait); + } return sum; } @@ -875,7 +892,7 @@ void scheduler_tick(int user_ticks, int sys_ticks) /* note: this timer irq context must be accounted for as well */ if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET) kstat_cpu(cpu).cpustat.system += sys_ticks; - else if (atomic_read(&nr_iowait_tasks) > 0) + else if (atomic_read(&rq->nr_iowait) > 0) kstat_cpu(cpu).cpustat.iowait += sys_ticks; else kstat_cpu(cpu).cpustat.idle += sys_ticks; @@ -1712,6 +1729,31 @@ void yield(void) sys_sched_yield(); } +/* + * This task is about to go to sleep on IO. Increment rq->nr_iowait so + * that process accounting knows that this is a task in IO wait state. + * + * But don't do that if it is a deliberate, throttling IO wait (this task + * has set its backing_dev_info: the queue against which it should throttle) + */ +void io_schedule(void) +{ + struct runqueue *rq = this_rq(); + + atomic_inc(&rq->nr_iowait); + schedule(); + atomic_dec(&rq->nr_iowait); +} + +void io_schedule_timeout(long timeout) +{ + struct runqueue *rq = this_rq(); + + atomic_inc(&rq->nr_iowait); + schedule_timeout(timeout); + atomic_dec(&rq->nr_iowait); +} + /** * sys_sched_get_priority_max - return maximum RT priority. * @policy: scheduling class. @@ -2160,6 +2202,7 @@ void __init sched_init(void) rq->expired = rq->arrays + 1; spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->migration_queue); + atomic_set(&rq->nr_iowait, 0); for (j = 0; j < 2; j++) { array = rq->arrays + j; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0317dd749b2b..c6eeba758371 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -31,7 +31,7 @@ #include <linux/sysrq.h> #include <linux/highuid.h> #include <linux/writeback.h> - +#include <linux/hugetlb.h> #include <asm/uaccess.h> #ifdef CONFIG_ROOT_NFS @@ -99,11 +99,6 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp, extern int acct_parm[]; #endif -#ifdef CONFIG_HUGETLB_PAGE -extern int htlbpage_max; -extern int set_hugetlb_mem_size(int); -#endif - static int parse_table(int *, int, void *, size_t *, void *, size_t, ctl_table *, void **); static int proc_doutsstring(ctl_table *table, int write, struct file *filp, @@ -315,8 +310,7 @@ static ctl_table vm_table[] = { 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, &one_hundred }, #ifdef CONFIG_HUGETLB_PAGE - {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, - &proc_dointvec}, + {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, &hugetlb_sysctl_handler}, #endif {0} }; @@ -907,10 +901,6 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, val = -val; buffer += len; left -= len; -#ifdef CONFIG_HUGETLB_PAGE - if (i == &htlbpage_max) - val = set_hugetlb_mem_size(val); -#endif switch(op) { case OP_SET: *i = val; break; case OP_AND: *i &= val; break; diff --git a/mm/filemap.c b/mm/filemap.c index 4dcbc344f2d2..421b8597995a 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -791,6 +791,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (seg == 0) return -EFAULT; nr_segs = seg; + count -= iv->iov_len; /* This segment is no good */ break; } @@ -1578,6 +1579,7 @@ generic_file_write_nolock(struct file *file, const struct iovec *iov, if (seg == 0) return -EFAULT; nr_segs = seg; + ocount -= iv->iov_len; /* This segment is no good */ break; } count = ocount; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 819a65b3d33a..0158427d2502 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -175,7 +175,6 @@ free_pages_bulk(struct zone *zone, int count, /* have to delete it as __free_pages_bulk list manipulates */ list_del(&page->list); __free_pages_bulk(page, base, zone, area, mask, order); - mod_page_state(pgfree, count<<order); ret++; } spin_unlock_irqrestore(&zone->lock, flags); @@ -186,6 +185,7 @@ void __free_pages_ok(struct page *page, unsigned int order) { LIST_HEAD(list); + mod_page_state(pgfree, 1 << order); free_pages_check(__FUNCTION__, page); list_add(&page->list, &list); free_pages_bulk(page_zone(page), 1, &list, order); @@ -291,32 +291,19 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, unsigned long count, struct list_head *list) { unsigned long flags; - int i, allocated = 0; + int i; + int allocated = 0; struct page *page; - struct list_head *curr; - LIST_HEAD(temp); spin_lock_irqsave(&zone->lock, flags); for (i = 0; i < count; ++i) { page = __rmqueue(zone, order); if (page == NULL) break; - ++allocated; - list_add(&page->list, &temp); + allocated++; + list_add_tail(&page->list, list); } spin_unlock_irqrestore(&zone->lock, flags); - - /* - * This may look inefficient because we're walking the list again, - * but the cachelines are hot, so it's very cheap, and this way we - * can drop the zone lock much earlier - */ - list_for_each(curr, &temp) { - page = list_entry(curr, struct page, list); - BUG_ON(bad_range(zone, page)); - prep_new_page(page, order); - } - list_splice(&temp, list->prev); return allocated; } @@ -354,6 +341,7 @@ static void free_hot_cold_page(struct page *page, int cold) struct per_cpu_pages *pcp; unsigned long flags; + inc_page_state(pgfree); free_pages_check(__FUNCTION__, page); pcp = &zone->pageset[get_cpu()].pcp[cold]; local_irq_save(flags); @@ -405,6 +393,7 @@ static struct page *buffered_rmqueue(struct zone *zone, int order, int cold) if (page != NULL) { BUG_ON(bad_range(zone, page)); + mod_page_state(pgalloc, 1 << order); prep_new_page(page, order); } return page; @@ -431,8 +420,6 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, if (gfp_mask & __GFP_COLD) cold = 1; - mod_page_state(pgalloc, 1<<order); - zones = zonelist->zones; /* the list of zones suitable for gfp_mask */ classzone = zones[0]; if (classzone == NULL) /* no zones in the zonelist */ diff --git a/sound/core/info.c b/sound/core/info.c index 0e1bfb625ddf..9792d9ee75a1 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -699,12 +699,10 @@ int __exit snd_info_done(void) */ -int snd_info_card_register(snd_card_t * card) +int snd_info_card_create(snd_card_t * card) { char str[8]; - char *s; snd_info_entry_t *entry; - struct proc_dir_entry *p; snd_assert(card != NULL, return -ENXIO); @@ -717,11 +715,20 @@ int snd_info_card_register(snd_card_t * card) return -ENOMEM; } card->proc_root = entry; + return 0; +} + +int snd_info_card_register(snd_card_t * card) +{ + char *s; + struct proc_dir_entry *p; + + snd_assert(card != NULL, return -ENXIO); - if (!strcmp(card->id, str)) + if (!strcmp(card->id, card->proc_root->name)) return 0; - s = snd_kmalloc_strdup(str, GFP_KERNEL); + s = snd_kmalloc_strdup(card->proc_root->name, GFP_KERNEL); if (s == NULL) return -ENOMEM; p = snd_create_proc_entry(card->id, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, snd_proc_root); @@ -738,7 +745,7 @@ int snd_info_card_register(snd_card_t * card) return 0; } -int snd_info_card_unregister(snd_card_t * card) +int snd_info_card_free(snd_card_t * card) { void *data; diff --git a/sound/core/init.c b/sound/core/init.c index 3e15f1a4fe61..77565af5ba45 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/time.h> +#include <linux/ctype.h> #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -45,7 +46,6 @@ snd_card_t *snd_card_new(int idx, const char *xid, struct module *module, int extra_size) { snd_card_t *card; - snd_info_entry_t *entry; int err; if (extra_size < 0) @@ -79,8 +79,6 @@ snd_card_t *snd_card_new(int idx, const char *xid, snd_cards_lock |= 1 << idx; /* lock it */ write_unlock(&snd_card_rwlock); card->number = idx; - if (!card->id[0]) - sprintf(card->id, "card%i", card->number); card->module = module; INIT_LIST_HEAD(&card->devices); rwlock_init(&card->control_rwlock); @@ -97,28 +95,14 @@ snd_card_t *snd_card_new(int idx, const char *xid, snd_printd("unable to register control minors\n"); goto __error; } - if ((err = snd_info_card_register(card)) < 0) { - snd_printd("unable to register card info\n"); + if ((err = snd_info_card_create(card)) < 0) { + snd_printd("unable to create card info\n"); goto __error_ctl; } - if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) { - snd_printd("unable to create card entry\n"); - goto __error_info; - } - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->c.text.read_size = PAGE_SIZE; - entry->c.text.read = snd_card_id_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - goto __error_info; - } - card->proc_id = entry; if (extra_size > 0) card->private_data = (char *)card + sizeof(snd_card_t); return card; - __error_info: - snd_info_card_unregister(card); __error_ctl: snd_ctl_unregister(card); __error: @@ -157,8 +141,8 @@ int snd_card_free(snd_card_t * card) if (card->private_free) card->private_free(card); snd_info_free_entry(card->proc_id); - if (snd_info_card_unregister(card) < 0) { - snd_printk(KERN_WARNING "unable to unregister card info\n"); + if (snd_info_card_free(card) < 0) { + snd_printk(KERN_WARNING "unable to free card info\n"); /* Not fatal error */ } write_lock(&snd_card_rwlock); @@ -168,9 +152,66 @@ int snd_card_free(snd_card_t * card) return 0; } +static void choose_default_id(snd_card_t *card) +{ + int i, len, idx_flag = 0, loops = 8; + char *id, *spos; + + id = spos = card->shortname; + while (*id != '\0') { + if (*id == ' ') + spos = id + 1; + id++; + } + id = card->id; + while (*spos != '\0' && id - card->id < sizeof(card->id) - 1) { + if (isalnum(*spos)) + *id++ = *spos; + spos++; + } + *id = '\0'; + + id = card->id; + + while (1) { + if (loops-- == 0) { + snd_printk(KERN_ERR "unable to choose default card id (%s)", id); + strcpy(card->id, card->proc_root->name); + return; + } + if (!snd_info_check_reserved_words(id)) + goto __change; + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) + goto __change; + } + break; + + __change: + len = strlen(id); + if (idx_flag) + id[len-1]++; + else if (len <= sizeof(card->id) - 3) { + strcat(id, "_1"); + idx_flag++; + } else { + spos = id + len - 2; + if (len <= sizeof(card->id) - 2) + spos++; + *spos++ = '_'; + *spos++ = '1'; + *spos++ = '\0'; + idx_flag++; + } + } + + strcpy(card->id, id); +} + int snd_card_register(snd_card_t * card) { int err; + snd_info_entry_t *entry; snd_runtime_check(card != NULL, return -EINVAL); if ((err = snd_device_register_all(card)) < 0) @@ -181,9 +222,28 @@ int snd_card_register(snd_card_t * card) write_unlock(&snd_card_rwlock); return 0; } + if (!card->id[0]) + choose_default_id(card); snd_cards[card->number] = card; snd_cards_count++; write_unlock(&snd_card_rwlock); + if ((err = snd_info_card_register(card)) < 0) { + snd_printd("unable to create card info\n"); + goto __skip_info; + } + if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) { + snd_printd("unable to create card entry\n"); + goto __skip_info; + } + entry->content = SNDRV_INFO_CONTENT_TEXT; + entry->c.text.read_size = PAGE_SIZE; + entry->c.text.read = snd_card_id_read; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + card->proc_id = entry; + __skip_info: #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, 0); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index cc7617872bb2..ad505e74f82d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -564,7 +564,15 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s } else { ret = snd_pcm_lib_read(substream, ptr, frames); } - if (ret != -EPIPE && ret != -ESTRPIPE) + if (ret == -EPIPE) { + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0); + if (ret < 0) + break; + } + continue; + } + if (ret != -ESTRPIPE) break; } return ret; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 275a30cb43c0..7a28d0905fd6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1996,7 +1996,7 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res) { snd_pcm_runtime_t *runtime = substream->runtime; int err; - snd_pcm_sframes_t n; + snd_pcm_sframes_t n = 0; spin_lock_irq(&runtime->lock); switch (runtime->status->state) { @@ -2014,8 +2014,6 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res) n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); - if (put_user(n, res)) - err = -EFAULT; break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2026,6 +2024,9 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res) break; } spin_unlock_irq(&runtime->lock); + if (!err) + if (put_user(n, res)) + err = -EFAULT; return err; } @@ -2668,12 +2669,13 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig if (offset > dma_bytes - PAGE_SIZE) return NOPAGE_SIGBUS; if (substream->ops->page) { - vaddr = substream->ops->page(substream, offset); - if (! vaddr) + page = substream->ops->page(substream, offset); + if (! page) return NOPAGE_OOM; - } else + } else { vaddr = runtime->dma_area + offset; - page = virt_to_page(vaddr); + page = virt_to_page(vaddr); + } get_page(page); #ifndef LINUX_2_2 return page; diff --git a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c index 5f7b9a047ef8..11371eb5130b 100644 --- a/sound/core/pcm_sgbuf.c +++ b/sound/core/pcm_sgbuf.c @@ -66,7 +66,7 @@ int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int sgbuf->tblsize = tblsize; sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL); if (! sgbuf->table) { - snd_pcm_sgbuf_free(substream); + snd_pcm_sgbuf_delete(substream); return -ENOMEM; } memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize); @@ -158,9 +158,8 @@ int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream) /* * get the page pointer on the given offset - * used as the page callback of pcm ops */ -void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) +static void *sgbuf_get_addr(snd_pcm_substream_t *substream, unsigned long offset) { struct snd_sg_buf *sgbuf; unsigned int idx; @@ -173,6 +172,19 @@ void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offse } /* + * get the page struct at the given offset + * used as the page callback of pcm ops + */ +struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) +{ + void *addr = sgbuf_get_addr(substream, offset); + if (addr) + return virt_to_page(addr); + else + return 0; +} + +/* * do copy_from_user to the sg buffer */ static int copy_from_user_sg_buf(snd_pcm_substream_t *substream, @@ -184,7 +196,7 @@ static int copy_from_user_sg_buf(snd_pcm_substream_t *substream, hwoff -= p; len = PAGE_SIZE - hwoff; for (;;) { - addr = snd_pcm_sgbuf_ops_page(substream, p); + addr = sgbuf_get_addr(substream, p); if (! addr) return -EFAULT; if (len > bytes) @@ -214,7 +226,7 @@ static int copy_to_user_sg_buf(snd_pcm_substream_t *substream, hwoff -= p; len = PAGE_SIZE - hwoff; for (;;) { - addr = snd_pcm_sgbuf_ops_page(substream, p); + addr = sgbuf_get_addr(substream, p); if (! addr) return -EFAULT; if (len > bytes) @@ -246,7 +258,7 @@ static int set_silence_sg_buf(snd_pcm_substream_t *substream, len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff); page_len = bytes_to_samples(substream->runtime, PAGE_SIZE); for (;;) { - addr = snd_pcm_sgbuf_ops_page(substream, p); + addr = sgbuf_get_addr(substream, p); if (! addr) return -EFAULT; if (len > samples) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 6b3bb04c6c56..2b5e56617107 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -699,7 +699,6 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, case SNDRV_RAWMIDI_IOCTL_PARAMS: { snd_rawmidi_params_t params; - int err; if (copy_from_user(¶ms, (snd_rawmidi_params_t *) arg, sizeof(snd_rawmidi_params_t))) return -EFAULT; switch (params.stream) { @@ -714,9 +713,6 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, default: return -EINVAL; } - if (copy_to_user((snd_rawmidi_params_t *) arg, ¶ms, sizeof(snd_rawmidi_params_t))) - return -EFAULT; - return err; } case SNDRV_RAWMIDI_IOCTL_STATUS: { diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index b28a1b2ec15f..f954d0115f08 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -25,7 +25,6 @@ #include <sound/core.h> #include "seq_timer.h" #include "seq_prioq.h" -#include "seq_timer.h" /* Implementation is a simple linked list for now... diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index 97facb47b564..51ae6acf0b85 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c @@ -16,7 +16,7 @@ * 2002-04-12 Tomas Kasparek Proc interface update, code cleanup */ -/* $Id: uda1341.c,v 1.4 2002/08/15 12:13:06 perex Exp $ */ +/* $Id: uda1341.c,v 1.5 2002/11/09 13:12:19 perex Exp $ */ #include <sound/driver.h> #include <linux/module.h> @@ -341,7 +341,7 @@ static void snd_uda1341_proc_read(snd_info_entry_t *entry, snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off"); snd_iprintf(buffer, "AGC attack time : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]); - snd_iprintf(buffer, "AGC decay time : %d ns\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]); + snd_iprintf(buffer, "AGC decay time : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]); snd_iprintf(buffer, "AGC output level : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]); snd_iprintf(buffer, "Mute : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off"); diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 827c3c2541d2..0982bba6b988 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -124,6 +124,48 @@ static unsigned char snd_cs4231_original_image[32] = * Basic I/O functions */ +#if !defined(EBUS_SUPPORT) && !defined(SBUS_SUPPORT) +#define __CS4231_INLINE__ inline +#else +#define __CS4231_INLINE__ /* nothing */ +#endif + +static __CS4231_INLINE__ void cs4231_outb(cs4231_t *chip, u8 offset, u8 val) +{ +#ifdef EBUS_SUPPORT + if (chip->ebus->flag) { + writeb(val, chip->port + (offset << 2)); + } else { +#endif +#ifdef SBUS_SUPPORT + sbus_writeb(val, chip->port + (offset << 2)); +#endif +#ifdef EBUS_SUPPORT + } +#endif +#ifdef LEGACY_SUPPORT + outb(val, chip->port + offset); +#endif +} + +static __CS4231_INLINE__ u8 cs4231_inb(cs4231_t *chip, u8 offset) +{ +#ifdef EBUS_SUPPORT + if (chip->ebus_flag) { + return readb(chip->port + (offset << 2)); + } else { +#endif +#ifdef SBUS_SUPPORT + return sbus_writeb(chip->port + (offset << 2)); +#endif +#ifdef EBUS_SUPPORT + } +#endif +#ifdef LEGACY_SUPPORT + return inb(chip->port + offset); +#endif +} + void snd_cs4231_outm(cs4231_t *chip, unsigned char reg, unsigned char mask, unsigned char value) { @@ -131,21 +173,21 @@ void snd_cs4231_outm(cs4231_t *chip, unsigned char reg, unsigned char tmp; for (timeout = 250; - timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); + timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(100); #ifdef CONFIG_SND_DEBUG - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif if (chip->calibrate_mute) { chip->image[reg] &= mask; chip->image[reg] |= value; } else { - outb(chip->mce_bit | reg, CS4231P(chip, REGSEL)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); mb(); tmp = (chip->image[reg] & mask) | value; - outb(tmp, CS4231P(chip, REG)); + cs4231_outb(chip, CS4231P(REG), tmp); chip->image[reg] = tmp; mb(); } @@ -156,11 +198,11 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val int timeout; for (timeout = 250; - timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); + timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(10); - outb(chip->mce_bit | reg, CS4231P(chip, REGSEL)); - outb(value, CS4231P(chip, REG)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + cs4231_outb(chip, CS4231P(REG), value); mb(); } @@ -169,15 +211,15 @@ void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char value) int timeout; for (timeout = 250; - timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); + timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(100); #ifdef CONFIG_SND_DEBUG - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif - outb(chip->mce_bit | reg, CS4231P(chip, REGSEL)); - outb(value, CS4231P(chip, REG)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + cs4231_outb(chip, CS4231P(REG), value); chip->image[reg] = value; mb(); #if 0 @@ -190,23 +232,23 @@ unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg) int timeout; for (timeout = 250; - timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); + timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(100); #ifdef CONFIG_SND_DEBUG - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); #endif - outb(chip->mce_bit | reg, CS4231P(chip, REGSEL)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); mb(); - return inb(CS4231P(chip, REG)); + return cs4231_inb(chip, CS4231P(REG)); } void snd_cs4236_ext_out(cs4231_t *chip, unsigned char reg, unsigned char val) { - outb(chip->mce_bit | 0x17, CS4231P(chip, REGSEL)); - outb(reg | (chip->image[CS4236_EXT_REG] & 0x01), CS4231P(chip, REG)); - outb(val, CS4231P(chip, REG)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); + cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01)); + cs4231_outb(chip, CS4231P(REG), val); chip->eimage[CS4236_REG(reg)] = val; #if 0 printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val); @@ -215,14 +257,14 @@ void snd_cs4236_ext_out(cs4231_t *chip, unsigned char reg, unsigned char val) unsigned char snd_cs4236_ext_in(cs4231_t *chip, unsigned char reg) { - outb(chip->mce_bit | 0x17, CS4231P(chip, REGSEL)); - outb(reg | (chip->image[CS4236_EXT_REG] & 0x01), CS4231P(chip, REG)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); + cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01)); #if 1 - return inb(CS4231P(chip, REG)); + return cs4231_inb(chip, CS4231P(REG)); #else { unsigned char res; - res = inb(CS4231P(chip, REG)); + res = cs4231_inb(chip, CS4231P(REG)); printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res); return res; } @@ -233,8 +275,8 @@ unsigned char snd_cs4236_ext_in(cs4231_t *chip, unsigned char reg) void snd_cs4231_debug(cs4231_t *chip) { - printk("CS4231 REGS: INDEX = 0x%02x ", inb(CS4231P(chip, REGSEL))); - printk(" STATUS = 0x%02x\n", inb(CS4231P(chip, STATUS))); + printk("CS4231 REGS: INDEX = 0x%02x ", cs4231_inb(chip, CS4231P(REGSEL))); + printk(" STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS))); printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00)); printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10)); printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01)); @@ -281,10 +323,10 @@ static void snd_cs4231_busy_wait(cs4231_t *chip) /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ for (timeout = 5; timeout > 0; timeout--) - inb(CS4231P(chip, REGSEL)); + cs4231_inb(chip, CS4231P(REGSEL)); /* end of cleanup sequence */ for (timeout = 250; - timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); + timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(10); } @@ -295,18 +337,18 @@ void snd_cs4231_mce_up(cs4231_t *chip) int timeout; spin_lock_irqsave(&chip->reg_lock, flags); - for (timeout = 250; timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) + for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(100); #ifdef CONFIG_SND_DEBUG - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("mce_up - auto calibration time out (0)\n"); #endif chip->mce_bit |= CS4231_MCE; - timeout = inb(CS4231P(chip, REGSEL)); + timeout = cs4231_inb(chip, CS4231P(REGSEL)); if (timeout == 0x80) snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); if (!(timeout & CS4231_MCE)) - outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -322,12 +364,12 @@ void snd_cs4231_mce_down(cs4231_t *chip) printk("(1) timeout = %i\n", timeout); #endif #ifdef CONFIG_SND_DEBUG - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", CS4231P(chip, REGSEL)); + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); #endif chip->mce_bit &= ~CS4231_MCE; - timeout = inb(CS4231P(chip, REGSEL)); - outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); + timeout = cs4231_inb(chip, CS4231P(REGSEL)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); if (timeout == 0x80) snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); if ((timeout & CS4231_MCE) == 0 || @@ -364,7 +406,7 @@ void snd_cs4231_mce_down(cs4231_t *chip) printk("(3) jiffies = %li\n", jiffies); #endif time = HZ / 10; - while (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) { + while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { spin_unlock_irqrestore(&chip->reg_lock, flags); if (time <= 0) { snd_printk("mce_down - auto calibration time out (3)\n"); @@ -377,7 +419,7 @@ void snd_cs4231_mce_down(cs4231_t *chip) spin_unlock_irqrestore(&chip->reg_lock, flags); #if 0 printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", inb(CS4231P(chip, REGSEL))); + snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); #endif } @@ -403,7 +445,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int result = 0; #if 0 - printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(CS4231P(card, STATUS))); + printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS))); #endif switch (cmd) { @@ -423,10 +465,15 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, s = s->link_next; } while (s != substream); spin_lock(&chip->reg_lock); - if (cmd == SNDRV_PCM_TRIGGER_START) + if (cmd == SNDRV_PCM_TRIGGER_START) { chip->image[CS4231_IFACE_CTRL] |= what; - else + if (chip->trigger) + chip->trigger(chip, what, 1); + } else { chip->image[CS4231_IFACE_CTRL] &= ~what; + if (chip->trigger) + chip->trigger(chip, what, 0); + } snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); spin_unlock(&chip->reg_lock); break; @@ -640,7 +687,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); -#ifdef SNDRV_DEBUG_MCE +#ifdef SNDRV_DEBUGq_MCE snd_printk("init: (1)\n"); #endif snd_cs4231_mce_up(chip); @@ -713,8 +760,8 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode) CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE; snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | @@ -743,8 +790,8 @@ static void snd_cs4231_close(cs4231_t *chip, unsigned int mode) /* disable IRQ */ spin_lock_irqsave(&chip->reg_lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE; snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); @@ -765,8 +812,8 @@ static void snd_cs4231_close(cs4231_t *chip, unsigned int mode) /* clear IRQ again */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ - outb(0, CS4231P(chip, STATUS)); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ spin_unlock_irqrestore(&chip->reg_lock, flags); snd_cs4231_calibrate_mute(chip, 0); @@ -829,6 +876,7 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t * substream) return snd_pcm_lib_free_pages(substream); } +#ifdef LEGACY_SUPPORT static int snd_cs4231_playback_prepare(snd_pcm_substream_t * substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); @@ -850,6 +898,7 @@ static int snd_cs4231_playback_prepare(snd_pcm_substream_t * substream) #endif return 0; } +#endif /* LEGACY_SUPPORT */ static int snd_cs4231_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) @@ -871,6 +920,7 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t * substream) return snd_pcm_lib_free_pages(substream); } +#ifdef LEGACY_SUPPORT static int snd_cs4231_capture_prepare(snd_pcm_substream_t * substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); @@ -894,6 +944,7 @@ static int snd_cs4231_capture_prepare(snd_pcm_substream_t * substream) spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } +#endif static void snd_cs4231_overrange(cs4231_t *chip) { @@ -940,6 +991,7 @@ void snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(&chip->reg_lock); } +#ifdef LEGACY_SUPPORT static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t * substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); @@ -961,12 +1013,13 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr ptr = chip->c_dma_size - snd_dma_residue(chip->dma2); return bytes_to_frames(substream->runtime, ptr); } +#endif /* LEGACY_SUPPORT */ /* */ -static int snd_cs4231_probe(cs4231_t *chip) +int snd_cs4231_probe(cs4231_t *chip) { unsigned long flags; int i, id, rev; @@ -979,7 +1032,7 @@ static int snd_cs4231_probe(cs4231_t *chip) id = 0; for (i = 0; i < 50; i++) { mb(); - if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) + if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) udelay(2000); else { spin_lock_irqsave(&chip->reg_lock, flags); @@ -1020,8 +1073,8 @@ static int snd_cs4231_probe(cs4231_t *chip) } } spin_lock_irqsave(&chip->reg_lock, flags); - inb(CS4231P(chip, STATUS)); /* clear any pendings IRQ */ - outb(0, CS4231P(chip, STATUS)); + cs4231_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */ + cs4231_outb(chip, CS4231P(STATUS), 0); mb(); spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -1189,6 +1242,7 @@ static int snd_cs4231_playback_open(snd_pcm_substream_t * substream) chip->hardware == CS4231_HW_CS4239) runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; +#ifdef LEGACY_SUPPORT snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max); @@ -1196,14 +1250,20 @@ static int snd_cs4231_playback_open(snd_pcm_substream_t * substream) if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0) return err; } +#endif if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) { +#ifdef LEGACY_SUPPORT if (chip->release_dma) chip->release_dma(chip, chip->dma_private_data, chip->dma1); +#endif snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->playback_substream = substream; +#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT) + chip->p_periods_sent = 0; +#endif snd_pcm_set_sync(substream); chip->rate_constraint(runtime); return 0; @@ -1222,21 +1282,28 @@ static int snd_cs4231_capture_open(snd_pcm_substream_t * substream) chip->hardware == CS4231_HW_CS4239) runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; +#ifdef LEGACY_SUPPORT + snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); + snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); + if (chip->claim_dma) { if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0) return err; } - - snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); - snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); +#endif if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) { +#ifdef LEGACY_SUPPORT if (chip->release_dma) chip->release_dma(chip, chip->dma_private_data, chip->dma2); +#endif snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->capture_substream = substream; +#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT) + chip->c_periods_sent = 0; +#endif snd_pcm_set_sync(substream); chip->rate_constraint(runtime); return 0; @@ -1301,8 +1368,8 @@ static void snd_cs4231_resume(cs4231_t *chip) spin_lock_irqsave(&chip->reg_lock, flags); snd_cs4231_busy_wait(chip); chip->mce_bit &= ~CS4231_MCE; - timeout = inb(CS4231P(chip, REGSEL)); - outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); + timeout = cs4231_inb(chip, CS4231P(REGSEL)); + cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); if (timeout == 0x80) snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port); if ((timeout & CS4231_MCE) == 0 || @@ -1334,6 +1401,8 @@ static int snd_cs4231_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d #endif /* CONFIG_PM */ +#ifdef LEGACY_SUPPORT + static int snd_cs4231_free(cs4231_t *chip) { if (chip->res_port) { @@ -1373,6 +1442,8 @@ static int snd_cs4231_dev_free(snd_device_t *device) return snd_cs4231_free(chip); } +#endif /* LEGACY_SUPPORT */ + const char *snd_cs4231_chip_id(cs4231_t *chip) { switch (chip->hardware) { @@ -1392,6 +1463,35 @@ const char *snd_cs4231_chip_id(cs4231_t *chip) } } +static int snd_cs4231_new(snd_card_t * card, + unsigned short hardware, + unsigned short hwshare, + cs4231_t ** rchip) +{ + cs4231_t *chip; + + *rchip = NULL; + chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + chip->hardware = hardware; + chip->hwshare = hwshare; + + spin_lock_init(&chip->reg_lock); + init_MUTEX(&chip->mce_mutex); + init_MUTEX(&chip->open_mutex); + chip->card = card; + chip->rate_constraint = snd_cs4231_xrate; + chip->set_playback_format = snd_cs4231_playback_format; + chip->set_capture_format = snd_cs4231_capture_format; + memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); + + *rchip = chip; + return 0; +} + +#ifdef LEGACY_SUPPORT + int snd_cs4231_create(snd_card_t * card, unsigned long port, unsigned long cport, @@ -1406,15 +1506,13 @@ int snd_cs4231_create(snd_card_t * card, cs4231_t *chip; int err; - *rchip = NULL; - chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; + err = snd_cs4231_new(card, hardware, hwshare, &chip); + if (err < 0) + return err; + chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; - chip->hardware = hardware; - chip->hwshare = hwshare; if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) { snd_cs4231_free(chip); @@ -1446,15 +1544,6 @@ int snd_cs4231_create(snd_card_t * card, } else chip->dma2 = dma2; - spin_lock_init(&chip->reg_lock); - init_MUTEX(&chip->mce_mutex); - init_MUTEX(&chip->open_mutex); - chip->card = card; - chip->rate_constraint = snd_cs4231_xrate; - chip->set_playback_format = snd_cs4231_playback_format; - chip->set_capture_format = snd_cs4231_capture_format; - memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); - /* global setup */ if (snd_cs4231_probe(chip) < 0) { snd_cs4231_free(chip); @@ -1486,6 +1575,8 @@ int snd_cs4231_create(snd_card_t * card, return 0; } +#endif /* LEGACY_SUPPORT */ + static snd_pcm_ops_t snd_cs4231_playback_ops = { .open = snd_cs4231_playback_open, .close = snd_cs4231_playback_close, @@ -1540,7 +1631,23 @@ int snd_cs4231_pcm(cs4231_t *chip, int device, snd_pcm_t **rpcm) pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, snd_cs4231_chip_id(chip)); +#ifdef LEGACY_SUPPORT snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); +#else +# ifdef EBUS_SUPPORT + if (chip->ebus_flag) { + snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm, + 64*1024, 128*1024); + } else { +# endif +# ifdef SBUS_SUPPORT + snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm, + 64*1024, 128*1024); +# endif +# ifdef EBUS_SUPPORT + } +# endif +#endif chip->pcm = pcm; if (rpcm) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 900b36f66256..67bc35c40661 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -154,10 +154,10 @@ struct _snd_es18xx { #define ES18XX_PM 0x07 #define ES18XX_PM_GPO0 0x01 #define ES18XX_PM_GPO1 0x02 -#define ES18XX_PM_PDR 0x03 -#define ES18XX_PM_ANA 0x04 -#define ES18XX_PM_FM 0x06 -#define ES18XX_PM_SUS 0x08 +#define ES18XX_PM_PDR 0x04 +#define ES18XX_PM_ANA 0x08 +#define ES18XX_PM_FM 0x020 +#define ES18XX_PM_SUS 0x080 typedef struct _snd_es18xx es18xx_t; diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 02830393730e..c01d3ceaad65 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -115,13 +115,15 @@ emu8k_open_dram_for_pcm(emu8000_t *emu, int channels) /* */ static void -snd_emu8000_write_wait(emu8000_t *emu) +snd_emu8000_write_wait(emu8000_t *emu, int can_schedule) { while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - if (signal_pending(current)) - break; + if (can_schedule) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + if (signal_pending(current)) + break; + } } } @@ -457,7 +459,7 @@ static int emu8k_pcm_copy(snd_pcm_substream_t *subs, emu8k_pcm_t *rec = subs->runtime->private_data; emu8000_t *emu = rec->emu; - snd_emu8000_write_wait(emu); + snd_emu8000_write_wait(emu, 1); if (voice == -1) { unsigned short *buf = src; int i, err; @@ -494,7 +496,7 @@ static int emu8k_pcm_silence(snd_pcm_substream_t *subs, emu8k_pcm_t *rec = subs->runtime->private_data; emu8000_t *emu = rec->emu; - snd_emu8000_write_wait(emu); + snd_emu8000_write_wait(emu, 1); if (voice == -1 && rec->voices == 1) voice = 0; if (voice == -1) { @@ -524,7 +526,7 @@ static int emu8k_pcm_copy(snd_pcm_substream_t *subs, emu8000_t *emu = rec->emu; unsigned short *buf = src; - snd_emu8000_write_wait(emu); + snd_emu8000_write_wait(emu, 1); EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); if (rec->voices > 1) EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); @@ -553,7 +555,7 @@ static int emu8k_pcm_silence(snd_pcm_substream_t *subs, emu8k_pcm_t *rec = subs->runtime->private_data; emu8000_t *emu = rec->emu; - snd_emu8000_write_wait(emu); + snd_emu8000_write_wait(emu, 1); EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos); if (rec->voices > 1) EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos); @@ -645,7 +647,7 @@ static int emu8k_pcm_prepare(snd_pcm_substream_t *subs) rec->dram_opened = 1; /* clear loop blanks */ - snd_emu8000_write_wait(rec->emu); + snd_emu8000_write_wait(rec->emu, 0); EMU8000_SMALW_WRITE(rec->emu, rec->offset); for (i = 0; i < LOOP_BLANK_SIZE; i++) EMU8000_SMLD_WRITE(rec->emu, 0); diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6496473e7387..85c2ab2bb234 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -105,7 +105,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x414c4310, 0xfffffff0, "RL5382", NULL }, { 0x414c4320, 0xfffffff0, "RL5383", NULL }, { 0x414c4710, 0xfffffff0, "ALC200/200P", NULL }, -{ 0x414c4720, 0xfffffff0, "ALC650", NULL }, +{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650 }, { 0x414c4730, 0xffffffff, "ALC101", NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL }, @@ -915,6 +915,25 @@ AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31) }; /* + * ALC650 + */ +static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { + AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), + AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), + AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), + AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), + AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0), + AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), + AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), +#if 0 /* always set in patch_alc650 */ + AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), + AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), +#endif +}; + +/* * */ @@ -1340,7 +1359,7 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97) } /* build S/PDIF controls */ - if (ac97->ext_id & AC97_EA_SPDIF) { + if (ac97->ext_id & AC97_EI_SPDIF) { if (ac97->flags & AC97_CS_SPDIF) { for (idx = 0; idx < 3; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) @@ -1379,7 +1398,7 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97) ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF; } - /* build Sigmatel specific controls */ + /* build chip specific controls */ switch (ac97->id) { case AC97_ID_STAC9700: case AC97_ID_STAC9708: @@ -1393,6 +1412,12 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97) if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0) return err; + break; + case AC97_ID_ALC650: + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++) + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0) + return err; + break; default: /* nothing */ break; diff --git a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h index b5b4dc1d9181..7f7ffe24aa0f 100644 --- a/sound/pci/ac97/ac97_id.h +++ b/sound/pci/ac97/ac97_id.h @@ -43,3 +43,4 @@ #define AC97_ID_CS4299 0x43525930 #define AC97_ID_CS4201 0x43525948 #define AC97_ID_CS4205 0x43525958 +#define AC97_ID_ALC650 0x414c4720 diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7b755ec4382d..b9f3f9378071 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -168,7 +168,7 @@ int patch_cirrus_spdif(ac97_t * ac97) ac97->flags |= AC97_CS_SPDIF; ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000; - ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */ + ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080); return 0; } @@ -184,7 +184,7 @@ int patch_cirrus_cs4299(ac97_t * ac97) int patch_conexant(ac97_t * ac97) { ac97->flags |= AC97_CX_SPDIF; - ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */ + ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ return 0; } @@ -336,3 +336,11 @@ int patch_ad1980(ac97_t * ac97) snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | 0x0420); return 0; } + +int patch_alc650(ac97_t * ac97) +{ + /* enable spdif in */ + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, + snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03); + return 0; +} diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index b7ee01f5ea51..317669c7bdec 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -38,3 +38,4 @@ int patch_ad1881(ac97_t * ac97); int patch_ad1885(ac97_t * ac97); int patch_ad1886(ac97_t * ac97); int patch_ad1980(ac97_t * ac97); +int patch_alc650(ac97_t * ac97); diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index c944f71d3fe2..140da1843066 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -233,6 +233,7 @@ struct snd_stru_ali { unsigned long port; unsigned char revision; + unsigned int hw_initialized: 1; struct resource *res_port; struct pci_dev *pci; @@ -1965,7 +1966,8 @@ static void snd_ali_resume(struct pci_dev *dev) static int snd_ali_free(ali_t * codec) { - snd_ali_disable_address_interrupt(codec); + if (codec->hw_initialized) + snd_ali_disable_address_interrupt(codec); if (codec->irq >= 0) { synchronize_irq(codec->irq); free_irq(codec->irq, (void *)codec); @@ -2036,13 +2038,11 @@ static int __devinit snd_ali_resources(ali_t *codec) { snd_ali_printk("resouces allocation ...\n"); if ((codec->res_port = request_region(codec->port, 0x100, "ALI 5451")) == NULL) { - snd_ali_free(codec); snd_printk("Unalbe to request io ports.\n"); return -EBUSY; } if (request_irq(codec->pci->irq, snd_ali_card_interrupt, SA_INTERRUPT|SA_SHIRQ, "ALI 5451", (void *)codec)) { - snd_ali_free(codec); snd_printk("Unable to request irq.\n"); return -EBUSY; } @@ -2112,6 +2112,7 @@ static int __devinit snd_ali_create(snd_card_t * card, pci_set_master(pci); if (snd_ali_resources(codec)) { + snd_ali_free(codec); return -EBUSY; } @@ -2156,7 +2157,6 @@ static int __devinit snd_ali_create(snd_card_t * card, if ((err = snd_ali_chip_init(codec)) < 0) { snd_printk("ali create: chip init error.\n"); - snd_ali_free(codec); return err; } @@ -2167,6 +2167,7 @@ static int __devinit snd_ali_create(snd_card_t * card, #endif snd_ali_enable_address_interrupt(codec); + codec->hw_initialized = 1; *r_ali = codec; snd_ali_printk("created.\n"); diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 618a844c4f4b..a2c05f2bf15f 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -110,6 +110,16 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, snd_card_free(card); return err; } +#ifdef CONFIG_SND_CS46XX_NEW_DSP + if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) { + snd_card_free(card); + return err; + } +#endif if ((err = snd_cs46xx_mixer(chip)) < 0) { snd_card_free(card); return err; @@ -118,6 +128,12 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, snd_card_free(card); return err; } + if ((err = snd_cs46xx_start_dsp(chip)) < 0) { + snd_card_free(card); + return err; + } + + snd_cs46xx_gameport(chip); strcpy(card->driver, "CS46xx"); @@ -132,6 +148,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, snd_card_free(card); return err; } + pci_set_drvdata(pci, chip); dev++; return 0; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 466af9f8673f..efff0b7466d9 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -15,8 +15,8 @@ * TODO: * - Secondary CODEC on some soundcards * - SPDIF input support for other sample rates then 48khz - * - Independent PCM channels for rear output * - Posibility to mix the SPDIF output with analog sources. + * - PCM channels for Center and LFE on secondary codec * * NOTE: with CONFIG_SND_CS46XX_NEW_DSP unset uses old DSP image (which * is default configuration), no SPDIF, no secondary codec, no @@ -269,23 +269,35 @@ static void snd_cs46xx_ac97_write(ac97_t *ac97, unsigned short val) { cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); +#ifndef CONFIG_SND_CS46XX_NEW_DSP int val2 = 0; +#endif int codec_index = -1; /* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */ if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] || chip->nr_ac97_codecs == 0) codec_index = CS46XX_PRIMARY_CODEC_INDEX; - /* UGGLY: nr_ac97_codecs == 0 secondary codec detection is in progress */ + /* UGGLY: nr_ac97_codecs == 1 secondary codec detection is in progress */ else if (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] || chip->nr_ac97_codecs == 1) codec_index = CS46XX_SECONDARY_CODEC_INDEX; else snd_assert(0,return); - chip->active_ctrl(chip, 1); + +#ifndef CONFIG_SND_CS46XX_NEW_DSP if (reg == AC97_CD) val2 = snd_cs46xx_codec_read(chip, AC97_CD, codec_index); +#endif snd_cs46xx_codec_write(chip, reg, val, codec_index); +#ifndef CONFIG_SND_CS46XX_NEW_DSP + /* Benny: I've not found *one* soundcard where + this code below could do any sense, and + with the HW mixering it's anyway broken, with + more then 1 PCM stream the amplifier will not + be turned off by unmuting CD channel. So just + lets skip it. + */ /* * Adjust power if the mixer is selected/deselected according @@ -323,6 +335,7 @@ static void snd_cs46xx_ac97_write(ac97_t *ac97, } chip->active_ctrl(chip, -1); +#endif } @@ -432,9 +445,33 @@ static void snd_cs46xx_reset(cs46xx_t *chip) snd_cs46xx_poke(chip, BA1_FRMT, 0xadf); } +static int cs46xx_wait_for_fifo(cs46xx_t * chip,int retry_timeout) +{ + u32 i, status; + /* + * Make sure the previous FIFO write operation has completed. + */ + for(i = 0; i < 50; i++){ + status = snd_cs46xx_peekBA0(chip, BA0_SERBST); + + if( !(status & SERBST_WBSY) ) + break; + + mdelay(retry_timeout); + } + + if(status & SERBST_WBSY) { + snd_printk( KERN_ERR "cs46xx: failure waiting for FIFO command to complete\n"); + + return -EINVAL; + } + + return 0; +} + static void snd_cs46xx_clear_serial_FIFOs(cs46xx_t *chip) { - int idx, loop, powerdown = 0; + int idx, powerdown = 0; unsigned int tmp; /* @@ -451,24 +488,23 @@ static void snd_cs46xx_clear_serial_FIFOs(cs46xx_t *chip) * We want to clear out the serial port FIFOs so we don't end up playing * whatever random garbage happens to be in them. We fill the sample FIFOS * with zero (silence). - */ + */ snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0); /* * Fill all 256 sample FIFO locations. */ - for (idx = 0; idx < 256; idx++) { + for (idx = 0; idx < 0xFF; idx++) { /* * Make sure the previous FIFO write operation has completed. */ - for (loop = 0; loop < 5; loop++) { - udelay(50); - if (!(snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY)) - break; - } - if (snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY) { + if (cs46xx_wait_for_fifo(chip,1)) { + snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx); + if (powerdown) snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); + + break; } /* * Write the serial port FIFO index. @@ -692,6 +728,8 @@ static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t diff; cs46xx_pcm_t * cpcm; + int buffer_size = runtime->period_size * CS46XX_FRAGS * 4; + cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); diff = runtime->control->appl_ptr - cpcm->appl_ptr; @@ -702,11 +740,11 @@ static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, } cpcm->sw_ready += frames << cpcm->shift; cpcm->appl_ptr = runtime->control->appl_ptr + frames; - while (cpcm->hw_ready < CS46XX_BUFFER_SIZE && + while (cpcm->hw_ready < buffer_size && cpcm->sw_ready > 0) { - size_t hw_to_end = CS46XX_BUFFER_SIZE - cpcm->hw_data; + size_t hw_to_end = buffer_size - cpcm->hw_data; size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data; - size_t bytes = CS46XX_BUFFER_SIZE - cpcm->hw_ready; + size_t bytes = buffer_size - cpcm->hw_ready; if (cpcm->sw_ready < bytes) bytes = cpcm->sw_ready; if (hw_to_end < bytes) @@ -717,7 +755,7 @@ static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, runtime->dma_area + cpcm->sw_data, bytes); cpcm->hw_data += bytes; - if (cpcm->hw_data == CS46XX_BUFFER_SIZE) + if (cpcm->hw_data == buffer_size) cpcm->hw_data = 0; cpcm->sw_data += bytes; if (cpcm->sw_data == cpcm->sw_bufsize) @@ -734,6 +772,7 @@ static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->capt.appl_ptr; + int buffer_size = runtime->period_size * CS46XX_FRAGS * 4; if (diff) { if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; @@ -743,7 +782,7 @@ static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, chip->capt.appl_ptr = runtime->control->appl_ptr + frames; while (chip->capt.hw_ready > 0 && chip->capt.sw_ready < chip->capt.sw_bufsize) { - size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->capt.hw_data; + size_t hw_to_end = buffer_size - chip->capt.hw_data; size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data; size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready; if (chip->capt.hw_ready < bytes) @@ -756,7 +795,7 @@ static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, chip->capt.hw_area + chip->capt.hw_data, bytes); chip->capt.hw_data += bytes; - if (chip->capt.hw_data == CS46XX_BUFFER_SIZE) + if (chip->capt.hw_data == buffer_size) chip->capt.hw_data = 0; chip->capt.sw_data += bytes; if (chip->capt.sw_data == chip->capt.sw_bufsize) @@ -789,6 +828,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_ size_t ptr; cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); ssize_t bytes; + int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4; #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (cpcm->pcm_channel,return -ENXIO); @@ -801,7 +841,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_ bytes = ptr - cpcm->hw_io; if (bytes < 0) - bytes += CS46XX_BUFFER_SIZE; + bytes += buffer_size; cpcm->hw_io = ptr; cpcm->hw_ready -= bytes; cpcm->sw_io += bytes; @@ -823,8 +863,10 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr; ssize_t bytes = ptr - chip->capt.hw_io; + int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4; + if (bytes < 0) - bytes += CS46XX_BUFFER_SIZE; + bytes += buffer_size; chip->capt.hw_io = ptr; chip->capt.hw_ready += bytes; chip->capt.sw_io += bytes; @@ -910,7 +952,9 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, snd_cs46xx_playback_transfer(substream, 0); /* raise playback volume */ - snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0x80008000); + cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb, + chip->dsp_spos_instance->dac_volume_right, + chip->dsp_spos_instance->dac_volume_left); #else if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream, 0); @@ -924,8 +968,9 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: #ifdef CONFIG_SND_CS46XX_NEW_DSP - /* mute channel */ - snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0xffffffff); + /* mute channel */ + cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0); + if (!cpcm->pcm_channel->unlinked) cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel); #else @@ -978,6 +1023,44 @@ static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream, return result; } +static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm, + int sample_rate) +{ + /* if this is the only PCMReaderSCB child under current + SrcTask then there no need to re-create pcm-channel */ + if ( cpcm->pcm_channel->src_scb->ref_count == 1 && + cpcm->pcm_channel->sample_rate != sample_rate && + /* never set a 0 khz sample rate */ + sample_rate) { + /* sample rate not set or we can reuse + the same SRC*/ + cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate); + cpcm->pcm_channel->sample_rate = sample_rate; + } + + /* if there is more then 1 PCMReaderSCB child's under current + SrcTask then we must recreate channel */ + if (cpcm->pcm_channel->sample_rate != sample_rate && + cpcm->pcm_channel->src_scb->ref_count != 1 && + /* never set a 0 khz sample rate */ + sample_rate) { + int unlinked = cpcm->pcm_channel->unlinked; + cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); + + if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, + cpcm->hw_addr, + cpcm->pcm_channel->pcm_channel_id)) == NULL) { + snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n"); + up (&chip->spos_mutex); + return -ENXIO; + } + + if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel); + cpcm->pcm_channel->sample_rate = sample_rate; + } + + return 0; +} static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { @@ -985,27 +1068,88 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; int err; - + cs46xx_t *chip = snd_pcm_substream_chip(substream); + int sample_rate = params_rate(hw_params); + int period_size = params_period_size(hw_params); cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); +#ifdef CONFIG_SND_CS46XX_NEW_DSP + down (&chip->spos_mutex); + + snd_assert (cpcm->pcm_channel != NULL); + + /* if IEC958 is opened in AC3 mode dont adjust SRCTask is not + used so dont adjust sample rate */ + if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL || + !(chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) { + if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) { + return -ENXIO; + } + } + + if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) { + up (&chip->spos_mutex); + return -EINVAL; + } + snd_printdd ("period_size (%d), periods (%d)\n", + period_size, params_periods(hw_params)); +#endif + if (params_periods(hw_params) == CS46XX_FRAGS) { if (runtime->dma_area != cpcm->hw_area) snd_pcm_lib_free_pages(substream); runtime->dma_area = cpcm->hw_area; runtime->dma_addr = cpcm->hw_addr; runtime->dma_bytes = cpcm->hw_size; + + +#ifdef CONFIG_SND_CS46XX_NEW_DSP + if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) { + substream->ops = &snd_cs46xx_playback_ops; + } else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) { + substream->ops = &snd_cs46xx_playback_rear_ops; + } else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) { + substream->ops = &snd_cs46xx_playback_iec958_ops; + } else { + snd_assert(0); + } +#else substream->ops = &snd_cs46xx_playback_ops; +#endif + } else { if (runtime->dma_area == cpcm->hw_area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; } - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) + if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) { +#ifdef CONFIG_SND_CS46XX_NEW_DSP + up (&chip->spos_mutex); +#endif return err; + } + +#ifdef CONFIG_SND_CS46XX_NEW_DSP + if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) { + substream->ops = &snd_cs46xx_playback_indirect_ops; + } else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) { + substream->ops = &snd_cs46xx_playback_indirect_rear_ops; + } else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) { + substream->ops = &snd_cs46xx_playback_indirect_iec958_ops; + } else { + snd_assert(0); + } +#else substream->ops = &snd_cs46xx_playback_indirect_ops; +#endif + } +#ifdef CONFIG_SND_CS46XX_NEW_DSP + up (&chip->spos_mutex); +#endif + return 0; } @@ -1038,35 +1182,10 @@ static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream) cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); #ifdef CONFIG_SND_CS46XX_NEW_DSP - down (&chip->spos_mutex); - - if ( cpcm->pcm_channel->src_scb->ref_count == 1 && - cpcm->pcm_channel->sample_rate != runtime->rate) { - /* sample rate not set or we can reuse - the same SRC*/ - - cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,runtime->rate); - cpcm->pcm_channel->sample_rate = runtime->rate; - } - - if (cpcm->pcm_channel->sample_rate != runtime->rate && - cpcm->pcm_channel->src_scb->ref_count != 1) { - int unlinked = cpcm->pcm_channel->unlinked; - cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); - - if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr)) == NULL) { - snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n"); - up (&chip->spos_mutex); - return -ENXIO; - } - - if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel); - cpcm->pcm_channel->sample_rate = runtime->rate; - } + snd_assert (cpcm->pcm_channel != NULL, return -ENXIO); pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 ); pfie &= ~0x0000f03f; - up (&chip->spos_mutex); #else /* old dsp */ pfie = snd_cs46xx_peek(chip, BA1_PFIE); @@ -1101,6 +1220,7 @@ static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream) cpcm->appl_ptr = 0; #ifdef CONFIG_SND_CS46XX_NEW_DSP + tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2); tmp &= ~0x000003ff; tmp |= (4 << cpcm->shift) - 1; @@ -1128,7 +1248,13 @@ static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream, cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; + int period_size = params_period_size(hw_params); + +#ifdef CONFIG_SND_CS46XX_NEW_DSP + snd_printdd ("capture period size (%d)\n",period_size); + cs46xx_dsp_pcm_ostream_set_period (chip,period_size * 4); +#endif if (runtime->periods == CS46XX_FRAGS) { if (runtime->dma_area != chip->capt.hw_area) snd_pcm_lib_free_pages(substream); @@ -1285,8 +1411,8 @@ static snd_pcm_hardware_t snd_cs46xx_playback = .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (256 * 1024), - .period_bytes_min = CS46XX_PERIOD_SIZE, - .period_bytes_max = CS46XX_PERIOD_SIZE, + .period_bytes_min = CS46XX_MIN_PERIOD_SIZE, + .period_bytes_max = CS46XX_MAX_PERIOD_SIZE, .periods_min = CS46XX_FRAGS, .periods_max = 1024, .fifo_size = 0, @@ -1305,13 +1431,23 @@ static snd_pcm_hardware_t snd_cs46xx_capture = .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (256 * 1024), - .period_bytes_min = CS46XX_PERIOD_SIZE, - .period_bytes_max = CS46XX_PERIOD_SIZE, + .period_bytes_min = CS46XX_MIN_PERIOD_SIZE, + .period_bytes_max = CS46XX_MAX_PERIOD_SIZE, .periods_min = CS46XX_FRAGS, .periods_max = 1024, .fifo_size = 0, }; +static unsigned int period_sizes[] = { 8, 16, 32, 64, 128, 256, 512 }; + +#define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0]) + +static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { + .count = PERIOD_SIZES, + .list = period_sizes, + .mask = 0 +}; + static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) { cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return); @@ -1320,7 +1456,7 @@ static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) snd_magic_kfree(cpcm); } -static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream) +static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) { cs46xx_t *chip = snd_pcm_substream_chip(substream); cs46xx_pcm_t * cpcm; @@ -1342,7 +1478,7 @@ static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream) cpcm->substream = substream; #ifdef CONFIG_SND_CS46XX_NEW_DSP down (&chip->spos_mutex); - cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr); + cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr,pcm_channel_id); if (cpcm->pcm_channel == NULL) { snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n"); @@ -1352,6 +1488,8 @@ static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream) return -ENOMEM; } + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); up (&chip->spos_mutex); #else chip->playback_pcm = cpcm; /* HACK */ @@ -1365,6 +1503,52 @@ static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream) return 0; } +static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream) +{ + snd_printdd("open front channel\n"); + return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL); +} + +#ifdef CONFIG_SND_CS46XX_NEW_DSP +static int snd_cs46xx_playback_open_rear(snd_pcm_substream_t * substream) +{ + snd_printdd("open rear channel\n"); + + return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL); +} + +static int snd_cs46xx_playback_open_iec958(snd_pcm_substream_t * substream) +{ + cs46xx_t *chip = snd_pcm_substream_chip(substream); + + snd_printdd("open raw iec958 channel\n"); + + down (&chip->spos_mutex); + cs46xx_iec958_pre_open (chip); + up (&chip->spos_mutex); + + return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL); +} + +static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream); + +static int snd_cs46xx_playback_close_iec958(snd_pcm_substream_t * substream) +{ + int err; + cs46xx_t *chip = snd_pcm_substream_chip(substream); + + snd_printdd("close raw iec958 channel\n"); + + err = snd_cs46xx_playback_close(substream); + + down (&chip->spos_mutex); + cs46xx_iec958_post_close (chip); + up (&chip->spos_mutex); + + return err; +} +#endif + static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream) { cs46xx_t *chip = snd_pcm_substream_chip(substream); @@ -1375,11 +1559,15 @@ static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream) substream->runtime->hw = snd_cs46xx_capture; if (chip->accept_valid) - substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID; + substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID; chip->active_ctrl(chip, 1); chip->amplifier_ctrl(chip, 1); +#ifdef CONFIG_SND_CS46XX_NEW_DSP + snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); +#endif return 0; } @@ -1422,6 +1610,55 @@ static int snd_cs46xx_capture_close(snd_pcm_substream_t * substream) return 0; } +#ifdef CONFIG_SND_CS46XX_NEW_DSP +snd_pcm_ops_t snd_cs46xx_playback_rear_ops = { + .open = snd_cs46xx_playback_open_rear, + .close = snd_cs46xx_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cs46xx_playback_hw_params, + .hw_free = snd_cs46xx_playback_hw_free, + .prepare = snd_cs46xx_playback_prepare, + .trigger = snd_cs46xx_playback_trigger, + .pointer = snd_cs46xx_playback_direct_pointer, +}; + +snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = { + .open = snd_cs46xx_playback_open_rear, + .close = snd_cs46xx_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cs46xx_playback_hw_params, + .hw_free = snd_cs46xx_playback_hw_free, + .prepare = snd_cs46xx_playback_prepare, + .trigger = snd_cs46xx_playback_trigger, + .copy = snd_cs46xx_playback_copy, + .pointer = snd_cs46xx_playback_indirect_pointer, +}; + +snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = { + .open = snd_cs46xx_playback_open_iec958, + .close = snd_cs46xx_playback_close_iec958, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cs46xx_playback_hw_params, + .hw_free = snd_cs46xx_playback_hw_free, + .prepare = snd_cs46xx_playback_prepare, + .trigger = snd_cs46xx_playback_trigger, + .pointer = snd_cs46xx_playback_direct_pointer, +}; + +snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = { + .open = snd_cs46xx_playback_open_iec958, + .close = snd_cs46xx_playback_close_iec958, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cs46xx_playback_hw_params, + .hw_free = snd_cs46xx_playback_hw_free, + .prepare = snd_cs46xx_playback_prepare, + .trigger = snd_cs46xx_playback_trigger, + .copy = snd_cs46xx_playback_copy, + .pointer = snd_cs46xx_playback_indirect_pointer, +}; + +#endif + snd_pcm_ops_t snd_cs46xx_playback_ops = { .open = snd_cs46xx_playback_open, .close = snd_cs46xx_playback_close, @@ -1476,6 +1713,20 @@ static void snd_cs46xx_pcm_free(snd_pcm_t *pcm) } #ifdef CONFIG_SND_CS46XX_NEW_DSP +static void snd_cs46xx_pcm_rear_free(snd_pcm_t *pcm) +{ + cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + chip->pcm_rear = NULL; + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static void snd_cs46xx_pcm_iec958_free(snd_pcm_t *pcm) +{ + cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + chip->pcm_iec958 = NULL; + snd_pcm_lib_preallocate_free_for_all(pcm); +} + #define MAX_PLAYBACK_CHANNELS (DSP_MAX_PCM_CHANNELS - 1) #else #define MAX_PLAYBACK_CHANNELS 1 @@ -1490,6 +1741,7 @@ int __devinit snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t ** rpcm) *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0) return err; + pcm->private_data = chip; pcm->private_free = snd_cs46xx_pcm_free; @@ -1505,13 +1757,74 @@ int __devinit snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t ** rpcm) if (rpcm) *rpcm = pcm; + + return 0; +} + + +#ifdef CONFIG_SND_CS46XX_NEW_DSP +int __devinit snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t ** rpcm) +{ + snd_pcm_t *pcm; + int err; + + if (rpcm) + *rpcm = NULL; + + if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) + return err; + + pcm->private_data = chip; + pcm->private_free = snd_cs46xx_pcm_rear_free; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_rear_ops); + + /* global setup */ + pcm->info_flags = 0; + strcpy(pcm->name, "CS46xx - Rear"); + chip->pcm_rear = pcm; + + snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + + if (rpcm) + *rpcm = pcm; + return 0; } +int __devinit snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t ** rpcm) +{ + snd_pcm_t *pcm; + int err; + + if (rpcm) + *rpcm = NULL; + + if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0) + return err; + + pcm->private_data = chip; + pcm->private_free = snd_cs46xx_pcm_iec958_free; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_iec958_ops); + + /* global setup */ + pcm->info_flags = 0; + strcpy(pcm->name, "CS46xx - IEC958"); + chip->pcm_rear = pcm; + + snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + + if (rpcm) + *rpcm = pcm; + + return 0; +} +#endif + /* * Mixer routines */ - static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97) { cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); @@ -1534,7 +1847,7 @@ static int snd_cs46xx_vol_info(snd_kcontrol_t *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 32767; + uinfo->value.integer.max = 0x7fff; return 0; } @@ -1556,26 +1869,9 @@ static int snd_cs46xx_vol_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * (0xffff - ucontrol->value.integer.value[1])); unsigned int old = snd_cs46xx_peek(chip, reg); int change = (old != val); + if (change) { snd_cs46xx_poke(chip, reg, val); -#ifdef CONFIG_SND_CS46XX_NEW_DSP - /* NOTE: this updates the current left and right volume - that should be automatically updated by the DSP and - not touched by the host. But for some strange reason - the DSP only updates the right channel volume, so with - this dirty hack we force updating the right and left - channel volume. - */ - snd_cs46xx_poke(chip, reg + 4, val); - - /* shadow the SPDIF input volume */ - if (reg == (ASYNCRX_SCB_ADDR + 0xE) << 2) { - /* FIXME: I known this is uggly ... - any other suggestion ? - */ - chip->dsp_spos_instance->spdif_input_volume = val; - } -#endif } return change; @@ -1583,6 +1879,57 @@ static int snd_cs46xx_vol_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * #ifdef CONFIG_SND_CS46XX_NEW_DSP +static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right; + ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left; + + return 0; +} + +static int snd_cs46xx_vol_dac_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + int change = 0; + + if (chip->dsp_spos_instance->dac_volume_right != ucontrol->value.integer.value[0] || + chip->dsp_spos_instance->dac_volume_left != ucontrol->value.integer.value[1]) { + cs46xx_dsp_set_dac_volume(chip, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1]); + change = 1; + } + + return change; +} + +static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_right; + ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_left; + return 0; +} + +static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + int change = 0; + + if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] || + chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[1]) { + cs46xx_dsp_set_iec958_volume (chip, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1]); + change = 1; + } + + return change; +} + static int snd_mixer_boolean_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { @@ -1600,7 +1947,7 @@ static int snd_cs46xx_iec958_get(snd_kcontrol_t *kcontrol, int reg = kcontrol->private_value; if (reg == CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT) - ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_out; + ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); else ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in; @@ -1615,13 +1962,15 @@ static int snd_cs46xx_iec958_put(snd_kcontrol_t *kcontrol, switch (kcontrol->private_value) { case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT: - change = chip->dsp_spos_instance->spdif_status_out; + down (&chip->spos_mutex); + change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); if (ucontrol->value.integer.value[0] && !change) cs46xx_dsp_enable_spdif_out(chip); else if (change && !ucontrol->value.integer.value[0]) cs46xx_dsp_disable_spdif_out(chip); - res = (change != chip->dsp_spos_instance->spdif_status_out); + res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED)); + up (&chip->spos_mutex); break; case CS46XX_MIXER_SPDIF_INPUT_ELEMENT: change = chip->dsp_spos_instance->spdif_status_in; @@ -1686,6 +2035,35 @@ static int snd_cs46xx_pcm_capture_get(snd_kcontrol_t *kcontrol, return 0; } +static int snd_cs46xx_iec958_ac3_mode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + if (!ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int snd_cs46xx_iec958_ac3_mode_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + int old = ins->spdif_status_out; + + if (ucontrol->value.integer.value[0]) + ins->spdif_status_out |= DSP_SPDIF_STATUS_AC3_MODE; + else + ins->spdif_status_out &= ~DSP_SPDIF_STATUS_AC3_MODE; + + return (old != ins->spdif_status_out); +} + static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { @@ -1720,7 +2098,7 @@ static int snd_herc_spdif_select_get(snd_kcontrol_t *kcontrol, } /* - * Game Theatre XP card - EGPIO[0] is used to select SDPIF input optical or coaxial. + * Game Theatre XP card - EGPIO[0] is used to select SPDIF input optical or coaxial. */ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) @@ -1818,13 +2196,13 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DAC Volume", .info = snd_cs46xx_vol_info, +#ifndef CONFIG_SND_CS46XX_NEW_DSP .get = snd_cs46xx_vol_get, .put = snd_cs46xx_vol_put, - -#ifndef CONFIG_SND_CS46XX_NEW_DSP .private_value = BA1_PVOL, #else - .private_value = (MASTERMIX_SCB_ADDR + 0xE) << 2, + .get = snd_cs46xx_vol_dac_get, + .put = snd_cs46xx_vol_dac_put, #endif }, @@ -1865,6 +2243,13 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC 958 AC3 Mode Switch", + .info = snd_mixer_boolean_info, + .get = snd_cs46xx_iec958_ac3_mode_get, + .put = snd_cs46xx_iec958_ac3_mode_put, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC 958 Input Switch", .info = snd_mixer_boolean_info, .get = snd_cs46xx_iec958_get, @@ -1875,8 +2260,8 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC 958 Input Volume", .info = snd_cs46xx_vol_info, - .get = snd_cs46xx_vol_get, - .put = snd_cs46xx_vol_put, + .get = snd_cs46xx_vol_iec958_get, + .put = snd_cs46xx_vol_iec958_put, .private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2, }, #endif @@ -1927,6 +2312,48 @@ static snd_kcontrol_new_t snd_hercules_controls[] __devinitdata = { .put = snd_herc_spdif_select_put, }, }; + + +static void snd_cs46xx_sec_codec_reset (ac97_t * ac97) +{ + signed long end_time; + int err; + + /* reset to defaults */ + snd_ac97_write(ac97, AC97_RESET, 0); + + /* set codec in extended mode */ + snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3); + + udelay(50); + + /* it's necessary to wait awhile until registers are accessible after RESET */ + /* because the PCM or MASTER volume registers can be modified, */ + /* the REC_GAIN register is used for tests */ + end_time = jiffies + HZ; + do { + unsigned short ext_mid; + + /* use preliminary reads to settle the communication */ + snd_ac97_read(ac97, AC97_RESET); + snd_ac97_read(ac97, AC97_VENDOR_ID1); + snd_ac97_read(ac97, AC97_VENDOR_ID2); + /* modem? */ + ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); + if (ext_mid != 0xffff && (ext_mid & 1) != 0) + return; + + /* test if we can write to the record gain volume register */ + snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); + if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) + return; + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); + } while (time_after_eq(end_time, jiffies)); + + snd_printk("CS46xx secondary codec dont respond!\n"); +} #endif int __devinit snd_cs46xx_mixer(cs46xx_t *chip) @@ -2001,11 +2428,16 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) /* well, one codec only ... */ goto _end; _ok2: + /* set secondary codec in extended mode */ + + /* use custom reset to set secondary codec in + extended mode */ + ac97.reset = snd_cs46xx_sec_codec_reset; + if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) return err; chip->nr_ac97_codecs = 2; - - /* add cs4630 mixer controls */ + _end: /* dosoundcard specific mixer setup */ @@ -2016,6 +2448,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) #endif /* CONFIG_SND_CS46XX_NEW_DSP */ + /* add cs4630 mixer controls */ for (idx = 0; idx < sizeof(snd_cs46xx_controls) / sizeof(snd_cs46xx_controls[0]); idx++) { snd_kcontrol_t *kctl; @@ -2491,10 +2924,8 @@ static int snd_cs46xx_dev_free(snd_device_t *device) /* * initialize chip */ - static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) { - unsigned int tmp; int timeout; /* @@ -2581,6 +3012,11 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, CLKCR1_PLLP | CLKCR1_SWCE); /* + * Enable FIFO Host Bypass + */ + snd_cs46xx_pokeBA0(chip, BA0_SERBCF, SERBCF_HBP); + + /* * Fill the serial port FIFOs with silence. */ snd_cs46xx_clear_serial_FIFOs(chip); @@ -2598,6 +3034,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) snd_cs46xx_pokeBA0(chip, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN); snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE); + #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_cs46xx_pokeBA0(chip, BA0_SERC7, SERC7_ASDI2EN); snd_cs46xx_pokeBA0(chip, BA0_SERC3, 0); @@ -2608,6 +3045,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) mdelay(5); + /* * Wait for the codec ready signal from the AC97 codec. */ @@ -2660,6 +3098,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); #endif + /* * Wait until we've sampled input slots 3 and 4 as valid, meaning that * the codec is pumping ADC data across the AC-link. @@ -2688,7 +3127,10 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) * Now, assert valid frame and the slot 3 and 4 valid bits. This will * commense the transfer of digital audio data to the AC97 codec. */ - snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | ACOSV_SLV7 | ACOSV_SLV8); + + snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | + ACOSV_SLV7 | ACOSV_SLV8); + /* * Power down the DAC and ADC. We will power them up (if) when we need @@ -2703,13 +3145,21 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) /* tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1) & ~CLKCR1_SWCE; */ /* snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); */ + return 0; +} + +/* + * start and load DSP + */ +int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip) +{ + unsigned int tmp; /* - * Reset the processor. - */ + * Reset the processor. + */ snd_cs46xx_reset(chip); - /* - * Download the image to the processor. + * Download the image to the processor. */ #ifdef CONFIG_SND_CS46XX_NEW_DSP #if 0 @@ -2741,7 +3191,6 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) if (cs46xx_dsp_scb_and_task_init(chip) < 0) return -EIO; - snd_printdd("[get here]\n"); #else /* old image */ if (snd_cs46xx_download_image(chip) < 0) { @@ -2775,7 +3224,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) * Enable interrupts on the part. */ snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM); - + tmp = snd_cs46xx_peek(chip, BA1_PFIE); tmp &= ~0x0000f03f; snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */ @@ -2785,19 +3234,24 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait) tmp |= 0x00000001; snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */ +#ifdef CONFIG_SND_CS46XX_NEW_DSP /* set the attenuation to 0dB */ - snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000); - snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000); + snd_cs46xx_poke(chip, (MASTERMIX_SCB_ADDR + 0xE) << 2, 0x80008000); + snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000); + + /* + * Initialize cs46xx SPDIF controller + */ -#ifdef CONFIG_SND_CS46XX_NEW_DSP /* time countdown enable */ cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000000); - + /* SPDIF input MASTER ENABLE */ cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff); - - /* mute spdif out */ - cs46xx_dsp_disable_spdif_out(chip); +#else + /* set the attenuation to 0dB */ + snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000); + snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000); #endif return 0; @@ -2812,15 +3266,26 @@ static void amp_none(cs46xx_t *chip, int change) { } - #ifdef CONFIG_SND_CS46XX_NEW_DSP static int voyetra_setup_eapd_slot(cs46xx_t *chip) { - int i; - u32 idx; - u16 modem_power,pin_config,logic_type,valid_slots,status; + + u32 idx, valid_slots,tmp,powerdown = 0; + u16 modem_power,pin_config,logic_type; + + snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n"); + + /* + * See if the devices are powered down. If so, we must power them up first + * or they will not respond. + */ + tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1); + + if (!(tmp & CLKCR1_SWCE)) { + snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp | CLKCR1_SWCE); + powerdown = 1; + } - snd_printd ("cs46xx: cs46xx_setup_eapd_slot()+\n"); /* * Clear PRA. The Bonzo chip will be used for GPIO not for modem * stuff. @@ -2831,45 +3296,50 @@ static int voyetra_setup_eapd_slot(cs46xx_t *chip) } modem_power = snd_cs46xx_codec_read (chip, - BA0_AC97_EXT_MODEM_POWER, + AC97_EXTENDED_MSTATUS, CS46XX_SECONDARY_CODEC_INDEX); modem_power &=0xFEFF; snd_cs46xx_codec_write(chip, - BA0_AC97_EXT_MODEM_POWER, modem_power, + AC97_EXTENDED_MSTATUS, modem_power, CS46XX_SECONDARY_CODEC_INDEX); /* * Set GPIO pin's 7 and 8 so that they are configured for output. */ pin_config = snd_cs46xx_codec_read (chip, - BA0_AC97_GPIO_PIN_CONFIG, + AC97_GPIO_CFG, CS46XX_SECONDARY_CODEC_INDEX); pin_config &=0x27F; snd_cs46xx_codec_write(chip, - BA0_AC97_GPIO_PIN_CONFIG, pin_config, + AC97_GPIO_CFG, pin_config, CS46XX_SECONDARY_CODEC_INDEX); /* * Set GPIO pin's 7 and 8 so that they are compatible with CMOS logic. */ - logic_type = snd_cs46xx_codec_read(chip, BA0_AC97_GPIO_PIN_TYPE, + logic_type = snd_cs46xx_codec_read(chip, AC97_GPIO_POLARITY, CS46XX_SECONDARY_CODEC_INDEX); logic_type &=0x27F; - snd_cs46xx_codec_write (chip, BA0_AC97_GPIO_PIN_TYPE, logic_type, + snd_cs46xx_codec_write (chip, AC97_GPIO_POLARITY, logic_type, CS46XX_SECONDARY_CODEC_INDEX); valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV); valid_slots |= 0x200; snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots); + if ( cs46xx_wait_for_fifo(chip,1) ) { + snd_printdd("FIFO is busy\n"); + + return -EINVAL; + } + /* * Fill slots 12 with the correct value for the GPIO pins. */ for(idx = 0x90; idx <= 0x9F; idx++) { - /* * Initialize the fifo so that bits 7 and 8 are on. * @@ -2877,25 +3347,16 @@ static int voyetra_setup_eapd_slot(cs46xx_t *chip) * the left. 0x1800 corresponds to bits 7 and 8. */ snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0x1800); - + /* - * Make sure the previous FIFO write operation has completed. + * Wait for command to complete */ - for(i = 0; i < 5; i++){ - status = snd_cs46xx_peekBA0(chip, BA0_SERBST); + if ( cs46xx_wait_for_fifo(chip,200) ) { + snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx); - if( !(status & SERBST_WBSY) ) { - break; - } - mdelay(100); - } - - if(status & SERBST_WBSY) { - snd_printk( KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() " \ - "Failure to write the GPIO pins for slot 12.\n"); return -EINVAL; } - + /* * Write the serial port FIFO index. */ @@ -2907,6 +3368,16 @@ static int voyetra_setup_eapd_slot(cs46xx_t *chip) snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC); } + /* wait for last command to complete */ + cs46xx_wait_for_fifo(chip,200); + + /* + * Now, if we powered up the devices, then power them back down again. + * This is kinda ugly, but should never happen. + */ + if (powerdown) + snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); + return 0; } #endif @@ -2981,6 +3452,18 @@ static void amp_hercules(cs46xx_t *chip, int change) } } +static void voyetra_mixer_init (cs46xx_t *chip) +{ + snd_printdd ("initializing Voyetra mixer\n"); + + /* turnon Amplifier and leave it on */ + chip->amplifier_ctrl(chip, 1); + + /* Enable SPDIF out */ + snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0); + snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIODR_GPOE0); +} + static void hercules_mixer_init (cs46xx_t *chip) { #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -3113,7 +3596,7 @@ struct cs_card_type static struct cs_card_type __initdata cards[] = { {0x1489, 0x7001, "Genius Soundmaker 128 value", NULL, amp_none, NULL, NULL}, - {0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, NULL}, + {0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, voyetra_mixer_init}, {0x1071, 0x6003, "Mitac MI6020/21", NULL, amp_voyetra, NULL, NULL}, {0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init}, {0x1681, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init}, @@ -3286,7 +3769,7 @@ int __devinit snd_cs46xx_create(snd_card_t * card, for (cp = &cards[0]; cp->name; cp++) { if (cp->vendor == ss_vendor && cp->id == ss_card) { - snd_printd("hack for %s enabled\n", cp->name); + snd_printd ("hack for %s enabled\n", cp->name); if (cp->init) cp->init(chip); chip->amplifier_ctrl = cp->amp; @@ -3362,7 +3845,7 @@ int __devinit snd_cs46xx_create(snd_card_t * card, snd_cs46xx_free(chip); return err; } - + chip->active_ctrl(chip, -1); *rchip = chip; diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h index 0517e7f7bfe1..53694dfd5bbb 100644 --- a/sound/pci/cs46xx/cs46xx_lib.h +++ b/sound/pci/cs46xx/cs46xx_lib.h @@ -35,9 +35,17 @@ #define CS46XX_BA1_REG_SIZE 0x0100 -#define CS46XX_PERIOD_SIZE 2048 + +#ifdef CONFIG_SND_CS46XX_NEW_DSP +#define CS46XX_MIN_PERIOD_SIZE 1 +#define CS46XX_MAX_PERIOD_SIZE 1024*1024 +#else +#define CS46XX_MIN_PERIOD_SIZE 2048 +#define CS46XX_MAX_PERIOD_SIZE 2048 +#endif + #define CS46XX_FRAGS 2 -#define CS46XX_BUFFER_SIZE CS46XX_PERIOD_SIZE * CS46XX_FRAGS +/* #define CS46XX_BUFFER_SIZE CS46XX_MAX_PERIOD_SIZE * CS46XX_FRAGS */ #define SCB_NO_PARENT 0 #define SCB_ON_PARENT_NEXT_SCB 1 @@ -51,6 +59,10 @@ extern snd_pcm_ops_t snd_cs46xx_playback_ops; extern snd_pcm_ops_t snd_cs46xx_playback_indirect_ops; extern snd_pcm_ops_t snd_cs46xx_capture_ops; extern snd_pcm_ops_t snd_cs46xx_capture_indirect_ops; +extern snd_pcm_ops_t snd_cs46xx_playback_rear_ops; +extern snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops; +extern snd_pcm_ops_t snd_cs46xx_playback_iec958_ops; +extern snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops; /* @@ -96,6 +108,7 @@ int snd_cs46xx_download (cs46xx_t *chip,u32 *src,unsigned lon unsigned long len); int snd_cs46xx_clear_BA1(cs46xx_t *chip,unsigned long offset,unsigned long len); int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip); +int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip); int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip); int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip); int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip); @@ -185,7 +198,8 @@ dsp_scb_descriptor_t * cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char * dsp_scb_descriptor_t * snoop_scb, dsp_scb_descriptor_t * parent_scb, int scb_child_type); -pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr); +pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr, + int pcm_channel_id); void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip, pcm_channel_descriptor_t * pcm_channel); void cs46xx_dsp_set_src_sample_rate(cs46xx_t * chip,dsp_scb_descriptor_t * src, @@ -194,6 +208,15 @@ int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_de int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel); dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source, u16 addr,char * scb_name); -int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src); -int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src); +int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src); +int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src); +int cs46xx_iec958_pre_open (cs46xx_t *chip); +int cs46xx_iec958_post_close (cs46xx_t *chip); +int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip, + pcm_channel_descriptor_t * pcm_channel, + int period_size); +int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip, + int period_size); +int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left); +int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left); #endif /* __CS46XX_LIB_H__ */ diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index c2c120bc7794..6a3b05de6b1a 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -257,7 +257,10 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip) ins->spdif_in_sample_rate = 48000; /* maximize volume */ - ins->spdif_input_volume = 0x80008000; + ins->dac_volume_right = 0x8000; + ins->dac_volume_left = 0x8000; + ins->spdif_input_volume_right = 0x8000; + ins->spdif_input_volume_left = 0x8000; return ins; } @@ -1017,11 +1020,10 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip) dsp_scb_descriptor_t * codec_in_scb; dsp_scb_descriptor_t * src_task_scb; dsp_scb_descriptor_t * master_mix_scb; + dsp_scb_descriptor_t * rear_mix_scb; dsp_scb_descriptor_t * record_mix_scb; dsp_scb_descriptor_t * write_back_scb; dsp_scb_descriptor_t * vari_decimate_scb; - dsp_scb_descriptor_t * pcm_serial_input_task; - dsp_scb_descriptor_t * asynch_tx_scb; dsp_scb_descriptor_t * sec_codec_out_scb; dsp_scb_descriptor_t * magic_snoop_scb; @@ -1095,6 +1097,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip) ins->the_null_scb->sub_list_ptr = ins->the_null_scb; ins->the_null_scb->next_scb_ptr = ins->the_null_scb; ins->the_null_scb->parent_scb_ptr = NULL; + cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb); } { @@ -1264,9 +1267,9 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip) /* create codec in */ codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0, - CODEC_INPUT_BUF1, - CODECIN_SCB_ADDR,codec_out_scb, - SCB_ON_PARENT_NEXT_SCB); + CODEC_INPUT_BUF1, + CODECIN_SCB_ADDR,codec_out_scb, + SCB_ON_PARENT_NEXT_SCB); if (!codec_in_scb) goto _fail_end; ins->codec_in_scb = codec_in_scb; @@ -1309,46 +1312,38 @@ int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip) /* create secondary CODEC output */ sec_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_II",0x0010,0x0040, - OUTPUTSNOOP_SCB_ADDR, + REAR_MIXER_SCB_ADDR, SEC_CODECOUT_SCB_ADDR,codec_in_scb, SCB_ON_PARENT_NEXT_SCB); if (!sec_codec_out_scb) goto _fail_end; + + /* create the rear PCM channel mixer SCB */ + rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB", + MIX_SAMPLE_BUF3, + REAR_MIXER_SCB_ADDR, + sec_codec_out_scb, + SCB_ON_PARENT_SUBLIST_SCB); + ins->rear_mix_scb = rear_mix_scb; + if (!rear_mix_scb) goto _fail_end; + /* the magic snooper */ magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR, OUTPUT_SNOOP_BUFFER, codec_out_scb, sec_codec_out_scb, - SCB_ON_PARENT_SUBLIST_SCB); + SCB_ON_PARENT_NEXT_SCB); + if (!magic_snoop_scb) goto _fail_end; ins->ref_snoop_scb = magic_snoop_scb; - - /* The asynch. transfer task */ - asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR, - SPDIFO_SCB_INST, - SPDIFO_IP_OUTPUT_BUFFER1, - magic_snoop_scb, - SCB_ON_PARENT_NEXT_SCB); - - if (!asynch_tx_scb) goto _fail_end; - - /* pcm input */ - pcm_serial_input_task = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II", - PCMSERIALINII_SCB_ADDR, - magic_snoop_scb,asynch_tx_scb, - SCB_ON_PARENT_SUBLIST_SCB); - - if (!pcm_serial_input_task) goto _fail_end; - /* SP IO access */ if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR, - asynch_tx_scb, + magic_snoop_scb, SCB_ON_PARENT_NEXT_SCB)) goto _fail_end; - /* SPDIF input sampel rate converter */ src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI", SRC_OUTPUT_BUF1, @@ -1505,6 +1500,7 @@ int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry) }; spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST); + snd_assert(spdifo_scb_desc, return -EIO); spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST); snd_assert(spdifi_scb_desc, return -EIO); @@ -1530,6 +1526,11 @@ int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry) is the FG task tree */ fg_entry->parent_scb_ptr = spdifo_scb_desc; + /* for proc fs */ + cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc); + cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc); + cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc); + /* Async MASTER ENABLE, affects both SPDIF input and output */ snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 ); } @@ -1537,7 +1538,7 @@ int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry) return 0; } -int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip) +int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip) { dsp_spos_instance_t * ins = chip->dsp_spos_instance; @@ -1547,29 +1548,11 @@ int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip) /* SPDIF output MASTER ENABLE */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000); - /* right and left validate bit - NOTE: 0x80000000 and enables the SCMC protection on stream - */ + /* right and left validate bit */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12)); /* monitor state */ - ins->spdif_status_out = 1; - - return 0; -} - -int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip) -{ - dsp_spos_instance_t * ins = chip->dsp_spos_instance; - - /* disable SPDIF output FIFO slot */ - snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0); - - /* SPDIF output MASTER DISABLE */ - cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x0); - - /* monitor state */ - ins->spdif_status_out = 0; + ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED; return 0; } @@ -1605,8 +1588,10 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip) cs46xx_src_link(chip,ins->spdif_in_src); /* restore SPDIF input volume */ - snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xE) << 2, ins->spdif_input_volume); - snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xF) << 2, ins->spdif_input_volume); + cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src, + ins->spdif_input_volume_right, + ins->spdif_input_volume_left); + spin_unlock_irq(&chip->reg_lock); /* set SPDIF input sample rate and unmute @@ -1739,3 +1724,41 @@ int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data) return 0; } + +int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left) +{ + int i; + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + down(&chip->spos_mutex); + + ins->dac_volume_right = right; + ins->dac_volume_left = left; + + for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) { + if (ins->pcm_channels[i].active && + !ins->pcm_channels[i].unlinked) { + cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb, + right,left); + + } + } + + up(&chip->spos_mutex); + + return 0; +} + +int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left) { + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + down(&chip->spos_mutex); + cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src, + right,left); + + ins->spdif_input_volume_right = right; + ins->spdif_input_volume_left = left; + up(&chip->spos_mutex); + + return 0; +} diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index fe5d47bf1907..1dfba850c687 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h @@ -73,7 +73,10 @@ typedef enum { #define SPDIFI_IP_OUTPUT_BUFFER1 0x0E00 #define SPDIFO_IP_OUTPUT_BUFFER1 0x1000 #define MIX_SAMPLE_BUF1 0x1400 -#define MIX_SAMPLE_BUF2 0x3000 +#define MIX_SAMPLE_BUF2 0x2D00 +#define MIX_SAMPLE_BUF3 0x2E00 +#define MIX_SAMPLE_BUF4 0x2F00 +#define MIX_SAMPLE_BUF5 0x3000 /* Task stack address */ #define HFG_STACK 0x066A @@ -104,6 +107,8 @@ typedef enum { #define OUTPUTSNOOPII_SCB_ADDR 0x150 #define PCMSERIALIN_PCM_SCB_ADDR 0x160 #define RECORD_MIXER_SCB_ADDR 0x170 +#define REAR_MIXER_SCB_ADDR 0x180 +#define SPDIF_MIXER_SCB_ADDR 0x190 /* hyperforground SCB's*/ #define HFG_TREE_SCB 0xBA0 @@ -123,6 +128,7 @@ typedef enum { #define SCBfuncEntryPtr 0xA #define SRCCorPerGof 0x2 #define SRCPhiIncr6Int26Frac 0xd +#define SCBVolumeCtrl 0xe /* conf */ #define UseASER1Input 1 @@ -179,5 +185,22 @@ typedef enum { #define SP_SPDOUT_CONTROL 0x804D #define SP_SPDOUT_CSUV 0x808E +static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descriptor_t * scb) +{ + /* update nextSCB and subListPtr in SCB */ + snd_cs46xx_poke(chip, + (scb->address + SCBsubListPtr) << 2, + (scb->sub_list_ptr->address << 0x10) | + (scb->next_scb_ptr->address)); +} + +static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb, + u16 right,u16 left) { + unsigned int val = ((0xffff - right) << 16 | (0xffff - left)); + + snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); + snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); +} + #endif /* __DSP_SPOS_H__ */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */ diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 28a6dfa0b551..b08ba01f51c0 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -150,17 +150,11 @@ static void _dsp_unlink_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb) spin_lock_irqsave(&chip->reg_lock, flags); /* update parent first entry in DSP RAM */ - snd_cs46xx_poke(chip, - (scb->parent_scb_ptr->address + SCBsubListPtr) << 2, - (scb->parent_scb_ptr->sub_list_ptr->address << 0x10) | - (scb->parent_scb_ptr->next_scb_ptr->address)); + cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); /* then update entry in DSP RAM */ - snd_cs46xx_poke(chip, - (scb->address + SCBsubListPtr) << 2, - (scb->sub_list_ptr->address << 0x10) | - (scb->next_scb_ptr->address)); - + cs46xx_dsp_spos_update_scb(chip,scb); + scb->parent_scb_ptr = NULL; spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -173,6 +167,7 @@ static void _dsp_clear_sample_buffer (cs46xx_t *chip, u32 sample_buffer_addr, in for (i = 0; i < dword_count ; ++i ) { writel(0, dst); + dst += 4; } } @@ -328,11 +323,9 @@ _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest, } spin_lock_irqsave(&chip->reg_lock, flags); + /* update entry in DSP RAM */ - snd_cs46xx_poke(chip, - (scb->parent_scb_ptr->address + SCBsubListPtr) << 2, - (scb->parent_scb_ptr->sub_list_ptr->address << 0x10) | - (scb->parent_scb_ptr->next_scb_ptr->address)); + cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -610,7 +603,7 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name, src_buffer_addr << 0x10, 0x04000000, { - 0xffff,0xffff, + 0x8000,0x8000, 0xffff,0xffff } }; @@ -665,7 +658,7 @@ cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name, /* D */ 0, { /* E */ 0x8000,0x8000, - /* F */ 0x8000,0x8000 + /* F */ 0xffff,0xffff } }; @@ -832,7 +825,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest, 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */ /* : Max delta 25 dwords == 100 bytes */ 0,hfg_scb_address, /* Point to HFG task SCB */ - 0,0, /* Initialize current Delta and Consumer ptr adjustment count */ + 0,0, /* Initialize current Delta and Consumer ptr adjustment count */ 0, /* Initialize accumulated Phi to 0 */ 0,0x2aab, /* Const 1/3 */ @@ -847,13 +840,13 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest, RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */ (asynch_buffer_address) << 0x10, /* This should be automagically synchronized - to the producer pointer */ + to the producer pointer */ /* There is no correct initial value, it will depend upon the detected rate etc */ 0x18000000, /* Phi increment for approx 32k operation */ 0x8000,0x8000, /* Volume controls are unused at this time */ - 0x8000,0x8000 + 0xffff,0xffff }; scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb, @@ -1093,15 +1086,46 @@ static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = { }; -pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr) +pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip, + u32 sample_rate, void * private_data, + u32 hw_dma_addr, + int pcm_channel_id) { dsp_spos_instance_t * ins = chip->dsp_spos_instance; - dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb; + dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL; /*dsp_scb_descriptor_t * pcm_parent_scb;*/ char scb_name[DSP_MAX_SCB_NAME]; int i,pcm_index = -1, insert_point, src_index = -1; unsigned long flags; + switch (pcm_channel_id) { + case DSP_PCM_MAIN_CHANNEL: + mixer_scb = ins->master_mix_scb; + break; + case DSP_PCM_REAR_CHANNEL: + mixer_scb = ins->rear_mix_scb; + break; + case DSP_PCM_CENTER_CHANNEL: + /* TODO */ + snd_assert(0); + break; + case DSP_PCM_LFE_CHANNEL: + /* TODO */ + snd_assert(0); + break; + case DSP_IEC958_CHANNEL: + snd_assert (ins->asynch_tx_scb != NULL, return NULL); + mixer_scb = ins->asynch_tx_scb; + if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) { + snd_printdd ("IEC958 opened in AC3 mode\n"); + /*src_scb = ins->asynch_tx_scb; + ins->asynch_tx_scb->ref_count ++;*/ + } + break; + default: + snd_assert (0); + return NULL; + } /* default sample rate is 44100 */ if (!sample_rate) sample_rate = 44100; @@ -1114,7 +1138,9 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue; if (ins->pcm_channels[i].active) { - if (!src_scb && ins->pcm_channels[i].sample_rate == sample_rate) { + if (!src_scb && + ins->pcm_channels[i].sample_rate == sample_rate && + ins->pcm_channels[i].mixer_scb == mixer_scb) { src_scb = ins->pcm_channels[i].src_scb; ins->pcm_channels[i].src_scb->ref_count ++; src_index = ins->pcm_channels[i].src_slot; @@ -1148,11 +1174,11 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa snd_assert (src_index != -1,return NULL); /* we need to create a new SRC SCB */ - if (ins->master_mix_scb->sub_list_ptr == ins->the_null_scb) { - src_parent_scb = ins->master_mix_scb; + if (mixer_scb->sub_list_ptr == ins->the_null_scb) { + src_parent_scb = mixer_scb; insert_point = SCB_ON_PARENT_SUBLIST_SCB; } else { - src_parent_scb = find_next_free_scb(chip,ins->master_mix_scb->sub_list_ptr); + src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr); insert_point = SCB_ON_PARENT_NEXT_SCB; } @@ -1172,7 +1198,9 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa return NULL; } - cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); + if (pcm_channel_id != DSP_IEC958_CHANNEL || + !(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) + cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); ins->nsrc_scb ++; } @@ -1180,7 +1208,8 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index); - snd_printdd( "dsp_spos: creating PCM \"%s\"\n",scb_name); + snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name, + pcm_channel_id); pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name, pcm_reader_buffer_addr[pcm_index], @@ -1206,12 +1235,91 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sa ins->pcm_channels[pcm_index].src_slot = src_index; ins->pcm_channels[pcm_index].active = 1; ins->pcm_channels[pcm_index].pcm_slot = pcm_index; + ins->pcm_channels[pcm_index].mixer_scb = mixer_scb; + ins->pcm_channels[pcm_index].pcm_channel_id = pcm_channel_id; ins->npcm_channels ++; spin_unlock_irqrestore(&chip->reg_lock, flags); return (ins->pcm_channels + pcm_index); } +int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip, + pcm_channel_descriptor_t * pcm_channel, + int period_size) +{ + u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2); + temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK; + + switch (period_size) { + case 2048: + temp |= DMA_RQ_C1_SOURCE_MOD1024; + break; + case 1024: + temp |= DMA_RQ_C1_SOURCE_MOD512; + break; + case 512: + temp |= DMA_RQ_C1_SOURCE_MOD256; + break; + case 256: + temp |= DMA_RQ_C1_SOURCE_MOD128; + break; + case 128: + temp |= DMA_RQ_C1_SOURCE_MOD64; + break; + case 64: + temp |= DMA_RQ_C1_SOURCE_MOD32; + break; + case 32: + temp |= DMA_RQ_C1_SOURCE_MOD16; + break; + default: + snd_printdd ("period size (%d) not supported by HW\n"); + return -EINVAL; + } + + snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp); + + return 0; +} + +int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip, + int period_size) +{ + u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2); + temp &= ~DMA_RQ_C1_DEST_SIZE_MASK; + + switch (period_size) { + case 2048: + temp |= DMA_RQ_C1_DEST_MOD1024; + break; + case 1024: + temp |= DMA_RQ_C1_DEST_MOD512; + break; + case 512: + temp |= DMA_RQ_C1_DEST_MOD256; + break; + case 256: + temp |= DMA_RQ_C1_DEST_MOD128; + break; + case 128: + temp |= DMA_RQ_C1_DEST_MOD64; + break; + case 64: + temp |= DMA_RQ_C1_DEST_MOD32; + break; + case 32: + temp |= DMA_RQ_C1_DEST_MOD16; + break; + default: + snd_printdd ("period size (%d) not supported by HW\n"); + return -EINVAL; + } + + snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp); + + return 0; +} + void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel) { dsp_spos_instance_t * ins = chip->dsp_spos_instance; @@ -1293,17 +1401,13 @@ int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel) snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; ); pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; - /* update entry in DSP RAM */ spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs46xx_poke(chip, - (pcm_channel->pcm_reader_scb->address + SCBsubListPtr) << 2, - (pcm_channel->pcm_reader_scb->sub_list_ptr->address << 0x10) | - (pcm_channel->pcm_reader_scb->next_scb_ptr->address)); - - snd_cs46xx_poke(chip, - (parent_scb->address + SCBsubListPtr) << 2, - (parent_scb->sub_list_ptr->address << 0x10) | - (parent_scb->next_scb_ptr->address)); + + /* update SCB entry in DSP RAM */ + cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); + + /* update parent SCB entry */ + cs46xx_dsp_spos_update_scb(chip,parent_scb); pcm_channel->unlinked = 0; spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -1358,14 +1462,16 @@ void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u spin_lock_irqsave(&chip->reg_lock, flags); /* mute SCB */ - snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff); + /* cs46xx_dsp_scb_set_volume (chip,src,0,0); */ + snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr); /* raise volume */ - snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0x80008000); + /* cs46xx_dsp_scb_set_volume (chip,src,0x7fff,0x7fff); */ + spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -1399,7 +1505,7 @@ int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src) snd_assert (src->parent_scb_ptr != NULL, return -EINVAL ); /* mute SCB */ - snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff); + cs46xx_dsp_scb_set_volume (chip,src,0,0); _dsp_unlink_scb (chip,src); @@ -1425,10 +1531,144 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src) src->parent_scb_ptr = parent_scb; /* update entry in DSP RAM */ - snd_cs46xx_poke(chip, - (parent_scb->address + SCBsubListPtr) << 2, - (parent_scb->sub_list_ptr->address << 0x10) | - (parent_scb->next_scb_ptr->address)); + cs46xx_dsp_spos_update_scb(chip,parent_scb); + + return 0; +} + +int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip) +{ + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) { + cs46xx_dsp_enable_spdif_hw (chip); + } + + /* dont touch anything if SPDIF is open */ + if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) { + /* when cs46xx_iec958_post_close(...) is called it + will call this function if necesary depending on + this bit */ + ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED; + + return -EBUSY; + } + + snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL); + snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL); + + /* reset output snooper sample buffer pointer */ + snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2, + (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 ); + + /* The asynch. transfer task */ + ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR, + SPDIFO_SCB_INST, + SPDIFO_IP_OUTPUT_BUFFER1, + ins->master_mix_scb, + SCB_ON_PARENT_NEXT_SCB); + if (!ins->asynch_tx_scb) return -ENOMEM; + + ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II", + PCMSERIALINII_SCB_ADDR, + ins->ref_snoop_scb, + ins->asynch_tx_scb, + SCB_ON_PARENT_SUBLIST_SCB); + + if (!ins->spdif_pcm_input_scb) return -ENOMEM; + + /* monitor state */ + ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED; + + return 0; +} + +int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip) +{ + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + /* dont touch anything if SPDIF is open */ + if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) { + ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED; + return -EBUSY; + } + + /* check integrety */ + snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL); + snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL); + snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL); + snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL); + + cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb); + cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb); + + ins->spdif_pcm_input_scb = NULL; + ins->asynch_tx_scb = NULL; + + /* clear buffer to prevent any undesired noise */ + _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256); + + /* monitor state */ + ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED; + + + return 0; +} + +int cs46xx_iec958_pre_open (cs46xx_t *chip) +{ + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) { + /* remove AsynchFGTxSCB and and PCMSerialInput_II */ + cs46xx_dsp_disable_spdif_out (chip); + + /* save state */ + ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED; + } + + /* if not enabled already */ + if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { + cs46xx_dsp_enable_spdif_hw (chip); + } + + /* Create the asynch. transfer task for playback */ + ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR, + SPDIFO_SCB_INST, + SPDIFO_IP_OUTPUT_BUFFER1, + ins->master_mix_scb, + SCB_ON_PARENT_NEXT_SCB); + + + if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) + /* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */ + cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1); + + ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN; + + return 0; +} + +int cs46xx_iec958_post_close (cs46xx_t *chip) +{ + dsp_spos_instance_t * ins = chip->dsp_spos_instance; + + snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL); + + ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN; + + /* restore settings */ + cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12)); + + /* deallocate stuff */ + cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb); + ins->asynch_tx_scb = NULL; + + /* restore state */ + if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) { + cs46xx_dsp_enable_spdif_out (chip); + } + return 0; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 99613539adbb..12933f97c860 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -37,6 +37,7 @@ #endif #define SNDRV_GET_ID #include <sound/initval.h> +#include <sound/asoundef.h> #define chip_t ensoniq_t @@ -109,66 +110,70 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #define ES_REG_CONTROL 0x00 /* R/W: Interrupt/Chip select control register */ #define ES_1370_ADC_STOP (1<<31) /* disable capture buffer transfers */ #define ES_1370_XCTL1 (1<<30) /* general purpose output bit */ -#define ES_1371_SPDIF_EN (1<<26) /* SPDIF enable */ -#define ES_1371_JOY_ASEL(o) (((o)&0x03)<<24) /* joystick port mapping */ +#define ES_1373_TEST_BIT (1<<29) /* should be set to 0 for normal operation */ +#define ES_1373_RECEN_B (1<<28) /* mix record with playback for I2S/SPDIF out */ +#define ES_1373_SPDIF_THRU (1<<26) /* 0 = SPDIF thru mode, 1 = SPDIF == dig out */ +#define ES_1371_JOY_ASEL(o) (((o)&0x03)<<24)/* joystick port mapping */ #define ES_1371_JOY_ASELM (0x03<<24) /* mask for above */ #define ES_1371_JOY_ASELI(i) (((i)>>24)&0x03) -#define ES_1371_GPIO_IN(i) (((i)>>20)&0x0f) /* GPIO in [3:0] pins - R/O */ -#define ES_1370_PCLKDIVO(o) (((o)&0x1fff)<<16) /* clock divide ratio for DAC2 */ +#define ES_1371_GPIO_IN(i) (((i)>>20)&0x0f)/* GPIO in [3:0] pins - R/O */ +#define ES_1370_PCLKDIVO(o) (((o)&0x1fff)<<16)/* clock divide ratio for DAC2 */ #define ES_1370_PCLKDIVM ((0x1fff)<<16) /* mask for above */ -#define ES_1370_PCLKDIVI(i) (((i)>>16)&0x1fff) /* clock divide ratio for DAC2 */ -#define ES_1371_GPIO_OUT(o) (((o)&0x0f)<<16) /* GPIO out [3:0] pins - W/R */ +#define ES_1370_PCLKDIVI(i) (((i)>>16)&0x1fff)/* clock divide ratio for DAC2 */ +#define ES_1371_GPIO_OUT(o) (((o)&0x0f)<<16)/* GPIO out [3:0] pins - W/R */ #define ES_1371_GPIO_OUTM (0x0f<<16) /* mask for above */ #define ES_MSFMTSEL (1<<15) /* MPEG serial data format; 0 = SONY, 1 = I2S */ #define ES_1370_M_SBB (1<<14) /* clock source for DAC - 0 = clock generator; 1 = MPEG clocks */ #define ES_1371_SYNC_RES (1<<14) /* Warm AC97 reset */ -#define ES_1370_WTSRSEL(o) (((o)&0x03)<<12) /* fixed frequency clock for DAC1 */ +#define ES_1370_WTSRSEL(o) (((o)&0x03)<<12)/* fixed frequency clock for DAC1 */ #define ES_1370_WTSRSELM (0x03<<12) /* mask for above */ #define ES_1371_ADC_STOP (1<<13) /* disable CCB transfer capture information */ #define ES_1371_PWR_INTRM (1<<12) /* power level change interrupts enable */ #define ES_1370_DAC_SYNC (1<<11) /* DAC's are synchronous */ -#define ES_1371_M_CB (1<<11) /* capture clock source; 0 = ADC; 1 = I2S */ +#define ES_1371_M_CB (1<<11) /* capture clock source; 0 = AC'97 ADC; 1 = I2S */ #define ES_CCB_INTRM (1<<10) /* CCB voice interrupts enable */ -#define ES_1370_M_CB (1<<9) /* capture clock source; 0 = ADC; 1 = MPEG */ -#define ES_1370_XCTL0 (1<<8) /* generap purpose output bit */ -#define ES_1371_PDLEV(o) (((o)&0x03)<<8) /* current power down level */ +#define ES_1370_M_CB (1<<9) /* capture clock source; 0 = ADC; 1 = MPEG */ +#define ES_1370_XCTL0 (1<<8) /* generap purpose output bit */ +#define ES_1371_PDLEV(o) (((o)&0x03)<<8) /* current power down level */ #define ES_1371_PDLEVM (0x03<<8) /* mask for above */ -#define ES_BREQ (1<<7) /* memory bus request enable */ -#define ES_DAC1_EN (1<<6) /* DAC1 playback channel enable */ -#define ES_DAC2_EN (1<<5) /* DAC2 playback channel enable */ -#define ES_ADC_EN (1<<4) /* ADC capture channel enable */ -#define ES_UART_EN (1<<3) /* UART enable */ -#define ES_JYSTK_EN (1<<2) /* Joystick module enable */ -#define ES_1370_CDC_EN (1<<1) /* Codec interface enable */ -#define ES_1371_XTALCKDIS (1<<1) /* Xtal clock disable */ -#define ES_1370_SERR_DISABLE (1<<0) /* PCI serr signal disable */ -#define ES_1371_PCICLKDIS (1<<0) /* PCI clock disable */ +#define ES_BREQ (1<<7) /* memory bus request enable */ +#define ES_DAC1_EN (1<<6) /* DAC1 playback channel enable */ +#define ES_DAC2_EN (1<<5) /* DAC2 playback channel enable */ +#define ES_ADC_EN (1<<4) /* ADC capture channel enable */ +#define ES_UART_EN (1<<3) /* UART enable */ +#define ES_JYSTK_EN (1<<2) /* Joystick module enable */ +#define ES_1370_CDC_EN (1<<1) /* Codec interface enable */ +#define ES_1371_XTALCKDIS (1<<1) /* Xtal clock disable */ +#define ES_1370_SERR_DISABLE (1<<0) /* PCI serr signal disable */ +#define ES_1371_PCICLKDIS (1<<0) /* PCI clock disable */ #define ES_REG_STATUS 0x04 /* R/O: Interrupt/Chip select status register */ -#define ES_INTR (1<<31) /* Interrupt is pending */ -#define ES_1371_ST_AC97_RST (1<<29) /* CT5880 AC'97 Reset bit */ -#define ES_1371_ST_SPDIF_EN (1<<18) /* SPDIF enable */ -#define ES_1371_ST_SPDIF_TEST (1<<17) /* SPDIF test */ -#define ES_1371_TEST (1<<16) /* test ASIC */ -#define ES_1370_CSTAT (1<<10) /* CODEC is busy or register write in progress */ -#define ES_1370_CBUSY (1<<9) /* CODEC is busy */ -#define ES_1370_CWRIP (1<<8) /* CODEC register write in progress */ -#define ES_1371_SYNC_ERR (1<<8) /* CODEC synchronization error occured */ -#define ES_1371_VC(i) (((i)>>6)&0x03) /* voice code from CCB module */ -#define ES_1370_VC(i) (((i)>>5)&0x03) /* voice code from CCB module */ -#define ES_1371_MPWR (1<<5) /* power level interrupt pending */ -#define ES_MCCB (1<<4) /* CCB interrupt pending */ -#define ES_UART (1<<3) /* UART interrupt pending */ -#define ES_DAC1 (1<<2) /* DAC1 channel interrupt pending */ -#define ES_DAC2 (1<<1) /* DAC2 channel interrupt pending */ -#define ES_ADC (1<<0) /* ADC channel interrupt pending */ +#define ES_INTR (1<<31) /* Interrupt is pending */ +#define ES_1371_ST_AC97_RST (1<<29) /* CT5880 AC'97 Reset bit */ +#define ES_1373_GPIO_INT_EN(o)(((o)&0x0f)<<20)/* GPIO [3:0] pins - interrupt enable */ +#define ES_1373_SPDIF_EN (1<<18) /* SPDIF enable */ +#define ES_1373_SPDIF_TEST (1<<17) /* SPDIF test */ +#define ES_1371_TEST (1<<16) /* test ASIC */ +#define ES_1373_GPIO_INT(i) (((i)&0x0f)>>12)/* GPIO [3:0] pins - interrupt pending */ +#define ES_1370_CSTAT (1<<10) /* CODEC is busy or register write in progress */ +#define ES_1370_CBUSY (1<<9) /* CODEC is busy */ +#define ES_1370_CWRIP (1<<8) /* CODEC register write in progress */ +#define ES_1371_SYNC_ERR (1<<8) /* CODEC synchronization error occured */ +#define ES_1371_VC(i) (((i)>>6)&0x03) /* voice code from CCB module */ +#define ES_1370_VC(i) (((i)>>5)&0x03) /* voice code from CCB module */ +#define ES_1371_MPWR (1<<5) /* power level interrupt pending */ +#define ES_MCCB (1<<4) /* CCB interrupt pending */ +#define ES_UART (1<<3) /* UART interrupt pending */ +#define ES_DAC1 (1<<2) /* DAC1 channel interrupt pending */ +#define ES_DAC2 (1<<1) /* DAC2 channel interrupt pending */ +#define ES_ADC (1<<0) /* ADC channel interrupt pending */ #define ES_REG_UART_DATA 0x08 /* R/W: UART data register */ #define ES_REG_UART_STATUS 0x09 /* R/O: UART status register */ -#define ES_RXINT (1<<7) /* RX interrupt occured */ -#define ES_TXINT (1<<2) /* TX interrupt occured */ -#define ES_TXRDY (1<<1) /* transmitter ready */ -#define ES_RXRDY (1<<0) /* receiver ready */ +#define ES_RXINT (1<<7) /* RX interrupt occured */ +#define ES_TXINT (1<<2) /* TX interrupt occured */ +#define ES_TXRDY (1<<1) /* transmitter ready */ +#define ES_RXRDY (1<<0) /* receiver ready */ #define ES_REG_UART_CONTROL 0x09 /* W/O: UART control register */ -#define ES_RXINTEN (1<<7) /* RX interrupt enable */ +#define ES_RXINTEN (1<<7) /* RX interrupt enable */ #define ES_TXINTENO(o) (((o)&0x03)<<5) /* TX interrupt enable */ #define ES_TXINTENM (0x03<<5) /* mask for above */ #define ES_TXINTENI(i) (((i)>>5)&0x03) @@ -191,29 +196,29 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #define ES_1371_CODEC_READ(i) (((i)>>0)&0xffff) #define ES_REG_1371_SMPRATE 0x10 /* W/R: Codec rate converter interface register */ -#define ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25) /* address of the sample rate converter */ +#define ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25)/* address of the sample rate converter */ #define ES_1371_SRC_RAM_ADDRM (0x7f<<25) /* mask for above */ -#define ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f) /* address of the sample rate converter */ +#define ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f)/* address of the sample rate converter */ #define ES_1371_SRC_RAM_WE (1<<24) /* R/W: read/write control for sample rate converter */ #define ES_1371_SRC_RAM_BUSY (1<<23) /* R/O: sample rate memory is busy */ #define ES_1371_SRC_DISABLE (1<<22) /* sample rate converter disable */ #define ES_1371_DIS_P1 (1<<21) /* playback channel 1 accumulator update disable */ #define ES_1371_DIS_P2 (1<<20) /* playback channel 1 accumulator update disable */ #define ES_1371_DIS_R1 (1<<19) /* capture channel accumulator update disable */ -#define ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0) /* current value of the sample rate converter */ +#define ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0)/* current value of the sample rate converter */ #define ES_1371_SRC_RAM_DATAM (0xffff<<0) /* mask for above */ -#define ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff) /* current value of the sample rate converter */ +#define ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff)/* current value of the sample rate converter */ #define ES_REG_1371_LEGACY 0x18 /* W/R: Legacy control/status register */ #define ES_1371_JFAST (1<<31) /* fast joystick timing */ #define ES_1371_HIB (1<<30) /* host interrupt blocking enable */ #define ES_1371_VSB (1<<29) /* SB; 0 = addr 0x220xH, 1 = 0x22FxH */ -#define ES_1371_VMPUO(o) (((o)&0x03)<<27) /* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */ +#define ES_1371_VMPUO(o) (((o)&0x03)<<27)/* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */ #define ES_1371_VMPUM (0x03<<27) /* mask for above */ -#define ES_1371_VMPUI(i) (((i)>>27)&0x03) /* base register address */ -#define ES_1371_VCDCO(o) (((o)&0x03)<<25) /* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */ +#define ES_1371_VMPUI(i) (((i)>>27)&0x03)/* base register address */ +#define ES_1371_VCDCO(o) (((o)&0x03)<<25)/* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */ #define ES_1371_VCDCM (0x03<<25) /* mask for above */ -#define ES_1371_VCDCI(i) (((i)>>25)&0x03) /* CODEC address */ +#define ES_1371_VCDCI(i) (((i)>>25)&0x03)/* CODEC address */ #define ES_1371_FIRQ (1<<24) /* force an interrupt */ #define ES_1371_SDMACAP (1<<23) /* enable event capture for slave DMA controller */ #define ES_1371_SPICAP (1<<22) /* enable event capture for slave IRQ controller */ @@ -223,36 +228,38 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #define ES_1371_SVCAP (1<<18) /* enable event capture for SB registers */ #define ES_1371_CDCCAP (1<<17) /* enable event capture for CODEC registers */ #define ES_1371_BACAP (1<<16) /* enable event capture for SoundScape base address */ -#define ES_1371_EXI(i) (((i)>>8)&0x07) /* event number */ -#define ES_1371_AI(i) (((i)>>3)&0x1f) /* event significant I/O address */ +#define ES_1371_EXI(i) (((i)>>8)&0x07) /* event number */ +#define ES_1371_AI(i) (((i)>>3)&0x1f) /* event significant I/O address */ #define ES_1371_WR (1<<2) /* event capture; 0 = read; 1 = write */ #define ES_1371_LEGINT (1<<0) /* interrupt for legacy events; 0 = interrupt did occur */ +#define ES_REG_CHANNEL_STATUS 0x1c /* R/W: first 32-bits from S/PDIF channel status block, es1373 */ + #define ES_REG_SERIAL 0x20 /* R/W: Serial interface control register */ #define ES_1371_DAC_TEST (1<<22) /* DAC test mode enable */ -#define ES_P2_END_INCO(o) (((o)&0x07)<<19) /* binary offset value to increment / loop end */ +#define ES_P2_END_INCO(o) (((o)&0x07)<<19)/* binary offset value to increment / loop end */ #define ES_P2_END_INCM (0x07<<19) /* mask for above */ -#define ES_P2_END_INCI(i) (((i)>>16)&0x07) /* binary offset value to increment / loop end */ -#define ES_P2_ST_INCO(o) (((o)&0x07)<<16) /* binary offset value to increment / start */ +#define ES_P2_END_INCI(i) (((i)>>16)&0x07)/* binary offset value to increment / loop end */ +#define ES_P2_ST_INCO(o) (((o)&0x07)<<16)/* binary offset value to increment / start */ #define ES_P2_ST_INCM (0x07<<16) /* mask for above */ -#define ES_P2_ST_INCI(i) (((i)<<16)&0x07) /* binary offset value to increment / start */ +#define ES_P2_ST_INCI(i) (((i)<<16)&0x07)/* binary offset value to increment / start */ #define ES_R1_LOOP_SEL (1<<15) /* ADC; 0 - loop mode; 1 = stop mode */ #define ES_P2_LOOP_SEL (1<<14) /* DAC2; 0 - loop mode; 1 = stop mode */ #define ES_P1_LOOP_SEL (1<<13) /* DAC1; 0 - loop mode; 1 = stop mode */ #define ES_P2_PAUSE (1<<12) /* DAC2; 0 - play mode; 1 = pause mode */ #define ES_P1_PAUSE (1<<11) /* DAC1; 0 - play mode; 1 = pause mode */ #define ES_R1_INT_EN (1<<10) /* ADC interrupt enable */ -#define ES_P2_INT_EN (1<<9) /* DAC2 interrupt enable */ -#define ES_P1_INT_EN (1<<8) /* DAC1 interrupt enable */ -#define ES_P1_SCT_RLD (1<<7) /* force sample counter reload for DAC1 */ -#define ES_P2_DAC_SEN (1<<6) /* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */ -#define ES_R1_MODEO(o) (((o)&0x03)<<4) /* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */ +#define ES_P2_INT_EN (1<<9) /* DAC2 interrupt enable */ +#define ES_P1_INT_EN (1<<8) /* DAC1 interrupt enable */ +#define ES_P1_SCT_RLD (1<<7) /* force sample counter reload for DAC1 */ +#define ES_P2_DAC_SEN (1<<6) /* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */ +#define ES_R1_MODEO(o) (((o)&0x03)<<4) /* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */ #define ES_R1_MODEM (0x03<<4) /* mask for above */ #define ES_R1_MODEI(i) (((i)>>4)&0x03) -#define ES_P2_MODEO(o) (((o)&0x03)<<2) /* DAC2 mode; -- '' -- */ +#define ES_P2_MODEO(o) (((o)&0x03)<<2) /* DAC2 mode; -- '' -- */ #define ES_P2_MODEM (0x03<<2) /* mask for above */ #define ES_P2_MODEI(i) (((i)>>2)&0x03) -#define ES_P1_MODEO(o) (((o)&0x03)<<0) /* DAC1 mode; -- '' -- */ +#define ES_P1_MODEO(o) (((o)&0x03)<<0) /* DAC1 mode; -- '' -- */ #define ES_P1_MODEM (0x03<<0) /* mask for above */ #define ES_P1_MODEI(i) (((i)>>0)&0x03) @@ -386,6 +393,10 @@ struct _snd_ensoniq { snd_rawmidi_substream_t *midi_input; snd_rawmidi_substream_t *midi_output; + unsigned int spdif; + unsigned int spdif_default; + unsigned int spdif_stream; + snd_info_entry_t *proc_entry; #ifdef CHIP1370 @@ -1032,6 +1043,10 @@ static int snd_ensoniq_playback1_open(snd_pcm_substream_t * substream) ensoniq->playback1_substream = substream; runtime->hw = snd_ensoniq_playback1; snd_pcm_set_sync(substream); + spin_lock_irq(&ensoniq->reg_lock); + if (ensoniq->spdif && ensoniq->playback2_substream == NULL) + ensoniq->spdif_stream = ensoniq->spdif_default; + spin_unlock_irq(&ensoniq->reg_lock); #ifdef CHIP1370 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_es1370_hw_constraints_rates); @@ -1051,6 +1066,10 @@ static int snd_ensoniq_playback2_open(snd_pcm_substream_t * substream) ensoniq->playback2_substream = substream; runtime->hw = snd_ensoniq_playback2; snd_pcm_set_sync(substream); + spin_lock_irq(&ensoniq->reg_lock); + if (ensoniq->spdif && ensoniq->playback1_substream == NULL) + ensoniq->spdif_stream = ensoniq->spdif_default; + spin_unlock_irq(&ensoniq->reg_lock); #ifdef CHIP1370 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_es1370_hw_constraints_clock); @@ -1241,6 +1260,116 @@ static int __devinit snd_ensoniq_pcm2(ensoniq_t * ensoniq, int device, snd_pcm_t #ifdef CHIP1371 + +static int snd_ens1373_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ens1373_spdif_default_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + spin_lock_irq(&ensoniq->reg_lock); + ucontrol->value.iec958.status[0] = (ensoniq->spdif_default >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (ensoniq->spdif_default >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (ensoniq->spdif_default >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (ensoniq->spdif_default >> 24) & 0xff; + spin_unlock_irq(&ensoniq->reg_lock); + return 0; +} + +static int snd_ens1373_spdif_default_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change; + + val = ((u32)ucontrol->value.iec958.status[0] << 0) | + ((u32)ucontrol->value.iec958.status[1] << 8) | + ((u32)ucontrol->value.iec958.status[2] << 16) | + ((u32)ucontrol->value.iec958.status[3] << 24); + spin_lock_irq(&ensoniq->reg_lock); + change = ensoniq->spdif_default != val; + ensoniq->spdif_default = val; + if (change && ensoniq->playback1_substream == NULL && ensoniq->playback2_substream == NULL) + outl(val, ES_REG(ensoniq, CHANNEL_STATUS)); + spin_unlock_irq(&ensoniq->reg_lock); + return change; +} + +static int snd_ens1373_spdif_mask_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + return 0; +} + +static int snd_ens1373_spdif_stream_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + spin_lock_irq(&ensoniq->reg_lock); + ucontrol->value.iec958.status[0] = (ensoniq->spdif_stream >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (ensoniq->spdif_stream >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (ensoniq->spdif_stream >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (ensoniq->spdif_stream >> 24) & 0xff; + spin_unlock_irq(&ensoniq->reg_lock); + return 0; +} + +static int snd_ens1373_spdif_stream_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change; + + val = ((u32)ucontrol->value.iec958.status[0] << 0) | + ((u32)ucontrol->value.iec958.status[1] << 8) | + ((u32)ucontrol->value.iec958.status[2] << 16) | + ((u32)ucontrol->value.iec958.status[3] << 24); + spin_lock_irq(&ensoniq->reg_lock); + change = ensoniq->spdif_stream != val; + ensoniq->spdif_stream = val; + if (change && (ensoniq->playback1_substream != NULL || ensoniq->playback2_substream != NULL)) + outl(val, ES_REG(ensoniq, CHANNEL_STATUS)); + spin_unlock_irq(&ensoniq->reg_lock); + return change; +} + +static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_default_get, + .put = snd_ens1373_spdif_default_put, +}; + +static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_mask_get +}; + +static snd_kcontrol_new_t snd_ens1373_spdif_stream __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_stream_get, + .put = snd_ens1373_spdif_stream_put +}; + #define ES1371_SPDIF(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \ .get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put } @@ -1257,32 +1386,30 @@ static int snd_es1371_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * static int snd_es1371_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&ensoniq->reg_lock, flags); - ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1371_SPDIF_EN ? 1 : 0; - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); + spin_lock_irq(&ensoniq->reg_lock); + ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1373_SPDIF_THRU ? 1 : 0; + spin_unlock_irq(&ensoniq->reg_lock); return 0; } static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned int nval1, nval2; int change; - nval1 = ucontrol->value.integer.value[0] ? ES_1371_SPDIF_EN : 0; - nval2 = ucontrol->value.integer.value[0] ? ES_1371_ST_SPDIF_EN : 0; - spin_lock_irqsave(&ensoniq->reg_lock, flags); - change = (ensoniq->ctrl & ES_1371_SPDIF_EN) != nval1; - ensoniq->ctrl &= ~ES_1371_SPDIF_EN; + nval1 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_THRU : 0; + nval2 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_EN : 0; + spin_lock_irq(&ensoniq->reg_lock); + change = (ensoniq->ctrl & ES_1373_SPDIF_THRU) != nval1; + ensoniq->ctrl &= ~ES_1373_SPDIF_THRU; ensoniq->ctrl |= nval1; - ensoniq->cssr &= ~ES_1371_ST_SPDIF_EN; + ensoniq->cssr &= ~ES_1373_SPDIF_EN; ensoniq->cssr |= nval2; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); + spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -1299,7 +1426,7 @@ static struct { unsigned short vid; /* vendor ID */ unsigned short did; /* device ID */ unsigned char rev; /* revision */ -} es1371_spdif_present[] = { +} __devinitdata es1371_spdif_present[] = { { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, @@ -1325,9 +1452,29 @@ static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq) if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid && ensoniq->pci->device == es1371_spdif_present[idx].did && ensoniq->rev == es1371_spdif_present[idx].rev) { - snd_kcontrol_t *kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq); + snd_kcontrol_t *kctl; + int index = 0; + + ensoniq->spdif_default = ensoniq->spdif_stream = SNDRV_PCM_DEFAULT_CON_SPDIF; + outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); + if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) - kctl->id.index = 1; + index++; + + kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq); + kctl->id.index = index; + snd_ctl_add(card, kctl); + + kctl = snd_ctl_new1(&snd_ens1373_spdif_default, ensoniq); + kctl->id.index = index; + snd_ctl_add(card, kctl); + + kctl = snd_ctl_new1(&snd_ens1373_spdif_mask, ensoniq); + kctl->id.index = index; + snd_ctl_add(card, kctl); + + kctl = snd_ctl_new1(&snd_ens1373_spdif_stream, ensoniq); + kctl->id.index = index; snd_ctl_add(card, kctl); break; } diff --git a/sound/pci/ice1712/ak4524.c b/sound/pci/ice1712/ak4524.c index bf0f0cdeb3bd..fe2e2a061de4 100644 --- a/sound/pci/ice1712/ak4524.c +++ b/sound/pci/ice1712/ak4524.c @@ -1,7 +1,7 @@ /* * ALSA driver for ICEnsemble ICE1712 (Envy24) * - * AK4524 / AK4528 interface + * AK4524 / AK4528 / AK4529 interface * * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> * @@ -67,6 +67,7 @@ void snd_ice1712_ak4524_write(ice1712_t *ice, int chip, addr &= 0x07; /* build I2C address + data byte */ + /* assume C1=1, C0=0 */ addrdata = 0xa000 | (addr << 8) | data; for (idx = 15; idx >= 0; idx--) { tmp &= ~(ak->data_mask | ak->clk_mask); @@ -80,11 +81,13 @@ void snd_ice1712_ak4524_write(ice1712_t *ice, int chip, udelay(1); } - if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0) - ak->images[chip][addr] = data; - else - ak->ipga_gain[chip][addr-4] = data; - + if (ak->type == SND_AK4524) { + if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0) + ak->images[chip][addr] = data; + else + ak->ipga_gain[chip][addr-4] = data; + } + if (ak->cs_mask == ak->cs_addr) { if (ak->cif) { /* assert a cs pulse to trigger */ @@ -112,16 +115,26 @@ void snd_ice1712_ak4524_reset(ice1712_t *ice, int state) unsigned char reg; ak4524_t *ak = &ice->ak4524; - for (chip = 0; chip < ak->num_dacs/2; chip++) { - snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03); - if (state) - continue; - for (reg = 0x04; reg < (ak->is_ak4528 ? 0x06 : 0x08); reg++) - snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]); - if (ak->is_ak4528) - continue; - for (reg = 0x04; reg < 0x06; reg++) - snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]); + switch (ak->type) { + case SND_AK4524: + case SND_AK4528: + for (chip = 0; chip < ak->num_dacs/2; chip++) { + snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03); + if (state) + continue; + /* DAC volumes */ + for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++) + snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]); + if (ak->type == SND_AK4528) + continue; + /* IPGA */ + for (reg = 0x04; reg < 0x06; reg++) + snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]); + } + break; + case SND_AK4529: + /* FIXME: needed for ak4529? */ + break; } } @@ -130,7 +143,7 @@ void snd_ice1712_ak4524_reset(ice1712_t *ice, int state) */ void __devinit snd_ice1712_ak4524_init(ice1712_t *ice) { - static unsigned char inits[] = { + static unsigned char inits_ak4524[] = { 0x00, 0x07, /* 0: all power up */ 0x01, 0x00, /* 1: ADC/DAC reset */ 0x02, 0x60, /* 2: 24bit I2S */ @@ -144,28 +157,68 @@ void __devinit snd_ice1712_ak4524_init(ice1712_t *ice) 0x07, 0x00, /* 7: DAC right muted */ 0xff, 0xff }; - int chip, idx; - unsigned char *ptr, reg, data; + static unsigned char inits_ak4528[] = { + 0x00, 0x07, /* 0: all power up */ + 0x01, 0x00, /* 1: ADC/DAC reset */ + 0x02, 0x60, /* 2: 24bit I2S */ + 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */ + 0x01, 0x03, /* 1: ADC/DAC enable */ + 0x04, 0x00, /* 4: ADC left muted */ + 0x05, 0x00, /* 5: ADC right muted */ + 0xff, 0xff + }; + static unsigned char inits_ak4529[] = { + 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ + 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ + 0x00, 0x08, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ + 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */ + 0x02, 0xff, /* 2: LOUT1 muted */ + 0x03, 0xff, /* 3: ROUT1 muted */ + 0x04, 0xff, /* 4: LOUT2 muted */ + 0x05, 0xff, /* 5: ROUT2 muted */ + 0x06, 0xff, /* 6: LOUT3 muted */ + 0x07, 0xff, /* 7: ROUT3 muted */ + 0x0b, 0xff, /* B: LOUT4 muted */ + 0x0c, 0xff, /* C: ROUT4 muted */ + 0x08, 0x55, /* 8: deemphasis all off */ + 0xff, 0xff + }; + int chip, num_chips; + unsigned char *ptr, reg, data, *inits; ak4524_t *ak = &ice->ak4524; - for (chip = idx = 0; chip < ak->num_dacs/2; chip++) { + switch (ak->type) { + case SND_AK4524: + inits = inits_ak4524; + num_chips = ak->num_dacs / 2; + break; + case SND_AK4528: + inits = inits_ak4528; + num_chips = ak->num_dacs / 2; + break; + case SND_AK4529: + default: + inits = inits_ak4529; + num_chips = 1; + break; + } + + for (chip = 0; chip < num_chips; chip++) { ptr = inits; while (*ptr != 0xff) { reg = *ptr++; data = *ptr++; - if (ak->is_ak4528) { - if (reg > 5) - continue; - if (reg >= 4 && (data & 0x80)) - continue; - } - if (reg == 0x03 && ak->is_ak4528) - data = 0x0d; /* deemphasis off, turn LR highpass filters on */ snd_ice1712_ak4524_write(ice, chip, reg, data); } } } + +#define AK_GET_CHIP(val) (((val) >> 8) & 0xff) +#define AK_GET_ADDR(val) ((val) & 0xff) +#define AK_GET_SHIFT(val) (((val) >> 16) & 0xff) +#define AK_COMPOSE(chip,addr,shift) (((chip) << 8) | (addr) | ((shift) << 16)) + static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -178,8 +231,8 @@ static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->private_value / 8; - int addr = kcontrol->private_value % 8; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); ucontrol->value.integer.value[0] = ice->ak4524.images[chip][addr]; return 0; } @@ -187,8 +240,8 @@ static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_ static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->private_value / 8; - int addr = kcontrol->private_value % 8; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); unsigned char nval = ucontrol->value.integer.value[0]; int change = ice->ak4524.images[chip][addr] != nval; if (change) @@ -208,8 +261,8 @@ static int snd_ice1712_ak4524_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_e static int snd_ice1712_ak4524_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->private_value / 8; - int addr = kcontrol->private_value % 8; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); ucontrol->value.integer.value[0] = ice->ak4524.ipga_gain[chip][addr-4] & 0x7f; return 0; } @@ -217,8 +270,8 @@ static int snd_ice1712_ak4524_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_el static int snd_ice1712_ak4524_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->private_value / 8; - int addr = kcontrol->private_value % 8; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; int change = ice->ak4524.ipga_gain[chip][addr] != nval; if (change) @@ -243,21 +296,26 @@ static int snd_ice1712_ak4524_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_ static int snd_ice1712_ak4524_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->id.index; - ucontrol->value.enumerated.item[0] = ice->ak4524.images[chip][3] & 3; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int shift = AK_GET_SHIFT(kcontrol->private_value); + ucontrol->value.enumerated.item[0] = (ice->ak4524.images[chip][addr] >> shift) & 3; return 0; } static int snd_ice1712_ak4524_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int chip = kcontrol->id.index; - unsigned char nval = ucontrol->value.enumerated.item[0]; + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int shift = AK_GET_SHIFT(kcontrol->private_value); + unsigned char nval = ucontrol->value.enumerated.item[0] & 3; int change; - nval |= (nval & 3) | (ice->ak4524.images[chip][3] & ~3); - change = ice->ak4524.images[chip][3] != nval; + + nval = (nval << shift) | (ice->ak4524.images[chip][addr] & ~(3 << shift)); + change = ice->ak4524.images[chip][addr] != nval; if (change) - snd_ice1712_ak4524_write(ice, chip, 3, nval); + snd_ice1712_ak4524_write(ice, chip, addr, nval); return change; } @@ -280,15 +338,24 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice) ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE; ctl.get = snd_ice1712_ak4524_volume_get; ctl.put = snd_ice1712_ak4524_volume_put; - if (ak->is_ak4528) - ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */ - else - ctl.private_value = (idx / 2) * 8 + (idx % 2) + 6; /* register 6 & 7 */ + switch (ak->type) { + case SND_AK4524: + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0); /* register 6 & 7 */ + break; + case SND_AK4528: + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */ + break; + case SND_AK4529: { + int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */ + ctl.private_value = AK_COMPOSE(0, val, 0); + break; + } + } ctl.private_data = ice; if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0) return err; } - for (idx = 0; idx < ak->num_adcs && !ak->is_ak4528; ++idx) { + for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { snd_kcontrol_t ctl; memset(&ctl, 0, sizeof(ctl)); strcpy(ctl.id.name, "ADC Volume"); @@ -298,7 +365,7 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice) ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE; ctl.get = snd_ice1712_ak4524_volume_get; ctl.put = snd_ice1712_ak4524_volume_put; - ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */ + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */ ctl.private_data = ice; if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0) return err; @@ -310,7 +377,7 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice) ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE; ctl.get = snd_ice1712_ak4524_ipga_gain_get; ctl.put = snd_ice1712_ak4524_ipga_gain_put; - ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */ + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */ ctl.private_data = ice; if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0) return err; @@ -325,6 +392,17 @@ int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice) ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE; ctl.get = snd_ice1712_ak4524_deemphasis_get; ctl.put = snd_ice1712_ak4524_deemphasis_put; + switch (ak->type) { + case SND_AK4524: + case SND_AK4528: + ctl.private_value = AK_COMPOSE(idx, 3, 0); /* register 3 */ + break; + case SND_AK4529: { + int shift = idx == 3 ? 6 : (2 - idx) * 2; + ctl.private_value = AK_COMPOSE(0, 8, shift); /* register 8 with shift */ + break; + } + } ctl.private_data = ice; if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0) return err; diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 46a293aba458..e4518ddab848 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -337,6 +337,9 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) case ICE1712_SUBDEVICE_AUDIOPHILE: ice->num_total_dacs = 2; break; + case ICE1712_SUBDEVICE_DELTA410: + ice->num_total_dacs = 8; + break; case ICE1712_SUBDEVICE_DELTA44: case ICE1712_SUBDEVICE_DELTA66: ice->num_total_dacs = ice->omni ? 8 : 4; @@ -350,6 +353,7 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) /* initialize spdif */ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_AUDIOPHILE: + case ICE1712_SUBDEVICE_DELTA410: case ICE1712_SUBDEVICE_DELTA1010LT: if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { snd_printk("unable to create I2C bus\n"); @@ -378,12 +382,17 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) ak = &ice->ak4524; switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_AUDIOPHILE: + case ICE1712_SUBDEVICE_DELTA410: ak->num_adcs = ak->num_dacs = 2; - ak->is_ak4528 = 1; - ak->cif = 0; /* the default level of the CIF pin from AK4524 */ + ak->type = SND_AK4528; + if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA410) { + ak->num_dacs = 8; + ak->type = SND_AK4529; + } + ak->cif = 0; /* the default level of the CIF pin from AK4528/4529 */ ak->data_mask = ICE1712_DELTA_AP_DOUT; ak->clk_mask = ICE1712_DELTA_AP_CCLK; - ak->cs_mask = ak->cs_addr = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528 codec */ + ak->cs_mask = ak->cs_addr = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528/4529 codec */ ak->cs_none = 0; ak->add_flags = ICE1712_DELTA_AP_CS_DIGITAL; /* assert digital high */ ak->mask_flags = 0; @@ -392,6 +401,7 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) break; case ICE1712_SUBDEVICE_DELTA1010LT: ak->num_adcs = ak->num_dacs = 8; + ak->type = SND_AK4524; ak->cif = 0; /* the default level of the CIF pin from AK4524 */ ak->data_mask = ICE1712_DELTA_1010LT_DOUT; ak->clk_mask = ICE1712_DELTA_1010LT_CCLK; @@ -406,6 +416,7 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) case ICE1712_SUBDEVICE_DELTA66: case ICE1712_SUBDEVICE_DELTA44: ak->num_adcs = ak->num_dacs = 4; + ak->type = SND_AK4524; ak->cif = 0; /* the default level of the CIF pin from AK4524 */ ak->data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA; ak->clk_mask = ICE1712_DELTA_CODEC_SERIAL_CLOCK; @@ -471,6 +482,8 @@ static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice) case ICE1712_SUBDEVICE_DELTADIO2496: case ICE1712_SUBDEVICE_DELTA66: case ICE1712_SUBDEVICE_AUDIOPHILE: + case ICE1712_SUBDEVICE_DELTA410: + case ICE1712_SUBDEVICE_DELTA1010LT: err = snd_ice1712_spdif_build_controls(ice); if (err < 0) return err; @@ -492,6 +505,7 @@ static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice) switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_DELTA1010LT: case ICE1712_SUBDEVICE_AUDIOPHILE: + case ICE1712_SUBDEVICE_DELTA410: case ICE1712_SUBDEVICE_DELTA44: case ICE1712_SUBDEVICE_DELTA66: err = snd_ice1712_ak4524_build_controls(ice); @@ -539,6 +553,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { snd_ice1712_delta_add_controls, }, { + ICE1712_SUBDEVICE_DELTA410, + "M Audio Delta 410", + snd_ice1712_delta_init, + snd_ice1712_delta_add_controls, + }, + { ICE1712_SUBDEVICE_DELTA1010LT, "M Audio Delta 1010LT", snd_ice1712_delta_init, diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index edae9fbcf224..dc8a3a61428d 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h @@ -37,6 +37,7 @@ #define ICE1712_SUBDEVICE_DELTA66 0x121432d6 #define ICE1712_SUBDEVICE_DELTA44 0x121433d6 #define ICE1712_SUBDEVICE_AUDIOPHILE 0x121434d6 +#define ICE1712_SUBDEVICE_DELTA410 0x121438d6 #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 /* entry point */ @@ -106,7 +107,8 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; /* 0x40 = CODEC_CHIP_A */ /* 0x80 = CODEC_CHIP_B */ -/* MidiMan M-Audio Audiophile definitions */ +/* MidiMan M-Audio Audiophile/Delta410 definitions */ +/* thanks to Kristof Pelckmans <Kristof.Pelckmans@antwerpen.be> for Delta410 info */ /* 0x01 = DFS */ #define ICE1712_DELTA_AP_CCLK 0x02 /* SPI clock */ /* (clocking on rising edge - 0->1) */ @@ -114,7 +116,7 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; #define ICE1712_DELTA_AP_DOUT 0x08 /* data output */ #define ICE1712_DELTA_AP_CS_DIGITAL 0x10 /* CS8427 chip select */ /* low signal = select */ -#define ICE1712_DELTA_AP_CS_CODEC 0x20 /* AK4528 chip select */ +#define ICE1712_DELTA_AP_CS_CODEC 0x20 /* AK4528 (audiophile), AK4529 (Delta410) chip select */ /* low signal = select */ /* MidiMan M-Audio Delta1010LT definitions */ diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 230731ad8a14..2195982175a0 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -406,6 +406,7 @@ static int __devinit snd_ice1712_ews_init(ice1712_t *ice) switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_EWS88MT: ak->num_adcs = ak->num_dacs = 8; + ak->type = SND_AK4524; ak->cif = 1; /* CIF high */ ak->data_mask = ICE1712_EWS88_SERIAL_DATA; ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK; @@ -418,6 +419,7 @@ static int __devinit snd_ice1712_ews_init(ice1712_t *ice) break; case ICE1712_SUBDEVICE_EWX2496: ak->num_adcs = ak->num_dacs = 2; + ak->type = SND_AK4524; ak->cif = 1; /* CIF high */ ak->data_mask = ICE1712_EWS88_SERIAL_DATA; ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK; @@ -430,6 +432,7 @@ static int __devinit snd_ice1712_ews_init(ice1712_t *ice) break; case ICE1712_SUBDEVICE_DMX6FIRE: ak->num_adcs = ak->num_dacs = 6; + ak->type = SND_AK4524; ak->cif = 1; /* CIF high */ ak->data_mask = ICE1712_6FIRE_SERIAL_DATA; ak->clk_mask = ICE1712_6FIRE_SERIAL_CLOCK; diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 2e7f439874b2..e1dba1ddbfcb 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1532,7 +1532,7 @@ static snd_kcontrol_new_t snd_ice1712_eeprom __devinitdata = { /* */ -static int snd_ice1712_spdif_default_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_ice1712_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; @@ -1559,20 +1559,13 @@ static int snd_ice1712_spdif_default_put(snd_kcontrol_t * kcontrol, static snd_kcontrol_new_t snd_ice1712_spdif_default __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .info = snd_ice1712_spdif_default_info, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .info = snd_ice1712_spdif_info, .get = snd_ice1712_spdif_default_get, .put = snd_ice1712_spdif_default_put }; -static int snd_ice1712_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; - uinfo->count = 1; - return 0; -} - static int snd_ice1712_spdif_maskc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { @@ -1617,29 +1610,22 @@ static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol, static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), - .info = snd_ice1712_spdif_mask_info, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), + .info = snd_ice1712_spdif_info, .get = snd_ice1712_spdif_maskc_get, }; static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), - .info = snd_ice1712_spdif_mask_info, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), + .info = snd_ice1712_spdif_info, .get = snd_ice1712_spdif_maskp_get, }; -static int snd_ice1712_spdif_stream_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; - uinfo->count = 1; - return 0; -} - static int snd_ice1712_spdif_stream_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { @@ -1660,10 +1646,10 @@ static int snd_ice1712_spdif_stream_put(snd_kcontrol_t * kcontrol, static snd_kcontrol_new_t snd_ice1712_spdif_stream __devinitdata = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), - .info = snd_ice1712_spdif_stream_info, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), + .info = snd_ice1712_spdif_info, .get = snd_ice1712_spdif_stream_get, .put = snd_ice1712_spdif_stream_put }; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index d530dd64d629..3d6ae77c1d62 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -239,10 +239,12 @@ typedef struct { struct snd_ak4524 { int num_adcs; /* AK4524 or AK4528 ADCs */ int num_dacs; /* AK4524 or AK4528 DACs */ - unsigned char images[4][8]; + unsigned char images[4][16]; unsigned char ipga_gain[4][2]; /* */ - unsigned int is_ak4528: 1; /* AK4524 or AK4528 */ + enum { + SND_AK4524, SND_AK4528, SND_AK4529 + } type; unsigned int cif: 1; unsigned char data_mask; unsigned char clk_mask; diff --git a/sound/pci/rme9652/hammerfall_mem.c b/sound/pci/rme9652/hammerfall_mem.c index 747e9d7cf2be..2705ca915220 100644 --- a/sound/pci/rme9652/hammerfall_mem.c +++ b/sound/pci/rme9652/hammerfall_mem.c @@ -25,7 +25,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - $Id: hammerfall_mem.c,v 1.4 2002/10/21 18:28:25 perex Exp $ + $Id: hammerfall_mem.c,v 1.5 2002/11/04 09:11:42 perex Exp $ Tue Oct 17 2000 Jaroslav Kysela <perex@suse.cz> @@ -34,7 +34,6 @@ */ -#include <linux/config.h> #include <linux/version.h> #include <linux/module.h> #include <linux/pci.h> diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index b7cb6b04aaac..3cff7ac49a53 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -201,11 +201,16 @@ typedef struct { } viadev_t; +/* + * allocate and initialize the descriptor buffers + * periods = number of periods + * fragsize = period size in bytes + */ static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream, - struct pci_dev *pci) + struct pci_dev *pci, + int periods, int fragsize) { - int i, idx, ofs, rest, fragsize; - snd_pcm_runtime_t *runtime = substream->runtime; + int i, idx, ofs, rest; struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL); if (! dev->table) { @@ -223,10 +228,9 @@ static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream, } /* fill the entries */ - fragsize = snd_pcm_lib_period_bytes(substream); idx = 0; ofs = 0; - for (i = 0; i < runtime->periods; i++) { + for (i = 0; i < periods; i++) { rest = fragsize; /* fill descriptors for a period. * a period can be split to several descriptors if it's @@ -241,7 +245,7 @@ static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream, r = rest; rest -= r; if (! rest) { - if (i == runtime->periods - 1) + if (i == periods - 1) flag = VIA_TBL_BIT_EOL; /* buffer boundary */ else flag = VIA_TBL_BIT_FLAG; /* period boundary */ @@ -472,19 +476,14 @@ static int snd_via82xx_trigger(via82xx_t *chip, viadev_t *viadev, int cmd) } -static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev, - snd_pcm_substream_t *substream) +static int snd_via82xx_set_format(via82xx_t *chip, viadev_t *viadev, + snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; unsigned long port = chip->port + viadev->reg_offset; - int err; snd_via82xx_channel_reset(chip, viadev); - err = build_via_table(viadev, substream, chip->pci); - if (err < 0) - return err; - outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR); switch (chip->chip_type) { case TYPE_VIA686: @@ -583,11 +582,28 @@ static int snd_via82xx_capture_trigger(snd_pcm_substream_t * substream, static int snd_via82xx_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { - return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params)); + via82xx_t *chip = snd_pcm_substream_chip(substream); + viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture; + int err; + + err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params)); + if (err < 0) + return err; + err = build_via_table(viadev, substream, chip->pci, + params_periods(hw_params), + params_period_bytes(hw_params)); + if (err < 0) + return err; + return err; } static int snd_via82xx_hw_free(snd_pcm_substream_t * substream) { + via82xx_t *chip = snd_pcm_substream_chip(substream); + viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture; + + clean_via_table(viadev, substream, chip->pci); + snd_pcm_sgbuf_free(substream); return 0; } @@ -606,7 +622,7 @@ static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream) tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff; outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX)); } - return snd_via82xx_setup_periods(chip, &chip->playback, substream); + return snd_via82xx_set_format(chip, &chip->playback, substream); } static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream) @@ -617,7 +633,7 @@ static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream) snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); if (chip->chip_type == TYPE_VIA8233) outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO)); - return snd_via82xx_setup_periods(chip, &chip->capture, substream); + return snd_via82xx_set_format(chip, &chip->capture, substream); } static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev) @@ -761,20 +777,16 @@ static int snd_via82xx_capture_open(snd_pcm_substream_t * substream) static int snd_via82xx_playback_close(snd_pcm_substream_t * substream) { via82xx_t *chip = snd_pcm_substream_chip(substream); - - clean_via_table(&chip->playback, substream, chip->pci); - snd_pcm_sgbuf_delete(substream); chip->playback.substream = NULL; + snd_pcm_sgbuf_delete(substream); return 0; } static int snd_via82xx_capture_close(snd_pcm_substream_t * substream) { via82xx_t *chip = snd_pcm_substream_chip(substream); - - clean_via_table(&chip->capture, substream, chip->pci); - snd_pcm_sgbuf_delete(substream); chip->capture.substream = NULL; + snd_pcm_sgbuf_delete(substream); return 0; } diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index f4c34e0318bb..6922201b7bf5 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -29,7 +29,6 @@ * --- End of notes from Thoamas's original driver --- */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 24c693642b65..d18451343ddf 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -935,7 +935,8 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) struct usb_device *dev = subs->dev; struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; - struct usb_interface *iface; + struct usb_interface_descriptor *altsd; + struct usb_interface *iface; struct audioformat *fmt; unsigned int ep, attr; unsigned char data[3]; @@ -951,7 +952,8 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) iface = &config->interface[fmt->iface]; alts = &iface->altsetting[fmt->altset_idx]; - snd_assert(alts->desc.bAlternateSetting == fmt->altsetting, return -EINVAL); + altsd = get_iface_desc(alts); + snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL); /* close the old interface */ if (subs->interface >= 0 && subs->interface != fmt->iface) { @@ -973,31 +975,31 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) } /* create a data pipe */ - ep = alts->endpoint[0].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep = get_endpoint(alts, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if (is_playback) subs->datapipe = usb_sndisocpipe(dev, ep); else subs->datapipe = usb_rcvisocpipe(dev, ep); subs->syncpipe = subs->syncinterval = 0; - subs->maxpacksize = alts->endpoint[0].desc.wMaxPacketSize; + subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->fill_max = 0; /* we need a sync pipe in async OUT or adaptive IN mode */ - attr = alts->endpoint[0].desc.bmAttributes & EP_ATTR_MASK; + attr = get_endpoint(alts, 0)->bmAttributes & EP_ATTR_MASK; if ((is_playback && attr == EP_ATTR_ASYNC) || (! is_playback && attr == EP_ATTR_ADAPTIVE)) { /* check endpoint */ - if (alts->desc.bNumEndpoints < 2 || - alts->endpoint[1].desc.bmAttributes != 0x01 || - alts->endpoint[1].desc.bSynchAddress != 0) { + if (altsd->bNumEndpoints < 2 || + get_endpoint(alts, 1)->bmAttributes != 0x01 || + get_endpoint(alts, 1)->bSynchAddress != 0) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; } - ep = alts->endpoint[1].desc.bEndpointAddress; - if ((is_playback && ep != (alts->endpoint[0].desc.bSynchAddress | USB_DIR_IN)) || - (! is_playback && ep != (alts->endpoint[0].desc.bSynchAddress & ~USB_DIR_IN))) { + ep = get_endpoint(alts, 1)->bEndpointAddress; + if ((is_playback && ep != (get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || + (! is_playback && ep != (get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN))) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; @@ -1007,10 +1009,10 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) subs->syncpipe = usb_rcvisocpipe(dev, ep); else subs->syncpipe = usb_sndisocpipe(dev, ep); - subs->syncinterval = alts->endpoint[1].desc.bRefresh; + subs->syncinterval = get_endpoint(alts, 1)->bRefresh; } - ep = alts->endpoint[0].desc.bEndpointAddress; + ep = get_endpoint(alts, 0)->bEndpointAddress; /* if endpoint has pitch control, enable it */ if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) { data[0] = 1; @@ -1676,6 +1678,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i struct usb_host_config *config; struct usb_interface *iface; struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; int i, altno, err, stream; int channels, nr_rates, pcm_format, format; struct audioformat *fp; @@ -1688,19 +1691,20 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i iface = &config->interface[iface_no]; for (i = 0; i < iface->num_altsetting; i++) { alts = &iface->altsetting[i]; + altsd = get_iface_desc(alts); /* skip invalid one */ - if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || - alts->desc.bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING || - alts->desc.bNumEndpoints < 1) + if (altsd->bInterfaceClass != USB_CLASS_AUDIO || + altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING || + altsd->bNumEndpoints < 1) continue; /* must be isochronous */ - if ((alts->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) continue; /* check direction */ - stream = (alts->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) ? + stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - altno = alts->desc.bAlternateSetting; + altno = altsd->bAlternateSetting; /* get audio formats */ fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, AS_GENERAL, iface_no, altno); @@ -1767,8 +1771,8 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i fp->altsetting = altno; fp->altset_idx = i; fp->format = pcm_format; - fp->endpoint = alts->endpoint[0].desc.bEndpointAddress; - fp->ep_attr = alts->endpoint[0].desc.bmAttributes; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; fp->channels = channels; fp->attributes = csep[3]; @@ -1857,8 +1861,10 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, */ config = dev->actconfig; for (i = 0; i < p1[7]; i++) { + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; j = p1[8 + i]; - if (j >= config->desc.bNumInterfaces) { + if (j >= get_cfg_desc(config)->bNumInterfaces) { snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", dev->devnum, ctrlif, j); continue; @@ -1868,8 +1874,10 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j); continue; } - if (iface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO && - iface->altsetting[0].desc.bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { + alts = &iface->altsetting[0]; + altsd = get_iface_desc(alts); + if (altsd->bInterfaceClass == USB_CLASS_AUDIO && + altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; @@ -1877,9 +1885,9 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1); continue; } - if (iface->altsetting[0].desc.bInterfaceClass != USB_CLASS_AUDIO || - iface->altsetting[0].desc.bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) { - snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, iface->altsetting[0].desc.bInterfaceClass); + if (altsd->bInterfaceClass != USB_CLASS_AUDIO || + altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) { + snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass); /* skip non-supported classes */ continue; } @@ -1941,7 +1949,7 @@ static int snd_usb_roland_ua100_hack(snd_usb_audio_t *chip) struct usb_interface *iface; int err; - if (cfg->desc.bNumInterfaces != 3) { + if (get_cfg_desc(cfg)->bNumInterfaces != 3) { snd_printdd(KERN_ERR "invalid UA-100 descriptor\n"); return -ENXIO; } @@ -2134,18 +2142,22 @@ static void *snd_usb_audio_probe(struct usb_device *dev, struct usb_interface *intf, const struct usb_device_id *usb_id) { - struct usb_host_config *config = dev->actconfig; + struct usb_host_config *config = dev->actconfig; const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; int i; snd_card_t *card; snd_usb_audio_t *chip; - int ifnum = intf->altsetting->desc.bInterfaceNumber; + struct usb_host_interface *alts; + int ifnum; + + alts = &intf->altsetting[0]; + ifnum = get_iface_desc(alts)->bInterfaceNumber; if (quirk && quirk->ifnum != QUIRK_ANY_INTERFACE && ifnum != quirk->ifnum) goto __err_val; - if (usb_set_configuration(dev, config->desc.bConfigurationValue) < 0) { - snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", config->desc.bConfigurationValue); + if (usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue) < 0) { + snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue); goto __err_val; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 868143cd4f47..1f70895ea831 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -191,4 +191,15 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffe int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); +/* + * retrieve usb_interface descriptor from the host interface + * (conditional for compatibility with the older API) + */ +#ifndef get_iface_desc +#define get_iface_desc(iface) (&iface->desc) +#define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc) +#define get_ep_desc(ep) (&(ep)->desc) +#define get_cfg_desc(cfg) (&(cfg)->desc) +#endif + #endif /* __USBAUDIO_H */ diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index f26b2069e5b2..4e75e1c102ec 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -515,7 +515,8 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep) static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi) { struct usb_interface* intf; - struct usb_host_interface* intfd; + struct usb_host_interface *hostif; + struct usb_interface_descriptor* intfd; if (umidi->chip->dev->descriptor.idVendor != 0x0582) return NULL; @@ -523,29 +524,37 @@ static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* u if (!intf || intf->num_altsetting != 2) return NULL; - intfd = &intf->altsetting[0]; - if (intfd->desc.bNumEndpoints != 2 || - (intfd->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || - (intfd->endpoint[1].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) + hostif = &intf->altsetting[0]; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints != 2 || + (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || + (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) return NULL; - intfd = &intf->altsetting[1]; - if (intfd->desc.bNumEndpoints != 2 || - (intfd->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || - (intfd->endpoint[1].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + hostif = &intf->altsetting[1]; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints != 2 || + (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || + (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return NULL; - usb_set_interface(umidi->chip->dev, intfd->desc.bInterfaceNumber, - intfd->desc.bAlternateSetting); - return &intfd->endpoint[1].desc; + usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + return get_endpoint(hostif, 1); } static struct usb_endpoint_descriptor* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi) { struct usb_interface* intf = umidi->iface; - if (!intf || intf->altsetting[0].desc.bNumEndpoints < 1) + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + if (!intf) + return NULL; + hostif = &intf->altsetting[0]; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints < 1) return NULL; - return &intf->altsetting[0].endpoint[0].desc; + return get_endpoint(hostif, 0); } /* @@ -772,18 +781,21 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi, snd_usb_midi_endpoint_info_t* endpoints) { struct usb_interface* intf; - struct usb_host_interface* intfd; + struct usb_host_interface *hostif; + struct usb_interface_descriptor* intfd; struct usb_ms_header_descriptor* ms_header; - struct usb_host_endpoint* ep; + struct usb_host_endpoint *hostep; + struct usb_endpoint_descriptor* ep; struct usb_ms_endpoint_descriptor* ms_ep; int i, epidx; intf = umidi->iface; if (!intf) return -ENXIO; - intfd = &intf->altsetting[0]; - ms_header = (struct usb_ms_header_descriptor*)intfd->extra; - if (intfd->extralen >= 7 && + hostif = &intf->altsetting[0]; + intfd = get_iface_desc(hostif); + ms_header = (struct usb_ms_header_descriptor*)hostif->extra; + if (hostif->extralen >= 7 && ms_header->bLength >= 7 && ms_header->bDescriptorType == USB_DT_CS_INTERFACE && ms_header->bDescriptorSubtype == HEADER) @@ -793,33 +805,34 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi, printk(KERN_WARNING "snd-usb-midi: MIDIStreaming interface descriptor not found\n"); epidx = 0; - for (i = 0; i < intfd->desc.bNumEndpoints; ++i) { - ep = &intfd->endpoint[i]; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) + for (i = 0; i < intfd->bNumEndpoints; ++i) { + hostep = &hostif->endpoint[i]; + ep = get_ep_desc(hostep); + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) continue; - ms_ep = (struct usb_ms_endpoint_descriptor*)ep->extra; - if (ep->extralen < 4 || + ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra; + if (hostep->extralen < 4 || ms_ep->bLength < 4 || ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || ms_ep->bDescriptorSubtype != MS_GENERAL) continue; if (endpoints[epidx].epnum != 0 && - endpoints[epidx].epnum != (ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) { + endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) { ++epidx; if (epidx >= MIDI_MAX_ENDPOINTS) { printk(KERN_WARNING "snd-usb-midi: too many endpoints\n"); break; } } - endpoints[epidx].epnum = ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if (ep->desc.bEndpointAddress & USB_DIR_IN) { + endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (ep->bEndpointAddress & USB_DIR_IN) { endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; } else { endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; } printk(KERN_INFO "snd-usb-midi: detected %d %s jack(s) on endpoint %d\n", ms_ep->bNumEmbMIDIJack, - ep->desc.bEndpointAddress & USB_DIR_IN ? "input" : "output", + ep->bEndpointAddress & USB_DIR_IN ? "input" : "output", endpoints[epidx].epnum); } return 0; @@ -833,17 +846,19 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi, snd_usb_midi_endpoint_info_t* endpoint) { struct usb_interface* intf; - struct usb_host_interface* intfd; + struct usb_host_interface *hostif; + struct usb_interface_descriptor* intfd; struct usb_endpoint_descriptor* epd; if (endpoint->epnum == -1) { intf = umidi->iface; if (!intf || intf->num_altsetting < 1) return -ENOENT; - intfd = intf->altsetting; - if (intfd->desc.bNumEndpoints < 1) + hostif = intf->altsetting; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints < 1) return -ENOENT; - epd = &intfd->endpoint [0].desc; + epd = get_endpoint(hostif, 0); endpoint->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } return 0; @@ -856,18 +871,20 @@ static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi, snd_usb_midi_endpoint_info_t* endpoint) { struct usb_interface* intf; - struct usb_host_interface* intfd; + struct usb_host_interface *hostif; + struct usb_interface_descriptor* intfd; uint8_t* cs_desc; intf = umidi->iface; if (!intf) return -ENOENT; - intfd = intf->altsetting; - if (intfd->desc.bNumEndpoints < 1) + hostif = intf->altsetting; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints < 1) return -ENOENT; - for (cs_desc = intfd->extra; - cs_desc < intfd->extra + intfd->extralen && cs_desc[0] >= 2; + for (cs_desc = hostif->extra; + cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; cs_desc += cs_desc[0]) { if (cs_desc[1] == CS_AUDIO_INTERFACE) { if (cs_desc[2] == MIDI_IN_JACK) @@ -890,33 +907,35 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports { snd_usb_midi_endpoint_info_t ep_info; struct usb_interface* intf; - struct usb_host_interface* intfd; + struct usb_host_interface *hostif; + struct usb_interface_descriptor* intfd; struct usb_endpoint_descriptor* epd; int cable, err; intf = umidi->iface; if (!intf) return -ENOENT; - intfd = intf->altsetting; - if (intfd->desc.bNumEndpoints < (ports > 1 ? 5 : 3)) { + hostif = intf->altsetting; + intfd = get_iface_desc(hostif); + if (intfd->bNumEndpoints < (ports > 1 ? 5 : 3)) { snd_printdd(KERN_ERR "not enough endpoints\n"); return -ENOENT; } - epd = &intfd->endpoint[0].desc; + epd = get_endpoint(hostif, 0); if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n"); return -ENXIO; } - epd = &intfd->endpoint[2].desc; + epd = get_endpoint(hostif, 2); if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n"); return -ENXIO; } if (ports > 1) { - epd = &intfd->endpoint[4].desc; + epd = get_endpoint(hostif, 4); if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n"); @@ -924,13 +943,13 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports } } - ep_info.epnum = intfd->endpoint[2].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.epnum = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_info.out_cables = 0x5555 & ((1 << ports) - 1); err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); if (err < 0) return err; - ep_info.epnum = intfd->endpoint[0].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.epnum = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_info.in_cables = (1 << ports) - 1; err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); if (err < 0) @@ -938,7 +957,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports umidi->endpoints[0].in->urb->complete = snd_usbmidi_in_midiman_complete; if (ports > 1) { - ep_info.epnum = intfd->endpoint[4].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.epnum = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_info.out_cables = 0xaaaa & ((1 << ports) - 1); err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]); if (err < 0) |
