- USB: remember to release the kernel lock and other updates..
- recognize the k6 model 13: it's a K6-2+ mobile processor.
- file locking deadlock detection bugfix..
- NFSv3 is not really really experimental any more.
- don't raise privileges when re-trying a failed NFS RPM request
- alpha cross-compile fixes..
- sound init cleanups
- shm statistics bugfix.
- nfsd: mark us as a O_LARGEFILE case, so that the VFS allows
the full 64-bit access..
- fix up ac97 codec initialization
- Ingo: clean up VM handling, improve balancing.
- add SGI PCI ID's.
- export the new lock copy/init functions
- cs4281 sound driver
- official Compaq CISS driver.
it as a module, say M here and read Documentation/modules.txt. The
module will be called phonedev.o.
+Compaq Smart Array support
+CONFIG_BLK_CPQ_CISS_DA
+ This is the driver for Compaq Smart Array controllers.
+ Everyone using these boards should say Y here.
+ See "linux/Documentation/cciss.txt" for the current list of
+ boards supported by this driver, and for further information
+ on the use of this driver.
+
QuickNet Internet LineJack/PhoneJack support
CONFIG_PHONE_IXJ
Say M if you have a telephony card manufactured by Quicknet
L: linux-fbdev@vuser.vu.union.edu
S: Maintained
-COMPAQ SMART CISS RAID DRIVER
-P: Charles White
-M: Charles White <arrays@compaq.com>
-L: compaqandlinux@cpqlin.van-dijk.net
-W: ftp.compaq.com/pub/products/drivers/linux
-S: Supported
-
COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
P: Amy Vanzant-Hodge
M: Amy Vanzant-Hodge (fibrechannel@compaq.com)
W: ftp.compaq.com/pub/products/drivers/linux
S: Supported
+COMPAQ SMART CISS RAID DRIVER
+P: Charles White
+M: Charles White <arrays@compaq.com>
+L: compaqandlinux@cpqlin.van-dijk.net
+W: ftp.compaq.com/pub/products/drivers/linux
+S: Supported
+
COMPUTONE INTELLIPORT MULTIPORT CARD
P: Doug McNash
P: Michael H. Warfield
# Copyright (C) 1994 by Linus Torvalds
#
-NM := nm -B
+NM := $(NM) -B
LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax
CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
$(OBJSTRIP) -v $(VMLINUX) vmlinux.nh
vmlinux: $(TOPDIR)/vmlinux
- strip -o vmlinux $(VMLINUX)
+ $(STRIP) -o vmlinux $(VMLINUX)
tools/lxboot: $(OBJSTRIP) bootloader
$(OBJSTRIP) -p bootloader tools/lxboot
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_EMU10K1 is not set
# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
# CONFIG_SOUND_ES1370 is not set
CONFIG_SOUND_ES1371=y
# CONFIG_SOUND_ESSSOLO1 is not set
* Set MTRR capability flag if appropriate
*/
if(boot_cpu_data.x86 == 5) {
- if((boot_cpu_data.x86_model == 9) ||
+ if((boot_cpu_data.x86_model == 13) ||
+ (boot_cpu_data.x86_model == 9) ||
((boot_cpu_data.x86_model == 8) &&
(boot_cpu_data.x86_mask >= 8)))
c->x86_capability |= X86_FEATURE_MTRR;
}
break;
}
- if (c->x86_model == 8 || c->x86_model == 9)
+ if (c->x86_model == 8 || c->x86_model == 9 || c->x86_model == 13)
{
/* The more serious chips .. */
}
}
+ /* Reenable any watchpoints before delivering the
+ * signal to user space. The processor register will
+ * have been cleared if the watchpoint triggered
+ * inside the kernel.
+ */
+ __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7]));
+
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
return 1;
}
/*
- * Careful - we must not do a lock-kernel until we have checked that the
- * debug fault happened in user mode. Getting debug exceptions while
- * in the kernel has to be handled without locking, to avoid deadlocks..
+ * Our handling of the processor debug registers is non-trivial.
+ * We do not clear them on entry and exit from the kernel. Therefore
+ * it is possible to get a watchpoint trap here from inside the kernel.
+ * However, the code in ./ptrace.c has ensured that the user can
+ * only set watchpoints on userspace addresses. Therefore the in-kernel
+ * watchpoint trap can only occur in code which is reading/writing
+ * from user space. Such code must not hold kernel locks (since it
+ * can equally take a page fault), therefore it is safe to call
+ * force_sig_info even though that claims and releases locks.
+ *
+ * Code in ./signal.c ensures that the debug control register
+ * is restored before we deliver any signal, and therefore that
+ * user code runs with the correct debug control register even though
+ * we clear it here.
*
* Being careful here means that we don't have to be as careful in a
* lot of more complicated places (task switching can be a bit lazy
* about restoring all the debug state, and ptrace doesn't have to
* find every occurrence of the TF bit that could be saved away even
- * by user code - and we don't have to be careful about what values
- * can be written to the debug registers because there are no really
- * bad cases).
+ * by user code)
*/
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
goto clear_TF;
}
- /* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */
- if ((regs->xcs & 3) == 0)
- goto clear_dr7;
-
/* Ok, finally something we can handle */
tsk->thread.trap_no = 1;
tsk->thread.error_code = error_code;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = (void *)regs->eip;
+
+ /* If this is a kernel mode trap, save the user PC on entry to
+ * the kernel, that's what the debugger can make sense of.
+ */
+ info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip :
+ (void *)regs->eip;
force_sig_info(SIGTRAP, &info, tsk);
- return;
-
-debug_vm86:
- handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
- return;
+ /* Disable additional traps. They'll be re-enabled when
+ * the signal is delivered.
+ */
clear_dr7:
__asm__("movl %0,%%db7"
: /* no output */
: "r" (0));
return;
+debug_vm86:
+ handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+ return;
+
clear_TF:
regs->eflags &= ~TF_MASK;
return;
source drivers/block/paride/Config.in
fi
dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
+dep_tristate 'Compaq CISS Array support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI
dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
-if [ "$CONFIG_PCI" = "y" ]; then
- tristate 'Compaq CISS Array support' CONFIG_BLK_CPQ_CISS_DA
-fi
-
tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o
obj-$(CONFIG_BLK_DEV_XD) += xd.o
obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
-obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
+obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
*
*/
+#include <linux/config.h> /* CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/major.h>
-#include <linux/blkpg.h>
#include <linux/fs.h>
+#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
-#include <linux/capability.h>
+#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/genhd.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 1.0.0)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(1,0,0)
+#define DRIVER_NAME "Compaq CISS Driver (v 2.4.0)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,0)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
*/
#define DO_CCISS_REQUEST(x) { do_cciss_request(x); }
-static void do_cciss_request0(request_queue_t *q) DO_CCISS_REQUEST(0);
-static void do_cciss_request1(request_queue_t *q) DO_CCISS_REQUEST(1);
-static void do_cciss_request2(request_queue_t *q) DO_CCISS_REQUEST(2);
-static void do_cciss_request3(request_queue_t *q) DO_CCISS_REQUEST(3);
-static void do_cciss_request4(request_queue_t *q) DO_CCISS_REQUEST(4);
-static void do_cciss_request5(request_queue_t *q) DO_CCISS_REQUEST(5);
-static void do_cciss_request6(request_queue_t *q) DO_CCISS_REQUEST(6);
-static void do_cciss_request7(request_queue_t *q) DO_CCISS_REQUEST(7);
+static void do_cciss_request0(request_queue_t * q) DO_CCISS_REQUEST(0);
+static void do_cciss_request1(request_queue_t * q) DO_CCISS_REQUEST(1);
+static void do_cciss_request2(request_queue_t * q) DO_CCISS_REQUEST(2);
+static void do_cciss_request3(request_queue_t * q) DO_CCISS_REQUEST(3);
+static void do_cciss_request4(request_queue_t * q) DO_CCISS_REQUEST(4);
+static void do_cciss_request5(request_queue_t * q) DO_CCISS_REQUEST(5);
+static void do_cciss_request6(request_queue_t * q) DO_CCISS_REQUEST(6);
+static void do_cciss_request7(request_queue_t * q) DO_CCISS_REQUEST(7);
static int cciss_open(struct inode *inode, struct file *filep);
static int cciss_release(struct inode *inode, struct file *filep);
static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c);
static void start_io( ctlr_info_t *h);
+#ifdef CONFIG_PROC_FS
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data);
+static void cciss_procinit(int i);
+#else
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data) {}
+static void cciss_procinit(int i) {}
+#endif /* CONFIG_PROC_FS */
+
static struct block_device_operations cciss_fops = {
- ioctl: cciss_ioctl, /* ioctl */
- open: cciss_open, /* open code */
- release: cciss_release, /* release */
- revalidate: frevalidate_logvol, /* revalidate */
+ open: cciss_open,
+ release: cciss_release,
+ ioctl: cciss_ioctl,
+ revalidate: frevalidate_logvol,
};
/*
* Report information about this controller.
*/
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+#ifdef CONFIG_PROC_FS
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
{
off_t pos = 0;
off_t len = 0;
* Get us a file in /proc/cciss that says something about each controller.
* Create /proc/cciss if it doesn't exist yet.
*/
-static void cciss_procinit(int i)
+static void __init cciss_procinit(int i)
{
- struct proc_dir_entry *pd;
-
if (proc_cciss == NULL) {
- proc_cciss = proc_mkdir("cciss", NULL);
+ proc_cciss = proc_mkdir("driver/cciss", NULL);
if (!proc_cciss)
return;
}
- pd = create_proc_read_entry(hba[i]->devname, 0, proc_cciss,
- cciss_proc_get_info, hba[i]);
+ create_proc_read_entry(hba[i]->devname, 0, proc_cciss,
+ cciss_proc_get_info, hba[i]);
}
+#endif /* CONFIG_PROC_FS */
/*
* For operations that cannot sleep, a command block is allocated at init,
/*
* fills in the disk information.
*/
-static void cciss_geninit(int ctlr)
+static void cciss_geninit( int ctlr)
{
drive_info_struct *drv;
int i,j;
-
+
/* Loop through each real device */
- hba[ctlr]->gendisk.nr_real = 0;
+ hba[ctlr]->gendisk.nr_real = 0;
for(i=0; i< NWD; i++)
{
drv = &(hba[ctlr]->drv[i]);
printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
#endif /* CCISS_DEBUG */
- fsync_dev(inode->i_rdev);
+ /* fsync_dev(inode->i_rdev); */
hba[ctlr]->drv[dsk].usage_count--;
hba[ctlr]->usage_count--;
if (!arg) return -EINVAL;
put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (long*)arg);
return 0;
- case BLKRASET:
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (!(inode->i_rdev)) return -EINVAL;
- if (arg>0xff) return -EINVAL;
- read_ahead[MAJOR(inode->i_rdev)] = arg;
- return 0;
- case BLKRAGET:
- if (!arg) return -EINVAL;
- put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg);
- return 0;
case BLKRRPART:
return revalidate_logvol(inode->i_rdev, 1);
-
+ case BLKFLSBUF:
+ case BLKROSET:
+ case BLKROGET:
+ case BLKRASET:
+ case BLKRAGET:
+ case BLKPG:
+ return( blk_ioctl(inode->i_rdev, cmd, arg));
case CCISS_GETPCIINFO:
{
cciss_pci_info_struct pciinfo;
if (!arg) return -EINVAL;
- pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
- pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
+ pciinfo.bus = hba[ctlr]->pci_bus;
+ pciinfo.dev_fn = hba[ctlr]->pci_dev_fn;
pciinfo.board_id = hba[ctlr]->board_id;
- if(copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct)))
- return -EFAULT;
+ if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct ))
+ return -EFAULT;
return(0);
}
case CCISS_GETINTINFO:
if (!arg) return -EINVAL;
intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
- if(copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct)))
- return -EFAULT;
+ if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct ))
+ return -EFAULT;
return(0);
}
case CCISS_SETINTINFO:
if (!arg) return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if(copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
- return -EFAULT;
+ if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct))
+ return -EFAULT;
if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
{
if (!arg) return -EINVAL;
for(i=0;i<16;i++)
NodeName[i] = readb(&c->cfgtable->ServerName[i]);
- if(copy_to_user((void *) arg, NodeName, sizeof(NodeName_type)))
- return -EFAULT;
+ if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type))
+ return -EFAULT;
return(0);
}
case CCISS_SETNODENAME:
if (!arg) return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if(copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
+ if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type))
return -EFAULT;
spin_lock_irqsave(&io_request_lock, flags);
}
spin_unlock_irqrestore(&io_request_lock, flags);
if (i >= MAX_CONFIG_WAIT)
- return -EIO;
+ return( -EFAULT);
return(0);
}
if (!arg) return -EINVAL;
heartbeat = readl(&c->cfgtable->HeartBeat);
- if(copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
+ if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
BusTypes = readl(&c->cfgtable->BusTypes);
- if(copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type)))
- return -EFAULT;
+ if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) )
+ return -EFAULT;
return(0);
}
case CCISS_GETFIRMVER:
if (!arg) return -EINVAL;
memcpy(firmware, hba[ctlr]->firm_ver, 4);
- if(copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
+ if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
- if(copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type)))
+ if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) )
return -EFAULT;
return(0);
}
if (!capable(CAP_SYS_RAWIO)) return -EPERM;
- if(copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct)))
- return -EFAULT;
+ if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) )
+ return -EFAULT;
if((iocommand.buf_size < 1) &&
(iocommand.Request.Type.Direction != XFER_NONE))
{
if (iocommand.Request.Type.Direction == XFER_WRITE)
{
/* Copy the data into the buffer we created */
- if(copy_from_user(buff, iocommand.buf,iocommand.buf_size))
+ if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
return -EFAULT;
}
if ((c = cmd_alloc(NULL)) == NULL)
/* Wait for completion */
while(c->cmd_type != CMD_IOCTL_DONE)
- {
- set_task_state(current, TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- rmb();
- }
/* Copy the error information out */
iocommand.error_info = *(c->err_info);
- if ( copy_to_user((void *) arg, &iocommand,
- sizeof( IOCTL_Command_struct) ) < 0 )
+ if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
{
cmd_free(NULL, c);
if (buff != NULL)
if (iocommand.Request.Type.Direction == XFER_READ)
{
/* Copy the data out of the buffer we created */
- if (copy_to_user(iocommand.buf, buff,
- iocommand.buf_size) < 0)
+ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
{
cmd_free(NULL, c);
kfree(buff);
return(0);
}
- case BLKFLSBUF:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_rdev, cmd, arg);
-
default:
- return -EINVAL;
+ return -EBADRQC;
}
}
/* reset the blocksize so we can read the partition table */
blksize_size[MAJOR_NR+ctlr][minor] = 1024;
}
- gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blocks;
- /* 16 minors per disk... */
- grok_partitions(gdev, target, 16, hba[ctlr]->drv[target].nr_blocks);
+ /* setup partitions per disk */
+ grok_partitions(gdev, target, MAX_PART,
+ hba[ctlr]->drv[target].nr_blocks);
hba[ctlr]->drv[target].usage_count--;
return 0;
}
/*
* Map (physical) PCI mem into (virtual) kernel space
*/
-static void *remap_pci_mem(ulong base, ulong size)
+static ulong remap_pci_mem(ulong base, ulong size)
{
ulong page_base = ((ulong) base) & PAGE_MASK;
ulong page_offs = ((ulong) base) - page_base;
- void *page_remapped = ioremap(page_base, page_offs+size);
+ ulong page_remapped = (ulong) ioremap(page_base, page_offs+size);
- return (page_remapped ? (page_remapped + page_offs) : NULL);
+ return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
}
/*
int log_unit, start_blk, seg, sect;
char *lastdataend;
struct buffer_head *bh;
- struct request *creq;
struct list_head *queue_head;
+ struct request *creq;
u64bit temp64;
- queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head;
-
- if(list_empty(queue_head))
+ queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head;
+ if (list_empty(queue_head))
+ {
+ /* nothing to do... */
+ start_io(h);
+ return;
+ }
+ creq = blkdev_entry_next_request(queue_head);
+ if ((creq == NULL) || (creq->rq_status == RQ_INACTIVE))
{
/* nothing to do... restart processing and return */
start_io(h);
return;
}
- creq = blkdev_entry_next_request(queue_head);
- if (creq->rq_status == RQ_INACTIVE)
- {
- start_io(h);
- return;
- }
-
if ((ctlr != (MAJOR(creq->rq_dev)-MAJOR_NR)) || (ctlr > nr_ctlr)
|| (h == NULL))
{
ctlr, creq->rq_dev, creq);
#endif /* CCISS_DEBUG */
complete_buffers(creq->bh, 0);
+ start_io(h);
return;
}
if (( c = cmd_alloc(h)) == NULL)
} else
{
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss: Done with %p, queueing %p\n", creq, creq->next);
+ printk("cciss: Done with %p, queueing %p\n", creq);
#endif /* CCISS_DEBUG */
+
blkdev_dequeue_request(creq);
end_that_request_last(creq);
}
}
#endif /* CCISS_DEBUG */
-static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
+static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
{
ushort vendor_id, device_id, command;
unchar cache_line_size, latency_timer;
unchar irq, revision;
- unsigned long addr[6];
+ uint addr[6];
__u32 board_id;
+ struct pci_dev *pdev;
int i;
+ pdev = pci_find_slot(bus, device_fn);
vendor_id = pdev->vendor;
device_id = pdev->device;
irq = pdev->irq;
for(i=0; i<6; i++)
- addr[i] = pci_resource_start(pdev, i);
+ addr[i] = pdev->resource[i].start;
+
+ if (pci_enable_device(pdev))
+ return( -1);
+
(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
- (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION,&revision);
- (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
- (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
+ (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ &cache_line_size);
+ (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
+ &latency_timer);
- (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, &board_id);
+ (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID,
+ &board_id);
#ifdef CCISS_DEBUG
printk("vendor_id = %x\n", vendor_id);
* Memory base addr is first addr , the second points to the config
* table
*/
- c->paddr = addr[0];
+ c->paddr = pci_resource_start(pdev, 0);
c->vaddr = remap_pci_mem(c->paddr, 128);
c->cfgtable = (CfgTable_struct *) remap_pci_mem(addr[1],
sizeof(CfgTable_struct));
*/
static int cciss_pci_detect(void)
{
- struct pci_dev *pdev;
- pdev = pci_find_device(PCI_VENDOR_ID_COMPAQ,
- PCI_DEVICE_ID_COMPAQ_CISS, NULL);
- while (pdev) {
+ int index;
+ unchar bus=0, dev_fn=0;
+
+ for(index=0; ; index++) {
+ if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+ PCI_DEVICE_ID_COMPAQ_CISS,
+ index, &bus, &dev_fn))
+ break;
printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n",
- PCI_DEVICE_ID_COMPAQ_CISS,
- pdev->bus->number, pdev->devfn);
+ PCI_DEVICE_ID_COMPAQ_CISS, bus, dev_fn);
+ if (index == 1000000) break;
if (nr_ctlr == 8) {
printk(KERN_WARNING "cciss: This driver"
" supports a maximum of 8 controllers.\n");
break;
}
- if (pci_enable_device(pdev))
- continue;
hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
if(hba[nr_ctlr]==NULL)
{
continue;
}
memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cciss_pci_init(hba[nr_ctlr], pdev) != 0)
+ if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
{
kfree(hba[nr_ctlr]);
continue;
}
sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr);
hba[nr_ctlr]->ctlr = nr_ctlr;
- hba[nr_ctlr]->pci_dev = pdev;
+ hba[nr_ctlr]->pci_bus = bus;
+ hba[nr_ctlr]->pci_dev_fn = dev_fn;
nr_ctlr++;
- pdev = pci_find_device(PCI_VENDOR_ID_COMPAQ,
- PCI_DEVICE_ID_COMPAQ_CISS, pdev);
- }
+ }
return nr_ctlr;
}
* stealing all these major device numbers.
* returns the number of block devices registered.
*/
-int cciss_init(void)
+int __init cciss_init(void)
{
int num_cntlrs_reg = 0;
- int i;
- int j;
+ int i,j;
void (*request_fns[MAX_CTLR])(request_queue_t *) = {
do_cciss_request0, do_cciss_request1,
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
cciss_procinit(i);
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR+i),
+ request_fns[i]);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR+i), 0);
+
+ /* fill in the other Kernel structs */
+ blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
+ hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
+ read_ahead[MAJOR_NR+i] = READ_AHEAD;
+
/* Fill in the gendisk data */
hba[i]->gendisk.major = MAJOR_NR + i;
hba[i]->gendisk.major_name = "cciss";
hba[i]->gendisk.sizes = hba[i]->sizes;
hba[i]->gendisk.nr_real = hba[i]->num_luns;
- /* fill in the other Kernel structs */
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i),
- request_fns[i]);
- blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0);
- blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
- hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
- read_ahead[MAJOR_NR+i] = READ_AHEAD;
-
/* Get on the disk list */
hba[i]->gendisk.next = gendisk_head;
gendisk_head = &(hba[i]->gendisk);
-
+
cciss_geninit(i);
- for(j=0; j<NWD; j++)
- register_disk(&hba[i]->gendisk,
- MKDEV(MAJOR_NR+i,j<<4),
- 16, &cciss_fops, hba[i]->drv[j].nr_blocks);
+ for(j=0; j<NWD; j++)
+ register_disk(&(hba[i]->gendisk),
+ MKDEV(MAJOR_NR+i, j <<4),
+ MAX_PART, &cciss_fops,
+ hba[i]->drv[j].nr_blocks);
}
return(nr_ctlr);
}
-#ifdef MODULE
EXPORT_NO_SYMBOLS;
-
/* This is a bit of a hack... */
-int init_module(void)
+static int __init init_cciss_module(void)
{
+
if (cciss_init() == 0) /* all the block dev numbers already used */
return -EIO; /* or no controllers were found */
return 0;
}
-void cleanup_module(void)
+static void __exit cleanup_cciss_module(void)
{
int i;
struct gendisk *g;
/* Turn board interrupts off */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
free_irq(hba[i]->intr, hba[i]);
- iounmap(hba[i]->vaddr);
+ iounmap((void*)hba[i]->vaddr);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i));
remove_proc_entry(hba[i]->devname, proc_cciss);
/* remove it from the disk list */
}
}
}
- remove_proc_entry("cciss", &proc_root);
+ remove_proc_entry("driver/cciss", &proc_root);
kfree(hba[i]->cmd_pool);
kfree(hba[i]->errinfo_pool);
kfree(hba[i]->cmd_pool_bits);
}
}
-#endif /* MODULE */
-
+module_init(init_cciss_module);
+module_exit(cleanup_cciss_module);
char devname[8];
char *product_name;
char firm_ver[4]; // Firmware version
- struct pci_dev *pci_dev;
+ unchar pci_bus;
+ unchar pci_dev_fn;
__u32 board_id;
- void *vaddr;
- unsigned long paddr;
+ ulong vaddr;
+ __u32 paddr;
CfgTable_struct *cfgtable;
int intr;
major = MAJOR(req->rq_dev);
if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7)
(q->request_fn)(q);
- if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7)
- (q->request_fn)(q);
if (major >= COMPAQ_CISS_MAJOR+0 && major <= COMPAQ_CISS_MAJOR+7)
+ (q->request_fn)(q);
+ if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7)
(q->request_fn)(q);
}
if (parport_nr[0] == LP_PARPORT_AUTO &&
port->probe_info[0].class != PARPORT_CLASS_PRINTER)
return;
-
+ if (lp_count == LP_NO) {
+ printk("lp: ignoring parallel port (max. %d)\n",LP_NO);
+ return;
+ }
if (!lp_register(lp_count, port))
- if (++lp_count == LP_NO)
- break;
-
+ lp_count++;
break;
default:
#ifdef CONFIG_I2C
extern int i2c_init_all(void);
#endif
-#ifdef CONFIG_SOUND
-void soundcore_init(void);
-#ifdef CONFIG_SOUND_OSS
-void soundcard_init(void);
-#endif
-#endif
#ifdef CONFIG_SPARCAUDIO
extern int sparcaudio_init(void);
#endif
lp_m68k_init();
#endif
misc_init();
-#ifdef CONFIG_SOUND
- soundcore_init();
-#ifdef CONFIG_SOUND_OSS
- soundcard_init();
-#endif
-#endif
-#ifdef CONFIG_SPARCAUDIO
- sparcaudio_init();
-#endif
#if CONFIG_QIC02_TAPE
qic02_tape_init();
#endif
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/delay.h>
#include <asm/io.h>
struct JEDECTable mtd_JEDEC_table[] =
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (5*HZ)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/klconfig.h>
-#include <asm/ioc3.h>
+#include <asm/sn/ioc3.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/pci/bridge.h>
#endif
/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#endif
/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
fi
dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
+dep_tristate ' Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
fi
fi
- dep_tristate ' SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS
- if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then
- int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050
- int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32
- fi
-
dep_tristate ' 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
dep_tristate ' AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS
dep_tristate ' Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
-obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
+obj-$(CONFIG_SOUND_CS4281) += cs4281.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
# Declare multi-part drivers.
-list-multi := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
+list-multi := sound.o gus.o pas2.o sb.o sb_lib.o vidc_mod.o \
soundcore.o wavefront.o
sound-objs := \
pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
sb-objs := sb_card.o
sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
-softoss2-objs := softoss.o softoss_rs.o
vidc_mod-objs := vidc.o vidc_fill.o
wavefront-objs := wavfront.o wf_midi.o yss225.o
sb_lib.o: $(sb_lib-objs)
$(LD) -r -o $@ $(sb_lib-objs)
-softoss2.o: $(softoss2-objs)
- $(LD) -r -o $@ $(softoss2-objs)
-
vidc_mod.o: $(vidc_mod-objs)
$(LD) -r -o $@ $(vidc_mod-objs)
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/ac97_codec.h>
#include <asm/uaccess.h>
/* also according to spec, we wait for codec-ready state */
if (codec->codec_wait)
codec->codec_wait(codec);
- else {
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(5);
- }
+ else
+ udelay(10);
if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
for (i = 0; i < arraysize(ac97_codec_ids); i++) {
if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
- codec->id = ac97_codec_ids[i].id;
codec->name = ac97_codec_ids[i].name;
codec->codec_init = ac97_codec_ids[i].init;
break;
codec->codec_write(codec, AC97_PCMOUT_VOL, 0L);
/* codec specific initialization for 4-6 channel output or secondary codec stuff */
- if (codec->id != 0 && codec->codec_init != NULL) {
+ if (codec->codec_init != NULL) {
codec->codec_init(codec);
}
static int sigmatel_init(struct ac97_codec * codec)
{
+ /* Only set up secondary codec */
+ if (codec->id == 0)
+ return 1;
+
codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
MODULE_PARM(spdif_loop, "i");
MODULE_PARM(four_ch, "i");
MODULE_PARM(rear_out, "i");
-
-int __init init_module(void)
#else
#ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
static int spdif_loop = 1;
#else
static int rear_out = 0;
#endif
-
-int __init init_cmpci(void)
#endif
+
+static int __init init_cmpci(void)
{
struct cm_state *s;
struct pci_dev *pcidev = NULL;
/* --------------------------------------------------------------------- */
-#ifdef MODULE
-
MODULE_AUTHOR("ChenLi Tien, cltien@home.com");
MODULE_DESCRIPTION("CMPCI Audio Driver");
-void cleanup_module(void)
+static void __exit cleanup_cmpci(void)
{
struct cm_state *s;
printk(KERN_INFO "cmpci: unloading\n");
}
-#endif /* MODULE */
+module_init(init_cmpci);
+module_exit(cleanup_cmpci);
--- /dev/null
+//*****************************************************************************
+//
+// "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
+//
+// Copyright (C) 2000 Cirrus Logic Corp.
+// -- adapted from drivers by Thomas Sailer,
+// -- but don't bug him; Problems should go to:
+// -- gw boynton (wesb@crystal.cirrus.com) or
+// -- tom woller (twoller@crystal.cirrus.com).
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// Module command line parameters:
+// none
+//
+// Supported devices:
+// /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
+// /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
+// /dev/midi simple MIDI UART interface, no ioctl
+//
+//
+//
+
+// *****************************************************************************
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <linux/vmalloc.h>
+#include "dm.h"
+#include "cs4281_hwdefs.h"
+
+EXPORT_NO_SYMBOLS;
+
+#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+// ---------------------------------------------------------------------
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281
+#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005
+#endif
+
+#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
+
+#define CSDEBUG 1
+//
+// Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
+//
+//
+// CSDEBUG is usual mode is set to 1, then use the
+// cs_debuglevel and cs_debugmask to turn on or off debugging.
+// Debug level of 1 has been defined to be kernel errors and info
+// that should be printed on any released driver.
+//
+#if CSDEBUG
+extern unsigned cs_debugmask;
+extern unsigned cs_debuglevel;
+#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
+#else
+#define CS_DBGOUT(mask,level,x)
+#endif
+//
+// cs_debugmask areas
+//
+#define CS_INIT 0x00000001 // initialization and probe functions
+#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
+#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
+#define CS_FUNCTION 0x00000008 // enter/leave functions
+#define CS_WAVE_WRITE 0x00000010 // write information for wave
+#define CS_WAVE_READ 0x00000020 // read information for wave
+#define CS_MIDI_WRITE 0x00000040 // write information for midi
+#define CS_MIDI_READ 0x00000080 // read information for midi
+#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
+#define CS_MPU401_READ 0x00000200 // read information for mpu401
+#define CS_OPEN 0x00000400 // all open functions in the driver
+#define CS_RELEASE 0x00000800 // all release functions in the driver
+#define CS_PARMS 0x00001000 // functional and operational parameters
+#define CS_TMP 0x10000000 // tmp debug mask bit
+
+unsigned cs_debuglevel=1; // levels range from 1-9
+unsigned cs_debugmask=CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
+#if MODULE
+MODULE_PARM(cs_debuglevel, "i");
+MODULE_PARM(cs_debugmask, "i");
+#endif
+
+// MIDI buffer sizes
+#define MIDIINBUF 500
+#define MIDIOUTBUF 500
+
+#define FMODE_MIDI_SHIFT 3
+#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
+#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+#define CS4281_MAJOR_VERSION 0
+#define CS4281_MINOR_VERSION 4
+#ifdef __ia64__
+#define CS4281_ARCH 64 //architecture key
+#else
+#define CS4281_ARCH 32 //architecture key
+#endif
+
+struct cs4281_state {
+ // magic
+ unsigned int magic;
+
+ // we keep the cards in a linked list
+ struct cs4281_state *next;
+
+ // pcidev is needed to turn off the DDMA controller at driver shutdown
+ struct pci_dev *pcidev;
+
+ // soundcore stuff
+ int dev_audio;
+ int dev_mixer;
+ int dev_midi;
+
+ // hardware resources
+ unsigned int pBA0phys, pBA1phys;
+ char *pBA0, *pBA1;
+ unsigned int irq;
+ int endofbuffer;
+
+ // mixer registers
+ struct {
+ unsigned short vol[10];
+ unsigned int recsrc;
+ unsigned int modcnt;
+ unsigned short micpreamp;
+ } mix;
+
+ // wave stuff // Note that play & record formats must be the same *wb.
+ unsigned fmt;
+ unsigned channels;
+ unsigned rate;
+ unsigned char clkdiv;
+ unsigned ena;
+
+ spinlock_t lock;
+ struct semaphore open_sem;
+ mode_t open_mode;
+ wait_queue_head_t open_wait;
+
+ struct dmabuf {
+ void *rawbuf; // Physical address of
+ dma_addr_t dmaaddr;
+ unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
+ unsigned numfrag; // # of 'fragments' in the buffer.
+ unsigned fragshift; // Log base 2 of fragment size.
+ unsigned hwptr, swptr;
+ unsigned total_bytes; // # bytes process since open.
+ unsigned blocks; // last returned blocks value GETOPTR
+ int count;
+ unsigned error; // over/underrun
+ wait_queue_head_t wait;
+ // redundant, but makes calculations easier
+ unsigned fragsize; // 2**fragshift..
+ unsigned dmasize; // 2**buforder.
+ unsigned fragsamples;
+ // OSS stuff
+ unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
+ unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
+ unsigned endcleared:1;
+ unsigned ossfragshift;
+ int ossmaxfrags;
+ unsigned subdivision;
+ } dma_dac, dma_adc;
+
+ // midi stuff
+ struct {
+ unsigned ird, iwr, icnt;
+ unsigned ord, owr, ocnt;
+ wait_queue_head_t iwait;
+ wait_queue_head_t owait;
+ struct timer_list timer;
+ unsigned char ibuf[MIDIINBUF];
+ unsigned char obuf[MIDIOUTBUF];
+ } midi;
+
+};
+
+
+struct cs4281_state *devs = NULL;
+// ---------------------------------------------------------------------
+//
+// Hardware Interfaces For the CS4281
+//
+
+
+//******************************************************************************
+// "delayus()-- Delay for the specified # of microseconds.
+//******************************************************************************
+static void delayus(u32 delay)
+{
+ u32 j;
+ if(delay > 9999)
+ {
+ j = (delay * HZ)/1000000; /* calculate delay in jiffies */
+ if(j<1)
+ j=1; /* minimum one jiffy. */
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(j);
+ }
+ else
+ udelay(delay);
+ return;
+}
+
+
+//******************************************************************************
+// "cs4281_read_ac97" -- Reads a word from the specified location in the
+// CS4281's address space(based on the BA0 register).
+//
+// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
+// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,
+// 0h for reads.
+// 3. Write ACCTL = Control Register = 460h for initiating the write
+// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
+// 5. if DCV not cleared, break and return error
+// 6. Read ACSTS = Status Register = 464h, check VSTS bit
+//****************************************************************************
+static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, u32 *value)
+{
+ u32 count, status;
+
+ // Make sure that there is not data sitting
+ // around from a previous uncompleted access.
+ // ACSDA = Status Data Register = 47Ch
+ status = readl(card->pBA0+BA0_ACSDA);
+
+ // Setup the AC97 control registers on the CS4281 to send the
+ // appropriate command to the AC97 to perform the read.
+ // ACCAD = Command Address Register = 46Ch
+ // ACCDA = Command Data Register = 470h
+ // ACCTL = Control Register = 460h
+ // bit DCV - will clear when process completed
+ // bit CRW - Read command
+ // bit VFRM - valid frame enabled
+ // bit ESYN - ASYNC generation enabled
+
+ // Get the actual AC97 register from the offset
+ writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD);
+ writel(0, card->pBA0+BA0_ACCDA);
+ writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL);
+
+ // Wait for the read to occur.
+ for(count = 0; count < 10; count++)
+ {
+ // First, we want to wait for a short time.
+ udelay(25);
+
+ // Now, check to see if the read has completed.
+ // ACCTL = 460h, DCV should be reset by now and 460h = 17h
+ if( !(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV))
+ break;
+ }
+
+ // Make sure the read completed.
+ if(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV)
+ return 1;
+
+ // Wait for the valid status bit to go active.
+ for(count = 0; count < 10; count++)
+ {
+ // Read the AC97 status register.
+ // ACSTS = Status Register = 464h
+ status = readl(card->pBA0+BA0_ACSTS);
+
+ // See if we have valid status.
+ // VSTS - Valid Status
+ if(status & ACSTS_VSTS)
+ break;
+ // Wait for a short while.
+ udelay(25);
+ }
+
+ // Make sure we got valid status.
+ if(!(status & ACSTS_VSTS))
+ return 1;
+
+ // Read the data returned from the AC97 register.
+ // ACSDA = Status Data Register = 474h
+ *value = readl(card->pBA0+BA0_ACSDA);
+
+ // Success.
+ return(0);
+}
+
+
+//****************************************************************************
+//
+// "cs4281_write_ac97()"-- writes a word to the specified location in the
+// CS461x's address space (based on the part's base address zero register).
+//
+// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
+// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.
+// 3. Write ACCTL = Control Register = 460h for initiating the write
+// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
+// 5. if DCV not cleared, break and return error
+//
+//****************************************************************************
+static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, u32 value)
+{
+ u32 count, status;
+
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n") );
+
+ // Setup the AC97 control registers on the CS4281 to send the
+ // appropriate command to the AC97 to perform the read.
+ // ACCAD = Command Address Register = 46Ch
+ // ACCDA = Command Data Register = 470h
+ // ACCTL = Control Register = 460h
+ // set DCV - will clear when process completed
+ // reset CRW - Write command
+ // set VFRM - valid frame enabled
+ // set ESYN - ASYNC generation enabled
+ // set RSTN - ARST# inactive, AC97 codec not reset
+
+ // Get the actual AC97 register from the offset
+
+ writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD);
+ writel(value, card->pBA0+BA0_ACCDA);
+ writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL);
+
+ // Wait for the write to occur.
+ for(count = 0; count < 10; count++)
+ {
+ // First, we want to wait for a short time.
+ udelay(25);
+ // Now, check to see if the write has completed.
+ // ACCTL = 460h, DCV should be reset by now and 460h = 07h
+ status = readl(card->pBA0+BA0_ACCTL);
+ if(!(status & ACCTL_DCV))
+ break;
+ }
+
+ // Make sure the write completed.
+ if(status & ACCTL_DCV)
+ {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+ "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n") );
+ return 1;
+ }
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n") );
+ // Success.
+ return 0;
+}
+
+
+//******************************************************************************
+// "Init4281()" -- Bring up the part.
+//******************************************************************************
+static int cs4281_hw_init(struct cs4281_state *card)
+{
+ u32 ac97_slotid;
+ u32 temp1, temp2;
+
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n") );
+ //***************************************7
+ // Set up the Sound System Configuration
+ //***************************************
+
+ // Set the 'Configuration Write Protect' register
+ // to 4281h. Allows vendor-defined configuration
+ // space between 0e4h and 0ffh to be written.
+
+ writel(0x4281, card->pBA0+BA0_CWPR); // (3e0h)
+
+ // (0), Blast the clock control register to zero so that the
+ // PLL starts out in a known state, and blast the master serial
+ // port control register to zero so that the serial ports also
+ // start out in a known state.
+
+ writel(0, card->pBA0+BA0_CLKCR1); // (400h)
+ writel(0, card->pBA0+BA0_SERMC); // (420h)
+
+
+ // (1), Make ESYN go to zero to turn off
+ // the Sync pulse on the AC97 link.
+
+ writel(0, card->pBA0+BA0_ACCTL);
+ udelay(50);
+
+
+ // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
+ // the AC97 spec) and then drive it high. This is done for non
+ // AC97 modes since there might be logic external to the CS461x
+ // that uses the ARST# line for a reset.
+
+ writel(0, card->pBA0+BA0_SPMC); // (3ech)
+ udelay(100);
+ writel(SPMC_RSTN, card->pBA0+BA0_SPMC);
+ delayus(50000); // Wait 50 ms for ABITCLK to become stable.
+
+ // (3) Turn on the Sound System Clocks.
+ writel(CLKCR1_PLLP, card->pBA0+BA0_CLKCR1); // (400h)
+ delayus(50000); // Wait for the PLL to stabilize.
+ // Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
+ writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0+BA0_CLKCR1);
+
+ // (4) Power on everything for now..
+ writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
+
+ // (5) Wait for clock stabilization.
+ for(temp1=0; temp1<1000; temp1++)
+ {
+ udelay(1000);
+ if(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY)
+ break;
+ }
+ if(!(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY))
+ {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: DLLRDY failed!\n") );
+ return -EIO;
+ }
+
+ // (6) Enable ASYNC generation.
+ writel(ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h)
+
+ // Now wait 'for a short while' to allow the AC97
+ // part to start generating bit clock. (so we don't
+ // Try to start the PLL without an input clock.)
+ delayus(50000);
+
+ // Set the serial port timing configuration, so that the
+ // clock control circuit gets its clock from the right place.
+ writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2.
+
+ // (7) Wait for the codec ready signal from the AC97 codec.
+
+ for(temp1=0; temp1<1000; temp1++)
+ {
+ // Delay a mil to let things settle out and
+ // to prevent retrying the read too quickly.
+ udelay(1000);
+ if( readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY ) // If ready, (464h)
+ break; // exit the 'for' loop.
+ }
+ if( !(readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY) ) // If never came ready,
+ {
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_ERR "cs4281: ACSTS never came ready!\n") );
+ return -EIO; // exit initialization.
+ }
+
+ // (8) Assert the 'valid frame' signal so we can
+ // begin sending commands to the AC97 codec.
+ writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h)
+
+ // (9), Wait until CODEC calibration is finished.
+ // Print an error message if it doesn't.
+ for(temp1 = 0; temp1 < 1000; temp1++)
+ {
+ delayus(10000);
+ // Read the AC97 Powerdown Control/Status Register.
+ cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
+ if( (temp2 & 0x0000000F) == 0x0000000F )
+ break;
+ }
+ if ( (temp2 & 0x0000000F) != 0x0000000F )
+ {
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
+ "cs4281: Codec failed to calibrate. Status = %.8x.\n", temp2) );
+ return -EIO;
+ }
+
+ // (10), Set the serial port timing configuration, so that the
+ // clock control circuit gets its clock from the right place.
+ writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2.
+
+
+ // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
+ // that the codec is pumping ADC data across the AC link.
+ for(temp1=0; temp1<1000; temp1++)
+ {
+ // Delay a mil to let things settle out and
+ // to prevent retrying the read too quickly.
+ delayus(1000); //(test)
+
+ // Read the input slot valid register; See
+ // if input slots 3 and 4 are valid yet.
+ if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) )
+ == (ACISV_ISV3 | ACISV_ISV4))
+ break; // Exit the 'for' if slots are valid.
+ }
+ // If we never got valid data, exit initialization.
+ if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) )
+ != (ACISV_ISV3 | ACISV_ISV4))
+ {
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR "cs4281: Never got valid data!\n"));
+ return -EIO; // If no valid data, exit initialization.
+ }
+
+ // (12), Start digital data transfer of audio data to the codec.
+ writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0+BA0_ACOSV); // (468h)
+
+
+ //**************************************
+ // Unmute the Master and Alternate
+ // (headphone) volumes. Set to max.
+ //**************************************
+ cs4281_write_ac97(card,BA0_AC97_HEADPHONE_VOLUME, 0);
+ cs4281_write_ac97(card,BA0_AC97_MASTER_VOLUME, 0);
+
+ //******************************************
+ // Power on the DAC(AddDACUser()from main())
+ //******************************************
+ cs4281_read_ac97(card,BA0_AC97_POWERDOWN, &temp1);
+ cs4281_write_ac97(card,BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
+
+ // Wait until we sample a DAC ready state.
+ for(temp2=0; temp2<32; temp2++)
+ {
+ // Let's wait a mil to let things settle.
+ delayus(1000);
+ // Read the current state of the power control reg.
+ cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+ // If the DAC ready state bit is set, stop waiting.
+ if(temp1 & 0x2)
+ break;
+ }
+
+ //******************************************
+ // Power on the ADC(AddADCUser()from main())
+ //******************************************
+ cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+ cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
+
+ // Wait until we sample ADC ready state.
+ for(temp2=0; temp2<32; temp2++)
+ {
+ // Let's wait a mil to let things settle.
+ delayus(1000);
+ // Read the current state of the power control reg.
+ cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+ // If the ADC ready state bit is set, stop waiting.
+ if(temp1 & 0x1)
+ break;
+ }
+ // Set up 4281 Register contents that
+ // don't change for boot duration.
+
+ // For playback, we map AC97 slot 3 and 4(Left
+ // & Right PCM playback) to DMA Channel 0.
+ // Set the fifo to be 15 bytes at offset zero.
+
+ ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback).
+ // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
+ // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
+ writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
+ writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
+
+ // For capture, we map AC97 slot 10 and 11(Left
+ // and Right PCM Record) to DMA Channel 1.
+ // Set the fifo to be 15 bytes at offset sixteen.
+ ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record).
+ // FCR1.LS[4:0]=10(=>slot10, left PCM record).
+ // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
+ writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
+ writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
+
+ // Map the Playback SRC to the same AC97 slots(3 & 4--
+ // --Playback left & right)as DMA channel 0.
+ // Map the record SRC to the same AC97 slots(10 & 11--
+ // -- Record left & right) as DMA channel 1.
+
+ ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
+ // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
+ // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
+ // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
+ writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
+
+ // Set 'Half Terminal Count Interrupt Enable' and 'Terminal
+ // Count Interrupt Enable' in DMA Control Registers 0 & 1.
+ // Set 'MSK' flag to 1 to keep the DMA engines paused.
+ temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
+ writel(temp1, card->pBA0 + BA0_DCR0); // (154h
+ writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
+
+ // Set 'Auto-Initialize Control' to 'enabled'; For playback,
+ // set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
+ // for record, set Transfer Type Control to 'write transfer'.
+ // All other bits set to zero; Some will be changed @ transfer start.
+ temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
+ writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
+ temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
+ writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
+
+ // Enable DMA interrupts generally, and
+ // DMA0 & DMA1 interrupts specifically.
+ temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
+ writel(temp1, card->pBA0+BA0_HIMR);
+
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n") );
+ return 0;
+}
+
+
+//******************************************************************************
+// "cs4281_play_rate()" --
+//******************************************************************************
+static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
+{
+ u32 DACSRvalue = 1;
+
+ // Based on the sample rate, program the DACSR register.
+ if(playrate == 8000)
+ DACSRvalue = 5;
+ if(playrate == 11025)
+ DACSRvalue = 4;
+ else if(playrate == 22050)
+ DACSRvalue = 2;
+ else if(playrate == 44100)
+ DACSRvalue = 1;
+ else if((playrate <= 48000) && (playrate >= 6023))
+ DACSRvalue = 24576000/(playrate*16);
+ else if(playrate < 6023)
+ // Not allowed by open.
+ return;
+ else if(playrate > 48000)
+ // Not allowed by open.
+ return;
+ CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
+ DACSRvalue,playrate));
+ // Write the 'sample rate select code'
+ // to the 'DAC Sample Rate' register.
+ writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
+}
+
+//******************************************************************************
+// "cs4281_record_rate()" -- Initialize the record sample rate converter.
+//******************************************************************************
+static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
+{
+ u32 ADCSRvalue = 1;
+
+ //
+ // Based on the sample rate, program the ADCSR register
+ //
+ if(outrate == 8000)
+ ADCSRvalue = 5;
+ if(outrate == 11025)
+ ADCSRvalue = 4;
+ else if(outrate == 22050)
+ ADCSRvalue = 2;
+ else if(outrate == 44100)
+ ADCSRvalue = 1;
+ else if((outrate <= 48000) && (outrate >= 6023))
+ ADCSRvalue = 24576000/(outrate*16);
+ else if(outrate < 6023)
+ {
+ // Not allowed by open.
+ return;
+ }
+ else if(outrate > 48000)
+ {
+ // Not allowed by open.
+ return;
+ }
+ CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
+ ADCSRvalue,outrate) );
+ // Write the 'sample rate select code
+ // to the 'ADC Sample Rate' register.
+ writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
+}
+
+
+
+static void stop_dac(struct cs4281_state *s)
+{
+ unsigned long flags;
+ unsigned temp1;
+
+ CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n") );
+ spin_lock_irqsave(&s->lock, flags);
+ s->ena &= ~FMODE_WRITE;
+ temp1 = readl(s->pBA0+ BA0_DCR0) | DCRn_MSK;
+ writel(temp1, s->pBA0+BA0_DCR0);
+
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+
+static void start_dac(struct cs4281_state *s)
+{
+ unsigned long flags;
+ unsigned temp1;
+
+ CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_dac():\n") );
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
+ s->dma_dac.count > 0) && s->dma_dac.ready) {
+ s->ena |= FMODE_WRITE;
+ temp1 = readl(s->pBA0+BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
+ writel(temp1, s->pBA0+BA0_DCR0); // Start DMA'ing.
+ writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts.
+
+ writel(7, s->pBA0+BA0_PPRVC);
+ writel(7, s->pBA0+BA0_PPLVC);
+
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+
+static void stop_adc(struct cs4281_state *s)
+{
+ unsigned long flags;
+ unsigned temp1;
+
+ CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO "cs4281: stop_adc():\n") );
+
+ spin_lock_irqsave(&s->lock, flags);
+ s->ena &= ~FMODE_READ;
+ temp1 = readl(s->pBA0+ BA0_DCR1) | DCRn_MSK;
+ writel(temp1, s->pBA0+BA0_DCR1);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+
+static void start_adc(struct cs4281_state *s)
+{
+ unsigned long flags;
+ unsigned temp1;
+
+ CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_adc():\n") );
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped
+ || s->dma_adc.count <=
+ (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+ && s->dma_adc.ready)
+ {
+ s->ena |= FMODE_READ;
+ temp1 = readl(s->pBA0+BA0_DCR1) & ~ DCRn_MSK; // Clear DMA1 channel mask bit.
+ writel(temp1, s->pBA0+BA0_DCR1); // Start recording
+ writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts.
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+
+}
+
+
+// ---------------------------------------------------------------------
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) // == 3(for PC), = log base 2( buff sz = 32k).
+#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
+
+
+extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
+{
+ struct page *map, *mapend;
+
+ if (db->rawbuf) {
+ // Undo prog_dmabuf()'s marking the pages as reserved
+ mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+ for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
+ clear_bit(PG_reserved, &map->flags);
+ pci_free_consistent(s->pcidev,PAGE_SIZE<<db->buforder,
+ db->rawbuf,db->dmaaddr);
+ }
+ db->rawbuf = NULL;
+ db->mapped = db->ready = 0;
+}
+
+static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
+{
+ int order;
+ unsigned bytespersec, temp1;
+ unsigned bufs, sample_shift = 0;
+ struct page *map, *mapend;
+
+ db->hwptr = db->swptr = db->total_bytes = db->count =
+ db->error = db->endcleared = db->blocks = 0;
+ if (!db->rawbuf) {
+ db->ready = db->mapped = 0;
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((db->rawbuf = (void *)pci_alloc_consistent(
+ s->pcidev, PAGE_SIZE << order, &db->dmaaddr)))
+ break;
+ if (!db->rawbuf)
+ {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: prog_dmabuf(): unable to allocate rawbuf\n") );
+ return -ENOMEM;
+ }
+ db->buforder = order;
+ // Now mark the pages as reserved; otherwise the
+ // remap_page_range() in cs4281_mmap doesn't work.
+ // 1. get index to last page in mem_map array for rawbuf.
+ mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+
+ // 2. mark each physical page in range as 'reserved'.
+ for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
+ set_bit(PG_reserved, &map->flags);
+ }
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ sample_shift++;
+ if (s->channels > 1)
+ sample_shift++;
+ bytespersec = s->rate << sample_shift;
+ bufs = PAGE_SIZE << db->buforder;
+
+
+#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
+ db->numfrag = 2;
+ temp1 = bytespersec/(1000/INTERRUPT_RATE_MS); // Nominal frag size(bytes/interrupt)
+ db->fragshift = 8; // Min 256 bytes.
+ while( 1 << db->fragshift < temp1) // Calc power of 2 frag size.
+ db->fragshift +=1;
+ db->fragsize = 1 << db->fragshift;
+ db->dmasize = db->fragsize * 2;
+
+ // If the calculated size is larger than the allocated
+ // buffer, divide the allocated buffer into 2 fragments.
+ if(db->dmasize > bufs) {
+ db->numfrag = 2; // Two fragments.
+ db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
+ db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
+ db->dmasize = bufs; // Use all the alloc'ed buffer.
+
+ db->fragshift = 0; // Calculate 'fragshift'.
+ temp1 = db->fragsize; // update_ptr() uses it
+ while( (temp1 >>=1) > 1) // to calc 'total-bytes'
+ db->fragshift +=1; // returned in DSP_GETI/OPTR.
+ }
+ CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
+ "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d\n",
+ db->numfrag,db->fragsize,db->fragsamples,db->fragshift) );
+ return 0;
+}
+
+
+static int prog_dmabuf_adc(struct cs4281_state *s)
+{
+ unsigned long va;
+ unsigned count;
+ int c;
+ stop_adc(s);
+ if ((c = prog_dmabuf(s, &s->dma_adc)))
+ return c;
+
+ va = virt_to_bus(s->dma_adc.rawbuf);
+
+ count = s->dma_adc.dmasize;
+
+ if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+ count /= 2; // 16-bit.
+
+ if(s->channels > 1)
+ count /= 2; // Assume stereo.
+
+ CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
+ "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n", count,(unsigned)va) );
+
+ writel(va, s->pBA0+BA0_DBA1); // Set buffer start address.
+ writel(count-1, s->pBA0+BA0_DBC1); // Set count.
+ s->dma_adc.ready = 1;
+ return 0;
+}
+
+
+static int prog_dmabuf_dac(struct cs4281_state *s)
+{
+ unsigned long va;
+ unsigned count;
+ int c;
+ stop_dac(s);
+ if ((c = prog_dmabuf(s, &s->dma_dac)))
+ return c;
+ memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE))
+ ? 0x80 : 0, s->dma_dac.dmasize);
+
+ va = virt_to_bus(s->dma_dac.rawbuf);
+
+ count = s->dma_dac.dmasize;
+ if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+ count /= 2; // 16-bit.
+
+ if(s->channels > 1)
+ count /= 2; // Assume stereo.
+
+ writel(va, s->pBA0+BA0_DBA0); // Set buffer start address.
+ writel(count-1, s->pBA0+BA0_DBC0); // Set count.
+
+ CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
+ "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n", count,(unsigned)va) );
+
+ s->dma_dac.ready = 1;
+ return 0;
+}
+
+
+static void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+{
+ if (bptr + len > bsize) {
+ unsigned x = bsize - bptr;
+ memset(((char *)buf) + bptr, c, x);
+ bptr = 0;
+ len -= x;
+ }
+ CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
+ "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n",
+ (unsigned)c,(unsigned)((char *)buf) + bptr, len) );
+ memset(((char *)buf) + bptr, c, len);
+}
+
+
+
+// call with spinlock held!
+static void cs4281_update_ptr(struct cs4281_state *s)
+{
+ int diff;
+ unsigned hwptr, va, temp1;
+
+ // update ADC pointer
+ if (s->ena & FMODE_READ) {
+ hwptr = readl(s->pBA0+BA0_DCA1); // Read capture DMA address.
+ va = virt_to_bus(s->dma_adc.rawbuf);
+ hwptr -= (unsigned)va;
+ diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+ s->dma_adc.hwptr = hwptr;
+ s->dma_adc.total_bytes += diff;
+ s->dma_adc.count += diff;
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ wake_up(&s->dma_adc.wait);
+ } else {
+ if (s->dma_adc.count > 0)
+ wake_up(&s->dma_adc.wait);
+ }
+ CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
+ (unsigned)s,s->dma_adc.hwptr,s->dma_adc.total_bytes,s->dma_adc.count) );
+ }
+ // update DAC pointer
+ //
+ // check for end of buffer, means that we are going to wait for another interrupt
+ // to allow silence to fill the fifos on the part, to keep pops down to a minimum.
+ //
+ if ( (s->ena & FMODE_WRITE) && (!s->endofbuffer) )
+ {
+ hwptr = readl(s->pBA0+BA0_DCA0); // Read play DMA address.
+ va = virt_to_bus(s->dma_dac.rawbuf);
+ hwptr -= (unsigned)va;
+ diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+ s->dma_dac.hwptr = hwptr;
+ s->dma_dac.total_bytes += diff;
+ if (s->dma_dac.mapped) {
+ s->dma_dac.count += diff;
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ wake_up(&s->dma_dac.wait);
+ } else {
+ s->dma_dac.count -= diff;
+ if (s->dma_dac.count <= 0) {
+ s->ena &= ~FMODE_WRITE;
+ temp1 = readl(s->pBA0+BA0_DCR0);
+ //
+ // fill with silence, and wait on turning off the DAC until interrupt routine.
+ // wait on "Poke(pBA0+BA0_DCR0, temp1 | DCRn_MSK); // Stop Play DMA"
+ //
+ CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n",
+ (unsigned)(s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+ (unsigned)s->dma_dac.rawbuf, s->dma_dac.dmasize) );
+ memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+ s->dma_dac.dmasize);
+ s->endofbuffer = 1;
+ } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize
+ && !s->dma_dac.endcleared) {
+ clear_advance(s->dma_dac.rawbuf,
+ s->dma_dac.dmasize, s->dma_dac.swptr,
+ s->dma_dac.fragsize,
+ (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0);
+ s->dma_dac.endcleared = 1;
+ }
+ if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+ wake_up(&s->dma_dac.wait);
+ }
+ CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
+ (unsigned)s,s->dma_dac.hwptr,s->dma_dac.total_bytes,s->dma_dac.count) );
+ }
+}
+
+
+// ---------------------------------------------------------------------
+
+static void prog_codec(struct cs4281_state *s)
+{
+ unsigned long flags;
+ unsigned temp1, format;
+
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_codec()+ \n") );
+
+ spin_lock_irqsave(&s->lock, flags);
+ temp1 = readl(s->pBA0+BA0_DCR0);
+ writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR0); // Stop play DMA, if active.
+ temp1 = readl(s->pBA0+BA0_DCR1);
+ writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR1); // Stop capture DMA, if active.
+
+ // program sampling rates
+ // Note, for CS4281, capture & play rates can be set independently.
+ cs4281_record_rate(s, s->rate);
+
+ // program ADC parameters
+ format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
+ if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+ if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
+ format |= DMRn_BEND;
+ if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE))
+ format |= DMRn_USIGN; // Unsigned.
+ }
+ else
+ format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+ if(s->channels < 2)
+ format |= DMRn_MONO;
+
+ writel(format, s->pBA0+BA0_DMR1);
+
+
+ // program DAC parameters
+ format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
+ if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+ if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE))
+ format |= DMRn_BEND; // Big Endian.
+ if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE))
+ format |= DMRn_USIGN; // Unsigned.
+ }
+ else
+ format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+
+ if(s->channels < 2)
+ format |= DMRn_MONO;
+
+ writel(format, s->pBA0+BA0_DMR0);
+
+ CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: prog_codec(): format=0x%.8x rate=%d\n", format,s->rate) );
+
+ cs4281_play_rate(s, s->rate);
+
+ s->ena = 0; // Neither writing or reading.
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+
+// ---------------------------------------------------------------------
+
+static const char invalid_magic[] = KERN_CRIT "cs4281: invalid magic value\n";
+
+#define VALIDATE_STATE(s) \
+({ \
+ if (!(s) || (s)->magic != CS4281_MAGIC) { \
+ printk(invalid_magic); \
+ return -ENXIO; \
+ } \
+})
+
+// ---------------------------------------------------------------------
+
+
+static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long arg)
+{
+ // Index to mixer_src[] is value of AC97 Input Mux Select Reg.
+ // Value of array member is recording source Device ID Mask.
+ static const unsigned int mixer_src[8] = {
+ SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
+ SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
+ };
+
+ // Index of mixtable1[] member is Device ID
+ // and must be <= SOUND_MIXER_NRDEVICES.
+ // Value of array member is index into s->mix.vol[]
+ static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+ [SOUND_MIXER_PCM] = 1, // voice
+ [SOUND_MIXER_LINE1] = 2, // AUX
+ [SOUND_MIXER_CD] = 3, // CD
+ [SOUND_MIXER_LINE] = 4, // Line
+ [SOUND_MIXER_SYNTH] = 5, // FM
+ [SOUND_MIXER_MIC] = 6, // Mic
+ [SOUND_MIXER_SPEAKER] = 7, // Speaker
+ [SOUND_MIXER_RECLEV] = 8, // Recording level
+ [SOUND_MIXER_VOLUME] = 9 // Master Volume
+ };
+
+
+ static const unsigned mixreg[] = {
+ BA0_AC97_PCM_OUT_VOLUME,
+ BA0_AC97_AUX_VOLUME,
+ BA0_AC97_CD_VOLUME,
+ BA0_AC97_LINE_IN_VOLUME
+ };
+ unsigned char l, r, rl, rr, vidx;
+ unsigned char attentbl[11] = {63,42,26,17,14,11,8,6,4,2,0};
+ unsigned temp1;
+ int i, val;
+
+ VALIDATE_STATE(s);
+
+ if (cmd == SOUND_MIXER_PRIVATE1) {
+ // enable/disable/query mixer preamp
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != -1) {
+ cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+ temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);
+ cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
+ }
+ cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+ val = (temp1 & 0x40) ? 1 : 0;
+ return put_user(val, (int *)arg);
+ }
+ if (cmd == SOUND_MIXER_PRIVATE2) {
+ // enable/disable/query spatializer
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != -1) {
+ temp1 = (val & 0x3f) >> 2;
+ cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
+ cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &temp1);
+ cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,temp1 | 0x2000);
+ }
+ cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
+ return put_user((temp1 << 2) | 3, (int *)arg);
+ }
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, "CS4281", sizeof(info.id));
+ strncpy(info.name, "Crystal CS4281", sizeof(info.name));
+ info.modify_counter = s->mix.modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, "CS4281", sizeof(info.id));
+ strncpy(info.name, "Crystal CS4281", sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
+
+ // If ioctl has only the IOC_READ bit(bit 31)
+ // on, process the only-read commands.
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+ cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
+ return put_user(mixer_src[temp1 & 7], (int *)arg);
+
+ case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME | SOUND_MASK_RECLEV |
+ SOUND_MASK_SPEAKER, (int *)arg);
+
+ case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD
+ | SOUND_MASK_VOLUME | SOUND_MASK_LINE1, (int *)arg);
+
+ case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, (int *)arg);
+
+ case SOUND_MIXER_CAPS:
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+ return -EINVAL;
+ return put_user(s->mix.vol[vidx-1], (int *)arg);
+ }
+ }
+
+ // If ioctl doesn't have both the IOC_READ and
+ // the IOC_WRITE bit set, return invalid.
+ if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ return -EINVAL;
+
+ // Increment the count of volume writes.
+ s->mix.modcnt++;
+
+ // Isolate the command; it must be a write.
+ switch (_IOC_NR(cmd)) {
+
+ case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ i = hweight32(val); // i = # bits on in val.
+ if (i != 1) // One & only 1 bit must be on.
+ return 0;
+ for(i=0; i<sizeof(mixer_src)/sizeof(int); i++) {
+ if(val == mixer_src[i]) {
+ temp1 = (i << 8) | i;
+ cs4281_write_ac97(s, BA0_AC97_RECORD_SELECT, temp1);
+ return 0;
+ }
+ }
+ return 0;
+
+ case SOUND_MIXER_VOLUME:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if(l > 100)
+ l = 100; // Max soundcard.h vol is 100.
+ if(l < 6) {
+ rl = 63;
+ l = 0;
+ }
+ else
+ rl = attentbl[(10*l)/100]; // Convert 0-100 vol to 63-0 atten.
+
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100; // Max right volume is 100, too
+ if(r < 6) {
+ rr = 63;
+ r = 0;
+ }
+ else
+ rr = attentbl[(10*r)/100]; // Convert volume to attenuation.
+
+ if ((rl > 60 ) && (rr > 60)) // If both l & r are 'low',
+ temp1 = 0x8000; // turn on the mute bit.
+ else
+ temp1 = 0;
+
+ temp1 |= (rl << 8) | rr;
+
+ cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
+ cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[8] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[8] = val;
+#endif
+ return put_user(s->mix.vol[8], (int *)arg);
+
+ case SOUND_MIXER_SPEAKER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ if(l < 3 ) {
+ rl = 0;
+ l = 0;
+ }
+ else {
+ rl = (l*2 - 5)/13; // Convert 0-100 range to 0-15.
+ l = (rl*13 +5)/2;
+ }
+
+ if (rl < 3){
+ temp1 = 0x8000;
+ rl = 0;
+ }
+ else
+ temp1 = 0;
+ rl = 15 - rl; // Convert volume to attenuation.
+ temp1 |= rl << 1;
+ cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[6] = l << 8;
+#else
+ s->mix.vol[6] = val;
+#endif
+ return put_user(s->mix.vol[6], (int *)arg);
+
+ case SOUND_MIXER_RECLEV:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100;
+ rl = (l*2 - 5) / 13; // Convert 0-100 scale to 0-15.
+ rr = (r*2 - 5) / 13;
+ if (rl <3 && rr <3)
+ temp1 = 0x8000;
+ else
+ temp1 = 0;
+
+ temp1 = temp1 | (rl << 8) | rr;
+ cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[7] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[7] = val;
+#endif
+ return put_user(s->mix.vol[7], (int *)arg);
+
+ case SOUND_MIXER_MIC:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ if (l < 1) {
+ l = 0;
+ rl = 0;
+ }
+ else {
+ rl = ((unsigned)l*5 - 4)/16; // Convert 0-100 range to 0-31.
+ l = (rl*16 +4)/5;
+ }
+ cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
+ temp1 &= 0x40; // Isolate 20db gain bit.
+ if (rl < 3){
+ temp1 |= 0x8000;
+ rl = 0;
+ }
+ rl = 31 - rl; // Convert volume to attenuation.
+ temp1 |= rl;
+ cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[5] = val << 8;
+#else
+ s->mix.vol[5] = val;
+#endif
+ return put_user(s->mix.vol[5], (int *)arg);
+
+
+ case SOUND_MIXER_SYNTH:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100;
+ rl = (l * 2 - 11)/3; // Convert 0-100 range to 0-63.
+ rr = (r * 2 - 11)/3;
+ if (rl < 3) // If l is low, turn on
+ temp1 = 0x0080; // the mute bit.
+ else
+ temp1 = 0;
+
+ rl = 63 - rl; // Convert vol to attenuation.
+ writel(temp1|rl, s->pBA0+BA0_FMLVC);
+ if (rr < 3) // If rr is low, turn on
+ temp1 = 0x0080; // the mute bit.
+ else
+ temp1 = 0;
+ rr = 63 - rr; // Convert vol to attenuation.
+ writel(temp1 | rr, s->pBA0+BA0_FMRVC);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[4] = (r << 8) | l;
+#else
+ s->mix.vol[4] = val;
+#endif
+ return put_user(s->mix.vol[4], (int *)arg);
+
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+ return -EINVAL;
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ l = val & 0xff;
+ if (l > 100)
+ l = 100;
+ if (l < 1) {
+ l = 0;
+ rl = 31;
+ }
+ else
+ rl = (attentbl[(l*10)/100])>>1;
+
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100;
+ if (r < 1) {
+ r = 0;
+ rr = 31;
+ }
+ else
+ rr = (attentbl[(r*10)/100])>>1;
+ if ((rl > 30) && (rr > 30))
+ temp1 = 0x8000;
+ else
+ temp1 = 0;
+ temp1 = temp1 | (rl << 8) | rr;
+ cs4281_write_ac97(s, mixreg[vidx-1], temp1);
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[vidx-1] = val;
+#endif
+ return put_user(s->mix.vol[vidx-1], (int *)arg);
+ }
+}
+
+
+// ---------------------------------------------------------------------
+
+static loff_t cs4281_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+
+// ---------------------------------------------------------------------
+
+static int cs4281_open_mixdev(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct cs4281_state *s = devs;
+
+ while (s && s->dev_mixer != minor)
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+
+static int cs4281_release_mixdev(struct inode *inode, struct file *file)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+
+ VALIDATE_STATE(s);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return mixer_ioctl((struct cs4281_state *)file->private_data, cmd, arg);
+}
+
+
+// ******************************************************************************************
+// Mixer file operations struct.
+// ******************************************************************************************
+static /*const*/ struct file_operations cs4281_mixer_fops = {
+ llseek: cs4281_llseek,
+ ioctl: cs4281_ioctl_mixdev,
+ open: cs4281_open_mixdev,
+ release: cs4281_release_mixdev,
+};
+
+// ---------------------------------------------------------------------
+
+static int drain_dac(struct cs4281_state *s, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+ unsigned tmo;
+
+ if (s->dma_dac.mapped)
+ return 0;
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->dma_dac.wait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
+ if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ tmo >>= 1;
+ if (s->channels > 1)
+ tmo >>= 1;
+ if (!schedule_timeout(tmo + 1))
+ printk(KERN_DEBUG "cs4281: dma timed out??\n");
+ }
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------
+
+static ssize_t cs4281_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+ printk(KERN_INFO "cs4281: cs4281_read()+ \n") );
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_adc.mapped)
+ return -ENXIO;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ swptr = s->dma_adc.swptr;
+ cnt = s->dma_adc.dmasize-swptr;
+ if (s->dma_adc.count < cnt)
+ cnt = s->dma_adc.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ start_adc(s);
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->dma_adc.wait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_adc.dmasize;
+ spin_lock_irqsave(&s->lock, flags);
+ s->dma_adc.swptr = swptr;
+ s->dma_adc.count -= cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ start_adc(s);
+ }
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+ printk(KERN_INFO "cs4281: cs4281_read()- %d\n",ret) );
+ return ret;
+}
+
+
+static ssize_t cs4281_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+ printk(KERN_INFO "cs4281: cs4281_write()+ \n") );
+ VALIDATE_STATE(s);
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_dac.mapped)
+ return -ENXIO;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ if (s->dma_dac.count < 0) {
+ s->dma_dac.count = 0;
+ s->dma_dac.swptr = s->dma_dac.hwptr;
+ }
+ swptr = s->dma_dac.swptr;
+ cnt = s->dma_dac.dmasize-swptr;
+ if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+ cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ start_dac(s);
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->dma_dac.wait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ spin_lock_irqsave(&s->lock, flags);
+ s->dma_dac.swptr = swptr;
+ s->dma_dac.count += cnt;
+ s->dma_dac.endcleared = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ start_dac(s);
+ }
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+ printk(KERN_INFO "cs4281: cs4281_write()- %d\n",ret) );
+ return ret;
+}
+
+
+static unsigned int cs4281_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO "cs4281: cs4281_poll()+\n") );
+ VALIDATE_STATE(s);
+ if (file->f_mode & FMODE_WRITE)
+ poll_wait(file, &s->dma_dac.wait, wait);
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &s->dma_adc.wait, wait);
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ if (file->f_mode & FMODE_READ) {
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ mask |= POLLIN | POLLRDNORM;
+ } else {
+ if (s->dma_adc.count > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (s->dma_dac.mapped) {
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ } else {
+ if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",mask) );
+ return mask;
+}
+
+
+static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct dmabuf *db;
+ int ret;
+ unsigned long size;
+
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+ printk(KERN_INFO "cs4281: cs4281_mmap()+\n") );
+
+ VALIDATE_STATE(s);
+ if (vma->vm_flags & VM_WRITE) {
+ if ((ret = prog_dmabuf_dac(s)) != 0)
+ return ret;
+ db = &s->dma_dac;
+ } else if (vma->vm_flags & VM_READ) {
+ if ((ret = prog_dmabuf_adc(s)) != 0)
+ return ret;
+ db = &s->dma_adc;
+ } else
+ return -EINVAL;
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+ size = vma->vm_end - vma->vm_start;
+ if (size > (PAGE_SIZE << db->buforder))
+ return -EINVAL;
+ if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+ return -EAGAIN;
+ db->mapped = 1;
+
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+ printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
+ (unsigned)size) );
+
+ return 0;
+}
+
+
+static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ count_info cinfo;
+ int val, mapped, ret;
+
+ CS_DBGOUT(CS_FUNCTION, 4,
+ printk(KERN_INFO "cs4281: cs4281_ioctl(): file=0x%.8x cmd=0x%.8x\n",
+ (unsigned)file,cmd) );
+ VALIDATE_STATE(s);
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n", SOUND_VERSION) );
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ synchronize_irq();
+ s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count =
+ s->dma_dac.total_bytes = s->dma_dac.blocks = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ synchronize_irq();
+ s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count =
+ s->dma_adc.total_bytes = s->dma_adc.blocks = 0;
+ }
+ prog_codec(s);
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ // program sampling rates
+ if (val > 48000)
+ val = 48000;
+ if (val < 6300)
+ val = 6300;
+ s->rate = val;
+ prog_codec(s);
+ }
+ return put_user(s->rate, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ // program channels
+ s->channels = val ? 2 : 1;
+ prog_codec(s);
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != 0) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ // program channels
+ s->channels = val ? 2 : 1;
+ prog_codec(s);
+ }
+ return put_user(s->channels, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: // Returns a mask
+ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: // Selects ONE fmt
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY) {
+ stop_adc(s);
+ stop_dac(s);
+ s->dma_adc.ready = s->dma_dac.ready = 0;
+ // program format
+ if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
+ val != AFMT_S8 && val != AFMT_U8)
+ val = AFMT_U8;
+ s->fmt = val;
+ prog_codec(s);
+ }
+ return put_user(s->fmt, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & s->ena & FMODE_READ)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & s->ena & FMODE_WRITE)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
+ start_adc(s);
+ } else
+ stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
+ start_dac(s);
+ } else
+ stop_dac(s);
+ }
+ return 0;
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ abinfo.fragsize = s->dma_dac.fragsize;
+ abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ abinfo.fragstotal = s->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ val = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ cinfo.bytes = s->dma_adc.total_bytes;
+ cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ cinfo.ptr = s->dma_adc.hwptr;
+ if (s->dma_adc.mapped)
+ s->dma_adc.count &= s->dma_adc.fragsize-1;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_update_ptr(s);
+ cinfo.bytes = s->dma_dac.total_bytes;
+ if (s->dma_dac.mapped)
+ {
+ cinfo.blocks = (cinfo.bytes >> s->dma_dac.fragshift)
+ - s->dma_adc.blocks;
+ s->dma_dac.blocks = cinfo.bytes >> s->dma_dac.fragshift;
+ }
+ else
+ {
+ cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ }
+ cinfo.ptr = s->dma_dac.hwptr;
+ if (s->dma_dac.mapped)
+ s->dma_dac.count &= s->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = prog_dmabuf_dac(s)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf_adc(s)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0; // Say OK, but do nothing.
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ return -EINVAL;
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != 1 && val != 2 && val != 4)
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ s->dma_adc.subdivision = val;
+ if (file->f_mode & FMODE_WRITE)
+ s->dma_dac.subdivision = val;
+ return 0;
+
+ case SOUND_PCM_READ_RATE:
+ return put_user(s->rate, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(s->channels, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+
+ }
+ return mixer_ioctl(s, cmd, arg);
+}
+
+
+static int cs4281_release(struct inode *inode, struct file *file)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
+ printk(KERN_INFO "cs4281: cs4281_release(): inode=0x%.8x file=0x%.8x\n",
+ (unsigned)inode,(unsigned)file) );
+
+ VALIDATE_STATE(s);
+
+ if (file->f_mode & FMODE_WRITE)
+ drain_dac(s, file->f_flags & O_NONBLOCK);
+ down(&s->open_sem);
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ dealloc_dmabuf(s,&s->dma_dac);
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ dealloc_dmabuf(s,&s->dma_adc);
+ }
+ s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int cs4281_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct cs4281_state *s = devs;
+
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
+ printk(KERN_INFO "cs4281: cs4281_open(): inode=0x%.8x file=0x%.8x\n",
+ (unsigned)inode,(unsigned)file) );
+ while (s && ((s->dev_audio ^ minor) & ~0xf))
+ s = s->next;
+ if (!s)
+ {
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+ "cs4281: cs4281_open(): ERROR unable to find audio state struct\n") );
+ return -ENODEV;
+ }
+ VALIDATE_STATE(s);
+ file->private_data = s;
+
+ // wait for device to become free
+ down(&s->open_sem);
+ while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ s->fmt = AFMT_U8;
+ s->channels = 1;
+ s->rate = 8000;
+ s->clkdiv = 96 | 0x80;
+ s->ena = s->endofbuffer = 0;
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ up(&s->open_sem);
+ MOD_INC_USE_COUNT;
+
+ if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
+
+ printk(KERN_ERR "cs4281: Program dmabufs failed.\n");
+ cs4281_release(inode, file);
+
+ return -ENOMEM;
+ }
+ prog_codec(s);
+ CS_DBGOUT(CS_INIT | CS_FUNCTION | CS_OPEN, 2,
+ printk(KERN_INFO "cs4281: cs4281_open()- 0\n") );
+ return 0;
+}
+
+
+// ******************************************************************************************
+// Wave (audio) file operations struct.
+// ******************************************************************************************
+static /*const*/ struct file_operations cs4281_audio_fops = {
+ llseek: cs4281_llseek,
+ read: cs4281_read,
+ write: cs4281_write,
+ poll: cs4281_poll,
+ ioctl: cs4281_ioctl,
+ mmap: cs4281_mmap,
+ open: cs4281_open,
+ release: cs4281_release,
+};
+
+// ---------------------------------------------------------------------
+
+// hold spinlock for the following!
+static void cs4281_handle_midi(struct cs4281_state *s)
+{
+ unsigned char ch;
+ int wake;
+ unsigned temp1;
+
+ wake = 0;
+ while (!(readl(s->pBA0+ BA0_MIDSR) & 0x80)) {
+ ch = readl(s->pBA0+BA0_MIDRP);
+ if (s->midi.icnt < MIDIINBUF) {
+ s->midi.ibuf[s->midi.iwr] = ch;
+ s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+ s->midi.icnt++;
+ }
+ wake = 1;
+ }
+ if (wake)
+ wake_up(&s->midi.iwait);
+ wake = 0;
+ while (!(readl(s->pBA0+ BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
+ temp1 = ( s->midi.obuf[s->midi.ord] ) & 0x000000ff;
+ writel(temp1, s->pBA0+BA0_MIDWP);
+ s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+ s->midi.ocnt--;
+ if (s->midi.ocnt < MIDIOUTBUF-16)
+ wake = 1;
+ }
+ if (wake)
+ wake_up(&s->midi.owait);
+}
+
+
+
+static void cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct cs4281_state *s = (struct cs4281_state *)dev_id;
+ unsigned int temp1;
+
+ // fastpath out, to ease interrupt sharing
+ temp1 = readl(s->pBA0+BA0_HISR); // Get Int Status reg.
+
+ CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
+ "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n",temp1) );
+
+ if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) { // If not DMA or MIDI int,
+ writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // reenable interrupts
+ CS_DBGOUT(CS_INTERRUPT, 4, printk(KERN_INFO
+ "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n") );
+ return; // and return.
+ }
+
+ if(temp1 & HISR_DMA0) // If play interrupt,
+ readl(s->pBA0+BA0_HDSR0); // clear the source.
+
+ if(temp1 & HISR_DMA1) // Same for play.
+ readl(s->pBA0+BA0_HDSR1);
+ writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // Local EOI
+
+ spin_lock(&s->lock);
+ //
+ // ok, at this point we assume that the fifos have been filled
+ // with silence and so we now turn off the DMA engine.
+ // if FMODE_WRITE is set that means that some thread
+ // attempted to start_dac, which probably means that an open
+ // occurred, so do not stop the dac in this case.
+ //
+ if(s->endofbuffer && !(s->ena & FMODE_WRITE))
+ {
+ CS_DBGOUT(CS_INTERRUPT, 2, printk(KERN_INFO
+ "cs4281: cs4281_interrupt() stopping play DMA\n") );
+ writel(temp1|DCRn_MSK, s->pBA0+BA0_DCR0); // Stop Play DMA
+ s->endofbuffer = 0;
+ }
+ else
+ {
+ cs4281_update_ptr(s);
+ }
+ cs4281_handle_midi(s);
+ spin_unlock(&s->lock);
+}
+
+// **************************************************************************
+
+static void cs4281_midi_timer(unsigned long data)
+{
+ struct cs4281_state *s = (struct cs4281_state *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ s->midi.timer.expires = jiffies+1;
+ add_timer(&s->midi.timer);
+}
+
+
+// ---------------------------------------------------------------------
+
+static ssize_t cs4281_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned ptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ ptr = s->midi.ird;
+ cnt = MIDIINBUF - ptr;
+ if (s->midi.icnt < cnt)
+ cnt = s->midi.icnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->midi.iwait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+ return ret ? ret : -EFAULT;
+ ptr = (ptr + cnt) % MIDIINBUF;
+ spin_lock_irqsave(&s->lock, flags);
+ s->midi.ird = ptr;
+ s->midi.icnt -= cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ }
+ return ret;
+}
+
+
+static ssize_t cs4281_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned ptr;
+ int cnt;
+
+ VALIDATE_STATE(s);
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ ptr = s->midi.owr;
+ cnt = MIDIOUTBUF - ptr;
+ if (s->midi.ocnt + cnt > MIDIOUTBUF)
+ cnt = MIDIOUTBUF - s->midi.ocnt;
+ if (cnt <= 0)
+ cs4281_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ interruptible_sleep_on(&s->midi.owait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+ return ret ? ret : -EFAULT;
+ ptr = (ptr + cnt) % MIDIOUTBUF;
+ spin_lock_irqsave(&s->lock, flags);
+ s->midi.owr = ptr;
+ s->midi.ocnt += cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ spin_lock_irqsave(&s->lock, flags);
+ cs4281_handle_midi(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ return ret;
+}
+
+
+static unsigned int cs4281_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ VALIDATE_STATE(s);
+ if (file->f_flags & FMODE_WRITE)
+ poll_wait(file, &s->midi.owait, wait);
+ if (file->f_flags & FMODE_READ)
+ poll_wait(file, &s->midi.iwait, wait);
+ spin_lock_irqsave(&s->lock, flags);
+ if (file->f_flags & FMODE_READ) {
+ if (s->midi.icnt > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ if (file->f_flags & FMODE_WRITE) {
+ if (s->midi.ocnt < MIDIOUTBUF)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return mask;
+}
+
+
+static int cs4281_midi_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct cs4281_state *s = devs;
+ unsigned long flags,temp1;
+ while (s && s->dev_midi != minor)
+ s = s->next;
+ if (!s)
+ return -ENODEV;
+ VALIDATE_STATE(s);
+ file->private_data = s;
+ // wait for device to become free
+ down(&s->open_sem);
+ while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+ writel(1, s->pBA0+BA0_MIDCR); // Reset the interface.
+ writel(0, s->pBA0+BA0_MIDCR); // Return to normal mode.
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ writel(0x0000000f, s->pBA0+BA0_MIDCR); // Enable transmit, record, ints.
+ temp1 = readl(s->pBA0+BA0_HIMR);
+ writel(temp1 & 0xffbfffff, s->pBA0+BA0_HIMR); // Enable midi int. recognition.
+ writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts
+ init_timer(&s->midi.timer);
+ s->midi.timer.expires = jiffies+1;
+ s->midi.timer.data = (unsigned long)s;
+ s->midi.timer.function = cs4281_midi_timer;
+ add_timer(&s->midi.timer);
+ }
+ if (file->f_mode & FMODE_READ) {
+ s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+ up(&s->open_sem);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+
+static int cs4281_midi_release(struct inode *inode, struct file *file)
+{
+ struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ unsigned count, tmo;
+
+ VALIDATE_STATE(s);
+
+ if (file->f_mode & FMODE_WRITE) {
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->midi.owait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->midi.ocnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ remove_wait_queue(&s->midi.owait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (count * HZ) / 3100;
+ if (!schedule_timeout(tmo ? : 1) && tmo)
+ printk(KERN_DEBUG "cs4281: midi timed out??\n");
+ }
+ remove_wait_queue(&s->midi.owait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ down(&s->open_sem);
+ s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+ writel(0, s->pBA0+BA0_MIDCR); // Disable Midi interrupts.
+ del_timer(&s->midi.timer);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+// ******************************************************************************************
+// Midi file operations struct.
+// ******************************************************************************************
+static /*const*/ struct file_operations cs4281_midi_fops = {
+ llseek: cs4281_llseek,
+ read: cs4281_midi_read,
+ write: cs4281_midi_write,
+ poll: cs4281_midi_poll,
+ open: cs4281_midi_open,
+ release: cs4281_midi_release,
+};
+
+
+// ---------------------------------------------------------------------
+
+// maximum number of devices
+#define NR_DEVICE 8 // Only eight devices supported currently.
+
+// ---------------------------------------------------------------------
+
+static struct initvol {
+ int mixch;
+ int vol;
+} initvol[] __initdata = {
+ { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+ { SOUND_MIXER_WRITE_PCM, 0x4040 },
+ { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+ { SOUND_MIXER_WRITE_CD, 0x4040 },
+ { SOUND_MIXER_WRITE_LINE, 0x4040 },
+ { SOUND_MIXER_WRITE_LINE1, 0x4040 },
+ { SOUND_MIXER_WRITE_RECLEV, 0x0000 },
+ { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
+ { SOUND_MIXER_WRITE_MIC, 0x0000 }
+};
+
+
+static int __devinit cs4281_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+{
+ struct cs4281_state *s;
+ dma_addr_t dma_mask;
+ mm_segment_t fs;
+ int i, val, index = 0;
+ unsigned int temp1, temp2;
+
+ CS_DBGOUT(CS_INIT, 2, printk(KERN_INFO "cs4281: probe()+\n") );
+
+ if (!RSRCISMEMORYREGION(pcidev, 0) ||
+ !RSRCISMEMORYREGION(pcidev, 1))
+ {
+ CS_DBGOUT(CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: probe()- Memory region not assigned\n") );
+ return -1;
+ }
+ if (pcidev->irq == 0) {
+ CS_DBGOUT(CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: probe() IRQ not assigned\n") );
+ return -1;
+ }
+ if (!pci_dma_supported(pcidev, 0xffffffff)) {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n") );
+ return -1;
+ }
+ dma_mask = 0xffffffff; /* this enables playback and recording */
+ if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: probe() no memory for state struct.\n") );
+ return -1;
+ }
+ memset(s, 0, sizeof(struct cs4281_state));
+ init_waitqueue_head(&s->dma_adc.wait);
+ init_waitqueue_head(&s->dma_dac.wait);
+ init_waitqueue_head(&s->open_wait);
+ init_waitqueue_head(&s->midi.iwait);
+ init_waitqueue_head(&s->midi.owait);
+ init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
+ s->pBA0phys = RSRCADDRESS(pcidev, 0);
+ s->pBA1phys = RSRCADDRESS(pcidev, 1);
+ s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); // Convert phys
+ s->pBA1 = ioremap_nocache(s->pBA1phys, 65536); // to linear.
+ temp1 = readl(s->pBA0+ BA0_PCICFG00);
+ temp2 = readl(s->pBA0+ BA0_PCICFG04);
+
+ CS_DBGOUT(CS_INIT, 2,
+ printk(KERN_INFO "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=0x%.8x pBA1=0x%.8x \n",
+ (unsigned)temp1,(unsigned)temp2,(unsigned)s->pBA0,(unsigned)s->pBA1) );
+
+ CS_DBGOUT(CS_INIT, 2,
+ printk(KERN_INFO "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
+ (unsigned)s->pBA0phys,(unsigned)s->pBA1phys) );
+
+ temp1 = cs4281_hw_init(s);
+ if(temp1){
+ CS_DBGOUT(CS_ERROR | CS_INIT, 1,
+ printk(KERN_ERR "cs4281: cs4281_hw_init() failed. Skipping part.\n") );
+ return -1;
+ }
+ s->magic = CS4281_MAGIC;
+ s->pcidev = pcidev;
+ s->irq = pcidev->irq;
+ if (pci_enable_device(pcidev))
+ {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: pci_enable_device() failed\n") );
+ goto err_irq;
+ }
+ if(request_irq(s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)){
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: irq %u in use\n", s->irq) );
+ goto err_irq;
+ }
+ if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) < 0)
+ {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: probe() register_sound_dsp() failed.\n") );
+ goto err_dev1;
+ }
+ if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) < 0)
+ {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: probe() register_sound_mixer() failed.\n") );
+ goto err_dev2;
+ }
+ if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0)
+ {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: probe() register_sound_midi() failed.\n") );
+ goto err_dev3;
+ }
+
+ pci_set_master(pcidev); // enable bus mastering
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ val = SOUND_MASK_LINE;
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ val = initvol[i].vol;
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ val = 1; // enable mic preamp
+ mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
+ set_fs(fs);
+
+ // queue it for later freeing
+ s->next = devs;
+ pcidev->driver_data = s;
+ pcidev->dma_mask = dma_mask;
+ devs = s;
+ index++;
+ return 0;
+
+err_dev3:
+ unregister_sound_mixer(s->dev_mixer);
+err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+err_dev1:
+ free_irq(s->irq, s);
+err_irq:
+ kfree(s);
+
+ if (!devs)
+ {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_INFO "cs4281: probe()- no device allocated\n") );
+ return -ENODEV;
+ }
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: probe()- device allocated successfully\n") );
+ return 0;
+} // probe_cs4281
+
+
+// ---------------------------------------------------------------------
+
+static void __devinit cs4281_remove(struct pci_dev *dev)
+{
+ struct cs4281_state *s = (struct cs4281_state *)dev->driver_data;
+ // stop DMA controller
+ synchronize_irq();
+ free_irq(s->irq, s);
+ unregister_sound_dsp(s->dev_audio);
+ unregister_sound_mixer(s->dev_mixer);
+ unregister_sound_midi(s->dev_midi);
+ kfree(s);
+ dev->driver_data = NULL;
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cs4281_remove(): remove successful\n") );
+}
+
+static struct pci_device_id id_table[] __devinitdata = {
+ { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CRYSTAL_CS4281, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static struct pci_driver cs4281_driver = {
+ name: "cs4281",
+ id_table: id_table,
+ probe: cs4281_probe,
+ remove: cs4281_remove
+};
+
+static int __init init_cs4281(void)
+{
+
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()+ \n") );
+ if (!pci_present()) /* No PCI bus in this machine! */
+ {
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: init_cs4281()- no pci bus found\n") );
+ return -ENODEV;
+ }
+ printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " " __DATE__ "\n",
+ CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION, CS4281_ARCH);
+ if (!pci_register_driver(&cs4281_driver)) {
+ pci_unregister_driver(&cs4281_driver);
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: init_cs4281()- unable to register pci device \n") );
+ return -ENODEV;
+ }
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()- 0\n") );
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------
+
+
+MODULE_AUTHOR("gw boynton, wesb@crystal.cirrus.com");
+MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
+
+static void __exit cleanup_cs4281(void)
+{
+ pci_unregister_driver(&cs4281_driver);
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n") );
+}
+
+// ---------------------------------------------------------------------
+
+module_init(init_cs4281);
+module_exit(cleanup_cs4281);
+
--- /dev/null
+//****************************************************************************
+//
+// HWDEFS.H - Definitions of the registers and data structures used by the
+// CS4281
+//
+// Copyright (c) 1999 Crystal Semiconductor Corp.
+//
+//****************************************************************************
+
+#ifndef _H_HWDEFS
+#define _H_HWDEFS
+
+//****************************************************************************
+//
+// The following define the offsets of the registers located in the PCI
+// configuration space of the CS4281 part.
+//
+//****************************************************************************
+#define PCICONFIG_DEVID_VENID 0x00000000L
+#define PCICONFIG_STATUS_COMMAND 0x00000004L
+#define PCICONFIG_CLASS_REVISION 0x00000008L
+#define PCICONFIG_LATENCY_TIMER 0x0000000CL
+#define PCICONFIG_BA0 0x00000010L
+#define PCICONFIG_BA1 0x00000014L
+#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL
+#define PCICONFIG_INTERRUPT 0x0000003CL
+
+//****************************************************************************
+//
+// The following define the offsets of the registers accessed via base address
+// register zero on the CS4281 part.
+//
+//****************************************************************************
+#define BA0_HISR 0x00000000L
+#define BA0_HICR 0x00000008L
+#define BA0_HIMR 0x0000000CL
+#define BA0_IIER 0x00000010L
+#define BA0_HDSR0 0x000000F0L
+#define BA0_HDSR1 0x000000F4L
+#define BA0_HDSR2 0x000000F8L
+#define BA0_HDSR3 0x000000FCL
+#define BA0_DCA0 0x00000110L
+#define BA0_DCC0 0x00000114L
+#define BA0_DBA0 0x00000118L
+#define BA0_DBC0 0x0000011CL
+#define BA0_DCA1 0x00000120L
+#define BA0_DCC1 0x00000124L
+#define BA0_DBA1 0x00000128L
+#define BA0_DBC1 0x0000012CL
+#define BA0_DCA2 0x00000130L
+#define BA0_DCC2 0x00000134L
+#define BA0_DBA2 0x00000138L
+#define BA0_DBC2 0x0000013CL
+#define BA0_DCA3 0x00000140L
+#define BA0_DCC3 0x00000144L
+#define BA0_DBA3 0x00000148L
+#define BA0_DBC3 0x0000014CL
+#define BA0_DMR0 0x00000150L
+#define BA0_DCR0 0x00000154L
+#define BA0_DMR1 0x00000158L
+#define BA0_DCR1 0x0000015CL
+#define BA0_DMR2 0x00000160L
+#define BA0_DCR2 0x00000164L
+#define BA0_DMR3 0x00000168L
+#define BA0_DCR3 0x0000016CL
+#define BA0_DLMR 0x00000170L
+#define BA0_DLSR 0x00000174L
+#define BA0_FCR0 0x00000180L
+#define BA0_FCR1 0x00000184L
+#define BA0_FCR2 0x00000188L
+#define BA0_FCR3 0x0000018CL
+#define BA0_FPDR0 0x00000190L
+#define BA0_FPDR1 0x00000194L
+#define BA0_FPDR2 0x00000198L
+#define BA0_FPDR3 0x0000019CL
+#define BA0_FCHS 0x0000020CL
+#define BA0_FSIC0 0x00000210L
+#define BA0_FSIC1 0x00000214L
+#define BA0_FSIC2 0x00000218L
+#define BA0_FSIC3 0x0000021CL
+#define BA0_PCICFG00 0x00000300L
+#define BA0_PCICFG04 0x00000304L
+#define BA0_PCICFG08 0x00000308L
+#define BA0_PCICFG0C 0x0000030CL
+#define BA0_PCICFG10 0x00000310L
+#define BA0_PCICFG14 0x00000314L
+#define BA0_PCICFG18 0x00000318L
+#define BA0_PCICFG1C 0x0000031CL
+#define BA0_PCICFG20 0x00000320L
+#define BA0_PCICFG24 0x00000324L
+#define BA0_PCICFG28 0x00000328L
+#define BA0_PCICFG2C 0x0000032CL
+#define BA0_PCICFG30 0x00000330L
+#define BA0_PCICFG34 0x00000334L
+#define BA0_PCICFG38 0x00000338L
+#define BA0_PCICFG3C 0x0000033CL
+#define BA0_PCICFG40 0x00000340L
+#define BA0_PMCS 0x00000344L
+#define BA0_CWPR 0x000003E0L
+#define BA0_EPPMC 0x000003E4L
+#define BA0_GPIOR 0x000003E8L
+#define BA0_SPMC 0x000003ECL
+#define BA0_CFLR 0x000003F0L
+#define BA0_IISR 0x000003F4L
+#define BA0_TMS 0x000003F8L
+#define BA0_SSVID 0x000003FCL
+#define BA0_CLKCR1 0x00000400L
+#define BA0_FRR 0x00000410L
+#define BA0_SLT12O 0x0000041CL
+#define BA0_SERMC 0x00000420L
+#define BA0_SERC1 0x00000428L
+#define BA0_SERC2 0x0000042CL
+#define BA0_SLT12M 0x0000045CL
+#define BA0_ACCTL 0x00000460L
+#define BA0_ACSTS 0x00000464L
+#define BA0_ACOSV 0x00000468L
+#define BA0_ACCAD 0x0000046CL
+#define BA0_ACCDA 0x00000470L
+#define BA0_ACISV 0x00000474L
+#define BA0_ACSAD 0x00000478L
+#define BA0_ACSDA 0x0000047CL
+#define BA0_JSPT 0x00000480L
+#define BA0_JSCTL 0x00000484L
+#define BA0_MIDCR 0x00000490L
+#define BA0_MIDCMD 0x00000494L
+#define BA0_MIDSR 0x00000494L
+#define BA0_MIDWP 0x00000498L
+#define BA0_MIDRP 0x0000049CL
+#define BA0_AODSD1 0x000004A8L
+#define BA0_AODSD2 0x000004ACL
+#define BA0_CFGI 0x000004B0L
+#define BA0_SLT12M2 0x000004DCL
+#define BA0_ACSTS2 0x000004E4L
+#define BA0_ACISV2 0x000004F4L
+#define BA0_ACSAD2 0x000004F8L
+#define BA0_ACSDA2 0x000004FCL
+#define BA0_IOTGP 0x00000500L
+#define BA0_IOTSB 0x00000504L
+#define BA0_IOTFM 0x00000508L
+#define BA0_IOTDMA 0x0000050CL
+#define BA0_IOTAC0 0x00000500L
+#define BA0_IOTAC1 0x00000504L
+#define BA0_IOTAC2 0x00000508L
+#define BA0_IOTAC3 0x0000050CL
+#define BA0_IOTPCP 0x0000052CL
+#define BA0_IOTCC 0x00000530L
+#define BA0_IOTCR 0x0000058CL
+#define BA0_PCPRR 0x00000600L
+#define BA0_PCPGR 0x00000604L
+#define BA0_PCPCR 0x00000608L
+#define BA0_PCPCIEN 0x00000608L
+#define BA0_SBMAR 0x00000700L
+#define BA0_SBMDR 0x00000704L
+#define BA0_SBRR 0x00000708L
+#define BA0_SBRDP 0x0000070CL
+#define BA0_SBWDP 0x00000710L
+#define BA0_SBWBS 0x00000710L
+#define BA0_SBRBS 0x00000714L
+#define BA0_FMSR 0x00000730L
+#define BA0_B0AP 0x00000730L
+#define BA0_FMDP 0x00000734L
+#define BA0_B1AP 0x00000738L
+#define BA0_B1DP 0x0000073CL
+#define BA0_SSPM 0x00000740L
+#define BA0_DACSR 0x00000744L
+#define BA0_ADCSR 0x00000748L
+#define BA0_SSCR 0x0000074CL
+#define BA0_FMLVC 0x00000754L
+#define BA0_FMRVC 0x00000758L
+#define BA0_SRCSA 0x0000075CL
+#define BA0_PPLVC 0x00000760L
+#define BA0_PPRVC 0x00000764L
+#define BA0_PASR 0x00000768L
+#define BA0_CASR 0x0000076CL
+
+//****************************************************************************
+//
+// 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 define the offsets of the registers and memories accessed via
+// base address register one on the CS4281 part.
+//
+//****************************************************************************
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI device ID/vendor ID
+// register.
+//
+//****************************************************************************
+#define PDV_VENID_MASK 0x0000FFFFL
+#define PDV_DEVID_MASK 0xFFFF0000L
+#define PDV_VENID_SHIFT 0L
+#define PDV_DEVID_SHIFT 16L
+#define VENID_CIRRUS_LOGIC 0x1013L
+#define DEVID_CS4281 0x6005L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI status and command
+// register.
+//
+//****************************************************************************
+#define PSC_IO_SPACE_ENABLE 0x00000001L
+#define PSC_MEMORY_SPACE_ENABLE 0x00000002L
+#define PSC_BUS_MASTER_ENABLE 0x00000004L
+#define PSC_SPECIAL_CYCLES 0x00000008L
+#define PSC_MWI_ENABLE 0x00000010L
+#define PSC_VGA_PALETTE_SNOOP 0x00000020L
+#define PSC_PARITY_RESPONSE 0x00000040L
+#define PSC_WAIT_CONTROL 0x00000080L
+#define PSC_SERR_ENABLE 0x00000100L
+#define PSC_FAST_B2B_ENABLE 0x00000200L
+#define PSC_UDF_MASK 0x007F0000L
+#define PSC_FAST_B2B_CAPABLE 0x00800000L
+#define PSC_PARITY_ERROR_DETECTED 0x01000000L
+#define PSC_DEVSEL_TIMING_MASK 0x06000000L
+#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L
+#define PSC_RECEIVED_TARGET_ABORT 0x10000000L
+#define PSC_RECEIVED_MASTER_ABORT 0x20000000L
+#define PSC_SIGNALLED_SERR 0x40000000L
+#define PSC_DETECTED_PARITY_ERROR 0x80000000L
+#define PSC_UDF_SHIFT 16L
+#define PSC_DEVSEL_TIMING_SHIFT 25L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI class/revision ID
+// register.
+//
+//****************************************************************************
+#define PCR_REVID_MASK 0x000000FFL
+#define PCR_INTERFACE_MASK 0x0000FF00L
+#define PCR_SUBCLASS_MASK 0x00FF0000L
+#define PCR_CLASS_MASK 0xFF000000L
+#define PCR_REVID_SHIFT 0L
+#define PCR_INTERFACE_SHIFT 8L
+#define PCR_SUBCLASS_SHIFT 16L
+#define PCR_CLASS_SHIFT 24L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI latency timer register.
+//
+//****************************************************************************
+#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL
+#define PLT_LATENCY_TIMER_MASK 0x0000FF00L
+#define PLT_HEADER_TYPE_MASK 0x00FF0000L
+#define PLT_BIST_MASK 0xFF000000L
+#define PLT_CACHE_LINE_SIZE_SHIFT 0L
+#define PLT_LATENCY_TIMER_SHIFT 8L
+#define PLT_HEADER_TYPE_SHIFT 16L
+#define PLT_BIST_SHIFT 24L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI base address registers.
+//
+//****************************************************************************
+#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L
+#define PBAR_LOCATION_TYPE_MASK 0x00000006L
+#define PBAR_NOT_PREFETCHABLE 0x00000008L
+#define PBAR_ADDRESS_MASK 0xFFFFFFF0L
+#define PBAR_LOCATION_TYPE_SHIFT 1L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI subsystem ID/subsystem
+// vendor ID register.
+//
+//****************************************************************************
+#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL
+#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L
+#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L
+#define PSS_SUBSYSTEM_ID_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PCI interrupt register.
+//
+//****************************************************************************
+#define PI_LINE_MASK 0x000000FFL
+#define PI_PIN_MASK 0x0000FF00L
+#define PI_MIN_GRANT_MASK 0x00FF0000L
+#define PI_MAX_LATENCY_MASK 0xFF000000L
+#define PI_LINE_SHIFT 0L
+#define PI_PIN_SHIFT 8L
+#define PI_MIN_GRANT_SHIFT 16L
+#define PI_MAX_LATENCY_SHIFT 24L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the host interrupt status
+// register.
+//
+//****************************************************************************
+#define HISR_HVOLMASK 0x00000003L
+#define HISR_VDNI 0x00000001L
+#define HISR_VUPI 0x00000002L
+#define HISR_GP1I 0x00000004L
+#define HISR_GP3I 0x00000008L
+#define HISR_GPSI 0x00000010L
+#define HISR_GPPI 0x00000020L
+#define HISR_DMAI 0x00040000L
+#define HISR_FIFOI 0x00100000L
+#define HISR_HVOL 0x00200000L
+#define HISR_MIDI 0x00400000L
+#define HISR_SBINT 0x00800000L
+#define HISR_INTENA 0x80000000L
+#define HISR_DMA_MASK 0x00000F00L
+#define HISR_FIFO_MASK 0x0000F000L
+#define HISR_DMA_SHIFT 8L
+#define HISR_FIFO_SHIFT 12L
+#define HISR_FIFO0 0x00001000L
+#define HISR_FIFO1 0x00002000L
+#define HISR_FIFO2 0x00004000L
+#define HISR_FIFO3 0x00008000L
+#define HISR_DMA0 0x00000100L
+#define HISR_DMA1 0x00000200L
+#define HISR_DMA2 0x00000400L
+#define HISR_DMA3 0x00000800L
+#define HISR_RESERVED 0x40000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the host interrupt control
+// register.
+//
+//****************************************************************************
+#define HICR_IEV 0x00000001L
+#define HICR_CHGM 0x00000002L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the DMA Mode Register n
+// (DMRn)
+//
+//****************************************************************************
+#define DMRn_TR_MASK 0x0000000CL
+#define DMRn_TR_SHIFT 2L
+#define DMRn_AUTO 0x00000010L
+#define DMRn_TR_READ 0x00000008L
+#define DMRn_TR_WRITE 0x00000004L
+#define DMRn_TYPE_MASK 0x000000C0L
+#define DMRn_TYPE_SHIFT 6L
+#define DMRn_SIZE8 0x00010000L
+#define DMRn_MONO 0x00020000L
+#define DMRn_BEND 0x00040000L
+#define DMRn_USIGN 0x00080000L
+#define DMRn_SIZE20 0x00100000L
+#define DMRn_SWAPC 0x00400000L
+#define DMRn_CBC 0x01000000L
+#define DMRn_TBC 0x02000000L
+#define DMRn_POLL 0x10000000L
+#define DMRn_DMA 0x20000000L
+#define DMRn_FSEL_MASK 0xC0000000L
+#define DMRn_FSEL_SHIFT 30L
+#define DMRn_FSEL0 0x00000000L
+#define DMRn_FSEL1 0x40000000L
+#define DMRn_FSEL2 0x80000000L
+#define DMRn_FSEL3 0xC0000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the DMA Command Register n
+// (DCRn)
+//
+//****************************************************************************
+#define DCRn_HTCIE 0x00020000L
+#define DCRn_TCIE 0x00010000L
+#define DCRn_MSK 0x00000001L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the FIFO Control
+// register n.(FCRn)
+//
+//****************************************************************************
+#define FCRn_OF_MASK 0x0000007FL
+#define FCRn_OF_SHIFT 0L
+#define FCRn_SZ_MASK 0x00007F00L
+#define FCRn_SZ_SHIFT 8L
+#define FCRn_LS_MASK 0x001F0000L
+#define FCRn_LS_SHIFT 16L
+#define FCRn_RS_MASK 0x1F000000L
+#define FCRn_RS_SHIFT 24L
+#define FCRn_FEN 0x80000000L
+#define FCRn_PSH 0x20000000L
+#define FCRn_DACZ 0x40000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the serial port Power Management
+// control register.(SPMC)
+//
+//****************************************************************************
+#define SPMC_RSTN 0x00000001L
+#define SPMC_ASYN 0x00000002L
+#define SPMC_WUP1 0x00000004L
+#define SPMC_WUP2 0x00000008L
+#define SPMC_ASDI2E 0x00000100L
+#define SPMC_ESSPD 0x00000200L
+#define SPMC_GISPEN 0x00004000L
+#define SPMC_GIPPEN 0x00008000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the Configuration Load register.
+// (CFLR)
+//
+//****************************************************************************
+#define CFLR_CLOCK_SOURCE_MASK 0x00000003L
+#define CFLR_CLOCK_SOURCE_AC97 0x00000001L
+
+#define CFLR_CB0_MASK 0x000000FFL
+#define CFLR_CB1_MASK 0x0000FF00L
+#define CFLR_CB2_MASK 0x00FF0000L
+#define CFLR_CB3_MASK 0xFF000000L
+#define CFLR_CB0_SHIFT 0L
+#define CFLR_CB1_SHIFT 8L
+#define CFLR_CB2_SHIFT 16L
+#define CFLR_CB3_SHIFT 24L
+
+#define IOTCR_DMA0 0x00000000L
+#define IOTCR_DMA1 0x00000400L
+#define IOTCR_DMA2 0x00000800L
+#define IOTCR_DMA3 0x00000C00L
+#define IOTCR_CCLS 0x00000100L
+#define IOTCR_PCPCI 0x00000200L
+#define IOTCR_DDMA 0x00000300L
+
+#define SBWBS_WBB 0x00000080L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the SRC Slot Assignment Register
+// (SRCSA)
+//
+//****************************************************************************
+#define SRCSA_PLSS_MASK 0x0000001FL
+#define SRCSA_PLSS_SHIFT 0L
+#define SRCSA_PRSS_MASK 0x00001F00L
+#define SRCSA_PRSS_SHIFT 8L
+#define SRCSA_CLSS_MASK 0x001F0000L
+#define SRCSA_CLSS_SHIFT 16L
+#define SRCSA_CRSS_MASK 0x1F000000L
+#define SRCSA_CRSS_SHIFT 24L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the Sound System Power Management
+// register.(SSPM)
+//
+//****************************************************************************
+#define SSPM_FPDN 0x00000080L
+#define SSPM_MIXEN 0x00000040L
+#define SSPM_CSRCEN 0x00000020L
+#define SSPM_PSRCEN 0x00000010L
+#define SSPM_JSEN 0x00000008L
+#define SSPM_ACLEN 0x00000004L
+#define SSPM_FMEN 0x00000002L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the Sound System Control
+// Register. (SSCR)
+//
+//****************************************************************************
+#define SSCR_SB 0x00000004L
+#define SSCR_HVC 0x00000008L
+#define SSCR_LPFIFO 0x00000040L
+#define SSCR_LPSRC 0x00000080L
+#define SSCR_XLPSRC 0x00000100L
+#define SSCR_MVMD 0x00010000L
+#define SSCR_MVAD 0x00020000L
+#define SSCR_MVLD 0x00040000L
+#define SSCR_MVCS 0x00080000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the Clock Control Register 1.
+// (CLKCR1)
+//
+//****************************************************************************
+#define CLKCR1_DLLSS_MASK 0x0000000CL
+#define CLKCR1_DLLSS_SHIFT 2L
+#define CLKCR1_DLLP 0x00000010L
+#define CLKCR1_SWCE 0x00000020L
+#define CLKCR1_DLLOS 0x00000040L
+#define CLKCR1_CKRA 0x00010000L
+#define CLKCR1_CKRN 0x00020000L
+#define CLKCR1_DLLRDY 0x01000000L
+#define CLKCR1_CLKON 0x02000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the Sound Blaster Read Buffer
+// Status.(SBRBS)
+//
+//****************************************************************************
+#define SBRBS_RD_MASK 0x0000007FL
+#define SBRBS_RD_SHIFT 0L
+#define SBRBS_RBF 0x00000080L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the serial port master control
+// register.(SERMC)
+//
+//****************************************************************************
+#define SERMC_MSPE 0x00000001L
+#define SERMC_PTC_MASK 0x0000000EL
+#define SERMC_PTC_SHIFT 1L
+#define SERMC_PTC_AC97 0x00000002L
+#define SERMC_PLB 0x00000010L
+#define SERMC_PXLB 0x00000020L
+#define SERMC_LOFV 0x00080000L
+#define SERMC_SLB 0x00100000L
+#define SERMC_SXLB 0x00200000L
+#define SERMC_ODSEN1 0x01000000L
+#define SERMC_ODSEN2 0x02000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the General Purpose I/O Register.
+// (GPIOR)
+//
+//****************************************************************************
+#define GPIOR_VDNS 0x00000001L
+#define GPIOR_VUPS 0x00000002L
+#define GPIOR_GP1S 0x00000004L
+#define GPIOR_GP3S 0x00000008L
+#define GPIOR_GPSS 0x00000010L
+#define GPIOR_GPPS 0x00000020L
+#define GPIOR_GP1D 0x00000400L
+#define GPIOR_GP3D 0x00000800L
+#define GPIOR_VDNLT 0x00010000L
+#define GPIOR_VDNPO 0x00020000L
+#define GPIOR_VDNST 0x00040000L
+#define GPIOR_VDNW 0x00080000L
+#define GPIOR_VUPLT 0x00100000L
+#define GPIOR_VUPPO 0x00200000L
+#define GPIOR_VUPST 0x00400000L
+#define GPIOR_VUPW 0x00800000L
+#define GPIOR_GP1OE 0x01000000L
+#define GPIOR_GP1PT 0x02000000L
+#define GPIOR_GP1ST 0x04000000L
+#define GPIOR_GP1W 0x08000000L
+#define GPIOR_GP3OE 0x10000000L
+#define GPIOR_GP3PT 0x20000000L
+#define GPIOR_GP3ST 0x40000000L
+#define GPIOR_GP3W 0x80000000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the clock control register 1.
+//
+//****************************************************************************
+#define CLKCR1_PLLSS_MASK 0x0000000CL
+#define CLKCR1_PLLSS_SERIAL 0x00000000L
+#define CLKCR1_PLLSS_CRYSTAL 0x00000004L
+#define CLKCR1_PLLSS_PCI 0x00000008L
+#define CLKCR1_PLLSS_RESERVED 0x0000000CL
+#define CLKCR1_PLLP 0x00000010L
+#define CLKCR1_SWCE 0x00000020L
+#define CLKCR1_PLLOS 0x00000040L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the feature reporting register.
+//
+//****************************************************************************
+#define FRR_FAB_MASK 0x00000003L
+#define FRR_MASK_MASK 0x0000001CL
+#define FRR_ID_MASK 0x00003000L
+#define FRR_FAB_SHIFT 0L
+#define FRR_MASK_SHIFT 2L
+#define FRR_ID_SHIFT 12L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the serial port 1 configuration
+// register.
+//
+//****************************************************************************
+#define SERC1_VALUE 0x00000003L
+#define SERC1_SO1EN 0x00000001L
+#define SERC1_SO1F_MASK 0x0000000EL
+#define SERC1_SO1F_CS423X 0x00000000L
+#define SERC1_SO1F_AC97 0x00000002L
+#define SERC1_SO1F_DAC 0x00000004L
+#define SERC1_SO1F_SPDIF 0x00000006L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the serial port 2 configuration
+// register.
+//
+//****************************************************************************
+#define SERC2_VALUE 0x00000003L
+#define SERC2_SI1EN 0x00000001L
+#define SERC2_SI1F_MASK 0x0000000EL
+#define SERC2_SI1F_CS423X 0x00000000L
+#define SERC2_SI1F_AC97 0x00000002L
+#define SERC2_SI1F_ADC 0x00000004L
+#define SERC2_SI1F_SPDIF 0x00000006L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 control register.
+//
+//****************************************************************************
+#define ACCTL_ESYN 0x00000002L
+#define ACCTL_VFRM 0x00000004L
+#define ACCTL_DCV 0x00000008L
+#define ACCTL_CRW 0x00000010L
+#define ACCTL_TC 0x00000040L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status register.
+//
+//****************************************************************************
+#define ACSTS_CRDY 0x00000001L
+#define ACSTS_VSTS 0x00000002L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 output slot valid
+// register.
+//
+//****************************************************************************
+#define ACOSV_SLV3 0x00000001L
+#define ACOSV_SLV4 0x00000002L
+#define ACOSV_SLV5 0x00000004L
+#define ACOSV_SLV6 0x00000008L
+#define ACOSV_SLV7 0x00000010L
+#define ACOSV_SLV8 0x00000020L
+#define ACOSV_SLV9 0x00000040L
+#define ACOSV_SLV10 0x00000080L
+#define ACOSV_SLV11 0x00000100L
+#define ACOSV_SLV12 0x00000200L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 command address
+// register.
+//
+//****************************************************************************
+#define ACCAD_CI_MASK 0x0000007FL
+#define ACCAD_CI_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 command data register.
+//
+//****************************************************************************
+#define ACCDA_CD_MASK 0x0000FFFFL
+#define ACCDA_CD_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 input slot valid
+// register.
+//
+//****************************************************************************
+#define ACISV_ISV3 0x00000001L
+#define ACISV_ISV4 0x00000002L
+#define ACISV_ISV5 0x00000004L
+#define ACISV_ISV6 0x00000008L
+#define ACISV_ISV7 0x00000010L
+#define ACISV_ISV8 0x00000020L
+#define ACISV_ISV9 0x00000040L
+#define ACISV_ISV10 0x00000080L
+#define ACISV_ISV11 0x00000100L
+#define ACISV_ISV12 0x00000200L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status address
+// register.
+//
+//****************************************************************************
+#define ACSAD_SI_MASK 0x0000007FL
+#define ACSAD_SI_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status data register.
+//
+//****************************************************************************
+#define ACSDA_SD_MASK 0x0000FFFFL
+#define ACSDA_SD_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the I/O trap address and control
+// registers (all 12).
+//
+//****************************************************************************
+#define IOTAC_SA_MASK 0x0000FFFFL
+#define IOTAC_MSK_MASK 0x000F0000L
+#define IOTAC_IODC_MASK 0x06000000L
+#define IOTAC_IODC_16_BIT 0x00000000L
+#define IOTAC_IODC_10_BIT 0x02000000L
+#define IOTAC_IODC_12_BIT 0x04000000L
+#define IOTAC_WSPI 0x08000000L
+#define IOTAC_RSPI 0x10000000L
+#define IOTAC_WSE 0x20000000L
+#define IOTAC_WE 0x40000000L
+#define IOTAC_RE 0x80000000L
+#define IOTAC_SA_SHIFT 0L
+#define IOTAC_MSK_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PC/PCI master enable
+// register.
+//
+//****************************************************************************
+#define PCPCIEN_EN 0x00000001L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the joystick poll/trigger
+// register.
+//
+//****************************************************************************
+#define JSPT_CAX 0x00000001L
+#define JSPT_CAY 0x00000002L
+#define JSPT_CBX 0x00000004L
+#define JSPT_CBY 0x00000008L
+#define JSPT_BA1 0x00000010L
+#define JSPT_BA2 0x00000020L
+#define JSPT_BB1 0x00000040L
+#define JSPT_BB2 0x00000080L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the joystick control register.
+// The TBF bit has been moved from MIDSR register to JSCTL register bit 8.
+//
+//****************************************************************************
+#define JSCTL_SP_MASK 0x00000003L
+#define JSCTL_SP_SLOW 0x00000000L
+#define JSCTL_SP_MEDIUM_SLOW 0x00000001L
+#define JSCTL_SP_MEDIUM_FAST 0x00000002L
+#define JSCTL_SP_FAST 0x00000003L
+#define JSCTL_ARE 0x00000004L
+#define JSCTL_TBF 0x00000100L
+
+
+//****************************************************************************
+//
+// The following defines are for the flags in the MIDI control register.
+//
+//****************************************************************************
+#define MIDCR_TXE 0x00000001L
+#define MIDCR_RXE 0x00000002L
+#define MIDCR_RIE 0x00000004L
+#define MIDCR_TIE 0x00000008L
+#define MIDCR_MLB 0x00000010L
+#define MIDCR_MRST 0x00000020L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the MIDI status register.
+//
+//****************************************************************************
+#define MIDSR_RBE 0x00000080L
+#define MIDSR_RDA 0x00008000L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the MIDI write port register.
+//
+//****************************************************************************
+#define MIDWP_MWD_MASK 0x000000FFL
+#define MIDWP_MWD_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the MIDI read port register.
+//
+//****************************************************************************
+#define MIDRP_MRD_MASK 0x000000FFL
+#define MIDRP_MRD_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the configuration interface
+// register.
+//
+//****************************************************************************
+#define CFGI_CLK 0x00000001L
+#define CFGI_DOUT 0x00000002L
+#define CFGI_DIN_EEN 0x00000004L
+#define CFGI_EELD 0x00000008L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the subsystem ID and vendor ID
+// register.
+//
+//****************************************************************************
+#define SSVID_VID_MASK 0x0000FFFFL
+#define SSVID_SID_MASK 0xFFFF0000L
+#define SSVID_VID_SHIFT 0L
+#define SSVID_SID_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the GPIO pin interface register.
+//
+//****************************************************************************
+#define GPIOR_VOLDN 0x00000001L
+#define GPIOR_VOLUP 0x00000002L
+#define GPIOR_SI2D 0x00000004L
+#define GPIOR_SI2OE 0x00000008L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status register 2.
+//
+//****************************************************************************
+#define ACSTS2_CRDY 0x00000001L
+#define ACSTS2_VSTS 0x00000002L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 input slot valid
+// register 2.
+//
+//****************************************************************************
+#define ACISV2_ISV3 0x00000001L
+#define ACISV2_ISV4 0x00000002L
+#define ACISV2_ISV5 0x00000004L
+#define ACISV2_ISV6 0x00000008L
+#define ACISV2_ISV7 0x00000010L
+#define ACISV2_ISV8 0x00000020L
+#define ACISV2_ISV9 0x00000040L
+#define ACISV2_ISV10 0x00000080L
+#define ACISV2_ISV11 0x00000100L
+#define ACISV2_ISV12 0x00000200L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status address
+// register 2.
+//
+//****************************************************************************
+#define ACSAD2_SI_MASK 0x0000007FL
+#define ACSAD2_SI_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 status data register 2.
+//
+//****************************************************************************
+#define ACSDA2_SD_MASK 0x0000FFFFL
+#define ACSDA2_SD_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the I/O trap control register.
+//
+//****************************************************************************
+#define IOTCR_ITD 0x00000001L
+#define IOTCR_HRV 0x00000002L
+#define IOTCR_SRV 0x00000004L
+#define IOTCR_DTI 0x00000008L
+#define IOTCR_DFI 0x00000010L
+#define IOTCR_DDP 0x00000020L
+#define IOTCR_JTE 0x00000040L
+#define IOTCR_PPE 0x00000080L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the I/O trap address and control
+// registers for Hardware Master Volume.
+//
+//****************************************************************************
+#define IOTGP_SA_MASK 0x0000FFFFL
+#define IOTGP_MSK_MASK 0x000F0000L
+#define IOTGP_IODC_MASK 0x06000000L
+#define IOTGP_IODC_16_BIT 0x00000000L
+#define IOTGP_IODC_10_BIT 0x02000000L
+#define IOTGP_IODC_12_BIT 0x04000000L
+#define IOTGP_WSPI 0x08000000L
+#define IOTGP_RSPI 0x10000000L
+#define IOTGP_WSE 0x20000000L
+#define IOTGP_WE 0x40000000L
+#define IOTGP_RE 0x80000000L
+#define IOTGP_SA_SHIFT 0L
+#define IOTGP_MSK_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the I/O trap address and control
+// registers for Sound Blaster
+//
+//****************************************************************************
+#define IOTSB_SA_MASK 0x0000FFFFL
+#define IOTSB_MSK_MASK 0x000F0000L
+#define IOTSB_IODC_MASK 0x06000000L
+#define IOTSB_IODC_16_BIT 0x00000000L
+#define IOTSB_IODC_10_BIT 0x02000000L
+#define IOTSB_IODC_12_BIT 0x04000000L
+#define IOTSB_WSPI 0x08000000L
+#define IOTSB_RSPI 0x10000000L
+#define IOTSB_WSE 0x20000000L
+#define IOTSB_WE 0x40000000L
+#define IOTSB_RE 0x80000000L
+#define IOTSB_SA_SHIFT 0L
+#define IOTSB_MSK_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the I/O trap address and control
+// registers for FM.
+//
+//****************************************************************************
+#define IOTFM_SA_MASK 0x0000FFFFL
+#define IOTFM_MSK_MASK 0x000F0000L
+#define IOTFM_IODC_MASK 0x06000000L
+#define IOTFM_IODC_16_BIT 0x00000000L
+#define IOTFM_IODC_10_BIT 0x02000000L
+#define IOTFM_IODC_12_BIT 0x04000000L
+#define IOTFM_WSPI 0x08000000L
+#define IOTFM_RSPI 0x10000000L
+#define IOTFM_WSE 0x20000000L
+#define IOTFM_WE 0x40000000L
+#define IOTFM_RE 0x80000000L
+#define IOTFM_SA_SHIFT 0L
+#define IOTFM_MSK_SHIFT 16L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PC/PCI request register.
+//
+//****************************************************************************
+#define PCPRR_RDC_MASK 0x00000007L
+#define PCPRR_REQ 0x00008000L
+#define PCPRR_RDC_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PC/PCI grant register.
+//
+//****************************************************************************
+#define PCPGR_GDC_MASK 0x00000007L
+#define PCPGR_VL 0x00008000L
+#define PCPGR_GDC_SHIFT 0L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the PC/PCI Control Register.
+//
+//****************************************************************************
+#define PCPCR_EN 0x00000001L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the debug index register.
+//
+//****************************************************************************
+#define DREG_REGID_MASK 0x0000007FL
+#define DREG_DEBUG 0x00000080L
+#define DREG_RGBK_MASK 0x00000700L
+#define DREG_TRAP 0x00000800L
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_TRAPX 0x00001000L
+#endif
+#endif
+#define DREG_REGID_SHIFT 0L
+#define DREG_RGBK_SHIFT 8L
+#define DREG_RGBK_REGID_MASK 0x0000077FL
+#define DREG_REGID_R0 0x00000010L
+#define DREG_REGID_R1 0x00000011L
+#define DREG_REGID_R2 0x00000012L
+#define DREG_REGID_R3 0x00000013L
+#define DREG_REGID_R4 0x00000014L
+#define DREG_REGID_R5 0x00000015L
+#define DREG_REGID_R6 0x00000016L
+#define DREG_REGID_R7 0x00000017L
+#define DREG_REGID_R8 0x00000018L
+#define DREG_REGID_R9 0x00000019L
+#define DREG_REGID_RA 0x0000001AL
+#define DREG_REGID_RB 0x0000001BL
+#define DREG_REGID_RC 0x0000001CL
+#define DREG_REGID_RD 0x0000001DL
+#define DREG_REGID_RE 0x0000001EL
+#define DREG_REGID_RF 0x0000001FL
+#define DREG_REGID_RA_BUS_LOW 0x00000020L
+#define DREG_REGID_RA_BUS_HIGH 0x00000038L
+#define DREG_REGID_YBUS_LOW 0x00000050L
+#define DREG_REGID_YBUS_HIGH 0x00000058L
+#define DREG_REGID_TRAP_0 0x00000100L
+#define DREG_REGID_TRAP_1 0x00000101L
+#define DREG_REGID_TRAP_2 0x00000102L
+#define DREG_REGID_TRAP_3 0x00000103L
+#define DREG_REGID_TRAP_4 0x00000104L
+#define DREG_REGID_TRAP_5 0x00000105L
+#define DREG_REGID_TRAP_6 0x00000106L
+#define DREG_REGID_TRAP_7 0x00000107L
+#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL
+#define DREG_REGID_TOP_OF_STACK 0x0000010FL
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_REGID_TRAP_8 0x00000110L
+#define DREG_REGID_TRAP_9 0x00000111L
+#define DREG_REGID_TRAP_10 0x00000112L
+#define DREG_REGID_TRAP_11 0x00000113L
+#define DREG_REGID_TRAP_12 0x00000114L
+#define DREG_REGID_TRAP_13 0x00000115L
+#define DREG_REGID_TRAP_14 0x00000116L
+#define DREG_REGID_TRAP_15 0x00000117L
+#define DREG_REGID_TRAP_16 0x00000118L
+#define DREG_REGID_TRAP_17 0x00000119L
+#define DREG_REGID_TRAP_18 0x0000011AL
+#define DREG_REGID_TRAP_19 0x0000011BL
+#define DREG_REGID_TRAP_20 0x0000011CL
+#define DREG_REGID_TRAP_21 0x0000011DL
+#define DREG_REGID_TRAP_22 0x0000011EL
+#define DREG_REGID_TRAP_23 0x0000011FL
+#endif
+#endif
+#define DREG_REGID_RSA0_LOW 0x00000200L
+#define DREG_REGID_RSA0_HIGH 0x00000201L
+#define DREG_REGID_RSA1_LOW 0x00000202L
+#define DREG_REGID_RSA1_HIGH 0x00000203L
+#define DREG_REGID_RSA2 0x00000204L
+#define DREG_REGID_RSA3 0x00000205L
+#define DREG_REGID_RSI0_LOW 0x00000206L
+#define DREG_REGID_RSI0_HIGH 0x00000207L
+#define DREG_REGID_RSI1 0x00000208L
+#define DREG_REGID_RSI2 0x00000209L
+#define DREG_REGID_SAGUSTATUS 0x0000020AL
+#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL
+#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL
+#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL
+#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL
+#define DREG_REGID_RSDMA01E 0x0000020FL
+#define DREG_REGID_RSDMA23E 0x00000210L
+#define DREG_REGID_RSD0_LOW 0x00000211L
+#define DREG_REGID_RSD0_HIGH 0x00000212L
+#define DREG_REGID_RSD1_LOW 0x00000213L
+#define DREG_REGID_RSD1_HIGH 0x00000214L
+#define DREG_REGID_RSD2_LOW 0x00000215L
+#define DREG_REGID_RSD2_HIGH 0x00000216L
+#define DREG_REGID_RSD3_LOW 0x00000217L
+#define DREG_REGID_RSD3_HIGH 0x00000218L
+#define DREG_REGID_SRAR_HIGH 0x0000021AL
+#define DREG_REGID_SRAR_LOW 0x0000021BL
+#define DREG_REGID_DMA_STATE 0x0000021CL
+#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL
+#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL
+#define DREG_REGID_CPU_STATUS 0x00000300L
+#define DREG_REGID_MAC_MODE 0x00000301L
+#define DREG_REGID_STACK_AND_REPEAT 0x00000302L
+#define DREG_REGID_INDEX0 0x00000304L
+#define DREG_REGID_INDEX1 0x00000305L
+#define DREG_REGID_DMA_STATE_0_3 0x00000400L
+#define DREG_REGID_DMA_STATE_4_7 0x00000404L
+#define DREG_REGID_DMA_STATE_8_11 0x00000408L
+#define DREG_REGID_DMA_STATE_12_15 0x0000040CL
+#define DREG_REGID_DMA_STATE_16_19 0x00000410L
+#define DREG_REGID_DMA_STATE_20_23 0x00000414L
+#define DREG_REGID_DMA_STATE_24_27 0x00000418L
+#define DREG_REGID_DMA_STATE_28_31 0x0000041CL
+#define DREG_REGID_DMA_STATE_32_35 0x00000420L
+#define DREG_REGID_DMA_STATE_36_39 0x00000424L
+#define DREG_REGID_DMA_STATE_40_43 0x00000428L
+#define DREG_REGID_DMA_STATE_44_47 0x0000042CL
+#define DREG_REGID_DMA_STATE_48_51 0x00000430L
+#define DREG_REGID_DMA_STATE_52_55 0x00000434L
+#define DREG_REGID_DMA_STATE_56_59 0x00000438L
+#define DREG_REGID_DMA_STATE_60_63 0x0000043CL
+#define DREG_REGID_DMA_STATE_64_67 0x00000440L
+#define DREG_REGID_DMA_STATE_68_71 0x00000444L
+#define DREG_REGID_DMA_STATE_72_75 0x00000448L
+#define DREG_REGID_DMA_STATE_76_79 0x0000044CL
+#define DREG_REGID_DMA_STATE_80_83 0x00000450L
+#define DREG_REGID_DMA_STATE_84_87 0x00000454L
+#define DREG_REGID_DMA_STATE_88_91 0x00000458L
+#define DREG_REGID_DMA_STATE_92_95 0x0000045CL
+#define DREG_REGID_TRAP_SELECT 0x00000500L
+#define DREG_REGID_TRAP_WRITE_0 0x00000500L
+#define DREG_REGID_TRAP_WRITE_1 0x00000501L
+#define DREG_REGID_TRAP_WRITE_2 0x00000502L
+#define DREG_REGID_TRAP_WRITE_3 0x00000503L
+#define DREG_REGID_TRAP_WRITE_4 0x00000504L
+#define DREG_REGID_TRAP_WRITE_5 0x00000505L
+#define DREG_REGID_TRAP_WRITE_6 0x00000506L
+#define DREG_REGID_TRAP_WRITE_7 0x00000507L
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_REGID_TRAP_WRITE_8 0x00000510L
+#define DREG_REGID_TRAP_WRITE_9 0x00000511L
+#define DREG_REGID_TRAP_WRITE_10 0x00000512L
+#define DREG_REGID_TRAP_WRITE_11 0x00000513L
+#define DREG_REGID_TRAP_WRITE_12 0x00000514L
+#define DREG_REGID_TRAP_WRITE_13 0x00000515L
+#define DREG_REGID_TRAP_WRITE_14 0x00000516L
+#define DREG_REGID_TRAP_WRITE_15 0x00000517L
+#define DREG_REGID_TRAP_WRITE_16 0x00000518L
+#define DREG_REGID_TRAP_WRITE_17 0x00000519L
+#define DREG_REGID_TRAP_WRITE_18 0x0000051AL
+#define DREG_REGID_TRAP_WRITE_19 0x0000051BL
+#define DREG_REGID_TRAP_WRITE_20 0x0000051CL
+#define DREG_REGID_TRAP_WRITE_21 0x0000051DL
+#define DREG_REGID_TRAP_WRITE_22 0x0000051EL
+#define DREG_REGID_TRAP_WRITE_23 0x0000051FL
+#endif
+#endif
+#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L
+#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L
+#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L
+#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L
+#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L
+#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L
+#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L
+#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L
+#define DREG_REGID_MAC0_ACC0_MID 0x00000608L
+#define DREG_REGID_MAC0_ACC1_MID 0x00000609L
+#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL
+#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL
+#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL
+#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL
+#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL
+#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL
+#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L
+#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L
+#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L
+#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L
+#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L
+#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L
+#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L
+#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L
+#define DREG_REGID_RSHOUT_LOW 0x00000620L
+#define DREG_REGID_RSHOUT_MID 0x00000628L
+#define DREG_REGID_RSHOUT_HIGH 0x00000630L
+
+//****************************************************************************
+//
+// The following defines are for the flags in the AC97 S/PDIF Control register.
+//
+//****************************************************************************
+#define SPDIF_CONTROL_SPDIF_EN 0x00008000L
+#define SPDIF_CONTROL_VAL 0x00004000L
+#define SPDIF_CONTROL_COPY 0x00000004L
+#define SPDIF_CONTROL_CC0 0x00000010L
+#define SPDIF_CONTROL_CC1 0x00000020L
+#define SPDIF_CONTROL_CC2 0x00000040L
+#define SPDIF_CONTROL_CC3 0x00000080L
+#define SPDIF_CONTROL_CC4 0x00000100L
+#define SPDIF_CONTROL_CC5 0x00000200L
+#define SPDIF_CONTROL_CC6 0x00000400L
+#define SPDIF_CONTROL_L 0x00000800L
+
+#endif // _H_HWDEFS
#define _DEV_TABLE_C_
#include "sound_config.h"
-int softoss_dev = 0;
-
int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
int driver_size, int flags, unsigned int format_mask,
void *devc, int dma1, int dma2)
static int fifosize __initdata = DEFFIFOSIZE;
static int calibrate_signal __initdata;
-/* If we're a module, this is just init_module */
-
-int init_module(void)
-
#else /* not a module */
static int write_ndelay __initdata = -1;
#endif
static int
calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL;
+#endif /* MODULE */
-#ifdef MSND_CLASSIC
-int __init msnd_classic_init(void)
-#else
-int __init msnd_pinnacle_init(void)
-#endif /* MSND_CLASSIC */
-#endif /* MODULE */
+static int __init msnd_init(void)
{
int err;
#ifndef MSND_CLASSIC
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit msdn_cleanup(void)
{
unload_multisound();
msnd_fifo_free(&dev.DAPF);
msnd_fifo_free(&dev.DARF);
}
-#endif
+
+module_init(msnd_init);
+module_exit(msdn_cleanup);
#define SEQUENCER_C
#include "sound_config.h"
-#include "softoss.h"
-
-int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL;
#include "midi_ctrl.h"
if (data == 0xfe) /* Ignore active sensing */
return;
- if (softsynthp != NULL)
- tstamp = softsynthp(SSYN_GETTIME, 0, 0, 0);
- else
- tstamp = jiffies - seq_time;
+ tstamp = jiffies - seq_time;
if (tstamp != prev_input_time)
{
if (seq_mode == SEQ_2)
this_time = tmr->get_time(tmr_no);
- else if (softsynthp != NULL)
- this_time = softsynthp(SSYN_GETTIME, 0, 0, 0);
else
this_time = jiffies - seq_time;
prev_event_time = time;
seq_playing = 1;
- if (softsynthp != NULL)
- softsynthp(SSYN_REQUEST, time, 0, 0);
- else
- request_sound_timer(time);
+ request_sound_timer(time);
if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
wake_up(&seq_sleeper);
break;
case TMR_START:
- if (softsynthp != NULL)
- {
- softsynthp(SSYN_START, 0, 0, 0);
- seq_time = 0;
- }
- else
- seq_time = jiffies;
+ seq_time = jiffies;
prev_input_time = 0;
prev_event_time = 0;
break;
time = *delay;
prev_event_time = time;
- if (softsynthp != NULL)
- softsynthp(SSYN_REQUEST, time, 0, 0);
- else
- request_sound_timer(time);
+ request_sound_timer(time);
if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
wake_up(&seq_sleeper);
case SEQ_SYNCTIMER: /*
* Reset timer
*/
- if (softsynthp != NULL)
- seq_time = 0;
- else
- seq_time = jiffies;
+ seq_time = jiffies;
prev_input_time = 0;
prev_event_time = 0;
- if (softsynthp != NULL)
- softsynthp(SSYN_START, 0, 0, 0);
break;
case SEQ_MIDIPUTC: /*
*/
seq_playing = 1;
- if (softsynthp != NULL)
- softsynthp(SSYN_REQUEST, -1, 0, 0);
- else
- request_sound_timer(-1);
+ request_sound_timer(-1);
return 2;
}
else
}
}
- if (softsynthp != NULL)
- seq_time = 0;
- else
- seq_time = jiffies;
+ seq_time = jiffies;
prev_input_time = 0;
prev_event_time = 0;
- if (softsynthp != NULL)
- softsynthp(SSYN_START, 0, 0, 0);
if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
{
int chn;
unsigned long flags;
- if (softsynthp != NULL)
- softsynthp(SSYN_STOP, 0, 0, 0);
- else
- sound_stop_timer();
+ sound_stop_timer();
seq_time = jiffies;
prev_input_time = 0;
case SNDCTL_SEQ_GETTIME:
if (seq_mode == SEQ_2)
return tmr->ioctl(tmr_no, cmd, arg);
- if (softsynthp != NULL)
- val = softsynthp(SSYN_GETTIME, 0, 0, 0);
- else
- val = jiffies - seq_time;
+ val = jiffies - seq_time;
break;
case SNDCTL_SEQ_CTRLRATE:
EXPORT_SYMBOL(sound_timer_syncinterval);
EXPORT_SYMBOL(reprogram_timer);
-#include "softoss.h"
-
-EXPORT_SYMBOL(softsynthp);
-
/* Tuning */
#define _SEQUENCER_C_
+++ /dev/null
-/*
- * sound/softoss.c
- *
- * Software based MIDI synthsesizer driver.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- * Christoph Hellwig : adapted to module_init/module_exit
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-/*
- * When POLLED_MODE is defined, the resampling loop is run using a timer
- * callback routine. Normally the resampling loop is executed inside
- * audio buffer interrupt handler which doesn't work with single mode DMA.
- */
-#define SOFTSYN_MAIN
-#undef POLLED_MODE
-#define HANDLE_LFO
-
-#define ENVELOPE_SCALE 8
-#define NO_SAMPLE 0xffff
-
-#include "sound_config.h"
-#include "softoss.h"
-#include <linux/ultrasound.h>
-
-int softsynth_disabled = 0;
-
-static volatile int intr_pending = 0;
-
-#ifdef POLLED_MODE
-
-static struct timer_list poll_timer = {
- NULL, NULL, 0, 0, softsyn_poll
-};
-
-#else
-#endif
-
-#ifdef HANDLE_LFO
-/*
- * LFO table. Playback at 128 Hz gives 1 Hz LFO frequency.
- */
-static int tremolo_table[128] =
-{
- 0, 39, 158, 355, 630, 982, 1411, 1915,
- 2494, 3146, 3869, 4662, 5522, 6448, 7438, 8489,
- 9598, 10762, 11980, 13248, 14563, 15922, 17321, 18758,
- 20228, 21729, 23256, 24806, 26375, 27960, 29556, 31160,
- 32768, 34376, 35980, 37576, 39161, 40730, 42280, 43807,
- 45308, 46778, 48215, 49614, 50973, 52288, 53556, 54774,
- 55938, 57047, 58098, 59088, 60014, 60874, 61667, 62390,
- 63042, 63621, 64125, 64554, 64906, 65181, 65378, 65497,
- 65536, 65497, 65378, 65181, 64906, 64554, 64125, 63621,
- 63042, 62390, 61667, 60874, 60014, 59087, 58098, 57047,
- 55938, 54774, 53556, 52288, 50973, 49614, 48215, 46778,
- 45308, 43807, 42280, 40730, 39161, 37576, 35980, 34376,
- 32768, 31160, 29556, 27960, 26375, 24806, 23256, 21729,
- 20228, 18758, 17321, 15922, 14563, 13248, 11980, 10762,
- 9598, 8489, 7438, 6448, 5522, 4662, 3869, 3146,
- 2494, 1915, 1411, 982, 630, 355, 158, 39
-};
-
-static int vibrato_table[128] =
-{
- 0, 1608, 3212, 4808, 6393, 7962, 9512, 11039,
- 12540, 14010, 15447, 16846, 18205, 19520, 20788, 22006,
- 23170, 24279, 25330, 26320, 27246, 28106, 28899, 29622,
- 30274, 30853, 31357, 31786, 32138, 32413, 32610, 32729,
- 32768, 32729, 32610, 32413, 32138, 31786, 31357, 30853,
- 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279,
- 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010,
- 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608,
- 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039,
- -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006,
- -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622,
- -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729,
- -32768, -32729, -32610, -32413, -32138, -31786, -31357, -30853,
- -30274, -29622, -28899, -28106, -27246, -26320, -25330, -24279,
- -23170, -22006, -20788, -19520, -18205, -16846, -15447, -14010,
- -12540, -11039, -9512, -7962, -6393, -4808, -3212, -1608
-};
-
-#endif
-
-static unsigned long last_resample_jiffies;
-static unsigned long resample_counter;
-
-extern int *sound_osp;
-
-static volatile int is_running = 0;
-static int softsynth_loaded = 0;
-
-static struct synth_info softsyn_info = {
- "SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH
-};
-
-static struct softsyn_devc sdev_info = {
- 0
-};
-
-softsyn_devc *devc = &sdev_info; /* used in softoss_rs.c */
-
-static struct voice_alloc_info *voice_alloc;
-
-static int softsyn_open(int synthdev, int mode);
-static void init_voice(softsyn_devc * devc, int voice);
-static void compute_step(int voice);
-
-static volatile int tmr_running = 0;
-static int voice_limit = 24;
-
-
-static void set_max_voices(int nr)
-{
- int i;
-
- if (nr < 4)
- nr = 4;
-
- if (nr > voice_limit)
- nr = voice_limit;
-
- voice_alloc->max_voice = devc->maxvoice = nr;
- devc->afterscale = 5;
-
- for (i = 31; i > 0; i--)
- if (nr & (1 << i))
- {
- devc->afterscale = i + 1;
- return;
- }
-}
-
-static void update_vibrato(int voice)
-{
- voice_info *v = &softoss_voices[voice];
-
-#ifdef HANDLE_LFO
- int x;
-
- x = vibrato_table[v->vibrato_phase >> 8];
- v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff;
-
- x = (x * v->vibrato_depth) >> 15;
- v->vibrato_level = (x * 600) >> 8;
-
- compute_step(voice);
-#else
- v->vibrato_level = 0;
-#endif
-}
-
-#ifdef HANDLE_LFO
-static void update_tremolo(int voice)
-{
- voice_info *v = &softoss_voices[voice];
- int x;
-
- x = tremolo_table[v->tremolo_phase >> 8];
- v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff;
-
- v->tremolo_level = (x * v->tremolo_depth) >> 20;
-}
-#endif
-
-static void start_vibrato(int voice)
-{
- voice_info *v = &softoss_voices[voice];
- int rate;
-
- if (!v->vibrato_depth)
- return;
-
- rate = v->vibrato_rate * 6 * 128;
- v->vibrato_step = (rate * devc->control_rate) / devc->speed;
-
- devc->vibratomap |= (1 << voice); /* Enable vibrato */
-}
-
-static void start_tremolo(int voice)
-{
- voice_info *v = &softoss_voices[voice];
- int rate;
-
- if (!v->tremolo_depth)
- return;
-
- rate = v->tremolo_rate * 6 * 128;
- v->tremolo_step = (rate * devc->control_rate) / devc->speed;
-
- devc->tremolomap |= (1 << voice); /* Enable tremolo */
-}
-
-static void update_volume(int voice)
-{
- voice_info *v = &softoss_voices[voice];
- unsigned int vol;
-
- /*
- * Compute plain volume
- */
-
- vol = (v->velocity * v->expression_vol * v->main_vol) >> 12;
-
-#ifdef HANDLE_LFO
- /*
- * Handle LFO
- */
-
- if (devc->tremolomap & (1 << voice))
- {
- int t;
-
- t = 32768 - v->tremolo_level;
- vol = (vol * t) >> 15;
- update_tremolo(voice);
- }
-#endif
- /*
- * Envelope
- */
-
- if (v->mode & WAVE_ENVELOPES && !v->percussive_voice)
- vol = (vol * (v->envelope_vol >> 16)) >> 19;
- else
- vol >>= 4;
-
- /*
- * Handle panning
- */
-
- if (v->panning < 0) /* Pan left */
- v->rightvol = (vol * (128 + v->panning)) / 128;
- else
- v->rightvol = vol;
-
- if (v->panning > 0) /* Pan right */
- v->leftvol = (vol * (128 - v->panning)) / 128;
- else
- v->leftvol = vol;
-}
-
-static void step_envelope(int voice, int do_release, int velocity)
-{
- voice_info *v = &softoss_voices[voice];
- int r, rate, time, dif;
- unsigned int vol;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if (!voice_active[voice] || v->sample == NULL)
- {
- restore_flags(flags);
- return;
- }
- if (!do_release)
- {
- if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2)
- {
- /* Stop envelope until note off */
- v->envelope_volstep = 0;
- v->envelope_time = 0x7fffffff;
- if (v->mode & WAVE_VIBRATO)
- start_vibrato(voice);
- if (v->mode & WAVE_TREMOLO)
- start_tremolo(voice);
- restore_flags(flags);
- return;
- }
- }
- if (do_release)
- v->envelope_phase = 3;
- else
- v->envelope_phase++;
-
- if (v->envelope_phase >= 5) /* Finished */
- {
- init_voice(devc, voice);
- restore_flags(flags);
- return;
- }
- vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22;
-
-
- rate = v->sample->env_rate[v->envelope_phase];
- r = 3 - ((rate >> 6) & 0x3);
- r *= 3;
- r = (int) (rate & 0x3f) << r;
- rate = (((r * 44100) / devc->speed) * devc->control_rate) << 8;
-
- if (rate < (1 << 20)) /* Avoid infinitely "releasing" voices */
- rate = 1 << 20;
-
- dif = (v->envelope_vol - vol);
- if (dif < 0)
- dif *= -1;
- if (dif < rate * 2) /* Too close */
- {
- step_envelope(voice, 0, 60);
- restore_flags(flags);
- return;
- }
-
- if (vol > v->envelope_vol)
- {
- v->envelope_volstep = rate;
- time = (vol - v->envelope_vol) / rate;
- }
- else
- {
- v->envelope_volstep = -rate;
- time = (v->envelope_vol - vol) / rate;
- }
-
- time--;
- if (time <= 0)
- time = 1;
- v->envelope_time = time;
- restore_flags(flags);
-}
-
-static void step_envelope_lfo(int voice)
-{
- voice_info *v = &softoss_voices[voice];
-
- /*
- * Update pitch (vibrato) LFO
- */
-
- if (devc->vibratomap & (1 << voice))
- update_vibrato(voice);
-
- /*
- * Update envelope
- */
-
- if (v->mode & WAVE_ENVELOPES)
- {
- v->envelope_vol += v->envelope_volstep;
- /* Overshoot protection */
- if (v->envelope_vol < 0)
- {
- v->envelope_vol = v->envelope_target;
- v->envelope_volstep = 0;
- }
- if (v->envelope_time-- <= 0)
- {
- v->envelope_vol = v->envelope_target;
- step_envelope(voice, 0, 60);
- }
- }
-}
-
-static void compute_step(int voice)
-{
- voice_info *v = &softoss_voices[voice];
-
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
-
- v->current_freq = compute_finetune(v->orig_freq,
- v->bender,
- v->bender_range,
- v->vibrato_level);
- v->step = (((v->current_freq << 9) + (devc->speed >> 1)) / devc->speed);
-
- if (v->mode & WAVE_LOOP_BACK)
- v->step *= -1; /* Reversed playback */
-}
-
-static void init_voice(softsyn_devc * devc, int voice)
-{
- voice_info *v = &softoss_voices[voice];
- unsigned long flags;
-
- save_flags(flags);
- cli();
- voice_active[voice] = 0;
- devc->vibratomap &= ~(1 << voice);
- devc->tremolomap &= ~(1 << voice);
- v->mode = 0;
- v->wave = NULL;
- v->sample = NULL;
- v->ptr = 0;
- v->step = 0;
- v->startloop = 0;
- v->startbackloop = 0;
- v->endloop = 0;
- v->looplen = 0;
- v->bender = 0;
- v->bender_range = 200;
- v->panning = 0;
- v->main_vol = 127;
- v->expression_vol = 127;
- v->patch_vol = 127;
- v->percussive_voice = 0;
- v->sustain_mode = 0;
- v->envelope_phase = 1;
- v->envelope_vol = 1 << 24;
- v->envelope_volstep = 256;
- v->envelope_time = 0;
- v->vibrato_phase = 0;
- v->vibrato_step = 0;
- v->vibrato_level = 0;
- v->vibrato_rate = 0;
- v->vibrato_depth = 0;
- v->tremolo_phase = 0;
- v->tremolo_step = 0;
- v->tremolo_level = 0;
- v->tremolo_rate = 0;
- v->tremolo_depth = 0;
- voice_alloc->map[voice] = 0;
- voice_alloc->alloc_times[voice] = 0;
- restore_flags(flags);
-}
-
-static void reset_samples(softsyn_devc * devc)
-{
- int i;
-
- for (i = 0; i < MAX_VOICE; i++)
- voice_active[i] = 0;
- for (i = 0; i < devc->maxvoice; i++)
- {
- init_voice(devc, i);
- softoss_voices[i].instr = 0;
- }
-
- devc->ram_used = 0;
-
- for (i = 0; i < MAX_PATCH; i++)
- devc->programs[i] = NO_SAMPLE;
-
- for (i = 0; i < devc->nrsamples; i++)
- {
- vfree(devc->samples[i]);
- vfree(devc->wave[i]);
- devc->samples[i] = NULL;
- devc->wave[i] = NULL;
- }
- devc->nrsamples = 0;
-}
-
-static void init_engine(softsyn_devc * devc)
-{
- int i, fz, srate, sz = devc->channels;
-
- set_max_voices(devc->default_max_voices);
- voice_alloc->timestamp = 0;
-
- if (devc->bits == 16)
- sz *= 2;
-
- fz = devc->fragsize / sz; /* Samples per fragment */
- devc->samples_per_fragment = fz;
-
- devc->usecs = 0;
- devc->usecs_per_frag = (1000000 * fz) / devc->speed;
-
- for (i = 0; i < devc->maxvoice; i++)
- {
- init_voice(devc, i);
- softoss_voices[i].instr = 0;
- }
- devc->engine_state = ES_STOPPED;
-
- /*
- * Initialize delay
- */
-
- for (i = 0; i < DELAY_SIZE; i++)
- left_delay[i] = right_delay[i] = 0;
- delayp = 0;
- srate = (devc->speed / 10000); /* 1 to 4 */
- if (srate <= 0)
- srate = 1;
- devc->delay_size = (DELAY_SIZE * srate) / 4;
- if (devc->delay_size == 0 || devc->delay_size > DELAY_SIZE)
- devc->delay_size = DELAY_SIZE;
-}
-
-void softsyn_control_loop(void)
-{
- int voice;
-
- /*
- * Recompute envlope, LFO, etc.
- */
- for (voice = 0; voice < devc->maxvoice; voice++)
- {
- if (voice_active[voice])
- {
- update_volume(voice);
- step_envelope_lfo(voice);
- }
- else
- voice_alloc->map[voice] = 0;
- }
-}
-
-static void start_engine(softsyn_devc * devc);
-
-static void do_resample(int dummy)
-{
- struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out;
- struct voice_info *vinfo;
- unsigned long flags, jif;
-
- int voice, loops;
- short *buf;
-
- if (softsynth_disabled)
- return;
-
- save_flags(flags);
- cli();
-
- if (is_running)
- {
- printk(KERN_WARNING "SoftOSS: Playback overrun\n");
- restore_flags(flags);
- return;
- }
- jif = jiffies;
- if (jif == last_resample_jiffies)
- {
- if (resample_counter++ > 50)
- {
- for (voice = 0; voice < devc->maxvoice; voice++)
- init_voice(devc, voice);
- voice_limit--;
- resample_counter = 0;
- printk(KERN_WARNING "SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit);
-
- if (voice_limit < 10)
- {
- voice_limit = 10;
- devc->speed = (devc->speed * 2) / 3;
-
- printk(KERN_WARNING "SoftOSS: Dropping sampling rate and stopping the device.\n");
- softsynth_disabled = 1;
- }
- }
- }
- else
- {
- last_resample_jiffies = jif;
- resample_counter = 0;
- }
-
- /* is_running = 1; */
-
- if (dmap->qlen > devc->max_playahead)
- {
- printk(KERN_WARNING "SoftOSS: audio buffers full\n");
- is_running = 0;
- restore_flags(flags);
- return;
- }
- /*
- * First verify that all active voices are valid (do this just once per block).
- */
-
- for (voice = 0; voice < devc->maxvoice; voice++)
- {
- if (voice_active[voice])
- {
- int ptr;
-
- vinfo = &softoss_voices[voice];
- ptr = vinfo->ptr >> 9;
-
- if (vinfo->wave == NULL || ptr < 0 || ptr > vinfo->sample->len)
- init_voice(devc, voice);
- else if (!(vinfo->mode & WAVE_LOOPING) && (vinfo->ptr + vinfo->step) > vinfo->endloop)
- voice_active[voice] = 0;
- }
- }
-
- /*
- * Start the resampling process
- */
-
- loops = devc->samples_per_fragment;
- buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size));
-
- softsynth_resample_loop(buf, loops); /* In Xsoftsynth_rs.c */
-
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
- dmap->qlen++;
- dmap->user_counter += dmap->fragment_size;
-
- devc->usecs += devc->usecs_per_frag;
-
- if (tmr_running)
- sound_timer_interrupt();
- /*
- * Execute timer
- */
-
- if (!tmr_running)
- {
- if (devc->usecs >= devc->next_event_usecs)
- {
- devc->next_event_usecs = ~0;
- sequencer_timer(0);
- }
- }
-
- is_running = 0;
- restore_flags(flags);
-}
-
-static void delayed_resample(int dummy)
-{
- struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out;
- int n = 0;
-
- if (is_running)
- return;
-
- while (devc->engine_state != ES_STOPPED && dmap->qlen < devc->max_playahead && n++ < 2)
- do_resample(0);
- intr_pending = 0;
-}
-
-#ifdef POLLED_MODE
-static void softsyn_poll(unsigned long dummy)
-{
- delayed_resample(0);
-
- if (devc->engine_state != ES_STOPPED)
- {
- poll_timer.expires = jiffies+1;
- add_timer(&poll_timer);
- }
-}
-
-#else
-static void softsyn_callback(int dev, int parm)
-{
- delayed_resample(0);
-}
-#endif
-
-static void start_engine(softsyn_devc * devc)
-{
- struct dma_buffparms *dmap;
- int trig, n;
- mm_segment_t fs;
-
- if (!devc->audio_opened)
- if (softsyn_open(devc->synthdev, 0) < 0)
- return;
-
- if (devc->audiodev >= num_audiodevs)
- return;
-
- dmap = audio_devs[devc->audiodev]->dmap_out;
-
- devc->usecs = 0;
- devc->next_event_usecs = ~0;
- devc->control_rate = 64;
- devc->control_counter = 0;
-
- if (devc->engine_state == ES_STOPPED)
- {
- n = trig = 0;
- fs = get_fs();
- set_fs(get_ds());
- dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig);
-#ifdef POLLED_MODE
- poll_timer.expires = jiffies+1;
- add_timer(&poll_timer);
- /* Start polling */
-#else
- dmap->audio_callback = softsyn_callback;
- dmap->qhead = dmap->qtail = dmap->qlen = 0;
-#endif
- while (dmap->qlen < devc->max_playahead && n++ < 2)
- do_resample(0);
- devc->engine_state = ES_STARTED;
- last_resample_jiffies = jiffies;
- resample_counter = 0;
- trig = PCM_ENABLE_OUTPUT;
- if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig) < 0)
- printk(KERN_ERR "SoftOSS: Trigger failed\n");
- set_fs(fs);
- }
-}
-
-static void stop_engine(softsyn_devc * devc)
-{
-}
-
-static void request_engine(softsyn_devc * devc, int ticks)
-{
- if (ticks < 0) /* Relative time */
- devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ);
- else
- devc->next_event_usecs = ticks * (1000000 / HZ);
-}
-
-/*
- * Softsync hook serves mode1 (timing) calls made by sequencer.c
- */
-
-static int softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3)
-{
- switch (cmd)
- {
- case SSYN_START:
- start_engine(devc);
- break;
-
- case SSYN_STOP:
- stop_engine(devc);
- break;
-
- case SSYN_REQUEST:
- request_engine(devc, parm1);
- break;
-
- case SSYN_GETTIME:
- return devc->usecs / (1000000 / HZ);
- break;
-
- default:
- printk(KERN_WARNING "SoftOSS: Unknown request %d\n", cmd);
- }
- return 0;
-}
-
-static int softsyn_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
- switch (cmd)
- {
- case SNDCTL_SYNTH_INFO:
- softsyn_info.nr_voices = devc->maxvoice;
- if (copy_to_user(arg, &softsyn_info, sizeof(softsyn_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- stop_engine(devc);
- reset_samples(devc);
- return 0;
-
- case SNDCTL_SYNTH_MEMAVL:
- return devc->ram_size - devc->ram_used;
-
- default:
- return -EINVAL;
- }
-}
-
-static int softsyn_kill_note(int devno, int voice, int note, int velocity)
-{
- if (voice < 0 || voice > devc->maxvoice)
- return 0;
- voice_alloc->map[voice] = 0xffff; /* Releasing */
-
- if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */
- {
- softoss_voices[voice].sustain_mode = 3; /* Note off pending */
- return 0;
- }
- if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE)
- {
- init_voice(devc, voice); /* Mark it inactive */
- return 0;
- }
- if (softoss_voices[voice].mode & WAVE_ENVELOPES)
- step_envelope(voice, 1, velocity); /* Enter sustain phase */
- else
- init_voice(devc, voice); /* Mark it inactive */
- return 0;
-}
-
-static int softsyn_set_instr(int dev, int voice, int instr)
-{
- if (voice < 0 || voice > devc->maxvoice)
- return 0;
-
- if (instr < 0 || instr > MAX_PATCH)
- {
- printk(KERN_ERR "SoftOSS: Invalid instrument number %d\n", instr);
- return 0;
- }
- softoss_voices[voice].instr = instr;
- return 0;
-}
-
-static int softsyn_start_note(int dev, int voice, int note, int volume)
-{
- int instr = 0;
- int best_sample, best_delta, delta_freq, selected;
- unsigned long note_freq, freq, base_note, flags;
- voice_info *v = &softoss_voices[voice];
-
- struct patch_info *sample;
-
- if (voice < 0 || voice > devc->maxvoice)
- return 0;
-
- if (volume == 0) /* Actually note off */
- softsyn_kill_note(dev, voice, note, volume);
-
- save_flags(flags);
- cli();
-
- if (note == 255)
- { /* Just volume update */
- v->velocity = volume;
- if (voice_active[voice])
- update_volume(voice);
- restore_flags(flags);
- return 0;
- }
- voice_active[voice] = 0; /* Stop the voice for a while */
- devc->vibratomap &= ~(1 << voice);
- devc->tremolomap &= ~(1 << voice);
-
- instr = v->instr;
- if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE)
- {
- printk(KERN_WARNING "SoftOSS: Undefined MIDI instrument %d\n", instr);
- restore_flags(flags);
- return 0;
- }
- instr = devc->programs[instr];
-
- if (instr < 0 || instr >= devc->nrsamples)
- {
- printk(KERN_WARNING "SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr);
- restore_flags(flags);
- return 0;
- }
- note_freq = note_to_freq(note);
-
- selected = -1;
-
- best_sample = instr;
- best_delta = 1000000;
-
- while (instr != NO_SAMPLE && instr >= 0 && selected == -1)
- {
- delta_freq = note_freq - devc->samples[instr]->base_note;
-
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = instr;
- best_delta = delta_freq;
- }
- if (devc->samples[instr]->low_note <= note_freq &&
- note_freq <= devc->samples[instr]->high_note)
- {
- selected = instr;
- }
- else instr = devc->samples[instr]->key; /* Link to next sample */
-
- if (instr < 0 || instr >= devc->nrsamples)
- instr = NO_SAMPLE;
- }
-
- if (selected == -1)
- instr = best_sample;
- else
- instr = selected;
-
- if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples)
- {
- printk(KERN_WARNING "SoftOSS: Unresolved MIDI instrument %d\n", v->instr);
- restore_flags(flags);
- return 0;
- }
- sample = devc->samples[instr];
- v->sample = sample;
-
- if (v->percussive_voice) /* No key tracking */
- v->orig_freq = sample->base_freq; /* Fixed pitch */
- else
- {
- base_note = sample->base_note / 100;
- note_freq /= 100;
-
- freq = sample->base_freq * note_freq / base_note;
- v->orig_freq = freq;
- }
-
- if (!(sample->mode & WAVE_LOOPING))
- sample->loop_end = sample->len;
-
- v->wave = devc->wave[instr];
- if (volume < 0)
- volume = 0;
- else if (volume > 127)
- volume = 127;
- v->ptr = 0;
- v->startloop = sample->loop_start * 512;
- v->startbackloop = 0;
- v->endloop = sample->loop_end * 512;
- v->looplen = (sample->loop_end - sample->loop_start) * 512;
- v->leftvol = 64;
- v->rightvol = 64;
- v->patch_vol = sample->volume;
- v->velocity = volume;
- v->mode = sample->mode;
- v->vibrato_phase = 0;
- v->vibrato_step = 0;
- v->vibrato_level = 0;
- v->vibrato_rate = 0;
- v->vibrato_depth = 0;
- v->tremolo_phase = 0;
- v->tremolo_step = 0;
- v->tremolo_level = 0;
- v->tremolo_rate = 0;
- v->tremolo_depth = 0;
-
- if (!(v->mode & WAVE_LOOPING))
- v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK);
- else if (v->mode & WAVE_LOOP_BACK)
- {
- v->ptr = sample->len;
- v->startbackloop = v->startloop;
- }
- if (v->mode & WAVE_VIBRATO)
- {
- v->vibrato_rate = sample->vibrato_rate;
- v->vibrato_depth = sample->vibrato_depth;
- }
- if (v->mode & WAVE_TREMOLO)
- {
- v->tremolo_rate = sample->tremolo_rate;
- v->tremolo_depth = sample->tremolo_depth;
- }
- if (v->mode & WAVE_ENVELOPES)
- {
- v->envelope_phase = -1;
- v->envelope_vol = 0;
- step_envelope(voice, 0, 60);
- }
- update_volume(voice);
- compute_step(voice);
-
- voice_active[voice] = 1; /* Mark it active */
- restore_flags(flags);
- return 0;
-}
-
-static int softsyn_open(int synthdev, int mode)
-{
- int err;
- extern int softoss_dev;
- int frags = 0x7fff0007; /* fragment size of 128 bytes */
- mm_segment_t fs;
-
- if (devc->audio_opened) /* Already opened */
- return 0;
-
- softsynth_disabled = 0;
- devc->finfo.f_mode = FMODE_WRITE;
- devc->finfo.f_flags = 0;
-
- if (softoss_dev >= num_audiodevs)
- softoss_dev = num_audiodevs - 1;
-
- if (softoss_dev < 0)
- softoss_dev = 0;
- if (softoss_dev >= num_audiodevs)
- return -ENXIO;
- devc->audiodev = softoss_dev;
-
- if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE))
- {
-/* printk(KERN_ERR "SoftOSS: The audio device doesn't support 16 bits\n"); */
- return -ENXIO;
- }
- if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0)
- return err;
-
- devc->speed = audio_devs[devc->audiodev]->d->set_speed(
- devc->audiodev, devc->speed);
- devc->channels = audio_devs[devc->audiodev]->d->set_channels(
- devc->audiodev, devc->channels);
- devc->bits = audio_devs[devc->audiodev]->d->set_bits(
- devc->audiodev, devc->bits);
-
-
- DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels));
- fs = get_fs();
- set_fs(get_ds());
- dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags);
- dma_ioctl(devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize);
- set_fs(fs);
-
- if (devc->bits != 16 || devc->channels != 2)
- {
- audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo);
-/* printk("SoftOSS: A 16 bit stereo sound card is required\n");*/
- return -EINVAL;
- }
- if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs)
- devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs;
-
- DDB(printk("SoftOSS: Using %d fragments of %d bytes\n", devc->max_playahead, devc->fragsize));
-
- init_engine(devc);
- devc->audio_opened = 1;
- devc->sequencer_mode = mode;
- return 0;
-}
-
-static void softsyn_close(int synthdev)
-{
- mm_segment_t fs;
-
- devc->engine_state = ES_STOPPED;
-#ifdef POLLED_MODE
- del_timer(&poll_timer);
-#endif
- fs = get_fs();
- set_fs(get_ds());
- dma_ioctl(devc->audiodev, SNDCTL_DSP_RESET, 0);
- set_fs(fs);
- if (devc->audio_opened)
- audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo);
- devc->audio_opened = 0;
-}
-
-static void softsyn_hw_control(int dev, unsigned char *event_rec)
-{
- int voice, cmd;
- unsigned short p1, p2;
- unsigned int plong;
-
- cmd = event_rec[2];
- voice = event_rec[3];
- p1 = *(unsigned short *) &event_rec[4];
- p2 = *(unsigned short *) &event_rec[6];
- plong = *(unsigned int *) &event_rec[4];
-
- switch (cmd)
- {
-
- case _GUS_NUMVOICES:
- set_max_voices(p1);
- break;
-
- default:;
- }
-}
-
-static int softsyn_load_patch(int dev, int format, const char *addr,
- int offs, int count, int pmgr_flag)
-{
- struct patch_info *patch = NULL;
-
- int i, p, instr;
- long sizeof_patch;
- int memlen, adj;
- unsigned short data;
- short *wave = NULL;
-
- sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */
-
- if (format != GUS_PATCH)
- {
-/* printk(KERN_ERR "SoftOSS: Invalid patch format (key) 0x%x\n", format);*/
- return -EINVAL;
- }
- if (count < sizeof_patch)
- {
-/* printk(KERN_ERR "SoftOSS: Patch header too short\n");*/
- return -EINVAL;
- }
- count -= sizeof_patch;
-
- if (devc->nrsamples >= MAX_SAMPLE)
- {
-/* printk(KERN_ERR "SoftOSS: Sample table full\n");*/
- return -ENOBUFS;
- }
-
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- patch = vmalloc(sizeof(*patch));
-
- if (patch == NULL)
- {
-/* printk(KERN_ERR "SoftOSS: Out of memory\n");*/
- return -ENOMEM;
- }
- if(copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs))
- {
- vfree(patch);
- return -EFAULT;
- }
-
- if (patch->mode & WAVE_ROM)
- {
- vfree(patch);
- return -EINVAL;
- }
- instr = patch->instr_no;
-
- if (instr < 0 || instr > MAX_PATCH)
- {
-/* printk(KERN_ERR "SoftOSS: Invalid patch number %d\n", instr);*/
- vfree(patch);
- return -EINVAL;
- }
- if (count < patch->len)
- {
-/* printk(KERN_ERR "SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len);*/
- patch->len = count;
- }
- if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used))
- {
-/* printk(KERN_ERR "SoftOSS: Invalid sample length %d\n", (int) patch->len); */
- vfree(patch);
- return -EINVAL;
- }
- if (patch->mode & WAVE_LOOPING)
- {
- if (patch->loop_start < 0 || patch->loop_start >= patch->len)
- {
-/* printk(KERN_ERR "SoftOSS: Invalid loop start %d\n", patch->loop_start);*/
- vfree(patch);
- return -EINVAL;
- }
- if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len)
- {
-/* printk(KERN_ERR "SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end);*/
- vfree(patch);
- return -EINVAL;
- }
- }
- /*
- * Next load the wave data to memory
- */
-
- memlen = patch->len;
- adj = 1;
-
- if (!(patch->mode & WAVE_16_BITS))
- memlen *= 2;
- else
- adj = 2;
-
- wave = vmalloc(memlen);
-
- if (wave == NULL)
- {
-/* printk(KERN_ERR "SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen);*/
- vfree(patch);
- return -ENOMEM;
- }
- p = 0;
- for (i = 0; i < memlen / 2; i++) /* Handle words */
- {
- unsigned char tmp;
- data = 0;
- if (patch->mode & WAVE_16_BITS)
- {
- get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */
- data = tmp;
- get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */
- if (patch->mode & WAVE_UNSIGNED)
- tmp ^= 0x80; /* Convert to signed */
- data |= (tmp << 8);
- }
- else
- {
- get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));
- if (patch->mode & WAVE_UNSIGNED)
- tmp ^= 0x80; /* Convert to signed */
- data = (tmp << 8); /* Convert to 16 bits */
- }
- wave[i] = (short) data;
- }
-
- devc->ram_used += patch->len;
-
- /*
- * Convert pointers to 16 bit indexes
- */
- patch->len /= adj;
- patch->loop_start /= adj;
- patch->loop_end /= adj;
-
- /*
- * Finally link the loaded patch to the chain
- */
-
- patch->key = devc->programs[instr];
- devc->programs[instr] = devc->nrsamples;
- devc->wave[devc->nrsamples] = (short *) wave;
- devc->samples[devc->nrsamples++] = patch;
-
- return 0;
-}
-
-static void softsyn_panning(int dev, int voice, int pan)
-{
- if (voice < 0 || voice > devc->maxvoice)
- return;
-
- if (pan < -128)
- pan = -128;
- if (pan > 127)
- pan = 127;
-
- softoss_voices[voice].panning = pan;
- if (voice_active[voice])
- update_volume(voice);
-}
-
-static void softsyn_volume_method(int dev, int mode)
-{
-}
-
-static void softsyn_aftertouch(int dev, int voice, int pressure)
-{
- if (voice < 0 || voice > devc->maxvoice)
- return;
-
- if (voice_active[voice])
- update_volume(voice);
-}
-
-static void softsyn_controller(int dev, int voice, int ctrl_num, int value)
-{
- unsigned long flags;
-
- if (voice < 0 || voice > devc->maxvoice)
- return;
- save_flags(flags);
- cli();
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- softoss_voices[voice].bender = value;
- if (voice_active[voice])
- compute_step(voice); /* Update pitch */
- break;
-
-
- case CTRL_PITCH_BENDER_RANGE:
- softoss_voices[voice].bender_range = value;
- break;
-
- case CTL_EXPRESSION:
- value /= 128;
- case CTRL_EXPRESSION:
- softoss_voices[voice].expression_vol = value;
- if (voice_active[voice])
- update_volume(voice);
- break;
-
- case CTL_PAN:
- softsyn_panning(dev, voice, (value * 2) - 128);
- break;
-
- case CTL_MAIN_VOLUME:
- value = (value * 100) / 16383;
-
- case CTRL_MAIN_VOLUME:
- softoss_voices[voice].main_vol = value;
- if (voice_active[voice])
- update_volume(voice);
- break;
-
- default:
- break;
- }
- restore_flags(flags);
-}
-
-static void softsyn_bender(int dev, int voice, int value)
-{
- if (voice < 0 || voice > devc->maxvoice)
- return;
-
- softoss_voices[voice].bender = value - 8192;
- if (voice_active[voice])
- compute_step(voice); /* Update pitch */
-}
-
-static int softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
- int i, p, best = -1, best_time = 0x7fffffff;
-
- p = alloc->ptr;
-
- /*
- * First look for a completely stopped voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0)
- {
- alloc->ptr = p;
- voice_active[p] = 0;
- return p;
- }
- if (alloc->alloc_times[p] < best_time)
- {
- best = p;
- best_time = alloc->alloc_times[p];
- }
- p = (p + 1) % alloc->max_voice;
- }
-
- /*
- * Then look for a releasing voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- voice_active[p] = 0;
- return p;
- }
- p = (p + 1) % alloc->max_voice;
- }
-
- if (best >= 0)
- p = best;
-
- alloc->ptr = p;
- voice_active[p] = 0;
- return p;
-}
-
-static void softsyn_setup_voice(int dev, int voice, int chn)
-{
- unsigned long flags;
-
- struct channel_info *info = &synth_devs[dev]->chn_info[chn];
-
- save_flags(flags);
- cli();
-
- /* init_voice(devc, voice); */
- softsyn_set_instr(dev, voice, info->pgm_num);
-
- softoss_voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */
- softoss_voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
- softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128);
- softoss_voices[voice].bender = 0; /* info->bender_value; */
- softoss_voices[voice].bender_range = info->bender_range;
-
- if (chn == 9)
- softoss_voices[voice].percussive_voice = 1;
- restore_flags(flags);
-}
-
-static void softsyn_reset(int devno)
-{
- int i;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- for (i = 0; i < devc->maxvoice; i++)
- init_voice(devc, i);
- restore_flags(flags);
-}
-
-static struct synth_operations softsyn_operations =
-{
- owner: THIS_MODULE,
- id: "SoftOSS",
- info: &softsyn_info,
- midi_dev: 0,
- synth_type: SYNTH_TYPE_SAMPLE,
- synth_subtype: 0,
- open: softsyn_open,
- close: softsyn_close,
- ioctl: softsyn_ioctl,
- kill_note: softsyn_kill_note,
- start_note: softsyn_start_note,
- set_instr: softsyn_set_instr,
- reset: softsyn_reset,
- hw_control: softsyn_hw_control,
- load_patch: softsyn_load_patch,
- aftertouch: softsyn_aftertouch,
- controller: softsyn_controller,
- panning: softsyn_panning,
- volume_method: softsyn_volume_method,
- bender: softsyn_bender,
- alloc_voice: softsyn_alloc_voice,
- setup_voice: softsyn_setup_voice
-};
-
-/*
- * Timer stuff (for /dev/music).
- */
-
-static unsigned int soft_tmr_start(int dev, unsigned int usecs)
-{
- tmr_running = 1;
- start_engine(devc);
- return devc->usecs_per_frag;
-}
-
-static void soft_tmr_disable(int dev)
-{
- stop_engine(devc);
- tmr_running = 0;
-}
-
-static void soft_tmr_restart(int dev)
-{
- tmr_running = 1;
-}
-
-static struct sound_lowlev_timer soft_tmr =
-{
- 0,
- 9999,
- soft_tmr_start,
- soft_tmr_disable,
- soft_tmr_restart
-};
-
-static int __init probe_softsyn(struct address_info *hw_config)
-{
- int i;
-
- if (softsynth_loaded)
- return 0;
-
- devc->ram_size = 8 * 1024 * 1024;
- devc->ram_used = 0;
- devc->nrsamples = 0;
- for (i = 0; i < MAX_PATCH; i++)
- {
- devc->programs[i] = NO_SAMPLE;
- devc->wave[i] = NULL;
- }
-
- devc->maxvoice = DEFAULT_VOICES;
-
- devc->audiodev = 0;
- devc->audio_opened = 0;
- devc->channels = 2;
- devc->bits = 16;
- devc->max_playahead = 32;
-
-#ifdef CONFIG_SOFTOSS_RATE
- devc->speed = CONFIG_SOFTOSS_RATE;
-#else
- devc->speed = 32000;
-#endif
-
-#ifdef CONFIG_SOFTOSS_VOICES
- devc->default_max_voices = CONFIG_SOFTOSS_VOICES;
-#else
- devc->default_max_voices = 32;
-#endif
- softsynth_loaded = 1;
- return 1;
-}
-
-static void __init attach_softsyn_card(struct address_info *hw_config)
-{
- voice_alloc = &softsyn_operations.alloc;
- synth_devs[devc->synthdev = num_synths++] = &softsyn_operations;
- sequencer_init();
- sound_timer_init(&soft_tmr, "SoftOSS");
- devc->timerdev = num_sound_timers;
- softsynthp = softsynth_hook;
-
-#ifndef POLLED_MODE
-#endif
-}
-
-static void __exit unload_softsyn(struct address_info *hw_config)
-{
- if (!softsynth_loaded)
- return;
- softsynthp = NULL;
- softsynth_loaded = 0;
- reset_samples(devc);
-}
-
-static struct address_info cfg;
-
-static int __init init_softoss(void)
-{
- printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n");
- if (!probe_softsyn(&cfg))
- return -ENODEV;
- attach_softsyn_card(&cfg);
-
- return 0;
-}
-
-static void __exit cleanup_softoss(void)
-{
- unload_softsyn(&cfg);
- sound_unload_synthdev(devc->synthdev);
- sound_unload_timerdev(devc->timerdev);
-}
-
-module_init(init_softoss);
-module_exit(cleanup_softoss);
+++ /dev/null
-/*
- * softoss.h - Definitions for Software MIDI Synthesizer.
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-
-/*
- * Sequencer mode1 timer calls made by sequencer.c
- */
-extern int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3);
-
-#define SSYN_START 1
-#define SSYN_REQUEST 2 /* parm1 = time */
-#define SSYN_STOP 3
-#define SSYN_GETTIME 4 /* Returns number of ticks since reset */
-
-#define MAX_PATCH 256
-#define MAX_SAMPLE 512
-#define MAX_VOICE 32
-#define DEFAULT_VOICES 16
-
-typedef struct voice_info
-{
-/*
- * Don't change anything in the beginning of this struct. These fields are used
- * by the resampling loop which may have been written in assembly for some
- * architectures. Any change may make the resampling code incompatible
- */
- int instr;
- short *wave;
- struct patch_info *sample;
-
- unsigned int ptr; int step; /* Pointer to the wave data and pointer increment */
-
- int mode;
- int startloop, startbackloop, endloop, looplen;
-
- unsigned int leftvol, rightvol;
-/***** Don't change anything above this */
-
- volatile unsigned long orig_freq, current_freq;
- volatile int bender, bender_range, panning;
- volatile int main_vol, expression_vol, patch_vol, velocity;
-
-/* Envelope parameters */
-
- int envelope_phase;
- volatile int envelope_vol;
- volatile int envelope_volstep;
- int envelope_time; /* Number of remaining envelope steps */
- unsigned int envelope_target;
- int percussive_voice;
- int sustain_mode; /* 0=off, 1=sustain on, 2=sustain on+key released */
-
-/* Vibrato */
- int vibrato_rate;
- int vibrato_depth;
- int vibrato_phase;
- int vibrato_step;
- int vibrato_level;
-
-/* Tremolo */
- int tremolo_rate;
- int tremolo_depth;
- int tremolo_phase;
- int tremolo_step;
- int tremolo_level;
-} voice_info;
-
-extern voice_info softoss_voices[MAX_VOICE]; /* Voice spesific info */
-
-typedef struct softsyn_devc
-{
-/*
- * Don't change anything in the beginning of this struct. These fields are used
- * by the resampling loop which may have been written in assembly for some
- * architectures. Any change may make the resampling code incompatible
- */
- int maxvoice; /* # of voices to be processed */
- int afterscale;
- int delay_size;
- int control_rate, control_counter;
-/***** Don't change anything above this */
-
- int ram_size;
- int ram_used;
-
- int synthdev;
- int timerdev;
- int sequencer_mode;
-/*
- * Audio parameters
- */
-
- int audiodev;
- int audio_opened;
- int speed;
- int channels;
- int bits;
- int default_max_voices;
- int max_playahead;
- struct file finfo;
- int fragsize;
- int samples_per_fragment;
-
-/*
- * Sample storage
- */
- int nrsamples;
- struct patch_info *samples[MAX_SAMPLE];
- short *wave[MAX_SAMPLE];
-
-/*
- * Programs
- */
- int programs[MAX_PATCH];
-
-/*
- * Timer parameters
- */
- volatile unsigned long usecs;
- volatile unsigned long usecs_per_frag;
- volatile unsigned long next_event_usecs;
-
-/*
- * Engine state
- */
-
- volatile int engine_state;
-#define ES_STOPPED 0
-#define ES_STARTED 1
-
- /* Voice spesific bitmaps */
- volatile int tremolomap;
- volatile int vibratomap;
-
-} softsyn_devc;
-
-void softsynth_resample_loop(short *buf, int loops);
-extern void softsyn_control_loop(void);
-
-#define DELAY_SIZE 4096
-
-#ifdef SOFTSYN_MAIN
- short voice_active[MAX_VOICE] = {0};
- voice_info softoss_voices[MAX_VOICE] = {{0}}; /* Voice spesific info */
- int left_delay[DELAY_SIZE]={0}, right_delay[DELAY_SIZE]={0};
- int delayp=0;
-#else
- extern softsyn_devc *devc;
-
- extern int left_delay[DELAY_SIZE], right_delay[DELAY_SIZE];
- extern int delayp;
- extern short voice_active[MAX_VOICE];
-#endif
+++ /dev/null
-
-/*
- * sound/softoss_rs.c
- *
- * Software based MIDI synthsesizer driver, the actual mixing loop.
- * Keep the loop as simple as possible to make it easier to rewrite this
- * routine in assembly.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include "sound_config.h"
-#include "softoss.h"
-
-void softsynth_resample_loop(short *buf, int loops)
-{
- int iloop, voice;
- volatile voice_info *v;
-
-#ifdef OSS_BIG_ENDIAN
- unsigned char *cbuf = (unsigned char *) buf;
-
-#endif
-
- for (iloop = 0; iloop < loops; iloop++)
- { /* Mix one sample */
- int accum, left = 0, right = 0;
- int ix, position;
-
- for (voice = 0; voice < devc->maxvoice; voice++)
- {
- if (voice_active[voice])
- { /* Compute voice */
- v = &softoss_voices[voice];
-#ifdef SOFTOSS_TEST
- ix = iloop << 3;
- position = v->ptr;
-#else
- ix = (position = v->ptr) >> 9;
-#endif
- /* Interpolation (resolution of 512 steps) */
- {
- int fract = v->ptr & 0x1ff; /* 9 bits */
-
- /* This method works with less arithmetic operations */
- register int v1 = v->wave[ix];
- accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9);
- }
-
- left += (accum * v->leftvol);
- right += (accum * v->rightvol);
-
- /* Update sample pointer */
- position += v->step;
- if (position <= v->endloop)
- v->ptr = position;
- else if (v->mode & WAVE_LOOPING)
- {
- if (v->mode & WAVE_BIDIR_LOOP)
- { v->mode ^= WAVE_LOOP_BACK; /* Turn around */
- v->step *= -1;
- }
- else
- {
- position -= v->looplen;
- v->ptr = position;
- }
- }
- /* else leave the voice looping the current sample */
-
- if (v->mode & WAVE_LOOP_BACK && position < v->startloop)
- {
- if (v->mode & WAVE_BIDIR_LOOP)
- { v->mode ^= WAVE_LOOP_BACK; /* Turn around */
- v->step *= -1;
- }
- else
- {
- position += v->looplen;
- v->ptr = position;
- }
- }
- } /* Compute voice */
- }
-#if 1 /* Delay */
- left += left_delay[delayp];
- right += right_delay[delayp];
-
- left_delay[delayp] = right >> 2;
- right_delay[delayp] = left >> 2;
- delayp = (delayp + 1) % devc->delay_size;
-#endif
-
-#define AFTERSCALE devc->afterscale;
-
- left >>= AFTERSCALE;
- right >>= AFTERSCALE;
-
- if (left > 32767)
- left = 32767;
- if (left < -32768)
- left = -32768;
- if (right > 32767)
- right = 32767;
- if (right < -32768)
- right = -32768;
-
-#ifdef OSS_BIG_ENDIAN
- *cbuf++ = left & 0xff;
- *cbuf++ = (left >> 8) & 0xff;
- *cbuf++ = right & 0xff;
- *cbuf++ = (right >> 8) & 0xff;
-#else
- *buf++ = left;
- *buf++ = right;
-#endif
- if (devc->control_counter++ >= devc->control_rate)
- {
- devc->control_counter = 0;
- softsyn_control_loop();
- }
- } /* Mix one sample */
-}
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/types.h>
#include <linux/kernel.h>
#ifdef CONFIG_SOUND_MSNDPIN
extern int msnd_pinnacle_init(void);
#endif
-#ifdef CONFIG_SOUND_CMPCI
-extern int init_cmpci(void);
-#endif
/*
* Low level list operator. Scan the ordered list, find a hole and
extern int mod_firmware_load(const char *, char **);
EXPORT_SYMBOL(mod_firmware_load);
-#ifdef MODULE
MODULE_DESCRIPTION("Core sound module");
MODULE_AUTHOR("Alan Cox");
-void cleanup_module(void)
+static void __exit cleanup_soundcore(void)
{
/* We have nothing to really do here - we know the lists must be
empty */
devfs_unregister (devfs_handle);
}
-int init_module(void)
-#else
-int soundcore_init(void)
-#endif
+static int __init init_soundcore(void)
{
if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
{
return -EBUSY;
}
devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
- /*
- * Now init non OSS drivers
- */
-#ifdef CONFIG_SOUND_CMPCI
- init_cmpci();
-#endif
-#ifdef CONFIG_SOUND_MSNDCLAS
- msnd_classic_init();
-#endif
-#ifdef CONFIG_SOUND_MSNDPIN
- msnd_pinnacle_init();
-#endif
-#ifdef CONFIG_SOUND_VWSND
- init_vwsnd();
-#endif
+
return 0;
}
+
+module_init(init_soundcore);
+module_exit(cleanup_soundcore);
EXPORT_SYMBOL(conf_printf);
EXPORT_SYMBOL(conf_printf2);
-extern int softoss_dev;
-EXPORT_SYMBOL(softoss_dev);
-
MODULE_DESCRIPTION("OSS Sound subsystem");
MODULE_AUTHOR("Hannu Savolainen, et al.");
#include <linux/config.h>
#include "sound_config.h"
+#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/signal.h>
#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4)
#endif
-static int chrdev_registered = 0;
-
/*
* Table for permanently allocated memory (used when unloading the module)
*/
}
}
-#ifdef MODULE
-static void
-#else
-void
-#endif
-soundcard_init(void)
-{
- /* drag in sound_syms.o */
- {
- extern char sound_syms_symbol;
- sound_syms_symbol = 0;
- }
-
-#ifndef MODULE
- create_special_devices();
- chrdev_registered = 1;
-#endif
-
- soundcard_register_devfs(1); /* register after we know # of devices */
-}
-
-#ifdef MODULE
-
-static void destroy_special_devices(void)
-{
- unregister_sound_special(1);
- unregister_sound_special(8);
-}
static int dmabuf = 0;
static int dmabug = 0;
MODULE_PARM(dmabuf, "i");
MODULE_PARM(dmabug, "i");
-int init_module(void)
+static int __init oss_init(void)
{
int err;
+
+ /* drag in sound_syms.o */
+ {
+ extern char sound_syms_symbol;
+ sound_syms_symbol = 0;
+ }
#ifdef CONFIG_PCI
if(dmabug)
isa_dma_bridge_buggy = dmabug;
#endif
+
err = create_special_devices();
if (err) {
printk(KERN_ERR "sound: driver already loaded/included in kernel\n");
/* Protecting the innocent */
sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
- chrdev_registered = 1;
- soundcard_init();
+ soundcard_register_devfs(1);
if (sound_nblocks >= 1024)
printk(KERN_ERR "Sound warning: Deallocation table was too small.\n");
return 0;
}
-void cleanup_module(void)
+static void __exit oss_cleanup(void)
{
int i;
return;
soundcard_register_devfs (0);
- if (chrdev_registered)
- destroy_special_devices();
+
+ unregister_sound_special(1);
+ unregister_sound_special(8);
sound_stop_timer();
vfree(sound_mem_blocks[i]);
}
-#endif
+
+module_init(oss_init);
+module_exit(oss_cleanup);
+
int sound_alloc_dma(int chn, char *deviceID)
{
static void (*old_mksound)(unsigned int hz, unsigned int ticks);
extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
extern void vidc_update_filler(int bits, int channels);
-extern int softoss_dev;
static void
vidc_mksound(unsigned int hz, unsigned int ticks)
vidc_adev = adev;
vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
-#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
- softoss_dev = adev;
-#endif
return;
irq_failed:
*/
#include <linux/module.h>
+#include <linux/init.h>
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
CO_IRQ(CO_APIC_LI_AUDIO) /* irq */
};
-#ifdef MODULE
-
MODULE_DESCRIPTION("SGI Visual Workstation sound module");
MODULE_AUTHOR("Bob Miller <kbob@sgi.com>");
-extern int init_module(void)
+static int __init init_vwsnd(void)
{
int err;
return 0;
}
-extern void cleanup_module(void)
+static void __exit cleanup_vwsnd(void)
{
DBGX("sound::vwsnd::cleanup_module()\n");
unload_vwsnd(&the_hw_config);
}
-#else
-
-extern void init_vwsnd(void)
-{
- DBGX("sound::vwsnd::init_vwsnd()\n");
- if (probe_vwsnd(&the_hw_config))
- (void) attach_vwsnd(&the_hw_config);
-}
-
-#endif /* !MODULE */
+module_init(init_vwsnd);
+module_exit(cleanup_vwsnd);
/*
* Local variables:
/*
- * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.net>
+ * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
/* These have the same application level protocol */
{ 0x040a, 0x0120 }, // Kodak DC-240
{ 0x040a, 0x0130 }, // Kodak DC-280
+ { 0x040a, 0x0132 }, // Kodak DC-3400
/* These have a different application level protocol which
* is part of the Flashpoint "DigitaOS". That supports some
}
-MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
+MODULE_AUTHOR("David Brownell, <dbrownell@users.sourceforge.net>");
MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
module_init (usb_dc2xx_init);
lock_kernel();
if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
- if (!st)
+ if (!st) {
+ unlock_kernel();
return POLLIN;
+ }
/*
* need to prevent the module from being unloaded, since
* proc_unregister does not call the release method and
{
if (as->urb.transfer_buffer)
kfree(as->urb.transfer_buffer);
+ if (as->urb.setup_packet)
+ kfree(as->urb.setup_packet);
kfree(as);
}
}
#endif
+static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index)
+{
+ int ret;
+
+ switch (recip & USB_RECIP_MASK) {
+ case USB_RECIP_ENDPOINT:
+ if ((ret = findintfep(ps->dev, index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ if ((ret = findintfif(ps->dev, index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+ }
+ return 0;
+}
+
/*
* file operations
*/
if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
return -EFAULT;
- switch (ctrl.requesttype & 0x1f) {
- case USB_RECIP_ENDPOINT:
- if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
- break;
-
- case USB_RECIP_INTERFACE:
- if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
- break;
- }
+ if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index)))
+ return ret;
if (ctrl.length > PAGE_SIZE)
return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
{
struct usbdevfs_urb uurb;
struct usbdevfs_iso_packet_desc *isopkt = NULL;
+ struct usb_endpoint_descriptor *ep_desc;
struct async *as;
+ devrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret;
return -EINVAL;
if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
return -EINVAL;
- if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
- return ret;
- if ((ret = checkintf(ps, ret)))
- return ret;
+ if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+ if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ }
switch(uurb.type) {
+ case USBDEVFS_URB_TYPE_CONTROL:
+ if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) {
+ if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+ return -ENOENT;
+ if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL)
+ return -EINVAL;
+ }
+ /* min 8 byte setup packet, max arbitrary */
+ if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
+ return -EINVAL;
+ if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) {
+ kfree(dr);
+ return -EFAULT;
+ }
+ if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) {
+ kfree(dr);
+ return -EINVAL;
+ }
+ if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) {
+ kfree(dr);
+ return ret;
+ }
+ uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK);
+ uurb.number_of_packets = 0;
+ uurb.buffer_length = le16_to_cpup(&dr->length);
+ uurb.buffer += 8;
+ if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
+ kfree(dr);
+ return -EFAULT;
+ }
+ break;
+
case USBDEVFS_URB_TYPE_BULK:
uurb.number_of_packets = 0;
if (uurb.buffer_length > 16384)
if (!(as = alloc_async(uurb.number_of_packets))) {
if (isopkt)
kfree(isopkt);
+ if (dr)
+ kfree(dr);
return -ENOMEM;
}
if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
if (isopkt)
kfree(isopkt);
+ if (dr)
+ kfree(dr);
free_async(as);
return -ENOMEM;
}
as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
as->urb.transfer_flags = uurb.flags;
as->urb.transfer_buffer_length = uurb.buffer_length;
+ as->urb.setup_packet = (unsigned char*)dr;
as->urb.start_frame = uurb.start_frame;
as->urb.number_of_packets = uurb.number_of_packets;
as->urb.context = as;
#include <linux/bitops.h>
#include <linux/malloc.h>
#include <linux/interrupt.h> /* for in_interrupt() */
-
-
-#if defined(CONFIG_KMOD) && defined(CONFIG_HOTPLUG)
#include <linux/kmod.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-
-/* waitpid() call glue uses this */
-static int errno;
-#endif
#ifdef CONFIG_USB_DEBUG
return NULL;
}
+struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
+{
+ int i, j, k;
+
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+ for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
+ for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++)
+ if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress)
+ return &dev->actconfig->interface[i].altsetting[j].endpoint[k];
+
+ return NULL;
+}
+
/*
* usb_calc_bus_time:
*
* (normally /sbin/hotplug) when USB devices get added or removed.
*/
-static int exec_helper (void *arg)
-{
- void **params = (void **) arg;
- char *path = (char *) params [0];
- char **argv = (char **) params [1];
- char **envp = (char **) params [2];
- return exec_usermodehelper (path, argv, envp);
-}
-
-int call_usermodehelper (char *path, char **argv, char **envp)
-{
- void *params [3] = { path, argv, envp };
- int pid, pid2, retval;
- mm_segment_t fs;
-
- if ((pid = kernel_thread (exec_helper, (void *) params, 0)) < 0) {
- err ("failed fork of %s, errno = %d", argv [0], -pid);
- return -1;
- }
-
- /* set signal mask? */
- fs = get_fs ();
- set_fs (KERNEL_DS); /* retval is in kernel space. */
- pid2 = waitpid (pid, &retval, __WCLONE); /* "errno" gets assigned */
- set_fs (fs);
- /* restore signal mask? */
-
- if (pid2 != pid) {
- err ("waitpid(%d) failed, returned %d\n", pid, pid2);
- return -1;
- }
- return retval;
-}
-
static int to_bcd (char *buf, __u16 *bcdValue)
{
int retval = 0;
value = call_usermodehelper (argv [0], argv, envp);
kfree (buf);
kfree (envp);
- dbg ("kusbd policy returned 0x%x", value);
+ if (value != 0)
+ dbg ("kusbd policy returned 0x%x", value);
}
#else
info("USB disconnect on device %d", dev->devnum);
- call_policy ("remove", dev);
-
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
usb_disconnect(child);
}
+ /* Let policy agent unload modules etc */
+ call_policy ("remove", dev);
+
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
* then these symbols need to be exported for the modules to use.
*/
EXPORT_SYMBOL(usb_ifnum_to_if);
+EXPORT_SYMBOL(usb_epnum_to_ep_desc);
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
- dep_mbool ' Provide NFSv3 client support (EXPERIMENTAL)' CONFIG_NFS_V3 $CONFIG_NFS_FS
+ dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
int shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
int count = 0;
+
+ /*
+ * Nasty deadlock avoidance.
+ *
+ * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->
+ * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->
+ * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super->
+ * DEADLOCK.
+ *
+ * We should make sure we don't hold the superblock lock over
+ * block allocations, but for now:
+ */
+ if (!(gfp_mask & __GFP_IO))
+ return 0;
+
if (priority)
count = dentry_stat.nr_unused / priority;
prune_dcache(count);
int shrink_icache_memory(int priority, int gfp_mask)
{
int count = 0;
-
+
+ /*
+ * Nasty deadlock avoidance..
+ *
+ * We may hold various FS locks, and we don't
+ * want to recurse into the FS that called us
+ * in clear_inode() and friends..
+ */
+ if (!(gfp_mask & __GFP_IO))
+ return 0;
+
if (priority)
count = inodes_stat.nr_unused / priority;
prune_icache(count);
if ((fl->fl_owner == blocked_owner)
&& (fl->fl_pid == blocked_pid)) {
fl = fl->fl_next;
- blocked_owner = fl->fl_owner;
- blocked_pid = fl->fl_pid;
+ if (fl) {
+ blocked_owner = fl->fl_owner;
+ blocked_pid = fl->fl_pid;
+ }
goto next_task;
}
}
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
+ clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
#endif
{ "udp", ~NFS_MOUNT_TCP, 0 },
{ "tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP },
+ { "broken_suid",~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID },
{ NULL, 0, 0 }
};
sprintf(current->comm, "nfsd");
current->fs->umask = 0;
+ current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+
nfsdstats.th_cnt++;
/* Let svc_process check client's authentication. */
rqstp->rq_auth = 1;
atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry;
if (access & MAY_WRITE) {
- filp->f_flags = O_WRONLY;
+ filp->f_flags = O_WRONLY|O_LARGEFILE;
filp->f_mode = FMODE_WRITE;
DQUOT_INIT(inode);
} else {
- filp->f_flags = O_RDONLY;
+ filp->f_flags = O_RDONLY|O_LARGEFILE;
filp->f_mode = FMODE_READ;
}
sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
return buf;
}
+ if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
+ int ctlr = hd->major - COMPAQ_CISS_MAJOR;
+ int disk = minor >> hd->minor_shift;
+ int part = minor & (( 1 << hd->minor_shift) - 1);
+ if (part == 0)
+ sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ else
+ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ return buf;
+ }
if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
int ctlr = hd->major - DAC960_MAJOR;
int disk = minor >> hd->minor_shift;
printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
else
printk(" %s", disk_name(hd, minor, buf));
+ if (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)
+ printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+ else
+ printk(" %s", disk_name(hd, minor, buf));
#endif
}
{ NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
+ { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
{ 0, NULL, NULL }
};
#ifndef _ALPHA_ATOMIC_H
#define _ALPHA_ATOMIC_H
-#include <linux/config.h>
-
/*
* Atomic operations that C can't guarantee us. Useful for
* resource counting etc...
#define wmb() \
__asm__ __volatile__("wmb": : :"memory")
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#define rmb() mb()
#define wmb() __asm__ __volatile__ ("": : :"memory")
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
#ifdef CONFIG_HOTPLUG
extern char hotplug_path [];
+extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
#endif
#else
static inline int request_module(const char * name) { return -ENOSYS; }
/* filemap.c */
extern void remove_inode_page(struct page *);
extern unsigned long page_unuse(struct page *);
-extern int shrink_mmap(int, int);
extern void truncate_inode_pages(struct address_space *, loff_t);
/* generic vm_area_ops exported for stackable file systems */
#define GFP_BUFFER (__GFP_HIGH | __GFP_WAIT)
#define GFP_ATOMIC (__GFP_HIGH)
-#define GFP_USER (__GFP_WAIT | __GFP_IO)
-#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM)
+#define GFP_USER ( __GFP_WAIT | __GFP_IO)
+#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHMEM)
#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
-#define GFP_KSWAPD (__GFP_IO)
+#define GFP_KSWAPD ( __GFP_IO)
/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
platforms, used as appropriate on others */
#define NFS_MOUNT_VER3 0x0080 /* 3 */
#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
#define NFS_MOUNT_NONLM 0x0200 /* 3 */
+#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
#define NFS_MOUNT_FLAGMASK 0xFFFF
#endif
cl_chatty : 1,/* be verbose */
cl_autobind : 1,/* use getport() */
cl_binding : 1,/* doing a getport() */
+ cl_droppriv : 1,/* enable NFS suid hack */
cl_oneshot : 1,/* dispose after use */
cl_dead : 1;/* abandoned */
unsigned int cl_flags; /* misc client flags */
/*
* USB recipients
*/
+#define USB_RECIP_MASK 0x1f
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
};
extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
/* some statistics */
static ulong swap_attempts;
static ulong swap_successes;
-static ulong used_segs;
void __init shm_init (void)
{
buf->f_blocks = shm_ctlall;
buf->f_bavail = buf->f_bfree = shm_ctlall - shm_tot;
buf->f_files = shm_ctlmni;
- buf->f_ffree = shm_ctlmni - used_segs;
+ shm_lockall();
+ buf->f_ffree = shm_ctlmni - shm_ids.in_use + 1;
+ shm_unlockall();
buf->f_namelen = SHM_NAME_LEN;
return 0;
}
if (doacc) {
shm_lockall();
shm_tot += pages;
- used_segs++;
shm_unlockall();
}
return ret;
shm_rss -= rss;
shm_swp -= swp;
shm_tot -= pages;
- used_segs--;
shm_unlockall();
}
}
memset(&shm_info,0,sizeof(shm_info));
shm_lockall();
- shm_info.used_ids = shm_ids.in_use;
+ shm_info.used_ids = shm_ids.in_use - 1; /* correct the /dev/zero hack */
shm_info.shm_rss = shm_rss;
shm_info.shm_tot = shm_tot;
shm_info.shm_swp = shm_swp;
int counter;
struct page * page_map;
+ /*
+ * Push this inside:
+ */
+ if (!(gfp_mask & __GFP_IO))
+ return 0;
+
zshm_swap(prio, gfp_mask);
counter = shm_rss >> prio;
if (!counter)
*/
char hotplug_path[256] = "/sbin/hotplug";
+
+static int exec_helper (void *arg)
+{
+ void **params = (void **) arg;
+ char *path = (char *) params [0];
+ char **argv = (char **) params [1];
+ char **envp = (char **) params [2];
+ return exec_usermodehelper (path, argv, envp);
+}
+
+
+int call_usermodehelper (char *path, char **argv, char **envp)
+{
+ void *params [3] = { path, argv, envp };
+ int pid, pid2, retval;
+ mm_segment_t fs;
+
+ if ( ! current->fs->root ) {
+ printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n",
+ path);
+ return -EPERM;
+ }
+ if ((pid = kernel_thread (exec_helper, (void *) params, 0)) < 0) {
+ printk(KERN_ERR "failed fork %s, errno = %d", argv [0], -pid);
+ return -1;
+ }
+
+ fs = get_fs ();
+ set_fs (KERNEL_DS);
+ pid2 = waitpid (pid, &retval, __WCLONE);
+ set_fs (fs);
+
+ if (pid2 != pid) {
+ printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
+ return -1;
+ }
+ return retval;
+}
+
#endif
EXPORT_SYMBOL(exec_usermodehelper);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(hotplug_path);
+EXPORT_SYMBOL(call_usermodehelper);
#endif
#endif
EXPORT_SYMBOL(page_hash_table);
EXPORT_SYMBOL(file_lock_list);
EXPORT_SYMBOL(file_lock_sem);
+EXPORT_SYMBOL(locks_init_lock);
+EXPORT_SYMBOL(locks_copy_lock);
EXPORT_SYMBOL(posix_lock_file);
EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
/* Ok, it wasn't in the queue. We must have
been out of queue space. So zero out the
info. */
+ sigdelset(&list->signal, sig);
info->si_signo = sig;
info->si_errno = 0;
info->si_code = 0;
* Application no longer needs these pages. If the pages are dirty,
* it's OK to just throw them away. The app will be more careful about
* data it wants to keep. Be sure to free swap resources too. The
- * zap_page_range call sets things up for shrink_mmap to actually free
+ * zap_page_range call sets things up for refill_inactive to actually free
* these pages later if no one else has touched them in the meantime,
* although we could add these pages to a global reuse list for
- * shrink_mmap to pick up before reclaiming other pages.
+ * refill_inactive to pick up before reclaiming other pages.
*
* NB: This interface discards data rather than pushes it out to swap,
* as some implementations do. This has performance implications for
* processes, etc).
*/
if (gfp_mask & __GFP_WAIT) {
+ /*
+ * Give other processes a chance to run:
+ */
+ if (current->need_resched) {
+ __set_current_state(TASK_RUNNING);
+ schedule();
+ }
try_to_free_pages(gfp_mask);
memory_pressure++;
goto try_again;
return 0;
/*
* Though the "found" page was in the swap cache an instant
- * earlier, it might have been removed by shrink_mmap etc.
+ * earlier, it might have been removed by refill_inactive etc.
* Re search ... Since find_lock_page grabs a reference on
* the page, it can not be reused for anything else, namely
* it can not be associated with another swaphandle, so it
* our scan.
*
* Basically, this just makes it possible for us to do
- * some real work in the future in "shrink_mmap()".
+ * some real work in the future in "refill_inactive()".
*/
if (!pte_dirty(pte)) {
flush_cache_page(vma, address);
* NOTE NOTE NOTE! This should just set a
* dirty bit in 'page', and just drop the
* pte. All the hard work would be done by
- * shrink_mmap().
+ * refill_inactive().
*
* That would get rid of a lot of problems.
*/
do {
made_progress = 0;
- if (current->need_resched && (gfp_mask & __GFP_IO)) {
+ if (current->need_resched) {
__set_current_state(TASK_RUNNING);
schedule();
}
while (refill_inactive_scan(priority, 1) ||
swap_out(priority, gfp_mask, idle_time)) {
made_progress = 1;
- if (!--count)
+ if (--count <= 0)
goto done;
}
- /* Try to get rid of some shared memory pages.. */
- if (gfp_mask & __GFP_IO) {
- /*
- * don't be too light against the d/i cache since
- * shrink_mmap() almost never fail when there's
- * really plenty of memory free.
- */
- count -= shrink_dcache_memory(priority, gfp_mask);
- count -= shrink_icache_memory(priority, gfp_mask);
- /*
- * Not currently working, see fixme in shrink_?cache_memory
- * In the inner funtions there is a comment:
- * "To help debugging, a zero exit status indicates
- * all slabs were released." (-arca?)
- * lets handle it in a primitive but working way...
- * if (count <= 0)
- * goto done;
- */
+ /*
+ * don't be too light against the d/i cache since
+ * refill_inactive() almost never fail when there's
+ * really plenty of memory free.
+ */
+ count -= shrink_dcache_memory(priority, gfp_mask);
+ count -= shrink_icache_memory(priority, gfp_mask);
+ /*
+ * Not currently working, see fixme in shrink_?cache_memory
+ * In the inner funtions there is a comment:
+ * "To help debugging, a zero exit status indicates
+ * all slabs were released." (-arca?)
+ * lets handle it in a primitive but working way...
+ * if (count <= 0)
+ * goto done;
+ */
- while (shm_swap(priority, gfp_mask)) {
- made_progress = 1;
- if (!--count)
- goto done;
- }
+ /* Try to get rid of some shared memory pages.. */
+ while (shm_swap(priority, gfp_mask)) {
+ made_progress = 1;
+ if (--count <= 0)
+ goto done;
}
/*
*/
while (swap_out(priority, gfp_mask, 0)) {
made_progress = 1;
- if (!--count)
+ if (--count <= 0)
goto done;
}
priority--;
} while (priority >= 0);
- /* Always end on a shrink_mmap.., may sleep... */
+ /* Always end on a refill_inactive.., may sleep... */
while (refill_inactive_scan(0, 1)) {
- if (!--count)
+ if (--count <= 0)
goto done;
}
{
int ret = 0;
- /*
- * First, reclaim unused slab cache memory.
- */
- kmem_cache_reap(gfp_mask);
-
/*
* If we're low on free pages, move pages from the
* inactive_dirty list to the inactive_clean list.
* the inode and dentry cache whenever we do this.
*/
if (free_shortage() || inactive_shortage()) {
- if (gfp_mask & __GFP_IO) {
- ret += shrink_dcache_memory(6, gfp_mask);
- ret += shrink_icache_memory(6, gfp_mask);
- }
-
+ ret += shrink_dcache_memory(6, gfp_mask);
+ ret += shrink_icache_memory(6, gfp_mask);
ret += refill_inactive(gfp_mask, user);
} else {
+ /*
+ * Reclaim unused slab cache memory.
+ */
+ kmem_cache_reap(gfp_mask);
ret = 1;
}
{
int ret = 1;
- if (gfp_mask & __GFP_WAIT) {
+ if (gfp_mask & __GFP_WAIT)
ret = do_try_to_free_pages(gfp_mask, 1);
- }
return ret;
}
memcpy(p, clnt->cl_nodename, n);
p += (n + 3) >> 2;
- if (ruid) {
+ /* Note: we don't use real uid if it involves raising priviledge */
+ if (ruid && cred->uc_uid != 0 && cred->uc_gid != 0) {
*p++ = htonl((u32) cred->uc_uid);
*p++ = htonl((u32) cred->uc_gid);
} else {
* The following is an NFS-specific hack to cater for setuid
* processes whose uid is mapped to nobody on the server.
*/
- if (task->tk_client->cl_prog == NFS_PROGRAM &&
+ if (task->tk_client->cl_droppriv &&
(ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
* The state machine looks for (approximately) these Perl regular expressions:
*
* m|\/\*.*?\*\/|
+ * m|\/\/.*|
* m|'.*?'|
* m|".*?"|
* m|#\s*include\s*"(.*?)"|
CASE('C', cee);
goto start;
+/* // */
+slash_slash:
+ GETNEXT
+ CASE('\n', start);
+ NOTCASE('\\', slash_slash);
+ GETNEXT
+ goto slash_slash;
+
/* / */
slash:
GETNEXT
+ CASE('/', slash_slash);
NOTCASE('*', __start);
slash_star_dot_star:
GETNEXT