From e7a392d5158afc2ccdefd294e9513efb203a90d9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:34:06 -0500 Subject: [PATCH] Import 2.3.99pre6-5 --- CREDITS | 11 + Documentation/Configure.help | 30 + Documentation/filesystems/devfs/ChangeLog | 16 + Documentation/filesystems/devfs/modules.conf | 2 +- MAINTAINERS | 15 +- Makefile | 1 - arch/i386/kernel/acpi.c | 2 + arch/i386/kernel/i386_ksyms.c | 2 +- arch/ia64/kernel/mca.c | 1 + arch/sparc/kernel/sun4d_smp.c | 1 - drivers/char/agp/agpgart_be.c | 30 +- drivers/char/joystick/joystick.c | 1 + drivers/char/msp3400.c | 12 +- drivers/char/pty.c | 10 +- drivers/char/tty_io.c | 2 + drivers/i2o/i2o_config.c | 18 +- drivers/i2o/i2o_core.c | 311 +-- drivers/ide/ide.c | 3 +- drivers/net/3c59x.c | 1 - drivers/net/acenic.c | 2 +- drivers/net/de4x5.c | 2 - drivers/net/eepro100.c | 3 +- drivers/net/ne2k-pci.c | 6 +- drivers/net/pcmcia/3c575_cb.c | 1 - drivers/net/pcmcia/xircom_tulip_cb.c | 1 - drivers/net/ppp_generic.c | 9 +- drivers/net/rrunner.c | 5 +- drivers/net/rtl8129.c | 1 - drivers/net/setup.c | 4 + drivers/net/starfire.c | 1 - drivers/net/via-rhine.c | 1 - drivers/net/wan/Config.in | 6 + drivers/net/wan/Makefile | 15 +- drivers/net/wan/cosa.c | 3 +- drivers/net/wan/lmc/Makefile | 39 + drivers/net/wan/lmc/lmc.h | 32 + drivers/net/wan/lmc/lmc_debug.c | 87 + drivers/net/wan/lmc/lmc_debug.h | 52 + drivers/net/wan/lmc/lmc_ioctl.h | 257 ++ drivers/net/wan/lmc/lmc_main.c | 2487 ++++++++++++++++++ drivers/net/wan/lmc/lmc_media.c | 1258 +++++++++ drivers/net/wan/lmc/lmc_media.h | 64 + drivers/net/wan/lmc/lmc_prot.h | 14 + drivers/net/wan/lmc/lmc_proto.c | 270 ++ drivers/net/wan/lmc/lmc_proto.h | 15 + drivers/net/wan/lmc/lmc_proto_raw.h | 4 + drivers/net/wan/lmc/lmc_var.h | 590 +++++ drivers/net/wan/lmc/lmc_ver.h | 123 + drivers/net/wan/sdla_chdlc.c | 5 +- drivers/net/wan/sdla_fr.c | 9 +- drivers/net/wan/sdla_ppp.c | 5 +- drivers/net/wan/sdlamain.c | 6 +- drivers/net/wan/syncppp.c | 10 +- drivers/net/yellowfin.c | 1 - drivers/pci/pci.ids | 1218 ++++++++- drivers/scsi/NCR53C9x.c | 2 +- drivers/scsi/scsi.h | 2 +- drivers/scsi/tmscsim.c | 4 +- drivers/scsi/tmscsim.h | 4 +- drivers/sound/Config.in | 1 + drivers/sound/Makefile | 12 +- drivers/sound/emu10k1/8010.h | 662 +++++ drivers/sound/emu10k1/Makefile | 29 + drivers/sound/emu10k1/audio.c | 1441 ++++++++++ drivers/sound/emu10k1/audio.h | 46 + drivers/sound/emu10k1/cardmi.c | 813 ++++++ drivers/sound/emu10k1/cardmi.h | 113 + drivers/sound/emu10k1/cardmo.c | 229 ++ drivers/sound/emu10k1/cardmo.h | 61 + drivers/sound/emu10k1/cardwi.c | 472 ++++ drivers/sound/emu10k1/cardwi.h | 92 + drivers/sound/emu10k1/cardwo.c | 755 ++++++ drivers/sound/emu10k1/cardwo.h | 118 + drivers/sound/emu10k1/efxmgr.c | 34 + drivers/sound/emu10k1/efxmgr.h | 43 + drivers/sound/emu10k1/emu_wrapper.h | 11 + drivers/sound/emu10k1/emuadxmg.c | 101 + drivers/sound/emu10k1/hwaccess.c | 430 +++ drivers/sound/emu10k1/hwaccess.h | 204 ++ drivers/sound/emu10k1/icardmid.h | 163 ++ drivers/sound/emu10k1/icardwav.h | 52 + drivers/sound/emu10k1/irqmgr.c | 127 + drivers/sound/emu10k1/irqmgr.h | 59 + drivers/sound/emu10k1/main.c | 825 ++++++ drivers/sound/emu10k1/midi.c | 446 ++++ drivers/sound/emu10k1/midi.h | 55 + drivers/sound/emu10k1/mixer.c | 824 ++++++ drivers/sound/emu10k1/osutils.c | 91 + drivers/sound/emu10k1/recmgr.c | 139 + drivers/sound/emu10k1/recmgr.h | 62 + drivers/sound/emu10k1/timer.c | 176 ++ drivers/sound/emu10k1/timer.h | 47 + drivers/sound/emu10k1/voicemgr.c | 349 +++ drivers/sound/emu10k1/voicemgr.h | 150 ++ fs/buffer.c | 5 +- fs/devfs/base.c | 102 +- fs/proc/array.c | 10 +- fs/proc/base.c | 5 +- fs/proc/proc_misc.c | 32 +- include/asm-ia64/keyboard.h | 2 - include/asm-ia64/pgtable.h | 2 + kernel/exit.c | 2 +- kernel/fork.c | 5 +- kernel/panic.c | 2 +- kernel/sched.c | 17 +- kernel/sysctl.c | 8 +- kernel/timer.c | 7 +- net/core/neighbour.c | 8 +- net/ipv4/route.c | 2 +- net/socket.c | 2 +- net/sunrpc/Makefile | 6 +- net/sunrpc/sched.c | 2 +- net/sunrpc/sunrpc_syms.c | 2 + net/sunrpc/sysctl.c | 2 +- 114 files changed, 16135 insertions(+), 407 deletions(-) create mode 100644 drivers/net/wan/lmc/Makefile create mode 100644 drivers/net/wan/lmc/lmc.h create mode 100644 drivers/net/wan/lmc/lmc_debug.c create mode 100644 drivers/net/wan/lmc/lmc_debug.h create mode 100644 drivers/net/wan/lmc/lmc_ioctl.h create mode 100644 drivers/net/wan/lmc/lmc_main.c create mode 100644 drivers/net/wan/lmc/lmc_media.c create mode 100644 drivers/net/wan/lmc/lmc_media.h create mode 100644 drivers/net/wan/lmc/lmc_prot.h create mode 100644 drivers/net/wan/lmc/lmc_proto.c create mode 100644 drivers/net/wan/lmc/lmc_proto.h create mode 100644 drivers/net/wan/lmc/lmc_proto_raw.h create mode 100644 drivers/net/wan/lmc/lmc_var.h create mode 100644 drivers/net/wan/lmc/lmc_ver.h create mode 100644 drivers/sound/emu10k1/8010.h create mode 100644 drivers/sound/emu10k1/Makefile create mode 100644 drivers/sound/emu10k1/audio.c create mode 100644 drivers/sound/emu10k1/audio.h create mode 100644 drivers/sound/emu10k1/cardmi.c create mode 100644 drivers/sound/emu10k1/cardmi.h create mode 100644 drivers/sound/emu10k1/cardmo.c create mode 100644 drivers/sound/emu10k1/cardmo.h create mode 100644 drivers/sound/emu10k1/cardwi.c create mode 100644 drivers/sound/emu10k1/cardwi.h create mode 100644 drivers/sound/emu10k1/cardwo.c create mode 100644 drivers/sound/emu10k1/cardwo.h create mode 100644 drivers/sound/emu10k1/efxmgr.c create mode 100644 drivers/sound/emu10k1/efxmgr.h create mode 100644 drivers/sound/emu10k1/emu_wrapper.h create mode 100644 drivers/sound/emu10k1/emuadxmg.c create mode 100644 drivers/sound/emu10k1/hwaccess.c create mode 100644 drivers/sound/emu10k1/hwaccess.h create mode 100644 drivers/sound/emu10k1/icardmid.h create mode 100644 drivers/sound/emu10k1/icardwav.h create mode 100644 drivers/sound/emu10k1/irqmgr.c create mode 100644 drivers/sound/emu10k1/irqmgr.h create mode 100644 drivers/sound/emu10k1/main.c create mode 100644 drivers/sound/emu10k1/midi.c create mode 100644 drivers/sound/emu10k1/midi.h create mode 100644 drivers/sound/emu10k1/mixer.c create mode 100644 drivers/sound/emu10k1/osutils.c create mode 100644 drivers/sound/emu10k1/recmgr.c create mode 100644 drivers/sound/emu10k1/recmgr.h create mode 100644 drivers/sound/emu10k1/timer.c create mode 100644 drivers/sound/emu10k1/timer.h create mode 100644 drivers/sound/emu10k1/voicemgr.c create mode 100644 drivers/sound/emu10k1/voicemgr.h diff --git a/CREDITS b/CREDITS index a0f11dcd9a3a..e06d6f08e6c5 100644 --- a/CREDITS +++ b/CREDITS @@ -2266,6 +2266,10 @@ D: Read only HPFS filesystem S: Richardson, Texas S: USA +N: Christopher Smith +E: x@xman.org +D: Tulip net driver hacker + N: Miquel van Smoorenburg E: miquels@cistron.nl D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff. @@ -2298,6 +2302,13 @@ S: Warburgring 67 S: 66424 Homburg S: Germany +N: Andrew Stanley-Jones +E: asj@lanmedia.com +D: LanMedia Corp. Device WAN card device driver +S: #102, 686 W. Maude Ave +S: Sunyvale, CA 94086 +S: USA + N: Henrik Storner E: storner@image.dk W: http://www.image.dk/~storner/ diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 6865e54cb657..0a8df66cfcf1 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -7598,6 +7598,31 @@ CONFIG_COSA The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Lan Media sync serial boards support +CONFIG_LANMEDIA + This is a driver for the following Lan Media family of serial boards. + + LMC 1000 board allows you to connect synchronous serial devices (for + example base-band modems, or any other device with the X.21, V.24, + V.35 or V.36 interface) to your Linux box. + + LMC 1200 with on board DSU board allows you to connect your Linux + box dirrectly to a T1 or E1 circuit. + + LMC 5200 board provides a HSSI interface capable of runnig up to + 52 mbits per second. + + LMC 5245 board connects directly to a T3 circuit saving the + additional external hardware. + + To change setting such as syncPPP vs cisco HDLC or clock source you + will need lmcctl. It it available at ftp.lanmedia.com. + + This code is also available as a module called lmc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + Fibre Channel driver support CONFIG_NET_FC Fibre Channel is a high speed serial protocol mainly used to connect @@ -13415,6 +13440,11 @@ CONFIG_AEDSP16_MPU401 driver as a module you have to specify the MPU I/O base address with the parameter 'mpu_base=0xNNN'. +Creative EMU10K1 based PCI sound cards +CONFIG_SOUND_EMU10K1 + Say Y or M if you have a PCI sound card using the EMU10K1 + chipset, such as the Creative SBLive! or SB PCI512. + Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 Say Y or M if you have a PCI sound card utilizing the Ensoniq diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog index 2b8a0d2f0c93..96a35860285c 100644 --- a/Documentation/filesystems/devfs/ChangeLog +++ b/Documentation/filesystems/devfs/ChangeLog @@ -1480,3 +1480,19 @@ Work sponsored by SGI - Only set auto-ownership for /dev/pty/s* +=============================================================================== +Changes for patch v162 + +Work sponsored by SGI + +- Set inode->i_size to correct size for symlinks + Thanks to Jeremy Fitzhardinge + +- Only give lookup() method to directories to comply with new VFS + assumptions + +- Remove unnecessary tests in symlink methods + +- Don't kill existing block ops in + +- Restore auto-ownership for /dev/pty/m* diff --git a/Documentation/filesystems/devfs/modules.conf b/Documentation/filesystems/devfs/modules.conf index 273568c3fcf5..43bae68ecdf3 100644 --- a/Documentation/filesystems/devfs/modules.conf +++ b/Documentation/filesystems/devfs/modules.conf @@ -38,7 +38,7 @@ alias /dev/sr* /dev/sr # SCSI tapes probeall /dev/st scsi-hosts st -alias /dev/st* /dev/sr +alias /dev/st* /dev/st alias /dev/nst* /dev/st # SCSI generic diff --git a/MAINTAINERS b/MAINTAINERS index 43e375cf781f..1f66e0b21089 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -50,7 +50,7 @@ trivial patch so apply some common sense. Maintainers List (try to look for most precise areas first) Note: For the hard of thinking, this list is meant to remain in alphabetical -order. If you could add yourselves to it in alphabetical order that would +order. If you could add yourselves to it in alphabetical order that would be so much easier [Ed] P: Person @@ -340,6 +340,13 @@ P: Andrey V. Savochkin M: saw@saw.sw.com.sg S: Maintained +EMU10K1 SOUND DRIVER +P: Rui Sousa +M: rsousa@grad.physics.sunysb.edu +L: emu10k1-devel@opensource.creative.com +W: http://opensource.creative.com/ +S: Maintained + ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com @@ -592,6 +599,12 @@ L: nfs-devel@linux.kernel.org (Linux NFS) W: http://csua.berkeley.edu/~gam3/knfsd S: Maintained +LANMEDIA WAN CARD DRIVER +P: Andrew Stanley-Jones +M: asj@lanmedia.com +W: http://www.lanmedia.com/ +S: Supported + LAPB module P: Henner Eisen M: eis@baty.hanse.de diff --git a/Makefile b/Makefile index 0fcc720279e4..88d247cfb1fc 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,6 @@ NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump -MAKE = make MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms MODFLAGS = -DMODULE diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index aa09400fc7a2..39dc60a2df6c 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -583,6 +583,8 @@ static int __init acpi_find_tables(void) dt = acpi_map_table(facp->dsdt); if (acpi_init_table(&acpi_dsdt, dt, 1)) acpi_unmap_table(dt); + + break; } else { acpi_unmap_table(dt); diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index ce406fb38dc1..584caa9c16cd 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -27,7 +27,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); extern spinlock_t rtc_lock; -#if defined(CONFIG_APM) +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); #endif diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index e6daa5808a3b..150feac03773 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 5cd8f7235983..ac9caa27f7bf 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -8,7 +8,6 @@ #include -#include #include #include #include diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index 447716420fee..274c9a86b44c 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -81,7 +81,7 @@ static inline void flush_cache(void) #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP static atomic_t cpus_waiting; static void ipi_handler(void *null) @@ -102,9 +102,9 @@ static void smp_flush_cache(void) barrier(); } #define global_cache_flush smp_flush_cache -#else /* __SMP__ */ +#else /* CONFIG_SMP */ #define global_cache_flush flush_cache -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ int agp_backend_acquire(void) { @@ -1764,6 +1764,30 @@ static struct { #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS + { PCI_DEVICE_ID_SI_630, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "630", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_540, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "540", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_620, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "620", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_530, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "530", + sis_generic_setup }, { PCI_DEVICE_ID_SI_630, PCI_VENDOR_ID_SI, SIS_GENERIC, diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c index d0dc70f55e13..5eaabe0f32c2 100644 --- a/drivers/char/joystick/joystick.c +++ b/drivers/char/joystick/joystick.c @@ -517,6 +517,7 @@ static int js_open(struct inode *inode, struct file *file) MOD_INC_USE_COUNT; if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) { + jd->close(jd); MOD_DEC_USE_COUNT; return -ENOMEM; } diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 8de178bb6a72..bb6db3b6a0d2 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -34,6 +34,7 @@ * */ +#include #include #include #include @@ -46,7 +47,7 @@ #include #include -#ifdef __SMP__ +#ifdef CONFIG_SMP #include #include #endif @@ -59,7 +60,6 @@ #define WAIT_QUEUE wait_queue_head_t /* sound mixer stuff */ -#include #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) # define REGISTER_MIXER 1 #endif @@ -678,7 +678,7 @@ static int msp3400c_thread(void *data) struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; -#ifdef __SMP__ +#ifdef CONFIG_SMP lock_kernel(); #endif @@ -691,7 +691,7 @@ static int msp3400c_thread(void *data) msp->thread = current; -#ifdef __SMP__ +#ifdef CONFIG_SMP unlock_kernel(); #endif @@ -933,7 +933,7 @@ static int msp3410d_thread(void *data) struct msp3400c *msp = client->data; int mode,val,i,std; -#ifdef __SMP__ +#ifdef CONFIG_SMP lock_kernel(); #endif @@ -946,7 +946,7 @@ static int msp3410d_thread(void *data) msp->thread = current; -#ifdef __SMP__ +#ifdef CONFIG_SMP unlock_kernel(); #endif diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 4f1c9c703115..f5626c8df7c1 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -138,7 +138,7 @@ static int pty_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct tty_struct *to = tty->link; - int c=0, n; + int c=0, n, room; char *temp_buffer; if (!to || tty->stopped) @@ -149,7 +149,9 @@ static int pty_write(struct tty_struct * tty, int from_user, temp_buffer = &tty->flip.char_buf[0]; while (count > 0) { /* check space so we don't copy needlessly */ - n = MIN(count, to->ldisc.receive_room(to)); + n = to->ldisc.receive_room(to); + if (n > count) + n = count; if (!n) break; n = MIN(n, PTY_BUF_SIZE); @@ -161,7 +163,9 @@ static int pty_write(struct tty_struct * tty, int from_user, } /* check again in case the buffer filled up */ - n = MIN(n, to->ldisc.receive_room(to)); + room = to->ldisc.receive_room(to); + if (n > room) + n = room; if (!n) break; buf += n; c += n; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f3cbce7f976d..071982e2b439 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2017,6 +2017,8 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: + if (driver->major == PTY_MASTER_MAJOR) + flags |= DEVFS_FL_AUTO_OWNER; break; } if ( (minor < driver->minor_start) || diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c index c2b72b21c2df..0202afb67a83 100644 --- a/drivers/i2o/i2o_config.c +++ b/drivers/i2o/i2o_config.c @@ -85,11 +85,21 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc { u32 *msg = (u32 *)m; - if (msg[0] & (1<<13)) + if (msg[0] & MSG_FAIL) { + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); - - if (msg[4] >> 24) // RegStatus != SUCCESS - i2o_report_status(KERN_INFO,"i2o_config",msg); + + /* Release the preserved msg frame by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + } + + if (msg[4] >> 24) // ReqStatus != SUCCESS + i2o_report_status(KERN_INFO,"i2o_config", msg); if(m->function == I2O_CMD_UTIL_EVT_REGISTER) { diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index 6d1092843dea..05ed6d851a61 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -51,9 +51,9 @@ // #define DRIVERDEBUG #ifdef DRIVERDEBUG -#define dprintk(x) printk x +#define dprintk(s, args...) printk(s, ## args) #else -#define dprintk(x) +#define dprintk(s, args...) #endif /* OSM table */ @@ -158,7 +158,7 @@ static struct i2o_handler i2o_core_handler = NULL, "I2O core layer", 0, - 0 + I2O_CLASS_EXECUTIVE }; @@ -220,15 +220,30 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, if (msg[0] & (1<<13)) // Fail bit is set { - printk(KERN_ERR "%s: Failed to process the msg:\n",c->name); - printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =% d\n", - (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + +// i2o_report_failure(KERN_INFO, c, "i2o_core", msg); + printk(KERN_ERR "%s: Failed to process the msg:\n", c->name); + printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =% d\n", + (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n" "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", msg[4] >> 24, (msg[4] >> 16) & 0xFF, (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", msg[5] >> 16, msg[5] & 0xFFF); + + /* If the failed request needs special treatment, + * it should be done here. */ + + /* Release the preserved msg by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + + /* If reply to i2o_post_wait failed, return causes a timeout */ return; } @@ -358,7 +373,7 @@ int __i2o_delete_device(struct i2o_device *d) { if(d->owner->dev_del_notify) { - dprintk((KERN_INFO "Device has owner, notifying\n")); + dprintk(KERN_INFO "Device has owner, notifying\n"); d->owner->dev_del_notify(d->controller, d); if(d->owner) { @@ -456,7 +471,7 @@ int i2o_delete_controller(struct i2o_controller *c) char name[16]; int stat; - dprintk((KERN_INFO "Deleting controller iop%d\n", c->unit)); + dprintk(KERN_INFO "Deleting controller iop%d\n", c->unit); /* * Clear event registration as this can cause weird behavior @@ -467,8 +482,8 @@ int i2o_delete_controller(struct i2o_controller *c) spin_lock(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { - dprintk((KERN_INFO "I2O: %d users for controller iop%d\n", users, - c->unit)); + dprintk(KERN_INFO "I2O: %d users for controller iop%d\n", users, + c->name); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -532,7 +547,7 @@ int i2o_delete_controller(struct i2o_controller *c) i2o_controllers[c->unit]=NULL; memcpy(name, c->name, strlen(c->name)+1); kfree(c); - dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name)); + dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); i2o_num_controllers--; return 0; @@ -701,10 +716,9 @@ int i2o_event_ack(struct i2o_controller *c, u32 *msg) * Core event handler. Runs as a separate thread and is woken * up whenever there is an Executive class event. */ -static int i2o_core_evt(void *foo) +static int i2o_core_evt(void *reply_data) { - struct reply_info reply_data; - struct reply_info *reply = &reply_data; + struct reply_info *reply = (struct reply_info *) reply_data; u32 *msg = reply->msg; struct i2o_controller *c = NULL; int flags; @@ -722,7 +736,7 @@ static int i2o_core_evt(void *foo) down_interruptible(&evt_sem); if(signal_pending(current)) { - dprintk((KERN_INFO "I2O event thread dead\n")); + dprintk(KERN_INFO "I2O event thread dead\n"); evt_running = 0; return 0; } @@ -738,7 +752,7 @@ static int i2o_core_evt(void *foo) spin_unlock_irqrestore(&i2o_evt_lock, flags); c = reply->iop; - dprintk((KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4])); + dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); /* * We do not attempt to delete/quiesce/etc. the controller if @@ -841,7 +855,7 @@ static int i2o_core_evt(void *foo) break; default: - printk(KERN_WARNING "%s: Unknown event...check config\n", c->name); + printk(KERN_WARNING "%s: Unknown event (0x%08x)...check config\n", c->name, msg[4]); break; } } @@ -883,7 +897,7 @@ static int i2o_dyn_lct(void *foo) down_interruptible(&c->lct_sem); if(signal_pending(current)) { - dprintk((KERN_ERR "%s: LCT thread dead\n", c->name)); + dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); c->lct_running = 0; return 0; } @@ -892,8 +906,8 @@ static int i2o_dyn_lct(void *foo) entries -= 3; entries /= 9; - dprintk((KERN_INFO "I2O: Dynamic LCT Update\n")); - dprintk((KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries)); + dprintk(KERN_INFO "I2O: Dynamic LCT Update\n"); + dprintk(KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries); if(!entries) { @@ -924,7 +938,7 @@ static int i2o_dyn_lct(void *foo) } if(!found) { - dprintk((KERN_INFO "Deleted device!\n")); + dprintk(KERN_INFO "Deleted device!\n"); i2o_delete_device(d); } d = d1; @@ -1091,8 +1105,8 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why) { if((jiffies-time)>=5*HZ) { - dprintk((KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", - c->name, why)); + dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", + c->name, why); return 0xFFFFFFFF; } schedule(); @@ -1115,8 +1129,8 @@ u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout) { if(jiffies-time >= timeout*HZ ) { - dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n", - c->name, why)); + dprintk(KERN_ERR "%s: timeout waiting for %s reply.\n", + c->name, why); return 0xFFFFFFFF; } schedule(); @@ -1311,7 +1325,7 @@ static int i2o_parse_lct(struct i2o_controller *c) d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL); if(d==NULL) { - printk("i2o_core: Out of memory for I2O device data.\n"); + printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n"); return -ENOMEM; } @@ -1360,7 +1374,7 @@ int i2o_quiesce_controller(struct i2o_controller *c) printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Quiesced.\n", c->name)); + dprintk(KERN_INFO "%s: Quiesced.\n", c->name); i2o_status_get(c); // Reread the Status Block @@ -1391,7 +1405,7 @@ int i2o_enable_controller(struct i2o_controller *c) printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Enabled.\n", c->name)); + dprintk(KERN_INFO "%s: Enabled.\n", c->name); i2o_status_get(c); @@ -1423,7 +1437,7 @@ int i2o_clear_controller(struct i2o_controller *c) printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Cleared.\n",c->name)); + dprintk(KERN_INFO "%s: Cleared.\n",c->name); i2o_status_get(c); @@ -1505,7 +1519,7 @@ static int i2o_reset_controller(struct i2o_controller *c) * time, we assume the IOP could not reboot properly. */ - dprintk((KERN_INFO "Reset succeeded...waiting for reboot\n")); + dprintk(KERN_INFO "Reset succeeded...waiting for reboot\n"); time = jiffies; m = I2O_POST_READ32(c); @@ -1524,7 +1538,7 @@ static int i2o_reset_controller(struct i2o_controller *c) i2o_flush_reply(c,m); - dprintk((KERN_INFO "%s: Reset completed.\n", c->name)); + dprintk(KERN_INFO "%s: Reset completed.\n", c->name); } /* If IopReset was rejected or didn't perform reset, try IopClear */ @@ -1726,7 +1740,7 @@ static int i2o_systab_send(struct i2o_controller *iop) printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", iop->name, ret); else - dprintk((KERN_INFO "%s: SysTab set.\n", iop->name)); + dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); return ret; @@ -1744,8 +1758,8 @@ static void __init i2o_sys_init() /* In INIT state, Activate IOPs */ for (iop = i2o_controller_chain; iop; iop = niop) { - dprintk((KERN_INFO "Calling i2o_activate_controller for %s\n", - iop->name)); + dprintk(KERN_INFO "Calling i2o_activate_controller for %s\n", + iop->name); niop = iop->next; i2o_activate_controller(iop); } @@ -1760,7 +1774,7 @@ rebuild_sys_tab: * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ - dprintk((KERN_INFO "calling i2o_build_sys_table\n")); + dprintk(KERN_INFO "calling i2o_build_sys_table\n"); if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; @@ -1769,7 +1783,7 @@ rebuild_sys_tab: /* If IOP don't get online, we need to rebuild the System table */ for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; - dprintk((KERN_INFO "Calling i2o_online_controller for %s\n", iop->name)); + dprintk(KERN_INFO "Calling i2o_online_controller for %s\n", iop->name); if (i2o_online_controller(iop) < 0) goto rebuild_sys_tab; } @@ -1816,7 +1830,7 @@ static void i2o_sys_shutdown(void) */ int i2o_activate_controller(struct i2o_controller *iop) { - /* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */ + /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ /* In READY state, Get status */ if (i2o_status_get(iop) < 0) { @@ -1841,8 +1855,8 @@ int i2o_activate_controller(struct i2o_controller *iop) iop->status_block->iop_state == ADAPTER_STATE_FAILED) { u32 m[MSG_FRAME_SIZE]; - dprintk((KERN_INFO "%s: already running...trying to reset\n", - iop->name)); + dprintk(KERN_INFO "%s: already running...trying to reset\n", + iop->name); i2o_init_outbound_q(iop); I2O_REPLY_WRITE32(iop,virt_to_phys(m)); @@ -1887,7 +1901,7 @@ int i2o_init_outbound_q(struct i2o_controller *c) u32 *msg; u32 time; - dprintk((KERN_INFO "%s: Initializing Outbound Queue\n", c->name)); + dprintk(KERN_INFO "%s: Initializing Outbound Queue\n", c->name); m=i2o_wait_message(c, "OutboundInit"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -2050,7 +2064,7 @@ int i2o_online_controller(struct i2o_controller *iop) /* In READY state */ - dprintk((KERN_INFO "Attempting to enable iop%d\n", iop->unit)); + dprintk(KERN_INFO "Attempting to enable iop%d\n", iop->unit); if (i2o_enable_controller(iop) < 0) { i2o_delete_controller(iop); return -1; @@ -2058,7 +2072,7 @@ int i2o_online_controller(struct i2o_controller *iop) /* In OPERATIONAL state */ - dprintk((KERN_INFO "Attempting to get/parse lct iop%d\n", iop->unit)); + dprintk(KERN_INFO "Attempting to get/parse lct iop%d\n", iop->unit); if (i2o_lct_get(iop) < 0){ i2o_delete_controller(iop); return -1; @@ -2178,8 +2192,8 @@ int i2o_post_this(struct i2o_controller *c, u32 *data, int len) if(m==0xFFFFFFFF) { - printk(KERN_ERR "i2o/iop%d: Timeout waiting for message frame!\n", - c->unit); + printk(KERN_ERR "%s: Timeout waiting for message frame!\n", + c->name); return -ETIMEDOUT; } msg = (u32 *)(c->mem_offset + m); @@ -2212,11 +2226,11 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) spin_lock_irqsave(&post_wait_lock, flags); wait_data->next = post_wait_queue; post_wait_queue = wait_data; - wait_data->id = (++post_wait_id) & 0x7fff; + wait_data->id = (++post_wait_id) & 0x7fff; spin_unlock_irqrestore(&post_wait_lock, flags); wait_data->wq = &wq_i2o_post; - wait_data->status = -EAGAIN; + wait_data->status = -ETIMEDOUT; msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); @@ -2226,7 +2240,7 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) } #ifdef DRIVERDEBUG - if(status == -EAGAIN) + if(status == -ETIMEDOUT) printk(KERN_INFO "POST WAIT TIMEOUT\n"); #endif @@ -2288,7 +2302,7 @@ static void i2o_post_wait_complete(u32 context, int status) } spin_unlock(&post_wait_lock); - printk(KERN_DEBUG "i2o_post_wait reply after timeout!"); + printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); } /* @@ -2369,9 +2383,7 @@ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ } - return (len << 2); - - // return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ + return (len << 2); /* bytes used by result list */ } /* @@ -2394,7 +2406,7 @@ int i2o_query_scalar(struct i2o_controller *iop, int tid, return size; memcpy(buf, resblk+8, buflen); /* cut off header */ - return buflen; + return buflen < size ? buflen : size; } /* @@ -2438,22 +2450,17 @@ int i2o_set_scalar(struct i2o_controller *iop, int tid, } /* - * if oper == I2O_PARAMS_TABLE_GET: - * Get all table group fields from all rows or - * get specific table group fields from all rows. - * - * if fieldcount == -1 we query all fields from all rows - * ibuf is NULL and ibuflen is 0 - * else we query specific fields from all rows + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields + * ibuf and ibuflen are unused (use NULL, 0) + * else return specific fields * ibuf contains fieldindexes * - * if oper == I2O_PARAMS_LIST_GET: - * Get all table group fields from specified rows or - * get specific table group fields from specified rows. - * - * if fieldcount == -1 we query all fields from specified rows + * if oper == I2O_PARAMS_LIST_GET, gte form specific rows + * if fieldcount == -1 return all fields * ibuf contains rowcount, keyvalues - * else we query specific fields from specified rows + * else return specific fields + * fieldcount is # of fieldindexes * ibuf contains fieldindexes, rowcount, keyvalues * * You could also use directly function i2o_issue_params(). @@ -2687,49 +2694,49 @@ static void i2o_report_util_cmd(u8 cmd) { switch (cmd) { case I2O_CMD_UTIL_NOP: - printk(KERN_INFO "UTIL_NOP, "); + printk("UTIL_NOP, "); break; case I2O_CMD_UTIL_ABORT: - printk(KERN_INFO "UTIL_ABORT, "); + printk("UTIL_ABORT, "); break; case I2O_CMD_UTIL_CLAIM: - printk(KERN_INFO "UTIL_CLAIM, "); + printk("UTIL_CLAIM, "); break; case I2O_CMD_UTIL_RELEASE: - printk(KERN_INFO "UTIL_CLAIM_RELEASE, "); + printk("UTIL_CLAIM_RELEASE, "); break; case I2O_CMD_UTIL_CONFIG_DIALOG: - printk(KERN_INFO "UTIL_CONFIG_DIALOG, "); + printk("UTIL_CONFIG_DIALOG, "); break; case I2O_CMD_UTIL_DEVICE_RESERVE: - printk(KERN_INFO "UTIL_DEVICE_RESERVE, "); + printk("UTIL_DEVICE_RESERVE, "); break; case I2O_CMD_UTIL_DEVICE_RELEASE: - printk(KERN_INFO "UTIL_DEVICE_RELEASE, "); + printk("UTIL_DEVICE_RELEASE, "); break; case I2O_CMD_UTIL_EVT_ACK: - printk(KERN_INFO "UTIL_EVENT_ACKNOWLEDGE, "); + printk("UTIL_EVENT_ACKNOWLEDGE, "); break; case I2O_CMD_UTIL_EVT_REGISTER: - printk(KERN_INFO "UTIL_EVENT_REGISTER, "); + printk("UTIL_EVENT_REGISTER, "); break; case I2O_CMD_UTIL_LOCK: - printk(KERN_INFO "UTIL_LOCK, "); + printk("UTIL_LOCK, "); break; case I2O_CMD_UTIL_LOCK_RELEASE: - printk(KERN_INFO "UTIL_LOCK_RELEASE, "); + printk("UTIL_LOCK_RELEASE, "); break; case I2O_CMD_UTIL_PARAMS_GET: - printk(KERN_INFO "UTIL_PARAMS_GET, "); + printk("UTIL_PARAMS_GET, "); break; case I2O_CMD_UTIL_PARAMS_SET: - printk(KERN_INFO "UTIL_PARAMS_SET, "); + printk("UTIL_PARAMS_SET, "); break; case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: - printk(KERN_INFO "UTIL_REPLY_FAULT_NOTIFY, "); + printk("UTIL_REPLY_FAULT_NOTIFY, "); break; default: - printk(KERN_INFO "%0#2x, ",cmd); + printk("%0#2x, ",cmd); } return; @@ -2742,106 +2749,106 @@ static void i2o_report_exec_cmd(u8 cmd) { switch (cmd) { case I2O_CMD_ADAPTER_ASSIGN: - printk(KERN_INFO "EXEC_ADAPTER_ASSIGN, "); + printk("EXEC_ADAPTER_ASSIGN, "); break; case I2O_CMD_ADAPTER_READ: - printk(KERN_INFO "EXEC_ADAPTER_READ, "); + printk("EXEC_ADAPTER_READ, "); break; case I2O_CMD_ADAPTER_RELEASE: - printk(KERN_INFO "EXEC_ADAPTER_RELEASE, "); + printk("EXEC_ADAPTER_RELEASE, "); break; case I2O_CMD_BIOS_INFO_SET: - printk(KERN_INFO "EXEC_BIOS_INFO_SET, "); + printk("EXEC_BIOS_INFO_SET, "); break; case I2O_CMD_BOOT_DEVICE_SET: - printk(KERN_INFO "EXEC_BOOT_DEVICE_SET, "); + printk("EXEC_BOOT_DEVICE_SET, "); break; case I2O_CMD_CONFIG_VALIDATE: - printk(KERN_INFO "EXEC_CONFIG_VALIDATE, "); + printk("EXEC_CONFIG_VALIDATE, "); break; case I2O_CMD_CONN_SETUP: - printk(KERN_INFO "EXEC_CONN_SETUP, "); + printk("EXEC_CONN_SETUP, "); break; case I2O_CMD_DDM_DESTROY: - printk(KERN_INFO "EXEC_DDM_DESTROY, "); + printk("EXEC_DDM_DESTROY, "); break; case I2O_CMD_DDM_ENABLE: - printk(KERN_INFO "EXEC_DDM_ENABLE, "); + printk("EXEC_DDM_ENABLE, "); break; case I2O_CMD_DDM_QUIESCE: - printk(KERN_INFO "EXEC_DDM_QUIESCE, "); + printk("EXEC_DDM_QUIESCE, "); break; case I2O_CMD_DDM_RESET: - printk(KERN_INFO "EXEC_DDM_RESET, "); + printk("EXEC_DDM_RESET, "); break; case I2O_CMD_DDM_SUSPEND: - printk(KERN_INFO "EXEC_DDM_SUSPEND, "); + printk("EXEC_DDM_SUSPEND, "); break; case I2O_CMD_DEVICE_ASSIGN: - printk(KERN_INFO "EXEC_DEVICE_ASSIGN, "); + printk("EXEC_DEVICE_ASSIGN, "); break; case I2O_CMD_DEVICE_RELEASE: - printk(KERN_INFO "EXEC_DEVICE_RELEASE, "); + printk("EXEC_DEVICE_RELEASE, "); break; case I2O_CMD_HRT_GET: - printk(KERN_INFO "EXEC_HRT_GET, "); + printk("EXEC_HRT_GET, "); break; case I2O_CMD_ADAPTER_CLEAR: - printk(KERN_INFO "EXEC_IOP_CLEAR, "); + printk("EXEC_IOP_CLEAR, "); break; case I2O_CMD_ADAPTER_CONNECT: - printk(KERN_INFO "EXEC_IOP_CONNECT, "); + printk("EXEC_IOP_CONNECT, "); break; case I2O_CMD_ADAPTER_RESET: - printk(KERN_INFO "EXEC_IOP_RESET, "); + printk("EXEC_IOP_RESET, "); break; case I2O_CMD_LCT_NOTIFY: - printk(KERN_INFO "EXEC_LCT_NOTIFY, "); + printk("EXEC_LCT_NOTIFY, "); break; case I2O_CMD_OUTBOUND_INIT: - printk(KERN_INFO "EXEC_OUTBOUND_INIT, "); + printk("EXEC_OUTBOUND_INIT, "); break; case I2O_CMD_PATH_ENABLE: - printk(KERN_INFO "EXEC_PATH_ENABLE, "); + printk("EXEC_PATH_ENABLE, "); break; case I2O_CMD_PATH_QUIESCE: - printk(KERN_INFO "EXEC_PATH_QUIESCE, "); + printk("EXEC_PATH_QUIESCE, "); break; case I2O_CMD_PATH_RESET: - printk(KERN_INFO "EXEC_PATH_RESET, "); + printk("EXEC_PATH_RESET, "); break; case I2O_CMD_STATIC_MF_CREATE: - printk(KERN_INFO "EXEC_STATIC_MF_CREATE, "); + printk("EXEC_STATIC_MF_CREATE, "); break; case I2O_CMD_STATIC_MF_RELEASE: - printk(KERN_INFO "EXEC_STATIC_MF_RELEASE, "); + printk("EXEC_STATIC_MF_RELEASE, "); break; case I2O_CMD_STATUS_GET: - printk(KERN_INFO "EXEC_STATUS_GET, "); + printk("EXEC_STATUS_GET, "); break; case I2O_CMD_SW_DOWNLOAD: - printk(KERN_INFO "EXEC_SW_DOWNLOAD, "); + printk("EXEC_SW_DOWNLOAD, "); break; case I2O_CMD_SW_UPLOAD: - printk(KERN_INFO "EXEC_SW_UPLOAD, "); + printk("EXEC_SW_UPLOAD, "); break; case I2O_CMD_SW_REMOVE: - printk(KERN_INFO "EXEC_SW_REMOVE, "); + printk("EXEC_SW_REMOVE, "); break; case I2O_CMD_SYS_ENABLE: - printk(KERN_INFO "EXEC_SYS_ENABLE, "); + printk("EXEC_SYS_ENABLE, "); break; case I2O_CMD_SYS_MODIFY: - printk(KERN_INFO "EXEC_SYS_MODIFY, "); + printk("EXEC_SYS_MODIFY, "); break; case I2O_CMD_SYS_QUIESCE: - printk(KERN_INFO "EXEC_SYS_QUIESCE, "); + printk("EXEC_SYS_QUIESCE, "); break; case I2O_CMD_SYS_TAB_SET: - printk(KERN_INFO "EXEC_SYS_TAB_SET, "); + printk("EXEC_SYS_TAB_SET, "); break; default: - printk(KERN_INFO "%02x, ",cmd); + printk("%02x, ",cmd); } return; @@ -2854,22 +2861,22 @@ static void i2o_report_lan_cmd(u8 cmd) { switch (cmd) { case LAN_PACKET_SEND: - printk(KERN_INFO "LAN_PACKET_SEND, "); + printk("LAN_PACKET_SEND, "); break; case LAN_SDU_SEND: - printk(KERN_INFO "LAN_SDU_SEND, "); + printk("LAN_SDU_SEND, "); break; case LAN_RECEIVE_POST: - printk(KERN_INFO "LAN_RECEIVE_POST, "); + printk("LAN_RECEIVE_POST, "); break; case LAN_RESET: - printk(KERN_INFO "LAN_RESET, "); + printk("LAN_RESET, "); break; case LAN_SUSPEND: - printk(KERN_INFO "LAN_SUSPEND, "); + printk("LAN_SUSPEND, "); break; default: - printk(KERN_INFO "%02x, ",cmd); + printk("%02x, ",cmd); } return; @@ -2877,51 +2884,43 @@ static void i2o_report_lan_cmd(u8 cmd) /* * Used for error reporting/debugging purposes - * - * This will have to be rewritten someday. The code currently - * assumes that a certain range of commands is reserved for - * given class. This is not completely true. Exec and Util - * message have their numbers reserved, but the rest are - * available _for each device class to use as it wishes_ - * - * For example 0x37 is BsaCacheFlush for a block class device and - * LanSuspend for a LAN class device. - * - * The ideal way to do this would be to look at the TID and then - * find the LCT entry to determine what the class of the device is. - * */ void i2o_report_status(const char *severity, const char *module, u32 *msg) { u8 cmd = (msg[1]>>24)&0xFF; u8 req_status = (msg[4]>>24)&0xFF; u16 detailed_status = msg[4]&0xFFFF; + struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)]; printk("%s%s: ", severity, module); - if (cmd < 0x1F) { // Utility Class - i2o_report_util_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_common_dsc(detailed_status); - return; - } + switch (h->class) { + case I2O_CLASS_EXECUTIVE: + if (cmd < 0x1F) { // Utility cmd + i2o_report_util_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); + } + if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive cmd + i2o_report_exec_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); + } + break; - if (cmd >= 0x30 && cmd <= 0x3F) { // LAN class - i2o_report_lan_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_lan_dsc(detailed_status); - return; - } - - if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive class - i2o_report_exec_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_common_dsc(detailed_status); - return; + case I2O_CLASS_LAN: + i2o_report_lan_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_lan_dsc(detailed_status); + break; +/* + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + break; +*/ + default: + printk(KERN_INFO "%02x, %02x / %04x.\n", + cmd, req_status, detailed_status); } - - printk(KERN_INFO "%02x, %02x / %04x.\n", cmd, req_status, detailed_status); - return; } /* Used to dump a message to syslog during debugging */ @@ -2977,6 +2976,7 @@ static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void } } + printk(KERN_INFO "I2O system down.\n"); return NOTIFY_DONE; } @@ -3050,7 +3050,8 @@ int init_module(void) i2o_remove_handler(&i2o_core_handler); return 0; } - else(KERN_INFO "event thread created as pid %d\n", evt_pid); + else + printk(KERN_INFO "event thread created as pid %d\n", evt_pid); if(i2o_num_controllers) i2o_sys_init(); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 1abf214cc24f..712ec7502252 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1775,7 +1775,8 @@ int ide_revalidate_disk (kdev_t i_rdev) drive->part[p].nr_sects = 0; }; - DRIVER(drive)->revalidate(drive); + if (DRIVER(drive)->revalidate) + DRIVER(drive)->revalidate(drive); drive->busy = 0; wake_up(&drive->wqueue); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ebaeb68bab7c..3c8a0ecd425b 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2072,7 +2072,6 @@ module_exit(vortex_cleanup_module); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" * c-indent-level: 4 * c-basic-offset: 4 diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 9969bcbde342..8fa454af9002 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2949,6 +2949,6 @@ static int __init read_eeprom_byte(struct net_device *dev, /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" * End: */ diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 81e0dbdaea46..4d738e579a60 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -5923,9 +5923,7 @@ insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_devi /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * - * Delete -D__SMP__ below if you didn't define this in your kernel * Delete -DMODVERSIONS below if you didn't define this in your kernel * * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c" diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 128128bcb637..b8e5acd66770 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1285,7 +1285,7 @@ static void speedo_tx_timeout(struct net_device *dev) del_timer(&sp->timer); end_bh_atomic(); #else /* LINUX_VERSION_CODE */ -#ifdef __SMP__ +#ifdef CONFIG_SMP del_timer_sync(&sp->timer); #else /* SMP */ del_timer(&sp->timer); @@ -2258,7 +2258,6 @@ module_exit(eepro100_cleanup_module); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 743812346b95..2ecbdee2d3d5 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -188,9 +188,10 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, return -ENODEV; } - if (pci_enable_device (pdev)) { + i = pci_enable_device (pdev); + if (i) { printk (KERN_ERR "ne2k-pci: cannot enable device\n"); - return -EIO; + return i; } if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) { @@ -292,6 +293,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, /* Set up the rest of the parameters. */ dev->irq = irq; dev->base_addr = ioaddr; + pdev->driver_data = dev; /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c index bff7bc9ed2a1..02d14a12e685 100644 --- a/drivers/net/pcmcia/3c575_cb.c +++ b/drivers/net/pcmcia/3c575_cb.c @@ -2150,7 +2150,6 @@ module_exit(vortex_cleanup); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c" * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index 380943f09e9a..bf71f29fd374 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -3143,7 +3143,6 @@ module_exit(tulip_exit) /* * Local variables: - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index a1d2b6e7e487..4a7454d3fdaa 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000412== + * ==FILEVERSION 20000417== */ #include @@ -2376,6 +2376,7 @@ ppp_disconnect_channel(struct channel *pch) { struct ppp *ppp; int err = -EINVAL; + int dead; write_lock_bh(&pch->upl); ppp = pch->ppp; @@ -2385,12 +2386,12 @@ ppp_disconnect_channel(struct channel *pch) ppp_lock(ppp); list_del(&pch->clist); --ppp->n_channels; - if (ppp->dev == 0 && ppp->n_channels == 0) + dead = ppp->dev == 0 && ppp->n_channels == 0; + ppp_unlock(ppp); + if (dead) /* Last disconnect from a ppp unit that is already dead: free it. */ kfree(ppp); - else - ppp_unlock(ppp); err = 0; } write_unlock_bh(&pch->upl); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 8ad1a2a16c81..dbd12bdb989a 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -25,6 +25,7 @@ #define RX_DMA_SKBUFF 1 #define PKT_COPY_THRESHOLD 512 +#include #include #include #include @@ -166,7 +167,7 @@ int __init rr_hippi_probe (struct net_device *dev) rrpriv = (struct rr_private *)dev->priv; memset(rrpriv, 0, sizeof(*rrpriv)); -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_init(&rrpriv->lock); #endif sprintf(rrpriv->name, "RoadRunner serial HIPPI"); @@ -1650,6 +1651,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" + * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff --git a/drivers/net/rtl8129.c b/drivers/net/rtl8129.c index b60a626086c4..725f16a4a51a 100644 --- a/drivers/net/rtl8129.c +++ b/drivers/net/rtl8129.c @@ -1460,7 +1460,6 @@ module_exit(rtl8129_cleanup); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/setup.c b/drivers/net/setup.c index 12e51e458051..7e01e3f83b65 100644 --- a/drivers/net/setup.c +++ b/drivers/net/setup.c @@ -28,6 +28,7 @@ extern int lapbeth_init(void); extern int sdla_setup(void); extern int sdla_c_setup(void); extern int comx_init(void); +extern int lmc_setup(void); extern int abyss_probe(void); extern int madgemc_probe(void); @@ -81,6 +82,9 @@ struct net_probe pci_probes[] __initdata = { * SLHC if present needs attaching so other people see it * even if not opened. */ +#if defined(CONFIG_LANMEDIA) + {lmc_setup, 0}, +#endif #ifdef CONFIG_INET #if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5036b01af783..43b093a121d5 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1375,7 +1375,6 @@ module_exit(starfire_cleanup); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c" * c-indent-level: 4 * c-basic-offset: 4 diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 83618f2fc597..ae451a43e17e 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1319,7 +1319,6 @@ module_exit(via_rhine_cleanup); /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index 4ffe0730fccf..d53e7f964660 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -21,6 +21,12 @@ if [ "$CONFIG_WAN" = "y" ]; then # tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX + + # + # Lan Media's board. Currently 1000, 1200, 5200, 5245 + # + tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA + if [ "$CONFIG_COMX" != "n" ]; then dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index dbb12c2bfda4..3904c76a67fe 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -12,7 +12,7 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) lmc L_TARGET := wan.a L_OBJS := @@ -119,6 +119,19 @@ else endif endif +ifeq ($(CONFIG_LANMEDIA),y) + SUB_DIRS += lmc + MOD_IN_SUB_DIRS += lmc + L_OBJS += lmc/lmc.o + CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_LANMEDIA),m) + CONFIG_SYNCPPP_MODULE = y + MOD_IN_SUB_DIRS += lmc + endif +endif + + # If anything built-in uses syncppp, then build it into the kernel also. # If not, but a module uses it, build as a module. diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 544fcb8dd42b..8e0c5d37dc18 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -79,6 +79,7 @@ /* ---------- Headers, macros, data structures ---------- */ +#include #include #include #include @@ -374,7 +375,7 @@ static int __init cosa_init(void) int i; printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak \n"); -#ifdef __SMP__ +#ifdef CONFIG_SMP printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif if (cosa_major > 0) { diff --git a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile new file mode 100644 index 000000000000..1fe61a348437 --- /dev/null +++ b/drivers/net/wan/lmc/Makefile @@ -0,0 +1,39 @@ +# File: drivers/lmc/Makefile +# +# Makefile for the Lan Media 21140 based WAN cards +# Specifically the 1000,1200,5200,5245 +# + +ifeq ($(CONFIG_LANMEDIA),y) + O_TARGET := lmc.o + O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o +else + ifeq ($(CONFIG_LANMEDIA),m) + MOD_LIST_NAME := NET_MODULES + M_OBJS := lmc.o + O_TARGET := lmc.o + O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o + endif +endif + +# +# Base debugging and event log (doubles lmc.o size) +# +# DBGDEF = \ +# -DDEBUG + +# +# Like above except every packet gets echoed to KERN_DEBUG +# in hex +# +# DBDEF = \ +# -DDEBUG \ +# -DLMC_PACKET_LOG + +EXTRA_CFLAGS += -I. $(DBGDEF) + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + diff --git a/drivers/net/wan/lmc/lmc.h b/drivers/net/wan/lmc/lmc.h new file mode 100644 index 000000000000..91b9e8f00ee1 --- /dev/null +++ b/drivers/net/wan/lmc/lmc.h @@ -0,0 +1,32 @@ +#ifndef _LMC_H_ +#define _LMC_H_ + +#include "lmc_var.h" + +/* + * prototypes for everyone + */ +int lmc_probe(struct net_device * dev); +unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned + devaddr, unsigned regno); +void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr, + unsigned regno, unsigned data); +void lmc_led_on(lmc_softc_t * const, u_int32_t); +void lmc_led_off(lmc_softc_t * const, u_int32_t); +unsigned lmc_mii_readreg(lmc_softc_t * const, unsigned, unsigned); +void lmc_mii_writereg(lmc_softc_t * const, unsigned, unsigned, unsigned); +void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits); +void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits); + +int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +extern lmc_media_t lmc_ds3_media; +extern lmc_media_t lmc_ssi_media; +extern lmc_media_t lmc_t1_media; +extern lmc_media_t lmc_hssi_media; + +#ifdef _DBG_EVENTLOG +static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 ); +#endif + +#endif \ No newline at end of file diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c new file mode 100644 index 000000000000..3db65b0c13a4 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_debug.c @@ -0,0 +1,87 @@ + +#include +#include +#include +#include +#include +#include "lmc_ver.h" +#include "lmc_debug.h" + +/* + * Prints out len, max to 80 octets using printk, 20 per line + */ +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) +{ +#ifdef DEBUG +#ifdef LMC_PACKET_LOG + int iNewLine = 1; + char str[80], *pstr; + + sprintf(str, KERN_DEBUG "lmc: %s: ", type); + pstr = str+strlen(str); + + if(iLen > 240){ + printk(KERN_DEBUG "lmc: Printing 240 chars... out of: %d\n", iLen); + iLen = 240; + } + else{ + printk(KERN_DEBUG "lmc: Printing %d chars\n", iLen); + } + + while(iLen > 0) + { + sprintf(pstr, "%02x ", *ucData); + pstr+=3; + ucData++; + if( !(iNewLine % 20)) + { + sprintf(pstr, "\n"); + printk(str); + sprintf(str, KERN_DEBUG "lmc: %s: ", type); + pstr=str+strlen(str); + } + iNewLine++; + iLen--; + } + sprintf(pstr, "\n"); + printk(str); +#endif +#endif +} + +#ifdef DEBUG +u_int32_t lmcEventLogIndex = 0; +u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; +#endif + +void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) +{ +#ifdef DEBUG + lmcEventLogBuf[lmcEventLogIndex++] = EventNum; + lmcEventLogBuf[lmcEventLogIndex++] = arg2; + lmcEventLogBuf[lmcEventLogIndex++] = arg3; + lmcEventLogBuf[lmcEventLogIndex++] = jiffies; + + lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1; +#endif +} + +inline void lmc_trace(struct net_device *dev, char *msg){ +#ifdef LMC_TRACE + unsigned long j = jiffies + 3; /* Wait for 50 ms */ + + if(in_interrupt()){ + printk("%s: * %s\n", dev->name, msg); +// while(jiffies < j+10) +// ; + } + else { + printk("%s: %s\n", dev->name, msg); + while(jiffies < j) + schedule(); + } +#endif +} + + +/* --------------------------- end if_lmc_linux.c ------------------------ */ diff --git a/drivers/net/wan/lmc/lmc_debug.h b/drivers/net/wan/lmc/lmc_debug.h new file mode 100644 index 000000000000..f42d59bff302 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_debug.h @@ -0,0 +1,52 @@ +#ifndef _LMC_DEBUG_H_ +#define _LMC_DEBUG_H_ + +#ifdef DEBUG +#ifdef LMC_PACKET_LOG +#define LMC_CONSOLE_LOG(x,y,z) lmcConsoleLog((x), (y), (z)) +#else +#define LMC_CONSOLE_LOG(x,y,z) +#endif +#else +#define LMC_CONSOLE_LOG(x,y,z) +#endif + + + +/* Debug --- Event log definitions --- */ +/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */ +#define LMC_EVENTLOGSIZE 1024 /* number of events in eventlog */ +#define LMC_EVENTLOGARGS 4 /* number of args for each event */ + +/* event indicators */ +#define LMC_EVENT_XMT 1 +#define LMC_EVENT_XMTEND 2 +#define LMC_EVENT_XMTINT 3 +#define LMC_EVENT_RCVINT 4 +#define LMC_EVENT_RCVEND 5 +#define LMC_EVENT_INT 6 +#define LMC_EVENT_XMTINTTMO 7 +#define LMC_EVENT_XMTPRCTMO 8 +#define LMC_EVENT_INTEND 9 +#define LMC_EVENT_RESET1 10 +#define LMC_EVENT_RESET2 11 +#define LMC_EVENT_FORCEDRESET 12 +#define LMC_EVENT_WATCHDOG 13 +#define LMC_EVENT_BADPKTSURGE 14 +#define LMC_EVENT_TBUSY0 15 +#define LMC_EVENT_TBUSY1 16 + + +#ifdef DEBUG +extern u_int32_t lmcEventLogIndex; +extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; +#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z)) +#else +#define LMC_EVENT_LOG(x,y,z) +#endif /* end ifdef _DBG_EVENTLOG */ + +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen); +void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3); +inline void lmc_trace(struct net_device *dev, char *msg); + +#endif diff --git a/drivers/net/wan/lmc/lmc_ioctl.h b/drivers/net/wan/lmc/lmc_ioctl.h new file mode 100644 index 000000000000..31eaaa67381c --- /dev/null +++ b/drivers/net/wan/lmc/lmc_ioctl.h @@ -0,0 +1,257 @@ +#ifndef _LMC_IOCTL_H_ +#define _LMC_IOCTL_H_ +/* $Id: lmc_ioctl.h,v 1.15 2000/04/06 12:16:43 asj Exp $ */ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */ +#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */ +#define LMCIOCGETLMCSTATS SIOCDEVPRIVATE+5 +#define LMCIOCCLEARLMCSTATS SIOCDEVPRIVATE+6 +#define LMCIOCDUMPEVENTLOG SIOCDEVPRIVATE+7 +#define LMCIOCGETXINFO SIOCDEVPRIVATE+8 +#define LMCIOCSETCIRCUIT SIOCDEVPRIVATE+9 +#define LMCIOCUNUSEDATM SIOCDEVPRIVATE+10 +#define LMCIOCRESET SIOCDEVPRIVATE+11 +#define LMCIOCT1CONTROL SIOCDEVPRIVATE+12 +#define LMCIOCIFTYPE SIOCDEVPRIVATE+13 +#define LMCIOCXILINX SIOCDEVPRIVATE+14 + +#define LMC_CARDTYPE_UNKNOWN -1 +#define LMC_CARDTYPE_HSSI 1 /* probed card is a HSSI card */ +#define LMC_CARDTYPE_DS3 2 /* probed card is a DS3 card */ +#define LMC_CARDTYPE_SSI 3 /* probed card is a SSI card */ +#define LMC_CARDTYPE_T1 4 /* probed card is a T1 card */ + +#define LMC_CTL_CARDTYPE_LMC5200 0 /* HSSI */ +#define LMC_CTL_CARDTYPE_LMC5245 1 /* DS3 */ +#define LMC_CTL_CARDTYPE_LMC1000 2 /* SSI, V.35 */ +#define LMC_CTL_CARDTYPE_LMC1200 3 /* DS1 */ + +#define LMC_CTL_OFF 0 /* generic OFF value */ +#define LMC_CTL_ON 1 /* generic ON value */ + +#define LMC_CTL_CLOCK_SOURCE_EXT 0 /* clock off line */ +#define LMC_CTL_CLOCK_SOURCE_INT 1 /* internal clock */ + +#define LMC_CTL_CRC_LENGTH_16 16 +#define LMC_CTL_CRC_LENGTH_32 32 +#define LMC_CTL_CRC_BYTESIZE_2 2 +#define LMC_CTL_CRC_BYTESIZE_4 4 + + +#define LMC_CTL_CABLE_LENGTH_LT_100FT 0 /* DS3 cable < 100 feet */ +#define LMC_CTL_CABLE_LENGTH_GT_100FT 1 /* DS3 cable >= 100 feet */ + +#define LMC_CTL_CIRCUIT_TYPE_E1 0 +#define LMC_CTL_CIRCUIT_TYPE_T1 1 + +/* + * IFTYPE defines + */ +#define LMC_PPP 1 /* use sppp interface */ +#define LMC_NET 2 /* use direct net interface */ +#define LMC_RAW 3 /* use direct net interface */ + +/* + * These are not in the least IOCTL related, but I want them common. + */ +/* + * assignments for the GPIO register on the DEC chip (common) + */ +#define LMC_GEP_INIT 0x01 /* 0: */ +#define LMC_GEP_RESET 0x02 /* 1: */ +#define LMC_GEP_MODE 0x10 /* 4: */ +#define LMC_GEP_DP 0x20 /* 5: */ +#define LMC_GEP_DATA 0x40 /* 6: serial out */ +#define LMC_GEP_CLK 0x80 /* 7: serial clock */ + +/* + * HSSI GPIO assignments + */ +#define LMC_GEP_HSSI_ST 0x04 /* 2: receive timing sense (deprecated) */ +#define LMC_GEP_HSSI_CLOCK 0x08 /* 3: clock source */ + +/* + * T1 GPIO assignments + */ +#define LMC_GEP_SSI_GENERATOR 0x04 /* 2: enable prog freq gen serial i/f */ +#define LMC_GEP_SSI_TXCLOCK 0x08 /* 3: provide clock on TXCLOCK output */ + +/* + * Common MII16 bits + */ +#define LMC_MII16_LED0 0x0080 +#define LMC_MII16_LED1 0x0100 +#define LMC_MII16_LED2 0x0200 +#define LMC_MII16_LED3 0x0400 /* Error, and the red one */ +#define LMC_MII16_LED_ALL 0x0780 /* LED bit mask */ +#define LMC_MII16_FIFO_RESET 0x0800 + +/* + * definitions for HSSI + */ +#define LMC_MII16_HSSI_TA 0x0001 +#define LMC_MII16_HSSI_CA 0x0002 +#define LMC_MII16_HSSI_LA 0x0004 +#define LMC_MII16_HSSI_LB 0x0008 +#define LMC_MII16_HSSI_LC 0x0010 +#define LMC_MII16_HSSI_TM 0x0020 +#define LMC_MII16_HSSI_CRC 0x0040 + +/* + * assignments for the MII register 16 (DS3) + */ +#define LMC_MII16_DS3_ZERO 0x0001 +#define LMC_MII16_DS3_TRLBK 0x0002 +#define LMC_MII16_DS3_LNLBK 0x0004 +#define LMC_MII16_DS3_RAIS 0x0008 +#define LMC_MII16_DS3_TAIS 0x0010 +#define LMC_MII16_DS3_BIST 0x0020 +#define LMC_MII16_DS3_DLOS 0x0040 +#define LMC_MII16_DS3_CRC 0x1000 +#define LMC_MII16_DS3_SCRAM 0x2000 +#define LMC_MII16_DS3_SCRAM_LARS 0x4000 + +/* Note: 2 pairs of LEDs where swapped by mistake + * in Xilinx code for DS3 & DS1 adapters */ +#define LMC_DS3_LED0 0x0100 /* bit 08 yellow */ +#define LMC_DS3_LED1 0x0080 /* bit 07 blue */ +#define LMC_DS3_LED2 0x0400 /* bit 10 green */ +#define LMC_DS3_LED3 0x0200 /* bit 09 red */ + +/* + * framer register 0 and 7 (7 is latched and reset on read) + */ +#define LMC_FRAMER_REG0_DLOS 0x80 /* digital loss of service */ +#define LMC_FRAMER_REG0_OOFS 0x40 /* out of frame sync */ +#define LMC_FRAMER_REG0_AIS 0x20 /* alarm indication signal */ +#define LMC_FRAMER_REG0_CIS 0x10 /* channel idle */ +#define LMC_FRAMER_REG0_LOC 0x08 /* loss of clock */ + +/* + * Framer register 9 contains the blue alarm signal + */ +#define LMC_FRAMER_REG9_RBLUE 0x02 /* Blue alarm failure */ + +/* + * Framer register 0x10 contains xbit error + */ +#define LMC_FRAMER_REG10_XBIT 0x01 /* X bit error alarm failure */ + +/* + * And SSI, LMC1000 + */ +#define LMC_MII16_SSI_DTR 0x0001 /* DTR output RW */ +#define LMC_MII16_SSI_DSR 0x0002 /* DSR input RO */ +#define LMC_MII16_SSI_RTS 0x0004 /* RTS output RW */ +#define LMC_MII16_SSI_CTS 0x0008 /* CTS input RO */ +#define LMC_MII16_SSI_DCD 0x0010 /* DCD input RO */ +#define LMC_MII16_SSI_RI 0x0020 /* RI input RO */ +#define LMC_MII16_SSI_CRC 0x1000 /* CRC select - RW */ + +/* + * bits 0x0080 through 0x0800 are generic, and described + * above with LMC_MII16_LED[0123] _LED_ALL, and _FIFO_RESET + */ +#define LMC_MII16_SSI_LL 0x1000 /* LL output RW */ +#define LMC_MII16_SSI_RL 0x2000 /* RL output RW */ +#define LMC_MII16_SSI_TM 0x4000 /* TM input RO */ +#define LMC_MII16_SSI_LOOP 0x8000 /* loopback enable RW */ + +/* + * Some of the MII16 bits are mirrored in the MII17 register as well, + * but let's keep thing seperate for now, and get only the cable from + * the MII17. + */ +#define LMC_MII17_SSI_CABLE_MASK 0x0038 /* mask to extract the cable type */ +#define LMC_MII17_SSI_CABLE_SHIFT 3 /* shift to extract the cable type */ + +/* + * And T1, LMC1200 + */ +#define LMC_MII16_T1_UNUSED1 0x0003 +#define LMC_MII16_T1_XOE 0x0004 +#define LMC_MII16_T1_RST 0x0008 /* T1 chip reset - RW */ +#define LMC_MII16_T1_Z 0x0010 /* output impedance T1=1, E1=0 output - RW */ +#define LMC_MII16_T1_INTR 0x0020 /* interrupt from 8370 - RO */ +#define LMC_MII16_T1_ONESEC 0x0040 /* one second square wave - ro */ + +#define LMC_MII16_T1_LED0 0x0100 +#define LMC_MII16_T1_LED1 0x0080 +#define LMC_MII16_T1_LED2 0x0400 +#define LMC_MII16_T1_LED3 0x0200 +#define LMC_MII16_T1_FIFO_RESET 0x0800 + +#define LMC_MII16_T1_CRC 0x1000 /* CRC select - RW */ +#define LMC_MII16_T1_UNUSED2 0xe000 + + +/* 8370 framer registers */ + +#define T1FRAMER_ALARM1_STATUS 0x47 +#define T1FRAMER_ALARM2_STATUS 0x48 +#define T1FRAMER_FERR_LSB 0x50 +#define T1FRAMER_FERR_MSB 0x51 /* framing bit error counter */ +#define T1FRAMER_LCV_LSB 0x54 +#define T1FRAMER_LCV_MSB 0x55 /* line code violation counter */ +#define T1FRAMER_AERR 0x5A + +/* mask for the above AERR register */ +#define T1FRAMER_LOF_MASK (0x0f0) /* receive loss of frame */ +#define T1FRAMER_COFA_MASK (0x0c0) /* change of frame alignment */ +#define T1FRAMER_SEF_MASK (0x03) /* severely errored frame */ + +/* 8370 framer register ALM1 (0x47) values + * used to determine link status + */ + +#define T1F_SIGFRZ 0x01 /* signaling freeze */ +#define T1F_RLOF 0x02 /* receive loss of frame alignment */ +#define T1F_RLOS 0x04 /* receive loss of signal */ +#define T1F_RALOS 0x08 /* receive analog loss of signal or RCKI loss of clock */ +#define T1F_RAIS 0x10 /* receive alarm indication signal */ +#define T1F_UNUSED 0x20 +#define T1F_RYEL 0x40 /* receive yellow alarm */ +#define T1F_RMYEL 0x80 /* receive multiframe yellow alarm */ + +#define LMC_T1F_WRITE 0 +#define LMC_T1F_READ 1 + +typedef struct lmc_st1f_control { + int command; + int address; + int value; + char *data; +} lmc_t1f_control; + +enum lmc_xilinx_c { + lmc_xilinx_reset = 1, + lmc_xilinx_load_prom = 2, + lmc_xilinx_load = 3 +}; + +struct lmc_xilinx_control { + enum lmc_xilinx_c command; + int len; + char *data; +}; + +/* ------------------ end T1 defs ------------------- */ + +#define LMC_MII_LedMask 0x0780 +#define LMC_MII_LedBitPos 7 + +#endif diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c new file mode 100644 index 000000000000..2710a7241389 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_main.c @@ -0,0 +1,2487 @@ + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * With Help By: + * David Boggs + * Ron Crane + * Allan Cox + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + * + * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. + * + * To control link specific options lmcctl is required. + * It can be obtained from ftp.lanmedia.com. + * + * Linux driver notes: + * Linux uses the device struct lmc_private to pass private information + * arround. + * + * The initialization portion of this driver (the lmc_reset() and the + * lmc_dec_reset() functions, as well as the led controls and the + * lmc_initcsrs() functions. + * + * The watchdog function runs every second and checks to see if + * we still have link, and that the timing source is what we expected + * it to be. If link is lost, the interface is marked down, and + * we no longer can transmit. + * + */ + +/* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < 0x20155 +#include +#endif + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include + +#if LINUX_VERSION_CODE >= 0x20200 +#include +//#include +#else /* 2.0 kernel */ +#define ARPHRD_HDLC 513 +#endif + +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define DRIVER_MAJOR_VERSION 1 +#define DRIVER_MINOR_VERSION 34 +#define DRIVER_SUB_VERSION 0 + +#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION) + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_ioctl.h" +#include "lmc_debug.h" +#include "lmc_proto.h" + + +static int Lmc_Count = 0; +static struct net_device *Lmc_root_dev = NULL; +static u8 cards_found = 0; + +static int lmc_first_load = 0; + +int LMC_PKT_BUF_SZ = 1542; + +#ifdef MODULE +static struct pci_device_id lmc_pci_tbl[] __devinitdata = { + { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0}, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); +#endif + + +int lmc_probe_fake(struct net_device *dev); +static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq, + int chip_id, int subdevice, int board_idx); +static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int lmc_rx (struct net_device *dev); +static int lmc_open(struct net_device *dev); +static int lmc_close(struct net_device *dev); +static struct enet_statistics *lmc_get_stats(struct net_device *dev); +static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int lmc_set_config(struct net_device *dev, struct ifmap *map); +static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size); +static void lmc_softreset(lmc_softc_t * const); +static void lmc_running_reset(struct net_device *dev); +static int lmc_ifdown(struct net_device * const); +static void lmc_watchdog(unsigned long data); +static int lmc_init(struct net_device * const); +static void lmc_reset(lmc_softc_t * const sc); +static void lmc_dec_reset(lmc_softc_t * const sc); +#if LINUX_VERSION_CODE >= 0x20363 +static void lmc_driver_timeout(struct net_device *dev); +int lmc_setup(void); +#endif + + +/* + * linux reserves 16 device specific IOCTLs. We call them + * LMCIOC* to control various bits of our world. + */ +int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ +{ + lmc_softc_t *sc; + lmc_ctl_t ctl; + int ret; + u_int16_t regVal; + unsigned long flags; + + struct sppp *sp; + + ret = -EOPNOTSUPP; + + sc = dev->priv; + + lmc_trace(dev, "lmc_ioctl in"); + + /* + * Most functions mess with the structure + * Disable interupts while we do the polling + */ + spin_lock_irqsave(&sc->lmc_lock, flags); + + switch (cmd) { + /* + * Return current driver state. Since we keep this up + * To date internally, just copy this out to the user. + */ + case LMCIOCGINFO: /*fold01*/ + LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)); + ret = 0; + break; + + case LMCIOCSINFO: /*fold01*/ + sp = &((struct ppp_device *) dev)->sppp; + if (!suser ()) { + ret = -EPERM; + break; + } + + if(dev->flags & IFF_UP){ + ret = -EBUSY; + break; + } + + LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + + sc->lmc_media->set_status (sc, &ctl); + + if(ctl.crc_length != sc->ictl.crc_length) { + sc->lmc_media->set_crc_length(sc, ctl.crc_length); + if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) + sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE; + else + sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE; + } + + if (ctl.keepalive_onoff == LMC_CTL_OFF) + sp->pp_flags &= ~PP_KEEPALIVE; /* Turn off */ + else + sp->pp_flags |= PP_KEEPALIVE; /* Turn on */ + + ret = 0; + break; + + case LMCIOCIFTYPE: /*fold01*/ + { + u_int16_t old_type = sc->if_type; + u_int16_t new_type; + + if (!suser ()) { + ret = -EPERM; + break; + } + + LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t)); + + + if (new_type == old_type) + { + ret = 0 ; + break; /* no change */ + } + + lmc_proto_close(sc); + lmc_proto_detach(sc); + + sc->if_type = new_type; +// lmc_proto_init(sc); + lmc_proto_attach(sc); + lmc_proto_open(sc); + + ret = 0 ; + break ; + } + + case LMCIOCGETXINFO: /*fold01*/ + sc->lmc_xinfo.Magic0 = 0xBEEFCAFE; + + sc->lmc_xinfo.PciCardType = sc->lmc_cardtype; + sc->lmc_xinfo.PciSlotNumber = 0; + sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION; + sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION; + sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION; + sc->lmc_xinfo.XilinxRevisionNumber = + lmc_mii_readreg (sc, 0, 3) & 0xf; + sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ; + sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc); + sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16); + + sc->lmc_xinfo.Magic1 = 0xDEADBEEF; + + LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo, + sizeof (struct lmc_xinfo)); + ret = 0; + + break; + + case LMCIOCGETLMCSTATS: /*fold01*/ + if (sc->lmc_cardtype == LMC_CARDTYPE_T1){ + lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB); + sc->stats.framingBitErrorCount += + lmc_mii_readreg (sc, 0, 18) & 0xff; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB); + sc->stats.framingBitErrorCount += + (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB); + sc->stats.lineCodeViolationCount += + lmc_mii_readreg (sc, 0, 18) & 0xff; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB); + sc->stats.lineCodeViolationCount += + (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR); + regVal = lmc_mii_readreg (sc, 0, 18) & 0xff; + + sc->stats.lossOfFrameCount += + (regVal & T1FRAMER_LOF_MASK) >> 4; + sc->stats.changeOfFrameAlignmentCount += + (regVal & T1FRAMER_COFA_MASK) >> 2; + sc->stats.severelyErroredFrameCount += + regVal & T1FRAMER_SEF_MASK; + } + + LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats, + sizeof (struct lmc_statistics)); + + ret = 0; + break; + + case LMCIOCCLEARLMCSTATS: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + memset (&sc->stats, 0, sizeof (struct lmc_statistics)); + sc->stats.check = STATCHECK; + sc->stats.version_size = (DRIVER_VERSION << 16) + + sizeof (struct lmc_statistics); + sc->stats.lmc_cardtype = sc->lmc_cardtype; + ret = 0; + break; + + case LMCIOCSETCIRCUIT: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + if(dev->flags & IFF_UP){ + ret = -EBUSY; + break; + } + + LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + sc->lmc_media->set_circuit_type(sc, ctl.circuit_type); + sc->ictl.circuit_type = ctl.circuit_type; + ret = 0; + + break; + + case LMCIOCRESET: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + /* Reset driver and bring back to current state */ + printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); + lmc_running_reset (dev); + printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); + + LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); + + ret = 0; + break; + +#ifdef DEBUG + case LMCIOCDUMPEVENTLOG: + LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)); + LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)); + + ret = 0; + break; +#endif /* end ifdef _DBG_EVENTLOG */ + case LMCIOCT1CONTROL: /*fold01*/ + if (sc->lmc_cardtype != LMC_CARDTYPE_T1){ + ret = -EOPNOTSUPP; + break; + } + break; + case LMCIOCXILINX: /*fold01*/ + { + struct lmc_xilinx_control xc; /*fold02*/ + + if (!suser ()){ + ret = -EPERM; + break; + } + + /* + * Stop the xwitter whlie we restart the hardware + */ + LMC_XMITTER_BUSY(dev); + + LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)); + switch(xc.command){ + case lmc_xilinx_reset: /*fold02*/ + { + u16 mii; + mii = lmc_mii_readreg (sc, 0, 16); + + /* + * Make all of them 0 and make input + */ + lmc_gpio_mkinput(sc, 0xff); + + /* + * make the reset output + */ + lmc_gpio_mkoutput(sc, LMC_GEP_RESET); + + /* + * RESET low to force configuration. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + + sc->lmc_gpio &= ~LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + sc->lmc_gpio |= LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, 0xff); + + /* Reset the frammer hardware */ + sc->lmc_media->set_link_status (sc, 1); + sc->lmc_media->set_status (sc, NULL); +// lmc_softreset(sc); + + { + int i; + for(i = 0; i < 5; i++){ + lmc_led_on(sc, LMC_DS3_LED0); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED0); + lmc_led_on(sc, LMC_DS3_LED1); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED1); + lmc_led_on(sc, LMC_DS3_LED3); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED3); + lmc_led_on(sc, LMC_DS3_LED2); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED2); + } + } + + + + ret = 0x0; + + } + + break; + case lmc_xilinx_load_prom: /*fold02*/ + { + u16 mii; + int timeout = 500000; + mii = lmc_mii_readreg (sc, 0, 16); + + /* + * Make all of them 0 and make input + */ + lmc_gpio_mkinput(sc, 0xff); + + /* + * make the reset output + */ + lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET); + + /* + * RESET low to force configuration. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + + sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP); + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + /* + * busy wait for the chip to reset + */ + while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && + (timeout-- > 0)) + ; + + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, 0xff); + + ret = 0x0; + + + break; + + } + + case lmc_xilinx_load: /*fold02*/ + { + char *data; + int pos; + int timeout = 500000; + + if(xc.data == 0x0){ + ret = -EINVAL; + break; + } + + data = kmalloc(xc.len, GFP_KERNEL); + if(data == 0x0){ + printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name); + ret = -ENOMEM; + break; + } + + LMC_COPY_FROM_USER(data, xc.data, xc.len); + + printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data); + + lmc_gpio_mkinput(sc, 0xff); + + /* + * Clear the Xilinx and start prgramming from the DEC + */ + + /* + * Set ouput as: + * Reset: 0 (active) + * DP: 0 (active) + * Mode: 1 + * + */ + sc->lmc_gpio = 0x00; + sc->lmc_gpio &= ~LMC_GEP_DP; + sc->lmc_gpio &= ~LMC_GEP_RESET; + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET); + + /* + * Wait at least 10 us 20 to be safe + */ + udelay(50); + + /* + * Clear reset and activate programing lines + * Reset: Input + * DP: Input + * Clock: Output + * Data: Output + * Mode: Output + */ + lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET); + + /* + * Set LOAD, DATA, Clock to 1 + */ + sc->lmc_gpio = 0x00; + sc->lmc_gpio |= LMC_GEP_MODE; + sc->lmc_gpio |= LMC_GEP_DATA; + sc->lmc_gpio |= LMC_GEP_CLK; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE ); + + /* + * busy wait for the chip to reset + */ + while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && + (timeout-- > 0)) + ; + + printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout); + + for(pos = 0; pos < xc.len; pos++){ + switch(data[pos]){ + case 0: + sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */ + break; + case 1: + sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */ + break; + default: + printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); + sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */ + } + sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */ + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + udelay(1); + + sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */ + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + udelay(1); + } + if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){ + printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name); + } + else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){ + printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name); + } + else { + printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos); + } + + lmc_gpio_mkinput(sc, 0xff); + + sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + kfree(data); + + ret = 0; + + break; + } + default: /*fold02*/ + ret = -EBADE; + break; + } + + LMC_XMITTER_FREE(dev); + sc->lmc_txfull = 0; + + } + break; + default: /*fold01*/ + /* If we don't know what to do, give the protocol a shot. */ + ret = lmc_proto_ioctl (sc, ifr, cmd); + break; + } + + spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/ + + lmc_trace(dev, "lmc_ioctl out"); + + return ret; +} + + +/* the watchdog process that cruises around */ +static void lmc_watchdog (unsigned long data) /*fold00*/ +{ + struct net_device *dev = (struct net_device *) data; + lmc_softc_t *sc; + int link_status; + u_int32_t ticks; + LMC_SPIN_FLAGS; + + sc = dev->priv; + + lmc_trace(dev, "lmc_watchdog in"); + + spin_lock_irqsave(&sc->lmc_lock, flags); + + if(sc->check != 0xBEAFCAFE){ + printk("LMC: Corrupt net_device stuct, breaking out\n"); + return; + } + + + /* Make sure the tx jabber and rx watchdog are off, + * and the transmit and recieve processes are running. + */ + + LMC_CSR_WRITE (sc, csr_15, 0x00000011); + sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN; + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + if (sc->lmc_ok == 0) + goto kick_timer; + + LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); + + /* --- begin time out check ----------------------------------- + * check for a transmit interrupt timeout + * Has the packet xmt vs xmt serviced threshold been exceeded */ + if (sc->lmc_taint_tx == sc->lastlmc_taint_tx && + sc->stats.tx_packets > sc->lasttx_packets && + sc->tx_TimeoutInd == 0) + { + + /* wait for the watchdog to come around again */ + sc->tx_TimeoutInd = 1; + } + else if (sc->lmc_taint_tx == sc->lastlmc_taint_tx && + sc->stats.tx_packets > sc->lasttx_packets && + sc->tx_TimeoutInd) + { + + LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0); + + sc->tx_TimeoutDisplay = 1; + sc->stats.tx_TimeoutCnt++; + + /* DEC chip is stuck, hit it with a RESET!!!! */ + lmc_running_reset (dev); + + + /* look at receive & transmit process state to make sure they are running */ + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + + /* look at: DSR - 02 for Reg 16 + * CTS - 08 + * DCD - 10 + * RI - 20 + * for Reg 17 + */ + LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17)); + + /* reset the transmit timeout detection flag */ + sc->tx_TimeoutInd = 0; + sc->lastlmc_taint_tx = sc->lmc_taint_tx; + sc->lasttx_packets = sc->stats.tx_packets; + } + else + { + sc->tx_TimeoutInd = 0; + sc->lastlmc_taint_tx = sc->lmc_taint_tx; + sc->lasttx_packets = sc->stats.tx_packets; + } + + /* --- end time out check ----------------------------------- */ + + + link_status = sc->lmc_media->get_link_status (sc); + + /* + * hardware level link lost, but the interface is marked as up. + * Mark it as down. + */ + if ((link_status == 0) && (sc->last_link_status != 0)) { + printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name); + sc->last_link_status = 0; + /* lmc_reset (sc); Why reset??? The link can go down ok */ + + /* Inform the world that link has been lost */ + dev->flags &= ~IFF_RUNNING; + } + + /* + * hardware link is up, but the interface is marked as down. + * Bring it back up again. + */ + if (link_status != 0 && sc->last_link_status == 0) { + printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name); + sc->last_link_status = 1; + /* lmc_reset (sc); Again why reset??? */ + + /* Inform the world that link protocol is back up. */ + dev->flags |= IFF_RUNNING; + + /* Now we have to tell the syncppp that we had an outage + * and that it should deal. Calling sppp_reopen here + * should do the trick, but we may have to call sppp_close + * when the link goes down, and call sppp_open here. + * Subject to more testing. + * --bbraun + */ + + lmc_proto_reopen(sc); + + } + + /* Call media specific watchdog functions */ + sc->lmc_media->watchdog(sc); + + /* + * Poke the transmitter to make sure it + * never stops, even if we run out of mem + */ + LMC_CSR_WRITE(sc, csr_rxpoll, 0); + + /* + * Check for code that failed + * and try and fix it as appropriate + */ + if(sc->failed_ring == 1){ + /* + * Failed to setup the recv/xmit rin + * Try again + */ + sc->failed_ring = 0; + lmc_softreset(sc); + } + if(sc->failed_recv_alloc == 1){ + /* + * We failed to alloc mem in the + * interupt halder, go through the rings + * and rebuild them + */ + sc->failed_recv_alloc = 0; + lmc_softreset(sc); + } + + + /* + * remember the timer value + */ +kick_timer: + + ticks = LMC_CSR_READ (sc, csr_gp_timer); + LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL); + sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff); + + /* + * restart this timer. + */ + sc->timer.expires = jiffies + (HZ); + add_timer (&sc->timer); + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_watchdog out"); + +} + +static int lmc_init(struct net_device * const dev) /*fold00*/ +{ + lmc_trace(dev, "lmc_init in"); + lmc_trace(dev, "lmc_init out"); + + return 0; +} + +/* This initializes each card from lmc_probe() */ +static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/ + int chip_id, int subdevice, int board_idx) +{ + lmc_softc_t *sc = NULL; + u_int16_t AdapModelNum; + + /* + * Allocate our own device structure + */ + +#if LINUX_VERSION_CODE < 0x20363 + dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL); +#else + dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); +#endif + if (dev == NULL){ + printk (KERN_ERR "lmc: kmalloc for device failed\n"); + return NULL; + } + memset (dev, 0, sizeof (struct net_device)); + +#ifndef GCOM + /* + * Switch to common hdlc%d naming. We name by type not by vendor + */ +#if LINUX_VERSION_CODE < 0x20363 + dev->name = ((char *) (dev)) + sizeof (struct ppp_device); +#else + dev->name = ((char *) (dev)) + sizeof (struct net_device); +#endif + + dev_alloc_name(dev, "hdlc%d"); +#else + /* + * GCOM uses LMC vendor name so that clients can know which card + * to attach to. + */ + dev->name = ((char *) (dev)) + sizeof (struct ppp_device); + dev_alloc_name(dev, "lmc%d"); +#endif + + lmc_trace(dev, "lmc_probe1 in"); + + Lmc_Count++; + + if(lmc_first_load == 0){ + printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); + lmc_first_load = 1; + } + + /* + * Allocate space for the private data structure + */ + + sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); + if (sc == NULL) { + printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", + dev->name); + return (NULL); + } + memset (sc, 0, sizeof (lmc_softc_t)); + dev->priv = sc; + sc->lmc_device = dev; + sc->name = dev->name; + + /* Initialize the sppp layer */ + /* An ioctl can cause a subsequent detach for raw frame interface */ + sc->if_type = LMC_PPP; + sc->check = 0xBEAFCAFE; + dev->base_addr = ioaddr; + dev->irq = irq; + /* + * This will get the protocol layer ready and do any 1 time init's + * Must have a valid sc and dev structure + */ + lmc_proto_init(sc); + + lmc_proto_attach(sc); + + /* Just fill in the entries for the device */ + + dev->init = lmc_init; + dev->type = ARPHRD_HDLC; + dev->hard_start_xmit = lmc_start_xmit; + dev->open = lmc_open; + dev->stop = lmc_close; + dev->get_stats = lmc_get_stats; + dev->do_ioctl = lmc_ioctl; + dev->set_config = lmc_set_config; +#if LINUX_VERSION_CODE >= 0x20363 + dev->tx_timeout = lmc_driver_timeout; + dev->watchdog_timeo = (HZ); /* 1 second */ +#endif + + /* + * Why were we changing this??? + dev->tx_queue_len = 100; + */ + + /* Init the spin lock so can call it latter */ + + spin_lock_init(&sc->lmc_lock); + + LMC_SETUP_20_DEV; + + printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); + + if (register_netdev (dev) != 0) { + printk (KERN_ERR "%s: register_netdev failed.\n", dev->name); + lmc_proto_detach(sc); + kfree (dev->priv); + kfree (dev); + return NULL; + } + + /* + * Request the region of registers we need, so that + * later on, no one else will take our card away from + * us. + */ + request_region (ioaddr, LMC_REG_RANGE, dev->name); + + sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN; + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + + switch (subdevice) { + case PCI_PRODUCT_LMC_HSSI: + printk ("%s: LMC HSSI\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_HSSI; + sc->lmc_media = &lmc_hssi_media; + break; + case PCI_PRODUCT_LMC_DS3: + printk ("%s: LMC DS3\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_DS3; + sc->lmc_media = &lmc_ds3_media; + break; + case PCI_PRODUCT_LMC_SSI: + printk ("%s: LMC SSI\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_SSI; + sc->lmc_media = &lmc_ssi_media; + break; + case PCI_PRODUCT_LMC_T1: + printk ("%s: LMC T1\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_T1; + sc->lmc_media = &lmc_t1_media; + break; + default: + printk (KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name); + break; + } + + lmc_initcsrs (sc, dev->base_addr, 8); + + lmc_gpio_mkinput (sc, 0xff); + sc->lmc_gpio = 0; /* drive no signals yet */ + + sc->lmc_media->defaults (sc); + + sc->lmc_media->set_link_status (sc, LMC_LINK_UP); + + /* verify that the PCI Sub System ID matches the Adapter Model number + * from the MII register + */ + AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4; + + if ((AdapModelNum == LMC_ADAP_T1 + && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */ + (AdapModelNum == LMC_ADAP_SSI + && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */ + (AdapModelNum == LMC_ADAP_DS3 + && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */ + (AdapModelNum == LMC_ADAP_HSSI + && subdevice == PCI_PRODUCT_LMC_HSSI)) + { /* detect LMC5200 */ + + } + else { + printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n", + dev->name, AdapModelNum, subdevice); +// return (NULL); + } + /* + * reset clock + */ + LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL); + + sc->board_idx = board_idx; + + memset (&sc->stats, 0, sizeof (struct lmc_statistics)); + + sc->stats.check = STATCHECK; + sc->stats.version_size = (DRIVER_VERSION << 16) + + sizeof (struct lmc_statistics); + sc->stats.lmc_cardtype = sc->lmc_cardtype; + + sc->lmc_ok = 0; + sc->last_link_status = 0; + + lmc_trace(dev, "lmc_probe1 out"); + + return dev; +} + + +/* This is the entry point. This is what is called immediatly. */ +/* This goes out and finds the card */ + +int lmc_probe_fake(struct net_device *dev) /*fold00*/ +{ + lmc_probe(NULL); + /* Return 1 to unloaded bogus device */ + return 1; +} + +int lmc_probe (struct net_device *dev) /*fold00*/ +{ + int pci_index = 0; +#if LINUX_VERSION_CODE >= 0x20155 + unsigned long pci_ioaddr; + unsigned short pci_command; + unsigned int pci_irq_line; +#else + unsigned char pci_irq_line; + u32 pci_ioaddr; +#endif + u16 vendor, subvendor, device, subdevice; + u32 foundaddr = 0; + unsigned char pci_bus, pci_device_fn; + u8 intcf = 0; + + /* The card is only available on PCI, so if we don't have a + * PCI bus, we are in trouble. + */ + + if (!LMC_PCI_PRESENT()) { +/* printk ("%s: We really want a pci bios!\n", dev->name);*/ + return -1; + } + /* Loop basically until we don't find anymore. */ + while (pci_index < 0xff){ + /* The tulip is considered an ethernet class of card... */ + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, &pci_bus, + &pci_device_fn) != PCIBIOS_SUCCESSFUL) { + /* No card found on this pass */ + break; + } + /* Read the info we need to determine if this is + * our card or not + */ +#if LINUX_VERSION_CODE >= 0x20155 + vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor; + device = pci_find_slot (pci_bus, pci_device_fn)->device; + pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq; +#if LINUX_VERSION_CODE < 0x20363 + pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0]; +#else + pci_ioaddr = pci_resource_start (pci_find_slot (pci_bus, pci_device_fn), 0); +#endif + pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), + PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), + PCI_SUBSYSTEM_ID, &subdevice); + /* + * SPARC PCI Bios doesn't set the BUS Master bit, unlike intel + * Without it we won't do much packet work + * Do this to everyone + */ + pci_read_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, + &pci_command); + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, + pci_command); +#else + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte (pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_SUBSYSTEM_ID, &subdevice); +#endif + + /* Align the io address on the 32 bit boundry just in case */ + pci_ioaddr &= ~3; + + /* + * Make sure it's the correct card. CHECK SUBVENDOR ID! + * There are lots of tulip's out there. + * Also check the region of registers we will soon be + * poking, to make sure no one else has reserved them. + * This prevents taking someone else's device. + * + * Check either the subvendor or the subdevice, some systems reverse + * the setting in the bois, seems to be version and arch dependant? + * Fix the two variables + * + */ + if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) && + (vendor == CORRECT_VENDOR_ID) && + (device == CORRECT_DEV_ID) && + ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){ + struct net_device *cur, *prev = NULL; + + /* Fix the error, exchange the two values */ + if(subdevice == PCI_VENDOR_LMC){ + subdevice = subvendor; + subvendor = PCI_VENDOR_LMC ; + } + + /* Make the call to actually setup this card */ + dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line, + device, subdevice, cards_found); + if (dev == NULL) { + printk ("lmc_probe: lmc_probe1 failed\n"); + goto lmc_probe_next_card; + } + /* insert the device into the chain of lmc devices */ + for (cur = Lmc_root_dev; + cur != NULL; + cur = ((lmc_softc_t *) cur->priv)->next_module) { + prev = cur; + } + + if (prev == NULL) + Lmc_root_dev = dev; + else + ((lmc_softc_t *) prev->priv)->next_module = dev; + + ((lmc_softc_t *) dev->priv)->next_module = NULL; + /* end insert */ + + foundaddr = dev->base_addr; + + cards_found++; + intcf++; + } + lmc_probe_next_card: + pci_index++; + } + + if (cards_found < 1) + return -1; + +#if LINUX_VERSION_CODE >= 0x20200 + return foundaddr; +#else + return 0; +#endif +} + +/* After this is called, packets can be sent. + * Does not initialize the addresses + */ +static int lmc_open (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc = dev->priv; + + lmc_trace(dev, "lmc_open in"); + + lmc_led_on(sc, LMC_DS3_LED0); + + lmc_dec_reset (sc); + lmc_reset (sc); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + + if (sc->lmc_ok){ + lmc_trace(dev, "lmc_open lmc_ok out"); + return (0); + } + + lmc_softreset (sc); + + /* Since we have to use PCI bus, this should work on x86,alpha,ppc */ + if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){ + printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq); + lmc_trace(dev, "lmc_open irq failed out"); + return -EAGAIN; + } + sc->got_irq = 1; + + /* Assert Terminal Active */ + sc->lmc_miireg16 |= LMC_MII16_LED_ALL; + sc->lmc_media->set_link_status (sc, LMC_LINK_UP); + + /* + * reset to last state. + */ + sc->lmc_media->set_status (sc, NULL); + + /* setup default bits to be used in tulip_desc_t transmit descriptor + * -baz */ + sc->TxDescriptControlInit = ( + LMC_TDES_INTERRUPT_ON_COMPLETION + | LMC_TDES_FIRST_SEGMENT + | LMC_TDES_LAST_SEGMENT + | LMC_TDES_SECOND_ADDR_CHAINED + | LMC_TDES_DISABLE_PADDING + ); + + if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) { + /* disable 32 bit CRC generated by ASIC */ + sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE; + } + sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length); + /* Acknoledge the Terminal Active and light LEDs */ + + /* dev->flags |= IFF_UP; */ + + lmc_proto_open(sc); + + dev->do_ioctl = lmc_ioctl; + + + LMC_XMITTER_INIT(dev); + +#if LINUX_VERSION_CODE < 0x20363 + dev->start = 1; +#endif + + sc->stats.tx_tbusy0++ ; + + MOD_INC_USE_COUNT; + + /* + * select what interrupts we want to get + */ + sc->lmc_intrmask = 0; + /* Should be using the default interrupt mask defined in the .h file. */ + sc->lmc_intrmask |= (TULIP_STS_NORMALINTR + | TULIP_STS_RXINTR + | TULIP_STS_TXINTR + | TULIP_STS_ABNRMLINTR + | TULIP_STS_SYSERROR + | TULIP_STS_TXSTOPPED + | TULIP_STS_TXUNDERFLOW + | TULIP_STS_RXSTOPPED + | TULIP_STS_RXNOBUF + ); + LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask); + + sc->lmc_cmdmode |= TULIP_CMD_TXRUN; + sc->lmc_cmdmode |= TULIP_CMD_RXRUN; + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + sc->lmc_ok = 1; /* Run watchdog */ + + /* + * Set the if up now - pfb + */ + + sc->last_link_status = 1; + + /* + * Setup a timer for the watchdog on probe, and start it running. + * Since lmc_ok == 0, it will be a NOP for now. + */ + init_timer (&sc->timer); + sc->timer.expires = jiffies + HZ; + sc->timer.data = (unsigned long) dev; + sc->timer.function = &lmc_watchdog; + add_timer (&sc->timer); + + lmc_trace(dev, "lmc_open out"); + + return (0); +} + +/* Total reset to compensate for the AdTran DSU doing bad things + * under heavy load + */ + +static void lmc_running_reset (struct net_device *dev) /*fold00*/ +{ + + lmc_softc_t *sc = (lmc_softc_t *) dev->priv; + + lmc_trace(dev, "lmc_runnig_reset in"); + + /* stop interrupts */ + /* Clear the interrupt mask */ + LMC_CSR_WRITE (sc, csr_intr, 0x00000000); + + lmc_dec_reset (sc); + lmc_reset (sc); + lmc_softreset (sc); + /* sc->lmc_miireg16 |= LMC_MII16_LED_ALL; */ + sc->lmc_media->set_link_status (sc, 1); + sc->lmc_media->set_status (sc, NULL); + + //dev->flags |= IFF_RUNNING; + + LMC_XMITTER_FREE(dev); + + sc->lmc_txfull = 0; + sc->stats.tx_tbusy0++ ; + + sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK; + LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask); + + sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN); + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + lmc_trace(dev, "lmc_runnin_reset_out"); +} + + +/* This is what is called when you ifconfig down a device. + * This disables the timer for the watchdog and keepalives, + * and disables the irq for dev. + */ +static int lmc_close (struct net_device *dev) /*fold00*/ +{ + /* not calling release_region() as we should */ + lmc_softc_t *sc; + + lmc_trace(dev, "lmc_close in"); + + sc = dev->priv; + sc->lmc_ok = 0; + sc->lmc_media->set_link_status (sc, 0); + del_timer (&sc->timer); + lmc_proto_close(sc); + lmc_ifdown (dev); + + lmc_trace(dev, "lmc_close out"); + + return 0; +} + +/* Ends the transfer of packets */ +/* When the interface goes down, this is called */ +static int lmc_ifdown (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc = dev->priv; + u32 csr6; + int i; + + lmc_trace(dev, "lmc_ifdown in"); + + /* Don't let anything else go on right now */ + // dev->start = 0; + LMC_XMITTER_BUSY(dev); + sc->stats.tx_tbusy1++ ; + + /* stop interrupts */ + /* Clear the interrupt mask */ + LMC_CSR_WRITE (sc, csr_intr, 0x00000000); + + /* Stop Tx and Rx on the chip */ + csr6 = LMC_CSR_READ (sc, csr_command); + csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */ + csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */ + LMC_CSR_WRITE (sc, csr_command, csr6); + + dev->flags &= ~IFF_RUNNING; + + sc->stats.rx_missed_errors += + LMC_CSR_READ (sc, csr_missed_frames) & 0xffff; + + /* release the interrupt */ + if(sc->got_irq == 1){ + free_irq (dev->irq, dev); + sc->got_irq = 0; + } + + /* free skbuffs in the Rx queue */ + for (i = 0; i < LMC_RXDESCS; i++) + { + struct sk_buff *skb = sc->lmc_rxq[i]; + sc->lmc_rxq[i] = 0; + sc->lmc_rxring[i].status = 0; + sc->lmc_rxring[i].length = 0; + sc->lmc_rxring[i].buffer1 = 0xDEADBEEF; + if (skb != NULL) + { + LMC_SKB_FREE(skb, 1); + LMC_DEV_KFREE_SKB (skb); + } + sc->lmc_rxq[i] = NULL; + } + + for (i = 0; i < LMC_TXDESCS; i++) + { + if (sc->lmc_txq[i] != NULL) + LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + sc->lmc_txq[i] = NULL; + } + + lmc_led_off (sc, LMC_MII16_LED_ALL); + + LMC_XMITTER_FREE(dev); + sc->stats.tx_tbusy0++ ; + + lmc_trace(dev, "lmc_ifdown out"); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* Interrupt handling routine. This will take an incoming packet, or clean + * up after a trasmit. + */ +static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ +{ + struct net_device *dev = (struct net_device *) dev_instance; + lmc_softc_t *sc; + u32 csr; + int i; + s32 stat; + unsigned int badtx; + u32 firstcsr; + int max_work = LMC_RXDESCS; + + lmc_trace(dev, "lmc_interrupt in"); + + sc = dev->priv; + + spin_lock(&sc->lmc_lock); + + /* + * Read the csr to find what interupts we have (if any) + */ + csr = LMC_CSR_READ (sc, csr_status); + + /* + * Make sure this is our interrupt + */ + if ( ! (csr & sc->lmc_intrmask)) { + goto lmc_int_fail_out; + } + + firstcsr = csr; + + /* always go through this loop at least once */ + while (csr & sc->lmc_intrmask) { + /* + * Clear interupt bits, we handle all case below + */ + LMC_CSR_WRITE (sc, csr_status, csr); + + /* + * One of + * - Transmit process timed out CSR5<1> + * - Transmit jabber timeout CSR5<3> + * - Transmit underflow CSR5<5> + * - Transmit Receiver buffer unavailable CSR5<7> + * - Receive process stopped CSR5<8> + * - Receive watchdog timeout CSR5<9> + * - Early transmit interrupt CSR5<10> + * + * Is this really right? Should we do a running reset for jabber? + * (being a WAN card and all) + */ + if (csr & TULIP_STS_ABNRMLINTR){ + lmc_running_reset (dev); + break; + } + + if (csr & TULIP_STS_RXINTR){ + lmc_trace(dev, "rx interupt"); + lmc_rx (dev); + + } + if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) { + + int n_compl = 0 ; + /* reset the transmit timeout detection flag -baz */ + sc->stats.tx_NoCompleteCnt = 0; + + badtx = sc->lmc_taint_tx; + i = badtx % LMC_TXDESCS; + + while ((badtx < sc->lmc_next_tx)) { + stat = sc->lmc_txring[i].status; + + LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat, + sc->lmc_txring[i].length); + /* + * If bit 31 is 1 the tulip owns it break out of the loop + */ + if (stat & 0x80000000) + break; + + n_compl++ ; /* i.e., have an empty slot in ring */ + /* + * If we have no skbuff or have cleared it + * Already continue to the next buffer + */ + if (sc->lmc_txq[i] == NULL) + continue; + + /* + * Check the total error summary to look for any errors + */ + if (stat & 0x8000) { + sc->stats.tx_errors++; + if (stat & 0x4104) + sc->stats.tx_aborted_errors++; + if (stat & 0x0C00) + sc->stats.tx_carrier_errors++; + if (stat & 0x0200) + sc->stats.tx_window_errors++; + if (stat & 0x0002) + sc->stats.tx_fifo_errors++; + } + else { + +#if LINUX_VERSION_CODE >= 0x20200 + sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff; +#endif + + sc->stats.tx_packets++; + } + + // LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + dev_kfree_skb_irq(sc->lmc_txq[i]); + sc->lmc_txq[i] = 0; + + badtx++; + i = badtx % LMC_TXDESCS; + } + + if (sc->lmc_next_tx - badtx > LMC_TXDESCS) + { + printk ("%s: out of sync pointer\n", dev->name); + badtx += LMC_TXDESCS; + } + LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0); + sc->lmc_txfull = 0; + LMC_XMITTER_FREE(dev); + sc->stats.tx_tbusy0++ ; +#if LINUX_VERSION_CODE < 0x20363 + mark_bh (NET_BH); /* Tell Linux to give me more packets */ +#endif + + +#ifdef DEBUG + sc->stats.dirtyTx = badtx; + sc->stats.lmc_next_tx = sc->lmc_next_tx; + sc->stats.lmc_txfull = sc->lmc_txfull; +#if LINUX_VERSION_CODE < 0x20363 + sc->stats.tbusy = dev->tbusy; +#endif +#endif + sc->lmc_taint_tx = badtx; + + /* + * Why was there a break here??? + */ + } /* end handle transmit interrupt */ + + if (csr & TULIP_STS_SYSERROR) { + u32 error; + printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr); + error = csr>>23 & 0x7; + switch(error){ + case 0x000: + printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name); + break; + case 0x001: + printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); + break; + case 0x010: + printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); + break; + default: + printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name); + } + lmc_dec_reset (sc); + lmc_reset (sc); + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + } + + + if(max_work-- <= 0) + break; + + /* + * Get current csr status to make sure + * we've cleared all interupts + */ + csr = LMC_CSR_READ (sc, csr_status); + } /* end interrupt loop */ + LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr); + +lmc_int_fail_out: + + spin_unlock(&sc->lmc_lock); + + lmc_trace(dev, "lmc_interrupt out"); + + return; +} + +static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + u32 flag; + int entry; + int ret = 0; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_start_xmit in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + /* + * If the transmitter is busy + * this must be the 5 second polling + * from the kernel which called us. + * Poke the chip and try to get it running + * + */ +#if LINUX_VERSION_CODE < 0x20363 + if(dev->tbusy != 0){ + u32 csr6; + + printk("%s: Xmitter busy|\n", dev->name); + + sc->stats.tx_tbusy_calls++ ; + if (jiffies - dev->trans_start < TX_TIMEOUT) { + ret = 1; + goto lmc_start_xmit_bug_out; + } + + /* + * Chip seems to have locked up + * Reset it + * This whips out all our decriptor + * table and starts from scartch + */ + + LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, + LMC_CSR_READ (sc, csr_status), + sc->stats.tx_ProcTimeout); + + lmc_running_reset (dev); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + /* restart the tx processes */ + csr6 = LMC_CSR_READ (sc, csr_command); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); + + /* immediate transmit */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + sc->stats.tx_errors++; + sc->stats.tx_ProcTimeout++; /* -baz */ + + dev->trans_start = jiffies; + + ret = 1; + goto lmc_start_xmit_bug_out; + } +#endif + /* normal path, tbusy known to be zero */ + + entry = sc->lmc_next_tx % LMC_TXDESCS; + + sc->lmc_txq[entry] = skb; + sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data); + + LMC_CONSOLE_LOG("xmit", skb->data, skb->len); + +#ifndef GCOM + /* If the queue is less than half full, don't interrupt */ + if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2) + { + /* Do not interrupt on completion of this packet */ + flag = 0x60000000; + LMC_XMITTER_FREE(dev); + } + else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2) + { + /* This generates an interrupt on completion of this packet */ + flag = 0xe0000000; + LMC_XMITTER_FREE(dev); + } + else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1) + { + /* Do not interrupt on completion of this packet */ + flag = 0x60000000; + LMC_XMITTER_FREE(dev); + } + else + { + /* This generates an interrupt on completion of this packet */ + flag = 0xe0000000; + sc->lmc_txfull = 1; + LMC_XMITTER_BUSY(dev); + } +#else + flag = LMC_TDES_INTERRUPT_ON_COMPLETION; + + if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1) + { /* ring full, go busy */ + sc->lmc_txfull = 1; + LMC_XMITTER_BUSY(dev); + sc->stats.tx_tbusy1++ ; + LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0); + } +#endif + + + if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */ + flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */ + + /* don't pad small packets either */ + flag = sc->lmc_txring[entry].length = (skb->len) | flag | + sc->TxDescriptControlInit; + + /* set the transmit timeout flag to be checked in + * the watchdog timer handler. -baz + */ + + sc->stats.tx_NoCompleteCnt++; + sc->lmc_next_tx++; + + /* give ownership to the chip */ + LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry); + sc->lmc_txring[entry].status = 0x80000000; + + /* send now! */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + dev->trans_start = jiffies; + +#if LINUX_VERSION_CODE < 0x20363 +lmc_start_xmit_bug_out: +#endif + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_start_xmit_out"); + return ret; +} + + +static int lmc_rx (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + int i; + int rx_work_limit = LMC_RXDESCS; + unsigned int next_rx; + int rxIntLoopCnt; /* debug -baz */ + int localLengthErrCnt = 0; + long stat; + struct sk_buff *skb, *nsb; + u16 len; + + lmc_trace(dev, "lmc_rx in"); + + sc = dev->priv; + + lmc_led_on(sc, LMC_DS3_LED3); + + rxIntLoopCnt = 0; /* debug -baz */ + + i = sc->lmc_next_rx % LMC_RXDESCS; + next_rx = sc->lmc_next_rx; + + while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4) + { + rxIntLoopCnt++; /* debug -baz */ + len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER); + if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */ + if ((stat & 0x0000ffff) != 0x7fff) { + /* Oversized frame */ + sc->stats.rx_length_errors++; + goto skip_packet; + } + } + + if(stat & 0x00000008){ /* Catch a dribbling bit error */ + sc->stats.rx_errors++; + sc->stats.rx_frame_errors++; + goto skip_packet; + } + + + if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */ + sc->stats.rx_errors++; + sc->stats.rx_crc_errors++; + goto skip_packet; + } + + + if (len > LMC_PKT_BUF_SZ){ + sc->stats.rx_length_errors++; + localLengthErrCnt++; + goto skip_packet; + } + + if (len < sc->lmc_crcSize + 2) { + sc->stats.rx_length_errors++; + sc->stats.rx_SmallPktCnt++; + localLengthErrCnt++; + goto skip_packet; + } + + if(stat & 0x00004000){ + printk(KERN_WARNING "%s: Receiver descriptor error, receiver out of sync?\n", dev->name); + } + + len -= sc->lmc_crcSize; + + skb = sc->lmc_rxq[i]; + + /* + * We ran out of memory at some point + * just allocate an skb buff and continue. + */ + + if(skb == 0x0){ + nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if (nsb) { + LMC_SKB_FREE(nsb, 1); + sc->lmc_rxq[i] = nsb; + nsb->dev = dev; + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); + } + sc->failed_recv_alloc = 1; + goto skip_packet; + } + + dev->last_rx = jiffies; + sc->stats.rx_packets++; + + LMC_CONSOLE_LOG("recv", skb->data, len); + + /* + * I'm not sure of the sanity of this + * Packets could be arriving at a constant + * 44.210mbits/sec and we're going to copy + * them into a new buffer?? + */ + + if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */ + /* + * If it's a large packet don't copy it just hand it up + */ + give_it_anyways: + + sc->lmc_rxq[i] = 0x0; + sc->lmc_rxring[i].buffer1 = 0x0; + + skb_put (skb, len); + skb->protocol = lmc_proto_type(sc, skb); + skb->protocol = htons(ETH_P_WAN_PPP); + skb->mac.raw = skb->data; +// skb->nh.raw = skb->data; + skb->dev = dev; + lmc_proto_netif(sc, skb); + + /* + * This skb will be destroyed by the upper layers, make a new one + */ + nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if (nsb) { + LMC_SKB_FREE(nsb, 1); + sc->lmc_rxq[i] = nsb; + nsb->dev = dev; + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); + /* Transfered to 21140 below */ + } + else { + /* + * We've run out of memory, stop trying to allocate + * memory and exit the interupt handler + * + * The chip may run out of receivers and stop + * in which care we'll try to allocate the buffer + * again. (once a second) + */ + sc->stats.rx_BuffAllocErr++; + LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len); + sc->failed_recv_alloc = 1; + goto skip_out_of_mem; + } + } + else { + nsb = dev_alloc_skb(len); + if(!nsb) { + goto give_it_anyways; + } + memcpy(skb_put(nsb, len), skb->data, len); + + nsb->protocol = lmc_proto_type(sc, skb); + nsb->mac.raw = nsb->data; +// nsb->nh.raw = nsb->data; + nsb->dev = dev; + lmc_proto_netif(sc, nsb); + } + + skip_packet: + LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len); + sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4; + + sc->lmc_next_rx++; + i = sc->lmc_next_rx % LMC_RXDESCS; + rx_work_limit--; + if (rx_work_limit < 0) + break; + } + + /* detect condition for LMC1000 where DSU cable attaches and fills + * descriptors with bogus packets + * + if (localLengthErrCnt > LMC_RXDESCS - 3) { + sc->stats.rx_BadPktSurgeCnt++; + LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE, + localLengthErrCnt, + sc->stats.rx_BadPktSurgeCnt); + } */ + + /* save max count of receive descriptors serviced */ + if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) { + sc->stats.rxIntLoopCnt = rxIntLoopCnt; /* debug -baz */ + } + +#ifdef DEBUG + if (rxIntLoopCnt == 0) + { + for (i = 0; i < LMC_RXDESCS; i++) + { + if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT) + != DESC_OWNED_BY_DC21X4) + { + rxIntLoopCnt++; + } + } + LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0); + } +#endif + + + lmc_led_off(sc, LMC_DS3_LED3); + +skip_out_of_mem: + + lmc_trace(dev, "lmc_rx out"); + + return 0; +} + +static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_get_stats in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff; + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_get_stats out"); + + return (struct enet_statistics *) &sc->stats; +} + +#ifdef MODULE + +int init_module (void) /*fold00*/ +{ + printk ("lmc: module loaded\n"); + + /* Have lmc_probe search for all the cards, and allocate devices */ + if (lmc_probe (NULL) < 0) + return -EIO; + + return 0; +} + +void cleanup_module (void) /*fold00*/ +{ + struct net_device *dev, *next; + lmc_softc_t *sc; + + /* we have no pointer to our devices, since they are all dynamically + * allocated. So, here we loop through all the network devices + * looking for ours. When found, dispose of them properly. + */ + + for (dev = Lmc_root_dev; + dev != NULL; + dev = next ) + { + + next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */ + printk ("%s: removing...\n", dev->name); + + /* close the syncppp stuff, and release irq. Close is run on unreg net */ + lmc_close (dev); + sc = dev->priv; + if (sc != NULL) + lmc_proto_detach(sc); + + /* Remove the device from the linked list */ + unregister_netdev (dev); + + /* Let go of the io region */; + release_region (dev->base_addr, LMC_REG_RANGE); + + /* free our allocated structures. */ + kfree (dev->priv); + dev->priv = NULL; + + kfree ((struct ppp_device *) dev); + dev = NULL; + } + + + Lmc_root_dev = NULL; + printk ("lmc module unloaded\n"); +} +#endif + +unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/ +{ + int i; + int command = (0xf6 << 10) | (devaddr << 5) | regno; + int retval = 0; + + lmc_trace(sc->lmc_device, "lmc_mii_readreg in"); + + LMC_MII_SYNC (sc); + + lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync"); + + for (i = 15; i >= 0; i--) + { + int dataval = (command & (1 << i)) ? 0x20000 : 0; + + LMC_CSR_WRITE (sc, csr_9, dataval); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + } + + lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1"); + + for (i = 19; i > 0; i--) + { + LMC_CSR_WRITE (sc, csr_9, 0x40000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0); + LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + } + + lmc_trace(sc->lmc_device, "lmc_mii_readreg out"); + + return (retval >> 1) & 0xffff; +} + +void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/ +{ + int i = 32; + int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data; + + lmc_trace(sc->lmc_device, "lmc_mii_writereg in"); + + LMC_MII_SYNC (sc); + + i = 31; + while (i >= 0) + { + int datav; + + if (command & (1 << i)) + datav = 0x20000; + else + datav = 0x00000; + + LMC_CSR_WRITE (sc, csr_9, datav); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000)); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + i--; + } + + i = 2; + while (i > 0) + { + LMC_CSR_WRITE (sc, csr_9, 0x40000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, 0x50000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + i--; + } + + lmc_trace(sc->lmc_device, "lmc_mii_writereg out"); +} + +static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ +{ + int i; + + lmc_trace(sc->lmc_device, "lmc_softreset in"); + + /* Initialize the recieve rings and buffers. */ + sc->lmc_txfull = 0; + sc->lmc_next_rx = 0; + sc->lmc_next_tx = 0; + sc->lmc_taint_rx = 0; + sc->lmc_taint_tx = 0; + + /* + * Setup each one of the receiver buffers + * allocate an skbuff for each one, setup the the descriptor table + * and point each buffer at the next one + */ + + for (i = 0; i < LMC_RXDESCS; i++) + { + struct sk_buff *skb; + + if (sc->lmc_rxq[i] == NULL) + { + skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if(skb == NULL){ + printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name); + sc->failed_ring = 1; + break; + } + else{ + sc->lmc_rxq[i] = skb; + } + } + else + { + skb = sc->lmc_rxq[i]; + } + + skb->dev = sc->lmc_device; + LMC_SKB_FREE(skb, 1); + + /* owned by 21140 */ + sc->lmc_rxring[i].status = 0x80000000; + + /* used to be PKT_BUF_SZ now uses skb since we loose some to head room */ + sc->lmc_rxring[i].length = skb->end - skb->data; + + /* use to be tail which is dumb since you're thinking why write + * to the end of the packj,et but since there's nothing there tail == data + */ + sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data); + + /* This is fair since the structure is static and we have the next address */ + sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]); + + } + + /* + * Sets end of ring + */ + sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ + sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */ + LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */ + + + /* Initialize the transmit rings and buffers */ + for (i = 0; i < LMC_TXDESCS; i++) + { + if (sc->lmc_txq[i] != NULL){ /* have buffer */ + dev_kfree_skb(sc->lmc_txq[i]); /* free it */ + sc->stats.tx_dropped++; /* We just dropped a packet */ + } + sc->lmc_txq[i] = 0; + sc->lmc_txring[i].status = 0x00000000; + sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]); + } + sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]); + LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring)); + + lmc_trace(sc->lmc_device, "lmc_softreset out"); +} + +static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/ +{ + lmc_trace(dev, "lmc_set_config in"); + lmc_trace(dev, "lmc_set_config out"); + return -EOPNOTSUPP; +} + +void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in"); + sc->lmc_gpio_io &= ~bits; + LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io)); + lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out"); +} + +void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in"); + sc->lmc_gpio_io |= bits; + LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io)); + lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out"); +} + +void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_led_on in"); + if((~sc->lmc_miireg16) & led){ /* Already on! */ + lmc_trace(sc->lmc_device, "lmc_led_on aon out"); + return; + } + + sc->lmc_miireg16 &= ~led; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + lmc_trace(sc->lmc_device, "lmc_led_on out"); +} + +void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_led_off in"); + if(sc->lmc_miireg16 & led){ /* Already set don't do anything */ + lmc_trace(sc->lmc_device, "lmc_led_off aoff out"); + return; + } + + sc->lmc_miireg16 |= led; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + lmc_trace(sc->lmc_device, "lmc_led_off out"); +} + +static void lmc_reset(lmc_softc_t * const sc) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_reset in"); + sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + /* + * make some of the GPIO pins be outputs + */ + lmc_gpio_mkoutput(sc, LMC_GEP_RESET); + + /* + * RESET low to force state reset. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + sc->lmc_gpio &= ~(LMC_GEP_RESET); + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, LMC_GEP_RESET); + + /* + * Call media specific init routine + */ + sc->lmc_media->init(sc); + + sc->stats.resetCount++; + lmc_trace(sc->lmc_device, "lmc_reset out"); +} + +static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/ +{ + u_int32_t val; + lmc_trace(sc->lmc_device, "lmc_dec_reset in"); + + /* + * disable all interrupts + */ + sc->lmc_intrmask = 0; + LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask); + + /* + * Reset the chip with a software reset command. + * Wait 10 microseconds (actually 50 PCI cycles but at + * 33MHz that comes to two microseconds but wait a + * bit longer anyways) + */ + LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); + udelay(25); +#ifdef __sparc__ + sc->lmc_busmode = LMC_CSR_READ(sc, csr_busmode); + sc->lmc_busmode = 0x00100000; + sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET; + LMC_CSR_WRITE(sc, csr_busmode, sc->lmc_busmode); +#endif + sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command); + + /* + * We want: + * no ethernet address in frames we write + * disable padding (txdesc, padding disable) + * ignore runt frames (rdes0 bit 15) + * no receiver watchdog or transmitter jabber timer + * (csr15 bit 0,14 == 1) + * if using 16-bit CRC, turn off CRC (trans desc, crc disable) + */ + + sc->lmc_cmdmode |= ( TULIP_CMD_PROMISCUOUS + | TULIP_CMD_FULLDUPLEX + | TULIP_CMD_PASSBADPKT + | TULIP_CMD_NOHEARTBEAT + | TULIP_CMD_PORTSELECT + | TULIP_CMD_RECEIVEALL + | TULIP_CMD_MUSTBEONE + ); + sc->lmc_cmdmode &= ~( TULIP_CMD_OPERMODE + | TULIP_CMD_THRESHOLDCTL + | TULIP_CMD_STOREFWD + | TULIP_CMD_TXTHRSHLDCTL + ); + + LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode); + + /* + * disable receiver watchdog and transmit jabber + */ + val = LMC_CSR_READ(sc, csr_sia_general); + val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE); + LMC_CSR_WRITE(sc, csr_sia_general, val); + + lmc_trace(sc->lmc_device, "lmc_dec_reset out"); +} + +static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/ + size_t csr_size) +{ + lmc_trace(sc->lmc_device, "lmc_initcsrs in"); + sc->lmc_csrs.csr_busmode = csr_base + 0 * csr_size; + sc->lmc_csrs.csr_txpoll = csr_base + 1 * csr_size; + sc->lmc_csrs.csr_rxpoll = csr_base + 2 * csr_size; + sc->lmc_csrs.csr_rxlist = csr_base + 3 * csr_size; + sc->lmc_csrs.csr_txlist = csr_base + 4 * csr_size; + sc->lmc_csrs.csr_status = csr_base + 5 * csr_size; + sc->lmc_csrs.csr_command = csr_base + 6 * csr_size; + sc->lmc_csrs.csr_intr = csr_base + 7 * csr_size; + sc->lmc_csrs.csr_missed_frames = csr_base + 8 * csr_size; + sc->lmc_csrs.csr_9 = csr_base + 9 * csr_size; + sc->lmc_csrs.csr_10 = csr_base + 10 * csr_size; + sc->lmc_csrs.csr_11 = csr_base + 11 * csr_size; + sc->lmc_csrs.csr_12 = csr_base + 12 * csr_size; + sc->lmc_csrs.csr_13 = csr_base + 13 * csr_size; + sc->lmc_csrs.csr_14 = csr_base + 14 * csr_size; + sc->lmc_csrs.csr_15 = csr_base + 15 * csr_size; + lmc_trace(sc->lmc_device, "lmc_initcsrs out"); +} + +#if LINUX_VERSION_CODE >= 0x20363 +static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/ + lmc_softc_t *sc; + u32 csr6; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_driver_timeout in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + printk("%s: Xmitter busy|\n", dev->name); + + sc->stats.tx_tbusy_calls++ ; + if (jiffies - dev->trans_start < TX_TIMEOUT) { + goto bug_out; + } + + /* + * Chip seems to have locked up + * Reset it + * This whips out all our decriptor + * table and starts from scartch + */ + + LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, + LMC_CSR_READ (sc, csr_status), + sc->stats.tx_ProcTimeout); + + lmc_running_reset (dev); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + /* restart the tx processes */ + csr6 = LMC_CSR_READ (sc, csr_command); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); + + /* immediate transmit */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + sc->stats.tx_errors++; + sc->stats.tx_ProcTimeout++; /* -baz */ + + dev->trans_start = jiffies; + +bug_out: + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_driver_timout out"); + + +} + +int lmc_setup(void) { /*FOLD00*/ + return lmc_probe(NULL); +} + +#endif diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c new file mode 100644 index 000000000000..8df3cb36c2f4 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_media.c @@ -0,0 +1,1258 @@ +/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#if LINUX_VERSION_CODE < 0x20155 +#include +#endif + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include + +#if LINUX_VERSION_CODE >= 0x20200 +#include +//#include +#endif + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_ioctl.h" +#include "lmc_debug.h" + +#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1 + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +/* + * For lack of a better place, put the SSI cable stuff here. + */ +char *lmc_t1_cables[] = { + "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35", + "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL +}; + +/* + * protocol independent method. + */ +static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *); + +/* + * media independent methods to check on media status, link, light LEDs, + * etc. + */ +static void lmc_ds3_init (lmc_softc_t * const); +static void lmc_ds3_default (lmc_softc_t * const); +static void lmc_ds3_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_ds3_set_100ft (lmc_softc_t * const, int); +static int lmc_ds3_get_link_status (lmc_softc_t * const); +static void lmc_ds3_set_crc_length (lmc_softc_t * const, int); +static void lmc_ds3_set_scram (lmc_softc_t * const, int); +static void lmc_ds3_watchdog (lmc_softc_t * const); + +static void lmc_hssi_init (lmc_softc_t * const); +static void lmc_hssi_default (lmc_softc_t * const); +static void lmc_hssi_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_hssi_set_clock (lmc_softc_t * const, int); +static int lmc_hssi_get_link_status (lmc_softc_t * const); +static void lmc_hssi_set_link_status (lmc_softc_t * const, int); +static void lmc_hssi_set_crc_length (lmc_softc_t * const, int); +static void lmc_hssi_watchdog (lmc_softc_t * const); + +static void lmc_ssi_init (lmc_softc_t * const); +static void lmc_ssi_default (lmc_softc_t * const); +static void lmc_ssi_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_ssi_set_clock (lmc_softc_t * const, int); +static void lmc_ssi_set_speed (lmc_softc_t * const, lmc_ctl_t *); +static int lmc_ssi_get_link_status (lmc_softc_t * const); +static void lmc_ssi_set_link_status (lmc_softc_t * const, int); +static void lmc_ssi_set_crc_length (lmc_softc_t * const, int); +static void lmc_ssi_watchdog (lmc_softc_t * const); + +static void lmc_t1_init (lmc_softc_t * const); +static void lmc_t1_default (lmc_softc_t * const); +static void lmc_t1_set_status (lmc_softc_t * const, lmc_ctl_t *); +static int lmc_t1_get_link_status (lmc_softc_t * const); +static void lmc_t1_set_circuit_type (lmc_softc_t * const, int); +static void lmc_t1_set_crc_length (lmc_softc_t * const, int); +static void lmc_t1_set_clock (lmc_softc_t * const, int); +static void lmc_t1_watchdog (lmc_softc_t * const); + +static void lmc_dummy_set_1 (lmc_softc_t * const, int); +static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *); + +static inline void write_av9110_bit (lmc_softc_t *, int); +static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t, + u_int32_t, u_int32_t); + +lmc_media_t lmc_ds3_media = { + lmc_ds3_init, /* special media init stuff */ + lmc_ds3_default, /* reset to default state */ + lmc_ds3_set_status, /* reset status to state provided */ + lmc_dummy_set_1, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_ds3_set_100ft, /* set cable length */ + lmc_ds3_set_scram, /* set scrambler */ + lmc_ds3_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_ds3_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ds3_watchdog +}; + +lmc_media_t lmc_hssi_media = { + lmc_hssi_init, /* special media init stuff */ + lmc_hssi_default, /* reset to default state */ + lmc_hssi_set_status, /* reset status to state provided */ + lmc_hssi_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_hssi_get_link_status, /* get link status */ + lmc_hssi_set_link_status, /* set link status */ + lmc_hssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_hssi_watchdog +}; + +lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ + lmc_ssi_default, /* reset to default state */ + lmc_ssi_set_status, /* reset status to state provided */ + lmc_ssi_set_clock, /* set clock source */ + lmc_ssi_set_speed, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_ssi_get_link_status, /* get link status */ + lmc_ssi_set_link_status, /* set link status */ + lmc_ssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ssi_watchdog +}; + +lmc_media_t lmc_t1_media = { + lmc_t1_init, /* special media init stuff */ + lmc_t1_default, /* reset to default state */ + lmc_t1_set_status, /* reset status to state provided */ + lmc_t1_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_t1_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_t1_set_crc_length, /* set CRC length */ + lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + lmc_t1_watchdog +}; + +static void +lmc_dummy_set_1 (lmc_softc_t * const sc, int a) +{ +} + +static void +lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a) +{ +} + +/* + * HSSI methods + */ + +static void +lmc_hssi_init (lmc_softc_t * const sc) +{ + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200; + + lmc_gpio_mkoutput (sc, LMC_GEP_HSSI_CLOCK); +} + +static void +lmc_hssi_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in clock source + */ + if (ctl->clock_source && !sc->ictl.clock_source) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT; + } + else if (!ctl->clock_source && sc->ictl.clock_source) + { + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + } + + lmc_set_protocol (sc, ctl); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_hssi_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = sc->ictl.clock_source; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_hssi_get_link_status (lmc_softc_t * const sc) +{ + /* + * We're using the same code as SSI since + * they're practically the same + */ + return lmc_ssi_get_link_status(sc); +} + +static void +lmc_hssi_set_link_status (lmc_softc_t * const sc, int state) +{ + if (state == LMC_LINK_UP) + sc->lmc_miireg16 |= LMC_MII16_HSSI_TA; + else + sc->lmc_miireg16 &= ~LMC_MII16_HSSI_TA; + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_hssi_watchdog (lmc_softc_t * const sc) +{ + /* HSSI is blank */ +} + +/* + * DS3 methods + */ + +/* + * Set cable length + */ +static void +lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT) + { + sc->lmc_miireg16 &= ~LMC_MII16_DS3_ZERO; + sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_GT_100FT; + } + else if (ie == LMC_CTL_CABLE_LENGTH_LT_100FT) + { + sc->lmc_miireg16 |= LMC_MII16_DS3_ZERO; + sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_LT_100FT; + } + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_ds3_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_cable_length (sc, LMC_CTL_CABLE_LENGTH_LT_100FT); + sc->lmc_media->set_scrambler (sc, LMC_CTL_OFF); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_cable_length (sc, sc->ictl.cable_length); + sc->lmc_media->set_scrambler (sc, sc->ictl.scrambler_onoff); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in cable length setting + */ + if (ctl->cable_length && !sc->ictl.cable_length) + lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_GT_100FT); + else if (!ctl->cable_length && sc->ictl.cable_length) + lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_LT_100FT); + + /* + * Check for change in scrambler setting (requires reset) + */ + if (ctl->scrambler_onoff && !sc->ictl.scrambler_onoff) + lmc_ds3_set_scram (sc, LMC_CTL_ON); + else if (!ctl->scrambler_onoff && sc->ictl.scrambler_onoff) + lmc_ds3_set_scram (sc, LMC_CTL_OFF); + + lmc_set_protocol (sc, ctl); +} + +static void +lmc_ds3_init (lmc_softc_t * const sc) +{ + int i; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5245; + + /* writes zeros everywhere */ + for (i = 0; i < 21; i++) + { + lmc_mii_writereg (sc, 0, 17, i); + lmc_mii_writereg (sc, 0, 18, 0); + } + + /* set some essential bits */ + lmc_mii_writereg (sc, 0, 17, 1); + lmc_mii_writereg (sc, 0, 18, 0x25); /* ser, xtx */ + + lmc_mii_writereg (sc, 0, 17, 5); + lmc_mii_writereg (sc, 0, 18, 0x80); /* emode */ + + lmc_mii_writereg (sc, 0, 17, 14); + lmc_mii_writereg (sc, 0, 18, 0x30); /* rcgen, tcgen */ + + /* clear counters and latched bits */ + for (i = 0; i < 21; i++) + { + lmc_mii_writereg (sc, 0, 17, i); + lmc_mii_readreg (sc, 0, 18); + } +} + +/* + * 1 == DS3 payload scrambled, 0 == not scrambled + */ +static void +lmc_ds3_set_scram (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_ON) + { + sc->lmc_miireg16 |= LMC_MII16_DS3_SCRAM; + sc->ictl.scrambler_onoff = LMC_CTL_ON; + } + else + { + sc->lmc_miireg16 &= ~LMC_MII16_DS3_SCRAM; + sc->ictl.scrambler_onoff = LMC_CTL_OFF; + } + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_ds3_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status, link_status_11; + int ret = 1; + + lmc_mii_writereg (sc, 0, 17, 7); + link_status = lmc_mii_readreg (sc, 0, 18); + + /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions + * led0 yellow = far-end adapter is in Red alarm condition + * led1 blue = received an Alarm Indication signal + * (upstream failure) + * led2 Green = power to adapter, Gate Array loaded & driver + * attached + * led3 red = Loss of Signal (LOS) or out of frame (OOF) + * conditions detected on T3 receive signal + */ + + lmc_led_on(sc, LMC_DS3_LED2); + + if ((link_status & LMC_FRAMER_REG0_DLOS) || + (link_status & LMC_FRAMER_REG0_OOFS)){ + ret = 0; + if(sc->last_led_err[3] != 1){ + u16 r1; + lmc_mii_writereg (sc, 0, 17, 01); /* Turn on Xbit error as our cisco does */ + r1 = lmc_mii_readreg (sc, 0, 18); + r1 &= 0xfe; + lmc_mii_writereg(sc, 0, 18, r1); + printk(KERN_WARNING "%s: Red Alarm - Loss of Signal or Loss of Framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); /* turn on red LED */ + sc->last_led_err[3] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED3); /* turn on red LED */ + if(sc->last_led_err[3] == 1){ + u16 r1; + lmc_mii_writereg (sc, 0, 17, 01); /* Turn off Xbit error */ + r1 = lmc_mii_readreg (sc, 0, 18); + r1 |= 0x01; + lmc_mii_writereg(sc, 0, 18, r1); + } + sc->last_led_err[3] = 0; + } + + lmc_mii_writereg(sc, 0, 17, 0x10); + link_status_11 = lmc_mii_readreg(sc, 0, 18); + if((link_status & LMC_FRAMER_REG0_AIS) || + (link_status_11 & LMC_FRAMER_REG10_XBIT)) { + ret = 0; + if(sc->last_led_err[0] != 1){ + printk(KERN_WARNING "%s: AIS Alarm or XBit Error\n", sc->name); + printk(KERN_WARNING "%s: Remote end has loss of signal or framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 0; + } + + lmc_mii_writereg (sc, 0, 17, 9); + link_status = lmc_mii_readreg (sc, 0, 18); + + if(link_status & LMC_FRAMER_REG9_RBLUE){ + ret = 0; + if(sc->last_led_err[1] != 1){ + printk(KERN_WARNING "%s: Blue Alarm - Receiving all 1's\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 0; + } + + return ret; +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_DS3_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_ds3_watchdog (lmc_softc_t * const sc) +{ + +} + + +/* + * SSI methods + */ + +static void +lmc_ssi_init (lmc_softc_t * const sc) +{ + u_int16_t mii17; + int cable; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1000; + + mii17 = lmc_mii_readreg (sc, 0, 17); + + cable = (mii17 & LMC_MII17_SSI_CABLE_MASK) >> LMC_MII17_SSI_CABLE_SHIFT; + sc->ictl.cable_type = cable; + + lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK); +} + +static void +lmc_ssi_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + /* + * make TXCLOCK always be an output + */ + lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK); + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_media->set_speed (sc, NULL); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source); + sc->lmc_media->set_speed (sc, &sc->ictl); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in clock source + */ + if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_INT + && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT; + } + else if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_EXT + && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_INT) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + } + + if (ctl->clock_rate != sc->ictl.clock_rate) + sc->lmc_media->set_speed (sc, ctl); + + lmc_set_protocol (sc, ctl); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_ssi_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = ie; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(ie != old) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(ie != old) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +static void +lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + lmc_ctl_t *ictl = &sc->ictl; + lmc_av9110_t *av; + + /* original settings for clock rate of: + * 100 Khz (8,25,0,0,2) were incorrect + * they should have been 80,125,1,3,3 + * There are 17 param combinations to produce this freq. + * For 1.5 Mhz use 120,100,1,1,2 (226 param. combinations) + */ + if (ctl == NULL) + { + av = &ictl->cardspec.ssi; + ictl->clock_rate = 1500000; + av->f = ictl->clock_rate; + av->n = 120; + av->m = 100; + av->v = 1; + av->x = 1; + av->r = 2; + + write_av9110 (sc, av->n, av->m, av->v, av->x, av->r); + return; + } + + av = &ctl->cardspec.ssi; + + if (av->f == 0) + return; + + ictl->clock_rate = av->f; /* really, this is the rate we are */ + ictl->cardspec.ssi = *av; + + write_av9110 (sc, av->n, av->m, av->v, av->x, av->r); +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_ssi_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status; + u_int32_t ticks; + int ret = 1; + int hw_hdsk = 1; + + /* + * missing CTS? Hmm. If we require CTS on, we may never get the + * link to come up, so omit it in this test. + * + * Also, it seems that with a loopback cable, DCD isn't asserted, + * so just check for things like this: + * DSR _must_ be asserted. + * One of DCD or CTS must be asserted. + */ + + /* LMC 1000 (SSI) LED definitions + * led0 Green = power to adapter, Gate Array loaded & + * driver attached + * led1 Green = DSR and DTR and RTS and CTS are set + * led2 Green = Cable detected + * led3 red = No timing is available from the + * cable or the on-board frequency + * generator. + */ + + link_status = lmc_mii_readreg (sc, 0, 16); + + /* Is the transmit clock still available */ + ticks = LMC_CSR_READ (sc, csr_gp_timer); + ticks = 0x0000ffff - (ticks & 0x0000ffff); + + lmc_led_on (sc, LMC_MII16_LED0); + + /* ====== transmit clock determination ===== */ + if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_INT) { + lmc_led_off(sc, LMC_MII16_LED3); + } + else if (ticks == 0 ) { /* no clock found ? */ + ret = 0; + if(sc->last_led_err[3] != 1){ + sc->stats.tx_lossOfClockCnt++; + printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name); + } + sc->last_led_err[3] = 1; + lmc_led_on (sc, LMC_MII16_LED3); /* turn ON red LED */ + } + else { + if(sc->last_led_err[3] == 1) + printk(KERN_WARNING "%s: Clock Returned\n", sc->name); + sc->last_led_err[3] = 0; + lmc_led_off (sc, LMC_MII16_LED3); /* turn OFF red LED */ + } + + if ((link_status & LMC_MII16_SSI_DSR) == 0) { /* Also HSSI CA */ + ret = 0; + hw_hdsk = 0; + } + +#ifdef CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE + if ((link_status & (LMC_MII16_SSI_CTS | LMC_MII16_SSI_DCD)) == 0){ + ret = 0; + hw_hdsk = 0; + } +#endif + + if(hw_hdsk == 0){ + if(sc->last_led_err[1] != 1) + printk(KERN_WARNING "%s: DSR not asserted\n", sc->name); + sc->last_led_err[1] = 1; + lmc_led_off(sc, LMC_MII16_LED1); + } + else { + if(sc->last_led_err[1] != 0) + printk(KERN_WARNING "%s: DSR now asserted\n", sc->name); + sc->last_led_err[1] = 0; + lmc_led_on(sc, LMC_MII16_LED1); + } + + if(ret == 1) { + lmc_led_on(sc, LMC_MII16_LED2); /* Over all good status? */ + } + + return ret; +} + +static void +lmc_ssi_set_link_status (lmc_softc_t * const sc, int state) +{ + if (state == LMC_LINK_UP) + { + sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS); + printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS); + printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS); + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); + +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_SSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4; + + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_SSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * These are bits to program the ssi frequency generator + */ +static inline void +write_av9110_bit (lmc_softc_t * sc, int c) +{ + /* + * set the data bit as we need it. + */ + sc->lmc_gpio &= ~(LMC_GEP_CLK); + if (c & 0x01) + sc->lmc_gpio |= LMC_GEP_DATA; + else + sc->lmc_gpio &= ~(LMC_GEP_DATA); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * set the clock to high + */ + sc->lmc_gpio |= LMC_GEP_CLK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * set the clock to low again. + */ + sc->lmc_gpio &= ~(LMC_GEP_CLK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); +} + +static void +write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v, + u_int32_t x, u_int32_t r) +{ + int i; + +#if 0 + printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n", + LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r); +#endif + + sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR; + sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK + * as outputs. + */ + lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK + | LMC_GEP_SSI_GENERATOR)); + + sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * a shifting we will go... + */ + for (i = 0; i < 7; i++) + write_av9110_bit (sc, n >> i); + for (i = 0; i < 7; i++) + write_av9110_bit (sc, m >> i); + for (i = 0; i < 1; i++) + write_av9110_bit (sc, v >> i); + for (i = 0; i < 2; i++) + write_av9110_bit (sc, x >> i); + for (i = 0; i < 2; i++) + write_av9110_bit (sc, r >> i); + for (i = 0; i < 5; i++) + write_av9110_bit (sc, 0x17 >> i); + + /* + * stop driving serial-related signals + */ + lmc_gpio_mkinput (sc, + (LMC_GEP_DATA | LMC_GEP_CLK + | LMC_GEP_SSI_GENERATOR)); +} + +static void +lmc_ssi_watchdog (lmc_softc_t * const sc) +{ + u_int16_t mii17; + struct ssicsr2 + { + unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1, + led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1; + }; + struct ssicsr2 *ssicsr; + mii17 = lmc_mii_readreg (sc, 0, 17); + ssicsr = (struct ssicsr2 *) &mii17; + if (ssicsr->cable == 7) + { + lmc_led_off (sc, LMC_MII16_LED2); + } + else + { + lmc_led_on (sc, LMC_MII16_LED2); + } + +} + +/* + * T1 methods + */ + +/* + * The framer regs are multiplexed through MII regs 17 & 18 + * write the register address to MII reg 17 and the * data to MII reg 18. */ +static void +lmc_t1_write (lmc_softc_t * const sc, int a, int d) +{ + lmc_mii_writereg (sc, 0, 17, a); + lmc_mii_writereg (sc, 0, 18, d); +} + +/* Save a warning +static int +lmc_t1_read (lmc_softc_t * const sc, int a) +{ + lmc_mii_writereg (sc, 0, 17, a); + return lmc_mii_readreg (sc, 0, 18); +} +*/ + + +static void +lmc_t1_init (lmc_softc_t * const sc) +{ + u_int16_t mii16; + int i; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200; + mii16 = lmc_mii_readreg (sc, 0, 16); + + /* reset 8370 */ + mii16 &= ~LMC_MII16_T1_RST; + lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST); + lmc_mii_writereg (sc, 0, 16, mii16); + + /* set T1 or E1 line. Uses sc->lmcmii16 reg in function so update it */ + sc->lmc_miireg16 = mii16; + lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1); + mii16 = sc->lmc_miireg16; + + lmc_t1_write (sc, 0x01, 0x1B); /* CR0 - primary control */ + lmc_t1_write (sc, 0x02, 0x42); /* JAT_CR - jitter atten config */ + lmc_t1_write (sc, 0x14, 0x00); /* LOOP - loopback config */ + lmc_t1_write (sc, 0x15, 0x00); /* DL3_TS - external data link timeslot */ + lmc_t1_write (sc, 0x18, 0xFF); /* PIO - programmable I/O */ + lmc_t1_write (sc, 0x19, 0x30); /* POE - programmable OE */ + lmc_t1_write (sc, 0x1A, 0x0F); /* CMUX - clock input mux */ + lmc_t1_write (sc, 0x20, 0x41); /* LIU_CR - RX LIU config */ + lmc_t1_write (sc, 0x22, 0x76); /* RLIU_CR - RX LIU config */ + lmc_t1_write (sc, 0x40, 0x03); /* RCR0 - RX config */ + lmc_t1_write (sc, 0x45, 0x00); /* RALM - RX alarm config */ + lmc_t1_write (sc, 0x46, 0x05); /* LATCH - RX alarm/err/cntr latch */ + lmc_t1_write (sc, 0x68, 0x40); /* TLIU_CR - TX LIU config */ + lmc_t1_write (sc, 0x70, 0x0D); /* TCR0 - TX framer config */ + lmc_t1_write (sc, 0x71, 0x05); /* TCR1 - TX config */ + lmc_t1_write (sc, 0x72, 0x0B); /* TFRM - TX frame format */ + lmc_t1_write (sc, 0x73, 0x00); /* TERROR - TX error insert */ + lmc_t1_write (sc, 0x74, 0x00); /* TMAN - TX manual Sa/FEBE config */ + lmc_t1_write (sc, 0x75, 0x00); /* TALM - TX alarm signal config */ + lmc_t1_write (sc, 0x76, 0x00); /* TPATT - TX test pattern config */ + lmc_t1_write (sc, 0x77, 0x00); /* TLB - TX inband loopback config */ + lmc_t1_write (sc, 0x90, 0x05); /* CLAD_CR - clock rate adapter config */ + lmc_t1_write (sc, 0x91, 0x05); /* CSEL - clad freq sel */ + lmc_t1_write (sc, 0xA6, 0x00); /* DL1_CTL - DL1 control */ + lmc_t1_write (sc, 0xB1, 0x00); /* DL2_CTL - DL2 control */ + lmc_t1_write (sc, 0xD0, 0x47); /* SBI_CR - sys bus iface config */ + lmc_t1_write (sc, 0xD1, 0x70); /* RSB_CR - RX sys bus config */ + lmc_t1_write (sc, 0xD4, 0x30); /* TSB_CR - TX sys bus config */ + for (i = 0; i < 32; i++) + { + lmc_t1_write (sc, 0x0E0 + i, 0x00); /* SBCn - sys bus per-channel ctl */ + lmc_t1_write (sc, 0x100 + i, 0x00); /* TPCn - TX per-channel ctl */ + lmc_t1_write (sc, 0x180 + i, 0x00); /* RPCn - RX per-channel ctl */ + } + for (i = 1; i < 25; i++) + { + lmc_t1_write (sc, 0x0E0 + i, 0x0D); /* SBCn - sys bus per-channel ctl */ + } + + mii16 |= LMC_MII16_T1_XOE; + lmc_mii_writereg (sc, 0, 16, mii16); + sc->lmc_miireg16 = mii16; +} + +static void +lmc_t1_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); + /* Right now we can only clock from out internal source */ + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; +} +/* * Given a user provided state, set ourselves up to match it. This will * always reset the card if needed. + */ +static void +lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_circuit_type (sc, sc->ictl.circuit_type); + lmc_set_protocol (sc, NULL); + + return; + } + /* + * check for change in circuit type */ + if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_T1 + && sc->ictl.circuit_type == + LMC_CTL_CIRCUIT_TYPE_E1) sc->lmc_media->set_circuit_type (sc, + LMC_CTL_CIRCUIT_TYPE_E1); + else if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_E1 + && sc->ictl.circuit_type == LMC_CTL_CIRCUIT_TYPE_T1) + sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1); + lmc_set_protocol (sc, ctl); +} +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ static int +lmc_t1_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status; + int ret = 1; + + /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions + * led0 yellow = far-end adapter is in Red alarm condition + * led1 blue = received an Alarm Indication signal + * (upstream failure) + * led2 Green = power to adapter, Gate Array loaded & driver + * attached + * led3 red = Loss of Signal (LOS) or out of frame (OOF) + * conditions detected on T3 receive signal + */ + lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in"); + lmc_led_on(sc, LMC_DS3_LED2); + + lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS); + link_status = lmc_mii_readreg (sc, 0, 18); + + + if (link_status & T1F_RAIS) { /* turn on blue LED */ + ret = 0; + if(sc->last_led_err[1] != 1){ + printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 1; + } + else { + if(sc->last_led_err[1] != 0){ + printk(KERN_WARNING "%s: End AIS/Blue Alarm\n", sc->name); + } + lmc_led_off (sc, LMC_DS3_LED1); + sc->last_led_err[1] = 0; + } + + /* + * Yellow Alarm is nasty evil stuff, looks at data patterns + * inside the channel and confuses it with HDLC framing + * ignore all yellow alarms. + * + * Do listen to MultiFrame Yellow alarm which while implemented + * different ways isn't in the channel and hence somewhat + * more reliable + */ + + if (link_status & T1F_RMYEL) { + ret = 0; + if(sc->last_led_err[0] != 1){ + printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 1; + } + else { + if(sc->last_led_err[0] != 0){ + printk(KERN_WARNING "%s: End of Yellow AIS Alarm\n", sc->name); + } + lmc_led_off(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 0; + } + + /* + * Loss of signal and los of frame + * Use the green bit to identify which one lit the led + */ + if(link_status & T1F_RLOF){ + ret = 0; + if(sc->last_led_err[3] != 1){ + printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); + sc->last_led_err[3] = 1; + + } + else { + if(sc->last_led_err[3] != 0){ + printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name); + } + if( ! (link_status & T1F_RLOS)) + lmc_led_off(sc, LMC_DS3_LED3); + sc->last_led_err[3] = 0; + } + + if(link_status & T1F_RLOS){ + ret = 0; + if(sc->last_led_err[2] != 1){ + printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); + sc->last_led_err[2] = 1; + + } + else { + if(sc->last_led_err[2] != 0){ + printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name); + } + if( ! (link_status & T1F_RLOF)) + lmc_led_off(sc, LMC_DS3_LED3); + sc->last_led_err[2] = 0; + } + + sc->lmc_xinfo.t1_alarm1_status = link_status; + + lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS); + sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18); + + + lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out"); + + return ret; +} + +/* + * 1 == T1 Circuit Type , 0 == E1 Circuit Type + */ +static void +lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_CIRCUIT_TYPE_T1) { + sc->lmc_miireg16 |= LMC_MII16_T1_Z; + sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1; + printk(KERN_INFO "%s: In T1 Mode\n", sc->name); + } + else { + sc->lmc_miireg16 &= ~LMC_MII16_T1_Z; + sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1; + printk(KERN_INFO "%s: In E1 Mode\n", sc->name); + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); + +} + +/* + * 0 == 16bit, 1 == 32bit */ +static void +lmc_t1_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_T1_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4; + + } + else + { + /* 16 bit */ sc->lmc_miireg16 &= ~LMC_MII16_T1_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2; + + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_t1_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = ie; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +static void +lmc_t1_watchdog (lmc_softc_t * const sc) +{ +} + +static void +lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == 0) + { + sc->ictl.keepalive_onoff = LMC_CTL_ON; + + return; + } +} diff --git a/drivers/net/wan/lmc/lmc_media.h b/drivers/net/wan/lmc/lmc_media.h new file mode 100644 index 000000000000..7cc6c1650ffc --- /dev/null +++ b/drivers/net/wan/lmc/lmc_media.h @@ -0,0 +1,64 @@ +#ifndef _LMC_MEDIA_H_ +#define _LMC_MEDIA_H_ + +lmc_media_t lmc_ds3_media = { + lmc_ds3_init, /* special media init stuff */ + lmc_ds3_default, /* reset to default state */ + lmc_ds3_set_status, /* reset status to state provided */ + lmc_dummy_set_1, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_ds3_set_100ft, /* set cable length */ + lmc_ds3_set_scram, /* set scrambler */ + lmc_ds3_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_ds3_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ds3_watchdog +}; + +lmc_media_t lmc_hssi_media = { + lmc_hssi_init, /* special media init stuff */ + lmc_hssi_default, /* reset to default state */ + lmc_hssi_set_status, /* reset status to state provided */ + lmc_hssi_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_hssi_get_link_status, /* get link status */ + lmc_hssi_set_link_status, /* set link status */ + lmc_hssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_hssi_watchdog +}; + +lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ + lmc_ssi_default, /* reset to default state */ + lmc_ssi_set_status, /* reset status to state provided */ + lmc_ssi_set_clock, /* set clock source */ + lmc_ssi_set_speed, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_ssi_get_link_status, /* get link status */ + lmc_ssi_set_link_status, /* set link status */ + lmc_ssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ssi_watchdog +}; + +lmc_media_t lmc_t1_media = { + lmc_t1_init, /* special media init stuff */ + lmc_t1_default, /* reset to default state */ + lmc_t1_set_status, /* reset status to state provided */ + lmc_t1_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_t1_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_t1_set_crc_length, /* set CRC length */ + lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + lmc_t1_watchdog +}; + + +#endif \ No newline at end of file diff --git a/drivers/net/wan/lmc/lmc_prot.h b/drivers/net/wan/lmc/lmc_prot.h new file mode 100644 index 000000000000..859ef0f006a1 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_prot.h @@ -0,0 +1,14 @@ +#ifndef _LMC_PROTO_H_ +#define _LMC_PROTO_H_ + +void lmc_proto_init(lmc_softc_t * const) +void lmc_proto_attach(lmc_softc_t *sc const) +void lmc_proto_detach(lmc_softc *sc const) +void lmc_proto_reopen(lmc_softc_t *sc const) +int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd) +void lmc_proto_open(lmc_softc_t *sc const) +void lmc_proto_close(lmc_softc_t *sc const) +unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb) + + +#endif \ No newline at end of file diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c new file mode 100644 index 000000000000..c15104f6a4d2 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -0,0 +1,270 @@ + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * With Help By: + * David Boggs + * Ron Crane + * Allan Cox + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + * + * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include +#include +#include + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_debug.h" +#include "lmc_ioctl.h" +#include "lmc_proto.h" +//#include "lmc_proto_raw.h" + +/* + * The compile-time variable SPPPSTUP causes the module to be + * compiled without referencing any of the sync ppp routines. + */ +#ifdef SPPPSTUB +#define SYNC_PPP_init() (void)0 +#define SPPP_detach(d) (void)0 +#define SPPP_open(d) 0 +#define SPPP_reopen(d) (void)0 +#define SPPP_close(d) (void)0 +#define SPPP_attach(d) (void)0 +#define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP +#else +#if LINUX_VERSION_CODE < 0x20363 +#define SYNC_PPP_init sync_ppp_init +#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device) +#define SPPP_detach(x) sppp_detach((x)->lmc_device) +#define SPPP_open(x) sppp_open((x)->lmc_device) +#define SPPP_reopen(x) sppp_reopen((x)->lmc_device) +#define SPPP_close(x) sppp_close((x)->lmc_device) +#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z)) +#else +#define SYNC_PPP_init sync_ppp_init +#define SPPP_attach(x) sppp_attach((x)->pd) +#define SPPP_detach(x) sppp_detach((x)->pd->dev) +#define SPPP_open(x) sppp_open((x)->pd->dev) +#define SPPP_reopen(x) sppp_reopen((x)->pd->dev) +#define SPPP_close(x) sppp_close((x)->pd->dev) +#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z)) +#endif +#endif + +static int lmc_first_ppp_load = 0; + +// init +void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_init in"); + switch(sc->if_type){ + case LMC_PPP: + if(lmc_first_ppp_load == 0) +#ifndef MODULE + SYNC_PPP_init(); +#endif + +#if LINUX_VERSION_CODE >= 0x20363 + sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + sc->pd->dev = sc->lmc_device; +#endif + sc->if_ptr = sc->pd; + break; + case LMC_RAW: + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_init out"); +} + +// attach +void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_attach in"); + switch(sc->if_type){ + case LMC_PPP: + { + struct net_device *dev = sc->lmc_device; + SPPP_attach(sc); + dev->do_ioctl = lmc_ioctl; + } + break; + case LMC_NET: + { + struct net_device *dev = sc->lmc_device; + /* + * They set a few basics because they don't use sync_ppp + */ + dev->flags |= IFF_POINTOPOINT; + dev->hard_header = 0; + dev->hard_header_len = 0; + dev->addr_len = 0; + } + case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */ + { + } + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_attach out"); +} + +// detach +void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/ +{ + switch(sc->if_type){ + case LMC_PPP: + SPPP_detach(sc); + break; + case LMC_RAW: /* Tell someone we're detaching? */ + break; + default: + break; + } + +} + +// reopen +void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_reopen in"); + switch(sc->if_type){ + case LMC_PPP: + SPPP_reopen(sc); + break; + case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_reopen out"); +} + + +// ioctl +int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_ioctl out"); + switch(sc->if_type){ + case LMC_PPP: + return SPPP_do_ioctl (sc, ifr, cmd); + break; + default: + return -EOPNOTSUPP; + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_ioctl out"); +} + +// open +void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/ +{ + int ret; + + lmc_trace(sc->lmc_device, "lmc_proto_open in"); + switch(sc->if_type){ + case LMC_PPP: + ret = SPPP_open(sc); + if(ret < 0) + printk("%s: syncPPP open failed: %d\n", sc->name, ret); + break; + case LMC_RAW: /* We're about to start getting packets! */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_open out"); +} + +// close + +void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_close in"); + switch(sc->if_type){ + case LMC_PPP: + SPPP_close(sc); + break; + case LMC_RAW: /* Interface going down */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_close out"); +} + +unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_type in"); + switch(sc->if_type){ + case LMC_PPP: + return htons(ETH_P_WAN_PPP); + break; + case LMC_NET: + return htons(ETH_P_802_2); + break; + case LMC_RAW: /* Packet type for skbuff kind of useless */ + return htons(ETH_P_802_2); + break; + default: + printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name); + return htons(ETH_P_802_2); + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_tye out"); + +} + +void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_netif in"); + switch(sc->if_type){ + case LMC_PPP: + case LMC_NET: + default: + netif_rx(skb); + break; + case LMC_RAW: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_netif out"); +} + diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h new file mode 100644 index 000000000000..6136dfad7516 --- /dev/null +++ b/drivers/net/wan/lmc/lmc_proto.h @@ -0,0 +1,15 @@ +#ifndef _LMC_PROTO_H_ +#define _LMC_PROTO_H_ + +void lmc_proto_init(lmc_softc_t *sc); +void lmc_proto_attach(lmc_softc_t *sc); +void lmc_proto_detach(lmc_softc_t *sc); +void lmc_proto_reopen(lmc_softc_t *sc); +int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd); +void lmc_proto_open(lmc_softc_t *sc); +void lmc_proto_close(lmc_softc_t *sc); +unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb); +void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb); +int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused); + +#endif \ No newline at end of file diff --git a/drivers/net/wan/lmc/lmc_proto_raw.h b/drivers/net/wan/lmc/lmc_proto_raw.h new file mode 100644 index 000000000000..c07c0b3302ba --- /dev/null +++ b/drivers/net/wan/lmc/lmc_proto_raw.h @@ -0,0 +1,4 @@ +#ifndef _LMC_PROTO_RAW_H_ +#define _LMC_PROTO_RAW_H_ + +#endif diff --git a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h new file mode 100644 index 000000000000..67215b93bfba --- /dev/null +++ b/drivers/net/wan/lmc/lmc_var.h @@ -0,0 +1,590 @@ +#ifndef _LMC_VAR_H_ +#define _LMC_VAR_H_ + +/* $Id: lmc_var.h,v 1.17 2000/04/06 12:16:47 asj Exp $ */ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +#include + +#ifndef __KERNEL__ +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +#endif + +/* + * basic definitions used in lmc include files + */ + +typedef struct lmc___softc lmc_softc_t; +typedef struct lmc___media lmc_media_t; +typedef struct lmc___ctl lmc_ctl_t; + +#define lmc_csrptr_t unsigned long +#define u_int16_t u16 +#define u_int8_t u8 +#define tulip_uint32_t u32 +#if LINUX_VERSION_CODE < 0x20155 +#define u_int32_t u32 +#endif + +#define LMC_REG_RANGE 0x80 + +#define LMC_PRINTF_FMT "%s" +#define LMC_PRINTF_ARGS (sc->lmc_device->name) + +#define TX_TIMEOUT (2*HZ) + +#define LMC_TXDESCS 32 +#define LMC_RXDESCS 32 + +#define LMC_LINK_UP 1 +#define LMC_LINK_DOWN 0 + +/* These macros for generic read and write to and from the dec chip */ +#define LMC_CSR_READ(sc, csr) \ + inl((sc)->lmc_csrs.csr) +#define LMC_CSR_WRITE(sc, reg, val) \ + outl((val), (sc)->lmc_csrs.reg) + +//#ifdef _LINUX_DELAY_H +// #define SLOW_DOWN_IO udelay(2); +// #undef __SLOW_DOWN_IO +// #define __SLOW_DOWN_IO udelay(2); +//#endif + +#define DELAY(n) SLOW_DOWN_IO + +#define lmc_delay() inl(sc->lmc_csrs.csr_9) + +/* This macro sync's up with the mii so that reads and writes can take place */ +#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \ + LMC_CSR_WRITE((sc), csr_9, 0x20000); \ + lmc_delay(); \ + LMC_CSR_WRITE((sc), csr_9, 0x30000); \ + lmc_delay(); \ + n--; }} while(0); + +struct lmc_regfile_t { + lmc_csrptr_t csr_busmode; /* CSR0 */ + lmc_csrptr_t csr_txpoll; /* CSR1 */ + lmc_csrptr_t csr_rxpoll; /* CSR2 */ + lmc_csrptr_t csr_rxlist; /* CSR3 */ + lmc_csrptr_t csr_txlist; /* CSR4 */ + lmc_csrptr_t csr_status; /* CSR5 */ + lmc_csrptr_t csr_command; /* CSR6 */ + lmc_csrptr_t csr_intr; /* CSR7 */ + lmc_csrptr_t csr_missed_frames; /* CSR8 */ + lmc_csrptr_t csr_9; /* CSR9 */ + lmc_csrptr_t csr_10; /* CSR10 */ + lmc_csrptr_t csr_11; /* CSR11 */ + lmc_csrptr_t csr_12; /* CSR12 */ + lmc_csrptr_t csr_13; /* CSR13 */ + lmc_csrptr_t csr_14; /* CSR14 */ + lmc_csrptr_t csr_15; /* CSR15 */ +}; + +#define csr_enetrom csr_9 /* 21040 */ +#define csr_reserved csr_10 /* 21040 */ +#define csr_full_duplex csr_11 /* 21040 */ +#define csr_bootrom csr_10 /* 21041/21140A/?? */ +#define csr_gp csr_12 /* 21140* */ +#define csr_watchdog csr_15 /* 21140* */ +#define csr_gp_timer csr_11 /* 21041/21140* */ +#define csr_srom_mii csr_9 /* 21041/21140* */ +#define csr_sia_status csr_12 /* 2104x */ +#define csr_sia_connectivity csr_13 /* 2104x */ +#define csr_sia_tx_rx csr_14 /* 2104x */ +#define csr_sia_general csr_15 /* 2104x */ + +/* tulip length/control transmit descriptor definitions + * used to define bits in the second tulip_desc_t field (length) + * for the transmit descriptor -baz */ + +#define LMC_TDES_FIRST_BUFFER_SIZE ((u_int32_t)(0x000007FF)) +#define LMC_TDES_SECOND_BUFFER_SIZE ((u_int32_t)(0x003FF800)) +#define LMC_TDES_HASH_FILTERING ((u_int32_t)(0x00400000)) +#define LMC_TDES_DISABLE_PADDING ((u_int32_t)(0x00800000)) +#define LMC_TDES_SECOND_ADDR_CHAINED ((u_int32_t)(0x01000000)) +#define LMC_TDES_END_OF_RING ((u_int32_t)(0x02000000)) +#define LMC_TDES_ADD_CRC_DISABLE ((u_int32_t)(0x04000000)) +#define LMC_TDES_SETUP_PACKET ((u_int32_t)(0x08000000)) +#define LMC_TDES_INVERSE_FILTERING ((u_int32_t)(0x10000000)) +#define LMC_TDES_FIRST_SEGMENT ((u_int32_t)(0x20000000)) +#define LMC_TDES_LAST_SEGMENT ((u_int32_t)(0x40000000)) +#define LMC_TDES_INTERRUPT_ON_COMPLETION ((u_int32_t)(0x80000000)) + +#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER 11 +#define TDES_COLLISION_COUNT_BIT_NUMBER 3 + +/* Constants for the RCV descriptor RDES */ + +#define LMC_RDES_OVERFLOW ((u_int32_t)(0x00000001)) +#define LMC_RDES_CRC_ERROR ((u_int32_t)(0x00000002)) +#define LMC_RDES_DRIBBLING_BIT ((u_int32_t)(0x00000004)) +#define LMC_RDES_REPORT_ON_MII_ERR ((u_int32_t)(0x00000008)) +#define LMC_RDES_RCV_WATCHDOG_TIMEOUT ((u_int32_t)(0x00000010)) +#define LMC_RDES_FRAME_TYPE ((u_int32_t)(0x00000020)) +#define LMC_RDES_COLLISION_SEEN ((u_int32_t)(0x00000040)) +#define LMC_RDES_FRAME_TOO_LONG ((u_int32_t)(0x00000080)) +#define LMC_RDES_LAST_DESCRIPTOR ((u_int32_t)(0x00000100)) +#define LMC_RDES_FIRST_DESCRIPTOR ((u_int32_t)(0x00000200)) +#define LMC_RDES_MULTICAST_FRAME ((u_int32_t)(0x00000400)) +#define LMC_RDES_RUNT_FRAME ((u_int32_t)(0x00000800)) +#define LMC_RDES_DATA_TYPE ((u_int32_t)(0x00003000)) +#define LMC_RDES_LENGTH_ERROR ((u_int32_t)(0x00004000)) +#define LMC_RDES_ERROR_SUMMARY ((u_int32_t)(0x00008000)) +#define LMC_RDES_FRAME_LENGTH ((u_int32_t)(0x3FFF0000)) +#define LMC_RDES_OWN_BIT ((u_int32_t)(0x80000000)) + +#define RDES_FRAME_LENGTH_BIT_NUMBER 16 + +#define LMC_RDES_ERROR_MASK ( (u_int32_t)( \ + LMC_RDES_OVERFLOW \ + | LMC_RDES_DRIBBLING_BIT \ + | LMC_RDES_REPORT_ON_MII_ERR \ + | LMC_RDES_COLLISION_SEEN ) ) + + +/* + * Ioctl info + */ + +typedef struct { + u_int32_t n; + u_int32_t m; + u_int32_t v; + u_int32_t x; + u_int32_t r; + u_int32_t f; + u_int32_t exact; +} lmc_av9110_t; + +/* + * Common structure passed to the ioctl code. + */ +struct lmc___ctl { + u_int32_t cardtype; + u_int32_t clock_source; /* HSSI, T1 */ + u_int32_t clock_rate; /* T1 */ + u_int32_t crc_length; + u_int32_t cable_length; /* DS3 */ + u_int32_t scrambler_onoff; /* DS3 */ + u_int32_t cable_type; /* T1 */ + u_int32_t keepalive_onoff; /* protocol */ + u_int32_t ticks; /* ticks/sec */ + union { + lmc_av9110_t ssi; + } cardspec; + u_int32_t circuit_type; /* T1 or E1 */ +}; + + +/* + * Carefull, look at the data sheet, there's more to this + * structure than meets the eye. It should probably be: + * + * struct tulip_desc_t { + * u8 own:1; + * u32 status:31; + * u32 control:10; + * u32 buffer1; + * u32 buffer2; + * }; + * You could also expand status control to provide more bit information + */ + +struct tulip_desc_t { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; +}; + +/* + * media independent methods to check on media status, link, light LEDs, + * etc. + */ +struct lmc___media { + void (* init)(lmc_softc_t * const); + void (* defaults)(lmc_softc_t * const); + void (* set_status)(lmc_softc_t * const, lmc_ctl_t *); + void (* set_clock_source)(lmc_softc_t * const, int); + void (* set_speed)(lmc_softc_t * const, lmc_ctl_t *); + void (* set_cable_length)(lmc_softc_t * const, int); + void (* set_scrambler)(lmc_softc_t * const, int); + int (* get_link_status)(lmc_softc_t * const); + void (* set_link_status)(lmc_softc_t * const, int); + void (* set_crc_length)(lmc_softc_t * const, int); + void (* set_circuit_type)(lmc_softc_t * const, int); + void (* watchdog)(lmc_softc_t * const); +}; + + +#define STATCHECK 0xBEEFCAFE + +/* Included in this structure are first + * - standard enet_statistics + * - some other counters used for debug and driver performance + * evaluation -baz + */ +struct lmc_statistics +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; + unsigned long tx_bytes; + + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; + + /* ------------------------------------- + * Custom stats & counters follow -baz */ + u_int32_t version_size; + u_int32_t lmc_cardtype; + + u_int32_t tx_ProcTimeout; + u_int32_t tx_IntTimeout; + u_int32_t tx_NoCompleteCnt; + u_int32_t tx_MaxXmtsB4Int; + u_int32_t tx_TimeoutCnt; + u_int32_t tx_OutOfSyncPtr; + u_int32_t tx_tbusy0; + u_int32_t tx_tbusy1; + u_int32_t tx_tbusy_calls; + u_int32_t resetCount; + u_int32_t lmc_txfull; + u_int32_t tbusy; + u_int32_t dirtyTx; + u_int32_t lmc_next_tx; + u_int32_t otherTypeCnt; + u_int32_t lastType; + u_int32_t lastTypeOK; + u_int32_t txLoopCnt; + u_int32_t usedXmtDescripCnt; + u_int32_t txIndexCnt; + u_int32_t rxIntLoopCnt; + + u_int32_t rx_SmallPktCnt; + u_int32_t rx_BadPktSurgeCnt; + u_int32_t rx_BuffAllocErr; + u_int32_t tx_lossOfClockCnt; + + /* T1 error counters */ + u_int32_t framingBitErrorCount; + u_int32_t lineCodeViolationCount; + + u_int32_t lossOfFrameCount; + u_int32_t changeOfFrameAlignmentCount; + u_int32_t severelyErroredFrameCount; + + u_int32_t check; +}; + + +typedef struct lmc_xinfo { + u_int32_t Magic0; /* BEEFCAFE */ + + u_int32_t PciCardType; + u_int32_t PciSlotNumber; /* PCI slot number */ + + u_int16_t DriverMajorVersion; + u_int16_t DriverMinorVersion; + u_int16_t DriverSubVersion; + + u_int16_t XilinxRevisionNumber; + u_int16_t MaxFrameSize; + + u_int16_t t1_alarm1_status; + u_int16_t t1_alarm2_status; + + int link_status; + u_int32_t mii_reg16; + + u_int32_t Magic1; /* DEADBEEF */ +} LMC_XINFO; + + +/* + * forward decl + */ +struct lmc___softc { + void *if_ptr; /* General purpose pointer (used by SPPP) */ + char *name; + u8 board_idx; + struct lmc_statistics stats; + struct net_device *lmc_device; + + int hang, rxdesc, bad_packet, some_counter; + u_int32_t txgo; + struct lmc_regfile_t lmc_csrs; + volatile u_int32_t lmc_txtick; + volatile u_int32_t lmc_rxtick; + u_int32_t lmc_flags; + u_int32_t lmc_intrmask; /* our copy of csr_intr */ + u_int32_t lmc_cmdmode; /* our copy of csr_cmdmode */ + u_int32_t lmc_busmode; /* our copy of csr_busmode */ + u_int32_t lmc_gpio_io; /* state of in/out settings */ + u_int32_t lmc_gpio; /* state of outputs */ + struct sk_buff* lmc_txq[LMC_TXDESCS]; + struct sk_buff* lmc_rxq[LMC_RXDESCS]; + volatile + struct tulip_desc_t lmc_rxring[LMC_RXDESCS]; + volatile + struct tulip_desc_t lmc_txring[LMC_TXDESCS]; + unsigned int lmc_next_rx, lmc_next_tx; + volatile + unsigned int lmc_taint_tx, lmc_taint_rx; + int lmc_tx_start, lmc_txfull; + int lmc_txbusy; + u_int16_t lmc_miireg16; + int lmc_ok; + int last_link_status; + int lmc_cardtype; + u_int32_t last_frameerr; + lmc_media_t *lmc_media; + struct timer_list timer; + lmc_ctl_t ictl; + u_int32_t TxDescriptControlInit; + struct net_device *next_module; /* Link to the next module */ + int tx_TimeoutInd; /* additional driver state */ + int tx_TimeoutDisplay; + unsigned int lastlmc_taint_tx; + int lasttx_packets; + u_int32_t tx_clockState; + u_int32_t lmc_crcSize; + LMC_XINFO lmc_xinfo; + char lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */ + char lmc_timing; /* for HSSI and SSI */ + int got_irq; + + char last_led_err[4]; + + u32 last_int; + u32 num_int; + +#if LINUX_VERSION_CODE >= 0x20200 + spinlock_t lmc_lock; +#endif + u_int16_t if_type; /* PPP or NET */ + struct ppp_device *pd; + + /* Failure cases */ + u8 failed_ring; + u8 failed_recv_alloc; + + /* Structure check */ + u32 check; +}; + +#define LMC_PCI_TIME 1 +#define LMC_EXT_TIME 0 + +#define PKT_BUF_SZ 1542 /* was 1536 */ + +/* CSR5 settings */ +#define TIMER_INT 0x00000800 +#define TP_LINK_FAIL 0x00001000 +#define TP_LINK_PASS 0x00000010 +#define NORMAL_INT 0x00010000 +#define ABNORMAL_INT 0x00008000 +#define RX_JABBER_INT 0x00000200 +#define RX_DIED 0x00000100 +#define RX_NOBUFF 0x00000080 +#define RX_INT 0x00000040 +#define TX_FIFO_UNDER 0x00000020 +#define TX_JABBER 0x00000008 +#define TX_NOBUFF 0x00000004 +#define TX_DIED 0x00000002 +#define TX_INT 0x00000001 + +/* CSR6 settings */ +#define OPERATION_MODE 0x00000200 /* Full Duplex */ +#define PROMISC_MODE 0x00000040 /* Promiscuous Mode */ +#define RECIEVE_ALL 0x40000000 /* Recieve All */ +#define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames */ + +/* Dec control registers CSR6 as well */ +#define LMC_DEC_ST 0x00002000 +#define LMC_DEC_SR 0x00000002 + +/* CSR15 settings */ +#define RECV_WATCHDOG_DISABLE 0x00000010 +#define JABBER_DISABLE 0x00000001 + +/* More settings */ +/* + * aSR6 -- Command (Operation Mode) Register + */ +#define TULIP_CMD_RECEIVEALL 0x40000000L /* (RW) Receivel all frames? */ +#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */ +#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */ +#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */ +#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */ +#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */ +#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */ +#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */ +#define TULIP_CMD_PROMISCUOUS 0x00000041L /* (RW) Promiscuous Mode */ +#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */ +#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */ + +#define TULIP_GP_PINSET 0x00000100L +#define TULIP_BUSMODE_SWRESET 0x00000001L +#define TULIP_WATCHDOG_TXDISABLE 0x00000001L +#define TULIP_WATCHDOG_RXDISABLE 0x00000010L + +#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ +#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ +#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interupt */ +#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ +#define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */ +#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interupt */ +#define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */ +#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */ +#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */ +#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */ +#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */ +#define TULIP_STS_TXJABER 0x00000008L /* (RW) Jabber timeout */ +#define TULIP_STS_TXNOBUF 0x00000004L +#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */ +#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */ + +#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */ + +#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */ +#define TULIP_STS_RXNOBUF 0x00000080L + +#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */ +#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */ +#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */ +#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = 21040) */ +#define TULIP_DSTS_RxMIIERR 0x00000008 +#define LMC_DSTS_ERRSUM (TULIP_DSTS_RxMIIERR) + +#define TULIP_DEFAULT_INTR_MASK (TULIP_STS_NORMALINTR \ + | TULIP_STS_RXINTR \ + | TULIP_STS_TXINTR \ + | TULIP_STS_ABNRMLINTR \ + | TULIP_STS_SYSERROR \ + | TULIP_STS_TXSTOPPED \ + | TULIP_STS_TXUNDERFLOW\ + | TULIP_STS_RXSTOPPED ) + +#define DESC_OWNED_BY_SYSTEM ((u_int32_t)(0x00000000)) +#define DESC_OWNED_BY_DC21X4 ((u_int32_t)(0x80000000)) + +#ifndef TULIP_CMD_RECEIVEALL +#define TULIP_CMD_RECEIVEALL 0x40000000L +#endif + + +/* PCI register values */ +#define CORRECT_VENDOR_ID 0x1011 +#define CORRECT_DEV_ID 9 + +#define PCI_VENDOR_LMC 0x1376 +#define PCI_PRODUCT_LMC_HSSI 0x0003 +#define PCI_PRODUCT_LMC_DS3 0x0004 +#define PCI_PRODUCT_LMC_SSI 0x0005 +#define PCI_PRODUCT_LMC_T1 0x0006 + +/* Adapcter module number */ +#define LMC_ADAP_HSSI 2 +#define LMC_ADAP_DS3 3 +#define LMC_ADAP_SSI 4 +#define LMC_ADAP_T1 5 + +#define HDLC_HDR_LEN 4 +#define HDLC_ADDR_LEN 1 +#define HDLC_SLARP 0x8035 +#define LMC_MTU 1500 +#define SLARP_LINECHECK 2 + +#define LMC_CRC_LEN_16 2 /* 16-bit CRC */ +#define LMC_CRC_LEN_32 4 + +#if LINUX_VERSION_CODE < 0x20100 +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif + +#ifdef LMC_HDLC +/* definition of an hdlc header. */ +struct hdlc_hdr +{ + u8 address; + u8 control; + u16 type; +}; + +/* definition of a slarp header. */ +struct slarp +{ + long code; + union sl + { + struct + { + ulong address; + ulong mask; + ushort unused; + } add; + struct + { + ulong mysequence; + ulong yoursequence; + ushort reliability; + ulong time; + } chk; + } t; +}; +#endif /* LMC_HDLC */ + + +#endif /* _LMC_VAR_H_ */ diff --git a/drivers/net/wan/lmc/lmc_ver.h b/drivers/net/wan/lmc/lmc_ver.h new file mode 100644 index 000000000000..1f382661726b --- /dev/null +++ b/drivers/net/wan/lmc/lmc_ver.h @@ -0,0 +1,123 @@ +#ifndef _IF_LMC_LINUXVER_ +#define _IF_LMC_LINUXVER_ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + + /* + * This file defines and controls all linux version + * differences. + * + * This is being done to keep 1 central location where all linux + * version differences can be kept and maintained. as this code was + * found version issues where pepered throughout the source code and + * made the souce code not only hard to read but version problems hard + * to track down. If I'm overiding a function/etc with something in + * this file it will be prefixed by "LMC_" which will mean look + * here for the the version dependant change that's been done. + * + */ + +#if LINUX_VERSION_CODE < 0x20363 +#define net_device device +#endif + +#if LINUX_VERSION_CODE < 0x20363 +#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1 +#define LMC_XMITTER_FREE(x) (x)->tbusy = 0 +#define LMC_XMITTER_INIT(x) (x)->tbusy = 0 +#else +#define LMC_XMITTER_BUSY(x) netif_stop_queue(x) +#define LMC_XMITTER_FREE(x) netif_wake_queue(x) +#define LMC_XMITTER_INIT(x) netif_start_queue(x) + +#endif + + +#if LINUX_VERSION_CODE < 0x20100 +//typedef unsigned int u_int32_t; + +#define LMC_SETUP_20_DEV {\ + int indx; \ + for (indx = 0; indx < DEV_NUMBUFFS; indx++) \ + skb_queue_head_init (&dev->buffs[indx]); \ + } \ + dev->family = AF_INET; \ + dev->pa_addr = 0; \ + dev->pa_brdaddr = 0; \ + dev->pa_mask = 0xFCFFFFFF; \ + dev->pa_alen = 4; /* IP addr. sizeof(u32) */ + +#else + +#define LMC_SETUP_20_DEV + +#endif + + +#if LINUX_VERSION_CODE < 0x20155 /* basically 2.2 plus */ + +#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb((skb), FREE_WRITE) +#define LMC_PCI_PRESENT() pcibios_present() + +#else /* Mostly 2.0 kernels */ + +#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb(skb) +#define LMC_PCI_PRESENT() pci_present() + +#endif + +#if LINUX_VERSION_CODE < 0x20200 +#else + +#endif + +#if LINUX_VERSION_CODE < 0x20100 +#define LMC_SKB_FREE(skb, val) (skb->free = val) +#else +#define LMC_SKB_FREE(skb, val) +#endif + + +#if (LINUX_VERSION_CODE >= 0x20200) + +#define LMC_SPIN_FLAGS unsigned long flags; +#define LMC_SPIN_LOCK_INIT(x) spin_lock_init(&(x)->lmc_lock); +#define LMC_SPIN_UNLOCK(x) ((x)->lmc_lock = SPIN_LOCK_UNLOCKED) +#define LMC_SPIN_LOCK_IRQSAVE(x) spin_lock_irqsave (&(x)->lmc_lock, flags); +#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags); +#else +#define LMC_SPIN_FLAGS +#define LMC_SPIN_LOCK_INIT(x) +#define LMC_SPIN_UNLOCK(x) +#define LMC_SPIN_LOCK_IRQSAVE(x) +#define LMC_SPIN_UNLOCK_IRQRESTORE(x) +#endif + + +#if LINUX_VERSION_CODE >= 0x20100 +#define LMC_COPY_FROM_USER(x, y, z) if(copy_from_user ((x), (y), (z))) return -EFAULT +#define LMC_COPY_TO_USER(x, y, z) if(copy_to_user ((x), (y), (z))) return -EFAULT +#else +#define LMC_COPY_FROM_USER(x, y, z) if(verify_area(VERIFY_READ, (y), (z))) \ + return -EFAULT; \ + memcpy_fromfs ((x), (y), (z)) + +#define LMC_COPY_TO_USER(x, y, z) if(verify_area(VERIFY_WRITE, (x), (z))) \ + return -EFAULT; \ + memcpy_tofs ((x), (y), (z)) +#endif + + +#endif diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c index 4bc7762cb9ff..62881254e26c 100644 --- a/drivers/net/wan/sdla_chdlc.c +++ b/drivers/net/wan/sdla_chdlc.c @@ -22,6 +22,7 @@ * Aug 07, 1998 David Fong Initial version. *****************************************************************************/ +#include #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ @@ -2762,7 +2763,7 @@ static void port_set_state (sdla_t *card, int state) void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); if (card->next){ spin_lock(&card->next->lock); @@ -2774,7 +2775,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP if (card->next){ spin_unlock(&card->next->lock); } diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 14257cc85e39..d7a246dd9966 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -109,6 +109,7 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -3677,13 +3678,13 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) { if (card->hw.type != SDLA_S514){ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); #else disable_irq(card->hw.irq); #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP else{ spin_lock(&card->lock); } @@ -3693,13 +3694,13 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) { if (card->hw.type != SDLA_S514){ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock_irqrestore(&card->lock, *smp_flags); #else enable_irq(card->hw.irq); #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP else{ spin_unlock(&card->lock); } diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c index 40134ff72393..f8c8fcae24ea 100644 --- a/drivers/net/wan/sdla_ppp.c +++ b/drivers/net/wan/sdla_ppp.c @@ -74,6 +74,7 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ @@ -2896,7 +2897,7 @@ static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); #else disable_irq(card->hw.irq); @@ -2905,7 +2906,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock_irqrestore(&card->lock, *smp_flags); #else enable_irq(card->hw.irq); diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c index 3565954e15b8..6d46b2e46060 100644 --- a/drivers/net/wan/sdlamain.c +++ b/drivers/net/wan/sdlamain.c @@ -391,7 +391,7 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf) if (!card->configured){ - #ifdef __SMP__ + #ifdef CONFIG_SMP /* Initialize the Spin lock */ printk(KERN_INFO "%s: Initializing SMP\n",wandev->name); spin_lock_init(&card->lock); @@ -825,13 +825,13 @@ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs) /* Use spin lock only for S508 */ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock(&card->lock); #endif sdla_intack(&card->hw); if (card->isr) card->isr(card); -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock(&card->lock); #endif diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index c57b59d4b9a4..1ee37e20ed7a 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -33,7 +33,7 @@ * * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 * - * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $ + * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $ */ #undef DEBUG @@ -395,7 +395,7 @@ static void sppp_keepalive (unsigned long dummy) if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ - printk (KERN_WARNING "%s: down\n", dev->name); + printk (KERN_WARNING "%s: protocol down\n", dev->name); if_down (dev); if (! (sp->pp_flags & PP_CISCO)) { /* Shut down the PPP link. */ @@ -529,7 +529,6 @@ badreq: sppp_ipcp_open (sp); break; case LCP_STATE_OPENED: -#if 0 /* Remote magic changed -- close session. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; @@ -537,7 +536,6 @@ badreq: sppp_lcp_open (sp); /* An ACK has already been sent. */ sp->lcp.state = LCP_STATE_ACK_SENT; -#endif break; } break; @@ -549,7 +547,7 @@ badreq: (dev->flags & IFF_UP)) { /* Coming out of loopback mode. */ sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: up\n", dev->name); + printk (KERN_INFO "%s: protocol up\n", dev->name); } switch (sp->lcp.state) { case LCP_STATE_CLOSED: @@ -716,7 +714,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) if (sp->pp_link_state==SPPP_LINK_DOWN && (dev->flags & IFF_UP)) { sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: up\n", dev->name); + printk (KERN_INFO "%s: protocol up\n", dev->name); } break; case CISCO_ADDR_REQ: diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index a86c83b7d8d5..17207612dd0d 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1418,7 +1418,6 @@ module_exit(yellowfin_cleanup); * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 9e11b6a82407..35fc7adca28c 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -4,7 +4,7 @@ # Maintained by Martin Mares # If you have any new entries, send them to the maintainer. # -# $Id: pci.ids,v 1.53 2000/03/09 08:19:20 mj Exp $ +# $Id: pci.ids,v 1.56 2000/04/17 16:11:58 mj Exp $ # # Vendors, devices and subsystems. Please keep sorted. @@ -18,7 +18,8 @@ 001a Ascend Communications, Inc. 0033 Paradyne corp. 003d Lockheed Martin-Marietta Corp -0070 Hauppage computer works Inc. +0070 Hauppauge computer works Inc. +0100 Ncipher Corp Ltd 0675 Dynalink 1700 IS64PH ISDN Adapter 1702 IS64PH ISDN Adapter @@ -34,7 +35,12 @@ 3034 QVision 1280/p 4000 4000 [Triflex] 6010 HotPlug PCI Bridge 6010 + 7020 USB Controller + a0ec Fibre Channel Host Controller + a0f0 Advanced System Management Controller a0f3 Triflex PCI to ISA Bridge + a0f7 PCI Hotplug Controller + a0f8 USB Open Host Controller ae10 Smart-2/P RAID Controller 0e11 4030 Smart-2/P Array Controller 0e11 4031 Smart-2SL Array Controller @@ -43,13 +49,16 @@ ae29 MIS-L ae2a MPC ae2b MIS-E + ae31 System Management Controller ae32 Netelligent 10/100 + ae33 Triflex Dual EIDE Controller ae34 Netelligent 10 ae35 Integrated NetFlex-3/P ae40 Netelligent 10/100 Dual ae43 ProLiant Integrated Netelligent 10/100 ae69 CETUS-L ae6c Northstar + ae6d NorthStar CPU to PCI Bridge b011 Integrated Netelligent 10/100 b012 Netelligent 10 T/2 b030 Netelligent WS 5100 @@ -66,6 +75,7 @@ 0004 53c815 0005 53c810AP 0006 53c860 + 000a 53c1510 000b 53c896 000c 53c895 000d 53c885 @@ -74,6 +84,7 @@ 1092 8760 FirePort 40 Dual SCSI Controller 1de1 3904 DC390F Ultra Wide SCSI Controller 0012 53c895a + 0020 53c1010 Ultra3 SCSI Adapter 008f 53c875J 1092 8000 FirePort 40 SCSI Controller 1092 8760 FirePort 40 Dual SCSI Host Adapter @@ -83,13 +94,24 @@ 0901 61C102 1000 63C815 1001 Initio + 0010 PCI 1616 Measurement card with 32 digital I/O lines + 0011 OPTO-PCI Opto-Isolated digital I/O board + 0012 PCI-AD/DA Analogue I/O board + 0013 PCI-OPTO-RELAIS Digital I/O board with relay outputs + 0014 PCI-Counter/Timer Counter Timer board + 0015 PCI-DAC416 Analogue output board + 0016 PCI-MFB Analogue I/O board + 0017 PROTO-3 PCI Prototyping board 9100 INI-9100/9100W SCSI Host 1002 ATI Technologies Inc 4158 68800AX [Mach32] 4354 215CT [Mach64 CT] 4358 210888CX [Mach64 CX] 4554 210888ET [Mach64 ET] + 4654 Mach64 VT 4742 3D Rage Pro AGP 1X/2X + 1028 4082 Optiplex GX1 Onboard Display Adapter + 8086 4152 Rage 3D Pro AGP 4744 3D Rage Pro AGP 1X 4747 3D Rage Pro 4749 3D Rage Pro @@ -99,17 +121,26 @@ 474f Rage XL 4750 3D Rage Pro 215GP 4751 3D Rage Pro 215GQ + 4752 Rage XL 4753 Rage XC 4754 3D Rage I/II 215GT [Mach64 GT] 4755 3D Rage II+ 215GTB [Mach64 GTB] 4756 3D Rage IIC 215IIC [Mach64 GT IIC] 4757 3D Rage IIC AGP + 1028 0089 Rage 3D IIC + 1028 4082 Rage 3D IIC + 1028 8082 Rage 3D IIC + 1028 c082 Rage 3D IIC 4758 210888GX [Mach64 GX] 4759 3D Rage IIC 475a 3D Rage IIC AGP + 1002 0087 Rage 3D IIC 4c42 3D Rage LT Pro AGP-133 + 0e11 b0e8 Rage 3D LT Pro 0e11 b10e 3D Rage LT Pro (Compaq Armada 1750) + 1028 0085 Rage 3D LT Pro 4c44 3D Rage LT Pro AGP-66 + 4c46 Mobility M3 AGP 2x 4c47 3D Rage LT-G 215LG 4c49 3D Rage LT Pro 4c4d 3D Rage P/M Mobility AGP 2x @@ -125,15 +156,17 @@ 5044 Rage 128 PD 5045 Rage 128 PE 5046 Rage 128 PF + 1002 2000 Rage Fury MAXX AGP 4x (TMDS) (VGA device) + 1002 2001 Rage Fury MAXX AGP 4x (TMDS) (Extra device?!) 5047 Rage 128 PG 5048 Rage 128 PH 5049 Rage 128 PI - 504A Rage 128 PJ - 504B Rage 128 PK - 504C Rage 128 PL - 504D Rage 128 PM - 504E Rage 128 PN - 504F Rage 128 PO + 504a Rage 128 PJ + 504b Rage 128 PK + 504c Rage 128 PL + 504d Rage 128 PM + 504e Rage 128 PN + 504f Rage 128 PO 5050 Rage 128 PP 5051 Rage 128 PQ 5052 Rage 128 PR @@ -150,12 +183,15 @@ 5345 Rage 128 SE 5346 Rage 128 SF 5347 Rage 128 SG - 534B Rage 128 SK - 534C Rage 128 SL - 534D Rage 128 SM + 5348 Rage 128 4x + 534b Rage 128 SK + 534c Rage 128 SL + 534d Rage 128 SM + 534e Rage 128 4x 5354 Mach 64 VT 1002 5654 Mach 64 reference 5654 264VT [Mach64 VT] + 1002 5654 Mach64VT Reference 5655 264VT3 [Mach64 VT3] 5656 264VT4 [Mach64 VT4] 1003 ULSI Systems @@ -175,6 +211,18 @@ 0105 82C147 0200 82C975 0280 82C925 + 0304 QSound ThunderBird PCI Audio + 1004 0304 QSound ThunderBird PCI Audio + 122d 1206 DSP368 Audio + 1483 5020 XWave Thunder 3D Audio + 0305 QSound ThunderBird PCI Audio Gameport + 1004 0305 QSound ThunderBird PCI Audio Gameport + 122d 1207 DSP368 Audio Gameport + 1483 5021 XWave Thunder 3D Audio Gameport + 0306 QSound ThunderBird PCI Audio Support Registers + 1004 0306 QSound ThunderBird PCI Audio Support Registers + 122d 1208 DSP368 Audio Support Registers + 1483 5022 XWave Thunder 3D Audio Support Registers 0702 VAS96011 [Golden Gate II] 1005 Avance Logic Inc. [ALI] 2064 ALG2032/2064 @@ -191,6 +239,9 @@ 100b National Semiconductor Corporation 0001 DP83810 0002 87415 + 000f OHCI Compliant FireWire Controller + 0011 National PCI System I/O + 0012 USB Controller d001 87410 100c Tseng Labs Inc 3202 ET4000/W32p rev A @@ -215,14 +266,15 @@ 10b8 2001 SMC9332BDT EtherPower 10/100 10b8 2002 SMC9332BVT EtherPower T4 10/100 10b8 2003 SMC9334BDT EtherPower 10/100 (1-port) + 1109 2400 ANA-6944A/TX Fast Ethernet 1112 2300 RNS2300 Fast Ethernet 1112 2320 RNS2320 Fast Ethernet 1112 2340 RNS2340 Fast Ethernet 1113 1207 EN-1207-TX Fast Ethernet - 1109 2400 ANA-6944A/TX Fast Ethernet 1186 1100 DFE-500TX Fast Ethernet 1186 1112 DFE-570TX Fast Ethernet 1282 9100 AEF-380TXD Fast Ethernet + 1385 1100 FA310TX Fast Ethernet 2646 0001 KNE100TX Fast Ethernet 000a 21230 Video Codec 000d PBXGB [TGA2] @@ -245,14 +297,17 @@ 115d 0002 Cardbus Ethernet 10/100 1179 0203 Fast Ethernet 1179 0204 Cardbus Fast Ethernet + 1186 1100 DFE-500TX Fast Ethernet 1186 1101 DFE-500TX Fast Ethernet 1186 1102 DFE-500TX Fast Ethernet 1266 0004 Eagle Fast EtherMAX 12af 0019 NetFlyer Cardbus Fast Ethernet + 1374 0001 Cardbus Ethernet Card 10/100 1395 0001 10/100 Ethernet CardBus PC Card 8086 0001 EtherExpress PRO/100 Mobile CardBus 32 0021 DECchip 21052 0022 DECchip 21150 + 0023 DECchip 21150 0024 DECchip 21152 0025 DECchip 21153 0026 DECchip 21154 @@ -260,6 +315,7 @@ 0046 DECchip 21554 9005 1364 Dell PowerEdge RAID Controller 2 9005 1365 Dell PowerEdge RAID Controller 2 + 1065 RAID Controller 1012 Micronics Computers Inc 1013 Cirrus Logic 0038 GD 7548 @@ -273,6 +329,7 @@ 00b0 GD 5440 00b8 GD 5446 00bc GD 5480 + 1013 00bc CL-GD5480 00d0 GD 5462 00d2 GD 5462 [Laguna I] 00d4 GD 5464 [Laguna] @@ -287,12 +344,26 @@ 1204 GD 7541 [Nordic Light] 4400 CD 4400 6001 CS 4610/11 [CrystalClear SoundFusion Audio Accelerator] + 1014 1010 CS4610 SoundFusion Audio Accelerator 6003 CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator] + 1013 4280 Crystal SoundFusion PCI Audio Accelerator + 6005 Crystal CS4281 PCI Audio + 1013 4281 Crystal CS4281 PCI Audio + 10cf 10a8 Crystal CS4281 PCI Audio + 10cf 10a9 Crystal CS4281 PCI Audio + 10cf 10aa Crystal CS4281 PCI Audio + 10cf 10ab Crystal CS4281 PCI Audio + 10cf 10ac Crystal CS4281 PCI Audio + 10cf 10ad Crystal CS4281 PCI Audio + 10cf 10b4 Crystal CS4281 PCI Audio + 1179 0001 Crystal CS4281 PCI Audio + 14c0 000c Crystal CS4281 PCI Audio 1014 IBM 0002 PCI to MCA Bridge 0005 Alta Lite 0007 Alta MP 000a Fire Coral + 0017 CPU to PCI Bridge 0018 TR Auto LANstreamer 001b GXT-150P 001d 82G2675 @@ -302,19 +373,22 @@ 002e ServeRAID controller 0036 Miami 003e 16/4 Token ring UTP/STP controller - 1014 003E Token-Ring Adapter - 1014 00CD Token-Ring Adapter + Wake-On-LAN - 1014 00CE 16/4 Token-Ring Adapter 2 - 1014 00CF 16/4 Token-Ring Adapter Special - 1014 00E4 High-Speed 100/16/4 Token-Ring Adapter - 1014 00E5 16/4 Token-Ring Adapter 2 + Wake-On-LAN + 1014 003e Token-Ring Adapter + 1014 00cd Token-Ring Adapter + Wake-On-LAN + 1014 00ce 16/4 Token-Ring Adapter 2 + 1014 00cf 16/4 Token-Ring Adapter Special + 1014 00e4 High-Speed 100/16/4 Token-Ring Adapter + 1014 00e5 16/4 Token-Ring Adapter 2 + Wake-On-LAN 0046 MPIC interrupt controller + 0047 PCI to PCI Bridge + 0048 PCI to PCI Bridge 0053 25 MBit ATM Controller 0057 MPEG PCI Bridge - 005C i82557B 10/100 + 005c i82557B 10/100 007d 3780IDSP [MWave] 0095 20H2999 PCI Docking Bridge 00b7 256-bit Graphics Rasterizer [Fire GL1] + 1902 00b8 Fire GL1 ffff MPIC-2 interrupt controller 1015 LSI Logic Corp of Canada 1016 ICL Personal Systems @@ -339,6 +413,11 @@ c24a 90C 101e American Megatrends Inc. 9010 MegaRAID + 9030 EIDE Controller + 9031 EIDE Controller + 9032 EIDE & SCSI Controller + 9033 SCSI Controller + 9040 Multimedia card 9060 MegaRAID 101f PictureTel 1020 Hitachi Computer Products @@ -373,9 +452,16 @@ 2000 4DWave DX 2001 4DWave NX 8400 CyberBlade/i7 + 1023 8400 CyberBlade i7 AGP 8420 CyberBlade/i7d + 0e11 b15a CyberBlade i7 AGP 8500 CyberBlade/i1 + 8520 CyberBlade i1 + 0e11 b16e CyberBlade i1 AGP + 1023 8520 CyberBlade i1 AGP 9320 TGUI 9320 + 9350 GUI Accelerator + 9360 Flat panel GUI Accelerator 9382 Cyber 9382 [Reference design] 9383 Cyber 9383 [Reference design] 9385 Cyber 9385 [Reference design] @@ -390,12 +476,15 @@ 9470 TGUI 9470 9520 Cyber 9520 9525 Cyber 9525 + 9540 Cyber 9540 9660 TGUI 9660/968x/968x 9680 TGUI 9680 9682 TGUI 9682 9683 TGUI 9683 9685 ProVIDIA 9685 9750 3DIm`age 975 + 1014 9750 3DImage 9750 + 1023 9750 3DImage 9750 9753 TGUI 9753 9754 TGUI 9754 9759 TGUI 975 @@ -403,6 +492,7 @@ 9785 TGUI 9785 9850 3DImage 9850 9880 Blade 3D PCI/AGP + 1023 9880 Blade 3D 1024 Zenith Data Systems 1025 Acer Incorporated [ALI] 1435 M1435 @@ -412,11 +502,18 @@ 1461 M1461 1489 M1489 1511 M1511 + 1512 ALI M1512 Aladdin 1513 M1513 + 1521 ALI M1521 Aladdin III CPU Bridge + 10b9 1521 ALI M1521 Aladdin III CPU Bridge + 1523 ALI M1523 ISA Bridge + 10b9 1523 ALI M1523 ISA Bridge 1531 M1531 Northbridge [Aladdin IV/IV+] 1533 M1533 PCI-to-ISA Bridge + 10b9 1533 ALI M1533 Aladdin IV/V ISA South Bridge 1535 M1535 PCI Bridge + Super I/O + FIR 1541 M1541 Northbridge [Aladdin V] + 10b9 1541 ALI M1541 Aladdin V/V+ AGP+PCI North Bridge 1542 M1542 Northbridge [Aladdin V] 1543 M1543 PCI-to-ISA Bridge + Super I/O + FIR 1561 M1561 Northbridge [Aladdin 7] @@ -432,12 +529,26 @@ 3307 M3307 MPEG-I Video Controller 3309 M3309 MPEG-II Video w/ Software Audio Decoder 3321 M3321 MPEG-II Audio/Video Decoder + 5212 ALI M4803 + 5215 ALI PCI EIDE Controller 5217 M5217H 5219 M5219 5225 M5225 5229 M5229 5235 M5235 + 5237 ALI M5237 PCI USB Host Controller + 5240 EIDE Controller + 5241 PCMCIA Bridge + 5242 General Purpose Controller + 5243 PCI to PCI Bridge Controller + 5244 Floppy Disk Controller + 5247 ALI M1541 PCI to PCI Bridge 5251 M5251 P1394 OHCI Controller + 5427 ALI PCI to AGP Bridge + 5451 ALI M5451 PCI AC-Link Controller Audio Device + 5453 ALI M5453 PCI AC-Link Controller Modem Device + 7101 ALI M7101 PCI PMU Power Management Controller + 10b9 7101 ALI M7101 PCI PMU Power Management Controller 1028 Dell Computer Corporation 0001 PowerEdge Expandable RAID Controller 2/Si 0002 PowerEdge Expandable RAID Controller 3/Di @@ -452,8 +563,14 @@ 0518 MGA-II [Athena] 0519 MGA 2064W [Millennium] 051a MGA 1064SG [Mystique] + 102b 1100 MGA-1084SG Mystique + 102b 1200 MGA-1084SG Mystique 1100 102b MGA-1084SG Mystique + 110a 0018 Scenic Pro C5 (D1025) 051b MGA 2164W [Millennium II] + 102b 051b MGA-2164W Millennium II + 102b 1100 MGA-2164W Millennium II + 102b 1200 MGA-2164W Millennium II 051e MGA 1064SG [Mystique] AGP 051f MGA 2164W [Millennium II] AGP 0520 MGA G200 @@ -475,10 +592,16 @@ 102b ca60 Millennium G250 LE AGP 102b ca6c Millennium G250 AGP 102b dbbc Millennium G200 AGP + 102b dbc2 Millennium G200 MMS (Dual G200) + 102b dbc8 Millennium G200 MMS (Dual G200) + 102b dbe2 Millennium G200 MMS (Quad G200) + 102b dbe8 Millennium G200 MMS (Quad G200) 102b f806 Mystique G200 Video AGP + 102b ff00 MGA-G200 AGP 102b ff02 Mystique G200 AGP 102b ff03 Millennium G200 AGP 102b ff04 Marvel G200 AGP + 110a 0032 MGA-G200 AGP 0525 MGA G400 AGP 0e11 b16f Matrox MGA-G400 AGP 102b 0328 Millennium G400 16Mb SDRAM @@ -497,9 +620,16 @@ 102b ff01 Productiva G100 102b ff05 Productiva G100 Multi-Monitor 1001 MGA G100 [Productiva] AGP + 102b 1001 MGA-G100 AGP + 102b ff00 MGA-G100 AGP + 102b ff01 MGA-G100 Productiva AGP + 102b ff03 Millennium G100 AGP + 102b ff04 MGA-G100 AGP 102b ff05 MGA-G100 Productiva AGP Multi-Monitor + 110a 001e MGA-G100 AGP 2007 MGA Mistral 4536 VIA Framegrabber + 6573 Shark 10/100 Multiport SwitchNIC 102c Chips and Technologies 00b8 F64310 00c0 F69000 HiQVideo @@ -532,12 +662,16 @@ 0003 ATM Controller 0004 R4000 PCI Bridge 0005 PCI to 486-like bus Bridge + 0006 GUI Accelerator 0007 PCI to UX-Bus Bridge + 0008 GUI Accelerator + 0009 GUI Accelerator for W98 001a [Nile II] 0021 Vrc4373 [Nile I] 0029 PowerVR PCX1 002a PowerVR 3D 0035 USB + 003e NAPCCARD Cardbus Controller 0046 PowerVR PCX2 [midas] 005a Vrc5074 [Nile 4] 0063 Firewarden @@ -565,7 +699,9 @@ 0006 85C501/2/3 0008 85C503/5513 0009 ACPI + 0018 SiS85C503/5513 (LPC Bridge) 0200 5597/5598 VGA + 1039 0000 SiS5597 SVGA (Shared RAM) 0204 82C204 0205 SG86C205 0406 85C501/2 @@ -577,34 +713,81 @@ 0620 620 Host 0630 630 Host 0900 SiS900 10/100 Ethernet + 1039 0900 SiS900 10/100 Ethernet Adapter 3602 83C602 5107 5107 + 5300 SiS540 PCI Display Adapter + 5401 486 PCI Chipset 5511 5511/5512 5513 5513 [IDE] + 1039 5513 SiS5513 EIDE Controller (A,B step) 5517 5517 5571 5571 + 5581 5581 Pentium Chipset + 5582 5582 5591 5591/5592 Host + 5596 5596 Pentium Chipset 5597 5597 [SiS5582] 5600 5600 Host 6204 Video decoder & MPEG interface + 6205 VGA Controller 6236 6236 3D-AGP + 6300 SiS630 GUI Accelerator+3D 6306 6306 3D-AGP + 1039 6306 SiS530,620 GUI Accelerator+3D 6326 86C326 + 1039 6326 SiS6326 GUI Accelerator 1092 0a50 SpeedStar A50 1092 0a70 SpeedStar A70 1092 4910 SpeedStar A70 1092 4920 SpeedStar A70 + 1569 6326 SiS6326 GUI Accelerator 7001 7001 7007 OHCI Compliant FireWire Controller + 7016 SiS7016 10/100 Ethernet Adapter + 1039 7016 SiS7016 10/100 Ethernet Adapter + 7018 SiS PCI Audio Accelerator + 1014 01b6 SiS PCI Audio Accelerator + 1014 01b7 SiS PCI Audio Accelerator + 1019 7018 SiS PCI Audio Accelerator + 1025 000e SiS PCI Audio Accelerator + 1025 0018 SiS PCI Audio Accelerator + 1039 7018 SiS PCI Audio Accelerator + 1043 800b SiS PCI Audio Accelerator + 1054 7018 SiS PCI Audio Accelerator + 107d 5330 SiS PCI Audio Accelerator + 107d 5350 SiS PCI Audio Accelerator + 1170 3209 SiS PCI Audio Accelerator + 1462 400a SiS PCI Audio Accelerator + 14a4 2089 SiS PCI Audio Accelerator + 14cd 2194 SiS PCI Audio Accelerator + 14ff 1100 SiS PCI Audio Accelerator + 152d 8808 SiS PCI Audio Accelerator + 1558 1103 SiS PCI Audio Accelerator + 1558 2200 SiS PCI Audio Accelerator + 1563 7018 SiS PCI Audio Accelerator + 15c5 0111 SiS PCI Audio Accelerator + 270f a171 SiS PCI Audio Accelerator + a0a0 0022 SiS PCI Audio Accelerator 103a Seiko Epson Corporation 103b Tatung Co. of America 103c Hewlett-Packard Company 1030 J2585A 1031 J2585B + 103c 1040 J2973A DeskDirect 10BaseT NIC + 103c 1041 J2585B DeskDirect 10/100VG NIC + 103c 1042 J2970A DeskDirect 10BaseT/2 NIC 1040 J2973A DeskDirect 10BaseT NIC 1041 J2585B DeskDirect 10/100 NIC 1042 J2970A DeskDirect 10BaseT/2 NIC 1064 79C970 PCnet Ethernet Controller + 10c1 NetServer Smart IRQ Router + 10ed TopTools Remote Control + 1200 82557B 10/100 NIC + 1219 NetServer PCI Hot-Plug Controller + 121a NetServer SMIC Controller + 121b NetServer Legacy COM Port Decoder + 121c NetServer PCI COM Port Decoder 2910 E2910A 2925 E2925A 103e Solliday Engineering @@ -640,8 +823,10 @@ c822 82C822 c824 82C824 c825 82C825 [Firebridge 2] + c832 82C832 c861 82C861 c895 82C895 + c935 EV1935 ECTIVA MachOne PCI Audio d568 82C825 [Firebridge 2] 1046 IPC Corporation, Ltd. 1047 Genoa Systems Corp @@ -678,11 +863,13 @@ 1097 3d01 Jeronimo Pro 3d3d 0100 Reference Permedia 2 3D 8000 PCILynx/PCILynx2 IEEE 1394 Link Layer Controller - e4bf 1010 CF1-1-SNARE - e4bf 1020 CF1-2-SNARE + e4bf 1010 CF1-1-SNARE + e4bf 1020 CF1-2-SNARE 8009 OHCI Compliant FireWire Controller 8019 TSB12LV23 OHCI Compliant IEEE-1394 Controller - e4bf 1010 CF2-1-CYMBAL + 11bd 000a Studio DV500-1394 + 11bd 000e Studio DV + e4bf 1010 CF2-1-CYMBAL a001 TDC1570 a100 TDC1561 ac10 PCI1050 @@ -701,15 +888,24 @@ ac1e PCI1211 ac1f PCI1251B ac20 TI 2030 + ac30 PCI1260 PC card Cardbus Controller + ac40 PCI4450 PC card Cardbus Controller + ac41 PCI4410 PC card Cardbus Controller + ac42 PCI4451 PC card Cardbus Controller + ac50 PCI1410 PC card Cardbus Controller ac51 PCI1420 + ac52 PCI1451 PC card Cardbus Controller + ac53 PCI1421 PC card Cardbus Controller fe00 FireWire Host Controller fe03 12C01A FireWire Host Controller 104d Sony Corporation - 8039 CXD3222 iLINK Controller + 8009 CXD1947Q i.LINK Controller + 8039 CXD3222 i.LINK Controller 8056 Rockwell HCF 56K modem 104e Oak Technology, Inc 0017 OTI-64017 0107 OTI-107 [Spitfire] + 0109 Video Adapter 0111 OTI-64111 [Spitfire] 0217 OTI-64217 0317 OTI-64317 @@ -719,35 +915,48 @@ 0001 W83769F 0105 W82C105 0840 W89C840 + 1050 0001 W89C840 Ethernet Adapter + 1050 0840 W89C840 Ethernet Adapter 0940 W89C940 5a5a W89C940F 9970 W9970CF 1051 Anigma, Inc. +1052 ?Young Micro Systems 1053 Young Micro Systems 1054 Hitachi, Ltd 1055 EFAR Microsystems 1056 ICL -# Motorola made a mistake and used this value, please duplicate Moto -# entries here -- Cort -1507 Motorola - 0001 MPC105 [Eagle] - 0002 MPC106 [Grackle] - 0003 MPC8240 [Kahlua] - 0100 MC145575 [HFC-PCI] - 0431 KTI829c 100VG - 4801 Raven - 4802 Falcon - 4803 Hawk - 4806 CPX8216 +# Motorola made a mistake and used 1507 instead of 1057 in some chips. +# Please look at the 1507 entry as well when updating this. 1057 Motorola 0001 MPC105 [Eagle] 0002 MPC106 [Grackle] 0100 MC145575 [HFC-PCI] 0431 KTI829c 100VG + 1801 Audio I/O Controller (MIDI) + ecc0 0030 Layla 4801 Raven 4802 Falcon 4803 Hawk 4806 CPX8216 + 5600 SM56 PCI Modem + 1057 0300 SM56 PCI Speakerphone Modem + 1057 0301 SM56 PCI Voice Modem + 1057 0302 SM56 PCI Fax Modem + 1057 5600 SM56 PCI Voice modem + 13d2 0300 SM56 PCI Speakerphone Modem + 13d2 0301 SM56 PCI Voice modem + 13d2 0302 SM56 PCI Fax Modem + 1436 0300 SM56 PCI Speakerphone Modem + 1436 0301 SM56 PCI Voice modem + 1436 0302 SM56 PCI Fax Modem + 144f 100c SM56 PCI Fax Modem + 1494 0300 SM56 PCI Speakerphone Modem + 1494 0301 SM56 PCI Voice modem + 14c8 0300 SM56 PCI Speakerphone Modem + 14c8 0302 SM56 PCI Fax Modem + 1668 0300 SM56 PCI Speakerphone Modem + 1668 0302 SM56 PCI Fax Modem 1058 Electronics & Telecommunications RSH 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. @@ -784,6 +993,7 @@ 0891 UM8891A 1001 UM886A 673a UM8886BF + 673b EIDE Master/DMA 8710 UM8710 886a UM8886A 8881 UM8881F @@ -795,6 +1005,7 @@ 9026 UM9026 e881 UM8881N e886 UM8886N + e88a UM8886N e891 UM8891N 1061 I.I.T. 0001 AGX016 @@ -828,6 +1039,8 @@ 0010 Heathrow Mac I/O 0017 Paddington Mac I/O 106c Hyundai Electronics America + 8801 Dual Pentium ISA/PCI Motherboard + 8802 PowerPC ISA/PCI Motherboard 8803 Dual Window Graphics Accelerator 8804 LAN Controller 8805 100-BaseT LAN @@ -838,13 +1051,29 @@ 1071 Mitac 1072 GIT Co Ltd 1073 Yamaha Corporation + 0001 3D GUI Accelerator 0002 YGV615 [RPA3 3D-Graphics Controller] 0003 YMF-740 0004 YMF-724 - 000C YMF-740C [DS-1L Audio Controller] - 000D YMF-724F [DS-1 Audio Controller] + 1073 0004 YMF724-Based PCI Audio Adapter + 0005 DS1 Audio + 1073 0005 DS-XG PCI Audio CODEC + 0006 DS1 Audio + 0008 DS1 Audio + 1073 0008 DS-XG PCI Audio CODEC + 000a DS1L Audio + 1073 0004 DS-XG PCI Audio CODEC + 1073 000a DS-XG PCI Audio CODEC + 000c YMF-740C [DS-1L Audio Controller] + 107a 000c DS-XG PCI Audio CODEC + 000d YMF-724F [DS-1 Audio Controller] + 1073 000d DS-XG PCI Audio CODEC 0010 YMF-744B [DS-1S Audio Controller] + 1073 0006 DS-XG PCI Audio CODEC + 1073 0010 DS-XG PCI Audio CODEC 0012 YMF-754 [DS-1E Audio Controller] + 1073 0012 DS-XG PCI Audio Codec + 0020 DS-1 Audio 1074 NexGen Microsystems 4e78 82c500/1 1075 Advanced Integrations Research @@ -899,18 +1128,24 @@ 0010 VME Bridge Model 618 3000 VME Bridge Model 2706 108c Oakleigh Systems Inc. -108d Olicom +108d Olicom 0001 Token-Ring 16/4 PCI Adapter (3136/3137) 0002 16/4 Token Ring 0004 RapidFire 3139 Token-Ring 16/4 PCI Adapter + 108d 0004 OC-3139/3140 RapidFire Token-Ring 16/4 Adapter 0005 GoCard 3250 Token-Ring 16/4 CardBus PC Card 0006 OC-3530 RapidFire Token-Ring 100 0007 RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter + 108d 0007 OC-3141 RapidFire Token-Ring 16/4 Adapter 0008 RapidFire 3540 HSTR 100/16/4 PCI Adapter + 108d 0008 OC-3540 RapidFire HSTR 100/16/4 Adapter 0011 OC-2315 0012 OC-2325 0013 OC-2183/2185 0014 OC-2326 + 0019 OC-2327/2250 10/100 Ethernet Adapter + 108d 0016 OC-2327 Rapidfire 10/100 Ethernet Adapter + 108d 0017 OC-2250 GoCard 10/100 Ethernet Adapter 0021 OC-6151/6152 [RapidFire ATM 155] 0022 ATM Adapter 108e Sun Microsystems Computer Corp. @@ -918,6 +1153,7 @@ 1000 EBUS 1001 Happy Meal 5000 Simba Advanced PCI Bridge + 5043 SunPCI Co-processor 8000 PCI Bus Module a000 Ultra IIi 108f Systemsoft @@ -928,7 +1164,7 @@ 0040 3D graphics frame buffer 0041 3D graphics frame buffer 0060 Proprietary bus bridge - 00E4 Powerstorm 4D50T + 00e4 Powerstorm 4D50T 0720 Motion JPEG codec 1092 Diamond Multimedia Systems 00a0 Speedstar Pro SE @@ -992,15 +1228,94 @@ 109e Brooktree Corporation 0350 Bt848 TV with DMA push 0351 Bt849A Video capture + 036c Bt879(??) Video Capture + 13e9 0070 Win/TV (Video Section) 036e Bt878 + 127a 0001 Bt878 Mediastream Controller NTSC + 127a 0002 Bt878 Mediastream Controller PAL BG + 127a 0003 Bt878a Mediastream Controller PAL BG + 127a 0048 Bt878/832 Mediastream Controller + 144f 3000 MagicTView CPH060 - Video + 14f1 0001 Bt878 Mediastream Controller NTSC + 14f1 0002 Bt878 Mediastream Controller PAL BG + 14f1 0003 Bt878a Mediastream Controller PAL BG + 14f1 0048 Bt878/832 Mediastream Controller 1851 1850 FlyVideo'98 - Video 1851 1851 FlyVideo II 1852 1852 FlyVideo'98 - Video (with FM Tuner) 036f Bt879 + 127a 0044 Bt879 Video Capture NTSC + 127a 0122 Bt879 Video Capture PAL I + 127a 0144 Bt879 Video Capture NTSC + 127a 0222 Bt879 Video Capture PAL BG + 127a 0244 Bt879a Video Capture NTSC + 127a 0322 Bt879 Video Capture NTSC + 127a 0422 Bt879 Video Capture NTSC + 127a 1122 Bt879 Video Capture PAL I + 127a 1222 Bt879 Video Capture PAL BG + 127a 1322 Bt879 Video Capture NTSC + 127a 1522 Bt879a Video Capture PAL I + 127a 1622 Bt879a Video Capture PAL BG + 127a 1722 Bt879a Video Capture NTSC + 14f1 0044 Bt879 Video Capture NTSC + 14f1 0122 Bt879 Video Capture PAL I + 14f1 0144 Bt879 Video Capture NTSC + 14f1 0222 Bt879 Video Capture PAL BG + 14f1 0244 Bt879a Video Capture NTSC + 14f1 0322 Bt879 Video Capture NTSC + 14f1 0422 Bt879 Video Capture NTSC + 14f1 1122 Bt879 Video Capture PAL I + 14f1 1222 Bt879 Video Capture PAL BG + 14f1 1322 Bt879 Video Capture NTSC + 14f1 1522 Bt879a Video Capture PAL I + 14f1 1622 Bt879a Video Capture PAL BG + 14f1 1722 Bt879a Video Capture NTSC 1851 1850 FlyVideo'98 - Video 1851 1851 FlyVideo II 1852 1852 FlyVideo'98 - Video (with FM Tuner) + 0370 Bt880 Video Capture + 1851 1850 FlyVideo'98 + 1851 1851 FlyVideo'98 EZ - video + 1852 1852 FlyVideo'98 (with FM Tuner) 0878 Bt878 + 127a 0001 Bt878 Video Capture (Audio Section) + 127a 0002 Bt878 Video Capture (Audio Section) + 127a 0003 Bt878 Video Capture (Audio Section) + 127a 0048 Bt878 Video Capture (Audio Section) + 13e9 0070 Win/TV (Audio Section) + 144f 3000 MagicTView CPH060 - Audio + 14f1 0001 Bt878 Video Capture (Audio Section) + 14f1 0002 Bt878 Video Capture (Audio Section) + 14f1 0003 Bt878 Video Capture (Audio Section) + 14f1 0048 Bt878 Video Capture (Audio Section) + 0879 Bt879 Video Capture (Audio Section) + 127a 0044 Bt879 Video Capture (Audio Section) + 127a 0122 Bt879 Video Capture (Audio Section) + 127a 0144 Bt879 Video Capture (Audio Section) + 127a 0222 Bt879 Video Capture (Audio Section) + 127a 0244 Bt879 Video Capture (Audio Section) + 127a 0322 Bt879 Video Capture (Audio Section) + 127a 0422 Bt879 Video Capture (Audio Section) + 127a 1122 Bt879 Video Capture (Audio Section) + 127a 1222 Bt879 Video Capture (Audio Section) + 127a 1322 Bt879 Video Capture (Audio Section) + 127a 1522 Bt879 Video Capture (Audio Section) + 127a 1622 Bt879 Video Capture (Audio Section) + 127a 1722 Bt879 Video Capture (Audio Section) + 14f1 0044 Bt879 Video Capture (Audio Section) + 14f1 0122 Bt879 Video Capture (Audio Section) + 14f1 0144 Bt879 Video Capture (Audio Section) + 14f1 0222 Bt879 Video Capture (Audio Section) + 14f1 0244 Bt879 Video Capture (Audio Section) + 14f1 0322 Bt879 Video Capture (Audio Section) + 14f1 0422 Bt879 Video Capture (Audio Section) + 14f1 1122 Bt879 Video Capture (Audio Section) + 14f1 1222 Bt879 Video Capture (Audio Section) + 14f1 1322 Bt879 Video Capture (Audio Section) + 14f1 1522 Bt879 Video Capture (Audio Section) + 14f1 1622 Bt879 Video Capture (Audio Section) + 14f1 1722 Bt879 Video Capture (Audio Section) + 0880 Bt880 Video Capture (Audio Section) 2115 BtV 2115 Mediastream controller 2125 BtV 2125 Mediastream controller 2164 BtV 2164 @@ -1108,17 +1423,24 @@ 0006 16/4 Cardbus Adapter 10b6 0006 16/4 CardBus Adapter 0007 Presto PCI Adapter + 10b6 0007 Presto PCI 0009 Smart 100/16/4 PCI-HS Ringnode + 10b6 0009 Smart 100/16/4 PCI-HS Ringnode 000a Smart 100/16/4 PCI Ringnode + 10b6 000a Smart 100/16/4 PCI Ringnode 000b 16/4 CardBus Adapter Mk2 + 10b6 000b 16/4 Cardbus Adapter Mk2 1000 Collage 25 ATM Adapter 1001 Collage 155 ATM Server Adapter 10b7 3Com Corporation 0001 3c985 1000BaseSX 3390 Token Link Velocity 3590 3c359 TokenLink Velocity XL + 10b7 3590 TokenLink Velocity XL Adapter 5057 3c575 [Megahertz] 10/100 LAN CardBus + 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5157 3c575 [Megahertz] 10/100 LAN CardBus + 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5900 3c590 10BaseT [Vortex] 5950 3c595 100BaseTX [Vortex] 5951 3c595 100BaseT4 [Vortex] @@ -1127,16 +1449,41 @@ 9000 3c900 10BaseT [Boomerang] 9001 3c900 Combo [Boomerang] 9004 3c900B-TPO [Etherlink XL TPO] + 10b7 9004 3C900B-TPO Etherlink XL TPO 10Mb 9005 3c900B-Combo [Etherlink XL Combo] + 10b7 9005 3C900B-Combo Etherlink XL Combo 9006 3c900B-TPC [Etherlink XL TPC] - 900A 3c900B-FL [Etherlink XL FL] + 900a 3c900B-FL [Etherlink XL FL] 9050 3c905 100BaseTX [Boomerang] 9051 3c905 100BaseT4 9055 3c905B 100BaseTX [Cyclone] + 1028 0080 3C905B Fast Etherlink XL 10/100 + 1028 0081 3C905B Fast Etherlink XL 10/100 + 1028 0082 3C905B Fast Etherlink XL 10/100 + 1028 0083 3C905B Fast Etherlink XL 10/100 + 1028 0084 3C905B Fast Etherlink XL 10/100 + 1028 0085 3C905B Fast Etherlink XL 10/100 + 1028 0086 3C905B Fast Etherlink XL 10/100 + 1028 0087 3C905B Fast Etherlink XL 10/100 + 1028 0088 3C905B Fast Etherlink XL 10/100 + 1028 0089 3C905B Fast Etherlink XL 10/100 + 1028 0090 3C905B Fast Etherlink XL 10/100 + 1028 0091 3C905B Fast Etherlink XL 10/100 + 1028 0092 3C905B Fast Etherlink XL 10/100 + 1028 0093 3C905B Fast Etherlink XL 10/100 + 1028 0094 3C905B Fast Etherlink XL 10/100 + 1028 0095 3C905B Fast Etherlink XL 10/100 + 1028 0096 3C905B Fast Etherlink XL 10/100 + 1028 0097 3C905B Fast Etherlink XL 10/100 + 1028 0098 3C905B Fast Etherlink XL 10/100 + 1028 0099 3C905B Fast Etherlink XL 10/100 + 10b7 9055 3C905B Fast Etherlink XL 10/100 9058 3c905B-Combo [Deluxe Etherlink XL 10/100] - 905A 3c905B-FX [Fast Etherlink XL FX 10/100] + 905a 3c905B-FX [Fast Etherlink XL FX 10/100] 9200 3c905C-TX [Fast Etherlink] + 10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC 9800 3c980-TX [Fast Etherlink XL Server Adapter] + 10b7 9800 3c980-TX Fast Etherlink XL Server Adapter 10b8 Standard Microsystems Corp [SMC] 0005 83C170QF 1055 e000 LANEPIC @@ -1147,11 +1494,20 @@ 10b8 a016 EtherPower II 10/100 10b8 a017 EtherPower II 10/100 0006 LANEPIC + 1055 e100 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e102 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e300 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e302 LANEPIC Cardbus Fast Ethernet Adapter + 10b8 a012 LANEPIC Cardbus Fast Ethernet Adapter + 13a2 8002 LANEPIC Cardbus Fast Ethernet Adapter + 13a2 8006 LANEPIC Cardbus Fast Ethernet Adapter 1000 FDC 37c665 1001 FDC 37C922 a011 83C170QF b106 SMC34C90 10b9 Acer Laboratories Inc. [ALi] + 0111 C-Media CMI8738/C3DX Audio Device (OEM) + 10b9 0111 C-Media CMI8738/C3DX Audio Device (OEM) 1435 M1435 1445 M1445 1449 M1449 @@ -1162,12 +1518,18 @@ 1512 M1512 [Aladdin] 1513 M1513 [Aladdin] 1521 M1521 [Aladdin III] + 10b9 1521 ALI M1521 Aladdin III CPU Bridge 1523 M1523 + 10b9 1523 ALI M1523 ISA Bridge 1531 M1531 [Aladdin IV] 1533 M1533 PCI to ISA Bridge [Aladdin IV] + 10b9 1533 ALI M1533 Aladdin IV ISA Bridge 1541 M1541 + 10b9 1541 ALI M1541 Aladdin V/V+ AGP System Controller 1543 M1543 1621 M1621 + 1631 ALI M1631 PCI North Bridge Aladdin Pro III + 1641 ALI M1641 PCI North Bridge Aladdin Pro IV 3141 M3141 3143 M3143 3145 M3145 @@ -1187,6 +1549,7 @@ 5243 M5243 5247 M5247 7101 M7101 PMU + 10b9 7101 ALI M7101 Power Management Controller 10ba Mitsubishi Electric Corp. 0301 AccelGraphics AccelECLIPSE 10bb Dapha Electronics Corporation @@ -1209,10 +1572,40 @@ 0002 NM2090 [MagicGraph 128V] 0003 NM2093 [MagicGraph 128ZV] 0004 NM2160 [MagicGraph 128XD] - 0005 [MagicGraph 256AV] - 0006 [MagicGraph 256ZX] + 1014 00ba MagicGraph 128XD + 1025 1007 MagicGraph 128XD + 1028 0074 MagicGraph 128XD + 1028 0075 MagicGraph 128XD + 1028 007d MagicGraph 128XD + 1028 007e MagicGraph 128XD + 1033 802f MagicGraph 128XD + 104d 801b MagicGraph 128XD + 104d 802f MagicGraph 128XD + 104d 830b MagicGraph 128XD + 10ba 0e00 MagicGraph 128XD + 10c8 0004 MagicGraph 128XD + 10cf 1029 MagicGraph 128XD + 10f7 8308 MagicGraph 128XD + 10f7 8309 MagicGraph 128XD + 10f7 830b MagicGraph 128XD + 10f7 830d MagicGraph 128XD + 10f7 8312 MagicGraph 128XD + 0005 [MagicMedia 256AV] + 0006 NM2360 [MagicMedia 256ZX] 0083 [MagicGraph 128ZV Plus] - 8005 [MagicMedia 256AV] + 8005 [MagicMedia 256AV Audio] + 0e11 b0d1 MagicMedia 256AV Audio Device on Discovery + 0e11 b126 MagicMedia 256AV Audio Device on Durango + 1014 00dd MagicMedia 256AV Audio Device on BlackTip Thinkpad + 1025 1003 MagicMedia 256AV Audio Device on TravelMate 720 + 1028 008f MagicMedia 256AV Audio Device on Colorado Inspiron + 103c 0007 MagicMedia 256AV Audio Device on Voyager II + 103c 0008 MagicMedia 256AV Audio Device on Voyager III + 103c 000d MagicMedia 256AV Audio Device on Omnibook 900 + 10c8 8005 MagicMedia 256AV Audio Device on FireAnt + 110a 8005 MagicMedia 256AV Audio Device + 14c0 0004 MagicMedia 256AV Audio Device + 8006 NM2360 [MagicMedia 256ZX Audio] 10c9 Dataexpert Corporation 10ca Fujitsu Microelectr., Inc. 10cb Omron Corporation @@ -1221,6 +1614,7 @@ 1100 ASC1100 1200 ASC1200 [(abp940) Fast SCSI-II] 1300 ABP940-U / ABP960-U + 10cd 1310 ASC1300 SCSI Adapter 2300 ABP940-UW 10ce Radius 10cf Citicorp TTI @@ -1258,7 +1652,6 @@ 1043 0200 V3400 TNT 1092 0550 Viper V550 1092 0552 Viper V550 - 1102 1015 Graphics Blaster CT6710 1092 4804 Viper V550 1092 4808 Viper V550 1092 4810 Viper V550 @@ -1269,31 +1662,70 @@ 1092 4904 Viper V550 1092 4914 Viper V550 1092 8225 Viper V550 + 10de 0020 Riva TNT + 1102 1015 Graphics Blaster CT6710 + 1102 1016 Graphics Blaster RIVA TNT 0028 Riva TnT2 [NV5] 1043 0200 AGP-V3800 SGRAM + 1043 0201 AGP-V3800 SDRAM + 1043 0205 PCI-V3800 + 1043 4000 AGP-V3800PRO 1092 4804 Viper V770 1092 4a00 Viper V770 1092 4a02 Viper V770 Ultra 1092 6a02 Viper V770 Ultra 1092 7a02 Viper V770 Ultra + 10de 0005 RIVA TNT2 Pro 1102 1020 3D Blaster RIVA TNT2 + 1102 1026 3D Blaster RIVA TNT2 Digital 14af 5810 Maxi Gamer Xentor 0029 Riva TnT2 Ultra [NV5] 1043 0200 AGP-V3800 Deluxe + 1043 0201 AGP-V3800 Ultra SDRAM + 1043 0205 PCI-V3800 Ultra 1102 1021 3D Blaster RIVA TNT2 Ultra + 1102 1029 3D Blaster RIVA TNT2 Ultra + 1102 102f 3D Blaster RIVA TNT2 Ultra 14af 5820 Maxi Gamer Xentor 32 002a Riva TnT2 [NV5] 002b Riva TnT2 [NV5] 002c Vanta [NV6] 1043 0200 AGP-V3800 Combat SDRAM + 1043 0201 AGP-V3800 Combat 1092 6820 Viper V730 + 1102 1031 CT6938 VANTA 8MB + 1102 1034 CT6894 VANTA 16MB 14af 5008 Maxi Gamer Phoenix 2 002d Vanta [NV6] 1043 0200 AGP-V3800M + 1043 0201 AGP-V3800M + 1102 1023 CT6892 RIVA TNT2 Value + 1102 1024 CT6932 RIVA TNT2 Value 32Mb + 1102 102c CT6931 RIVA TNT2 Value (Jumper) + 1462 8808 MSI-8808 002e Vanta [NV6] 002f Vanta [NV6] 00a0 Riva TNT2 14af 5810 Maxi Gamer Xentor + 0100 GeForce 256 + 1043 0200 AGP-V6600 SGRAM + 1043 0201 AGP-V6600 SDRAM + 1043 4008 AGP-V6600 SGRAM + 1043 4009 AGP-V6600 SDRAM + 1102 102d CT6941 GeForce 256 + 0101 GeForce 256 DDR + 1043 0202 AGP-V6800 DDR + 1043 400a AGP-V6800 DDR SGRAM + 1043 400b AGP-V6800 DDR SDRAM + 1102 102e CT6971 GeForce 256 DDR + 0103 Quadro (GeForce 256 GL) + 0110 NV11 + 0111 NV11 DDR + 0113 NV11 GL + 0150 NV15 (Geforce2 GTS) + 0151 NV15 DDR (Geforce2 GTS) + 0152 NV15 Bladerunner (Geforce2 GTS) + 0153 NV15 GL (Quadro2) 10df Emulex Corporation 10df Light Pulse Fibre Channel Adapter 1ae5 LP6000 Fibre Channel Host Adapter @@ -1327,6 +1759,9 @@ 8088 Kingsberg Spacetec Format Synchronizer 8089 Kingsberg Spacetec Serial Output Board 809c S5933_HEPC3 + 80d7 PCI-9112 + 80d9 PCI-9118 + 80da PCI-9812 811a PCI-IEEE1355-DS-DE Interface 8170 S5933 "Matchmaker" [PCI Chipset Development Tool] 10e9 Alps Electric Co., Ltd. @@ -1349,6 +1784,9 @@ 1186 0300 DE-528 1259 2400 AT-2400 8129 RTL-8129 + 10ec 8129 RT8129 Fast Ethernet Adapter + 8138 RT8139 (B/C) Cardbus Fast Ethernet Adapter + 10ec 8138 RT8139 (B/C) Fast Ethernet Adapter 8139 RTL-8139 1025 8920 ALN-325 1025 8921 ALN-325 @@ -1407,12 +1845,16 @@ 1102 0020 CT4850 SBLive! Value 1102 0021 CT4620 SBLive! 1102 002f SBLive! mainboard implementation + 1102 4001 E-mu APS 1102 8022 CT4780 SBLive! Value + 1102 8023 CT4790 SoundBlaster PCI512 1102 8024 CT4760 SBLive! + 1102 8025 SBLive! Mainboard Implementation 1102 8026 CT4830 SBLive! Value 1102 8027 CT4832 SBLive! Value 1102 8031 CT4831 SBLive! Value 1102 8040 CT4760 SBLive! + 1102 8051 CT4850 SBLive! Value 7002 SB Live! 1102 0020 Gameport Joystick 1103 Triones Technologies, Inc. @@ -1424,7 +1866,6 @@ 1106 VIA Technologies, Inc. 0391 VT8371 [KX133] 0501 VT8501 - 0601 VT8601 0505 VT82C505 0561 VT82C561 0571 VT82C586 IDE [Apollo] @@ -1434,11 +1875,17 @@ 1106 0000 MVP3 ISA Bridge 0595 VT82C595 [Apollo VP2] 0596 VT82C596 ISA [Apollo PRO] + 1106 0000 VT82C596/A/B PCI to ISA Bridge + 1458 0596 VT82C596/A/B PCI to ISA Bridge 0597 VT82C597 [Apollo VP3] 0598 VT82C598 [Apollo MVP3] + 0601 VT8601 0680 VT82C680 [Apollo P6] 0686 VT82C686 [Apollo Super] + 1106 0000 VT82C686/A PCI to ISA Bridge + 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C691 [Apollo PRO] + 1458 0691 VT82C691 Apollo Pro System Controller 0693 VT82C693 [Apollo Pro Plus] 0926 VT82C926 [Amazon] 1000 VT82C570MV @@ -1449,10 +1896,13 @@ 1234 0925 MVP3 USB Controller 3040 VT82C586B ACPI 3043 VT86C100A [Rhine 10/100] - 1106 0100 VT86C100A + 10bd 0000 VT86C100A Fast Ethernet Adapter + 1106 0100 VT86C100A Fast Ethernet Adapter 1186 1400 DFE-530TX + 3044 OHCI Compliant IEEE 1394 Host Controller 3057 VT82C686 [Apollo Super ACPI] 3058 VT82C686 [Apollo Super AC97/Audio] + 1462 3091 MS-6309 Onboard Audio 3068 VT82C686 [Apollo Super AC97/Modem] 5030 VT82C596 ACPI [Apollo PRO] 6100 VT85C100A [Rhine II] @@ -1462,8 +1912,8 @@ 8596 VT82C596 [Apollo PRO AGP] 8597 VT82C597 [Apollo VP3 AGP] 8598 VT82C598 [Apollo MVP3 AGP] - 8691 VT82C691 [Apollo Pro] 8601 VT8601 + 8691 VT82C691 [Apollo Pro] 1107 Stratus Computers 0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!) 1108 Proteon, Inc. @@ -1473,8 +1923,8 @@ 0108 P1690Plus 0138 P1690Plus 0139 P1690Plus - 013C P1690Plus - 013D P1690Plus + 013c P1690Plus + 013d P1690Plus 1109 Cogent Data Technologies, Inc. 1400 EM110TX [EX110TX] 110a Siemens Nixdorf AG @@ -1495,23 +1945,27 @@ # DJ- Some people say that 0x1112 is Rockwell International ? 1112 RNS - Div. of Meret Communications Inc 2200 FDDI Adapter + 2300 Fast Ethernet Adapter 2340 4 Port Fast Ethernet Adapter 2400 ATM Adapter 1113 Accton Technology Corporation 1211 SMC2-1211TX + 103c 1207 EN-1207D Fast Ethernet Adapter + 1113 1211 EN-1207D Fast Ethernet Adapter 1217 EN-1217 Ethernet Adapter 5105 10Mbps Network card 9211 EN-1207D Fast Ethernet Adapter + 1113 9211 EN-1207D Fast Ethernet Adapter 1114 Atmel Corporation 1115 3D Labs 1116 Data Translation 0022 DT3001 0023 DT3002 0024 DT3003 - 0028 DT3003-PGL 0025 DT3004 0026 DT3005 0027 DT3001-PGL + 0028 DT3003-PGL 1117 Datacube, Inc 9500 Max-1C SVGA card 9501 Max-1C image processing @@ -1545,8 +1999,8 @@ 0115 GDT 6121RP1/6521RP1 0118 GDT 6x18RD 0119 GDT 6x28RD - 011A GDT 6x38RD - 011B GDT 6x58RD + 011a GDT 6x38RD + 011b GDT 6x58RD 0120 GDT 6117RP2/6517RP2 0121 GDT 6127RP2/6527RP2 0122 GDT 6537RP2 @@ -1555,8 +2009,8 @@ 0125 GDT 6121RP2/6521RP2 0168 GDT 7x18RN 0169 GDT 7x28RN - 016A GDT 7x38RN - 016B GDT 7x58RN + 016a GDT 7x38RN + 016b GDT 7x58RN 0210 GDT 6x19RD 0211 GDT 6x29RD 0260 GDT 7x19RN @@ -1565,7 +2019,9 @@ 0000 155P-MF1 (FPGA) 0002 155P-MF1 (ASIC) 0003 ENI-25P ATM Adapter + 111a 0000 ENI-25p Miniport ATM Adapter 0005 Speedstream 30xx ATM Adapter + 111a 0001 SS-3010 Miniport ATM Adapter 111b Teledyne Electronic Systems 111c Tricord Systems Inc. 0001 Powerbis Bridge @@ -1581,6 +2037,7 @@ 1123 Excellent Design, Inc. 1124 Leutron Vision AG 1125 Eurocore +1126 Vigra 1127 FORE Systems Inc 0200 ForeRunner PCA-200 ATM 0210 PCA-200PC @@ -1601,6 +2058,9 @@ 1131 Philips Semiconductors 7145 SAA7145 7146 SAA7146 + 114b 2003 DVRaptor Video Edit/Capture Card + 11bd 0006 DV500 Overlay + 11bd 000a DV500 Overlay 1132 Mitel Corp. 1133 Eicon Technology Corporation 7901 EiconCard S90 @@ -1612,11 +2072,17 @@ b921 EiconCard P92 b922 EiconCard P92 e001 DIVA 20PRO + 1133 e001 DIVA Pro 2.0 S/T e002 DIVA 20 + 1133 e002 DIVA 2.0 S/T e003 DIVA 20PRO_U + 1133 e003 DIVA Pro 2.0 U e004 DIVA 20_U + 1133 e004 DIVA 2.0 U e010 DIVA Server BRI-2M + 1133 e010 DIVA Server BRI-2M e014 DIVA Server PRO-30M + 1133 e014 DIVA Server PRI-30M 1134 Mercury Computer Systems 0001 Raceway Bridge 1135 Fuji Xerox Co Ltd @@ -1626,6 +2092,7 @@ 1138 Ziatech Corporation 8905 8905 [STD 32 Bridge] 1139 Dynamic Pictures, Inc + 0001 VGA Compatable 3D Graphics 113a FWB Inc 113b Network Computing Devices 113c Cyclone Microsystems, Inc. @@ -1640,9 +2107,9 @@ 113f Equinox Systems, Inc. 0808 SST-64P Adapter 1010 SST-128P Adapter - 80C0 SST-16P Adapter - 80C4 SST-16P Adapter - 80C8 SST-16P Adapter + 80c0 SST-16P Adapter + 80c4 SST-16P Adapter + 80c8 SST-16P Adapter 8888 SST-4P Adapter 9090 SST-8P Adapter 1140 Intervoice Inc @@ -1699,8 +2166,8 @@ 0006 AccelePort Xr,C/X 0009 AccelePort Xr/J 000a AccelePort EPC/J - 000C DataFirePRIme T1 (1-port) - 000D SyncPort 2-Port (x.25/FR) + 000c DataFirePRIme T1 (1-port) + 000d SyncPort 2-Port (x.25/FR) 0011 AccelePort 8r EIA-232 (IBM) 0012 AccelePort 8r EIA-422 0013 AccelePort Xr @@ -1708,9 +2175,9 @@ 0015 AccelePort Xem 0016 AccelePort EPC/X 0017 AccelePort C/X - 001A DataFirePRIme E1 (1-port) - 001B AccelePort C/X (IBM) - 001D DataFire RAS T1/E1/PRI + 001a DataFirePRIme E1 (1-port) + 001b AccelePort C/X (IBM) + 001d DataFire RAS T1/E1/PRI 0023 AccelePort RAS 0024 DataFire RAS B4 ST/U 0026 AccelePort 4r 920 @@ -1760,6 +2227,7 @@ 1014 0183 10/100 EtherJet Cardbus Adapter 115d 0183 Cardbus Ethernet 10/100 0101 Cardbus 56k modem + 115d 1081 Cardbus 56k Modem 0103 Cardbus Ethernet + 56k Modem 115d 1181 CBEM56G-100 Ethernet + 56k Modem 8086 9181 PRO/100 LAN + Modem56 CardBus @@ -1771,10 +2239,12 @@ 1163 Rendition 0001 Verite 1000 2000 Verite V2000/V2100/V2200 + 1092 2000 Stealth II S220 1164 Advanced Peripherals Technologies 1165 Imagraph Corporation 0001 Motion TPEG Recorder/Player with audio 1166 Relience Computer + 0007 CNB20-LE CPU to PCI Bridge 0008 CNB20HE 0009 CNB20HE 1167 Mutoh Industries Inc @@ -1799,6 +2269,7 @@ 1176 SBE Incorporated 1177 Silicon Engineering 1178 Alfa, Inc. + afa1 Fast Ethernet Adapter 1179 Toshiba America Info Systems 0404 DVD Decoder card 0406 Tecra Video Capture device @@ -1807,9 +2278,14 @@ 0603 ToPIC95 PCI to CardBus Bridge for Notebooks 060a ToPIC95 060f ToPIC97 + 0617 ToPIC95 PCI to Cardbus Bridge with ZV Support + 0618 CPU to PCI and PCI to ISA bridge 0701 FIR Port # This is apparently incorrect. Does anyone know the correct ID? # 0701 Lucent DSP1645 [Mars] + 0d01 FIR Port Type-DO + 1179 0001 FIR Port Type-DO +117a A-Trend Technology 117b L G Electronics, Inc. 117c Atto Technology 117d Becton & Dickinson @@ -1856,7 +2332,9 @@ 118e Hermstedt GmbH 118f Green Logic 1190 Tripace + c731 TP-910/920/940 PCI Ultra(Wide) SCSI Adapter 1191 Artop Electronic Corp + 0003 SCSI Cache Host Adapter 0004 ATP8400 0005 ATP850UF 0006 ATP860 NO-BIOS @@ -1908,6 +2386,7 @@ 11ad f003 LNE100TX 11ad ffff LNE100TX 1385 f004 FA310TX + c115 LNE100TX Fast Ethernet Adapter 11ae Aztech System Ltd 11af Avid Technology Inc. 11b0 V3 Semiconductor Inc. @@ -1920,6 +2399,7 @@ 11b4 Leitch Technology International 11b5 Radstone Technology Plc 11b6 United Video Corp +11b7 Motorola 11b8 XPoint Technologies, Inc 0001 Quad PeerMaster 11b9 Pathlight Technology Inc. @@ -1976,6 +2456,11 @@ 144d 2104 LT56PT Modem 149f 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 1668 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + 0443 LT WinModem + 0444 LT WinModem + 0445 LT WinModem + 0446 LT WinModem + 0447 LT WinModem 0448 WinModem 56k 13e0 0040 LT WinModem 56k Data+Fax+Voice+Dsvd 0449 WinModem 56k @@ -1984,12 +2469,28 @@ 13e0 0041 TelePath Internet 56k WinModem 144f 0449 Lucent 56k V.90 DFi Modem 1468 0449 Presario 56k V.90 DFi Modem - 044A F-1156IV WinModem (V90, 56KFlex) + 044a F-1156IV WinModem (V90, 56KFlex) 13e0 0012 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 13e0 0042 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 144f 1005 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + 044b LT WinModem + 044c LT WinModem + 044d LT WinModem + 044e LT WinModem + 0450 LT WinModem + 0451 LT WinModem + 0452 LT WinModem + 0453 LT WinModem + 0454 LT WinModem + 0455 LT WinModem + 0456 LT WinModem + 0457 LT WinModem + 0458 LT WinModem + 0459 LT WinModem + 045a LT WinModem 0480 Venus WinModem (V90, 56KFlex) 11c2 Sand Microelectronics +11c3 NEC Corp 11c4 Document Technologies, Inc 11c5 Shiva Corporation 11c6 Dainippon Screen Mfg. Co. Ltd @@ -2072,6 +2573,7 @@ 1401 ReadyLink 2000 2011 RL100-ATX 10/100 2201 ReadyLink 100TX (Winbond W89C840) + 11f6 2011 ReadyLink 100TX 9881 RL100TX 11f7 Scientific Atlanta 11f8 PMC-Sierra Inc. @@ -2090,9 +2592,9 @@ 0006 RocketPort 8J 0008 RocketPort 8-port 0009 RocketPort 16-port - 000A RocketPort Plus Quadcable - 000B RocketPort Plus Octacable - 000C RocketPort 8-port Modem + 000a RocketPort Plus Quadcable + 000b RocketPort Plus Octacable + 000c RocketPort 8-port Modem 11ff Scion Corporation 1200 CSS Corporation 1201 Vista Controls Corp @@ -2131,6 +2633,8 @@ 673a 6730 6832 6832 6836 6836 + 6872 OZ6812 Cardbus Controller + 6933 OZ6933 Cardbus Controller 1218 Hybricon Corp. 1219 First Virtual Corporation 121a 3Dfx Interactive, Inc. @@ -2144,10 +2648,16 @@ 1092 4803 Monster Fusion AGP 1092 8030 Monster Fusion 1092 8035 Monster Fusion AGP + 10b0 0001 Dragon 4000 + 1102 1017 CT6760 3D Blaster Banshee 121a 0001 Voodoo Banshee AGP 121a 0003 Voodoo Banshee AGP SGRAM 121a 0004 Voodoo Banshee + 139c 0016 Raven + 139c 0017 Raven + 14af 0002 Maxi Gamer Phoenix 3030 3030 Skywell Magic TwinPower + 0004 Voodoo Banshee 0005 Voodoo 3 121a 0004 Voodoo3 AGP 121a 0030 Voodoo3 AGP @@ -2188,7 +2698,9 @@ 122d Aztech System Ltd 1206 368DSP 50dc 3328 Audio + 122d 0001 3328 Audio 80da 3328 Audio + 122d 0001 3328 Audio 122e Xyratex 122f Andrew Corporation 1230 Fishcamp Engineering @@ -2213,7 +2725,13 @@ 123e Simutech, Inc. 123f C-Cube Microsystems 00e4 MPEG + 8120 E4? + 11bd 0006 DV500 E4 + 11bd 000a DV500 E4 8888 Cinemaster C 3.0 DVD Decoder + 1002 0001 Cinemaster C 3.0 DVD Decoder + 1002 0002 Cinemaster C 3.0 DVD Decoder + 1328 0001 Cinemaster C 3.0 DVD Decoder 1240 Marathon Technologies Corp. 1241 DSC Communications 1242 Jaycor Networks, Inc. @@ -2222,6 +2740,7 @@ 1244 AVM Audiovisuelles MKTG & Computer System GmbH 0700 B1 ISDN 0a00 A1 ISDN [Fritz] + 1244 0a00 FRITZ!Card ISDN Controller 1245 A.P.D., S.A. 1246 Dipix Technologies, Inc. 1247 Xylon Research, Inc. @@ -2259,10 +2778,26 @@ 0000 ES336H Fax Modem (Early Model) 1948 Solo? 1968 ES1968 Maestro 2 + 1028 0085 ES1968 Maestro-2 PCI + 1033 8051 ES1968 Maestro-2 Audiodrive 1969 ES1969 Solo-1 Audiodrive + 1014 0166 ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard + 125d 8888 Solo-1 Audio Adapter + 525f c888 ES1969 SOLO-1 AudioDrive (+ES1938) 1978 ES1978 Maestro 2E + 1033 803c ES1978 Maestro-2E Audiodrive + 1033 8058 ES1978 Maestro-2E Audiodrive + 1092 4000 Monster Sound MX400 + 1179 0001 ES1978 Maestro-2E Audiodrive 1988 ES1988 Allegro-1 + 1092 4100 Sonic Impact S100 + 125d 1988 ESS Allegro-1 Audiodrive + 1989 ESS Modem + 125d 1989 ESS Modem + 1998 ES1983S Maestro-3i PCI Audio Accelerator + 1999 ES1983S Maestro-3i PCI Modem Accelerator 2808 ES336H Fax Modem (Later Model) + 2838 ES2838/2839 SuperLink Modem 2898 ES2898 Modem 125e Specialvideo Engineering SRL 125f Concurrent Technologies, Inc. @@ -2277,6 +2812,7 @@ 1266 Microdyne Corporation 0001 NE10/100 Adapter (i82557B) 1910 NE2000Plus (RT8029) Ethernet Adapter + 1266 1910 NE2000Plus Ethernet Adapter 1267 S. A. Telecommunications 5352 PCR2101 5a4b Telsat Turbo @@ -2288,6 +2824,12 @@ 126d Splash Technology, Inc. 126e Sumitomo Metal Industries, Ltd. 126f Silicon Motion, Inc. + 0710 SM710 LynxEM + 0712 SM712 LynxEM+ + 0720 SM720 Lynx3DM + 0810 SM810 LynxE + 0811 SM811 LynxE + 0820 SM820 Lynx3D 0910 SM910 1270 Olympus Optical Co., Ltd. 1271 GW Instruments @@ -2296,7 +2838,66 @@ 0002 DirecPC 1274 Ensoniq 1371 ES1371 [AudioPCI-97] + 0e11 b1a7 ES1371, ES1373 AudioPCI + 1033 80ac ES1371, ES1373 AudioPCI + 1042 1854 Tazer + 107b 8054 Tabor2 + 1274 1371 Creative Sound Blaster AudioPCI64V, AudioPCI128 + 1462 6470 ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A + 1462 6560 ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10 + 1462 6630 ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A + 1462 6631 ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A + 1462 6632 ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A + 1462 6633 ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A + 1462 6820 ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00 + 1462 6822 ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A + 1462 6830 ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00 + 1462 6880 ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00 + 1462 6900 ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00 + 1462 6910 ES1371, ES1373 AudioPCI On Motherboard MS-6191 + 1462 6930 ES1371, ES1373 AudioPCI On Motherboard MS-6193 + 1462 6990 ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A + 1462 6991 ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A + 14a4 2077 ES1371, ES1373 AudioPCI On Motherboard KR639 + 14a4 2105 ES1371, ES1373 AudioPCI On Motherboard MR800 + 14a4 2107 ES1371, ES1373 AudioPCI On Motherboard MR801 + 14a4 2172 ES1371, ES1373 AudioPCI On Motherboard DR739 + 1509 9902 ES1371, ES1373 AudioPCI On Motherboard KW11 + 1509 9903 ES1371, ES1373 AudioPCI On Motherboard KW31 + 1509 9904 ES1371, ES1373 AudioPCI On Motherboard KA11 + 1509 9905 ES1371, ES1373 AudioPCI On Motherboard KC13 + 152d 8801 ES1371, ES1373 AudioPCI On Motherboard CP810E + 152d 8802 ES1371, ES1373 AudioPCI On Motherboard CP810 + 152d 8803 ES1371, ES1373 AudioPCI On Motherboard P3810E + 152d 8804 ES1371, ES1373 AudioPCI On Motherboard P3810-S + 152d 8805 ES1371, ES1373 AudioPCI On Motherboard P3820-S + 270f 2001 ES1371, ES1373 AudioPCI On Motherboard 6CTR + 270f 2200 ES1371, ES1373 AudioPCI On Motherboard 6WTX + 270f 3000 ES1371, ES1373 AudioPCI On Motherboard 6WSV + 270f 3100 ES1371, ES1373 AudioPCI On Motherboard 6WIV2 + 270f 3102 ES1371, ES1373 AudioPCI On Motherboard 6WIV + 270f 7060 ES1371, ES1373 AudioPCI On Motherboard 6ASA2 + 8086 4249 ES1371, ES1373 AudioPCI On Motherboard BI440ZX + 8086 424c ES1371, ES1373 AudioPCI On Motherboard BL440ZX + 8086 425a ES1371, ES1373 AudioPCI On Motherboard BZ440ZX + 8086 4341 ES1371, ES1373 AudioPCI On Motherboard Cayman + 8086 4343 ES1371, ES1373 AudioPCI On Motherboard Cape Cod + 8086 4649 ES1371, ES1373 AudioPCI On Motherboard Fire Island + 8086 464a ES1371, ES1373 AudioPCI On Motherboard FJ440ZX + 8086 4d4f ES1371, ES1373 AudioPCI On Motherboard Montreal + 8086 4f43 ES1371, ES1373 AudioPCI On Motherboard OC440LX + 8086 5243 ES1371, ES1373 AudioPCI On Motherboard RC440BX + 8086 5352 ES1371, ES1373 AudioPCI On Motherboard SunRiver + 8086 5643 ES1371, ES1373 AudioPCI On Motherboard Vancouver + 8086 5753 ES1371, ES1373 AudioPCI On Motherboard WS440BX 5000 ES1370 [AudioPCI] + 5880 5880 AudioPCI + 1274 2000 Creative Sound Blaster AudioPCI128 + 1274 5880 Creative Sound Blaster AudioPCI128 + 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 + 270f 2001 5880 AudioPCI On Motherboard 6CTR + 270f 2200 5880 AudioPCI On Motherboard 6WTX + 270f 7040 5880 AudioPCI On Motherboard 6ATA4 1275 Network Appliance Corporation 1276 Switched Network Technologies, Inc. 1277 Comstream @@ -2305,15 +2906,37 @@ 0295 Virtual Northbridge 127a Rockwell International 1002 HCF 56k V90 FaxModem + 127a 1002 HCF 56k V90 Modem 1003 HCF 56k V90 FaxModem + 127a 1003 PCI56RX Modem + 13df 1003 PCI56RX Modem 1004 HCF 56k V90 FaxModem 1005 HCF 56k V90 FaxModem 122d 4008 MDP3858SP-A SVD Modem 127a 1005 PCI56RVP Modem 13df 1005 PCI56RVP Modem 1436 1005 WS-5614PS3G + 1025 HCF 56k PCI Modem + 127a 1025 HCF 56k PCI Modem + 1026 HCF 56k PCI Speakerphone Modem + 127a 1026 HCF 56k PCI Speakerphone Modem + 1035 HCF 56k PCI Speakerphone Modem + 127a 1035 HCF 56k PCI Speakerphone Modem + 1085 Volcano HCF 56k PCI Modem + 127a 1085 Volcano HCF 56k PCI Modem 2005 HCF 56k V90 FaxModem + 127a 2005 Conexant SoftK56 Speakerphone Modem + 2015 Conexant SoftK56 Speakerphone Modem + 127a 2015 Conexant SoftK56 Speakerphone Modem + 14c8 2115 Conexant SoftK56 Speakerphone Modem + 4320 Riptide PCI Audio Controller + 1235 4320 Riptide PCI Audio Controller + 4321 Riptide HCF 56k PCI Modem + 1235 4321 Riptide HCF 56k PCI Modem + 4322 Riptide PCI Game Controller + 1235 4322 Riptide PCI Game Controller 8234 RapidFire 616X ATM155 Adapter + 108d 0027 RapidFire 616X ATM155 Adapter 127b Pixera Corporation 127c Crosspoint Solutions, Inc. 127d Vela Research @@ -2326,6 +2949,8 @@ 1283 Integrated Technology Express, Inc. 673a IT8330G 8330 IT8330G + 8888 IT8888F PCI to ISA Bridge with SMB + 8889 IT8889F PCI to ISA Bridge e886 IT8330G 1284 Sahara Networks, Inc. 1285 Platform Technologies, Inc. @@ -2376,6 +3001,7 @@ 12a9 Xiotech Corporation 12aa SDL Communications, Inc. 12ab Yuan Yuan Enterprise Co., Ltd. + 3000 MPG-200C PCI DVD Decoder Card 12ac Measurex Corporation 12ad Multidata GmbH 12ae Alteon Networks Inc. @@ -2392,7 +3018,23 @@ 12b8 Korg 12b9 US Robotics/3Com 1006 WinModem + 12b9 005c USR 56k Internal Voice WinModem (Model 3472) + 12b9 005e USR 56k Internal WinModem (Models 662975) + 12b9 0062 USR 56k Internal Voice WinModem (Model 662978) + 12b9 0068 USR 56k Internal Voice WinModem (Model 5690) + 12b9 007a USR 56k Internal Voice WinModem (Model 662974) + 12b9 007f USR 56k Internal WinModem (Models 5698, 5699) + 12b9 0080 USR 56k Internal WinModem (Models 2975, 3528) + 12b9 0081 USR 56k Internal Voice WinModem (Models 2974, 3529) + 12b9 0091 USR 56k Internal Voice WinModem (Model 2978) + 1007 USR 56k Internal WinModem + 12b9 00a3 USR 56k Internal WinModem (Model 3595) 1008 56K FaxModem Model 5610 + 12b9 00a2 USR 56k Internal FAX Modem (Model 2977) + 12b9 00aa USR 56k Internal Voice Modem (Model 2976) + 12b9 00ab USR 56k Internal Voice Modem (Model 5609) + 12b9 00ac USR 56k Internal Voice Modem (Model 3298) + 12b9 00ad USR 56k Internal FAX Modem (Model 5610) 12ba PMC Sierra 12bb Nippon Unisoft Corporation 12bc Array Microsystems @@ -2400,6 +3042,7 @@ 12be Anchor Chips Inc. 3041 AN3041Q CO-MEM 3042 AN3042Q CO-MEM Lite + 12be 3042 Anchor Chips Lite Evaluation Board 12bf Fujifilm Microdevices 12c0 Infimed 12c1 GMM Research Corp @@ -2438,12 +3081,13 @@ 10b4 222a STB Velocity 128 AGP 10b4 2230 STB Velocity 128 10b4 2235 STB Velocity 128 AGP + 2a15 54a3 3DVision-SAGP 0019 Riva128ZX 0020 TNT 0028 TNT2 0029 UTNT2 - 002C VTNT2 - 00A0 ITNT2 + 002c VTNT2 + 00a0 ITNT2 12d3 Vingmed Sound A/S 12d4 DGM&S 12d5 Equator Technologies @@ -2473,7 +3117,38 @@ 12ea Zuken 12eb Aureal Semiconductor 0001 Vortex 1 + 104d 8036 AU8820 Vortex Digital Audio Processor + 1092 2000 Sonic Impact A3D + 1092 2100 Sonic Impact A3D + 1092 2110 Sonic Impact A3D + 1092 2200 Sonic Impact A3D + 12eb 0001 AU8820 Vortex Digital Audio Processor + 5053 3355 Montego 0002 Vortex 2 + 104d 8049 AU8830 Vortex 3D Digital Audio Processor + 104d 807b AU8830 Vortex 3D Digital Audio Processor + 1092 3000 Monster Sound II + 1092 3001 Monster Sound II + 1092 3002 Monster Sound II + 1092 3003 Monster Sound II + 1092 3004 Monster Sound II + 12eb 0001 AU8830 Vortex 3D Digital Audio Processor + 12eb 0002 AU8830 Vortex 3D Digital Audio Processor + 12eb 0088 AU8830 Vortex 3D Digital Audio Processor + 144d 3510 AU8830 Vortex 3D Digital Audio Processor + 5053 3356 Montego II + 0003 AU8810 Vortex Digital Audio Processor + 104d 8049 AU8810 Vortex Digital Audio Processor + 104d 8077 AU8810 Vortex Digital Audio Processor + 109f 1000 AU8810 Vortex Digital Audio Processor + 12eb 0003 AU8810 Vortex Digital Audio Processor + 1462 6780 AU8810 Vortex Digital Audio Processor + 14a4 2073 AU8810 Vortex Digital Audio Processor + 14a4 2091 AU8810 Vortex Digital Audio Processor + 14a4 2104 AU8810 Vortex Digital Audio Processor + 14a4 2106 AU8810 Vortex Digital Audio Processor + 8803 Vortex 56k Software Modem + 12eb 8803 Vortex 56k Software Modem 12ec 3A International, Inc. 12ed Optivision Inc. 12ee Orange Micro @@ -2502,10 +3177,10 @@ 1306 Duet Technologies 1307 Computer Boards 0001 PCI-DAS1602/16 - 000C PCI-PDISO8 - 000D PCI-PDISO16 - 000B PCI-DIO48H - 000F PCI-DAS1200 + 000b PCI-DIO48H + 000c PCI-PDISO8 + 000d PCI-PDISO16 + 000f PCI-DAS1200 0010 PCI-DAS1602/12 0014 PCI-DIO24H 0015 PCI-DIO24H/CTR3 @@ -2513,12 +3188,12 @@ 0017 PCI-DIO96H 0018 PCI-CTR05 0019 PCI-DAS1200/JR - 001A PCI-DAS1001 - 001B PCI-DAS1002 - 001C PCI-DAS1602JR/16 - 001D PCI-DAS6402/16 - 001E PCI-DAS6402/12 - 001F PCI-DAS16/M1 + 001a PCI-DAS1001 + 001b PCI-DAS1002 + 001c PCI-DAS1602JR/16 + 001d PCI-DAS6402/16 + 001e PCI-DAS6402/12 + 001f PCI-DAS16/M1 0020 PCI-DDA02/12 0021 PCI-DDA04/12 0022 PCI-DDA08/12 @@ -2529,15 +3204,16 @@ 0027 PCI-DAC04/16-HS 0028 PCI-DIO24 0029 PCI-DAS08 - 002C PCI-INT32 + 002c PCI-INT32 0033 PCI-DUAL-AC5 0034 PCI-DAS-TC 0035 PCI-DAS64/M1/16 0036 PCI-DAS64/M2/16 0037 PCI-DAS64/M3/16 - 004C PCI-DAS1000 + 004c PCI-DAS1000 1308 Jato Technologies Inc. 0001 NetCelerator Adapter + 1308 0001 NetCelerator Adapter 1309 AB Semiconductor Ltd 130a Mitsubishi Electric Microcomputer 130b Colorgraphic Communications Corp @@ -2552,9 +3228,12 @@ 1316 Teradyne Inc 1317 Bridgecom, Inc 1318 Packet Engines Inc. + 0911 PCI Ethernet Adapter 1319 Fortemedia, Inc 0801 Xwave QS3000A [FM801] 0802 Xwave QS3000A [FM801 game port] + 1000 FM801 PCI Audio + 1001 FM801 PCI Joystick 131a Finisar Corp. 131c Nippon Electro-Sensory Devices Corp 131d Sysmic, Inc. @@ -2586,6 +3265,7 @@ 2020 CyberParallel (1-port) 2021 CyberParallel (2-port) 2030 CyberSerial (2-port) 16550 + 131f 2030 PCI Serial Card 2031 CyberSerial (2-port) 16650 2032 CyberSerial (2-port) 16850 2040 Trio 1S(16550)+2P @@ -2634,9 +3314,19 @@ 1349 Sumitomo Electric Industries, Ltd. 134a DTC Technology Corp. 0001 Domex 536 + 0002 Domex DMX3194UP SCSI Adapter 134b ARK Research Corp. 134c Chori Joho System Co. Ltd 134d PCTel Inc + 7890 HSP MicroModem 56 + 7891 HSP MicroModem 56 + 134d 0001 HSP MicroModem 56 + 7892 HSP MicroModem 56 + 7893 HSP MicroModem 56 + 7894 HSP MicroModem 56 + 7895 HSP MicroModem 56 + 7896 HSP MicroModem 56 + 7897 HSP MicroModem 56 134e CSTI 134f Algo System Co Ltd 1350 Systec Co. Ltd @@ -2658,6 +3348,7 @@ 7402 Four Port RS-422/485 Interface 7801 Eight Port RS-232 Interface 8001 8001 Digital I/O Adapter +135f I-Data International A-S 1360 Meinberg Funkuhren 1361 Soliton Systems K.K. 1362 Fujifacom Corporation @@ -2715,8 +3406,8 @@ 1396 Cipher Systems Inc 1397 Cologne Chip Designs GmbH 2bd0 ISDN network controller [HFC-PCI] - 1397 2bd0 ISDN Board - e4bf 1000 CI1-1-Harp + 1397 2bd0 ISDN Board + e4bf 1000 CI1-1-Harp 1398 Clarion co. Ltd 1399 Rios systems Co Ltd 139a Alacritech Inc @@ -2792,6 +3483,7 @@ 13de ABB Robotics Products AB 13df E-Tech Inc 0001 PCI56RVP Modem + 13df 0001 PCI56RVP Modem 13e0 GVC Corporation 13e1 Silicom Multimedia Systems Inc 13e2 Dynamics Research Corporation @@ -2816,8 +3508,11 @@ 13f5 Kansai Electric Co. Ltd 13f6 C-Media Electronics Inc 0100 CM8338A + 13f6 ffff CMI8338/C3DX PCI Audio Device 0101 CM8338B + 13f6 0101 CMI8338-031 PCI Audio Device 0111 CM8738 + 13f6 0111 CMI8738/C3DX PCI Audio Device 0211 CM8738 13f7 Wildfire Communications 13f8 Ad Lib Multimedia Inc @@ -2906,6 +3601,16 @@ 1448 Alesis Studio Electronics 1449 TUT Systems Inc 144a Adlink Technology + 7296 PCI-7296 + 7432 PCI-7432 + 7433 PCI-7433 + 7434 PCI-7434 + 7841 PCI-7841 + 8133 PCI-8133 + 8554 PCI-8554 + 9111 PCI-9111 + 9113 PCI-9113 + 9114 PCI-9114 144b Loronix Information Systems Inc 144c Catalina Research Inc 144d Samsung Electronics Co Ltd @@ -2988,7 +3693,7 @@ 149a ANDOR Technology Ltd 149b SEIKO Instruments Inc 149c OVISLINK Corp. -149D NEWTEK Inc +149d NEWTEK Inc 149e Mapletree Networks Inc. 149f LECTRON Co Ltd 14a0 SOFTING GmBH @@ -3086,7 +3791,27 @@ 14ef CARRY Computer ENG. CO Ltd 14f0 CANON RESEACH CENTRE FRANCE 14f1 CONEXANT + 1033 56K Winmodem + 13e0 02b0 56K Winmodem + 1035 PCI Modem Enumerator + 2003 SoftK56 Winmodem + 14f1 2003 SoftK56 Winmodem + 2004 SoftK56 RemoteTAM Winmodem + 14f1 2004 SoftK56 RemoteTAM Winmodem + 2005 SoftK56 Speakerphone Winmodem + 14f1 2005 SoftK56 Speakerphone Winmodem + 2006 SoftK56 Speakerphone Winmodem + 14f1 2006 SoftK56 Speakerphone Winmodem 2013 HSP MicroModem 56K + 14f1 2013 SoftK56 Winmodem + 2014 SoftK56 RemoteTAM Winmodem + 144f 101c SoftK56 RemoteTAM Winmodem + 144f 2014 SoftK56 RemoteTAM Winmodem + 2015 SoftK56 Speakerphone Winmodem + 14c8 2115 SoftK56 Speakerphone Winmodem + 14f1 2015 SoftK56 Speakerphone Winmodem + 2016 SoftK56 Speakerphone Winmodem + 14f1 2016 SoftK56 Speakerphone Winmodem 14f2 MOBILITY Electronics 14f3 BROADLOGIC 14f4 TOKYO Electronic Industry CO Ltd @@ -3111,6 +3836,16 @@ # 1507 HTEC Ltd # Commented out because there are no known HTEC chips and 1507 is already # used by mistake by Motorola (see vendor ID 1057) +1507 Motorola ?? / HTEC + 0001 MPC105 [Eagle] + 0002 MPC106 [Grackle] + 0003 MPC8240 [Kahlua] + 0100 MC145575 [HFC-PCI] + 0431 KTI829c 100VG + 4801 Raven + 4802 Falcon + 4803 Hawk + 4806 CPX8216 1508 HONDA CONNECTORS/MHOTRONICS Inc 1509 FIRST INTERNATIONAL Computer Inc 150a FORVUS RESEARCH Inc @@ -3197,7 +3932,189 @@ 1559 SI LOGIC Ltd 155a INNOMEDIA Inc 155b PROTAC INTERNATIONAL Corp +155c Cemax-Icon Inc +155d Mac System Co Ltd +155e LP Elektronik GmbH +155f Perle Systems Ltd +1560 Terayon Communications Systems +1561 Viewgraphics Inc +1562 Symbol Technologies +1563 A-Trend Technology Co Ltd +1564 Yamakatsu Electronics Industry Co Ltd +1565 Biostar Microtech Int'l Corp +1566 Ardent Technologies Inc +1567 Jungsoft +1568 DDK Electronics Inc +1569 Palit Microsystems Inc. +156a Avtec Systems +156b 2wire Inc +156c Vidac Electronics GmbH +156d Alpha-Top Corp +156e Alfa Inc +156f M-Systems Flash Disk Pioneers Ltd +1570 Lecroy Corp +1571 Contemporary Controls +1572 Otis Elevator Company +1573 Lattice - Vantis +1574 Fairchild Semiconductor +1575 Voltaire Advanced Data Security Ltd +1576 Viewcast COM +1578 HITT +1579 Dual Technology Corp +157a Japan Elecronics Ind Inc +157b Star Multimedia Corp +157c Eurosoft (UK) + 8001 Fix2000 PCI Y2K Compliance Card +157d Gemflex Networks +157e Transition Networks +157f PX Instruments Technology Ltd +1580 Primex Aerospace Co +1581 SEH Computertechnik GmbH +1582 Cytec Corp +1583 Inet Technologies Inc +1584 Uniwill Computer Corp +1585 Logitron +1586 Lancast Inc +1587 Konica Corp +1588 Solidum Systems Corp +1589 Atlantek Microsystems Pty Ltd +158a Digalog Systems Inc +158b Allied Data Technologies +158c Hitachi Semiconductor & Devices Sales Co Ltd +158d Point Multimedia Systems +158e Lara Technology Inc +158f Ditect Coop +1590 3pardata Inc +1591 ARN +1592 Syba Tech Ltd + 0781 Multi-IO Card + 0782 Parallel Port Card 2xEPP + 0783 Multi-IO Card + 0785 Multi-IO Card + 0786 Multi-IO Card + 0787 Multi-IO Card + 0788 Multi-IO Card + 078a Multi-IO Card +1593 Bops Inc +1594 Netgame Ltd +1595 Diva Systems Corp +1596 Folsom Research Inc +1597 Memec Design Services +1598 Granite Microsystems +1599 Delta Electronics Inc +159a General Instrument +159b Faraday Technology Corp +159c Stratus Computer Systems +159d Ningbo Harrison Electronics Co Ltd +159e A-Max Technology Co Ltd +159f Galea Network Security +15a0 Compumaster SRL +15a1 Geocast Network Systems +15a2 Catalyst Enterprises Inc +15a3 Italtel +15a4 X-Net OY +15a5 Toyota Macs Inc +15a6 Sunlight Ultrasound Technologies Ltd +15a7 SSE Telecom Inc +15a8 Shanghai Communications Technologies Center +15aa Moreton Bay +15ab Bluesteel Networks Inc +15ac North Atlantic Instruments +15ad VMWare Inc + 0710 Virtual SVGA +15ae Amersham Pharmacia Biotech +15b0 Zoltrix International Ltd +15b1 Source Technology Inc +15b2 Mosaid Technologies Inc +15b3 Mellanox Technology +15b4 CCI/TRIAD +15b5 Cimetrics Inc +15b6 Texas Memory Systems Inc +15b7 Sandisk Corp +15b8 ADDI-DATA GmbH +15b9 Maestro Digital Communications +15ba Impacct Technology Corp +15bb Portwell Inc +15bc Agilent Technologies +15bd DFI Inc +15be Sola Electronics +15bf High Tech Computer Corp (HTC) +15c0 BVM Ltd +15c1 Quantel +15c2 Newer Technology Inc +15c3 Taiwan Mycomp Co Ltd +15c4 EVSX Inc +15c5 Procomp Informatics Ltd +15c6 Technical University of Budapest +15c7 Tateyama Dystem Laboratory Co Ltd +15c8 Penta Media Co Ltd +15c9 Serome Technology Inc +15ca Bitboys OY +15cb AG Electronics Ltd +15cc Hotrail Inc +15cd Dreamtech Co Ltd +15ce Genrad Inc +15cf Hilscher GmbH +15d1 Infineon Technologies AG +15d2 FIC (First International Computer Inc) +15d3 NDS Technologies Israel Ltd +15d4 Iwill Corp +15d5 Tatung Co +15d6 Entridia Corp +15d7 Rockwell-Collins Inc +15d8 Cybernetics Technology Co Ltd +15d9 Super Micro Computer Inc +15da Cyberfirm Inc +15db Applied Computing Systems Inc +15dc Litronic Inc + 0001 Argus 300 PCI Cryptography Module +15dd Sigmatel Inc +15de Malleable Technologies Inc +15df Infinilink Corp +15e0 Cacheflow Inc +15e1 Voice Technologies Group Inc +15e2 Quicknet Technologies Inc +15e3 Networth Technologies Inc +15e4 VSN Systemen BV +15e5 Valley technologies Inc +15e6 Agere Inc +15e7 Get Engineering Corp +15e8 National Datacomm Corp +15e9 Pacific Digital Corp +15ea Tokyo Denshi Sekei K.K. +15eb Drsearch GmbH +15ec Beckhoff GmbH +15ed Macrolink Inc +15ee In Win Development Inc +15ef Intelligent Paradigm Inc +15f0 B-Tree Systems Inc +15f1 Times N Systems Inc +15f2 Diagnostic Instruments Inc +15f3 Digitmedia Corp +15f4 Valuesoft +15f5 Power Micro Research +15f6 Extreme Packet Device Inc +15f7 Banctec +15f8 Koga Electronics Co +15f9 Zenith Electronics Corp +15fa J.P. Axzam Corp +15fb Zilog Inc +15fc Techsan Electronics Co Ltd +15fd N-CUBED.NET +15fe Kinpo Electronics Inc +15ff Fastpoint Technologies Inc +1600 Northrop Grumman - Canada Ltd +1601 Tenta Technology +1602 Prosys-tec Inc +1603 Nokia Wireless Communications +1604 Central System Research Co Ltd +1605 Pairgain Technologies +1606 Europop AG +1607 Lava Semiconductor Manufacturing Inc +1608 Automated Wagering International +1609 Scimetric Instruments Inc 1668 Action Tec Electronics Inc +1813 Ambient Technologies Inc 1a08 Sierra semiconductor 0000 SC15064 1b13 Jaton Corp @@ -3218,13 +4135,19 @@ 270b Xantel Corporation 270f Chaintech Computer Co. Ltd 2711 AVID Technology Inc. +2a15 3D Vision(???) 3000 Hansol Electronics Inc. 3142 Post Impression Systems. 3388 Hint Corp 8011 VXPro II Chipset + 3388 8011 VXPro II Chipset CPU to PCI Bridge 8012 VXPro II Chipset + 3388 8012 VXPro II Chipset PCI to ISA Bridge 8013 VXPro II Chipset + 3388 8013 VXPro II Chipset EIDE Controller +3411 Quantum Designs (H.K.) Inc 3513 ARCOM Control Systems Ltd +38ef 4Links 3d3d 3DLabs 0001 GLINT 300SX 0002 GLINT 500TX @@ -3249,6 +4172,9 @@ 3d04 Permedia ffff Glint VGA 4005 Avance Logic Inc. + 0300 ALS300 PCI Audio Device + 0308 ALS300+ PCI Audio Device + 0309 PCI Input Controller 1064 ALG-2064 2064 ALG-2064i 2128 ALG-2364A GUI Accelerator @@ -3258,7 +4184,11 @@ 2364 ALG-2364A 2464 ALG-2464 2501 ALG-2564A/25128A + 4000 ALS4000 Audio Chipset + 4005 4000 ALS4000 Audio Chipset 4033 Addtron Technology Co, Inc. +4143 Digital Equipment Corp +416c Aladdin Knowledge Systems 4444 Internext Compression Inc 4468 Bridgeport machines 4594 Cogetec Informatique Inc @@ -3269,10 +4199,13 @@ 4978 Axil Computer Inc 4a14 NetVin 5000 NV5000SC + 4a14 5000 RT8029-Based Ethernet Adapter 4b10 Buslogic Inc. 4c48 LUNG HWA Electronics +4ca1 Seanix Technology Inc 4d51 MediaQ Inc. 0200 MQ-200 +4d54 Microtechnica Co Ltd 4ddc ILC Data Device Corp 5053 Voyetra Technologies 2010 Daytona Audio Adapter @@ -3316,7 +4249,9 @@ 88f2 86c968 [Vision 968 VRAM] rev 2 88f3 86c968 [Vision 968 VRAM] rev 3 8900 86c755 [Trio 64V2/DX] + 5333 8900 86C775 Trio64V2/DX 8901 Trio 64V2/DX or /GX + 5333 8901 86C775 Trio64V2/DX, 86C785 Trio64V2/GX 8902 Plato/PX 8903 Trio 3D business multimedia 8904 Trio 64 3D @@ -3343,7 +4278,9 @@ 8a13 86c368 [Trio 3D/2X] 5333 8a13 Trio3D/2X 8a20 86c794 [Savage 3D] + 5333 8a20 86C391 Savage3D 8a21 86c795 [Savage 3D/MV] + 5333 8a21 86C390 Savage3D/MV 8a22 Savage 4 105d 0018 SR9 8Mb SDRAM 105d 002a SR9 Pro 16Mb SDRAM @@ -3351,20 +4288,42 @@ 105d 092f SR9 Pro+ 16Mb SGRAM 1092 4207 Stealth III S540 1092 4800 Stealth III S540 + 1092 4807 SpeedStar A90 1092 4808 Stealth III S540 + 1092 4809 Stealth III S540 1092 480e Stealth III S540 1092 4904 Stealth III S520 + 1092 4905 SpeedStar A200 1092 4a09 Stealth III S540 1092 4a0b Stealth III S540 Xtreme 1092 4a0f Stealth III S540 1092 4e01 Stealth III S540 1102 101d 3d Blaster Savage 4 1102 101e 3d Blaster Savage 4 + 5333 8100 86C394-397 Savage4 SDRAM 100 + 5333 8110 86C394-397 Savage4 SDRAM 110 + 5333 8125 86C394-397 Savage4 SDRAM 125 + 5333 8143 86C394-397 Savage4 SDRAM 143 + 5333 8a22 86C394-397 Savage4 + 5333 8a2e 86C394-397 Savage4 32bit + 5333 9125 86C394-397 Savage4 SGRAM 125 + 5333 9143 86C394-397 Savage4 SGRAM 143 8a23 Savage 4 8c00 ViRGE/M3 8c01 ViRGE/MX 8c02 ViRGE/MX+ 8c03 ViRGE/MX+MV + 8c10 86C270-294 Savage/MX-/IX + 8c12 86C270-294 Savage/MX-/IX + 9102 86C410 Savage 2000 + 1092 5932 Viper II Z200 + 1092 5934 Viper II Z200 + 1092 5952 Viper II Z200 + 1092 5954 Viper II Z200 + 1092 5a35 Viper II Z200 + 1092 5a37 Viper II Z200 + 1092 5a55 Viper II Z200 + 1092 5a57 Viper II Z200 ca00 SonicVibes 544c Teralogic Inc 5455 Technische University Berlin @@ -3404,6 +4363,7 @@ 1014 0119 Netfinity Gigabit Ethernet SX Adapter 8086 1000 EtherExpress PRO/1000 Gigabit Server Adapter 1030 82559 InBusiness 10/100 + 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller 1209 82559ER 1221 82092AA_0 1222 82092AA_1 @@ -3428,10 +4388,11 @@ 1033 8000 PC-9821X-B06 1033 8016 PK-UG-X006 1033 801f PK-UG-X006 - 103c 10C0 Ethernet Pro 10/100TX - 103c 10C3 Ethernet Pro 10/100TX + 103c 10c0 Ethernet Pro 10/100TX + 103c 10c3 Ethernet Pro 10/100TX 103c 1200 Ethernet Pro 10/100TX 10c3 1100 SmartEther100 SC1100 + 1179 0002 PCI FastEther LAN on Docker 1259 2560 AT-2560 100 1259 2561 AT-2560 100 FX Ethernet Adapter 1266 0001 NE10/100 Adapter @@ -3450,7 +4411,7 @@ 8086 000d EtherExpress PRO/100+ Alert On LAN II* Adapter 8086 000e EtherExpress PRO/100+ Management Adapter with Alert On LAN* 8086 1009 EtherExpress PRO/100+ Server Adapter - 8086 100C EtherExpress PRO/100+ Server Adapter (PILA8470B) + 8086 100c EtherExpress PRO/100+ Server Adapter (PILA8470B) 8086 10f0 EtherExpress PRO/100+ Dual Port Adapter 8086 200d EtherExpress PRO/100 Cardbus 8086 200e EtherExpress PRO/100 LAN+V90 Cardbus Modem @@ -3467,21 +4428,30 @@ 1239 82371FB 123b 82380PB 123c 82380AB + 123d 683053 Programmable Interrupt Device 1240 752 AGP 124b 82380FB 1250 430HX - 82439HX TXC [Triton II] + 1360 82806AA PCI64 Hub PCI Bridge + 1361 82806AA PCI64 Hub Controller (HRes) 1960 80960RP [i960RP Microprocessor] 101e 0438 MegaRaid 438 101e 0466 MegaRaid 466 - 103c 10C6 MegaRaid 438 - 103c 10C7 MegaRaid T5 + 103c 10c6 MegaRaid 438 + 103c 10c7 MegaRaid T5 1111 1111 MegaRaid 466 - 113c 03A2 MegaRaid + 113c 03a2 MegaRaid + 1a21 82840 840 (Carmel) Chipset Host Bridge (Hub A) + 1a23 82840 840 (Carmel) Chipset AGP Bridge + 1a24 82840 840 (Carmel) Chipset PCI Bridge (Hub B) 2410 82801AA 82810 Chipset ISA Bridge (LPC) 2411 82801AA 82810 Chipset IDE 2412 82801AA 82810 Chipset USB 2413 82801AA 82810 Chipset SMBus 2415 82801AA 82810 AC'97 Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio + 11d4 5340 SoundMAX Integrated Digital Audio 2416 82801AA 82810 AC'97 Modem 2418 82801AA 82810 PCI Bridge 2420 82801AB 82810 Chipset ISA Bridge (LPC) @@ -3489,10 +4459,21 @@ 2422 82801AB 82810 Chipset USB 2423 82801AB 82810 Chipset SMBus 2425 82801AB 82810 AC'97 Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB 82810 AC'97 Modem 2428 82801AB 82810 PCI Bridge + 2500 82820 820 (Camino) Chipset Host Bridge (MCH) + 1043 801c P3C-2000 system chipset + 2501 82820 820 (Camino) Chipset Host Bridge (MCH) + 1043 801c P3C-2000 system chipset + 250b 82820 820 (Camino) Chipset Host Bridge + 250f 82820 820 (Camino) Chipset PCI to AGP Bridge + 2520 82805AA MTH Memory Translator Hub + 2521 82804AA MRH-S Memory Repeater Hub for SDRAM 5200 EtherExpress PRO/100 5201 EtherExpress PRO/100 + 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter 7000 82371SB PIIX3 ISA [Natoma/Triton II] 7010 82371SB PIIX3 IDE [Natoma/Triton II] 7020 82371SB PIIX3 USB [Natoma/Triton II] @@ -3508,6 +4489,7 @@ 7123 82810-DC100 CGC [Chipset Graphics Controller] 7124 82810E GMCH [Graphics Memory Controller Hub] 7125 82810E CGC [Chipset Graphics Controller] + 7126 82810 810 Chipset Host Bridge and Memory Controller Hub 7180 440LX/EX - 82443LX/EX Host bridge 7181 440LX/EX - 82443LX/EX AGP bridge 7190 440BX/ZX - 82443BX/ZX Host bridge @@ -3515,11 +4497,22 @@ 7191 440BX/ZX - 82443BX/ZX AGP bridge 7192 440BX/ZX - 82443BX/ZX Host bridge (AGP disabled) 0e11 0460 Armada 1700 Laptop System Chipset + 7194 82440MX I/O Controller + 7195 82440MX AC'97 Audio Controller + 10cf 1099 QSound_SigmaTel Stac97 PCI Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio + 7198 82440MX PCI to ISA Bridge + 7199 82440MX EIDE Controller + 719a 82440MX USB Universal Host Controller + 719b 82440MX Power Management Controller 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) + 7600 82372FB PCI to ISA Bridge 7601 82372FB PIIX4 IDE 7602 82372FB [PCI-to-USB UHCI] + 7603 82372FB System Management Bus Controller 7800 i740 1092 0100 Stealth II G460 8086 0100 Intel740 Graphics Accelerator @@ -3544,6 +4537,7 @@ 3b78 AHA-4844W/4844UW 5075 AIC-755x 5078 AHA-7850 + 9004 7850 AHA-2904/Integrated AIC-7850 5175 AIC-755x 5178 AIC-7851 5275 AIC-755x @@ -3562,10 +4556,10 @@ 5900 ANA-5910/5930/5940 ATM155 & 25 LAN Adapter 5905 ANA-5910A/5930A/5940A ATM Adapter 6038 AIC-3860 -# FIXME: This is a cardbus card. The declaration may be duplicative. 6075 AIC-1480 / APA-1480 6078 AIC-7860 6178 AIC-7861 + 9004 7861 AHA-2940AU Single 6278 AIC-7860 6378 AIC-7860 6478 AIC-786 @@ -3595,6 +4589,9 @@ 7678 AHA-4944W/UW / 7876 7778 AIC-787x 7810 AIC-7810 + 7815 AIC-7815 RAID+Memory Controller IC + 9004 7815 ARO-1130U2 RAID Controller + 9004 7840 AIC-7815 RAID+Memory Controller IC 7850 AIC-7850 7855 AHA-2930 7860 AIC-7860 @@ -3610,16 +4607,20 @@ 7893 AIC-789x 7894 AIC-789x 7895 AHA-2940U/UW / AHA-39xx / AIC-7895 + 9004 7895 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B 7896 AIC-789x 7897 AIC-789x 8078 AIC-7880U + 9004 7880 AIC-7880P Ultra/Ultra Wide SCSI Chipset 8178 AIC-7881U + 9004 7881 AHA-2940UW SCSI Host Adapter 8278 AHA-3940U/UW / AIC-7882U 8378 AHA-3940U/UW / AIC-7883U 8478 AHA-294x / AIC-7884U 8578 AHA-3944U / AHA-3944UWD / 7885 8678 AHA-4944UW / 7886 8778 AIC-788x + 9004 7887 2940UW Pro Ultra-Wide SCSI Controller 8878 7888 8b78 ABA-1030 ec78 AHA-4944W/UW @@ -3627,13 +4628,18 @@ 0010 AHA-2940U2/W 0011 2930U2 0013 78902 + 9005 0003 AAA-131U2 Array1000 1 Channel RAID Controller 001f AHA-2940U2/W / 7890 + 9005 000f 2940U2W SCSI Controller + 9005 a180 2940U2W SCSI Controller 0020 AIC-7890 002f AIC-7890 0030 AIC-7890 003f AIC-7890 0050 3940U2 0051 3950U2D + 0053 AIC-7896 SCSI Controller + 9005 ffff AIC-7896 SCSI Controller mainboard implementation 005f 7896 0080 7892A 0081 7892B @@ -3645,8 +4651,11 @@ 00cf 7899P 907f Atronics 2015 IDE-2015PL +919a Gigapixel Corp 9412 Holtek 6565 6565 +9699 Omni Media Technology Inc + 6565 6565 a0a0 AOPEN Inc. a0f1 UNISYS Corporation a200 NEC Corporation @@ -3655,14 +4664,17 @@ a25b Hewlett Packard GmbH PL24-MKT a304 Sony a727 3Com Corporation aa42 Scitex Digital Video +ac1e Digital Receiver Technology Inc b1b3 Shiva Europe Limited c001 TSI Telsys c0a9 Micron/Crucial Technology c0de Motorola c0fe Motion Engineering, Inc. +ca50 Varian Australia Pty Ltd cafe Chrysalis-ITS cccc Catapult Communications d4d4 Dy4 Systems Inc + 0601 PCI Mezzanine Card d84d Exsys e000 Winbond e000 W89C940 @@ -3671,6 +4683,7 @@ e159 Tiger Jet Network Inc. 0059 0001 128k ISDN-S/T Adapter 0059 0003 128k ISDN-U Adapter e4bf EKF Elektronik GmbH +ea01 Eagle Technology eabb Aashima Technology B.V. ecc0 Echo Corporation edd8 ARK Logic Inc @@ -3678,6 +4691,7 @@ edd8 ARK Logic Inc a099 2000PV [Stingray] a0a1 2000MT a0a9 2000MI +fa57 Fast Search & Transfer ASA feda Epigram Inc fffe VMWare Inc 0710 Virtual SVGA @@ -3687,9 +4701,9 @@ ffff Illegal Vendor ID # List of known device classes, subclasses and programming interfaces # Syntax: -# C class class_name -# subclass subclass_name <-- single tab -# prog-if prog-if_name <-- two tabs +# C class class_name +# subclass subclass_name <-- single tab +# prog-if prog-if_name <-- two tabs C 00 Unclassified device 00 Non-VGA unclassified device @@ -3752,7 +4766,7 @@ C 07 Communication controller 01 BiDir 02 ECP 03 IEEE1284 - FE IEEE1284 Target + fe IEEE1284 Target 02 Multiport serial controller 03 Modem 00 Generic @@ -3790,10 +4804,10 @@ C 09 Input device controller 00 Generic 10 Extended 80 Input device controller -C 0A Docking station +C 0a Docking station 00 Generic Docking Station 80 Docking Station -C 0B Processor +C 0b Processor 00 386 01 486 02 Pentium @@ -3801,7 +4815,7 @@ C 0B Processor 20 Power PC 30 MIPS 40 Co-processor -C 0C Serial bus controller +C 0c Serial bus controller 00 FireWire (IEEE 1394) 00 Generic 10 OHCI @@ -3811,17 +4825,17 @@ C 0C Serial bus controller 00 UHCI 10 OHCI 80 Unspecified - FE USB Device + Fe USB Device 04 Fiber Channel 05 SMBus -C 0D Wireless controller +C 0d Wireless controller 00 IRDA controller 01 Consumer IR controller 10 RF controller 80 Wireless controller -C 0E Intelligent controller +C 0e Intelligent controller 00 I2O -C 0F Satellite communications controller +C 0f Satellite communications controller 00 Satellite TV controller 01 Satellite audio communication controller 03 Satellite voice communication controller diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index cdf480d706b2..fbd167eb8b45 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -3542,7 +3542,7 @@ state_machine: esp->dma_irq_exit(esp); } -#ifndef __SMP__ +#ifndef CONFIG_SMP void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) { struct NCR_ESP *esp; diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index c9e6e70fa79b..e40d64ccb4ce 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -105,7 +105,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; */ #define ASSERT_LOCK(_LOCK, _COUNT) -#if defined(__SMP__) && defined(CONFIG_USER_DEBUG) +#if defined(CONFIG_SMP) && defined(CONFIG_USER_DEBUG) #undef ASSERT_LOCK #define ASSERT_LOCK(_LOCK,_COUNT) \ { if( (_LOCK)->lock != _COUNT ) \ diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 9bc1c575bfeb..4b6b5d510af8 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -212,7 +212,7 @@ # if USE_SPINLOCKS == 3 /* both */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT @@ -241,7 +241,7 @@ # if USE_SPINLOCKS == 2 /* adapter specific locks */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h index acc6526fdfec..1b6e2ff08d47 100644 --- a/drivers/scsi/tmscsim.h +++ b/drivers/scsi/tmscsim.h @@ -8,6 +8,8 @@ #ifndef _TMSCSIM_H #define _TMSCSIM_H +#include + #define IRQ_NONE 255 #define MAX_ADAPTER_NUM 4 @@ -210,7 +212,7 @@ PSRB pTmpSRB; UCHAR msgin123[4]; UCHAR DCBmap[MAX_SCSI_ID]; -#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) spinlock_t lock; #endif UCHAR sel_timeout; diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index d0072dcb1d43..1c6073d2a64b 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -17,6 +17,7 @@ if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then bool ' Separate rear out jack' CONFIG_SOUND_CMPCI_REAR fi fi +dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $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 diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index ea91e2fa9ed3..5d9f2320189e 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -10,8 +10,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := $(SUB_DIRS) - +ALL_SUB_DIRS := $(SUB_DIRS) emu10k1 # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. @@ -81,6 +80,15 @@ obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o +ifeq ($(CONFIG_SOUND_EMU10K1),y) + SUB_DIRS += emu10k1 + obj-y += emu10k1/emu10k1.o +else + ifeq ($(CONFIG_SOUND_EMU10K1),m) + MOD_SUB_DIRS += emu10k1 + endif +endif + ifeq ($(CONFIG_DMASOUND),y) SUB_DIRS += dmasound MOD_SUB_DIRS += dmasound diff --git a/drivers/sound/emu10k1/8010.h b/drivers/sound/emu10k1/8010.h new file mode 100644 index 000000000000..8f4526013502 --- /dev/null +++ b/drivers/sound/emu10k1/8010.h @@ -0,0 +1,662 @@ +/* + ********************************************************************** + * 8010.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS + * line endings + * December 8, 1999 Jon Taylor Added lots of new register info + * + ********************************************************************** + * + * 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. + * + * + ********************************************************************** + */ + + +#ifndef _8010_H +#define _8010_H + +/* ------------------- DEFINES -------------------- */ + +#define EMUPAGESIZE 4096 /* don't change */ +#define RESERVED 0 +#define NUM_G 64 /* use all channels */ +#define NUM_FXSENDS 4 /* don't change */ +#define MAXPAGES (32768 * NUM_G / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */ + +#define TMEMSIZE 256*1024 +#define TMEMSIZEREG 4 + +#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) + +/************************************************************************************************/ +/* PCI function 0 registers, address = + PCIBASE0 */ +/************************************************************************************************/ + +#define PTR 0x00 /* Indexed register set pointer register */ + /* NOTE: The CHANNELNUM and ADDRESS words can */ + /* be modified independently of each other. */ +#define PTR_CHANNELNUM_MASK 0x0000003f /* For each per-channel register, indicates the */ + /* channel number of the register to be */ + /* accessed. For non per-channel registers the */ + /* value should be set to zero. */ +#define PTR_ADDRESS_MASK 0x07ff0000 /* Register index */ + +#define DATA 0x04 /* Indexed register set data register */ + +#define IPR 0x08 /* Global interrupt pending register */ + /* Clear pending interrupts by writing a 1 to */ + /* the relevant bits and zero to the other bits */ +#define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */ +#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ +#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ +#define IPR_PCIERROR 0x00200000 /* PCI bus error */ +#define IPR_VOLINCR 0x00100000 /* Volume increment button pressed */ +#define IPR_VOLDECR 0x00080000 /* Volume decrement button pressed */ +#define IPR_MUTE 0x00040000 /* Mute button pressed */ +#define IPR_MICBUFFULL 0x00020000 /* Microphone buffer full */ +#define IPR_MICBUFHALFFULL 0x00010000 /* Microphone buffer half full */ +#define IPR_ADCBUFFULL 0x00008000 /* ADC buffer full */ +#define IPR_ADCBUFHALFFULL 0x00004000 /* ADC buffer half full */ +#define IPR_EFXBUFFULL 0x00002000 /* Effects buffer full */ +#define IPR_EFXBUFHALFFULL 0x00001000 /* Effects buffer half full */ +#define IPR_GPSPDIFSTATUSCHANGE 0x00000800 /* GPSPDIF channel status change */ +#define IPR_CDROMSTATUSCHANGE 0x00000400 /* CD-ROM channel status change */ +#define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */ +#define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */ +#define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */ +#define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */ +#define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ + /* Highest set channel in CLIPL or CLIPH. When */ + /* IP is written with CL set, the bit in CLIPL */ + /* or CLIPH corresponding to the CIN value */ + /* written will be cleared. */ + +#define INTE 0x0c /* Interrupt enable register */ +#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ +#define INTE_VIRTUALSB_220 0x00000000 /* Capture at I/O base address 0x220-0x22f */ +#define INTE_VIRTUALSB_240 0x40000000 /* Capture at I/O base address 0x240 */ +#define INTE_VIRTUALSB_260 0x80000000 /* Capture at I/O base address 0x260 */ +#define INTE_VIRTUALSB_280 0xc0000000 /* Capture at I/O base address 0x280 */ +#define INTE_VIRTUALMPU_MASK 0x30000000 /* Virtual MPU I/O port capture */ +#define INTE_VIRTUALMPU_300 0x00000000 /* Capture at I/O base address 0x300-0x301 */ +#define INTE_VIRTUALMPU_310 0x10000000 /* Capture at I/O base address 0x310 */ +#define INTE_VIRTUALMPU_320 0x20000000 /* Capture at I/O base address 0x320 */ +#define INTE_VIRTUALMPU_330 0x30000000 /* Capture at I/O base address 0x330 */ +#define INTE_MASTERDMAENABLE 0x08000000 /* Master DMA emulation at 0x000-0x00f */ +#define INTE_SLAVEDMAENABLE 0x04000000 /* Slave DMA emulation at 0x0c0-0x0df */ +#define INTE_MASTERPICENABLE 0x02000000 /* Master PIC emulation at 0x020-0x021 */ +#define INTE_SLAVEPICENABLE 0x01000000 /* Slave PIC emulation at 0x0a0-0x0a1 */ +#define INTE_VSBENABLE 0x00800000 /* Enable virtual Soundblaster */ +#define INTE_ADLIBENABLE 0x00400000 /* Enable AdLib emulation at 0x388-0x38b */ +#define INTE_MPUENABLE 0x00200000 /* Enable virtual MPU */ +#define INTE_FORCEINT 0x00100000 /* Continuously assert INTAN */ + +#define INTE_MRHANDENABLE 0x00080000 /* Enable the "Mr. Hand" logic */ + /* NOTE: There is no reason to use this under */ + /* Linux, and it will cause odd hardware */ + /* behavior and possibly random segfaults and */ + /* lockups if enabled. */ + +#define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */ + /* NOTE: This bit must always be enabled */ +#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */ +#define INTE_PCIERRORENABLE 0x00000800 /* Enable PCI bus error interrupts */ +#define INTE_VOLINCRENABLE 0x00000400 /* Enable volume increment button interrupts */ +#define INTE_VOLDECRENABLE 0x00000200 /* Enable volume decrement button interrupts */ +#define INTE_MUTEENABLE 0x00000100 /* Enable mute button interrupts */ +#define INTE_MICBUFENABLE 0x00000080 /* Enable microphone buffer interrupts */ +#define INTE_ADCBUFENABLE 0x00000040 /* Enable ADC buffer interrupts */ +#define INTE_EFXBUFENABLE 0x00000020 /* Enable Effects buffer interrupts */ +#define INTE_GPSPDIFENABLE 0x00000010 /* Enable GPSPDIF status interrupts */ +#define INTE_CDSPDIFENABLE 0x00000008 /* Enable CDSPDIF status interrupts */ +#define INTE_INTERVALTIMERENB 0x00000004 /* Enable interval timer interrupts */ +#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */ +#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */ + +#define WC 0x10 /* Wall Clock register */ +#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ +#define WC_SAMPLECOUNTER 0x14060010 +#define WC_CURRENTCHANNEL 0x0000003F /* Channel [0..63] currently being serviced */ + /* NOTE: Each channel takes 1/64th of a sample */ + /* period to be serviced. */ + +#define HCFG 0x14 /* Hardware config register */ + /* NOTE: There is no reason to use the legacy */ + /* SoundBlaster emulation stuff described below */ + /* under Linux, and all kinds of weird hardware */ + /* behavior can result if you try. Don't. */ +#define HCFG_LEGACYFUNC_MASK 0xe0000000 /* Legacy function number */ +#define HCFG_LEGACYFUNC_MPU 0x00000000 /* Legacy MPU */ +#define HCFG_LEGACYFUNC_SB 0x40000000 /* Legacy SB */ +#define HCFG_LEGACYFUNC_AD 0x60000000 /* Legacy AD */ +#define HCFG_LEGACYFUNC_MPIC 0x80000000 /* Legacy MPIC */ +#define HCFG_LEGACYFUNC_MDMA 0xa0000000 /* Legacy MDMA */ +#define HCFG_LEGACYFUNC_SPCI 0xc0000000 /* Legacy SPCI */ +#define HCFG_LEGACYFUNC_SDMA 0xe0000000 /* Legacy SDMA */ +#define HCFG_IOCAPTUREADDR 0x1f000000 /* The 4 LSBs of the captured I/O address. */ +#define HCFG_LEGACYWRITE 0x00800000 /* 1 = write, 0 = read */ +#define HCFG_LEGACYWORD 0x00400000 /* 1 = word, 0 = byte */ +#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ + /* NOTE: The rest of the bits in this register */ + /* _are_ relevant under Linux. */ +#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */ +#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ +#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ +#define HCFG_GPINPUT0 0x00004000 /* External pin112 */ +#define HCFG_GPINPUT1 0x00002000 /* External pin110 */ +#define HCFG_GPOUTPUT_MASK 0x00001c00 /* External pins which may be controlled */ +#define HCFG_JOYENABLE 0x00000200 /* Internal joystick enable */ +#define HCFG_PHASETRACKENABLE 0x00000100 /* Phase tracking enable */ + /* 1 = Force all 3 async digital inputs to use */ + /* the same async sample rate tracker (ZVIDEO) */ +#define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */ +#define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */ +#define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */ +#define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */ + /* will automatically mute their output when */ + /* they are not rate-locked to the external */ + /* async audio source */ +#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ + /* NOTE: This should generally never be used. */ +#define HCFG_LOCKTANKCACHE 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ + /* NOTE: This should generally never be used. */ +#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ + /* NOTE: This is a 'cheap' way to implement a */ + /* master mute function on the mute button, and */ + /* in general should not be used unless a more */ + /* sophisticated master mute function has not */ + /* been written. */ +#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */ + /* Should be set to 1 when the EMU10K1 is */ + /* completely initialized. */ + +#define MUDATA 0x18 /* MPU401 data register (8 bits) */ + +#define MUCMD 0x19 /* MPU401 command register (8 bits) */ +#define MUCMD_RESET 0xff /* RESET command */ +#define MUCMD_ENTERUARTMODE 0x3f /* Enter_UART_mode command */ + /* NOTE: All other commands are ignored */ + +#define MUSTAT MUCMD /* MPU401 status register (8 bits) */ +#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */ +#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */ + +#define TIMER 0x1a /* Timer terminal count register */ + /* NOTE: After the rate is changed, a maximum */ + /* of 1024 sample periods should be allowed */ + /* before the new rate is guaranteed accurate. */ +#define TIMER_RATE_MASK 0x000003ff /* Timer interrupt rate in sample periods */ + /* 0 == 1024 periods, [1..4] are not useful */ +#define TIMER_RATE 0x0a00001a + +#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ + +#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ +#define AC97ADDRESS_READY 0x80 /* Read-only bit, reflects CODEC READY signal */ +#define AC97ADDRESS_ADDRESS 0x7f /* Address of indexed AC97 register */ + +/************************************************************************************************/ +/* PCI function 1 registers, address = + PCIBASE1 */ +/************************************************************************************************/ + +#define JOYSTICK1 0x00 /* Analog joystick port register */ +#define JOYSTICK2 0x01 /* Analog joystick port register */ +#define JOYSTICK3 0x02 /* Analog joystick port register */ +#define JOYSTICK4 0x03 /* Analog joystick port register */ +#define JOYSTICK5 0x04 /* Analog joystick port register */ +#define JOYSTICK6 0x05 /* Analog joystick port register */ +#define JOYSTICK7 0x06 /* Analog joystick port register */ +#define JOYSTICK8 0x07 /* Analog joystick port register */ + +/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write. */ +/* When reading, use these bitfields: */ +#define JOYSTICK_BUTTONS 0x0f /* Joystick button data */ +#define JOYSTICK_COMPARATOR 0xf0 /* Joystick comparator data */ + + +/********************************************************************************************************/ +/* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers */ +/********************************************************************************************************/ + +#define AC97_RESET 0x00 +#define AC97_MASTERVOLUME 0x02 /* Master volume */ +#define AC97_HEADPHONEVOLUME 0x04 /* Headphone volume */ +#define AC97_MASTERVOLUMEMONO 0x06 /* Mast volume mono */ +#define AC97_MASTERTONE 0x08 +#define AC97_PCBEEPVOLUME 0x0a /* PC speaker system beep volume */ +#define AC97_PHONEVOLUME 0x0c +#define AC97_MICVOLUME 0x0e +#define AC97_LINEINVOLUME 0x10 +#define AC97_CDVOLUME 0x12 +#define AC97_VIDEOVOLUME 0x14 +#define AC97_AUXVOLUME 0x16 +#define AC97_PCMOUTVOLUME 0x18 +#define AC97_RECORDSELECT 0x1a +#define AC97_RECORDGAIN 0x1c +#define AC97_RECORDGAINMIC 0x1e +#define AC97_GENERALPUPOSE 0x20 +#define AC97_3DCONTROL 0x22 +#define AC97_MODEMRATE 0x24 +#define AC97_POWERDOWN 0x26 +#define AC97_VENDORID1 0x7c +#define AC97_VENDORID2 0x7e +#define AC97_ZVIDEOVOLUME 0xec +#define AC97_AC3VOLUME 0xed + +/********************************************************************************************************/ +/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */ +/********************************************************************************************************/ + +#define CPF 0x00 /* Current pitch and fraction register */ +#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */ +#define CPF_CURRENTPITCH 0x10100000 +#define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */ +#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */ +#define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */ + +#define PTRX 0x01 /* Pitch target and send A/B amounts register */ +#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */ +#define PTRX_PITCHTARGET 0x10100001 +#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */ +#define PTRX_FXSENDAMOUNT_A 0x08080001 +#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */ +#define PTRX_FXSENDAMOUNT_B 0x08000001 + +#define CVCF 0x02 /* Current volume and filter cutoff register */ +#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */ +#define CVCF_CURRENTVOL 0x10100002 +#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */ +#define CVCF_CURRENTFILTER 0x10000002 + +#define VTFT 0x03 /* Volume target and filter cutoff target register */ +#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */ +#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */ + +#define Z1 0x05 /* Filter delay memory 1 register */ + +#define Z2 0x04 /* Filter delay memory 2 register */ + +#define PSST 0x06 /* Send C amount and loop start address register */ +#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */ + +#define PSST_FXSENDAMOUNT_C 0x08180006 + +#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */ +#define PSST_LOOPSTARTADDR 0x18000006 + +#define DSL 0x07 /* Send D amount and loop start address register */ +#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */ + +#define DSL_FXSENDAMOUNT_D 0x08180007 + +#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */ +#define DSL_LOOPENDADDR 0x18000007 + +#define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */ +#define CCCA_RESONANCE 0xf0000000 /* Lowpass filter resonance (Q) height */ +#define CCCA_INTERPROMMASK 0x0e000000 /* Selects passband of interpolation ROM */ + /* 1 == full band, 7 == lowpass */ + /* ROM 0 is used when pitch shifting downward or less */ + /* then 3 semitones upward. Increasingly higher ROM */ + /* numbers are used, typically in steps of 3 semitones, */ + /* as upward pitch shifting is performed. */ +#define CCCA_INTERPROM_0 0x00000000 /* Select interpolation ROM 0 */ +#define CCCA_INTERPROM_1 0x02000000 /* Select interpolation ROM 1 */ +#define CCCA_INTERPROM_2 0x04000000 /* Select interpolation ROM 2 */ +#define CCCA_INTERPROM_3 0x06000000 /* Select interpolation ROM 3 */ +#define CCCA_INTERPROM_4 0x08000000 /* Select interpolation ROM 4 */ +#define CCCA_INTERPROM_5 0x0a000000 /* Select interpolation ROM 5 */ +#define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */ +#define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */ +#define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */ +#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ +#define CCCA_CURRADDR 0x18000008 + +#define CCR 0x09 /* Cache control register */ +#define CCR_CACHEINVALIDSIZE 0xfe000000 /* Number of invalid samples cache for this channel */ +#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ +#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ +#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ +#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ +#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ + /* NOTE: This is valid only if CACHELOOPFLAG is set */ +#define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */ +#define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ + +#define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */ + /* NOTE: This register is normally not used */ +#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */ + +#define FXRT 0x0b /* Effects send routing register */ + /* NOTE: It is illegal to assign the same routing to */ + /* two effects sends. */ +#define FXRT_CHANNELA 0x000f0000 /* Effects send bus number for channel's effects send A */ +#define FXRT_CHANNELB 0x00f00000 /* Effects send bus number for channel's effects send B */ +#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ +#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ + +#define MAPA 0x0c /* Cache map A */ + +#define MAPB 0x0d /* Cache map B */ + +#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ + +#define ENVVOL 0x10 /* Volume envelope register */ +#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ATKHLDV 0x11 /* Volume envelope hold and attack register */ +#define ATKHLDV_PHASE0 0x00008000 /* 0 = Begin attack phase */ +#define ATKHLDV_HOLDTIME_MASK 0x00007f00 /* Envelope hold time (127-n == n*88.2msec) */ +#define ATKHLDV_ATTACKTIME_MASK 0x0000007f /* Envelope attack time, log encoded */ + /* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */ + +#define DCYSUSV 0x12 /* Volume envelope sustain and decay register */ +#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ +#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */ + /* this channel and from writing to pitch, filter and */ + /* volume targets. */ +#define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */ + /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ + +#define LFOVAL1 0x13 /* Modulation LFO value */ +#define LFOVAL_MASK 0x0000ffff /* Current value of modulation LFO state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ENVVAL 0x14 /* Modulation envelope register */ +#define ENVVAL_MASK 0x0000ffff /* Current value of modulation envelope state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ATKHLDM 0x15 /* Modulation envelope hold and attack register */ +#define ATKHLDM_PHASE0 0x00008000 /* 0 = Begin attack phase */ +#define ATKHLDM_HOLDTIME 0x00007f00 /* Envelope hold time (127-n == n*42msec) */ +#define ATKHLDM_ATTACKTIME 0x0000007f /* Envelope attack time, log encoded */ + /* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */ + +#define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */ +#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ +#define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */ + /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ + +#define LFOVAL2 0x17 /* Vibrato LFO register */ +#define LFOVAL2_MASK 0x0000ffff /* Current value of vibrato LFO state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define IP 0x18 /* Initial pitch register */ +#define IP_MASK 0x0000ffff /* Exponential initial pitch shift */ + /* 4 bits of octave, 12 bits of fractional octave */ +#define IP_UNITY 0x0000e000 /* Unity pitch shift */ + +#define IFATN 0x19 /* Initial filter cutoff and attenuation register */ +#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */ + /* 6 most significant bits are semitones */ + /* 2 least significant bits are fractions */ +#define IFATN_FILTERCUTOFF 0x08080019 +#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */ +#define IFATN_ATTENUATION 0x08000019 + + +#define PEFE 0x1a /* Pitch envelope and filter envelope amount register */ +#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */ + /* Signed 2's complement, +/- one octave peak extremes */ +#define PEFE_PITCHAMOUNT 0x0808001a +#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */ + /* Signed 2's complement, +/- six octaves peak extremes */ +#define PEFE_FILTERAMOUNT 0x0800001a +#define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */ +#define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */ + /* Signed 2's complement, +/- one octave extremes */ +#define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */ + /* Signed 2's complement, +/- three octave extremes */ + + +#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ +#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ + /* Signed 2's complement, with +/- 12dB extremes */ + +#define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */ +#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ + /* Signed 2's complement, +/- one octave extremes */ +#define FM2FRQ2_FREQUENCY 0x000000ff /* Vibrato LFO frequency */ + /* 0.039Hz steps, maximum of 9.85 Hz. */ + +#define TEMPENV 0x1e /* Tempory envelope register */ +#define TEMPENV_MASK 0x0000ffff /* 16-bit value */ + /* NOTE: All channels contain internal variables; do */ + /* not write to these locations. */ + +#define CD0 0x20 /* Cache data 0 register */ +#define CD1 0x21 /* Cache data 1 register */ +#define CD2 0x22 /* Cache data 2 register */ +#define CD3 0x23 /* Cache data 3 register */ +#define CD4 0x24 /* Cache data 4 register */ +#define CD5 0x25 /* Cache data 5 register */ +#define CD6 0x26 /* Cache data 6 register */ +#define CD7 0x27 /* Cache data 7 register */ +#define CD8 0x28 /* Cache data 8 register */ +#define CD9 0x29 /* Cache data 9 register */ +#define CDA 0x2a /* Cache data A register */ +#define CDB 0x2b /* Cache data B register */ +#define CDC 0x2c /* Cache data C register */ +#define CDD 0x2d /* Cache data D register */ +#define CDE 0x2e /* Cache data E register */ +#define CDF 0x2f /* Cache data F register */ + +#define PTB 0x40 /* Page table base register */ +#define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */ + +#define TCB 0x41 /* Tank cache base register */ +#define TCB_MASK 0xfffff000 /* Physical address of the bottom of host based TRAM */ + +#define ADCCR 0x42 /* ADC sample rate/stereo control register */ +#define ADCCR_RCHANENABLE 0x00000010 /* Enables right channel for writing to the host */ +#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */ + /* NOTE: To guarantee phase coherency, both channels */ + /* must be disabled prior to enabling both channels. */ +#define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */ +#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */ +#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */ +#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */ +#define ADCCR_SAMPLERATE_24 0x00000003 /* 24kHz sample rate */ +#define ADCCR_SAMPLERATE_22 0x00000004 /* 22.05kHz sample rate */ +#define ADCCR_SAMPLERATE_16 0x00000005 /* 16kHz sample rate */ +#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */ +#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */ + +#define FXWC 0x43 /* FX output write channels register */ + /* When set, each bit enables the writing of the */ + /* corresponding FX output channel into host memory */ + +#define TCBS 0x44 /* Tank cache buffer size register */ +#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ +#define TCBS_BUFFSIZE_16K 0x00000000 +#define TCBS_BUFFSIZE_32K 0x00000001 +#define TCBS_BUFFSIZE_64K 0x00000002 +#define TCBS_BUFFSIZE_128K 0x00000003 +#define TCBS_BUFFSIZE_256K 0x00000004 +#define TCBS_BUFFSIZE_512K 0x00000005 +#define TCBS_BUFFSIZE_1024K 0x00000006 +#define TCBS_BUFFSIZE_2048K 0x00000007 + +#define MICBA 0x45 /* AC97 microphone buffer address register */ +#define MICBA_MASK 0xfffff000 /* 20 bit base address */ + +#define ADCBA 0x46 /* ADC buffer address register */ +#define ADCBA_MASK 0xfffff000 /* 20 bit base address */ + +#define FXBA 0x47 /* FX Buffer Address */ +#define FXBA_MASK 0xfffff000 /* 20 bit base address */ + +#define MICBS 0x49 /* Microphone buffer size register */ + +#define ADCBS 0x4a /* ADC buffer size register */ + +#define FXBS 0x4b /* FX buffer size register */ + +/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */ +#define ADCBS_BUFSIZE_NONE 0x00000000 +#define ADCBS_BUFSIZE_384 0x00000001 +#define ADCBS_BUFSIZE_448 0x00000002 +#define ADCBS_BUFSIZE_512 0x00000003 +#define ADCBS_BUFSIZE_640 0x00000004 +#define ADCBS_BUFSIZE_768 0x00000005 +#define ADCBS_BUFSIZE_896 0x00000006 +#define ADCBS_BUFSIZE_1024 0x00000007 +#define ADCBS_BUFSIZE_1280 0x00000008 +#define ADCBS_BUFSIZE_1536 0x00000009 +#define ADCBS_BUFSIZE_1792 0x0000000a +#define ADCBS_BUFSIZE_2048 0x0000000b +#define ADCBS_BUFSIZE_2560 0x0000000c +#define ADCBS_BUFSIZE_3072 0x0000000d +#define ADCBS_BUFSIZE_3584 0x0000000e +#define ADCBS_BUFSIZE_4096 0x0000000f +#define ADCBS_BUFSIZE_5120 0x00000010 +#define ADCBS_BUFSIZE_6144 0x00000011 +#define ADCBS_BUFSIZE_7168 0x00000012 +#define ADCBS_BUFSIZE_8192 0x00000013 +#define ADCBS_BUFSIZE_10240 0x00000014 +#define ADCBS_BUFSIZE_12288 0x00000015 +#define ADCBS_BUFSIZE_14366 0x00000016 +#define ADCBS_BUFSIZE_16384 0x00000017 +#define ADCBS_BUFSIZE_20480 0x00000018 +#define ADCBS_BUFSIZE_24576 0x00000019 +#define ADCBS_BUFSIZE_28672 0x0000001a +#define ADCBS_BUFSIZE_32768 0x0000001b +#define ADCBS_BUFSIZE_40960 0x0000001c +#define ADCBS_BUFSIZE_49152 0x0000001d +#define ADCBS_BUFSIZE_57344 0x0000001e +#define ADCBS_BUFSIZE_65536 0x0000001f + + +#define CDCS 0x50 /* CD-ROM digital channel status register */ + +#define GPSCS 0x51 /* General Purpose SPDIF channel status register*/ + +#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ + +#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ + +#define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ + +#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ + +#define SPCS2 0x56 /* SPDIF output Channel Status 2 register */ + +#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */ +#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */ +#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */ +#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */ +#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */ +#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */ +#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */ +#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */ +#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */ +#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */ +#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */ +#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */ +#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */ +#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */ +#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */ +#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */ +#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */ +#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */ +#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */ +#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */ +#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */ +#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ +#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ + +/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ +#define CLIEL 0x58 /* Channel loop interrupt enable low register */ + +#define CLIEH 0x59 /* Channel loop interrupt enable high register */ + +#define CLIPL 0x5a /* Channel loop interrupt pending low register */ + +#define CLIPH 0x5b /* Channel loop interrupt pending high register */ + +#define SOLEL 0x5c /* Stop on loop enable low register */ + +#define SOLEH 0x5d /* Stop on loop enable high register */ + +#define SPBYPASS 0x5e /* SPDIF BYPASS mode register */ +#define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */ + +#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ + +#define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */ + +#define ZVSRCS 0x62 /* ZVideo sample rate converter status */ + /* NOTE: This one has no SPDIFLOCKED field */ + /* Assumes sample lock */ + +/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ +#define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ +#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ +#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ + +#define MICIDX 0x63 /* Microphone recording buffer index register */ +#define MICIDX_MASK 0x0000ffff /* 16-bit value */ +#define MICIDX_IDX 0x10000063 + +#define ADCIDX 0x64 /* ADC recording buffer index register */ +#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ +#define ADCIDX_IDX 0x10000064 + +#define FXIDX 0x65 /* FX recording buffer index register */ +#define FXIDX_MASK 0x0000ffff /* 16-bit value */ +#define FXIDX_IDX 0x10000065 + +/* Each FX general purpose register is 32 bits in length, all bits are used */ +#define FXGPREGBASE 0x100 /* FX general purpose registers base */ + +/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ +/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ +/* locations are for external TRAM. */ +#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */ +#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */ + +/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */ +#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */ +#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ +#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ +#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ +#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ +#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ + +#define MICROCODEBASE 0x400 /* Microcode data base address */ + +/* Each DSP microcode instruction is mapped into 2 doublewords */ +/* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */ +#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */ +#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */ +#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */ +#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ +#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ + +#endif /* _8010_H */ diff --git a/drivers/sound/emu10k1/Makefile b/drivers/sound/emu10k1/Makefile new file mode 100644 index 000000000000..3f4d227f1493 --- /dev/null +++ b/drivers/sound/emu10k1/Makefile @@ -0,0 +1,29 @@ +# Makefile for Creative Labs EMU10K1 +# +# 12 Apr 2000 Rui Sousa + +ifeq ($(CONFIG_SOUND_EMU10K1),y) + O_TARGET := emu10k1.o + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ + osutils.o recmgr.o timer.o voicemgr.o +else + ifeq ($(CONFIG_SOUND_EMU10K1),m) + M_OBJS := emu10k1.o + O_TARGET := emu10k1.o + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ + osutils.o recmgr.o timer.o voicemgr.o + endif +endif + +EXTRA_CFLAGS += -I. + +ifdef DEBUG + EXTRA_CFLAGS += -DEMU10K1_DEBUG +endif + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c new file mode 100644 index 000000000000..a68287984493 --- /dev/null +++ b/drivers/sound/emu10k1/audio.c @@ -0,0 +1,1441 @@ + +/* + ********************************************************************** + * audio.c -- /dev/dsp interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up types/leaks + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardwo.h" +#include "cardwi.h" +#include "recmgr.h" +#include "audio.h" + +static void calculate_ofrag(struct woinst *); +static void calculate_ifrag(struct wiinst *); + +/* Audio file operations */ +static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin) +{ + return -ESPIPE; +} + +static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + ssize_t ret = 0; + unsigned long flags; + + DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count); + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wiinst->mapped) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return -ENXIO; + } + + if (!wiinst->wave_in) { + calculate_ifrag(wiinst); + + while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wave_dev->card->open_wait); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&wiinst->lock, flags); + } + } + + wave_in = wiinst->wave_in; + + spin_unlock_irqrestore(&wiinst->lock, flags); + + while (count > 0) { + u32 bytestocopy, dummy; + + spin_lock_irqsave(&wiinst->lock, flags); + + if ((wave_in->state != CARDWAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_INPUT)) + emu10k1_wavein_start(wave_dev); + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + DPD(4, "bytestocopy --> %x\n", bytestocopy); + + if ((bytestocopy >= wiinst->fragment_size) + || (bytestocopy >= count)) { + bytestocopy = min(bytestocopy, count); + + emu10k1_wavein_xferdata(wiinst, (u8 *) buffer, &bytestocopy); + + count -= bytestocopy; + buffer += bytestocopy; + ret += bytestocopy; + } + + if (count > 0) { + if ((file->f_flags & O_NONBLOCK) + || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) + return (ret ? ret : -EAGAIN); + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wiinst->wait_queue); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return (ret ? ret : -ERESTARTSYS); + + } + } + + DPD(4, "bytes copied -> %x\n", (u32) ret); + + return ret; +} + +static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + ssize_t ret; + unsigned long flags; + + GET_INODE_STRUCT(); + + DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count); + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + + spin_lock_irqsave(&woinst->lock, flags); + + if (woinst->mapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -ENXIO; + } + + if (!woinst->wave_out) { + calculate_ofrag(woinst); + + while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wave_dev->card->open_wait); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&woinst->lock, flags); + } + } + + wave_out = woinst->wave_out; + + spin_unlock_irqrestore(&woinst->lock, flags); + + ret = 0; + while (count > 0) { + u32 bytestocopy, pending, dummy; + + spin_lock_irqsave(&woinst->lock, flags); + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(4, "bytestocopy --> %x\n", bytestocopy); + + if ((bytestocopy >= woinst->fragment_size) + || (bytestocopy >= count)) { + + bytestocopy = min(bytestocopy, count); + + emu10k1_waveout_xferdata(woinst, (u8 *) buffer, &bytestocopy); + + count -= bytestocopy; + buffer += bytestocopy; + ret += bytestocopy; + + spin_lock_irqsave(&woinst->lock, flags); + woinst->total_copied += bytestocopy; + + if ((wave_out->state != CARDWAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) + && (woinst->total_copied >= woinst->fragment_size)) { + + if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + ERROR(); + return -EFAULT; + } + } + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (count > 0) { + if ((file->f_flags & O_NONBLOCK) + || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) + return (ret ? ret : -EAGAIN); + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&woinst->wait_queue); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return (ret ? ret : -ERESTARTSYS); + } + } + + DPD(4, "bytes copied -> %x\n", (u32) ret); + + return ret; +} + +static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + int val = 0; + struct woinst *woinst = NULL; + struct wave_out *wave_out = NULL; + struct wiinst *wiinst = NULL; + struct wave_in *wave_in = NULL; + u32 pending, bytestocopy, dummy; + unsigned long flags; + + DPF(4, "emu10k1_audio_ioctl()\n"); + + if (file->f_mode & FMODE_WRITE) { + woinst = wave_dev->woinst; + spin_lock_irqsave(&woinst->lock, flags); + wave_out = woinst->wave_out; + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + wiinst = wave_dev->wiinst; + spin_lock_irqsave(&wiinst->lock, flags); + wave_in = wiinst->wave_in; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + switch (cmd) { + case OSS_GETVERSION: + DPF(2, "OSS_GETVERSION:\n"); + return put_user(SOUND_VERSION, (int *) arg); + + case SNDCTL_DSP_RESET: + DPF(2, "SNDCTL_DSP_RESET:\n"); + wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out) + emu10k1_waveout_close(wave_dev); + + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) + emu10k1_wavein_close(wave_dev); + + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + break; + + case SNDCTL_DSP_SYNC: + DPF(2, "SNDCTL_DSP_SYNC:\n"); + + if (file->f_mode & FMODE_WRITE) { + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out->state == CARDWAVE_STATE_STARTED) + while ((woinst->total_played < woinst->total_copied) + && !signal_pending(current)) { + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } + + emu10k1_waveout_close(wave_dev); + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) + emu10k1_wavein_close(wave_dev); + + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + break; + + case SNDCTL_DSP_SETDUPLEX: + DPF(2, "SNDCTL_DSP_SETDUPLEX:\n"); + break; + + case SNDCTL_DSP_GETCAPS: + DPF(2, "SNDCTL_DSP_GETCAPS:\n"); + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg); + + case SNDCTL_DSP_SPEED: + DPF(2, "SNDCTL_DSP_SPEED:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, "val is %d\n", val); + + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.samplingrate = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.samplingrate; + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback sampling rate -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.samplingrate = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.samplingrate; + + spin_unlock_irqrestore(&wiinst->lock, flags); + + DPD(2, "set recording sampling rate -> %d\n", val); + } + + return put_user(val, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.samplingrate; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.samplingrate; + + return put_user(val, (int *) arg); + } + break; + + case SNDCTL_DSP_STEREO: + DPF(2, "SNDCTL_DSP_STEREO:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.channels = val ? 2 : 1; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.channels - 1; + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback stereo -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.channels = val ? 2 : 1; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.channels - 1; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording stereo -> %d\n", val); + } + + return put_user(val, (int *) arg); + + break; + + case SNDCTL_DSP_CHANNELS: + DPF(2, "SNDCTL_DSP_CHANNELS:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (val != 0) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.channels = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.channels; + + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback number of channels -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.channels = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.channels; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording number of channels -> %d\n", val); + } + + return put_user(val, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.channels; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.channels; + + return put_user(val, (int *) arg); + } + break; + + case SNDCTL_DSP_GETFMTS: + DPF(2, "SNDCTL_DSP_GETFMTS:\n"); + + if (file->f_mode & FMODE_READ) + val = AFMT_S16_LE; + else if (file->f_mode & FMODE_WRITE) + val = AFMT_S16_LE | AFMT_U8; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */ + DPF(2, "SNDCTL_DSP_SETFMT:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.bitsperchannel = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.bitsperchannel; + + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback sample size -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.bitsperchannel = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.bitsperchannel; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording sample size -> %d\n", val); + } + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.bitsperchannel; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.bitsperchannel; + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + } + break; + + case SOUND_PCM_READ_BITS: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.bitsperchannel; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.bitsperchannel; + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + + case SOUND_PCM_READ_RATE: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.samplingrate; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.samplingrate; + + return put_user(val, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.channels; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.channels; + + return put_user(val, (int *) arg); + + case SOUND_PCM_WRITE_FILTER: + DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n"); + break; + + case SOUND_PCM_READ_FILTER: + DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n"); + break; + + case SNDCTL_DSP_SETSYNCRO: + DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n"); + break; + + case SNDCTL_DSP_GETTRIGGER: + DPF(2, "SNDCTL_DSP_GETTRIGGER:\n"); + + if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) + val |= PCM_ENABLE_OUTPUT; + if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) + val |= PCM_ENABLE_INPUT; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: + DPF(2, "SNDCTL_DSP_SETTRIGGER:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (val & PCM_ENABLE_OUTPUT) { + wave_dev->enablebits |= PCM_ENABLE_OUTPUT; + if (wave_out) + emu10k1_waveout_start(wave_dev); + } else { + wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; + if (wave_out) + emu10k1_waveout_stop(wave_dev); + } + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (val & PCM_ENABLE_INPUT) { + wave_dev->enablebits |= PCM_ENABLE_INPUT; + if (wave_in) + emu10k1_wavein_start(wave_dev); + } else { + wave_dev->enablebits &= ~PCM_ENABLE_INPUT; + if (wave_in) + emu10k1_wavein_stop(wave_dev); + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + break; + + case SNDCTL_DSP_GETOSPACE: + { + audio_buf_info info; + + DPF(4, "SNDCTL_DSP_GETOSPACE:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + spin_unlock_irqrestore(&woinst->lock, flags); + + info.bytes = bytestocopy; + } else { + spin_lock_irqsave(&woinst->lock, flags); + calculate_ofrag(woinst); + spin_unlock_irqrestore(&woinst->lock, flags); + + info.bytes = woinst->numfrags * woinst->fragment_size; + } + + info.fragstotal = woinst->numfrags; + info.fragments = info.bytes / woinst->fragment_size; + info.fragsize = woinst->fragment_size; + + if (copy_to_user((int *) arg, &info, sizeof(info))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info info; + + DPF(4, "SNDCTL_DSP_GETISPACE:\n"); + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + + if (wave_in) { + spin_lock_irqsave(&wiinst->lock, flags); + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + spin_unlock_irqrestore(&wiinst->lock, flags); + + info.bytes = bytestocopy; + } else { + spin_lock_irqsave(&wiinst->lock, flags); + calculate_ifrag(wiinst); + spin_unlock_irqrestore(&wiinst->lock, flags); + + info.bytes = 0; + } + + info.fragstotal = wiinst->numfrags; + info.fragments = info.bytes / wiinst->fragment_size; + info.fragsize = wiinst->fragment_size; + + if (copy_to_user((int *) arg, &info, sizeof(info))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_NONBLOCK: + DPF(2, "SNDCTL_DSP_NONBLOCK:\n"); + + file->f_flags |= O_NONBLOCK; + break; + + case SNDCTL_DSP_GETODELAY: + DPF(4, "SNDCTL_DSP_GETODELAY:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + spin_unlock_irqrestore(&woinst->lock, flags); + + val = pending; + } else + val = 0; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_GETIPTR: + { + count_info cinfo; + + DPF(4, "SNDCTL_DSP_GETIPTR: \n"); + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) { + emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr); + cinfo.bytes = + cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags); + cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks; + wiinst->blocks = cinfo.bytes / wiinst->fragment_size; + } else { + cinfo.ptr = 0; + cinfo.bytes = 0; + cinfo.blocks = 0; + wiinst->blocks = 0; + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETOPTR: + { + count_info cinfo; + + DPF(4, "SNDCTL_DSP_GETOPTR:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out) { + emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr); + cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags); + cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks; + woinst->blocks = cinfo.bytes / woinst->fragment_size; + } else { + cinfo.ptr = 0; + cinfo.bytes = 0; + cinfo.blocks = 0; + woinst->blocks = 0; + } + + spin_unlock_irqrestore(&woinst->lock, flags); + + if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETBLKSIZE: + DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n"); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + calculate_ofrag(woinst); + val = woinst->fragment_size; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + calculate_ifrag(wiinst); + val = wiinst->fragment_size; + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return put_user(val, (int *) arg); + + break; + + case SNDCTL_DSP_POST: + DPF(2, "SNDCTL_DSP_POST: not implemented\n"); + break; + + case SNDCTL_DSP_SUBDIVIDE: + DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n"); + break; + + case SNDCTL_DSP_SETFRAGMENT: + DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + + DPD(2, "val is %x\n", val); + + if (val == 0) + return -EIO; + + if (file->f_mode & FMODE_WRITE) { + if (wave_out) + return -EINVAL; /* too late to change */ + + woinst->ossfragshift = val & 0xffff; + woinst->numfrags = (val >> 16) & 0xffff; + } + + if (file->f_mode & FMODE_READ) { + if (wave_in) + return -EINVAL; /* too late to change */ + + wiinst->ossfragshift = val & 0xffff; + wiinst->numfrags = (val >> 16) & 0xffff; + } + + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer buf; + u32 i; + + DPF(2, "SNDCTL_COPR_LOAD:\n"); + + if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf))) + return -EFAULT; + + if ((buf.command != 1) && (buf.command != 2)) + return -EINVAL; + + if (((buf.offs < 0x100) && (buf.command == 2)) + || (buf.offs < 0x000) + || (buf.offs + buf.len > 0x800) || (buf.len > 1000)) + return -EINVAL; + + if (buf.command == 1) { + for (i = 0; i < buf.len; i++) + + ((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0); + if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf))) + return -EFAULT; + } else { + for (i = 0; i < buf.len; i++) + sblive_writeptr(wave_dev->card, buf.offs + i, 0, ((u32 *) buf.data)[i]); + } + break; + } + + default: /* Default is unrecognized command */ + DPD(2, "default: %x\n", cmd); + return -EINVAL; + } + return 0; +} + +static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + + DPF(2, "emu10k1_audio_mmap()\n"); + + if (vma_get_pgoff(vma) != 0) + return -ENXIO; + + if (vma->vm_flags & VM_WRITE) { + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + u32 size; + unsigned long flags; + int i; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (!wave_out) { + calculate_ofrag(woinst); + + if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + ERROR(); + return -EINVAL; + } + + wave_out = woinst->wave_out; + + /* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */ + for (i = 0; i < wave_out->wavexferbuf->numpages; i++) + set_bit(PG_reserved, &mem_map[MAP_NR(wave_out->pagetable[i])].flags); + } + + size = vma->vm_end - vma->vm_start; + + if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -EINVAL; + } + + for (i = 0; i < wave_out->wavexferbuf->numpages; i++) { + if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -EAGAIN; + } + } + + woinst->mapped = 1; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (vma->vm_flags & VM_READ) { + struct wiinst *wiinst = wave_dev->wiinst; + unsigned long flags; + + spin_lock_irqsave(&wiinst->lock, flags); + wiinst->mapped = 1; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return 0; +} + +static int emu10k1_audio_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct list_head *entry; + struct emu10k1_wavedevice *wave_dev; + + DPF(2, "emu10k1_audio_open()\n"); + + /* Check for correct device to open */ + + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->audio1_num == minor || card->audio2_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + if ((wave_dev = (struct emu10k1_wavedevice *) + kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -EINVAL; + } + + wave_dev->card = card; + wave_dev->wiinst = NULL; + wave_dev->woinst = NULL; + wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */ + + if (file->f_mode & FMODE_WRITE) { + struct woinst *woinst; + + if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + woinst->wave_fmt.samplingrate = 8000; + woinst->wave_fmt.bitsperchannel = 8; + woinst->wave_fmt.channels = 1; + woinst->ossfragshift = 0; + woinst->fragment_size = 0; + woinst->numfrags = 0; + woinst->device = (card->audio2_num == minor); + woinst->wave_out = NULL; + + init_waitqueue_head(&woinst->wait_queue); + + woinst->mapped = 0; + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + woinst->lock = SPIN_LOCK_UNLOCKED; + wave_dev->woinst = woinst; + +#ifdef PRIVATE_PCM_VOLUME + { + int i; + int j = -1; + + /* + * find out if we've already been in this table + * xmms reopens dsp on every move of slider + * this way we keep the same local pcm for such + * process + */ + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) + break; + // here we should select last used memeber + // improve me in case its not sufficient + if (j < 0 && !sblive_pcm_volume[i].opened) + j = i; + } + // current task not found + if (i == MAX_PCM_CHANNELS) { + // add new entry + if (j < 0) + printk("TOO MANY WRITTERS!!!\n"); + i = (j >= 0) ? j : 0; + DPD(2, "new pcm private %p\n", current->files); + sblive_pcm_volume[i].files = current->files; + sblive_pcm_volume[i].mixer = 0x6464; // max + sblive_pcm_volume[i].attn_l = 0; + sblive_pcm_volume[i].attn_r = 0; + sblive_pcm_volume[i].channel_l = NUM_G; + sblive_pcm_volume[i].channel_r = NUM_G; + } + sblive_pcm_volume[i].opened++; + } +#endif + } + + if (file->f_mode & FMODE_READ) { + /* Recording */ + struct wiinst *wiinst; + + if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + switch (card->wavein->recsrc) { + case WAVERECORD_AC97: + wiinst->wave_fmt.samplingrate = 8000; + wiinst->wave_fmt.bitsperchannel = 8; + wiinst->wave_fmt.channels = 1; + break; + case WAVERECORD_MIC: + wiinst->wave_fmt.samplingrate = 8000; + wiinst->wave_fmt.bitsperchannel = 8; + wiinst->wave_fmt.channels = 1; + break; + case WAVERECORD_FX: + wiinst->wave_fmt.samplingrate = 48000; + wiinst->wave_fmt.bitsperchannel = 16; + wiinst->wave_fmt.channels = 2; + break; + default: + break; + } + + wiinst->recsrc = card->wavein->recsrc; + wiinst->ossfragshift = 0; + wiinst->fragment_size = 0; + wiinst->numfrags = 0; + wiinst->wave_in = NULL; + + init_waitqueue_head(&wiinst->wait_queue); + + wiinst->mapped = 0; + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + wiinst->lock = SPIN_LOCK_UNLOCKED; + wave_dev->wiinst = wiinst; + } + + file->private_data = (void *) wave_dev; + + return 0; /* Success? */ +} + +static int emu10k1_audio_release(struct inode *inode, struct file *file) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct emu10k1_card *card = wave_dev->card; + unsigned long flags; + + DPF(2, "emu10k1_audio_release()\n"); + + if (file->f_mode & FMODE_WRITE) { + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (wave_out) { + if ((wave_out->state == CARDWAVE_STATE_STARTED) + && !(file->f_flags & O_NONBLOCK)) { + while (!signal_pending(current) + && (woinst->total_played < woinst->total_copied)) { + DPF(4, "Buffer hasn't been totally played, sleep....\n"); + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } + } + + if (woinst->mapped && wave_out->pagetable) { + int i; + + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) + set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags); + } + + woinst->mapped = 0; + emu10k1_waveout_close(wave_dev); + } +#ifdef PRIVATE_PCM_VOLUME + { + int i; + + /* mark as closed + * NOTE: structure remains unchanged for next reopen */ + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].opened--; + break; + } + } + } +#endif + spin_unlock_irqrestore(&woinst->lock, flags); + kfree(wave_dev->woinst); + } + + if (file->f_mode & FMODE_READ) { + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + + spin_lock_irqsave(&wiinst->lock, flags); + + wave_in = wiinst->wave_in; + + if (wave_in) { + wiinst->mapped = 0; + emu10k1_wavein_close(wave_dev); + } + spin_unlock_irqrestore(&wiinst->lock, flags); + kfree(wave_dev->wiinst); + } + + kfree(wave_dev); + + wake_up_interruptible(&card->open_wait); + MOD_DEC_USE_COUNT; + + return 0; +} + +static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct woinst *woinst = wave_dev->woinst; + struct wiinst *wiinst = wave_dev->wiinst; + unsigned int mask = 0; + u32 bytestocopy, pending, dummy; + unsigned long flags; + + DPF(4, "emu10k1_audio_poll()\n"); + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &woinst->wait_queue, wait); + + if (file->f_mode & FMODE_READ) + poll_wait(file, &wiinst->wait_queue, wait); + + if (file->f_mode & FMODE_WRITE) { + struct wave_out *wave_out; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (wave_out) { + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + + if (bytestocopy >= woinst->fragment_size) + mask |= POLLOUT | POLLWRNORM; + } else + mask |= POLLOUT | POLLWRNORM; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + struct wave_in *wave_in; + + spin_lock_irqsave(&wiinst->lock, flags); + + wave_in = wiinst->wave_in; + + if (!wave_in) { + calculate_ifrag(wiinst); + if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return (mask |= POLLERR); + } + + wave_in = wiinst->wave_in; + } + + if (wave_in->state != CARDWAVE_STATE_STARTED) { + wave_dev->enablebits |= PCM_ENABLE_INPUT; + emu10k1_wavein_start(wave_dev); + } + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + + if (bytestocopy >= wiinst->fragment_size) + mask |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return mask; +} + +static void calculate_ofrag(struct woinst *woinst) +{ + u32 fragsize, bytespersec; + + if (woinst->fragment_size) + return; + + bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate; + + if (!woinst->ossfragshift) { + fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; + + while (fragsize) { + fragsize >>= 1; + woinst->ossfragshift++; + } + } + + if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT) + woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT; + + woinst->fragment_size = 1 << woinst->ossfragshift; + + if (!woinst->numfrags) { + u32 numfrags; + + numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1; + + woinst->numfrags = 1; + + while (numfrags) { + numfrags >>= 1; + woinst->numfrags <<= 1; + } + } + + if (woinst->numfrags < MINFRAGS) + woinst->numfrags = MINFRAGS; + + if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) { + woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size; + + if (woinst->numfrags < MINFRAGS) { + woinst->numfrags = MINFRAGS; + woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; + } + + } else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE) + woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size; + + DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size); + DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags); +} + +static void calculate_ifrag(struct wiinst *wiinst) +{ + u32 fragsize, bytespersec; + + if (wiinst->fragment_size) + return; + + bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate; + + if (!wiinst->ossfragshift) { + fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; + + while (fragsize) { + fragsize >>= 1; + wiinst->ossfragshift++; + } + } + + if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT) + wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT; + + wiinst->fragment_size = 1 << wiinst->ossfragshift; + + if (!wiinst->numfrags) + wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1; + + if (wiinst->numfrags < MINFRAGS) + wiinst->numfrags = MINFRAGS; + + if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) { + wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size; + + if (wiinst->numfrags < MINFRAGS) { + wiinst->numfrags = MINFRAGS; + wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; + } + } else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE) + wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size; + + DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size); + DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags); +} + +void emu10k1_wavein_bh(unsigned long refdata) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in = wiinst->wave_in; + u32 bytestocopy, curpos; + unsigned long flags; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in->state == CARDWAVE_STATE_STOPPED) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return; + } + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos); + + wiinst->total_recorded += curpos - wiinst->curpos; + + if (curpos < wiinst->curpos) + wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags; + + wiinst->curpos = curpos; + + if (wiinst->mapped) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return; + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (bytestocopy >= wiinst->fragment_size) + wake_up_interruptible(&wiinst->wait_queue); + else + DPD(4, "Not enough transfer size, %d\n", bytestocopy); + + return; +} + +void emu10k1_waveout_bh(unsigned long refdata) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out = woinst->wave_out; + u32 bytestocopy, pending, curpos; + unsigned long flags; + + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out->state == CARDWAVE_STATE_STOPPED) { + spin_unlock_irqrestore(&woinst->lock, flags); + return; + } + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos); + + woinst->total_played += curpos - woinst->curpos; + + if (curpos < woinst->curpos) + woinst->total_played += woinst->fragment_size * woinst->numfrags; + + woinst->curpos = curpos; + + if (woinst->mapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return; + } + + if (wave_out->fill_silence) { + spin_unlock_irqrestore(&woinst->lock, flags); + emu10k1_waveout_fillsilence(woinst); + } else + spin_unlock_irqrestore(&woinst->lock, flags); + + if (bytestocopy >= woinst->fragment_size) + wake_up_interruptible(&woinst->wait_queue); + else + DPD(4, "Not enough transfer size -> %x\n", bytestocopy); + + return; +} + +struct file_operations emu10k1_audio_fops = { + llseek:emu10k1_audio_llseek, + read:emu10k1_audio_read, + write:emu10k1_audio_write, + poll:emu10k1_audio_poll, + ioctl:emu10k1_audio_ioctl, + mmap:emu10k1_audio_mmap, + open:emu10k1_audio_open, + release:emu10k1_audio_release, +}; diff --git a/drivers/sound/emu10k1/audio.h b/drivers/sound/emu10k1/audio.h new file mode 100644 index 000000000000..357479acb35d --- /dev/null +++ b/drivers/sound/emu10k1/audio.h @@ -0,0 +1,46 @@ +/* + ********************************************************************** + * audio.c -- /dev/dsp interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up types/leaks + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _AUDIO_H +#define _AUDIO_H + +#define __NO_VERSION__ +#include +#include +#include + +#define MINFRAGS 2 /* _don't_ got bellow 2 */ + +void emu10k1_waveout_bh(unsigned long); +void emu10k1_wavein_bh(unsigned long); + +#endif /* _AUDIO_H */ diff --git a/drivers/sound/emu10k1/cardmi.c b/drivers/sound/emu10k1/cardmi.c new file mode 100644 index 000000000000..f741b9d6d893 --- /dev/null +++ b/drivers/sound/emu10k1/cardmi.c @@ -0,0 +1,813 @@ + +/* + ********************************************************************** + * sblive_mi.c - MIDI UART input HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox clean up + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmi.h" + +static struct { + int (*Fn) (struct emu10k1_mpuin *, u8); +} midistatefn[] = { + + { + sblive_miStateParse}, { + sblive_miState3Byte}, /* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */ + { + sblive_miState3ByteKey}, /* Byte 1 */ + { + sblive_miState3ByteVel}, /* Byte 2 */ + { + sblive_miState2Byte}, /* 0xCn, 0xDn */ + { + sblive_miState2ByteKey}, /* Byte 1 */ + { + sblive_miStateSysCommon2}, /* 0xF1 , 0xF3 */ + { + sblive_miStateSysCommon2Key}, /* 0xF1 , 0xF3, Byte 1 */ + { + sblive_miStateSysCommon3}, /* 0xF2 */ + { + sblive_miStateSysCommon3Key}, /* 0xF2 , Byte 1 */ + { + sblive_miStateSysCommon3Vel}, /* 0xF2 , Byte 2 */ + { + sblive_miStateSysExNorm}, /* 0xF0, 0xF7, Normal mode */ + { + sblive_miStateSysReal} /* 0xF4 - 0xF6 ,0xF8 - 0xFF */ +}; + +/* Installs the IRQ handler for the MPU in port */ + +/* and initialize parameters */ + +int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + DPF(2, "emu10k1_mpuin_open\n"); + + if (!(card_mpuin->status & FLAGS_AVAILABLE)) + return CTSTATUS_INUSE; + + /* Copy open info and mark channel as in use */ + card_mpuin->openinfo = *openinfo; + card_mpuin->status &= ~FLAGS_AVAILABLE; /* clear */ + card_mpuin->status |= FLAGS_READY; /* set */ + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + card_mpuin->firstmidiq = NULL; + card_mpuin->lastmidiq = NULL; + card_mpuin->qhead = 0; + card_mpuin->qtail = 0; + + sblive_miStateInit(card_mpuin); + + emu10k1_mpu_reset(card); + emu10k1_mpu_acquire(card); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpuin_close(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + DPF(2, "emu10k1_mpuin_close()\n"); + + /* Check if there are pending input SysEx buffers */ + if (card_mpuin->firstmidiq != NULL) { + ERROR(); + return CTSTATUS_ERROR; + } + + /* Disable RX interrupt */ + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + emu10k1_mpu_release(card); + + card_mpuin->status |= FLAGS_AVAILABLE; /* set */ + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + + return CTSTATUS_SUCCESS; +} + +/* Adds MIDI buffer to local queue list */ + +int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr) +{ + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuin_add_buffer()\n"); + + /* Update MIDI buffer flags */ + midihdr->flags |= MIDIBUF_INQUEUE; /* set */ + midihdr->flags &= ~MIDIBUF_DONE; /* clear */ + + if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) { + /* Message lost */ + return CTSTATUS_ERROR; + } + + midiq->next = NULL; + midiq->qtype = 1; + midiq->length = midihdr->bufferlength; + midiq->sizeLeft = midihdr->bufferlength; + midiq->midibyte = midihdr->data; + midiq->refdata = (unsigned long) midihdr; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + if (card_mpuin->firstmidiq == NULL) { + card_mpuin->firstmidiq = midiq; + card_mpuin->lastmidiq = midiq; + } else { + (card_mpuin->lastmidiq)->next = midiq; + card_mpuin->lastmidiq = midiq; + } + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/* First set the Time Stamp if MIDI IN has not started. */ + +/* Then enable RX Irq. */ + +int emu10k1_mpuin_start(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + u8 dummy; + + DPF(2, "emu10k1_mpuin_start()\n"); + + /* Set timestamp if not set */ + if (card_mpuin->status & FLAGS_MIDM_STARTED) { + DPF(2, "Time Stamp not changed\n"); + } else { + while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS); + + card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */ + + /* Set new time stamp */ + card_mpuin->timestart = (jiffies * 1000) / HZ; + DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart); + + card_mpuin->qhead = 0; + card_mpuin->qtail = 0; + + emu10k1_irq_enable(card, INTE_MIDIRXENABLE); + } + + return CTSTATUS_SUCCESS; +} + +/* Disable the RX Irq. If a partial recorded buffer */ + +/* exist, send it up to IMIDI level. */ + +int emu10k1_mpuin_stop(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuin_stop()\n"); + + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + + if (card_mpuin->firstmidiq) { + spin_lock_irqsave(&card_mpuin->lock, flags); + + midiq = card_mpuin->firstmidiq; + if (midiq != NULL) { + if (midiq->sizeLeft == midiq->length) + midiq = NULL; + else { + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + } + } + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + if (midiq) { + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + kfree(midiq); + } + } + + return CTSTATUS_SUCCESS; +} + +/* Disable the RX Irq. If any buffer */ + +/* exist, send it up to IMIDI level. */ +int emu10k1_mpuin_reset(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + struct midi_queue *midiq; + + DPF(2, "emu10k1_mpuin_reset()\n"); + + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + while (card_mpuin->firstmidiq) { + midiq = card_mpuin->firstmidiq; + card_mpuin->firstmidiq = midiq->next; + + if (midiq->sizeLeft == midiq->length) + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + else + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + + kfree(midiq); + } + + card_mpuin->lastmidiq = NULL; + card_mpuin->status &= ~FLAGS_MIDM_STARTED; + + return CTSTATUS_SUCCESS; +} + +/* Passes the message with the data back to the client */ + +/* via IRQ & DPC callbacks to Ring 3 */ +int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid) +{ + unsigned long timein; + struct midi_queue *midiq; + unsigned long callback_msg[3]; + struct midi_hdr *midihdr; + + /* Called during ISR. The data & code touched are: + * 1. card_mpuin + * 2. The function to be called + */ + + timein = card_mpuin->timein; + if (card_mpuin->timestart <= timein) + callback_msg[0] = timein - card_mpuin->timestart; + else + callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein; + + if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) { + callback_msg[1] = data; + callback_msg[2] = bytesvalid; + DPD(2, "emu10k1_mpuin_callback: midimsg = %lx\n", data); + } else { + midiq = (struct midi_queue *) data; + midihdr = (struct midi_hdr *) midiq->refdata; + + callback_msg[1] = midiq->length - midiq->sizeLeft; + callback_msg[2] = midiq->refdata; + midihdr->flags &= ~MIDIBUF_INQUEUE; + midihdr->flags |= MIDIBUF_DONE; + + midihdr->bytesrecorded = midiq->length - midiq->sizeLeft; + } + + /* Notify client that Sysex buffer has been sent */ + emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg); + + return CTSTATUS_SUCCESS; +} + +void emu10k1_mpuin_bh(unsigned long refdata) +{ + u8 data; + unsigned idx; + struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata; + unsigned long flags; + + while (card_mpuin->qhead != card_mpuin->qtail) { + spin_lock_irqsave(&card_mpuin->lock, flags); + idx = card_mpuin->qhead; + data = card_mpuin->midiq[idx].data; + card_mpuin->timein = card_mpuin->midiq[idx].timein; + idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; + card_mpuin->qhead = idx; + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + sblive_miStateEntry(card_mpuin, data); + } + + return; +} + +/* IRQ callback handler routine for the MPU in port */ + +int emu10k1_mpuin_irqhandler(struct emu10k1_card *card) +{ + unsigned idx; + unsigned count; + u8 MPUIvalue; + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + /* IRQ service routine. The data and code touched are: + * 1. card_mpuin + */ + + count = 0; + idx = card_mpuin->qtail; + + while (1) { + if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) { + ++count; + card_mpuin->midiq[idx].data = MPUIvalue; + card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ; + idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; + } else { + break; + } + } + + if (count) { + card_mpuin->qtail = idx; + + tasklet_hi_schedule(&card_mpuin->tasklet); + } + + return CTSTATUS_SUCCESS; +} + +/*****************************************************************************/ + +/* Supporting functions for Midi-In Interpretation State Machine */ + +/*****************************************************************************/ + +/* FIXME: This should be a macro */ +int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin) +{ + card_mpuin->status = 0; /* For MIDI running status */ + card_mpuin->fstatus = 0; /* For 0xFn status only */ + card_mpuin->curstate = STIN_PARSE; + card_mpuin->laststate = STIN_PARSE; + card_mpuin->data = 0; + card_mpuin->timestart = 0; + card_mpuin->timein = 0; + + return CTSTATUS_SUCCESS; +} + +/* FIXME: This should be a macro */ +int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); +} + +int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + switch (data & 0xf0) { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + card_mpuin->curstate = STIN_3BYTE; + break; + + case 0xC0: + case 0xD0: + card_mpuin->curstate = STIN_2BYTE; + break; + + case 0xF0: + /* System messages do not affect the previous running status! */ + switch (data & 0x0f) { + case 0x0: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_EX_NORM; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + } + + return CTSTATUS_NEXT_BYTE; + + case 0x7: + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0); + return CTSTATUS_ERROR; + + case 0x2: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_COMMON_3; + break; + + case 0x1: + case 0x3: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_COMMON_2; + break; + + default: + /* includes 0xF4 - 0xF6, 0xF8 - 0xFF */ + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + } + + break; + + default: + DPF(2, "BUG: default case hit\n"); + return CTSTATUS_ERROR; + } + + return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); +} + +int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + u8 temp = data & 0xf0; + + if (temp < 0x80) { + return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data); + } else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) { + card_mpuin->status = data; + card_mpuin->curstate = STIN_3BYTE_KEY; + + return CTSTATUS_NEXT_BYTE; + } + + return midistatefn[STIN_PARSE].Fn(card_mpuin, data); +} + +int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = ((unsigned long) data) << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->data = data; + card_mpuin->curstate = STIN_3BYTE_VEL; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 2 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = ((unsigned long) data) << 8; + tmp |= card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = STIN_3BYTE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); + + return CTSTATUS_SUCCESS; +} + +int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + u8 temp = data & 0xf0; + + if ((temp == 0xc0) || (temp == 0xd0)) { + card_mpuin->status = data; + card_mpuin->curstate = STIN_2BYTE_KEY; + + return CTSTATUS_NEXT_BYTE; + } + + if (temp < 0x80) + return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data); + + return midistatefn[STIN_PARSE].Fn(card_mpuin, data); +} + +int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = STIN_2BYTE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + card_mpuin->fstatus = data; + card_mpuin->curstate = STIN_SYS_COMMON_2_KEY; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + card_mpuin->fstatus = data; + card_mpuin->curstate = STIN_SYS_COMMON_3_KEY; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->data = data; + card_mpuin->curstate = STIN_SYS_COMMON_3_VEL; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 2 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + unsigned long flags; + + if ((data > 0x7f) && (data != 0xf7)) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid Data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + + kfree(midiq); + } + + return CTSTATUS_ERROR; + } + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + } + + if (data == 0xf7) { + /* End of Sysex buffer */ + /* Send down the buffer */ + + card_mpuin->curstate = card_mpuin->laststate; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + + kfree(midiq); + } + + return CTSTATUS_SUCCESS; + } + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + + if (midiq->sizeLeft == 0) { + /* Special case */ + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + + kfree(midiq); + + return CTSTATUS_NEXT_BYTE; + } + } + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1); + + return CTSTATUS_NEXT_BYTE; +} diff --git a/drivers/sound/emu10k1/cardmi.h b/drivers/sound/emu10k1/cardmi.h new file mode 100644 index 000000000000..f78fc1f70dfd --- /dev/null +++ b/drivers/sound/emu10k1/cardmi.h @@ -0,0 +1,113 @@ +/* + ********************************************************************** + * sblive_mi.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _CARDMI_H +#define _CARDMI_H + +#include "icardmid.h" + +typedef enum +{ + STIN_PARSE = 0, + STIN_3BYTE, /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */ + STIN_3BYTE_KEY, /* Byte 1 */ + STIN_3BYTE_VEL, /* Byte 1 */ + STIN_2BYTE, /* 0xC0, 0xD0 */ + STIN_2BYTE_KEY, /* Byte 1 */ + STIN_SYS_COMMON_2, /* 0xF1, 0xF3 */ + STIN_SYS_COMMON_2_KEY, + STIN_SYS_COMMON_3, /* 0xF2 */ + STIN_SYS_COMMON_3_KEY, + STIN_SYS_COMMON_3_VEL, + STIN_SYS_EX_NORM, /* 0xF0, Normal mode */ + STIN_SYS_REAL +} midi_in_state; + + +/* flags for card MIDI in object */ +#define FLAGS_MIDM_STARTED 0x00001000 // Data has started to come in after Midm Start +#define MIDIIN_MAX_BUFFER_SIZE 200 // Definition for struct emu10k1_mpuin + +struct midi_data +{ + u8 data; + u32 timein; +}; + +struct emu10k1_mpuin +{ + spinlock_t lock; + struct midi_queue *firstmidiq; + struct midi_queue *lastmidiq; + unsigned qhead, qtail; + struct midi_data midiq[MIDIIN_MAX_BUFFER_SIZE]; + struct tasklet_struct tasklet; + struct midi_openinfo openinfo; + + /* For MIDI state machine */ + u8 status; /* For MIDI running status */ + u8 fstatus; /* For 0xFn status only */ + midi_in_state curstate; + midi_in_state laststate; + u32 timestart; + u32 timein; + u8 data; +}; + +int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *); +int emu10k1_mpuin_close(struct emu10k1_card *); +int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *); +int emu10k1_mpuin_start(struct emu10k1_card *); +int emu10k1_mpuin_stop(struct emu10k1_card *); +int emu10k1_mpuin_reset(struct emu10k1_card *); + +int sblive_miStateInit(struct emu10k1_mpuin *); +int sblive_miStateEntry(struct emu10k1_mpuin *, u8); +int sblive_miStateParse(struct emu10k1_mpuin *, u8); +int sblive_miState3Byte(struct emu10k1_mpuin *, u8); +int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8); +int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8); +int sblive_miState2Byte(struct emu10k1_mpuin *, u8); +int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8); +int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8); +int sblive_miStateSysReal(struct emu10k1_mpuin *, u8); + +int emu10k1_mpuin_irqhandler(struct emu10k1_card *); +void emu10k1_mpuin_bh(unsigned long); +int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid); + +#endif /* _CARDMI_H */ diff --git a/drivers/sound/emu10k1/cardmo.c b/drivers/sound/emu10k1/cardmo.c new file mode 100644 index 000000000000..e7a8612d231a --- /dev/null +++ b/drivers/sound/emu10k1/cardmo.c @@ -0,0 +1,229 @@ + +/* + ********************************************************************** + * cardmo.c - MIDI UART output HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmo.h" + +/* Installs the IRQ handler for the MPU out port * + * and initialize parameters */ + +int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + + DPF(2, "emu10k1_mpuout_open()\n"); + + if (!(card_mpuout->status & FLAGS_AVAILABLE)) + return CTSTATUS_INUSE; + + /* Copy open info and mark channel as in use */ + card_mpuout->intr = 0; + card_mpuout->openinfo = *openinfo; + card_mpuout->status &= ~FLAGS_AVAILABLE; + card_mpuout->laststatus = 0x80; + card_mpuout->firstmidiq = NULL; + card_mpuout->lastmidiq = NULL; + + emu10k1_mpu_reset(card); + emu10k1_mpu_acquire(card); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpuout_close(struct emu10k1_card *card) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + struct midi_queue *midiq; + struct midi_hdr *midihdr; + unsigned long flags; + + DPF(2, "emu10k1_mpuout_close()\n"); + + emu10k1_irq_disable(card, INTE_MIDITXENABLE); + + spin_lock_irqsave(&card_mpuout->lock, flags); + + while (card_mpuout->firstmidiq != NULL) { + midiq = card_mpuout->firstmidiq; + midihdr = (struct midi_hdr *) midiq->refdata; + + card_mpuout->firstmidiq = midiq->next; + + kfree(midihdr->data); + kfree(midihdr); + kfree(midiq); + } + + card_mpuout->lastmidiq = NULL; + + emu10k1_mpu_release(card); + + card_mpuout->status |= FLAGS_AVAILABLE; + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/* If there isn't enough buffer space, reject Midi Buffer. * +* Otherwise, disable TX, create object to hold Midi * +* uffer, update buffer flags and other parameters * +* before enabling TX again. */ + +int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuout_add_buffer()\n"); + + if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) + return CTSTATUS_SUCCESS; + + midihdr->flags |= MIDIBUF_INQUEUE; + midihdr->flags &= ~MIDIBUF_DONE; + + if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { + /* Message lost */ + return CTSTATUS_NOMEMORY; + } + + midiq->next = NULL; + midiq->qtype = 1; + midiq->length = midihdr->bufferlength; + midiq->sizeLeft = midihdr->bufferlength; + midiq->midibyte = midihdr->data; + + midiq->refdata = (unsigned long) midihdr; + + spin_lock_irqsave(&card_mpuout->lock, flags); + + if (card_mpuout->firstmidiq == NULL) { + card_mpuout->firstmidiq = midiq; + card_mpuout->lastmidiq = midiq; + } else { + (card_mpuout->lastmidiq)->next = midiq; + card_mpuout->lastmidiq = midiq; + } + + card_mpuout->intr = 0; + + emu10k1_irq_enable(card, INTE_MIDITXENABLE); + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return CTSTATUS_SUCCESS; +} + +void emu10k1_mpuout_bh(unsigned long refdata) +{ + struct emu10k1_card *card = (struct emu10k1_card *) refdata; + struct emu10k1_mpuout *card_mpuout = card->mpuout; + int cByteSent = 0; + int status; + struct midi_queue *midiq; + struct midi_queue *doneq = NULL; + unsigned long flags; + + spin_lock_irqsave(&card_mpuout->lock, flags); + + while (card_mpuout->firstmidiq != NULL) { + midiq = card_mpuout->firstmidiq; + + while (cByteSent < 4 && midiq->sizeLeft) { + status = emu10k1_mpu_write_data(card, *midiq->midibyte); + + if (status == CTSTATUS_SUCCESS) { + ++cByteSent; + --midiq->sizeLeft; + ++midiq->midibyte; + } else { + DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); + } + } + + if (midiq->sizeLeft == 0) { + if (doneq == NULL) + doneq = midiq; + card_mpuout->firstmidiq = midiq->next; + } else + break; + } + + if (card_mpuout->firstmidiq == NULL) + card_mpuout->lastmidiq = NULL; + + if (doneq != NULL) { + while (doneq != card_mpuout->firstmidiq) { + unsigned long callback_msg[3]; + + midiq = doneq; + doneq = midiq->next; + + if (midiq->qtype) { + callback_msg[0] = 0; + callback_msg[1] = midiq->length; + callback_msg[2] = midiq->refdata; + + emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg); + } else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F) + card_mpuout->laststatus = (u8) midiq->refdata; + + kfree(midiq); + } + } + + if ((card_mpuout->firstmidiq != NULL) || cByteSent) { + card_mpuout->intr = 0; + emu10k1_irq_enable(card, INTE_MIDITXENABLE); + } + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return; +} + +int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + + DPF(4, "emu10k1_mpuout_irqhandler\n"); + + card_mpuout->intr = 1; + emu10k1_irq_disable(card, INTE_MIDITXENABLE); + + tasklet_hi_schedule(&card_mpuout->tasklet); + + return CTSTATUS_SUCCESS; +} diff --git a/drivers/sound/emu10k1/cardmo.h b/drivers/sound/emu10k1/cardmo.h new file mode 100644 index 000000000000..83871185ed08 --- /dev/null +++ b/drivers/sound/emu10k1/cardmo.h @@ -0,0 +1,61 @@ +/* + ********************************************************************** + * cardmo.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _CARDMO_H +#define _CARDMO_H + +#include "icardmid.h" + +#define CARDMIDIOUT_STATE_DEFAULT 0x00000000 +#define CARDMIDIOUT_STATE_SUSPEND 0x00000001 + +struct emu10k1_mpuout +{ + u32 status; + u32 state; + volatile int intr; + struct midi_queue *firstmidiq; + struct midi_queue *lastmidiq; + u8 laststatus; + struct tasklet_struct tasklet; + spinlock_t lock; + struct midi_openinfo openinfo; +}; + +int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *); +int emu10k1_mpuout_close(struct emu10k1_card *); +int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *); + +int emu10k1_mpuout_irqhandler(struct emu10k1_card *); +void emu10k1_mpuout_bh(unsigned long); + +#endif /* _CARDMO_H */ diff --git a/drivers/sound/emu10k1/cardwi.c b/drivers/sound/emu10k1/cardwi.c new file mode 100644 index 000000000000..fce4f0fdf11e --- /dev/null +++ b/drivers/sound/emu10k1/cardwi.c @@ -0,0 +1,472 @@ + +/* + ********************************************************************** + * cardwi.c - PCM input HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "recmgr.h" +#include "audio.h" +#include "cardwi.h" + +void query_format(int recsrc, struct wave_format *wave_fmt) +{ + + switch (recsrc) { + case WAVERECORD_AC97: + + if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1)) + wave_fmt->channels = 2; + + if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2) + wave_fmt->samplingrate = 0xBB80; + else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2) + wave_fmt->samplingrate = 0xAC44; + else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2) + wave_fmt->samplingrate = 0x7D00; + else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2) + wave_fmt->samplingrate = 0x5DC0; + else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2) + wave_fmt->samplingrate = 0x5622; + else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2) + wave_fmt->samplingrate = 0x3E80; + else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2) + wave_fmt->samplingrate = 0x2B11; + else + wave_fmt->samplingrate = 0x1F40; + + if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8)) + wave_fmt->bitsperchannel = 16; + + break; + + case WAVERECORD_MIC: + wave_fmt->channels = 1; + wave_fmt->samplingrate = 0x1F40; + wave_fmt->bitsperchannel = 8; + break; + + case WAVERECORD_FX: + wave_fmt->channels = 2; + wave_fmt->samplingrate = 0xBB80; + wave_fmt->bitsperchannel = 16; + break; + + default: + break; + } + + return; +} + +static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer) +{ + u32 reqsize; + int i, j; + u32 size[4]; + + /* NOTE: record buffer size only can be certain sizes. If the requested + * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */ + if (!wave_in->rec_ptr->is_16bit) + *bufsize <<= 1; + + if (*bufsize >= 0x10000) { + *bufsize = reqsize = 0x10000; + wave_in->rec_ptr->bufsize = 31; + } else { + reqsize = 0; + size[0] = 384; + size[1] = 448; + size[2] = 512; + size[3] = 640; + + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (*bufsize >= size[j]) { + reqsize = size[j]; + size[j] = size[j] * 2; + wave_in->rec_ptr->bufsize = i * 4 + j + 1; + } else + goto exitloop; + exitloop: + if (reqsize == 0) { + reqsize = 384; + wave_in->rec_ptr->bufsize = 1; + } + + *bufsize = reqsize; + } + + DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize); + + /* Recording buffer must be continuous and page-aligned */ + if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL) + return CTSTATUS_ERROR; + + DPD(2, "recbufsize: %x\n", *bufsize); + + *buffer = (u8 *) wave_in->memhandle->virtaddx; + + return CTSTATUS_SUCCESS; +} + +static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size) +{ + u8 *buffer; + + wave_in->rec_ptr->card = card; + wave_in->rec_ptr->recpos = 0; + wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate; + wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0; + wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0; + + /* Allocate buffer here */ + if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) { + ERROR(); + return CTSTATUS_ERROR; + } + + /* recbufsize contains actual record buffer size */ + /* for 8 bit samples the size is twice the requested */ + /* value since we only make use of one in every two bytes */ + wave_in->rec_ptr->recbufsize = *size; + wave_in->rec_ptr->recbuffer = buffer; + wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx; + + return CTSTATUS_SUCCESS; +} + +static void dealloc_recbuffer(struct wave_in *wave_in) +{ + emu10k1_free_memphysical(wave_in->memhandle); + return; +} + +int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + struct wave_in **wave_in_tmp = NULL; + u32 buffsize, bytespersec, delay; + unsigned long flags; + + DPF(2, "emu10k1_wavein_open()\n"); + + if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) { + ERROR(); + return CTSTATUS_ERROR; + } + + wave_in->state = CARDWAVE_STATE_STOPPED; + wave_in->wave_fmt = wiinst->wave_fmt; + wave_in->memhandle = NULL; + wave_in->timer = NULL; + + switch (wiinst->recsrc) { + case WAVERECORD_AC97: + wave_in_tmp = &card->wavein->ac97; + break; + case WAVERECORD_MIC: + wave_in_tmp = &card->wavein->mic; + break; + case WAVERECORD_FX: + wave_in_tmp = &card->wavein->fx; + break; + default: + break; + } + + spin_lock_irqsave(&card->lock, flags); + if (*wave_in_tmp != NULL) { + spin_unlock_irqrestore(&card->lock, flags); + kfree(wave_in); + return CTSTATUS_ERROR; + } + + *wave_in_tmp = wave_in; + spin_unlock_irqrestore(&card->lock, flags); + + wiinst->wave_in = wave_in; + + if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + buffsize = wiinst->fragment_size * wiinst->numfrags; + + if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + wiinst->fragment_size = buffsize / wiinst->numfrags; + + /* This callback size returned is the size in the play buffer. + * For 8-bit samples, callbacksize of user buffer should be + * half of the callbacksize in play buffer. */ + if (wave_in->wave_fmt.bitsperchannel == 8) + wiinst->fragment_size >>= 1; + + wave_in->callbacksize = wiinst->fragment_size; + + emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc); + + bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); + delay = (48000 * wave_in->callbacksize) / bytespersec; + + if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + unsigned long flags; + + if (wave_in->state != CARDWAVE_STATE_STOPPED) + emu10k1_wavein_stop(wave_dev); + + if (wave_in->timer != NULL) + emu10k1_timer_uninstall(card, wave_in->timer); + + if (wave_in->memhandle != NULL) + dealloc_recbuffer(wave_in); + + if (wave_in->rec_ptr != NULL) + kfree(wave_in->rec_ptr); + + spin_lock_irqsave(&card->lock, flags); + switch (wave_dev->wiinst->recsrc) { + case WAVERECORD_AC97: + card->wavein->ac97 = NULL; + break; + case WAVERECORD_MIC: + card->wavein->mic = NULL; + break; + case WAVERECORD_FX: + card->wavein->fx = NULL; + break; + default: + break; + } + spin_unlock_irqrestore(&card->lock, flags); + + kfree(wave_in); + wave_dev->wiinst->wave_in = NULL; + + return; +} + +void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) +{ + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + + DPF(2, "emu10k1_wavein_start()\n"); + + if (wave_in->state == CARDWAVE_STATE_STARTED) + return; + + emu10k1_start_record(wave_in->rec_ptr); + wave_in->state = CARDWAVE_STATE_STARTED; + + emu10k1_timer_enable(wave_dev->card, wave_in->timer); + + return; +} + +void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev) +{ + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + + DPF(2, "emu10k1_wavein_stop()\n"); + + emu10k1_stop_record(wave_in->rec_ptr); + emu10k1_timer_disable(wave_dev->card, wave_in->timer); + + wave_in->rec_ptr->recpos = 0; + wave_in->state = CARDWAVE_STATE_STOPPED; + + return; +} + +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in = wiinst->wave_in; + u32 bytespersec, delay; + + DPF(2, "emu10k1_wavein_setformat()\n"); + + query_format(wiinst->recsrc, &wiinst->wave_fmt); + + if (!wave_in) + return CTSTATUS_SUCCESS; + + if (wave_in->state == CARDWAVE_STATE_STARTED) { + wiinst->wave_fmt = wave_in->wave_fmt; + return CTSTATUS_SUCCESS; + } + + if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate) + || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel) + || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) { + + emu10k1_timer_uninstall(card, wave_in->timer); + + wave_in->wave_fmt = wiinst->wave_fmt; + + bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); + delay = (48000 * wave_in->callbacksize) / bytespersec; + + if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos) +{ + struct record *rec_ptr = wave_in->rec_ptr; + + /* Get position of current address, this is in no. of bytes in play buffer */ + emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos); + + *size = *curpos - rec_ptr->recpos; + + /* Recpos is the actual position in user buffer and play buffer */ + if (*curpos < rec_ptr->recpos) + *size += rec_ptr->recbufsize; + + if (!rec_ptr->is_16bit) + *size >>= 1; + + return; +} + +static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size) +{ + u16 sample; + u8 byte; + + while (size--) { + sample = (*srcbuf) + 32767; + byte = (u8) (sample >> 8); + copy_to_user(dstbuf, &byte, 1); + dstbuf++; + srcbuf++; + } +} + +/* transfer the data from the wave device. */ +void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size) +{ + struct wave_in *wave_in = wiinst->wave_in; + struct record *rec_ptr = wave_in->rec_ptr; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size); + *size = sizetocopy; + + if (!sizetocopy) + return; + + spin_lock_irqsave(&wiinst->lock, flags); + + sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2; + + start = rec_ptr->recpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (rec_ptr->is_16bit) { + copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now); + copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy); + } else { + copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now); + copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy); + } + } else { + if (sizetocopy == sizetocopy_now) + rec_ptr->recpos = 0; + else + rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (rec_ptr->is_16bit) + copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy); + else + copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy); + } + + return; +} + +/* get the specified control value of the wave device. */ + +int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value) +{ + switch (ctrlid) { + case WAVECURPOS: + /* There is no actual start yet */ + if (wave_in->state == CARDWAVE_STATE_STOPPED) { + *value = 0; + } else { + /* value is in byte units */ + *value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0); + } + + break; + + default: + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} diff --git a/drivers/sound/emu10k1/cardwi.h b/drivers/sound/emu10k1/cardwi.h new file mode 100644 index 000000000000..2d781033d788 --- /dev/null +++ b/drivers/sound/emu10k1/cardwi.h @@ -0,0 +1,92 @@ +/* + ********************************************************************** + * cardwi.h -- header file for card wave input functions + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ +#ifndef _CARDWI_H +#define _CARDWI_H + +#include "icardwav.h" + +struct wave_in +{ + struct list_head list; + + u32 state; + struct record *rec_ptr; + struct memhandle *memhandle; + struct emu_timer *timer; + u32 callbacksize; + struct wave_format wave_fmt; +}; + +struct wiinst +{ + struct wave_in *wave_in; + struct wave_format wave_fmt; + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + wait_queue_head_t wait_queue; + int mapped; + u32 total_recorded; + u32 blocks; + u32 curpos; + spinlock_t lock; + u8 recsrc; +}; + +struct emu10k1_wavein +{ + struct wave_in *ac97; + struct wave_in *mic; + struct wave_in *fx; + + u8 recsrc; +}; + + +#define WAVEIN_MAXBUFSIZE 65536 +#define WAVEIN_MINBUFSIZE 368 + +#define WAVEIN_DEFAULTFRAGLEN 100 +#define WAVEIN_DEFAULTBUFLEN 1000 + +#define WAVEIN_MINFRAGSHIFT 8 + +int emu10k1_wavein_open(struct emu10k1_wavedevice *); +void emu10k1_wavein_close(struct emu10k1_wavedevice *); +void emu10k1_wavein_start(struct emu10k1_wavedevice *); +void emu10k1_wavein_stop(struct emu10k1_wavedevice *); +void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *); +void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *); +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *); +int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *); + + +#endif /* _CARDWI_H */ diff --git a/drivers/sound/emu10k1/cardwo.c b/drivers/sound/emu10k1/cardwo.c new file mode 100644 index 000000000000..2423df032d13 --- /dev/null +++ b/drivers/sound/emu10k1/cardwo.c @@ -0,0 +1,755 @@ + +/* + ********************************************************************** + * cardwo.c - PCM output HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardwo.h" +#include "audio.h" + +/* Volume calcs */ + +static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left) +{ + /* only applicable for playback */ + u32 volL, volR, vol = 0; + + volL = (wave_out->localvol & 0xffff); + volR = ((wave_out->localvol >> 16) & 0xffff); + + if (wave_out->globalvolFactor) { + volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff; + volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff; + } + + /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */ + /* New volume and pan */ + + if (volL == volR) { + vol = volL; + left->send_c = 0xff; + left->send_b = 0xff; + } else { + if (volL > volR) { + vol = volL; + left->send_c = 0xff; + left->send_b = (char) ((volR * 255) / vol); + } else { + vol = volR; + left->send_b = 0xff; + left->send_c = (char) ((volL * 255) / vol); + } + } + + left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); + + return vol; +} + +static void query_format(struct wave_format *wave_fmt) +{ + if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) + wave_fmt->channels = 2; + + if (wave_fmt->samplingrate >= 0x2EE00) + wave_fmt->samplingrate = 0x2EE00; + + if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) + wave_fmt->bitsperchannel = 16; + + return; +} + +static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer) +{ + u32 numpages, reqsize, pageindex, pagecount; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + unsigned long busaddx; + int i; + + reqsize = *size; + numpages = reqsize / PAGE_SIZE; + + /* If size is not a multiple of PAGE_SIZE then we need to round up */ + if (reqsize % PAGE_SIZE) + numpages += 1; + + DPD(2, "requested pages is: %d\n", numpages); + + wavexferbuf->numpages = numpages; + + /* Only for playback, request for emu address space */ + /* Support non page-aligned buffer, don't need interpolation page */ + + if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0) + return CTSTATUS_ERROR; + + if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL) + return CTSTATUS_ERROR; + + /* Fill in virtual memory table */ + for (pagecount = 0; pagecount < numpages; pagecount++) { + if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) { + wavexferbuf->numpages = pagecount; + return CTSTATUS_ERROR; + } + + DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]); + + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE); + + DPD(3, "Bus Addx: %lx\n", busaddx); + + pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + + ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex; + } + } + + *buffer = wave_out->pagetable; + + return CTSTATUS_SUCCESS; +} + +static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size) +{ + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + void **buffer; + + wavexferbuf->xferpos = 0; + wavexferbuf->silence_xferpos = 0; + wavexferbuf->stopposition = 0; + wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; + wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; + wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); + + if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS) + return CTSTATUS_ERROR; + + /* xferbufsize contains actual transfer buffer size */ + wavexferbuf->xferbufsize = *size; + wavexferbuf->xferbuffer = buffer; + + return CTSTATUS_SUCCESS; +} + +static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out) +{ + u32 pagecount, pageindex; + int i; + + if (wave_out->pagetable != NULL) { + for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) { + free_page((unsigned long) wave_out->pagetable[pagecount]); + + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex; + } + } + kfree(wave_out->pagetable); + } + + emu10k1_addxmgr_free(card, wave_out->emupageindex); + + return; +} + +static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device) +{ + struct emu10k1_waveout *card_waveout = card->waveout; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct voice_allocdesc voice_allocdesc; + struct voice_param *left, *right; + u32 size; + + /* Allocate voices here, if no voices available, return error. + * Init voice_allocdesc first.*/ + + voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK; + + voice_allocdesc.flags = 0; + + if (device == 1) + voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2; + + if (wave_out->wave_fmt.channels == 1) + voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO; + + if (wave_out->wave_fmt.bitsperchannel == 16) + voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT; + + if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL) + return CTSTATUS_ERROR; + + /* voice initialization */ + + left = &wave_out->voice->params; + + /* Calculate pitch */ + left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8); + + DPD(2, "Initial pitch --> %x\n", left->initial_pitch); + + /* Easy way out.. gotta calculate value */ + left->pitch_target = 0; + left->volume_target = 0; + left->FC_target = 0; + + left->byampl_env_sustain = 0x7f; + left->byampl_env_decay = 0x7f; + + if (wave_out->globalreverbFactor) { + u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff); + + left->send_a = (t > 255) ? 255 : t; + } else { + left->send_a = 0; + } + + if (wave_out->globalchorusFactor) { + u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff); + + left->send_d = (t > 255) ? 255 : t; + } else { + left->send_d = 0; + } + + set_volume_instance(card_waveout, wave_out, left); + + left->pan_target = left->send_c; + left->aux_target = left->send_b; + + size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample; + left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample; + left->end = left->start + size; + left->startloop = left->start; + left->endloop = left->end; + + if (wave_out->voice->linked_voice) { + DPF(2, "is stereo\n"); + right = &wave_out->voice->linked_voice->params; + + right->initial_pitch = left->initial_pitch; + + /* Easy way out.. gotta calculate value */ + right->pitch_target = 0; + right->volume_target = 0; + right->FC_target = 0; + + right->byampl_env_sustain = 0x7f; + right->byampl_env_decay = 0x7f; + + right->send_d = left->send_d; + right->send_a = left->send_a; + + /* Left output of right channel is always zero */ + right->send_c = 0; + + /* Update right channel aux */ + right->pan_target = 0; + right->send_b = left->send_b; + right->aux_target = right->send_b; + + /* Zero out right output of left channel */ + left->send_b = 0; + left->aux_target = 0; + + /* Update right channel attenuation */ + right->initial_attn = left->initial_attn; + + right->start = left->start; + right->end = left->end; + right->startloop = left->startloop; + right->endloop = left->endloop; + + } + + DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + u32 bytespersec, delay; + u32 buffsize; + + DPF(2, "emu10k1_waveout_open()\n"); + + if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + woinst->wave_out = wave_out; + + /* Init channel object */ + wave_out->state = CARDWAVE_STATE_STOPPED; + wave_out->wave_fmt = woinst->wave_fmt; + wave_out->voice = NULL; + wave_out->emupageindex = -1; + wave_out->wavexferbuf = NULL; + wave_out->pagetable = NULL; + wave_out->timer = NULL; + + /* Assign default local volume */ + /* FIXME: Should we be maxing the initial values like this? */ + wave_out->localvol = 0xffffffff; + wave_out->localreverb = 0xffffffff; + wave_out->localchorus = 0xffffffff; + wave_out->globalvolFactor = 0xffff; + wave_out->globalreverbFactor = 0xffff; + wave_out->globalchorusFactor = 0xffff; + + wave_out->setpos = 0; + wave_out->position = 0; + + wave_out->fill_silence = 0; + + if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + buffsize = woinst->fragment_size * woinst->numfrags; + + if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + woinst->fragment_size = buffsize / woinst->numfrags; + wave_out->callbacksize = woinst->fragment_size; + + if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); + delay = (48000 * wave_out->callbacksize) / bytespersec; + + if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + + DPF(2, "emu10k1_waveout_close()\n"); + + if (wave_out->state != CARDWAVE_STATE_STOPPED) + emu10k1_waveout_stop(wave_dev); + + if (wave_out->timer != NULL) + emu10k1_timer_uninstall(card, wave_out->timer); + + if (wave_out->voice != NULL) + emu10k1_voice_free(&card->voicemgr, wave_out->voice); + + if (wave_out->emupageindex >= 0) + dealloc_xferbuffer(card, wave_out); + + if (wave_out->wavexferbuf != NULL) + kfree(wave_out->wavexferbuf); + + kfree(wave_out); + wave_dev->woinst->wave_out = NULL; + + return; +} + +int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + u32 start, startPosition; + + DPF(2, "emu10k1_waveout_start()\n"); + + /* If already started, return success */ + if (wave_out->state == CARDWAVE_STATE_STARTED) + return CTSTATUS_SUCCESS; + + if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos) + startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample); + else + startPosition = wave_out->wavexferbuf->stopposition; + + start = wave_out->voice->params.start; + wave_out->voice->params.start += startPosition; + + DPD(2, "CA is %x\n", wave_out->voice->params.start); + + emu10k1_voice_playback_setup(wave_out->voice); + + wave_out->voice->params.start = start; + + /* Actual start */ + emu10k1_voice_start(wave_out->voice); + + wave_out->state = CARDWAVE_STATE_STARTED; + wave_out->setpos = 0; + + emu10k1_timer_enable(card, wave_out->timer); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out = woinst->wave_out; + u32 bytespersec, delay; + + DPF(2, "emu10k1_waveout_setformat()\n"); + + query_format(&woinst->wave_fmt); + + if (wave_out == NULL) + return CTSTATUS_SUCCESS; + + if (wave_out->state == CARDWAVE_STATE_STARTED) { + woinst->wave_fmt = wave_out->wave_fmt; + return CTSTATUS_SUCCESS; + } + + if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate) + || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel) + || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) { + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + + emu10k1_timer_uninstall(card, wave_out->timer); + + emu10k1_voice_free(&card->voicemgr, wave_out->voice); + + wave_out->wave_fmt = woinst->wave_fmt; + wave_out->timer = NULL; + + wavexferbuf->xferpos = 0; + wavexferbuf->silence_xferpos = 0; + wavexferbuf->stopposition = 0; + wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; + wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; + wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); + + if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); + delay = (48000 * wave_out->callbacksize) / bytespersec; + + if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 samples = 32; + u32 position; + + DPF(2, "emu10k1_waveout_stop()\n"); + + if (wave_out->state == CARDWAVE_STATE_STOPPED) + return; + + emu10k1_timer_disable(card, wave_out->timer); + + /* Stop actual voice */ + emu10k1_voice_stop(wave_out->voice); + + /* Save the stop position */ + emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition); + + wavexferbuf->stopposition -= wave_out->voice->params.start; + + /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */ + position = wavexferbuf->stopposition * wavexferbuf->bytespersample; + + if (!wavexferbuf->is_16bit) + samples <<= 1; + + if (wavexferbuf->is_stereo) + samples <<= 1; + + samples -= 4; + + if (position >= samples * (wavexferbuf->is_16bit + 1)) + position -= samples * (wavexferbuf->is_16bit + 1); + else + position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1); + + wavexferbuf->stopposition = position / wavexferbuf->bytespersample; + + DPD(2, "position is %x\n", wavexferbuf->stopposition); + + wave_out->state = CARDWAVE_STATE_STOPPED; + wave_out->setpos = 0; + wave_out->position = 0; + + return; +} + +void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos) +{ + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + + /* Get position of current address, this is in no. of bytes in play buffer */ + emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos); + + if ((*curpos > wavexferbuf->silence_xferpos) + || ((*curpos == wavexferbuf->silence_xferpos) + && (wave_out->state == CARDWAVE_STATE_STARTED)) + || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0) + && (wave_out->state == CARDWAVE_STATE_STOPPED))) { + *size = *curpos - wavexferbuf->silence_xferpos; + *pending = wavexferbuf->xferbufsize - *size; + } else { + *pending = wavexferbuf->silence_xferpos - *curpos; + *size = wavexferbuf->xferbufsize - *pending; + } + + if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) { + if (*pending < wave_out->callbacksize) { + wave_out->fill_silence = 2; + *pending = 0; + *size = wavexferbuf->xferbufsize; + wavexferbuf->xferpos = *curpos; + } else { + if (wave_out->fill_silence == 2) { + *pending = 0; + *size = wavexferbuf->xferbufsize; + wavexferbuf->xferpos = *curpos; + } else { + *pending -= wave_out->callbacksize; + *size += wave_out->callbacksize; + } + } + } else { + if (*pending < wave_out->callbacksize) + wave_out->fill_silence = 1; + else + wave_out->fill_silence = 0; + } + + return; +} + +static void copy_block(u32 dst, u8 * src, u32 len, void **pt) +{ + int i, j, k; + + i = dst / PAGE_SIZE; + j = dst % PAGE_SIZE; + k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; + copy_from_user(pt[i] + j, src, k); + len -= k; + while (len >= PAGE_SIZE) { + copy_from_user(pt[++i], src + k, PAGE_SIZE); + k += PAGE_SIZE; + len -= PAGE_SIZE; + } + copy_from_user(pt[++i], src + k, len); + + return; +} + +static void fill_block(u32 dst, u8 val, u32 len, void **pt) +{ + int i, j, k; + + i = dst / PAGE_SIZE; + j = dst % PAGE_SIZE; + k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; + memset(pt[i] + j, val, k); + len -= k; + while (len >= PAGE_SIZE) { + memset(pt[++i], val, PAGE_SIZE); + len -= PAGE_SIZE; + } + memset(pt[++i], val, len); + + return; +} + +void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size) +{ + struct wave_out *wave_out = woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = min(wavexferbuf->xferbufsize, *size); + *size = sizetocopy; + + if (!sizetocopy) + return; + + spin_lock_irqsave(&woinst->lock, flags); + + sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos; + + start = wavexferbuf->xferpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + wavexferbuf->xferpos = sizetocopy; + wavexferbuf->silence_xferpos = wavexferbuf->xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); + + copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer); + copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer); + } else { + if (sizetocopy == sizetocopy_now) + wavexferbuf->xferpos = 0; + else + wavexferbuf->xferpos += sizetocopy; + + wavexferbuf->silence_xferpos = wavexferbuf->xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); + + copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer); + } + + return; +} + +void emu10k1_waveout_fillsilence(struct woinst *woinst) +{ + struct wave_out *wave_out = woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u16 filldata; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = wave_out->callbacksize; + + if (wave_out->wave_fmt.bitsperchannel == 8) + filldata = 0x8080; + else + filldata = 0x0000; + + spin_lock_irqsave(&woinst->lock, flags); + + sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos; + start = wavexferbuf->silence_xferpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + wavexferbuf->silence_xferpos = sizetocopy; + spin_unlock_irqrestore(&woinst->lock, flags); + fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer); + fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer); + } else { + if (sizetocopy == sizetocopy_now) + wavexferbuf->silence_xferpos = 0; + else + wavexferbuf->silence_xferpos += sizetocopy; + + spin_unlock_irqrestore(&woinst->lock, flags); + + fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer); + } + + return; +} + +/* get the specified control value of the wave device. */ + +int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value) +{ + switch (ctrl_id) { + case WAVECURPOS: + /* There is no actual start yet */ + if (wave_out->state == CARDWAVE_STATE_STOPPED) { + if (wave_out->setpos) + *value = wave_out->position; + else + *value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample; + } else { + emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value); + + *value -= wave_out->voice->params.start; + + /* Get number of bytes in play buffer per channel. + * If 8 bit mode is enabled, this needs to be changed. */ + { + u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1); + + *value *= wave_out->wavexferbuf->bytespersample; + + /* Refer to voicemgr.c, CA is not started at zero. + * We need to take this into account. */ + + samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1); + + if (*value >= samples) + *value -= samples; + else + *value += wave_out->wavexferbuf->xferbufsize - samples; + } + } + + break; + default: + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} diff --git a/drivers/sound/emu10k1/cardwo.h b/drivers/sound/emu10k1/cardwo.h new file mode 100644 index 000000000000..20391432a0ce --- /dev/null +++ b/drivers/sound/emu10k1/cardwo.h @@ -0,0 +1,118 @@ +/* + ********************************************************************** + * cardwo.h -- header file for card wave out functions + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _CARDWO_H +#define _CARDWO_H + +#include "icardwav.h" + +struct wave_xferbuf +{ + u32 xferpos; + u32 silence_xferpos; + u32 xferbufsize; /* transfer buffer size */ + u32 numpages; /* number of pages in transfer buffer */ + void **xferbuffer; /* pointer to the transfer buffer */ + int is_stereo; + int is_16bit; + int bytespersample; + u32 stopposition; +}; + +struct wave_out +{ + u32 state; + struct emu_voice *voice; + int emupageindex; + struct emu_timer *timer; + struct wave_xferbuf *wavexferbuf; + void **pagetable; + u32 callbacksize; + u32 localvol; + u32 localreverb; + u32 localchorus; + u32 globalvolFactor; + u32 globalreverbFactor; + u32 globalchorusFactor; + int setpos; + u32 position; + struct wave_format wave_fmt; + int fill_silence; +}; + +/* setting this to other than a power of two + may break some applications */ +#define WAVEOUT_MAXBUFSIZE 32768 +#define WAVEOUT_MINBUFSIZE 64 + +#define WAVEOUT_DEFAULTFRAGLEN 100 /* Time to play a fragment in ms (latency) */ +#define WAVEOUT_DEFAULTBUFLEN 1000 /* Time to play the entire buffer in ms */ + +#define WAVEOUT_MINFRAGSHIFT 4 + +struct woinst +{ + struct wave_out *wave_out; + struct wave_format wave_fmt; + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + wait_queue_head_t wait_queue; + int mapped; + u32 total_copied; + u32 total_played; + u32 blocks; + u32 curpos; + u32 device; + spinlock_t lock; +}; + +struct emu10k1_waveout +{ + u32 globalvol; + u32 mute; + u32 left; + u32 right; + u32 globalreverb; + u32 globalchorus; +}; + +int emu10k1_waveout_open(struct emu10k1_wavedevice *); +void emu10k1_waveout_close(struct emu10k1_wavedevice *); +int emu10k1_waveout_start(struct emu10k1_wavedevice *); +void emu10k1_waveout_stop(struct emu10k1_wavedevice *); +void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *); +void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *); +void emu10k1_waveout_fillsilence(struct woinst*); +int emu10k1_waveout_setformat(struct emu10k1_wavedevice*); +int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *); + +#endif /* _CARDWO_H */ diff --git a/drivers/sound/emu10k1/efxmgr.c b/drivers/sound/emu10k1/efxmgr.c new file mode 100644 index 000000000000..1b4e01a213c1 --- /dev/null +++ b/drivers/sound/emu10k1/efxmgr.c @@ -0,0 +1,34 @@ + +/* + ********************************************************************** + * sblive_fx.c + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "efxmgr.h" diff --git a/drivers/sound/emu10k1/efxmgr.h b/drivers/sound/emu10k1/efxmgr.h new file mode 100644 index 000000000000..eaa9dffa263c --- /dev/null +++ b/drivers/sound/emu10k1/efxmgr.h @@ -0,0 +1,43 @@ +/* + ********************************************************************** + * sblive_fx.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _EFXMGR_H +#define _EFXMGR_H + +#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c)) + +#define OP(op, z, w, x, y) \ + do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \ + WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \ + ++pc; } while (0) + + +#endif /* _EFXMGR_H */ diff --git a/drivers/sound/emu10k1/emu_wrapper.h b/drivers/sound/emu10k1/emu_wrapper.h new file mode 100644 index 000000000000..f0010d40e6d6 --- /dev/null +++ b/drivers/sound/emu10k1/emu_wrapper.h @@ -0,0 +1,11 @@ +#ifndef __EMU_WRAPPER_H +#define __EMU_WRAPPER_H + +#include + +#define UP_INODE_SEM(a) +#define DOWN_INODE_SEM(a) + +#define GET_INODE_STRUCT() + +#endif diff --git a/drivers/sound/emu10k1/emuadxmg.c b/drivers/sound/emu10k1/emuadxmg.c new file mode 100644 index 000000000000..94243c874558 --- /dev/null +++ b/drivers/sound/emu10k1/emuadxmg.c @@ -0,0 +1,101 @@ + +/* + ********************************************************************** + * emuadxmg.c - Address space manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +/* Allocates emu address space */ + +int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card) +{ + u16 *pagetable = card->emupagetable; + u16 index = 0; + u16 numpages; + unsigned long flags; + + /* Convert bytes to pages */ + numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0); + + while (index < (MAXPAGES - RESERVED - 1)) { + if (pagetable[index] & 0x8000) { + /* This block of pages is in use, jump to the start of the next block. */ + index += (pagetable[index] & 0x7fff); + } else { + /* Found free block */ + if (pagetable[index] >= numpages) { + spin_lock_irqsave(&card->lock, flags); + + /* Block is large enough */ + + /* If free block is larger than the block requested + * then adjust the size of the block remaining */ + if (pagetable[index] > numpages) + pagetable[index + numpages] = pagetable[index] - numpages; + + pagetable[index] = (numpages | 0x8000); /* Mark block as used */ + + spin_unlock_irqrestore(&card->lock, flags); + + return index; + } else { + /* Block too small, jump to the start of the next block */ + index += pagetable[index]; + } + } + } + + return -1; +} + +/* Frees a previously allocated emu address space. */ + +void emu10k1_addxmgr_free(struct emu10k1_card *card, int index) +{ + u16 *pagetable = card->emupagetable; + u16 origsize = 0; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + if (pagetable[index] & 0x8000) { + /* Block is allocated - mark block as free */ + origsize = pagetable[index] & 0x7fff; + pagetable[index] = origsize; + + /* If next block is free, we concat both blocks */ + if (!(pagetable[index + origsize] & 0x8000)) + pagetable[index] += pagetable[index + origsize] & 0x7fff; + } + + spin_unlock_irqrestore(&card->lock, flags); + + return; +} diff --git a/drivers/sound/emu10k1/hwaccess.c b/drivers/sound/emu10k1/hwaccess.c new file mode 100644 index 000000000000..fda2baa2210c --- /dev/null +++ b/drivers/sound/emu10k1/hwaccess.c @@ -0,0 +1,430 @@ + +/* + ********************************************************************** + * hwaccess.c -- Hardware access layer + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * December 9, 1999 Jon Taylor rewrote the I/O subsystem + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "icardmid.h" + +/************************************************************************* +* Function : srToPitch * +* Input : sampleRate - sampling rate * +* Return : pitch value * +* About : convert sampling rate to pitch * +* Note : for 8010, sampling rate is at 48kHz, this function should * +* be changed. * +*************************************************************************/ +u32 srToPitch(u32 sampleRate) +{ + int i; + + /* FIXME: These tables should be defined in a headerfile */ + static u32 logMagTable[128] = { + 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, + 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, + 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, + 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, + 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, + 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, + 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, + 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, + 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, + 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, + 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, + 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, + 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, + 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, + 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, + 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df + }; + + static char logSlopeTable[128] = { + 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, + 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, + 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, + 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, + 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, + 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, + 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, + 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, + 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, + 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, + 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, + 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f + }; + + if (sampleRate == 0) + return (0); /* Bail out if no leading "1" */ + + sampleRate *= 11185; /* Scale 48000 to 0x20002380 */ + + for (i = 31; i > 0; i--) { + if (sampleRate & 0x80000000) { /* Detect leading "1" */ + return (u32) (((s32) (i - 15) << 20) + + logMagTable[0x7f & (sampleRate >> 24)] + + (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]); + } + sampleRate = sampleRate << 1; + } + + DPF(2, "srToPitch: BUG!\n"); + return 0; /* Should never reach this point */ +} + +/* Returns an attenuation based upon a cumulative volume value */ + +/* Algorithm calculates 0x200 - 0x10 log2 (input) */ +u8 sumVolumeToAttenuation(u32 value) +{ + u16 count = 16; + s16 ans; + + if (value == 0) + return 0xFF; + + /* Find first SET bit. This is the integer part of the value */ + while ((value & 0x10000) == 0) { + value <<= 1; + count--; + } + + /* The REST of the data is the fractional part. */ + ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12))); + if (ans > 0xFF) + ans = 0xFF; + + return (u8) ans; +} + +/******************************************* +* write/read PCI function 0 registers * +********************************************/ +void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return; +} + +void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data) +{ + unsigned long flags; + + data &= mask; + + spin_lock_irqsave(&card->lock, flags); + data |= inl(card->iobase + reg) & ~mask; + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return; +} + +u32 sblive_readfn0(struct emu10k1_card * card, u8 reg) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val; +} + +u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val & mask; +} + +/************************************************************************ +* write/read Emu10k1 pointer-offset register set, accessed through * +* the PTR and DATA registers * +*************************************************************************/ +void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) +{ + u32 regptr; + unsigned long flags; + + regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; + + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + data |= inl(card->iobase + DATA) & ~mask; + outl(data, card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + } else { + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + outl(data, card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + } + + return; +} + +u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) +{ + u32 regptr, val; + unsigned long flags; + + regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; + + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + val = inl(card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + + return (val & mask) >> offset; + } else { + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + val = inl(card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + + return val; + } +} + +void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum) +{ + /* Voice interrupt */ + if (voicenum >= 32) + sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1); + else + sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1); + + return; +} + +void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum) +{ + /* Voice interrupt */ + if (voicenum >= 32) + sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0); + else + sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0); + + return; +} + +static void sblive_wcwait(struct emu10k1_card *card, u32 wait) +{ + volatile unsigned uCount; + u32 newtime = 0, curtime; + + curtime = READ_FN0(card, WC_SAMPLECOUNTER); + while (wait--) { + uCount = 0; + while (uCount++ < TIMEOUT) { + newtime = READ_FN0(card, WC_SAMPLECOUNTER); + if (newtime != curtime) + break; + } + + if (uCount >= TIMEOUT) + break; + + curtime = newtime; + } +} + +int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + *data = inw(card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + outw(data, card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask) +{ + u16 temp; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + temp = inw(card->mixeraddx); + temp &= ~mask; + data &= mask; + temp |= data; + outw(temp, card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/********************************************************* +* MPU access functions * +**********************************************************/ + +int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + + if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { + outb(data, card->iobase + MUDATA); + ret = CTSTATUS_SUCCESS; + } else + ret = CTSTATUS_BUSY; + + spin_unlock_irqrestore(&card->lock, flags); + + return ret; +} + +int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + + if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { + *data = inb(card->iobase + MUDATA); + ret = CTSTATUS_SUCCESS; + } else + ret = CTSTATUS_NODATA; + + spin_unlock_irqrestore(&card->lock, flags); + + return ret; +} + +int emu10k1_mpu_reset(struct emu10k1_card *card) +{ + u8 status; + unsigned long flags; + + DPF(2, "emu10k1_mpu_reset()\n"); + + if (card->mpuacqcount == 0) { + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + status = inb(card->iobase + MUDATA); + spin_unlock_irqrestore(&card->lock, flags); + + if (status == 0xfe) + return CTSTATUS_SUCCESS; + else + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpu_acquire(struct emu10k1_card *card) +{ + /* FIXME: This should be a macro */ + ++card->mpuacqcount; + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpu_release(struct emu10k1_card *card) +{ + /* FIXME: this should be a macro */ + --card->mpuacqcount; + + return CTSTATUS_SUCCESS; +} diff --git a/drivers/sound/emu10k1/hwaccess.h b/drivers/sound/emu10k1/hwaccess.h new file mode 100644 index 000000000000..0dba188d3887 --- /dev/null +++ b/drivers/sound/emu10k1/hwaccess.h @@ -0,0 +1,204 @@ +/* + ********************************************************************** + * hwaccess.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _HWACCESS_H +#define _HWACCESS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +enum GlobalErrorCode +{ + CTSTATUS_SUCCESS = 0x0000, + CTSTATUS_ERROR, + CTSTATUS_NOMEMORY, + CTSTATUS_INUSE, +}; + +#define FLAGS_AVAILABLE 0x0001 +#define FLAGS_READY 0x0002 + +#define min(x,y) ((x) < (y)) ? (x) : (y) + +struct memhandle +{ + unsigned long busaddx; + void *virtaddx; + u32 order; +}; + +struct memhandle *emu10k1_alloc_memphysical(u32); +void emu10k1_free_memphysical(struct memhandle *); + +#define DEBUG_LEVEL 2 + +#ifdef EMU10K1_DEBUG +# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0) +# define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0) +#define ERROR() DPF(1,"error\n"); +#else +# define DPD(level,x,y...) /* not debugging: nothing */ +# define DPF(level,x) +#define ERROR() +#endif /* EMU10K1_DEBUG */ + +#include "8010.h" +#include "voicemgr.h" + +int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); +void emu10k1_addxmgr_free(struct emu10k1_card *, int); + +#include "timer.h" +#include "irqmgr.h" + +/* DATA STRUCTURES */ + +struct emu10k1_card +{ + struct list_head list; + + struct memhandle *virtualpagetable; + + struct memhandle *tankmem; + u32 tmemsize; + struct memhandle *silentpage; + + spinlock_t lock; + + struct voice_manager voicemgr; + u16 emupagetable[MAXPAGES]; + + struct list_head timers; + unsigned timer_delay; + spinlock_t timer_lock; + + struct pci_dev *pci_dev; + unsigned long iobase; + unsigned long mixeraddx; + u32 irq; + + unsigned long audio1_num; + unsigned long audio2_num; + unsigned long mixer_num; + unsigned long midi_num; + + struct emu10k1_waveout *waveout; + struct emu10k1_wavein *wavein; + struct emu10k1_mpuout *mpuout; + struct emu10k1_mpuin *mpuin; + + u16 arrwVol[SOUND_MIXER_NRDEVICES + 1]; + /* array is used from the member 1 to save (-1) operation */ + u32 digmix[96]; + unsigned int modcnt; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + u32 mpuacqcount; // Mpu acquire count + u32 has_toslink; // TOSLink detection + + u8 chiprev; /* Chip revision */ +}; + +#ifdef PRIVATE_PCM_VOLUME + +#define MAX_PCM_CHANNELS NUM_G +struct sblive_pcm_volume_rec { + struct files_struct *files; // identification of the same thread + u8 attn_l; // attenuation for left channel + u8 attn_r; // attenuation for right channel + u16 mixer; // saved mixer value for return + u8 channel_l; // idx of left channel + u8 channel_r; // idx of right channel + int opened; // counter - locks element +}; +extern struct sblive_pcm_volume_rec sblive_pcm_volume[]; + +#endif + + +#define ENABLE 0xffffffff +#define DISABLE 0x00000000 + +#define ENV_ON 0x80 +#define ENV_OFF 0x00 + +#define TIMEOUT 16384 + +u32 srToPitch(u32); +u8 sumVolumeToAttenuation(u32); + +extern struct list_head emu10k1_devs; + +/* Hardware Abstraction Layer access functions */ + +#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f)) + +#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f) + +void sblive_writefn0(struct emu10k1_card *, u8 , u32 ); +void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 ); + +u32 sblive_readfn0(struct emu10k1_card *, u8 ); +u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 ); + +void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 ); +u32 sblive_readptr(struct emu10k1_card *, u32 , u32 ); + +void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32); +void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32); + +/* AC97 Mixer access function */ +int sblive_readac97(struct emu10k1_card *, u8, u16 *); +int sblive_writeac97(struct emu10k1_card *, u8, u16); +int sblive_rmwac97(struct emu10k1_card *, u8, u16, u16); + +/* MPU access function*/ +int emu10k1_mpu_write_data(struct emu10k1_card *, u8); +int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *); +int emu10k1_mpu_reset(struct emu10k1_card *); +int emu10k1_mpu_acquire(struct emu10k1_card *); +int emu10k1_mpu_release(struct emu10k1_card *); + +#endif /* _HWACCESS_H */ diff --git a/drivers/sound/emu10k1/icardmid.h b/drivers/sound/emu10k1/icardmid.h new file mode 100644 index 000000000000..6a6ef419401f --- /dev/null +++ b/drivers/sound/emu10k1/icardmid.h @@ -0,0 +1,163 @@ +/* + ********************************************************************** + * isblive_mid.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _ICARDMIDI_H +#define _ICARDMIDI_H + +/* MIDI defines */ +#define MIDI_DATA_FIRST 0x00 +#define MIDI_DATA_LAST 0x7F +#define MIDI_STATUS_FIRST 0x80 +#define MIDI_STATUS_LAST 0xFF + +/* Channel status bytes */ +#define MIDI_STATUS_CHANNEL_FIRST 0x80 +#define MIDI_STATUS_CHANNEL_LAST 0xE0 +#define MIDI_STATUS_CHANNEL_MASK 0xF0 + +/* Channel voice messages */ +#define MIDI_VOICE_NOTE_OFF 0x80 +#define MIDI_VOICE_NOTE_ON 0x90 +#define MIDI_VOICE_POLY_PRESSURE 0xA0 +#define MIDI_VOICE_CONTROL_CHANGE 0xB0 +#define MIDI_VOICE_PROGRAM_CHANGE 0xC0 +#define MIDI_VOICE_CHANNEL_PRESSURE 0xD0 +#define MIDI_VOICE_PITCH_BEND 0xE0 + +/* Channel mode messages */ +#define MIDI_MODE_CHANNEL MIDI_VOICE_CONTROL_CHANGE + +/* System status bytes */ +#define MIDI_STATUS_SYSTEM_FIRST 0xF0 +#define MIDI_STATUS_SYSTEM_LAST 0xFF + +/* System exclusive messages */ +#define MIDI_SYSEX_BEGIN 0xF0 +#define MIDI_SYSEX_EOX 0xF7 + +/* System common messages */ +#define MIDI_COMMON_TCQF 0xF1 /* Time code quarter frame */ +#define MIDI_COMMON_SONG_POSITION 0xF2 +#define MIDI_COMMON_SONG_SELECT 0xF3 +#define MIDI_COMMON_UNDEFINED_F4 0xF4 +#define MIDI_COMMON_UNDEFINED_F5 0xF5 +#define MIDI_COMMON_TUNE_REQUEST 0xF6 + +/* System real-time messages */ +#define MIDI_RTIME_TIMING_CLOCK 0xF8 +#define MIDI_RTIME_UNDEFINED_F9 0xF9 +#define MIDI_RTIME_START 0xFA +#define MIDI_RTIME_CONTINUE 0xFB +#define MIDI_RTIME_STOP 0xFC +#define MIDI_RTIME_UNDEFINED_FD 0xFD +#define MIDI_RTIME_ACTIVE_SENSING 0xFE +#define MIDI_RTIME_SYSTEM_RESET 0xFF + +/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */ +#define MIDI_CACHE_ALL 1 +#define MIDI_CACHE_BESTFIT 2 +#define MIDI_CACHE_QUERY 3 +#define MIDI_UNCACHE 4 + +/* Event declarations for MPU IRQ Callbacks */ +#define ICARDMIDI_INLONGDATA 0x00000001 /* MIM_LONGDATA */ +#define ICARDMIDI_INLONGERROR 0x00000002 /* MIM_LONGERROR */ +#define ICARDMIDI_OUTLONGDATA 0x00000004 /* MOM_DONE for MPU OUT buffer */ +#define ICARDMIDI_INDATA 0x00000010 /* MIM_DATA */ +#define ICARDMIDI_INDATAERROR 0x00000020 /* MIM_ERROR */ + +/* Declaration for flags in CARDMIDIBUFFERHDR */ +/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */ +#define MIDIBUF_DONE 0x00000001 +#define MIDIBUF_INQUEUE 0x00000004 + +/* Declaration for msg parameter in midiCallbackFn */ +#define ICARDMIDI_OUTBUFFEROK 0x00000001 +#define ICARDMIDI_INMIDIOK 0x00000002 + +/* Declaration for technology in struct midi_caps */ +#define MT_MIDIPORT 0x00000001 /* In original MIDIOUTCAPS structure */ +#define MT_FMSYNTH 0x00000004 /* In original MIDIOUTCAPS structure */ +#define MT_AWESYNTH 0x00001000 +#define MT_PCISYNTH 0x00002000 +#define MT_PCISYNTH64 0x00004000 +#define CARDMIDI_AWEMASK 0x0000F000 + +enum LocalErrorCode +{ + CTSTATUS_NOTENABLED = 0x7000, + CTSTATUS_READY, + CTSTATUS_BUSY, + CTSTATUS_DATAAVAIL, + CTSTATUS_NODATA, + CTSTATUS_NEXT_BYTE +}; + +/* MIDI data block header */ +struct midi_hdr +{ + u8 *reserved; /* Pointer to original locked data block */ + u32 bufferlength; /* Length of data in data block */ + u32 bytesrecorded; /* Used for input only */ + u32 user; /* For client's use */ + u32 flags; /* Assorted flags (see defines) */ + struct list_head list; /* Reserved for driver */ + u8 *data; /* Second copy of first pointer */ +}; + +/* Enumeration for SetControl */ +enum +{ + MIDIOBJVOLUME = 0x1, + MIDIQUERYACTIVEINST +}; + +struct midi_queue +{ + struct midi_queue *next; + u32 qtype; /* 0 = short message, 1 = long data */ + u32 length; + u32 sizeLeft; + u8 *midibyte; + unsigned long refdata; +}; + +struct midi_openinfo +{ + u32 cbsize; + u32 flags; + unsigned long refdata; + u32 streamid; +}; + +int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *); + +#endif /* _ICARDMIDI_H */ diff --git a/drivers/sound/emu10k1/icardwav.h b/drivers/sound/emu10k1/icardwav.h new file mode 100644 index 000000000000..a141e7396513 --- /dev/null +++ b/drivers/sound/emu10k1/icardwav.h @@ -0,0 +1,52 @@ +/* + ********************************************************************** + * icardwav.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _ICARDWAV_H +#define _ICARDWAV_H + +/* Enumeration for SetControl */ +enum +{ + WAVECURPOS = 0x10, +}; + +struct wave_format +{ + u32 samplingrate; + u32 bitsperchannel; + u32 channels; /* 1 = Mono, 2 = Stereo */ +}; + +/* emu10k1_wave states */ +#define CARDWAVE_STATE_STOPPED 0x0001 +#define CARDWAVE_STATE_STARTED 0x0002 + +#endif /* _ICARDWAV_H */ diff --git a/drivers/sound/emu10k1/irqmgr.c b/drivers/sound/emu10k1/irqmgr.c new file mode 100644 index 000000000000..96bffcfe4878 --- /dev/null +++ b/drivers/sound/emu10k1/irqmgr.c @@ -0,0 +1,127 @@ + +/* + ********************************************************************** + * irqmgr.c - IRQ manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmi.h" +#include "cardmo.h" +#include "irqmgr.h" + +/* Interrupt handler */ + +void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct emu10k1_card *card = (struct emu10k1_card *) dev_id; + u32 irqstatus, ptr, tmp; + + if (!(irqstatus = sblive_readfn0(card, IPR))) + return; + + DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); + + /* Preserve PTR register */ + ptr = sblive_readfn0(card, PTR); + + /* + ** NOTE : + ** We do a 'while loop' here cos on certain machines, with both + ** playback and recording going on at the same time, IRQs will + ** stop coming in after a while. Checking IPND indeed shows that + ** there are interrupts pending but the PIC says no IRQs pending. + ** I suspect that some boards need edge-triggered IRQs but are not + ** getting that condition if we don't completely clear the IPND + ** (make sure no more interrupts are pending). + ** - Eric + */ + + do { + DPD(4, "irq status %x\n", irqstatus); + + tmp = irqstatus; + + if (irqstatus & IRQTYPE_TIMER) { + emu10k1_timer_irqhandler(card); + irqstatus &= ~IRQTYPE_TIMER; + } + + if (irqstatus & IRQTYPE_MPUIN) { + emu10k1_mpuin_irqhandler(card); + irqstatus &= ~IRQTYPE_MPUIN; + } + + if (irqstatus & IRQTYPE_MPUOUT) { + emu10k1_mpuout_irqhandler(card); + irqstatus &= ~IRQTYPE_MPUOUT; + } + + if (irqstatus) + emu10k1_irq_disable(card, irqstatus); + + sblive_writefn0(card, IPR, tmp); + + } while ((irqstatus = sblive_readfn0(card, IPR))); + + sblive_writefn0(card, PTR, ptr); + + return; +} + +/* Enables the specified irq service */ + +int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype) +{ + /* + * TODO : + * put protection here so that we don't accidentally + * screw-up another cardxxx objects irqs + */ + + DPD(4, "emu10k1_irq_enable %x\n", irqtype); + sblive_wrtmskfn0(card, INTE, irqtype, ENABLE); + + return CTSTATUS_SUCCESS; +} + +/* Disables the specified irq service */ + +int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype) +{ + /* + * TODO : + * put protection here so that we don't accidentally + * screw-up another cardxxx objects irqs + */ + + DPD(4, "emu10k1_irq_disable %x\n", irqtype); + sblive_wrtmskfn0(card, INTE, irqtype, DISABLE); + + return CTSTATUS_SUCCESS; +} diff --git a/drivers/sound/emu10k1/irqmgr.h b/drivers/sound/emu10k1/irqmgr.h new file mode 100644 index 000000000000..886a7374edd6 --- /dev/null +++ b/drivers/sound/emu10k1/irqmgr.h @@ -0,0 +1,59 @@ +/* + ********************************************************************** + * irq.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _IRQ_H +#define _IRQ_H + +/* EMU Irq Types */ +#define IRQTYPE_PCIBUSERROR IPR_PCIERROR +#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE) +#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK) +#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL) +#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY +#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY +#define IRQTYPE_TIMER IPR_INTERVALTIMER +#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) +#define IRQTYPE_DSP IPR_FXDSP + +struct emu10k1_wavedevice +{ + struct emu10k1_card *card; + struct wiinst *wiinst; + struct woinst *woinst; + u16 enablebits; +}; + +void emu10k1_timer_irqhandler(struct emu10k1_card *); + +int emu10k1_irq_enable(struct emu10k1_card *, u32); +int emu10k1_irq_disable(struct emu10k1_card *, u32); + +#endif /* _IRQ_H */ diff --git a/drivers/sound/emu10k1/main.c b/drivers/sound/emu10k1/main.c new file mode 100644 index 000000000000..bbdf721fb358 --- /dev/null +++ b/drivers/sound/emu10k1/main.c @@ -0,0 +1,825 @@ + +/* + ********************************************************************** + * main.c - Creative EMU10K1 audio driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up stuff + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + * + * Supported devices: + * /dev/dsp: Standard /dev/dsp device, OSS-compatible + * /dev/mixer: Standard /dev/mixer device, OSS-compatible + * /dev/midi: Raw MIDI UART device, mostly OSS-compatible + * + * Revision history: + * 0.1 beta Initial release + * 0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support. + * 0.3 Fixed mixer routing bug, added APS, joystick support. + * 0.4 Added rear-channel, SPDIF support. + * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes, + * moved bh's to tasklets, moved to the new PCI driver initialization style. + ********************************************************************** + */ + +/* These are only included once per module */ +#include +#include + +#include "hwaccess.h" +#include "efxmgr.h" +#include "cardwo.h" +#include "cardwi.h" +#include "cardmo.h" +#include "cardmi.h" +#include "recmgr.h" + +#define DRIVER_VERSION "0.5" + +/* FIXME: is this right? */ +#define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ + +#ifndef PCI_VENDOR_ID_CREATIVE +#define PCI_VENDOR_ID_CREATIVE 0x1102 +#endif + +#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1 +#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 +#endif + +#define EMU10K1_EXTENT 0x20 /* 32 byte I/O space */ + +enum { + EMU10K1 = 0, +}; + +static char *card_names[] __devinitdata = { + "EMU10K1", +}; + +static struct pci_device_id emu10k1_pci_tbl[] __initdata = { + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl); + +/* Global var instantiation */ + +LIST_HEAD(emu10k1_devs); + +extern struct file_operations emu10k1_audio_fops; +extern struct file_operations emu10k1_mixer_fops; +extern struct file_operations emu10k1_midi_fops; + +extern void emu10k1_interrupt(int, void *, struct pt_regs *s); +extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int); + +static int __devinit audio_init(struct emu10k1_card *card) +{ + if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n"); + return CTSTATUS_ERROR; + } + memset(card->waveout, 0, sizeof(struct emu10k1_waveout)); + + /* Assign default global volume, reverb, chorus */ + card->waveout->globalvol = 0xffffffff; + card->waveout->left = 0xffff; + card->waveout->right = 0xffff; + card->waveout->mute = 0; + card->waveout->globalreverb = 0xffffffff; + card->waveout->globalchorus = 0xffffffff; + + if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL)) + == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n"); + return CTSTATUS_ERROR; + } + memset(card->wavein, 0, sizeof(struct emu10k1_wavein)); + + card->wavein->recsrc = WAVERECORD_AC97; + + return CTSTATUS_SUCCESS; +} + +static void __devinit mixer_init(struct emu10k1_card *card) +{ + int count; + struct initvol { + int mixch; + int vol; + } initvol[] = { + { + SOUND_MIXER_VOLUME, 0x5050}, { + SOUND_MIXER_OGAIN, 0x3232}, { + SOUND_MIXER_SPEAKER, 0x3232}, { + SOUND_MIXER_PHONEIN, 0x3232}, { + SOUND_MIXER_MIC, 0x0000}, { + SOUND_MIXER_LINE, 0x0000}, { + SOUND_MIXER_CD, 0x3232}, { + SOUND_MIXER_LINE1, 0x3232}, { + SOUND_MIXER_LINE3, 0x3232}, { + SOUND_MIXER_DIGITAL1, 0x6464}, { + SOUND_MIXER_DIGITAL2, 0x6464}, { + SOUND_MIXER_PCM, 0x6464}, { + SOUND_MIXER_RECLEV, 0x3232}, { + SOUND_MIXER_TREBLE, 0x3232}, { + SOUND_MIXER_BASS, 0x3232}, { + SOUND_MIXER_LINE2, 0x4b4b}}; + + int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71, + 84, 85 + }; + + /* Reset */ + sblive_writeac97(card, AC97_RESET, 0); + +#if 0 + /* Check status word */ + { + u16 reg; + + sblive_readac97(card, AC97_RESET, ®); + DPD(2, "RESET 0x%x\n", reg); + sblive_readac97(card, AC97_MASTERTONE, ®); + DPD(2, "MASTER_TONE 0x%x\n", reg); + } +#endif + + /* Set default recording source to mic in */ + sblive_writeac97(card, AC97_RECORDSELECT, 0); + + /* Set default AC97 "PCM" volume to acceptable max */ + //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + //sblive_writeac97(card, AC97_LINE2, 0); + + /* Set default volumes for all mixer channels */ + + for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { + card->digmix[count] = 0x80000000; + sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); + } + + for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { + card->digmix[initdig[count]] = 0x7fffffff; + sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); + } + + for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) { + emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol); + } + + card->modcnt = 0; // Should this be here or in open() ? + + return; +} + +static int __devinit midi_init(struct emu10k1_card *card) +{ + if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL)) + == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); + return CTSTATUS_ERROR; + } + + memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); + + card->mpuout->intr = 1; + card->mpuout->status = FLAGS_AVAILABLE; + card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT; + + tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card); + + spin_lock_init(&card->mpuout->lock); + + if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) { + kfree(card->mpuout); + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); + return CTSTATUS_ERROR; + } + + memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); + + card->mpuin->status = FLAGS_AVAILABLE; + + tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin); + + spin_lock_init(&card->mpuin->lock); + + /* Reset the MPU port */ + if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) { + ERROR(); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +static void __devinit voice_init(struct emu10k1_card *card) +{ + struct voice_manager *voicemgr = &card->voicemgr; + struct emu_voice *voice; + int i; + + voicemgr->card = card; + voicemgr->lock = SPIN_LOCK_UNLOCKED; + + voice = voicemgr->voice; + for (i = 0; i < NUM_G; i++) { + voice->card = card; + voice->usage = VOICEMGR_USAGE_FREE; + voice->num = i; + voice->linked_voice = NULL; + voice++; + } + + return; +} + +static void __devinit timer_init(struct emu10k1_card *card) +{ + INIT_LIST_HEAD(&card->timers); + card->timer_delay = TIMER_STOPPED; + card->timer_lock = SPIN_LOCK_UNLOCKED; + + return; +} + +static void __devinit addxmgr_init(struct emu10k1_card *card) +{ + u32 count; + + for (count = 0; count < MAXPAGES; count++) + card->emupagetable[count] = 0; + + /* Mark first page as used */ + /* This page is reserved by the driver */ + card->emupagetable[0] = 0x8001; + card->emupagetable[1] = MAXPAGES - RESERVED - 1; + + return; +} + +static void __devinit fx_init(struct emu10k1_card *card) +{ + int i, j, k, l; + u32 pc = 0; + + for (i = 0; i < 512; i++) + OP(6, 0x40, 0x40, 0x40, 0x40); + + for (i = 0; i < 256; i++) + sblive_writeptr(card, FXGPREGBASE + i, 0, 0); + + pc = 0; + + for (j = 0; j < 2; j++) { + + OP(4, 0x100, 0x40, j, 0x44); + OP(4, 0x101, 0x40, j + 2, 0x44); + + for (i = 0; i < 6; i++) { + k = i * 16 + j; + OP(0, 0x102, 0x40, 0x110 + k, 0x100); + OP(0, 0x102, 0x102, 0x112 + k, 0x101); + OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j); + OP(0, 0x102, 0x102, 0x116 + k, 0x12 + j); + OP(0, 0x102, 0x102, 0x118 + k, 0x14 + j); + OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j); + OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j); + OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j); + + k = 0x190 + i * 8 + j * 4; + OP(0, 0x40, 0x40, 0x102, 0x170 + j); + OP(7, k + 1, k, k + 1, 0x174 + j); + OP(7, k, 0x102, k, 0x172 + j); + OP(7, k + 3, k + 2, k + 3, 0x178 + j); + OP(0, k + 2, 0x56, k + 2, 0x176 + j); + OP(6, k + 2, k + 2, k + 2, 0x40); + + l = 0x1c0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, k + 2, 0x180 + j); + OP(7, l + 1, l, l + 1, 0x184 + j); + OP(7, l, k + 2, l, 0x182 + j); + OP(7, l + 3, l + 2, l + 3, 0x188 + j); + OP(0, l + 2, 0x56, l + 2, 0x186 + j); + OP(4, l + 2, 0x40, l + 2, 0x46); + + OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); + + } + } + sblive_writeptr(card, DBG, 0, 0); + + return; +} + +static int __devinit hw_init(struct emu10k1_card *card) +{ + int nCh; + +#ifdef TANKMEM + u32 size = 0; +#endif + u32 sizeIdx = 0; + u32 pagecount, tmp; + + /* Disable audio and lock cache */ + sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + + /* Reset recording buffers */ + sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, MICBA, 0, 0); + sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, FXBA, 0, 0); + sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, ADCBA, 0, 0); + + /* Disable channel interrupt */ + sblive_writefn0(card, INTE, DISABLE); + sblive_writeptr(card, CLIEL, 0, 0); + sblive_writeptr(card, CLIEH, 0, 0); + sblive_writeptr(card, SOLEL, 0, 0); + sblive_writeptr(card, SOLEH, 0, 0); + + /* Init envelope engine */ + for (nCh = 0; nCh < NUM_G; nCh++) { + sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF); + sblive_writeptr(card, IP, nCh, 0); + sblive_writeptr(card, VTFT, nCh, 0xffff); + sblive_writeptr(card, CVCF, nCh, 0xffff); + sblive_writeptr(card, PTRX, nCh, 0); + sblive_writeptr(card, CPF, nCh, 0); + sblive_writeptr(card, CCR, nCh, 0); + + sblive_writeptr(card, PSST, nCh, 0); + sblive_writeptr(card, DSL, nCh, 0x10); + sblive_writeptr(card, CCCA, nCh, 0); + sblive_writeptr(card, Z1, nCh, 0); + sblive_writeptr(card, Z2, nCh, 0); + sblive_writeptr(card, FXRT, nCh, 0xd01c0000); + + sblive_writeptr(card, ATKHLDM, nCh, 0); + sblive_writeptr(card, DCYSUSM, nCh, 0); + sblive_writeptr(card, IFATN, nCh, 0xffff); + sblive_writeptr(card, PEFE, nCh, 0); + sblive_writeptr(card, FMMOD, nCh, 0); + sblive_writeptr(card, TREMFRQ, nCh, 24); /* 1 Hz */ + sblive_writeptr(card, FM2FRQ2, nCh, 24); /* 1 Hz */ + sblive_writeptr(card, TEMPENV, nCh, 0); + + /*** These are last so OFF prevents writing ***/ + sblive_writeptr(card, LFOVAL2, nCh, 0); + sblive_writeptr(card, LFOVAL1, nCh, 0); + sblive_writeptr(card, ATKHLDV, nCh, 0); + sblive_writeptr(card, ENVVOL, nCh, 0); + sblive_writeptr(card, ENVVAL, nCh, 0); + } + + /* + ** Init to 0x02109204 : + ** Clock accuracy = 0 (1000ppm) + ** Sample Rate = 2 (48kHz) + ** Audio Channel = 1 (Left of 2) + ** Source Number = 0 (Unspecified) + ** Generation Status = 1 (Original for Cat Code 12) + ** Cat Code = 12 (Digital Signal Mixer) + ** Mode = 0 (Mode 0) + ** Emphasis = 0 (None) + ** CP = 1 (Copyright unasserted) + ** AN = 0 (Digital audio) + ** P = 0 (Consumer) + */ + + /* SPDIF0 */ + sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + /* SPDIF1 */ + sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + /* SPDIF2 & SPDIF3 */ + sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + fx_init(card); /* initialize effects engine */ + + card->tankmem = NULL; + +#ifdef TANKMEM + size = TMEMSIZE; + sizeIdx = TMEMSIZEREG; + while (size > 16384) { + if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL) + break; + + size /= 2; + sizeIdx -= 1; + } + + if (card->tankmem == NULL) { + card->tmemsize = 0; + return CTSTATUS_ERROR; + } + + card->tmemsize = size; +#else /* !TANKMEM */ + card->tmemsize = 0; +#endif /* TANKMEM */ + + if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) { + ERROR(); + emu10k1_free_memphysical(card->tankmem); + return CTSTATUS_ERROR; + } + + if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) { + ERROR(); + emu10k1_free_memphysical(card->tankmem); + emu10k1_free_memphysical(card->virtualpagetable); + return CTSTATUS_ERROR; + } else + memset(card->silentpage->virtaddx, 0, EMUPAGESIZE); + + for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++) + + ((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount; + + /* Init page table & tank memory base register */ + sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx); +#ifdef TANKMEM + sblive_writeptr(card, TCB, 0, card->tankmem->busaddx); +#else + sblive_writeptr(card, TCB, 0, 0); +#endif + sblive_writeptr(card, TCBS, 0, sizeIdx); + + for (nCh = 0; nCh < NUM_G; nCh++) { + sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + } + + /* Hokay, now enable the AUD bit */ + /* Enable Audio = 1 */ + /* Mute Disable Audio = 0 */ + /* Lock Tank Memory = 1 */ + /* Lock Sound Memory = 0 */ + /* Auto Mute = 1 */ + + sblive_rmwac97(card, AC97_MASTERVOLUME, 0x8000, 0x8000); + + sblive_writeac97(card, AC97_MASTERVOLUME, 0); + sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + + sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE); + + /* TOSLink detection */ + card->has_toslink = 0; + + tmp = sblive_readfn0(card, HCFG); + if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { + sblive_writefn0(card, HCFG, tmp | 0x800); + + udelay(512); + + if (tmp != (sblive_readfn0(card, HCFG) & ~0x800)) { + card->has_toslink = 1; + sblive_writefn0(card, HCFG, tmp); + } + } + + return CTSTATUS_SUCCESS; +} + +static int __devinit emu10k1_init(struct emu10k1_card *card) +{ + /* Init Card */ + if (hw_init(card) != CTSTATUS_SUCCESS) + return CTSTATUS_ERROR; + + voice_init(card); + timer_init(card); + addxmgr_init(card); + + DPD(2, " hw control register -> %x\n", sblive_readfn0(card, HCFG)); + + return CTSTATUS_SUCCESS; +} + +static void __devexit audio_exit(struct emu10k1_card *card) +{ + kfree(card->waveout); + kfree(card->wavein); + return; +} + +static void __devexit midi_exit(struct emu10k1_card *card) +{ + tasklet_unlock_wait(&card->mpuout->tasklet); + kfree(card->mpuout); + + tasklet_unlock_wait(&card->mpuin->tasklet); + kfree(card->mpuin); + + return; +} + +static void __devexit emu10k1_exit(struct emu10k1_card *card) +{ + int ch; + + sblive_writefn0(card, INTE, DISABLE); + + /** Shutdown the chip **/ + for (ch = 0; ch < NUM_G; ch++) + sblive_writeptr(card, DCYSUSV, ch, ENV_OFF); + + for (ch = 0; ch < NUM_G; ch++) { + sblive_writeptr(card, VTFT, ch, 0); + sblive_writeptr(card, CVCF, ch, 0); + sblive_writeptr(card, PTRX, ch, 0); + sblive_writeptr(card, CPF, ch, 0); + } + + /* Reset recording buffers */ + sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, MICBA, 0, 0); + sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, FXBA, 0, 0); + sblive_writeptr(card, FXWC, 0, 0); + sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, ADCBA, 0, 0); + sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K); + sblive_writeptr(card, TCB, 0, 0); + sblive_writeptr(card, DBG, 0, 0x8000); + + /* Disable channel interrupt */ + sblive_writeptr(card, CLIEL, 0, 0); + sblive_writeptr(card, CLIEH, 0, 0); + sblive_writeptr(card, SOLEL, 0, 0); + sblive_writeptr(card, SOLEH, 0, 0); + + /* Disable audio and lock cache */ + sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + sblive_writeptr(card, PTB, 0, 0); + + emu10k1_free_memphysical(card->silentpage); + emu10k1_free_memphysical(card->virtualpagetable); +#ifdef TANKMEM + emu10k1_free_memphysical(card->tankmem); +#endif + return; +} + +/* Driver initialization routine */ +static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +{ + struct emu10k1_card *card; + + if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "emu10k1: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(struct emu10k1_card)); + +#if LINUX_VERSION_CODE > 0x020320 + if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { + printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); + kfree(card); + return -ENODEV; + } + + if (pci_enable_device(pci_dev)) { + printk(KERN_ERR "emu10k1: couldn't enable device\n"); + kfree(card); + return -ENODEV; + } + + pci_set_master(pci_dev); + + card->iobase = pci_dev->resource[0].start; + + if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { + printk(KERN_ERR "emu10k1: IO space in use\n"); + kfree(card); + return -ENODEV; + } + pci_dev->driver_data = card; + pci_dev->dma_mask = EMU10K1_DMA_MASK; +#else + pci_set_master(pci_dev); + + card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + if (check_region(card->iobase, EMU10K1_EXTENT)) { + printk(KERN_ERR "emu10k1: IO space in use\n"); + kfree(card); + return -ENODEV; + } + + request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]); +#endif + card->irq = pci_dev->irq; + card->pci_dev = pci_dev; + + /* Reserve IRQ Line */ + if (request_irq(card->irq, emu10k1_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { + printk(KERN_ERR "emu10k1: IRQ in use\n"); + goto err_irq; + } + + pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); + + printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq); + + spin_lock_init(&card->lock); + card->mixeraddx = card->iobase + AC97DATA; + init_MUTEX(&card->open_sem); + card->open_mode = 0; + init_waitqueue_head(&card->open_wait); + + /* Register devices */ + if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); + goto err_dev0; + } + + if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); + goto err_dev1; + } + + if ((card->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register mixer device!\n"); + goto err_dev2; + } + + if ((card->midi_num = register_sound_midi(&emu10k1_midi_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register midi device!\n"); + goto err_dev3; + } + + if (emu10k1_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize device!\n"); + goto err_emu10k1_init; + } + + if (audio_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize audio!\n"); + goto err_audio_init; + } + + if (midi_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize midi!\n"); + goto err_midi_init; + } + + mixer_init(card); + + DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize); + + list_add(&card->list, &emu10k1_devs); + + return 0; + + err_midi_init: + audio_exit(card); + + err_audio_init: + emu10k1_exit(card); + + err_emu10k1_init: + unregister_sound_midi(card->midi_num); + + err_dev3: + unregister_sound_mixer(card->mixer_num); + + err_dev2: + unregister_sound_dsp(card->audio2_num); + + err_dev1: + unregister_sound_dsp(card->audio1_num); + + err_dev0: + free_irq(card->irq, card); + + err_irq: + release_region(card->iobase, EMU10K1_EXTENT); + kfree(card); + + return -ENODEV; +} + +static void __devexit emu10k1_remove(struct pci_dev *pci_dev) +{ +#if LINUX_VERSION_CODE > 0x020320 + struct emu10k1_card *card = pci_dev->driver_data; +#else + struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); +#endif + midi_exit(card); + audio_exit(card); + emu10k1_exit(card); + + unregister_sound_midi(card->midi_num); + unregister_sound_mixer(card->mixer_num); + unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); + + free_irq(card->irq, card); + release_region(card->iobase, EMU10K1_EXTENT); + + list_del(&card->list); + + kfree(card); + return; +} + +MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"); +MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd."); + +static struct pci_driver emu10k1_pci_driver __initdata = { + name:"emu10k1", + id_table:emu10k1_pci_tbl, + probe:emu10k1_probe, + remove:emu10k1_remove, +}; + +#if LINUX_VERSION_CODE > 0x020320 +static int __init emu10k1_init_module(void) +{ + printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + return pci_module_init(&emu10k1_pci_driver); +} + +static void __exit emu10k1_cleanup_module(void) +{ + pci_unregister_driver(&emu10k1_pci_driver); + return; +} + +#else + +static int __init emu10k1_init_module(void) +{ + struct pci_dev *dev = NULL; + const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table; + + printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + if (!pci_present()) + return -ENODEV; + + while (pci_id->vendor) { + while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev))) + emu10k1_probe(dev, pci_id); + + pci_id++; + } + return 0; +} + +static void __exit emu10k1_cleanup_module(void) +{ + struct emu10k1_card *card; + + while (!list_empty(&emu10k1_devs)) { + card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); + + emu10k1_remove(card->pci_dev); + } + + return; +} + +#endif + +module_init(emu10k1_init_module); +module_exit(emu10k1_cleanup_module); diff --git a/drivers/sound/emu10k1/midi.c b/drivers/sound/emu10k1/midi.c new file mode 100644 index 000000000000..497e48113116 --- /dev/null +++ b/drivers/sound/emu10k1/midi.c @@ -0,0 +1,446 @@ + +/* + ********************************************************************** + * midi.c - /dev/midi interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#define __NO_VERSION__ +#include +#include + +#include "hwaccess.h" +#include "cardmo.h" +#include "cardmi.h" +#include "midi.h" + +static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED; + +static void init_midi_hdr(struct midi_hdr *midihdr) +{ + midihdr->bufferlength = MIDIIN_BUFLEN; + midihdr->bytesrecorded = 0; + midihdr->flags = 0; +} + +static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr) +{ + struct midi_hdr *midihdr; + + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) { + ERROR(); + return -EINVAL; + } + + init_midi_hdr(midihdr); + + if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) { + ERROR(); + kfree(midihdr); + return CTSTATUS_ERROR; + } + + if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midihdr->data); + kfree(midihdr); + return CTSTATUS_ERROR; + } + + *midihdrptr = midihdr; + list_add_tail(&midihdr->list, &midi_dev->mid_hdrs); + + return CTSTATUS_SUCCESS; +} + +static int emu10k1_midi_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct emu10k1_mididevice *midi_dev; + struct list_head *entry; + + DPF(2, "emu10k1_midi_open()\n"); + + /* Check for correct device to open */ + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->midi_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + /* Wait for device to become free */ + down(&card->open_sem); + while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { + if (file->f_flags & O_NONBLOCK) { + up(&card->open_sem); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + up(&card->open_sem); + interruptible_sleep_on(&card->open_wait); + + if (signal_pending(current)) { + MOD_DEC_USE_COUNT; + return -ERESTARTSYS; + } + + down(&card->open_sem); + } + + if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + + midi_dev->card = card; + midi_dev->mistate = MIDIIN_STATE_STOPPED; + init_waitqueue_head(&midi_dev->oWait); + init_waitqueue_head(&midi_dev->iWait); + midi_dev->ird = 0; + midi_dev->iwr = 0; + midi_dev->icnt = 0; + INIT_LIST_HEAD(&midi_dev->mid_hdrs); + + if (file->f_mode & FMODE_READ) { + struct midi_openinfo dsCardMidiOpenInfo; + struct midi_hdr *midihdr1; + struct midi_hdr *midihdr2; + + dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; + + if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) + != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + /* Add two buffers to receive sysex buffer */ + if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) { + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) { + list_del(&midihdr1->list); + kfree(midihdr1->data); + kfree(midihdr1); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + } + + if (file->f_mode & FMODE_WRITE) { + struct midi_openinfo dsCardMidiOpenInfo; + + dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; + + if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) + != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + } + + file->private_data = (void *) midi_dev; + + card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); + + up(&card->open_sem); + + return 0; +} + +static int emu10k1_midi_release(struct inode *inode, struct file *file) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + struct emu10k1_card *card = midi_dev->card; + + DPF(2, "emu10k1_midi_release()\n"); + + if (file->f_mode & FMODE_WRITE) { + if (!(file->f_flags & O_NONBLOCK)) { + + while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) { + DPF(4, "Cannot close - buffers not empty\n"); + + interruptible_sleep_on(&midi_dev->oWait); + + } + } + + emu10k1_mpuout_close(card); + } + + if (file->f_mode & FMODE_READ) { + struct midi_hdr *midihdr; + + if (midi_dev->mistate == MIDIIN_STATE_STARTED) { + emu10k1_mpuin_stop(card); + midi_dev->mistate = MIDIIN_STATE_STOPPED; + } + + emu10k1_mpuin_reset(card); + emu10k1_mpuin_close(card); + + while (!list_empty(&midi_dev->mid_hdrs)) { + midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list); + + list_del(midi_dev->mid_hdrs.next); + kfree(midihdr->data); + kfree(midihdr); + } + } + + kfree(midi_dev); + + down(&card->open_sem); + card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE)); + up(&card->open_sem); + wake_up_interruptible(&card->open_wait); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t * pos) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + ssize_t ret = 0; + u16 cnt; + unsigned long flags; + + DPD(4, "emu10k1_midi_read(), count %x\n", (u32) count); + + if (pos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + + if (midi_dev->mistate == MIDIIN_STATE_STOPPED) { + if (emu10k1_mpuin_start(midi_dev->card) + != CTSTATUS_SUCCESS) { + ERROR(); + return -EINVAL; + } + + midi_dev->mistate = MIDIIN_STATE_STARTED; + } + + while (count > 0) { + cnt = MIDIIN_BUFLEN - midi_dev->ird; + + spin_lock_irqsave(&midi_spinlock, flags); + + if (midi_dev->icnt < cnt) + cnt = midi_dev->icnt; + + spin_unlock_irqrestore(&midi_spinlock, flags); + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + DPF(2, " Go to sleep...\n"); + + interruptible_sleep_on(&midi_dev->iWait); + + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + + continue; + } + + if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) { + ERROR(); + return ret ? ret : -EFAULT; + } + + midi_dev->ird += cnt; + midi_dev->ird %= MIDIIN_BUFLEN; + + spin_lock_irqsave(&midi_spinlock, flags); + + midi_dev->icnt -= cnt; + + spin_unlock_irqrestore(&midi_spinlock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if (midi_dev->icnt == 0) + break; + } + + return ret; +} + +static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t * pos) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + struct midi_hdr *midihdr; + ssize_t ret = 0; + unsigned long flags; + + DPD(4, "emu10k1_midi_write(), count=%x\n", (u32) count); + + if (pos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) + return -EINVAL; + + midihdr->bufferlength = count; + midihdr->bytesrecorded = 0; + midihdr->flags = 0; + + if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) { + ERROR(); + kfree(midihdr); + return -EINVAL; + } + + if (copy_from_user(midihdr->data, buffer, count)) { + kfree(midihdr->data); + kfree(midihdr); + return ret ? ret : -EFAULT; + } + + spin_lock_irqsave(&midi_spinlock, flags); + + if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midihdr->data); + kfree(midihdr); + spin_unlock_irqrestore(&midi_spinlock, flags); + return -EINVAL; + } + + spin_unlock_irqrestore(&midi_spinlock, flags); + + return count; +} + +static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait) +{ + DPF(4, "emu10k1_midi_poll() called\n"); + return 0; +} + +int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata; + struct midi_hdr *midihdr = NULL; + unsigned long flags; + int i; + + DPF(4, "emu10k1_midi_callback()\n"); + + spin_lock_irqsave(&midi_spinlock, flags); + + switch (msg) { + case ICARDMIDI_OUTLONGDATA: + midihdr = (struct midi_hdr *) pmsg[2]; + + kfree(midihdr->data); + kfree(midihdr); + wake_up_interruptible(&midi_dev->oWait); + + break; + + case ICARDMIDI_INLONGDATA: + midihdr = (struct midi_hdr *) pmsg[2]; + + for (i = 0; i < midihdr->bytesrecorded; i++) { + midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i]; + midi_dev->iwr %= MIDIIN_BUFLEN; + } + + midi_dev->icnt += midihdr->bytesrecorded; + + if (midi_dev->mistate == MIDIIN_STATE_STARTED) { + init_midi_hdr(midihdr); + emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr); + wake_up_interruptible(&midi_dev->iWait); + } + break; + + case ICARDMIDI_INDATA: + { + u8 *pBuf = (u8 *) & pmsg[1]; + u16 bytesvalid = pmsg[2]; + + for (i = 0; i < bytesvalid; i++) { + midi_dev->iBuf[midi_dev->iwr++] = pBuf[i]; + midi_dev->iwr %= MIDIIN_BUFLEN; + } + + midi_dev->icnt += bytesvalid; + } + + wake_up_interruptible(&midi_dev->iWait); + break; + + default: /* Unknown message */ + return CTSTATUS_ERROR; + } + + spin_unlock_irqrestore(&midi_spinlock, flags); + + return CTSTATUS_SUCCESS; +} + +/* MIDI file operations */ +struct file_operations emu10k1_midi_fops = { + read:emu10k1_midi_read, + write:emu10k1_midi_write, + poll:emu10k1_midi_poll, + open:emu10k1_midi_open, + release:emu10k1_midi_release, +}; diff --git a/drivers/sound/emu10k1/midi.h b/drivers/sound/emu10k1/midi.h new file mode 100644 index 000000000000..360ca978f415 --- /dev/null +++ b/drivers/sound/emu10k1/midi.h @@ -0,0 +1,55 @@ +/* + ********************************************************************** + * midi.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _MIDI_H +#define _MIDI_H + +#define FMODE_MIDI_SHIFT 3 +#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) +#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) + +#define MIDIIN_STATE_STARTED 0x00000001 +#define MIDIIN_STATE_STOPPED 0x00000002 + +#define MIDIIN_BUFLEN 1024 + +struct emu10k1_mididevice +{ + struct emu10k1_card *card; + u32 mistate; + wait_queue_head_t oWait; + wait_queue_head_t iWait; + s8 iBuf[MIDIIN_BUFLEN]; + u16 ird, iwr, icnt; + struct list_head mid_hdrs; +}; + +#endif /* _MIDI_H */ diff --git a/drivers/sound/emu10k1/mixer.c b/drivers/sound/emu10k1/mixer.c new file mode 100644 index 000000000000..fa54ca435f0a --- /dev/null +++ b/drivers/sound/emu10k1/mixer.c @@ -0,0 +1,824 @@ + +/* + ********************************************************************** + * mixer.c - /dev/mixer interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + * This program uses some code from es1371.c, Copyright 1998-1999 + * Thomas Sailer + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up stuff + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#define __NO_VERSION__ /* Kernel version only defined once */ +#include +#include + +#include "hwaccess.h" + +#define AC97_PESSIMISTIC +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +#define vol_to_hw_5(swvol) (31 - (((swvol) * 31) / 100)) +#define vol_to_hw_4(swvol) (15 - (((swvol) * 15) / 100)) + +#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31) +#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15) + +#ifdef PRIVATE_PCM_VOLUME +struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS]; +#endif + +/* --------------------------------------------------------------------- */ + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#ifdef hweight32 +#undef hweight32 +#endif + +extern __inline__ unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +/* Mapping arrays */ +static const unsigned int recsrc[] = { + SOUND_MASK_MIC, + SOUND_MASK_CD, + SOUND_MASK_VIDEO, + SOUND_MASK_LINE1, + SOUND_MASK_LINE, + SOUND_MASK_VOLUME, + SOUND_MASK_OGAIN, /* Used to be PHONEOUT */ + SOUND_MASK_PHONEIN, + SOUND_MASK_TREBLE, + SOUND_MASK_BASS, + SOUND_MASK_MONITOR, + SOUND_MASK_PCM, +}; + +static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = AC97_LINEINVOLUME, + [SOUND_MIXER_CD] = AC97_CDVOLUME, + [SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME, + [SOUND_MIXER_LINE1] = AC97_AUXVOLUME, + +/* [SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME, */ + /* 5 bit stereo, setting 6th bit equal to maximum attenuation */ + +/* [SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME, */ + [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME, + /* 5 bit mono, setting 6th bit equal to maximum attenuation */ + [SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO, + /* 5 bit mono */ + [SOUND_MIXER_PHONEIN] = AC97_PHONEVOLUME, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = AC97_PCBEEPVOLUME, + /* 5 bit mono, 7th bit = preamp */ + [SOUND_MIXER_MIC] = AC97_MICVOLUME, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = AC97_RECORDGAIN, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC, + /* test code */ + [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE, + [SOUND_MIXER_TREBLE] = AC97_MASTERTONE, + [SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME, + [SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME +}; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) + +/* FIXME: mixer_rdch() is broken. */ + +static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg) +{ + u16 reg; + int j; + int nL, nR; + + switch (ch) { + case SOUND_MIXER_LINE: + case SOUND_MIXER_CD: + case SOUND_MIXER_VIDEO: + case SOUND_MIXER_LINE1: + case SOUND_MIXER_PCM: + case SOUND_MIXER_VOLUME: + sblive_readac97(card, volreg[ch], ®); + nL = ((~(reg >> 8) & 0x1f) * 100) / 32; + nR = (~(reg & 0x1f) * 100) / 32; + DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR); + return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); + + case SOUND_MIXER_OGAIN: + case SOUND_MIXER_PHONEIN: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg); + + case SOUND_MIXER_SPEAKER: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg); + + case SOUND_MIXER_MIC: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg); + + case SOUND_MIXER_RECLEV: + sblive_readac97(card, volreg[ch], ®); + nL = ((~(reg >> 8) & 0x1f) * 100) / 16; + nR = (~(reg & 0x1f) * 100) / 16; + return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); + + case SOUND_MIXER_TREBLE: + case SOUND_MIXER_BASS: + return put_user(0x0000, (int *) arg); + default: + return -EINVAL; + } +} + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = { + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = 1, + [SOUND_MIXER_CD] = 2, + [SOUND_MIXER_VIDEO] = 3, + [SOUND_MIXER_LINE1] = 4, + [SOUND_MIXER_PCM] = 5, + /* 6 bit stereo */ + [SOUND_MIXER_VOLUME] = 6, + [SOUND_MIXER_PHONEOUT] = 7, + /* 6 bit mono */ + [SOUND_MIXER_OGAIN] = 8, + [SOUND_MIXER_PHONEIN] = 9, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = 10, + /* 6 bit mono + preamp */ + [SOUND_MIXER_MIC] = 11, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = 12, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = 13, + [SOUND_MIXER_TREBLE] = 14, + [SOUND_MIXER_BASS] = 15, + [SOUND_MIXER_LINE2] = 16, + [SOUND_MIXER_LINE3] = 17, + [SOUND_MIXER_DIGITAL1] = 18, + [SOUND_MIXER_DIGITAL2] = 19 +}; + +u32 bass_table[41][5] = { + { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, + { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, + { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee }, + { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c }, + { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b }, + { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 }, + { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f }, + { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 }, + { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 }, + { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 }, + { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 }, + { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be }, + { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b }, + { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c }, + { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b }, + { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 }, + { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a }, + { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 }, + { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 }, + { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e }, + { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee }, + { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 }, + { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 }, + { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 }, + { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 }, + { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e }, + { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 }, + { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 }, + { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 }, + { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 }, + { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 }, + { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca }, + { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 }, + { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 }, + { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 }, + { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 }, + { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a }, + { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f }, + { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 }, + { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 }, + { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 } +}; + +u32 treble_table[41][5] = { + { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 }, + { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 }, + { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 }, + { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca }, + { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 }, + { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 }, + { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 }, + { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 }, + { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 }, + { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df }, + { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff }, + { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 }, + { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c }, + { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 }, + { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 }, + { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 }, + { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 }, + { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d }, + { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 }, + { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 }, + { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f }, + { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb }, + { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 }, + { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 }, + { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd }, + { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 }, + { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad }, + { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 }, + { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 }, + { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c }, + { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 }, + { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 }, + { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 }, + { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 }, + { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 }, + { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 }, + { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d }, + { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b }, + { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 }, + { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd }, + { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } +}; + +static void set_bass(struct emu10k1_card *card, int l, int r) +{ + int i; + + l = (l * 40 + 50) / 100; + r = (r * 40 + 50) / 100; + for (i = 0; i < 5; i++) { + sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]); + } +} + +static void set_treble(struct emu10k1_card *card, int l, int r) +{ + int i; + + l = (l * 40 + 50) / 100; + r = (r * 40 + 50) / 100; + for (i = 0; i < 5; i++) { + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]); + } +} + +u32 db_table[101] = { + 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, + 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, + 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1, + 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0, + 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9, + 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb, + 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005, + 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d, + 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd, + 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8, + 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481, + 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333, + 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d, + 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6, + 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d, + 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf, + 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038, + 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a, + 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea, + 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272, + 0x7fffffff, +}; + +static void update_digital(struct emu10k1_card *card) +{ + int i, k, l1, r1, l2, r2, l3, r3, l4, r4; + u64 j; + + i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]]; + l1 = (i & 0xff); + r1 = ((i >> 8) & 0xff); + i = card->arrwVol[volidx[SOUND_MIXER_LINE3]]; + l2 = i & 0xff; + r2 = (i >> 8) & 0xff; + + i = card->arrwVol[volidx[SOUND_MIXER_PCM]]; + l3 = i & 0xff; + r3 = (i >> 8) & 0xff; + + i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]]; + l4 = i & 0xff; + r4 = (i >> 8) & 0xff; + + i = (r1 * r2) / 50; + if (r2 > 50) + r2 = 2 * r1 - i; + else { + r2 = r1; + r1 = i; + } + + i = (l1 * l2) / 50; + if (l2 > 50) + l2 = 2 * l1 - i; + else { + l2 = l1; + l1 = i; + } + + for (i = 0; i < 16; i++) { + if (card->digmix[i] != 0x80000000) { + if ((i >= 0) && (i < 4)) + j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]); + else if ((i == 6) || (i == 7)) + j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]); + else + j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31; + card->digmix[i] = j >> 31; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } + + for (i = 64; i < 80; i++) { + if (card->digmix[i] != 0x80000000) { + if ((i >= 64) && (i < 68)) + j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]); + else if ((i == 70) || (i == 71)) + j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]); + else + j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31; + card->digmix[i] = j >> 31; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } + + for (i = 16; i <= 80; i += 16) { + if (i != 64) { + for (k = 0; k < 4; k++) + if (card->digmix[i + k] != 0x80000000) { + card->digmix[i + k] = db_table[l3]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]); + } + if (card->digmix[i + 6] != 0x80000000) { + card->digmix[i + 6] = db_table[l4]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]); + } + if (card->digmix[i + 7] != 0x80000000) { + card->digmix[i + 7] = db_table[r4]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]); + } + } + } + +} + +#ifdef PRIVATE_PCM_VOLUME + +/* calc & set attenuation factor for given channel */ +static int set_pcm_attn(struct emu10k1_card *card, int ch, int l) +{ +#ifndef PCMLEVEL +#define PCMLEVEL 140 // almost silence +#endif + int vol = IFATN_ATTENUATION_MASK; // silence + + if (l > 0) + vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100); + sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol); + DPD(2, "SOUND_MIXER_PCM: channel:%d level:%d attn:%d\n", ch, l, vol); + + return vol; +#undef PCMLEVEL +} + +/* update value of local PCM volume level (using channel attenuation) + * + * return 1: in case its local change + * 0: if the current process doesn't have entry in table + * (it means this process have not opened audio (mixer usually) + */ +static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1) +{ + int i; + int mixer = (r1 << 8) | l1; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].mixer = mixer; + if (sblive_pcm_volume[i].opened) { + if (sblive_pcm_volume[i].channel_r < NUM_G) { + if (sblive_pcm_volume[i].channel_l < NUM_G) + sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1); + sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); + } else { + // mono voice + if (sblive_pcm_volume[i].channel_l < NUM_G) + sblive_pcm_volume[i].attn_l = + set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1); + // to correctly handle mono voice here we would need + // to go into stereo mode and move the voice to the right & left + // looks a bit overcomlicated... + } + + } + return 1; + } + } + if (i == MAX_PCM_CHANNELS) + card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; + + return 0; +} +#endif + +int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) +{ + int i; + unsigned l1, r1; + u16 wval; + + l1 = val & 0xff; + r1 = (val >> 8) & 0xff; + if (l1 > 100) + l1 = 100; + if (r1 > 100) + r1 = 100; + + DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1); + + if (!volidx[ch]) + return -EINVAL; +#ifdef PRIVATE_PCM_VOLUME + if (ch != SOUND_MIXER_PCM) +#endif + card->arrwVol[volidx[ch]] = (r1 << 8) | l1; + + switch (ch) { + case SOUND_MIXER_VOLUME: + case SOUND_MIXER_DIGITAL1: + case SOUND_MIXER_LINE3: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); + update_digital(card); + return 0; + case SOUND_MIXER_PCM: + DPF(4, "SOUND_MIXER_PCM\n"); +#ifdef PRIVATE_PCM_VOLUME + if (update_pcm_attn(card, l1, r1)) + return 0; +#endif + update_digital(card); + return 0; + case SOUND_MIXER_DIGITAL2: + case SOUND_MIXER_LINE2: + case SOUND_MIXER_LINE1: + case SOUND_MIXER_LINE: + case SOUND_MIXER_CD: + DPD(4, "SOUND_MIXER_%s:\n", + (ch == SOUND_MIXER_LINE1) ? "LINE1" : + (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD"); + wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100); + if (wval == 0x2020) + wval = 0x8000; + else + wval -= ((wval & 0x2020) / 0x20); + sblive_writeac97(card, volreg[ch], wval); + return 0; + + case SOUND_MIXER_OGAIN: + case SOUND_MIXER_PHONEIN: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN"); + sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100); + return 0; + + case SOUND_MIXER_SPEAKER: + DPF(4, "SOUND_MIXER_SPEAKER:\n"); + sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1); + return 0; + + case SOUND_MIXER_MIC: + DPF(4, "SOUND_MIXER_MIC:\n"); + i = 0; + if (l1 >= 30) + // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 + { + l1 -= 30; + i = 0x40; + } + sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i)); + return 0; + + case SOUND_MIXER_RECLEV: + DPF(4, "SOUND_MIXER_RECLEV:\n"); + + wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100); + if (wval == 0) + wval = 0x8000; + else { + if (wval & 0xff) + wval--; + if (wval & 0xff00) + wval -= 0x0100; + } + sblive_writeac97(card, volreg[ch], wval); + return 0; + + case SOUND_MIXER_TREBLE: + DPF(4, "SOUND_MIXER_TREBLE:\n"); + set_treble(card, l1, r1); + return 0; + + case SOUND_MIXER_BASS: + DPF(4, "SOUND_MIXER_BASS:\n"); + set_bass(card, l1, r1); + return 0; + + default: + DPF(2, "Got unknown SOUND_MIXER ioctl\n"); + return -EINVAL; + } +} + +static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin) +{ + DPF(2, "sblive_mixer_llseek() called\n"); + return -ESPIPE; +} + +/* Mixer file operations */ + +/* FIXME: Do we need spinlocks in here? */ +static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + static const char id[] = "SBLive"; + static const char name[] = "Creative SBLive"; + int i, val; + struct emu10k1_card *card = (struct emu10k1_card *) file->private_data; + u16 reg; + + switch (cmd) { + + case SOUND_MIXER_INFO:{ + mixer_info info; + + DPF(4, "SOUND_MIXER_INFO\n"); + + strncpy(info.id, id, sizeof(info.id)); + strncpy(info.name, name, sizeof(info.name)); + + info.modify_counter = card->modcnt; + if (copy_to_user((void *) arg, &info, sizeof(info))) + return -EFAULT; + + return 0; + } + break; + case SOUND_OLD_MIXER_INFO:{ + _old_mixer_info info; + + DPF(4, "SOUND_OLD_MIXER_INFO\n"); + + strncpy(info.id, id, sizeof(info.id)); + strncpy(info.name, name, sizeof(info.name)); + + if (copy_to_user((void *) arg, &info, sizeof(info))) + return -EFAULT; + + return 0; + } + break; + + case OSS_GETVERSION: + DPF(4, "OSS_GETVERSION\n"); + return put_user(SOUND_VERSION, (int *) arg); + break; + + case SOUND_MIXER_PRIVATE1: + DPF(4, "SOUND_MIXER_PRIVATE1"); + + if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix))) + return -EFAULT; + + return 0; + + break; + case SOUND_MIXER_PRIVATE2: + DPF(4, "SOUND_MIXER_PRIVATE2"); + + if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix))) + return -EFAULT; + + for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++) + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]); + return 0; + + break; + + default: + break; + } + + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_READ_RECSRC\n"); + sblive_readac97(card, AC97_RECORDSELECT, ®); + return put_user(recsrc[reg & 7], (int *) arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + DPF(2, "SOUND_MIXER_READ_RECMASK\n"); + return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | + SOUND_MASK_LINE1 | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | + SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | + SOUND_MASK_PCM, (int *) arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_LINE2, (int *) arg); + + case SOUND_MIXER_CAPS: + DPF(2, "SOUND_MIXER_READ_CAPS\n"); + return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); + +#ifdef PRIVATE_PCM_VOLUME + case SOUND_MIXER_PCM: + // needs to be before default: !! + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); + } + } + } +#endif + default: + i = _IOC_NR(cmd); + DPD(4, "SOUND_MIXER_READ(%d)\n", i); + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return mixer_rdch(card, i, (int *) arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(card->arrwVol[volidx[i]], (int *) arg); + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } + } + /* End of _IOC_READ */ + if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) + return -EINVAL; + + /* _IOC_WRITE */ + card->modcnt++; + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_WRITE_RECSRC\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + i = hweight32(val); + if (i == 0) + return 0; /*val = mixer_recmask(s); */ + else if (i > 1) { + sblive_readac97(card, AC97_RECORDSELECT, ®); + val &= ~recsrc[reg & 7]; + } + + for (i = 0; i < 8; i++) { + if (val & recsrc[i]) { + DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i); + sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i); + return 0; + } + } + return 0; + + default: + i = _IOC_NR(cmd); + DPD(4, "SOUND_MIXER_WRITE(%d)\n", i); + + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; + get_user_ret(val, (int *) arg, -EFAULT); + if (emu10k1_mixer_wrch(card, i, val)) + return -EINVAL; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return mixer_rdch(card, i, (int *) arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + return put_user(card->arrwVol[volidx[i]], (int *) arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + + } +} + +static int emu10k1_mixer_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct list_head *entry; + + DPF(4, "emu10k1_mixer_open()\n"); + + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->mixer_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + file->private_data = card; + return 0; +} + +static int emu10k1_mixer_release(struct inode *inode, struct file *file) +{ + DPF(3, "emu10k1_mixer_release()\n"); + MOD_DEC_USE_COUNT; + return 0; +} + +struct file_operations emu10k1_mixer_fops = { + llseek:emu10k1_mixer_llseek, + ioctl:emu10k1_mixer_ioctl, + open:emu10k1_mixer_open, + release:emu10k1_mixer_release, +}; diff --git a/drivers/sound/emu10k1/osutils.c b/drivers/sound/emu10k1/osutils.c new file mode 100644 index 000000000000..c0f5f63ac60a --- /dev/null +++ b/drivers/sound/emu10k1/osutils.c @@ -0,0 +1,91 @@ + +/* + ********************************************************************** + * osutils.c - OS Services layer for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +struct memhandle *emu10k1_alloc_memphysical(u32 size) +{ + struct memhandle *handle; + u32 reqpage, order; + + if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL) + return handle; + + DPD(3, "kmalloc: [%p]\n", handle); + + order = 0; + reqpage = size / PAGE_SIZE; + + if (size % PAGE_SIZE) + reqpage++; + + if (reqpage != 0) { + reqpage--; + while (reqpage > 0) { + reqpage >>= 1; + order++; + } + } + + if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) { + kfree(handle); + + DPD(3, "kfree: [%p]\n", handle); + return (void *) NULL; + } + + /* in linux, we can directly access physical address, don't need to do + * phys_to_virt. + * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages + * returns physical address. But in kernel 2.2.1 upwards, + * get_free_pages returns virtual address, we need to convert it + * to physical address. Then this physical address can be used to + * program hardware registers. */ + handle->busaddx = virt_to_bus(handle->virtaddx); + handle->order = order; + + DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx); + + return handle; +} + +void emu10k1_free_memphysical(struct memhandle *handle) +{ + free_pages((unsigned long) handle->virtaddx, handle->order); + kfree(handle); + + DPD(3, "free_pages: [%p]\n", handle->virtaddx); + DPD(3, "kfree: [%p]\n", handle); + + return; +} diff --git a/drivers/sound/emu10k1/recmgr.c b/drivers/sound/emu10k1/recmgr.c new file mode 100644 index 000000000000..18980ce4e6cd --- /dev/null +++ b/drivers/sound/emu10k1/recmgr.c @@ -0,0 +1,139 @@ + +/* + ********************************************************************** + * recmgr.c -- Recording manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "recmgr.h" + +void emu10k1_start_record(struct record *rec_ptr) +{ + struct emu10k1_card *hw_ptr = rec_ptr->card; + + DPF(2, "emu10k1_start_record()\n"); + DPD(2, "bus addx: %lx\n", rec_ptr->busaddx); + + sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx); + sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize); + + if (rec_ptr->adcctl) + sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl); + + return; +} + +void emu10k1_stop_record(struct record *rec_ptr) +{ + struct emu10k1_card *hw_ptr = rec_ptr->card; + + DPF(2, "emu10k1_stop_record()\n"); + + /* Disable record transfer */ + if (rec_ptr->adcctl) + sblive_writeptr(hw_ptr, ADCCR, 0, 0); + + sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE); + + return; +} + +void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc) +{ + DPF(2, "emu10k1_set_record_src()\n"); + + switch (recsrc) { + + case WAVERECORD_AC97: + DPF(2, "recording source: AC97\n"); + rec_ptr->bufsizereg = ADCBS; + rec_ptr->bufaddrreg = ADCBA; + rec_ptr->bufidxreg = ADCIDX_IDX; + + switch (rec_ptr->samplingrate) { + case 0xBB80: + rec_ptr->adcctl = ADCCR_SAMPLERATE_48; + break; + case 0xAC44: + rec_ptr->adcctl = ADCCR_SAMPLERATE_44; + break; + case 0x7D00: + rec_ptr->adcctl = ADCCR_SAMPLERATE_32; + break; + case 0x5DC0: + rec_ptr->adcctl = ADCCR_SAMPLERATE_24; + break; + case 0x5622: + rec_ptr->adcctl = ADCCR_SAMPLERATE_22; + break; + case 0x3E80: + rec_ptr->adcctl = ADCCR_SAMPLERATE_16; + break; + case 0x2B11: + rec_ptr->adcctl = ADCCR_SAMPLERATE_11; + break; + case 0x1F40: + rec_ptr->adcctl = ADCCR_SAMPLERATE_8; + break; + default: + break; + } + + rec_ptr->adcctl |= ADCCR_LCHANENABLE; + + if (rec_ptr->is_stereo) + rec_ptr->adcctl |= ADCCR_RCHANENABLE; + + // rec_ptr->fxwc = 0; + + break; + + case WAVERECORD_MIC: + DPF(2, "recording source: MIC\n"); + rec_ptr->bufsizereg = MICBS; + rec_ptr->bufaddrreg = MICBA; + rec_ptr->bufidxreg = MICIDX_IDX; + rec_ptr->adcctl = 0; + // rec_ptr->fxwc = 0; + break; + + case WAVERECORD_FX: + DPF(2, "recording source: FX\n"); + rec_ptr->bufsizereg = FXBS; + rec_ptr->bufaddrreg = FXBA; + rec_ptr->bufidxreg = FXIDX_IDX; + rec_ptr->adcctl = 0; + // rec_ptr->fxwc = 0x000ffff; + break; + default: + break; + } + + return; +} diff --git a/drivers/sound/emu10k1/recmgr.h b/drivers/sound/emu10k1/recmgr.h new file mode 100644 index 000000000000..1fbde606b696 --- /dev/null +++ b/drivers/sound/emu10k1/recmgr.h @@ -0,0 +1,62 @@ +/* + ********************************************************************** + * recmgr.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _RECORDMGR_H +#define _RECORDMGR_H + +struct record +{ + struct emu10k1_card *card; + u8 *recbuffer; + u32 recpos; + int is_stereo; + int is_16bit; + u32 recbufsize; + u32 bufsize; + u32 bufsizereg; + u32 bufaddrreg; + u32 bufidxreg; + u32 adcctl; + unsigned long busaddx; + u32 samplingrate; +}; + +/* Recording resources */ +#define WAVERECORD_AC97 0x01 +#define WAVERECORD_MIC 0x02 +#define WAVERECORD_FX 0x03 + +void emu10k1_start_record(struct record *); +void emu10k1_stop_record(struct record *); +void emu10k1_set_record_src(struct record *, u8); + + +#endif /* _RECORDMGR_H */ diff --git a/drivers/sound/emu10k1/timer.c b/drivers/sound/emu10k1/timer.c new file mode 100644 index 000000000000..1614b464d009 --- /dev/null +++ b/drivers/sound/emu10k1/timer.c @@ -0,0 +1,176 @@ + +/* + ********************************************************************** + * timer.c + * Copyright (C) 1999, 2000 Creative Labs, inc. + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +/* 3/6/2000 Improved support for different timer delays Rui Sousa */ + +/* 4/3/2000 Implemented timer list using list.h Rui Sousa */ + +#include "hwaccess.h" + +/* Try to schedule only once per fragment */ + +void emu10k1_timer_irqhandler(struct emu10k1_card *card) +{ + struct emu_timer *t; + struct list_head *entry; + + spin_lock(&card->timer_lock); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + if (t->active) { + t->count++; + if (t->count == t->count_max) { + t->count = 0; + tasklet_hi_schedule(&t->tasklet); + } + } + } + + spin_unlock(&card->timer_lock); + + return; +} + +struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay) +{ + struct emu_timer *timer; + struct emu_timer *t; + struct list_head *entry; + unsigned long flags; + + if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL) + return timer; + + if (delay < 5) + delay = 5; + + timer->delay = delay; + tasklet_init(&timer->tasklet, func, data); + timer->active = 0; + + spin_lock_irqsave(&card->timer_lock, flags); + + timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024); + timer->count = timer->count_max - 1; + + list_add(&timer->list, &card->timers); + + if (card->timer_delay > delay) { + if (card->timer_delay == TIMER_STOPPED) + emu10k1_irq_enable(card, INTE_INTERVALTIMERENB); + + card->timer_delay = delay; + delay = (delay < 1024 ? delay : 1024); + + WRITE_FN0(card, TIMER_RATE, delay); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + t->count_max = t->delay / delay; + /* don't want to think much, just force scheduling + on the next interrupt */ + t->count = t->count_max - 1; + } + + DPD(2, "timer rate --> %u\n", delay); + } + + spin_unlock_irqrestore(&card->timer_lock, flags); + + return timer; +} + +void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) +{ + struct emu_timer *t; + struct list_head *entry; + u32 delay = TIMER_STOPPED; + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + + list_del(&timer->list); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + if (t->delay < delay) + delay = t->delay; + } + + if (card->timer_delay != delay) { + card->timer_delay = delay; + + if (delay == TIMER_STOPPED) + emu10k1_irq_disable(card, INTE_INTERVALTIMERENB); + else { + delay = (delay < 1024 ? delay : 1024); + + WRITE_FN0(card, TIMER_RATE, delay); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + t->count_max = t->delay / delay; + t->count = t->count_max - 1; + } + } + + DPD(2, "timer rate --> %u\n", delay); + } + + spin_unlock_irqrestore(&card->timer_lock, flags); + + tasklet_unlock_wait(&timer->tasklet); + kfree(timer); + + return; +} + +void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer) +{ + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + timer->active = 1; + spin_unlock_irqrestore(&card->timer_lock, flags); + + return; +} + +void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer) +{ + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + timer->active = 0; + spin_unlock_irqrestore(&card->timer_lock, flags); + + return; +} diff --git a/drivers/sound/emu10k1/timer.h b/drivers/sound/emu10k1/timer.h new file mode 100644 index 000000000000..39e1ee2c9987 --- /dev/null +++ b/drivers/sound/emu10k1/timer.h @@ -0,0 +1,47 @@ +/* + ********************************************************************** + * timer.h + * Copyright (C) 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + + +#ifndef _TIMER_H +#define _TIMER_H + +struct emu_timer +{ + struct list_head list; + struct tasklet_struct tasklet; + int active; + u32 count; /* current number of interrupts */ + u32 count_max; /* number of interrupts needed to schedule the bh */ + u32 delay; /* timer delay */ +}; + +struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32); +void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *); +void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *); +void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *); + +#define TIMER_STOPPED 0xffffffff + +#endif /* _TIMER_H */ diff --git a/drivers/sound/emu10k1/voicemgr.c b/drivers/sound/emu10k1/voicemgr.c new file mode 100644 index 000000000000..de94a453ecfe --- /dev/null +++ b/drivers/sound/emu10k1/voicemgr.c @@ -0,0 +1,349 @@ + +/* + ********************************************************************** + * voicemgr.c - Voice manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc) +{ + struct emu10k1_card *card = voicemgr->card; + struct emu_voice *voice_tmp = voicemgr->voice; + struct emu_voice *voice = NULL; + int i; + unsigned long flags; + + DPF(2, "emu10k1_voice_alloc()\n"); + + spin_lock_irqsave(&voicemgr->lock, flags); + + if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) { + for (i = 0; i < NUM_G; i++) + if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) { + voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; + voice_tmp[i].usage = voiceallocdesc->usage; + voice = &voice_tmp[i]; + break; + } + } else { + for (i = 0; i < NUM_G; i += 2) + if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE) + && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) { + voice_tmp[i].linked_voice = &voice_tmp[i + 1]; + voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; + voice_tmp[i].usage = voiceallocdesc->usage; + voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags; + voice_tmp[i + 1].usage = voiceallocdesc->usage; + voice = &voice_tmp[i]; + break; + } + } + + spin_unlock_irqrestore(&voicemgr->lock, flags); + + voice_tmp = voice; + + while (voice_tmp != NULL) { + + DPD(2, " voice allocated -> %d\n", voice_tmp->num); + + sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff); + sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF); + sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff); + sblive_writeptr(card, PTRX, voice_tmp->num, 0); + + voice_tmp = voice_tmp->linked_voice; + } + + return voice; +} + +void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + struct emu_voice *voice_tmp; + unsigned dcysusv; + u32 cra, sample; + int i; + unsigned long flags; + + DPF(2, "emu10k1_voice_free()\n"); + + voice_tmp = voice; + + while (voice_tmp != NULL) { + + DPD(2, " voice freed -> %d\n", voice_tmp->num); + + sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK); + sblive_writeptr(card, IP, voice_tmp->num, 0); + + dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK); + sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF); + + sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK); + sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0); + sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK); + sblive_writeptr(card, CPF, voice_tmp->num, 0); + + sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080; + cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK; + sblive_writeptr(card, CCR, voice_tmp->num, cra); + cra = (cra >> 18) & 0xf; + sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + cra = (cra + 0x1) & 0xf; + sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + + for (i = 0; i < NUM_FXSENDS; i++) + voice_tmp->sendhandle[i] = 0; + + voice_tmp->flags = 0; + + spin_lock_irqsave(&voicemgr->lock, flags); + voice_tmp->usage = VOICEMGR_USAGE_FREE; + + voice_tmp = voice_tmp->linked_voice; + voice->linked_voice = NULL; + spin_unlock_irqrestore(&voicemgr->lock, flags); + } + + return; +} + +/* Sets up a voices for Wave Playback */ + +void emu10k1_voice_playback_setup(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + u32 sample, cra = 0, start = 0; + + DPF(2, "emu10k1_voice_playback_setup()\n"); + + while (voice != NULL) { + sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF); + sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK); + sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK); + sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000); + + /* Stop CA */ + /* Assumption that PT is alreadt 0 so no harm overwriting */ + sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b); + + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) { + if (voice->linked_voice != NULL) { + /* Set stereo bit */ + cra = 64; + sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); + sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); + } else { + cra = 32; + sblive_writeptr(card, CPF, voice->num, 0); + } + + if (voice->flags & VOICEMGR_FLAGS_16BIT) + sample = 0; + else { + cra = cra * 2; + sample = 0x80808080; + } + cra -= 4; + + if (voice->linked_voice != NULL) { + /* CCR_READADDRESS_MASK */ + sblive_writeptr(card, CCR, voice->num, 0x3c << 16); + sblive_writeptr(card, CCR, voice->num + 1, cra << 16); + sblive_writeptr(card, CDE, voice->num + 1, sample); + sblive_writeptr(card, CDF, voice->num + 1, sample); + start = voice->params.start + cra / 2; + } else { + sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */ + sblive_writeptr(card, CDE, voice->num, sample); + sblive_writeptr(card, CDF, voice->num, sample); + start = voice->params.start + cra; + } + + if (start > voice->params.endloop) { + start -= voice->params.endloop; + + if (voice->linked_voice != NULL) + cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9); + else + cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9); + + start += voice->params.startloop; + + if (start >= voice->params.endloop) + start = voice->params.endloop - 1; + } else if (voice->linked_voice != NULL) + cra = (cra << 25) | (0x3c << 16); + else + cra = (cra << 25) | (0x1c << 16); + + start |= CCCA_INTERPROM_0; + } + + /* CSL, ST, CA */ + sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24)); + sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24)); + + if (voice->flags & VOICEMGR_FLAGS_16BIT) + sblive_writeptr(card, CCCA, voice->num, start); + else + sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT); + + /* Clear filter delay memory */ + sblive_writeptr(card, Z1, voice->num, 0); + sblive_writeptr(card, Z2, voice->num, 0); + + /* Invalidate maps */ + sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + + /* Fill cache */ + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) + sblive_writeptr(card, CCR, voice->num, cra); + + sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); + sblive_writeptr(card, LFOVAL1, voice->num, 0x8000); + sblive_writeptr(card, ATKHLDM, voice->num, 0); + sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK); + sblive_writeptr(card, LFOVAL2, voice->num, 0x8000); + sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch); + sblive_writeptr(card, PEFE, voice->num, 0x7f); + sblive_writeptr(card, FMMOD, voice->num, 0); + sblive_writeptr(card, TREMFRQ, voice->num, 0); + sblive_writeptr(card, FM2FRQ2, voice->num, 0); + sblive_writeptr(card, ENVVAL, voice->num, 0xbfff); + sblive_writeptr(card, ENVVOL, voice->num, 0xbfff); + +#ifdef PRIVATE_PCM_VOLUME + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].channel_l == voice->num) { + voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : + // test for mono channel (reverse logic is correct here!) + (sblive_pcm_volume[i].attn_r > + sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r; + DPD(2, "set left volume %d\n", voice->params.initial_attn); + break; + } else if (sblive_pcm_volume[i].channel_r == voice->num) { + voice->params.initial_attn = sblive_pcm_volume[i].attn_r; + DPD(2, "set right volume %d\n", voice->params.initial_attn); + break; + } + } + } +#endif + sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn); + + voice->params.FC_target = 0xffff; + voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16); + + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_start(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + + DPF(2, "emu10k1_voice_start()\n"); + + while (voice != NULL) { + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target); + + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) + sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target); + + sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16) + | voice->params.FC_target); + sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16) + | voice->params.FC_target); + sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8) + | ENV_ON | voice->params.byampl_env_decay); + + /* Using StopOnLoop for MIDI stops the playback + too early, which may cause a DC level to be played + until the note is released. */ + + if (voice->usage == VOICEMGR_USAGE_MIDI) + emu10k1_clear_stop_on_loop(card, voice->num); + else { + if (voice->params.startloop > voice->params.end) + emu10k1_set_stop_on_loop(card, voice->num); + else + emu10k1_clear_stop_on_loop(card, voice->num); + } + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_stop(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + + DPF(2, "emu10k1_voice_stop()\n"); + + while (voice != NULL) { + sblive_writeptr(card, IFATN, voice->num, 0xffff); + sblive_writeptr(card, IP, voice->num, 0); + sblive_writeptr(card, VTFT, voice->num, 0xffff); + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0); + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam) +{ + struct emu10k1_card *card = voice->card; + int count; + + for (count = 0; count < numparam; count++) + sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value); + + return; +} + +void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value) +{ + struct emu10k1_card *card = voice->card; + + *value = sblive_readptr(card, controlid, voice->num); + + return; +} diff --git a/drivers/sound/emu10k1/voicemgr.h b/drivers/sound/emu10k1/voicemgr.h new file mode 100644 index 000000000000..bef340d8b38b --- /dev/null +++ b/drivers/sound/emu10k1/voicemgr.h @@ -0,0 +1,150 @@ +/* + ********************************************************************** + * sblive_voice.h -- EMU Voice Resource Manager header file + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#ifndef _VOICEMGR_H +#define _VOICEMGR_H +/* struct emu_voice.usage flags */ +#define VOICEMGR_USAGE_FREE 0x00000000 +#define VOICEMGR_USAGE_MIDI 0x00000001 +#define VOICEMGR_USAGE_PLAYBACK 0x00000002 + +/* struct emu_voice.flags flags */ +#define VOICEMGR_FLAGS_MONO 0x00000002 +#define VOICEMGR_FLAGS_16BIT 0x00000004 +#define VOICEMGR_FLAGS_STEREOSLAVE 0x00000008 +#define VOICEMGR_FLAGS_VOICEMASTER 0x80000000 +#define VOICEMGR_FLAGS_FXRT2 0x00000010 + +struct voice_param +{ + /* Sound engine */ + u32 start; + u32 startloop; + u32 endloop; + u32 end; + + u16 current_pitch; + u16 pitch_target; + + u16 current_volume; + u16 volume_target; + + u16 current_FC; + u16 FC_target; + + u8 pan_target; + u8 aux_target; + + /* FX bus amount send */ + + u32 send_a; + u32 send_b; + u32 send_c; + u32 send_d; + + /* Envelope engine */ + u16 ampl_env_delay; + u8 byampl_env_attack; + u8 byampl_env_hold; + u8 byampl_env_decay; + u8 byampl_env_sustain; + u8 byampl_env_release; + + u16 aux_env_delay; + u8 byaux_env_attack; + u8 byaux_env_hold; + u8 byaux_env_decay; + u8 byaux_env_sustain; + u8 byaux_env_release; + + u16 mod_LFO_delay; /* LFO1 */ + u16 vib_LFO_delay; /* LFO2 */ + u8 mod_LFO_freq; /* LFO1 */ + u8 vib_LFO_freq; /* LFO2 */ + + s8 aux_env_to_pitch; + s8 aux_env_to_FC; + s8 mod_LFO_to_pitch; + s8 vib_LFO_to_pitch; + s8 mod_LFO_to_FC; + s8 mod_LFO_to_volume; + + u16 sample_pitch; + u16 initial_pitch; + u8 initial_attn; + u8 initial_FC; +}; + +struct voice_allocdesc +{ + u32 usage; /* playback, Midi */ + u32 flags; /* stereo/mono rec/playback 8/16 bit*/ +}; + +struct emu_voice +{ + struct list_head list; + + struct emu10k1_card *card; + u32 usage; /* Free, MIDI, playback */ + u32 num; /* Voice ID */ + u32 flags; /* Stereo/mono, rec/playback, 8/16 bit */ + + struct voice_param params; + + struct emu_voice *linked_voice; /*for stereo voice*/ + + u32 sendhandle[NUM_FXSENDS]; +}; + +struct voice_manager +{ + struct emu10k1_card *card; + spinlock_t lock; + + struct emu_voice voice[NUM_G]; +}; + +struct voice_cntlset +{ + u32 paramID; + u32 value; +}; + +struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *); +void emu10k1_voice_free(struct voice_manager *, struct emu_voice *); +void emu10k1_voice_playback_setup(struct emu_voice *); +void emu10k1_voice_start(struct emu_voice *); +void emu10k1_voice_stop(struct emu_voice *); +void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32); +void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *); + +#endif /* _VOICEMGR_H */ diff --git a/fs/buffer.c b/fs/buffer.c index 26580ee0db5f..bcaadfd69a22 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -28,6 +28,7 @@ /* async buffer flushing, 1999 Andrea Arcangeli */ +#include #include #include #include @@ -2192,7 +2193,7 @@ busy_buffer_page: void show_buffers(void) { -#ifdef __SMP__ +#ifdef CONFIG_SMP struct buffer_head * bh; int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; int protected = 0; @@ -2203,7 +2204,7 @@ void show_buffers(void) printk("Buffer memory: %6dkB\n", atomic_read(&buffermem_pages) << (PAGE_SHIFT-10)); -#ifdef __SMP__ /* trylock does nothing on UP and so we could deadlock */ +#ifdef CONFIG_SMP /* trylock does nothing on UP and so we could deadlock */ if (!spin_trylock(&lru_list_lock)) return; for(nlist = 0; nlist < NR_LIST; nlist++) { diff --git a/fs/devfs/base.c b/fs/devfs/base.c index e71618b8a72e..b934ff9b9026 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -432,6 +432,17 @@ . Work sponsored by SGI. v0.93 + 20000413 Richard Gooch + Set inode->i_size to correct size for symlinks. + 20000414 Richard Gooch + Only give lookup() method to directories to comply with new VFS + assumptions. + Work sponsored by SGI. + 20000415 Richard Gooch + Remove unnecessary tests in symlink methods. + Don't kill existing block ops in . + Work sponsored by SGI. + v0.94 */ #include #include @@ -466,7 +477,7 @@ #include #include -#define DEVFS_VERSION "0.93 (20000306)" +#define DEVFS_VERSION "0.94 (20000415)" #ifndef DEVFS_NAME # define DEVFS_NAME "devfs" @@ -2192,6 +2203,7 @@ static int get_removable_partition (struct devfs_entry *dir, const char *name, /* Superblock operations follow */ static struct inode_operations devfs_iops; +static struct inode_operations devfs_dir_iops; static struct file_operations devfs_fops; static struct inode_operations devfs_symlink_iops; @@ -2215,28 +2227,33 @@ static void devfs_read_inode (struct inode *inode) inode->i_blocks = 0; inode->i_blksize = 1024; inode->i_op = &devfs_iops; + inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; - if ( S_ISCHR (di->mode) ) { + if ( S_ISCHR (di->mode) ) + { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); - inode->i_fop = &devfs_fops; - } else if ( S_ISBLK (di->mode) ) { + } + else if ( S_ISBLK (di->mode) ) + { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); inode->i_bdev = bdget (inode->i_rdev); - if (inode->i_bdev) inode->i_bdev->bd_op = di->de->u.fcb.ops; + if (inode->i_bdev) + { + if (!inode->i_bdev->bd_op && di->de->u.fcb.ops) + inode->i_bdev->bd_op = di->de->u.fcb.ops; + } else printk ("%s: read_inode(%d): no block device from bdget()\n", DEVFS_NAME, (int) inode->i_ino); - inode->i_fop = &devfs_fops; - } else if ( S_ISFIFO (di->mode) ) { - inode->i_fop = &def_fifo_fops; - } else if ( S_ISREG (di->mode) ) { - inode->i_size = di->de->u.fcb.u.file.size; - inode->i_fop = &devfs_fops; - } else if (S_ISLNK(di->mode)) { + } + else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops; + else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size; + else if ( S_ISDIR (di->mode) ) inode->i_op = &devfs_dir_iops; + else if ( S_ISLNK (di->mode) ) + { inode->i_op = &devfs_symlink_iops; - } else { - inode->i_fop = &devfs_fops; + inode->i_size = di->de->u.symlink.length; } inode->i_mode = di->mode; inode->i_uid = di->uid; @@ -2754,7 +2771,7 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) de = search_for_entry_in_dir (parent, dentry->d_name.name, dentry->d_name.len, FALSE); } - if ( (de == NULL) || (!de->registered) ) + if ( (de == NULL) || !de->registered ) { /* Try with devfsd. For any kind of failure, leave a negative dentry so someone else can deal with it (in the case where the sysadmin @@ -3090,41 +3107,46 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen) { - struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); - char *name = ERR_PTR(-ENOENT); + struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); - if (di && di->de->registered) - name = di->de->u.symlink.linkname; - return vfs_readlink(dentry, buffer, buflen, name); + return vfs_readlink (dentry, buffer, buflen, di->de->u.symlink.linkname); } /* End Function devfs_readlink */ static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd) { - struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); - char *name = ERR_PTR(-ENOENT); + struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); - if (di && di->de->registered) - name = di->de->u.symlink.linkname; - return vfs_follow_link(nd, name); + return vfs_follow_link (nd, di->de->u.symlink.linkname); } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = { - lookup: devfs_lookup, - link: devfs_link, - unlink: devfs_unlink, - symlink: devfs_symlink, - mkdir: devfs_mkdir, - rmdir: devfs_rmdir, - mknod: devfs_mknod, - setattr: devfs_notify_change, + link: devfs_link, + unlink: devfs_unlink, + symlink: devfs_symlink, + mkdir: devfs_mkdir, + rmdir: devfs_rmdir, + mknod: devfs_mknod, + setattr: devfs_notify_change, +}; + +static struct inode_operations devfs_dir_iops = +{ + lookup: devfs_lookup, + link: devfs_link, + unlink: devfs_unlink, + symlink: devfs_symlink, + mkdir: devfs_mkdir, + rmdir: devfs_rmdir, + mknod: devfs_mknod, + setattr: devfs_notify_change, }; static struct inode_operations devfs_symlink_iops = { - readlink: devfs_readlink, - follow_link: devfs_follow_link, - setattr: devfs_notify_change, + readlink: devfs_readlink, + follow_link: devfs_follow_link, + setattr: devfs_notify_change, }; static struct super_block *devfs_read_super (struct super_block *sb, @@ -3186,7 +3208,7 @@ out_no_root: } /* End Function devfs_read_super */ -static DECLARE_FSTYPE(devfs_fs_type, DEVFS_NAME, devfs_read_super, 0); +static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, 0); /* File operations for devfsd follow */ @@ -3315,7 +3337,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, doesn't matter who gets in first, as long as only one gets it */ if (fs_info->devfsd_task == NULL) { -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Looks like no-one has it: check again and grab, with interrupts disabled */ __cli (); @@ -3325,7 +3347,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, fs_info->devfsd_event_mask = 0; /* Temporary disable */ fs_info->devfsd_task = current; } -#ifdef __SMP__ +#ifdef CONFIG_SMP __sti (); #endif } @@ -3399,7 +3421,7 @@ void __init mount_devfs_fs (void) { int err; extern long do_sys_mount (char *dev_name, char *dir_name, - char * type, int flags, void * data); + char *type, int flags, void *data); if ( (boot_options & OPTION_NOMOUNT) ) return; err = do_sys_mount ("none", "/dev", "devfs", 0, ""); diff --git a/fs/proc/array.c b/fs/proc/array.c index 476f05f8cd92..6f73e28dd139 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -52,6 +52,7 @@ * : base.c too. */ +#include #include #include #include @@ -269,6 +270,9 @@ int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; struct mm_struct *mm = task->mm; +#if defined(CONFIG_ARCH_S390) + int line,len; +#endif buffer = task_name(task, buffer); buffer = task_state(task, buffer); @@ -276,6 +280,10 @@ int proc_pid_status(struct task_struct *task, char * buffer) buffer = task_mem(mm, buffer); buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); +#if defined(CONFIG_ARCH_S390) + for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++) + buffer+=len; +#endif return buffer - orig; } @@ -637,7 +645,7 @@ out: return retval; } -#ifdef __SMP__ +#ifdef CONFIG_SMP int proc_pid_cpu(struct task_struct *task, char * buffer) { int i, len; diff --git a/fs/proc/base.c b/fs/proc/base.c index 63bd4459be86..ae3c361227e0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -474,7 +475,7 @@ static struct pid_entry base_stuff[] = { E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), -#ifdef __SMP__ +#ifdef CONFIG_SMP E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), #endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), @@ -800,7 +801,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) case PROC_PID_MAPS: inode->i_fop = &proc_maps_operations; break; -#ifdef __SMP__ +#ifdef CONFIG_SMP case PROC_PID_CPU: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_cpu; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 8e18e212a97e..7136b2684614 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -285,14 +285,16 @@ static int kstat_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int i, len; - unsigned sum = 0; extern unsigned long total_forks; unsigned long jif = jiffies; +#if !defined(CONFIG_ARCH_S390) + unsigned sum = 0; for (i = 0 ; i < NR_IRQS ; i++) sum += kstat_irqs(i); +#endif -#ifdef __SMP__ +#ifdef CONFIG_SMP len = sprintf(page, "cpu %u %u %u %lu\n", kstat.cpu_user, @@ -315,8 +317,12 @@ static int kstat_read_proc(char *page, char **start, off_t off, "disk_rblk %u %u %u %u\n" "disk_wblk %u %u %u %u\n" "page %u %u\n" - "swap %u %u\n" +#if !defined(CONFIG_ARCH_S390) + "swap %u %u\n" "intr %u", +#else + "swap %u %u\n", +#endif #else len = sprintf(page, "cpu %u %u %u %lu\n" @@ -326,8 +332,12 @@ static int kstat_read_proc(char *page, char **start, off_t off, "disk_rblk %u %u %u %u\n" "disk_wblk %u %u %u %u\n" "page %u %u\n" - "swap %u %u\n" +#if !defined(CONFIG_ARCH_S390) + "swap %u %u\n" "intr %u", +#else + "swap %u %u\n", +#endif kstat.cpu_user, kstat.cpu_nice, kstat.cpu_system, @@ -346,10 +356,14 @@ static int kstat_read_proc(char *page, char **start, off_t off, kstat.pgpgin, kstat.pgpgout, kstat.pswpin, +#if !defined(CONFIG_ARCH_S390) kstat.pswpout, sum); - for (i = 0 ; i < NR_IRQS ; i++) - len += sprintf(page + len, " %u", kstat_irqs(i)); + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(page + len, " %u", kstat_irqs(i)); +#else + kstat.pswpout); +#endif len += sprintf(page + len, "\nctxt %u\n" "btime %lu\n" @@ -389,6 +403,7 @@ static int partitions_read_proc(char *page, char **start, off_t off, return len; } +#if !defined(CONFIG_ARCH_S390) static int interrupts_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -400,6 +415,7 @@ static int interrupts_read_proc(char *page, char **start, off_t off, if (len<0) len = 0; return len; } +#endif static int filesystems_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -578,7 +594,7 @@ static ssize_t read_profile(struct file *file, char *buf, static ssize_t write_profile(struct file * file, const char * buf, size_t count, loff_t *ppos) { -#ifdef __SMP__ +#ifdef CONFIG_SMP extern int setup_profiling_timer (unsigned int multiplier); if (count==sizeof(int)) { @@ -631,7 +647,9 @@ void __init proc_misc_init(void) {"stat", kstat_read_proc}, {"devices", devices_read_proc}, {"partitions", partitions_read_proc}, +#if !defined(CONFIG_ARCH_S390) {"interrupts", interrupts_read_proc}, +#endif {"filesystems", filesystems_read_proc}, {"dma", dma_read_proc}, {"ioports", ioports_read_proc}, diff --git a/include/asm-ia64/keyboard.h b/include/asm-ia64/keyboard.h index b795574fc042..9259e163c0fb 100644 --- a/include/asm-ia64/keyboard.h +++ b/include/asm-ia64/keyboard.h @@ -11,8 +11,6 @@ # ifdef __KERNEL__ -#include - #include #define KEYBOARD_IRQ isa_irq_to_vector(1) diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index 52326f296658..a7f5ceb56579 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -12,6 +12,8 @@ * Copyright (C) 1998-2000 David Mosberger-Tang */ +#include + #include #include #include diff --git a/kernel/exit.c b/kernel/exit.c index ce1e771aede5..d72741a7655e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -25,7 +25,7 @@ int getrusage(struct task_struct *, int, struct rusage *); static void release(struct task_struct * p) { if (p != current) { -#ifdef __SMP__ +#ifdef CONFIG_SMP int has_cpu; /* diff --git a/kernel/fork.c b/kernel/fork.c index 4932f6cbc1c6..fa63452e124b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -11,6 +11,7 @@ * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' */ +#include #include #include #include @@ -98,7 +99,7 @@ static inline struct user_struct *uid_hash_find(unsigned short uid, unsigned int * the common case (not freeing anything) without having * any locking. */ -#ifdef __SMP__ +#ifdef CONFIG_SMP #define uid_hash_free(up) (!atomic_read(&(up)->count)) #else #define uid_hash_free(up) (1) @@ -695,7 +696,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) p->tty_old_pgrp = 0; p->times.tms_utime = p->times.tms_stime = 0; p->times.tms_cutime = p->times.tms_cstime = 0; -#ifdef __SMP__ +#ifdef CONFIG_SMP { int i; p->has_cpu = 0; diff --git a/kernel/panic.c b/kernel/panic.c index 920e4a1a76b0..8e53e13b475b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -65,7 +65,7 @@ NORET_TYPE void panic(const char * fmt, ...) unblank_console(); -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_stop(); #endif diff --git a/kernel/sched.c b/kernel/sched.c index d1d49df5c66e..c846e4160eb6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -19,6 +19,7 @@ * current-task */ +#include #include #include #include @@ -80,7 +81,7 @@ static union { struct kernel_stat kstat = { 0 }; -#ifdef __SMP__ +#ifdef CONFIG_SMP #define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) #define can_schedule(p) (!(p)->has_cpu) @@ -133,7 +134,7 @@ static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struc if (!weight) goto out; -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Give a largish advantage to the same processor... */ /* (this is equivalent to penalizing other processors) */ if (p->processor == this_cpu) @@ -184,7 +185,7 @@ static inline int preemption_goodness(struct task_struct * prev, struct task_str */ static inline void reschedule_idle(struct task_struct * p, unsigned long flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP int this_cpu = smp_processor_id(), target_cpu; struct task_struct *tsk; int cpu, best_cpu, i; @@ -406,7 +407,7 @@ signed long schedule_timeout(signed long timeout) static inline void __schedule_tail(struct task_struct *prev) { current->need_resched |= prev->need_resched; -#ifdef __SMP__ +#ifdef CONFIG_SMP if ((prev->state == TASK_RUNNING) && (prev != idle_task(smp_processor_id()))) { unsigned long flags; @@ -416,7 +417,7 @@ static inline void __schedule_tail(struct task_struct *prev) } wmb(); prev->has_cpu = 0; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ } void schedule_tail(struct task_struct *prev) @@ -516,7 +517,7 @@ still_running_back: * sched_data. */ sched_data->curr = next; -#ifdef __SMP__ +#ifdef CONFIG_SMP next->has_cpu = 1; next->processor = this_cpu; #endif @@ -525,7 +526,7 @@ still_running_back: if (prev == next) goto same_process; -#ifdef __SMP__ +#ifdef CONFIG_SMP /* * maintain the per-process 'average timeslice' value. * (this has to be recalculated even if we reschedule to @@ -554,7 +555,7 @@ still_running_back: * rescheduled during switch_to(). */ -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ kstat.context_swtch++; /* diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5a9bb0215d86..5137a8e90780 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -320,6 +320,7 @@ int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, kfree(context); if (error != -ENOTDIR) return error; + tmp = tmp->next; } while (tmp != &root_table_header.ctl_entry); return -ENOTDIR; } @@ -365,14 +366,13 @@ static int parse_table(int *name, int nlen, void *newval, size_t newlen, ctl_table *table, void **context) { + int n; repeat: if (!nlen) return -ENOTDIR; - + if (get_user(n, name)) + return -EFAULT; for ( ; table->ctl_name; table++) { - int n; - if (get_user(n, name)) - return -EFAULT; if (n == table->ctl_name || table->ctl_name == CTL_ANY) { int error; if (table->child) { diff --git a/kernel/timer.c b/kernel/timer.c index f087d239fc90..b28c69123f8a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -15,6 +15,7 @@ * 1999-03-10 Improved NTP compatibility by Ulrich Windl */ +#include #include #include #include @@ -211,7 +212,7 @@ int del_timer(struct timer_list * timer) return ret; } -#ifdef __SMP__ +#ifdef CONFIG_SMP /* * SMP specific function to delete periodic timer. * Caller must disable by some means restarting the timer @@ -564,7 +565,7 @@ static void update_process_times(unsigned long ticks, unsigned long system) /* * SMP does this on a per-CPU basis elsewhere */ -#ifndef __SMP__ +#ifndef CONFIG_SMP struct task_struct * p = current; unsigned long user = ticks - system; if (p->pid) { @@ -748,7 +749,7 @@ asmlinkage long sys_getppid(void) parent = me->p_opptr; for (;;) { pid = parent->pid; -#if __SMP__ +#if CONFIG_SMP { struct task_struct *old = parent; mb(); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d97bdc5f2eb7..5a3ccd0625dd 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -54,7 +54,7 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; -#if defined(__i386__) && defined(__SMP__) +#if defined(__i386__) && defined(CONFIG_SMP) #define ASSERT_WL(n) if ((int)((n)->lock.lock) > 0) { printk("WL assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } #else #define ASSERT_WL(n) do { } while(0) @@ -597,7 +597,7 @@ next_elt: write_unlock(&tbl->lock); } -#ifdef __SMP__ +#ifdef CONFIG_SMP static void neigh_periodic_timer(unsigned long arg) { struct neigh_table *tbl = (struct neigh_table*)arg; @@ -629,7 +629,7 @@ static void neigh_timer_handler(unsigned long arg) state = neigh->nud_state; if (!(state&NUD_IN_TIMER)) { -#ifndef __SMP__ +#ifndef CONFIG_SMP printk("neigh: timer & !nud_in_timer\n"); #endif goto out; @@ -1106,7 +1106,7 @@ void neigh_table_init(struct neigh_table *tbl) 0, SLAB_HWCACHE_ALIGN, NULL, NULL); -#ifdef __SMP__ +#ifdef CONFIG_SMP tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer), (unsigned long)tbl); #endif init_timer(&tbl->gc_timer); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1e9fad9bf25f..866178fbcabe 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2227,7 +2227,7 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset, memcpy(dst, src, length); -#ifdef __SMP__ +#ifdef CONFIG_SMP if (smp_num_cpus > 1) { int i; int cnt = length/4; diff --git a/net/socket.c b/net/socket.c index 84eae63b71ae..88ffcfdc96e3 100644 --- a/net/socket.c +++ b/net/socket.c @@ -130,7 +130,7 @@ static struct file_operations socket_file_ops = { static struct net_proto_family *net_families[NPROTO]; -#ifdef __SMP__ +#ifdef CONFIG_SMP static atomic_t net_family_lockct = ATOMIC_INIT(0); static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED; diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 1bf4f60700d9..ef50303540d6 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -11,13 +11,17 @@ O_TARGET := sunrpc.o O_OBJS := clnt.o xprt.o sched.o \ auth.o auth_null.o auth_unix.o \ svc.o svcsock.o svcauth.o \ - pmap_clnt.o xdr.o sysctl.o + pmap_clnt.o xdr.o OX_OBJS := sunrpc_syms.o ifeq ($(CONFIG_PROC_FS),y) O_OBJS += stats.o endif +ifeq ($(CONFIG_SYSCTL),y) + O_OBJS += sysctl.o +endif + M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index da46ab910ba7..c4d946cb3c2c 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -1015,7 +1015,7 @@ rpciod(void *ptr) current->session = 1; current->pgrp = 1; - sprintf(current->comm, "rpciod"); + strcpy(current->comm, "rpciod"); dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid); while (rpciod_users) { diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 1607d84f320e..e53759e3e4f0 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -105,7 +105,9 @@ EXPORT_SYMBOL(rpc_garbage_args); EXPORT_SYMBOL(rpc_system_err); /* Debugging symbols */ +#ifdef RPC_DEBUG EXPORT_SYMBOL(rpc_debug); EXPORT_SYMBOL(nfs_debug); EXPORT_SYMBOL(nfsd_debug); EXPORT_SYMBOL(nlm_debug); +#endif diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 6219c37209c1..be49a16a1f53 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -57,7 +57,7 @@ rpc_unregister_sysctl(void) } } -int +static int proc_dodebug(ctl_table *table, int write, struct file *file, void *buffer, size_t *lenp) { -- 2.39.5