AMI MegaRAID support
CONFIG_SCSI_MEGARAID
- This driver supports the AMI MegaRAID 428 and 438 (and maybe 466)
- SCSI host adapters.
+ This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
+ and 467 SCSI host adapters.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read Documentation/modules.txt. This is recommended.
The module will be called yellowfin.o.
+General Instruments Surfboard 1000
+CONFIG_NET_SB1000
+ This is a driver for the General Instrument SURFboard 1000 internal cable
+ modem. This is an ISA card which is used by a number of cable TV companies
+ to provide cable modem access. It's a one-way downstream-only cable modem,
+ meaning that your upstream net link is provided by your regular phone modem.
+
+ At present this driver only compiles as a module, so say M here if you
+ have this card. Then read Documentation/networking/README.sb1000 for
+ information on how to use this module, as it needs special ppp scripts for
+ establishing a connection. Further documentation and the necessary scripts
+ can be found at:
+
+ http://www.jacksonville.net/~fventuri/
+ http://home.adelphia.net/~siglercm/sb1000.html
+ http://linuxpower.cx/~cable/
+
+ If you don't have this card, of course say N.
+
Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
CONFIG_ACENIC
Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
You don't want to use the minix filesystem on your hard disk because
of certain built-in restrictions, but it is sometimes found on older
Linux floppy disks. This option will enlarge your kernel by about
- 25 kB. If unsure, say N.
+ 28 kB. If unsure, say N.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
ext2fs is a diskless Linux box which mounts all files over the
network using NFS (in this case it's sufficient to say Y to "NFS
filesystem support" below). Saying Y here will enlarge your kernel
- by about 41 kB.
+ by about 44 kB.
The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini,
that has a program like lynx or netscape), and also on the proc(8)
manpage ("man 8 proc").
- This option will enlarge your kernel by about 18 KB. Several
+ This option will enlarge your kernel by about 67 KB. Several
programs depend on this, so everyone should say Y here.
NFS filesystem support
Say Y to this only if you plan on mounting disks with SGI disklabels.
This is not required to mount EFS-format CDROMs.
+EFS filesystem support (experimental)
+CONFIG_EFS_FS
+ EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX.
+ This implementation only offers read-only access. If you don't know
+ what all this is about, it's safe to say N. For more information
+ about EFS see it's homepage at http://aeschi.ch.eu.org/efs.
+
+SGI disklabel support
+CONFIG_SGI_DISKLABEL
+ Say Y to this only if you plan on mounting disks with SGI disklabels.
+ This is not required to mount EFS-format CDROMs.
+
BSD disklabel (FreeBSD partition tables) support
CONFIG_BSD_DISKLABEL
FreeBSD uses its own hard disk partition scheme on your PC. It
letters that were missing in Latin 4 to cover the entire Nordic
area.
+nls iso8859-14
+CONFIG_NLS_ISO8859_14
+ If you want to display filenames with native language characters
+ from the Microsoft fat filesystem family or from JOLIET CDROMs
+ correctly on the screen, you need to include the appropriate
+ input/output character sets. Say Y here for the Latin 8 character
+ set, which adds the last accented vowels for Welsh (and Manx Gaelic)
+ that were missing in Latin 1. http://linux.speech.cymru.org/
+ has further information.
+
nls iso8859-15
CONFIG_NLS_ISO8859_15
If you want to display filenames with native language characters
you compiled aedsp16.o as a module you can specify this parameter as
'mpu_irq=NN'.
+SGI Visual Workstation on-board audio
+CONFIG_SOUND_VWSND
+ Say Y or M if you have an SGI Visual Workstation and you want to
+ be able to use its on-board audio. Read Documentation/sound/visws
+ for more info on this driver's capabilities.
+
Ensoniq ES1370 based PCI sound cards
CONFIG_SOUND_ES1370
Say Y or M if you have a PCI sound card utilizing the Ensoniq
will create two modules called ircomm and ircomm_tty. For more
information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
-IrLPT Protocol
-CONFIG_IRLPT
- Say Y here if you want to build support for the IrLPT protocol. If
- you want to compile it as a module, say M here and read
- Documentation/modules.txt. IrLPT makes it possible to print
- documents to IrDA capable printers.
-
-IrLPT Client Protocol
-CONFIG_IRLPT_CLIENT
- Say Y here if you want to build support for the IrLPT client
- protocol. If you want to compile it as a module, say M here and read
- Documentation/modules.txt. The IrLPT client protocol can be used to
- print documents to IrDA compatible printers like the HP-5MP, or
- IrLPT printer adapters like the ACTiSYS IR-100M.
-
-IrLPT Server Protocol
-CONFIG_IRLPT_SERVER
- Say Y here if you want to build support for the IrLPT server
- protocol. If you want to compile it as a module, say M here and read
- Documentation/modules.txt. The IrLPT server protocol makes it
- possible to use a Linux machine as an infrared printer server for
- other laptops. So if your Linux machine has a cable connection to a
- printer, then other laptops can use the Linux machine to print out
- documents using infrared communication.
-
IrTTY IrDA Device Driver
CONFIG_IRTTY_SIR
Say Y here if you want to build support for the IrTTY line
by IrTTY. To activate support for Greenwich dongles you will have to
insert "irattach -d girbil" in the /etc/irda/drivers script.
+Adaptec Airport 1000 and 2000 dongle
+CONFIG_AIRPORT_DONGLE
+ Say Y here if you want to build support for the Adaptec Airport 1000
+ and 2000 dongles. If you want to compile it as a module, say M here
+ and read Documentation/modules.txt. The Airport dongle attaches to
+ the normal 9-pin serial port connector, and can currently only be
+ used by IrTTY. To activate support for Airport dongles you will have
+ to insert "irattach -d airport" in the /etc/irda/drivers script.
+
Parallax Litelink dongle
CONFIG_LITELINK_DONGLE
Say Y here if you want to build support for the Parallax Litelink
ADVANSYS SCSI DRIVER
P: Bob Frey
M: Bob Frey <bobf@advansys.com>
-W: http://www.advansys.com/linux
+W: http://www.advansys.com/linux.html
+L: linux-scsi@vger.rutgers.edu
S: Maintained
AEDSP16 DRIVER
S: Supported
STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
-P: Greg Ungerer
M: support@stallion.oz.au
-M: gerg@stallion.com
W: http://www.stallion.com
S: Supported
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 16
+SUBLEVEL = 17
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
DRIVERS := $(DRIVERS) drivers/pci/pci.a
endif
+ifdef CONFIG_PCMCIA
+DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o
+endif
+
ifdef CONFIG_DIO
DRIVERS := $(DRIVERS) drivers/dio/dio.a
endif
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
- ptrace.o time.o fpreg.o semaphore.o pci_syscall.o
+ ptrace.o time.o fpreg.o semaphore.o
OX_OBJS := alpha_ksyms.o
sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \
sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \
sys_sx164.o sys_takara.o sys_rx164.o \
- es1888.o smc37c669.o smc37c93x.o ns87312.o \
- pci.o pci_setup.o
+ es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o
else
ifdef CONFIG_PCI
-O_OBJS += pci.o pci_setup.o
+O_OBJS += pci.o
endif
# Core logic support
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/sched.h>
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
* Code common to all MCbus-PCI Adaptor core logic chipsets
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
* Code common to all PYXIS core logic chips.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
* Code common to all T2 core logic chips.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
* Code common to all TSUNAMI core logic chips.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
* David Mosberger (davidm@cs.arizona.edu)
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/init.h>
*/
static void __init
-pci_assign_special(void)
+pcibios_assign_special(void)
{
struct pci_dev *dev;
-
- /* The first three resources of the Cypress IDE controler need
- to remain unchanged. So allocate them as-is. */
- dev = NULL;
- while ((dev = pci_find_device(PCI_VENDOR_ID_CONTAQ,
- PCI_DEVICE_ID_CONTAQ_82C693, dev))) {
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- pci_record_assignment(dev, 0);
- pci_record_assignment(dev, 1);
- pci_record_assignment(dev, 2);
+ int i;
+
+ /* The first three resources of an IDE controler are often magic,
+ so leave them unchanged. This is true, for instance, of the
+ Contaq 82C693 as seen on SX164 and DP264. */
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
+ continue;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (dev->resource[i].flags)
+ pci_claim_resource(dev, i);
}
}
}
{
/* Propogate hose info into the subordinate devices. */
+ struct pci_controler *hose = probing_hose;
struct pci_dev *dev;
- void *sysdata;
- sysdata = (bus->parent ? bus->parent->sysdata : bus->sysdata);
+ bus->resource[0] = hose->io_space;
+ bus->resource[1] = hose->mem_space;
for (dev = bus->devices; dev; dev = dev->sibling)
- dev->sysdata = sysdata;
+ dev->sysdata = hose;
}
void __init
-pcibios_base_address_update(struct pci_dev *dev, int resource)
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
{
- struct pci_controler *hose = dev->sysdata;
- struct resource *res = &dev->resource[resource];
- unsigned long base, where, size;
+ unsigned long where, size;
u32 reg;
- if (res->flags & IORESOURCE_IO)
- base = hose->io_space->start;
- else
- base = hose->mem_space->start;
-
where = PCI_BASE_ADDRESS_0 + (resource * 4);
size = res->end - res->start;
pci_read_config_dword(dev, where, ®);
- reg = (reg & size) | (((u32)(res->start - base)) & ~size);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
pci_write_config_dword(dev, where, reg);
/* ??? FIXME -- record old value for shutdown. */
}
void __init
-pcibios_irq_update(struct pci_dev *dev, u8 irq)
+pcibios_update_irq(struct pci_dev *dev, int irq)
{
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
/* ??? FIXME -- record old value for shutdown. */
}
}
probing_hose = NULL;
- pci_assign_special();
- pci_assign_unassigned(alpha_mv.min_io_address,
- alpha_mv.min_mem_address);
- pci_fixup_irq(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
+ pcibios_assign_special();
+ pci_assign_unassigned_resources(alpha_mv.min_io_address,
+ alpha_mv.min_mem_address);
+ pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
pci_set_bus_ranges();
}
extern struct pci_controler *hose_head, **hose_tail;
extern struct pci_controler *probing_hose;
-/* pci_common.c */
extern void common_init_pci(void);
extern u8 common_swizzle(struct pci_dev *, u8 *);
extern struct pci_controler *alloc_pci_controler(unsigned long *);
extern const char *const pci_io_names[];
extern const char *const pci_mem_names[];
extern const char pci_hae0_name[];
-
-/* pci_setup.c */
-void pci_record_assignment(struct pci_dev *dev, int resource);
-void pci_assign_unassigned(int, int);
-void pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(struct pci_dev *, u8, u8));
-void pci_set_bus_ranges(void);
-
+++ /dev/null
-/*
- * linux/arch/alpha/kernel/pci_setup.c
- *
- * Extruded from code written by
- * Dave Rusling (david.rusling@reo.mts.dec.com)
- * David Mosberger (davidm@cs.arizona.edu)
- * David Miller (davem@redhat.com)
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/pci.h>
-
-
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBGC(args) printk args
-#else
-# define DBGC(args)
-#endif
-
-
-void __init
-pci_record_assignment(struct pci_dev *dev, int resource)
-{
- struct pci_controler *hose = dev->sysdata;
- struct resource *res = &dev->resource[resource];
- struct resource *base;
- int ok;
-
- if (res->flags == 0)
- return;
- if (res->flags & IORESOURCE_IO)
- base = hose->io_space;
- else
- base = hose->mem_space;
-
- res->start += base->start;
- res->end += base->start;
-
- ok = request_resource(base, res);
-
- DBGC(("PCI record assignment: (%s) resource %d %s\n",
- dev->name, resource, (ok < 0 ? "failed" : "ok")));
-}
-
-static void inline
-pdev_assign_unassigned(struct pci_dev *dev, int min_io, int min_mem)
-{
- u32 reg;
- u16 cmd;
- int i;
-
- DBGC(("PCI assign resources : (%s)\n", dev->name));
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct pci_controler *hose;
- struct resource *root, *res;
- unsigned long size, min, max;
-
- res = &dev->resource[i];
-
- if (res->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- else if (res->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
-
- /* If it is already assigned or the resource does
- not exist, there is nothing to do. */
- if (res->parent != NULL || res->flags == 0UL)
- continue;
-
- hose = dev->sysdata;
-
- /* Determine the root we allocate from. */
- if (res->flags & IORESOURCE_IO) {
- root = hose->io_space;
- min = root->start + min_io;
- max = root->end;
- } else {
- root = hose->mem_space;
- min = root->start + min_mem;
- max = root->end;
- }
-
- size = res->end - res->start + 1;
-
- DBGC((" for root[%016lx:%016lx]\n"
- " res[%016lx:%016lx]\n"
- " span[%016lx:%016lx] size[%lx]\n",
- root->start, root->end, res->start, res->end,
- min, max, size));
-
- if (allocate_resource(root, res, size, min, max, size) < 0) {
- printk(KERN_ERR
- "PCI: Failed to allocate resource %d for %s\n",
- i, dev->name);
- }
-
- DBGC((" got res[%016lx:%016lx] for resource %d\n",
- res->start, res->end, i));
-
- /* Update PCI config space. */
- pcibios_base_address_update(dev, i);
- }
-
- /* Special case, disable the ROM. Several devices act funny
- (ie. do not respond to memory space writes) when it is left
- enabled. A good example are QlogicISP adapters. */
-
- pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®);
- reg &= ~PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
-
- /* All of these (may) have I/O scattered all around and may not
- use IO-base address registers at all. So we just have to
- always enable IO to these devices. */
- if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
- || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
- || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
- || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- cmd |= PCI_COMMAND_IO;
- }
-
- /* ??? Always turn on bus mastering. */
- cmd |= PCI_COMMAND_MASTER;
-
- /* Enable the appropriate bits in the PCI command register. */
- pci_write_config_word(dev, PCI_COMMAND, cmd);
-
- DBGC((" cmd reg 0x%x\n", cmd));
-
- /* If this is a PCI bridge, set the cache line correctly. */
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- /* ??? EV4/EV5 cache line is 32 bytes. */
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
- (64 / sizeof(u32)));
- }
-}
-
-void __init
-pci_assign_unassigned(int min_io, int min_mem)
-{
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- pdev_assign_unassigned(dev, min_io, min_mem);
-}
-
-struct pbus_set_ranges_data
-{
- int found_vga;
- unsigned int io_start, io_end;
- unsigned int mem_start, mem_end;
-};
-
-static void __init
-pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
- struct pbus_set_ranges_data inner;
- struct pci_bus *child;
- struct pci_dev *dev;
-
- inner.found_vga = 0;
- inner.mem_start = inner.io_start = ~0;
- inner.mem_end = inner.io_end = 0;
-
- /* Collect information about how our direct children are layed out. */
- for (dev = bus->devices; dev; dev = dev->sibling) {
- int i;
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = &dev->resource[i];
- if (res->flags & IORESOURCE_IO) {
- if (res->start < inner.io_start)
- inner.io_start = res->start;
- if (res->end > inner.io_end)
- inner.io_end = res->end;
- } else if (res->flags & IORESOURCE_MEM) {
- if (res->start < inner.mem_start)
- inner.mem_start = res->start;
- if (res->end > inner.mem_end)
- inner.mem_end = res->end;
- }
- }
- if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- inner.found_vga = 1;
- }
-
- /* And for all of the sub-busses. */
- for (child = bus->children; child; child = child->next)
- pbus_set_ranges(child, &inner);
-
- /* Align the values. */
- inner.io_start &= ~(4*1024 - 1);
- inner.mem_start &= ~(1*1024*1024 - 1);
- if (inner.io_end & (4*1024-1))
- inner.io_end = (inner.io_end | (4*1024 - 1)) + 1;
- if (inner.mem_end & (1*1024*1024-1))
- inner.mem_end = (inner.mem_end | (1*1024*1024 - 1)) + 1;
-
- /* Configure the bridge, if possible. */
- if (bus->self) {
- struct pci_dev *bridge = bus->self;
- u32 l;
-
- /* Set up the top and bottom of the PCI I/O segment
- for this bus. */
- pci_read_config_dword(bridge, PCI_IO_BASE, &l);
- l &= 0xffff0000;
- l |= (inner.io_start >> 8) & 0x00f0;
- l |= (inner.io_end - 1) & 0xf000;
- pci_write_config_dword(bridge, PCI_IO_BASE, l);
-
- /*
- * Clear out the upper 16 bits of IO base/limit.
- * Clear out the upper 32 bits of PREF base/limit.
- */
- pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
- pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
-
- /* Set up the top and bottom of the PCI Memory segment
- for this bus. */
- l = (inner.mem_start & 0xfff00000) >> 16;
- l |= (inner.mem_end - 1) & 0xfff00000;
- pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
- /*
- * Turn off downstream PF memory address range, unless
- * there is a VGA behind this bridge, in which case, we
- * enable the PREFETCH range to include BIOS ROM at C0000.
- *
- * NOTE: this is a bit of a hack, done with PREFETCH for
- * simplicity, rather than having to add it into the above
- * non-PREFETCH range, which could then be bigger than we want.
- * We might assume that we could relocate the BIOS ROM, but
- * that would depend on having it found by those who need it
- * (the DEC BIOS emulator would find it, but I do not know
- * about the Xservers). So, we do it this way for now... ;-)
- */
- l = (inner.found_vga) ? 0 : 0x0000ffff;
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
-
- /*
- * Tell bridge that there is an ISA bus in the system,
- * and (possibly) a VGA as well.
- */
- l = (inner.found_vga) ? 0x0c : 0x04;
- pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
-
- /*
- * Clear status bits,
- * turn on I/O enable (for downstream I/O),
- * turn on memory enable (for downstream memory),
- * turn on master enable (for upstream memory and I/O).
- */
- pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
- }
-
- if (outer) {
- outer->found_vga |= inner.found_vga;
- if (inner.io_start < outer->io_start)
- outer->io_start = inner.io_start;
- if (inner.io_end > outer->io_end)
- outer->io_end = inner.io_end;
- if (inner.mem_start < outer->mem_start)
- outer->mem_start = inner.mem_start;
- if (inner.mem_end > outer->mem_end)
- outer->mem_end = inner.mem_end;
- }
-}
-
-void __init
-pci_set_bus_ranges(void)
-{
- struct pci_bus *bus;
-
- for (bus = pci_root; bus; bus = bus->next)
- pbus_set_ranges(bus, NULL);
-}
-
-static void inline
-pdev_fixup_irq(struct pci_dev *dev,
- u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(struct pci_dev *, u8, u8))
-{
- u8 pin, slot;
- int irq;
-
- /* If this device is not on the primary bus, we need to figure out
- which interrupt pin it will come in on. We know which slot it
- will come in on 'cos that slot is where the bridge is. Each
- time the interrupt line passes through a PCI-PCI bridge we must
- apply the swizzle function. */
-
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- /* Cope with 0 and illegal. */
- if (pin == 0 || pin > 4)
- pin = 1;
-
- /* Follow the chain of bridges, swizzling as we go. */
- slot = (*swizzle)(dev, &pin);
-
- irq = (*map_irq)(dev, slot, pin);
- if (irq == -1)
- irq = 0;
- dev->irq = irq;
-
- DBGC(("PCI fixup irq : (%s) got %d\n", dev->name, dev->irq));
-
- /* Always tell the device, so the driver knows what is
- the real IRQ to use; the device does not use it. */
- pcibios_irq_update(dev, irq);
-}
-
-void __init
-pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(struct pci_dev *, u8, u8))
-{
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- pdev_fixup_irq(dev, swizzle, map_irq);
-}
+++ /dev/null
-/*
- * pci_syscall.c
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-
-
-#ifndef CONFIG_PCI
-
-asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
-asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
-
-#else
-
-asmlinkage long
-sys_pciconfig_read(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len, void *buf)
-{
- struct pci_dev *dev;
- u8 byte;
- u16 word;
- u32 dword;
- long err, cfg_ret;
-
- err = -EPERM;
- if (!capable(CAP_SYS_ADMIN))
- goto error;
-
- err = -ENODEV;
- dev = pci_find_slot(bus, dfn);
- if (!dev)
- goto error;
-
- lock_kernel();
- switch (len) {
- case 1:
- cfg_ret = pci_read_config_byte(dev, off, &byte);
- break;
- case 2:
- cfg_ret = pci_read_config_word(dev, off, &word);
- break;
- case 4:
- cfg_ret = pci_read_config_dword(dev, off, &dword);
- break;
- default:
- err = -EINVAL;
- unlock_kernel();
- goto error;
- };
- unlock_kernel();
-
- err = -EIO;
- if (cfg_ret != PCIBIOS_SUCCESSFUL)
- goto error;
-
- switch (len) {
- case 1:
- err = put_user(byte, (unsigned char *)buf);
- break;
- case 2:
- err = put_user(word, (unsigned short *)buf);
- break;
- case 4:
- err = put_user(dword, (unsigned int *)buf);
- break;
- };
- return err;
-
-error:
- /* ??? XFree86 doesn't even check the return value. They
- just look for 0xffffffff in the output, since that's what
- they get instead of a machine check on x86. */
- switch (len) {
- case 1:
- put_user(-1, (unsigned char *)buf);
- break;
- case 2:
- put_user(-1, (unsigned short *)buf);
- break;
- case 4:
- put_user(-1, (unsigned int *)buf);
- break;
- };
- return err;
-}
-
-asmlinkage long
-sys_pciconfig_write(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len, void *buf)
-{
- struct pci_dev *dev;
- u8 byte;
- u16 word;
- u32 dword;
- int err = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (!pcibios_present())
- return -ENOSYS;
-
- dev = pci_find_slot(bus, dfn);
- if (!dev)
- return -ENODEV;
-
- lock_kernel();
- switch(len) {
- case 1:
- err = get_user(byte, (u8 *)buf);
- if (err)
- break;
- err = pci_write_config_byte(dev, off, byte);
- if (err != PCIBIOS_SUCCESSFUL)
- err = -EIO;
- break;
-
- case 2:
- err = get_user(word, (u16 *)buf);
- if (err)
- break;
- err = pci_write_config_byte(dev, off, word);
- if (err != PCIBIOS_SUCCESSFUL)
- err = -EIO;
- break;
-
- case 4:
- err = get_user(dword, (u32 *)buf);
- if (err)
- break;
- pci_write_config_byte(dev, off, dword);
- if (err != PCIBIOS_SUCCESSFUL)
- err = -EIO;
- break;
-
- default:
- err = -EINVAL;
- break;
- };
- unlock_kernel();
-
- return err;
-}
-
-#endif /* CONFIG_PCI */
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/core_mcpcia.h>
-#include <asm/pci.h>
#include "proto.h"
#include "irq_impl.h"
*
* Bits taken from various places.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
* These are the low level assembler for performing cache and TLB
* functions on the sa110.
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/procinfo.h>
mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_X86 y
+define_bool CONFIG_ISA y
mainmenu_option next_comment
comment 'Code maturity level options'
fi
fi
+source drivers/pcmcia/Config.in
+
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
# Automatically generated make config: don't edit
#
CONFIG_X86=y
+CONFIG_ISA=y
#
# Code maturity level options
# CONFIG_VISWS is not set
CONFIG_X86_IO_APIC=y
CONFIG_X86_LOCAL_APIC=y
+
+#
+# PCMCIA/Cardbus support
+#
+CONFIG_PCMCIA=y
+CONFIG_CARDBUS=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
}
}
#endif
- if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
+ if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0)
&& (apm_bios_info.version > 0x0100)) {
if (apm_engage_power_management(0x0001) == APM_SUCCESS)
apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
char saved_command_line[COMMAND_LINE_SIZE];
struct resource standard_io_resources[] = {
- { "dma1", 0x00, 0x1f },
- { "pic1", 0x20, 0x3f },
- { "timer", 0x40, 0x5f },
- { "keyboard", 0x60, 0x6f },
- { "dma page reg", 0x80, 0x8f },
- { "pic2", 0xa0, 0xbf },
- { "dma2", 0xc0, 0xdf },
- { "fpu", 0xf0, 0xff }
+ { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+ { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+ { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+ { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+ { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+ { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+ { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
};
#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
static struct resource ram_resources[] = {
{ "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
{ "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
- { "Video RAM area", 0x0a0000, 0x0bffff },
+ { "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY },
{ "Kernel code", 0x100000, 0 },
{ "Kernel data", 0, 0 }
};
#define MAXROMS 6
static struct resource rom_resources[MAXROMS] = {
{ "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
- { "Video ROM", 0xc0000, 0xc7fff }
+ { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
};
#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
rom_resources[roms].start = base;
rom_resources[roms].end = base + length - 1;
rom_resources[roms].name = "Extension ROM";
+ rom_resources[roms].flags = IORESOURCE_BUSY;
request_resource(&iomem_resource, rom_resources + roms);
roms++;
rom_resources[roms].start = base;
rom_resources[roms].end = base + 65535;
rom_resources[roms].name = "Extension ROM";
+ rom_resources[roms].flags = IORESOURCE_BUSY;
request_resource(&iomem_resource, rom_resources + roms);
}
memory_end = 0;
for (i=0; i < e820.nr_map; i++) {
+ printk("type=%d, addr=%08x, size=%08x",
+ e820.map[i].type,
+ e820.map[i].addr,
+ e820.map[i].size);
/* RAM? */
if (e820.map[i].type == 1) {
unsigned long end = e820.map[i].addr + e820.map[i].size;
{ \
tsk->thread.error_code = error_code; \
tsk->thread.trap_no = trapnr; \
- force_sig(signr, tsk); \
die_if_no_fixup(str,regs,error_code); \
+ force_sig(signr, tsk); \
}
#define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
* Head.S contains the MIPS exception handler and startup code.
*/
#include <linux/config.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <asm/asm.h>
#include <asm/cacheops.h>
#include "ppc_asm.tmpl"
#include "ppc_defs.h"
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/gemini.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/pci.h>
-#include <linux/stddef.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/major.h>
*
*/
-#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/unistd.h>
#include <linux/delay.h>
#include <linux/reboot.h>
* linux/arch/sh/kernel/ptrace.c
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/delay.h>
#include <linux/timex.h>
-#include <linux/config.h>
#include <linux/irq.h>
#define TMU_TOCR 0xfffffe90 /* Byte access */
* 'Traps.c' handles hardware traps and faults after we have saved some
* state in 'entry.S'.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/hardirq.h>
-#include <asm/uaccess.h> /* to get __m() macro */
#include <asm/mmu_context.h>
extern void die(const char *,struct pt_regs *,long);
/* ld script to make SuperH Linux kernel
* Written by Niibe Yutaka
*/
+#include <linux/config.h>
#ifdef CONFIG_LITTLE_ENDIAN
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
#else
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/ap1000/pgtapmmu.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/ap1000/apreg.h>
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
extern int cap_cid0;
extern unsigned _ncel, _ncelx, _ncely, _cid;
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
*/
#include <linux/kernel.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/init.h>
#include <linux/ioport.h>
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
SUB_DIRS += pci
endif
+ifdef CONFIG_PCMCIA
+SUB_DIRS += pcmcia
+endif
+
ifdef CONFIG_SBUS
SUB_DIRS += sbus
MOD_SUB_DIRS += sbus
}
}
-static void __init mod_setup(char *pattern, void (*setup)(char *))
+static void __init mod_setup(char *pattern, int (*setup)(char *))
{
unsigned long i;
char c;
byte ata66 = 0;
pci_read_config_byte(dev, 0x5a, &ata66);
- if (dev->rom_address)
- pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn));
return dev->irq;
}
/* Figure out how much data to transfer. */
thislen = pc->buflen;
- if (thislen < 0) thislen = -thislen;
if (thislen > len) thislen = len;
/* The drive wants to be written to. */
if ((ireason & 3) == 0) {
- /* Check that we want to write. */
- if (pc->buflen > 0) {
- printk ("%s: cdrom_pc_intr: Drive wants "
- "to transfer data the wrong way!\n",
- drive->name);
- pc->stat = 1;
- thislen = 0;
- }
-
/* Transfer the data. */
atapi_output_bytes (drive, pc->buffer, thislen);
/* Keep count of how much data we've moved. */
pc->buffer += thislen;
- pc->buflen += thislen;
+ pc->buflen -= thislen;
}
/* Same drill for reading. */
else if ((ireason & 3) == 2) {
- /* Check that we want to read. */
- if (pc->buflen < 0) {
- printk ("%s: cdrom_pc_intr: Drive wants to "
- "transfer data the wrong way!\n",
- drive->name);
- pc->stat = 1;
- thislen = 0;
- }
/* Transfer the data. */
atapi_input_bytes (drive, pc->buffer, thislen);
struct cdrom_info *info = drive->driver_data;
info->dma = 0;
-
- len = pc->buflen;
- if (len < 0) len = -len;
-
pc->stat = 0;
+ len = pc->buflen;
/* Start sending the command to the drive. */
cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
/* Now try to get the total cdrom capacity. */
+#if 0
stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major,
drive->select.b.unit << PARTN_BITS),
(long *)&toc->capacity);
- if (stat) stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
+ if (stat)
+#endif
+ stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
if (stat) toc->capacity = 0x1fffff;
HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
pc.sense_data = reqbuf;
pc.buffer = buf;
- pc.buflen = - buflen;
+ pc.buflen = buflen;
pc.c[0] = GPCMD_MODE_SELECT_10;
pc.c[1] = 0x10;
pc.c[2] = pageno;
return cgc->stat;
}
-
static
int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg)
MOD_DEC_USE_COUNT;
return 0;
}
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
* Make real block number available to downstream transfer functions, enables
* CBC (and relatives) mode encryption requiring unique IVs per data block.
* Reed H. Petty, rhp@draper.net
+ *
+ * Maximum number of loop devices now dynamic via max_loop module parameter.
+ * Still fixed at 8 devices when compiled into the kernel normally.
+ * Russell Kroll <rkroll@exploits.org> 19990701
*
* Still To Fix:
* - Advisory locking is ignored here.
#define TIMEOUT_VALUE (6 * HZ)
#include <linux/blk.h>
-#define MAX_LOOP 8
-static struct loop_device loop_dev[MAX_LOOP];
-static int loop_sizes[MAX_LOOP];
-static int loop_blksizes[MAX_LOOP];
+#include <linux/malloc.h>
+static int max_loop = 8;
+static struct loop_device *loop_dev;
+static int *loop_sizes;
+static int *loop_blksizes;
#define FALSE 0
#define TRUE (!FALSE)
INIT_REQUEST;
current_request=CURRENT;
CURRENT=current_request->next;
- if (MINOR(current_request->rq_dev) >= MAX_LOOP)
+ if (MINOR(current_request->rq_dev) >= max_loop)
goto error_out;
lo = &loop_dev[MINOR(current_request->rq_dev)];
if (!lo->lo_dentry || !lo->transfer)
return -ENODEV;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP)
+ if (dev >= max_loop)
return -ENODEV;
lo = &loop_dev[dev];
switch (cmd) {
return -ENODEV;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP) {
+ if (dev >= max_loop) {
return -ENODEV;
}
lo = &loop_dev[dev];
return 0;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP)
+ if (dev >= max_loop)
return 0;
err = fsync_dev(inode->i_rdev);
lo = &loop_dev[dev];
*/
#ifdef MODULE
#define loop_init init_module
+MODULE_PARM(max_loop, "i");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
#endif
int loop_register_transfer(struct loop_func_table *funcs)
if ((unsigned)number >= MAX_LO_CRYPT)
return -EINVAL;
- for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) {
+ for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
int type = lo->lo_encrypt_type;
if (type == number) {
xfer_funcs[type]->release(lo);
MAJOR_NR);
return -EIO;
}
+
+ if ((max_loop < 1) || (max_loop > 255)) {
+ printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n");
+ return -EINVAL;
+ }
+
#ifndef MODULE
printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
+#else
+ printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop);
#endif
+ loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL);
+ if (!loop_dev) {
+ printk (KERN_ERR "loop: Unable to create loop_dev\n");
+ return -ENOMEM;
+ }
+
+ loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+ if (!loop_sizes) {
+ printk (KERN_ERR "loop: Unable to create loop_sizes\n");
+ kfree (loop_dev);
+ return -ENOMEM;
+ }
+
+ loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL);
+ if (!loop_blksizes) {
+ printk (KERN_ERR "loop: Unable to create loop_blksizes\n");
+ kfree (loop_dev);
+ kfree (loop_sizes);
+ return -ENOMEM;
+ }
+
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- for (i=0; i < MAX_LOOP; i++) {
+ for (i=0; i < max_loop; i++) {
memset(&loop_dev[i], 0, sizeof(struct loop_device));
loop_dev[i].lo_number = i;
}
- memset(&loop_sizes, 0, sizeof(loop_sizes));
- memset(&loop_blksizes, 0, sizeof(loop_blksizes));
+ memset(loop_sizes, 0, max_loop * sizeof(int));
+ memset(loop_blksizes, 0, max_loop * sizeof(int));
blk_size[MAJOR_NR] = loop_sizes;
blksize_size[MAJOR_NR] = loop_blksizes;
{
if (unregister_blkdev(MAJOR_NR, "loop") != 0)
printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+
+ kfree (loop_dev);
+ kfree (loop_sizes);
+ kfree (loop_blksizes);
}
#endif
/* give people a warning shot, now that CDO_CHECK_TYPE
is the default case! */
cdinfo(CD_OPEN, "bummer. wrong media type.\n");
- cdinfo(CD_WARNING, "pid %d is buggy!\n", (unsigned int)current->pid);
+ cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
+ (unsigned int)current->pid);
ret=-EMEDIUMTYPE;
goto clean_up_and_return;
}
case DVD_HOST_SEND_CHALLENGE:
cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n");
setup_send_key (&cgc, ai->hsc.agid, 1);
- cgc.buflen = -(cgc.cmd[9] = 16);
+ cgc.buflen = cgc.cmd[9] = 16;
buf[1] = 14;
copy_chal (&buf[4], ai->hsc.chal);
case DVD_HOST_SEND_KEY2:
cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n");
setup_send_key (&cgc, ai->hsk.agid, 3);
- cgc.buflen = -(cgc.cmd[9] = 12);
+ cgc.buflen = cgc.cmd[9] = 12;
buf[1] = 10;
copy_key (&buf[4], ai->hsk.key);
cgc->cmd[0] = GPCMD_MODE_SELECT_10;
cgc->cmd[1] = 0x10; /* PF */
-
- /* generic_packet() wants the length as seen from the drive, i.e.
- it will transfer data _to_ us. The CD-ROM wants the absolute
- value, however. */
- cgc->cmd[7] = (-cgc->buflen) >> 8;
- cgc->cmd[8] = (-cgc->buflen) & 0xff;
-
+ cgc->cmd[7] = cgc->buflen >> 8;
+ cgc->cmd[8] = cgc->buflen & 0xff;
return cdo->generic_packet(cdi, cgc);
}
memset(buffer, 0, 3);
/* set volume */
- cgc.buflen = -cgc.buflen;
cgc.buffer = buffer;
return cdrom_mode_select(cdi, &cgc);
}
}
#endif /* endif MODULE */
-
-
-
-/*
- * Local variables:
- * comment-column: 40
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c"
- * End:
- */
dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
- dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+ if [ "$CONFIG_PPC" = "y" ; then
+ dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+ fi
fi
tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
#endif /* MODULE */
-__initfunc(int applicom_init(void))
+int __init applicom_init(void)
{
int i, numisa=0;
struct pci_dev *dev = NULL;
* istallion.c -- stallion intelligent multiport serial driver.
*
* Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
*/
static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
static char *stli_drvname = "istallion";
-static char *stli_drvversion = "5.5.1";
+static char *stli_drvversion = "5.6.0";
static char *stli_serialname = "ttyE";
static char *stli_calloutname = "cue";
* is already swapping a shared buffer won't make things any worse.
*/
static char *stli_tmpwritebuf = (char *) NULL;
-static struct semaphore stli_tmpwritesem = MUTEX;
+static DECLARE_MUTEX(stli_tmpwritesem);
#define STLI_TXBUFSIZE 4096
portp->closing_wait = 30 * HZ;
portp->tqhangup.routine = stli_dohangup;
portp->tqhangup.data = portp;
+ init_waitqueue_head(&portp->open_wait);
+ init_waitqueue_head(&portp->close_wait);
+ init_waitqueue_head(&portp->raw_wait);
portp->normaltermios = stli_deftermios;
portp->callouttermios = stli_deftermios;
panelport++;
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
- devp->base_address[0], devp->base_address[1],
- devp->base_address[2], devp->base_address[3]);
+ devp->resource[0].start, devp->resource[1].start,
+ devp->resource[2].start, devp->resource[3].start);
#endif
/*
* We have all resources from the board, so lets setup the actual
* board structure now.
*/
- brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK);
- brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+ brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
stli_brdinit(brdp);
return(0);
#include <linux/malloc.h>
#include <linux/tty.h>
#include <linux/errno.h>
-#include <linux/sched.h> /* to get the struct task_struct */
#include <linux/string.h> /* used in new tty drivers */
#include <linux/signal.h> /* used in new tty drivers */
#include <linux/ioctl.h>
#endif /* MODULE */
-__initfunc(static int r3964_init(void))
+static int __init r3964_init(void)
{
int status;
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
-#include <linux/module.h>
#else /* !NEW_MODULES */
#ifdef MODVERSIONS
#define MODULE
#endif
-#include <linux/module.h>
#endif /* NEW_MODULES */
+#include <linux/module.h>
#ifdef LOCAL_HEADERS
#include "serial_local.h"
* stallion.c -- stallion multiport serial driver.
*
* Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
*/
static char *stl_drvtitle = "Stallion Multiport Serial Driver";
static char *stl_drvname = "stallion";
-static char *stl_drvversion = "5.5.1";
+static char *stl_drvversion = "5.6.0";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
break;
}
if (i >= stl_numintrs) {
- if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+ if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, irq);
rc = -ENODEV;
portp->callouttermios = stl_deftermios;
portp->tqueue.routine = stl_offintr;
portp->tqueue.data = portp;
+ init_waitqueue_head(&portp->open_wait);
+ init_waitqueue_head(&portp->close_wait);
portp->stats.brd = portp->brdnr;
portp->stats.panel = portp->panelnr;
portp->stats.port = portp->portnr;
#if DEBUG
printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
- dev->bus->number, dev->devfn);
+ devp->bus->number, devp->devfn);
#endif
if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
*/
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- devp->base_address[0], devp->base_address[1],
- devp->base_address[2], devp->base_address[3], devp->irq);
+ devp->resource[0].start, devp->resource[1].start,
+ devp->resource[2].start, devp->resource[3].start, devp->irq);
#endif
/*
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = (devp->base_address[0] &
+ brdp->ioaddr2 = (devp->resource[0].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->base_address[1] &
+ brdp->ioaddr1 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = (devp->base_address[2] &
+ brdp->ioaddr2 = (devp->resource[2].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->base_address[1] &
+ brdp->ioaddr1 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = (devp->base_address[2] &
+ brdp->ioaddr1 = (devp->resource[2].start &
PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr2 = (devp->base_address[1] &
+ brdp->ioaddr2 = (devp->resource[1].start &
PCI_BASE_ADDRESS_IO_MASK);
break;
default:
if ((tty == (struct tty_struct *) NULL) ||
(tty->flip.char_buf_ptr == (char *) NULL) ||
((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ len = MIN(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
if ((tty == (struct tty_struct *) NULL) ||
(tty->flip.char_buf_ptr == (char *) NULL) ||
((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ len = MIN(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
/* Skip I/O spaces */
if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE))
{
- memptr=dev->resource[i].flags;
+ memptr=dev->resource[i].start;
break;
}
}
if(i==6)
{
printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n");
- return -ENOMEM;
+ kfree(c);
+ return -EINVAL;
}
size = dev->resource[i].end-dev->resource[i].start+1;
/* Map the I2O controller */
- printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size);
- mem = ioremap(memptr, -size);
+ printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+ mem = ioremap(memptr, size);
+ if(mem==NULL)
+ {
+ printk(KERN_ERR "i2o_pci: Unable to map controller.\n");
+ kfree(c);
+ return -EINVAL;
+ }
c->bus.pci.irq = -1;
if(i<0)
{
printk(KERN_ERR "i2o: unable to install controller.\n");
+ kfree(c);
+ iounmap(mem);
return i;
}
core->delete(c);
#else
i2o_delete_controller(c);
-#endif /* MODULE */
+#endif /* MODULE */
+ kfree(c);
+ iofree(mem);
return -EBUSY;
}
}
}
printk(KERN_INFO "I2O controller on bus %d at %d.\n",
dev->bus->number, dev->devfn);
- if(!dev->master)
- printk(KERN_WARNING "Controller not master enabled.\n");
+ pci_set_master(dev);
if(i2o_pci_install(dev)==0)
count++;
}
return 0;
}
-static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
{
struct i2o_device *unit;
struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
#define eicon_init init_module
#endif
-__initfunc(int
-eicon_init(void))
+int __init
+eicon_init(void)
{
int card_count = 0;
int release = 0;
str = get_options(line, 4, ints);
#else
-__initfunc(void
-eicon_setup(char *str, int *ints))
+void __init
+eicon_setup(char *str, int *ints)
{
int i, argc;
#endif
return(0);
}
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
return(0);
}
-__initfunc(int
-setup_avm_a1(struct IsdnCard *card))
+int __init
+setup_avm_a1(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
return 0;
}
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int __init
+setup_avm_a1_pcmcia(struct IsdnCard *card)
{
u_char model, vers;
struct IsdnCardState *cs = card->cs;
static int pci_index __initdata = 0;
#endif
-__initfunc(int
-setup_avm_pcipnp(struct IsdnCard *card))
+int __init
+setup_avm_pcipnp(struct IsdnCard *card)
{
u_int val, ver;
struct IsdnCardState *cs = card->cs;
static int pci_index __initdata = 0;
#endif
-__initfunc(int
- setup_bkm_a4t(struct IsdnCard *card))
+int __init
+ setup_bkm_a4t(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
static int pci_index __initdata = 0;
#endif
-__initfunc(int
- setup_sct_quadro(struct IsdnCard *card))
+int __init
+ setup_sct_quadro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
str = get_options(line, MAX_ARG, ints);
#else
-__initfunc(void
-HiSax_setup(char *str, int *ints))
+void __init
+HiSax_setup(char *str, int *ints)
{
int i, j, argc;
#endif
}
-__initfunc(int
-HiSax_init(void))
+int __init
+HiSax_init(void)
{
int i;
static int pci_index __initdata = 0;
#endif
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init
+setup_diva(struct IsdnCard *card)
{
int bytecnt;
u_char val;
return (0);
}
-__initfunc(int
- setup_gazel(struct IsdnCard *card))
+int __init
+ setup_gazel(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
#endif
}
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int * __init
+init_send_hfcd(int cnt)
{
int i, *send;
return(send);
}
-__initfunc(void
-init2bds0(struct IsdnCardState *cs))
+void __init
+init2bds0(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcd;
cs->dbusytimer.function = (void *) hfc_dbusy_timer;
return (0);
}
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
{
int i;
bcs->hw.hfc.send[i] = 0x1fff;
}
-__initfunc(void
-inithfc(struct IsdnCardState *cs))
+void __init
+inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
init_send(&cs->bcs[1]);
/*************************************/
/* Alloc memory send data for queues */
/*************************************/
-__initfunc(unsigned int
- *init_send_hfcpci(int cnt))
+unsigned int * __init
+ init_send_hfcpci(int cnt)
{
int i, *send;
/********************************/
/* called for card init message */
/********************************/
-__initfunc(void
- inithfcpci(struct IsdnCardState *cs))
+void __init
+ inithfcpci(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcpci;
cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
#endif /* CONFIG_PCI */
-__initfunc(int
- setup_hfcpci(struct IsdnCard *card))
+int __init
+ setup_hfcpci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
#define __initdata
#endif
+#ifndef __init
+#define __init
+#endif
+
#define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
#define HISAX_INITDATA __initdata
return(isar_auxcmd(cs, ic));
}
-__initfunc(int
-setup_isurf(struct IsdnCard *card))
+int __init
+setup_isurf(struct IsdnCard *card)
{
int ver;
struct IsdnCardState *cs = card->cs;
}
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
}
-__initfunc(void
-inittiger(struct IsdnCardState *cs))
+void __init
+inittiger(struct IsdnCardState *cs)
{
if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
GFP_KERNEL | GFP_DMA))) {
static int pci_index __initdata = 0;
#endif
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
+int __init
+setup_netjet(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
static int pci_index __initdata = 0;
#endif
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init
+setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
}
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
#endif
#endif
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int __init
+setup_sedlbauer(struct IsdnCard *card)
{
int bytecnt, ver, val;
struct IsdnCardState *cs = card->cs;
return(0);
}
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+int __init
+get_io_range(struct IsdnCardState *cs)
{
int i, j, adr;
}
}
-__initfunc(int
-setup_sportster(struct IsdnCard *card))
+int __init
+setup_sportster(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
return(0);
}
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
return(0);
}
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int __init
+setup_teles3(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
static int pci_index __initdata = 0;
#endif
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
/* Get I/O base address from PCI Configuration Space */
- port = pdev->resource[1].start
+ port = pdev->resource[1].start;
/* Verify port address range is not already being used */
#else
#define __init
#define __initdata
-#define __initfunc(x) x
#endif
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
-__initfunc(int yam_init(struct net_device *dev))
+int __init yam_init(struct net_device *dev)
{
int i;
#endif
-__initfunc(int init_module(void))
+int init_module(void)
{
int ret = yam_init(NULL);
* ==FILEVERSION 990806==
*/
-/* $Id$ */
+/* $Id: ppp_async.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */
#include <linux/module.h>
#include <linux/kernel.h>
/* stuff the chars in the skb */
skb = ap->rpkt;
if (skb == 0) {
- skb = alloc_skb(ap->mru + PPP_HDRLEN + 2,
- GFP_ATOMIC);
+ skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
if (skb == 0)
goto nomem;
/* Try to get the payload 4-byte aligned */
* ==FILEVERSION 990806==
*/
-/* $Id$ */
+/* $Id: ppp_generic.c,v 1.3 1999/09/02 05:30:12 paulus Exp $ */
#include <linux/config.h>
#include <linux/module.h>
void *rc_state; /* its internal state */
unsigned long last_xmit; /* jiffies when last pkt sent */
unsigned long last_recv; /* jiffies when last pkt rcvd */
- struct net_device dev; /* network interface device */
+ struct net_device *dev; /* network interface device */
struct net_device_stats stats; /* statistics */
};
static struct compressor *find_compressor(int type);
static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
static struct ppp *ppp_create_unit(int unit, int *retp);
+static void ppp_release_unit(struct ppp *ppp);
static struct ppp *ppp_find_unit(int unit);
/* Translates a PPP protocol number to a NP index (NP == network protocol) */
static int ppp_release(struct inode *inode, struct file *file)
{
struct ppp *ppp = (struct ppp *) file->private_data;
- struct list_head *list, *next;
- int ref;
-
- if (ppp == 0)
- goto out;
- file->private_data = 0;
- spin_lock(&all_ppp_lock);
- ref = --ppp->refcnt;
- if (ref == 0)
- list_del(&ppp->list);
- spin_unlock(&all_ppp_lock);
- if (ref != 0)
- goto out;
- /* Last fd open to this ppp unit is being closed -
- mark the interface down, free the ppp unit */
- rtnl_lock();
- dev_close(&ppp->dev);
- rtnl_unlock();
- for (list = ppp->channels.next; list != &ppp->channels; list = next) {
- /* forcibly detach this channel */
- struct channel *chan;
- chan = list_entry(list, struct channel, list);
- chan->chan->ppp = 0;
- next = list->next;
- kfree(chan);
+ if (ppp != 0) {
+ file->private_data = 0;
+ ppp_release_unit(ppp);
}
-
- /* Free up resources. */
- ppp_ccp_closed(ppp);
- lock_xmit_path(ppp);
- lock_recv_path(ppp);
- if (ppp->vj) {
- slhc_free(ppp->vj);
- ppp->vj = 0;
- }
- free_skbs(&ppp->xq);
- free_skbs(&ppp->rq);
- free_skbs(&ppp->recv_pending);
- unregister_netdev(&ppp->dev);
- kfree(ppp);
-
- out:
MOD_DEC_USE_COUNT;
return 0;
}
return -ENXIO;
err = -EFAULT;
switch (cmd) {
+ case PPPIOCDETACH:
+ file->private_data = 0;
+ ppp_release_unit(ppp);
+ err = 0;
+ break;
+
case PPPIOCSMRU:
if (get_user(val, (int *) arg))
break;
/* try to do packet compression */
if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
&& proto != PPP_LCP && proto != PPP_CCP) {
- new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC);
+ new_skb = alloc_skb(ppp->dev->mtu + PPP_HDRLEN, GFP_ATOMIC);
if (new_skb == 0) {
printk(KERN_ERR "PPP: no memory (comp pkt)\n");
goto drop;
/* compressor still expects A/C bytes in hdr */
len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
new_skb->data, skb->len + 2,
- ppp->dev.mtu + PPP_HDRLEN);
+ ppp->dev->mtu + PPP_HDRLEN);
if (len > 0 && (ppp->flags & SC_CCP_UP)) {
kfree_skb(skb);
skb = new_skb;
}
}
+ /* for data packets, record the time */
+ if (proto < 0x8000)
+ ppp->last_xmit = jiffies;
+
/*
* If we are waiting for traffic (demand dialling),
* queue it up for pppd to receive.
goto err;
if (skb_tailroom(skb) < 124) {
/* copy to a new sk_buff with more tailroom */
- ns = alloc_skb(skb->len + 128, GFP_ATOMIC);
+ ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) {
printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
goto err;
} else {
/* network protocol frame - give it to the kernel */
ppp->last_recv = jiffies;
- if ((ppp->dev.flags & IFF_UP) == 0
+ if ((ppp->dev->flags & IFF_UP) == 0
|| ppp->npmode[npi] != NPMODE_PASS) {
kfree_skb(skb);
} else {
skb_pull(skb, 2); /* chop off protocol */
- skb->dev = &ppp->dev;
+ skb->dev = ppp->dev;
skb->protocol = htons(npindex_to_ethertype[npi]);
skb->mac.raw = skb->data;
netif_rx(skb);
int len;
if (proto == PPP_COMP) {
- ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+ ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
if (ns == 0) {
printk(KERN_ERR "ppp_receive: no memory\n");
goto err;
if (trylock_xmit_path(ppp))
ppp_xmit_unlock(ppp);
if (ppp->xmit_pending == 0) {
- ppp->dev.tbusy = 0;
+ ppp->dev->tbusy = 0;
mark_bh(NET_BH);
}
}
ppp_create_unit(int unit, int *retp)
{
struct ppp *ppp;
+ struct net_device *dev;
struct list_head *list;
int last_unit = -1;
int ret = -EEXIST;
if (ppp == 0)
goto out;
memset(ppp, 0, sizeof(struct ppp));
+ dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (dev == 0) {
+ kfree(ppp);
+ goto out;
+ }
+ memset(dev, 0, sizeof(struct net_device));
ppp->index = unit;
sprintf(ppp->name, "ppp%d", unit);
INIT_LIST_HEAD(&ppp->channels);
skb_queue_head_init(&ppp->recv_pending);
- ppp->dev.init = ppp_net_init;
- ppp->dev.name = ppp->name;
- ppp->dev.priv = ppp;
+ ppp->dev = dev;
+ dev->init = ppp_net_init;
+ dev->name = ppp->name;
+ dev->priv = ppp;
+ dev->new_style = 1;
- ret = register_netdev(&ppp->dev);
+ rtnl_lock();
+ ret = register_netdevice(dev);
+ rtnl_unlock();
if (ret != 0) {
printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
+ kfree(dev);
kfree(ppp);
goto out;
}
return ppp;
}
+/*
+ * Remove a reference to a ppp unit, and destroy it if
+ * the reference count goes to 0.
+ */
+static void ppp_release_unit(struct ppp *ppp)
+{
+ struct list_head *list, *next;
+ int ref;
+
+ spin_lock(&all_ppp_lock);
+ ref = --ppp->refcnt;
+ if (ref == 0)
+ list_del(&ppp->list);
+ spin_unlock(&all_ppp_lock);
+ if (ref != 0)
+ return;
+
+ /* Last fd open to this ppp unit is being closed or detached:
+ mark the interface down, free the ppp unit */
+ if (ppp->dev) {
+ rtnl_lock();
+ dev_close(ppp->dev);
+ rtnl_unlock();
+ }
+ for (list = ppp->channels.next; list != &ppp->channels; list = next) {
+ /* forcibly detach this channel */
+ struct channel *chan;
+ chan = list_entry(list, struct channel, list);
+ chan->chan->ppp = 0;
+ next = list->next;
+ kfree(chan);
+ }
+
+ /* Free up resources. */
+ ppp_ccp_closed(ppp);
+ lock_xmit_path(ppp);
+ lock_recv_path(ppp);
+ if (ppp->vj) {
+ slhc_free(ppp->vj);
+ ppp->vj = 0;
+ }
+ free_skbs(&ppp->xq);
+ free_skbs(&ppp->rq);
+ free_skbs(&ppp->recv_pending);
+ if (ppp->dev) {
+ rtnl_lock();
+ unregister_netdevice(ppp->dev);
+ ppp->dev = 0;
+ rtnl_unlock();
+ }
+ kfree(ppp);
+}
+
/*
* Locate an existing ppp unit.
* The caller should have locked the all_ppp_lock.
cleanup_module(void)
{
/* should never happen */
- if (all_ppp_units.next != &all_ppp_units)
+ if (!list_empty(&all_ppp_units))
printk(KERN_ERR "PPP: removing module but units remain!\n");
if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
printk(KERN_ERR "PPP: failed to unregister PPP device\n");
L_OBJS += proc.o
endif
-L_OBJS += compat.o quirks.o names.o
+L_OBJS += compat.o quirks.o names.o syscall.o setup.o
include $(TOPDIR)/Rules.make
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
-static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
{
u8 io_base_lo, io_limit_lo;
u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
child->primary = bus->secondary;
child->subordinate = 0xff;
sprintf(child->name, "PCI Bus #%02x", child->number);
- pci_read_bridge_bases(dev, child);
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
struct resource *r = &dev->resource[0];
if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
- printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name);
r->start = 0;
r->end = 0x3ffffff;
- if (pcibios_assign_resource(dev, 0))
- printk("FAILED\n");
- else
- printk("moved to %08lx\n", r->start);
}
}
* quantity.
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs },
- { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M },
- { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M },
{ 0 }
};
--- /dev/null
+/*
+ * drivers/pci/setup.c
+ *
+ * Extruded from code written by
+ * Dave Rusling (david.rusling@reo.mts.dec.com)
+ * David Mosberger (davidm@cs.arizona.edu)
+ * David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+#include <asm/cache.h>
+#include <asm/pci.h>
+
+
+#define DEBUG_CONFIG 0
+#if DEBUG_CONFIG
+# define DBGC(args) printk args
+#else
+# define DBGC(args)
+#endif
+
+
+int __init
+pci_claim_resource(struct pci_dev *dev, int resource)
+{
+ struct resource *res = &dev->resource[resource];
+ struct resource *root = pci_find_parent_resource(dev, res);
+ int err;
+
+ err = -EINVAL;
+ if (root != NULL) {
+ /* If `dev' is on a secondary pci bus, `root' may not be
+ at the origin. In that case, adjust the resource into
+ range. */
+ res->start += root->start;
+ res->end += root->start;
+
+ err = request_resource(root, res);
+ }
+ if (err) {
+ printk(KERN_ERR "PCI: Address space collision on region %d "
+ "of device %s\n", resource, dev->name);
+ }
+
+ return err;
+}
+
+static void
+pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem)
+{
+ u32 reg;
+ u16 cmd;
+ int i;
+
+ DBGC(("PCI assign unassigned: (%s)\n", dev->name));
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *root, *res;
+ unsigned long size, min;
+
+ res = &dev->resource[i];
+
+ if (res->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ else if (res->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+
+ /* If it is already assigned or the resource does
+ not exist, there is nothing to do. */
+ if (res->parent != NULL || res->flags == 0)
+ continue;
+
+ /* Determine the root we allocate from. */
+ root = pci_find_parent_resource(dev, res);
+ if (root == NULL)
+ continue;
+
+ min = (res->flags & IORESOURCE_IO ? min_io : min_mem);
+ min += root->start;
+ size = res->end - res->start + 1;
+
+ DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n",
+ root->start, root->end, min, size));
+
+ if (allocate_resource(root, res, size, min, -1, size) < 0) {
+ printk(KERN_ERR
+ "PCI: Failed to allocate resource %d for %s\n",
+ i, dev->name);
+ continue;
+ }
+
+ DBGC((" got res[%lx:%lx] for resource %d\n",
+ res->start, res->end, i));
+
+ /* Update PCI config space. */
+ pcibios_update_resource(dev, root, res, i);
+ }
+
+ /* Special case, disable the ROM. Several devices act funny
+ (ie. do not respond to memory space writes) when it is left
+ enabled. A good example are QlogicISP adapters. */
+
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®);
+ reg &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
+
+ /* All of these (may) have I/O scattered all around and may not
+ use I/O base address registers at all. So we just have to
+ always enable IO to these devices. */
+ if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
+ || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
+ || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
+ || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+ cmd |= PCI_COMMAND_IO;
+ }
+
+ /* ??? Always turn on bus mastering. If the device doesn't support
+ it, the bit will go into the bucket. */
+ cmd |= PCI_COMMAND_MASTER;
+
+ /* Enable the appropriate bits in the PCI command register. */
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ DBGC((" cmd reg 0x%x\n", cmd));
+
+ /* If this is a PCI bridge, set the cache line correctly. */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+ (L1_CACHE_BYTES / sizeof(u32)));
+ }
+}
+
+void __init
+pci_assign_unassigned_resources(u32 min_io, u32 min_mem)
+{
+ struct pci_dev *dev;
+ for (dev = pci_devices; dev; dev = dev->next)
+ pdev_assign_unassigned_resources(dev, min_io, min_mem);
+}
+
+struct pbus_set_ranges_data
+{
+ int found_vga;
+ unsigned int io_start, io_end;
+ unsigned int mem_start, mem_end;
+};
+
+#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
+
+static void __init
+pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+ struct pbus_set_ranges_data inner;
+ struct pci_bus *child;
+ struct pci_dev *dev;
+
+ inner.found_vga = 0;
+ inner.mem_start = inner.io_start = ~0;
+ inner.mem_end = inner.io_end = 0;
+
+ /* Collect information about how our direct children are layed out. */
+ for (dev = bus->devices; dev; dev = dev->sibling) {
+ int i;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+ if (res->flags & IORESOURCE_IO) {
+ if (res->start < inner.io_start)
+ inner.io_start = res->start;
+ if (res->end > inner.io_end)
+ inner.io_end = res->end;
+ } else if (res->flags & IORESOURCE_MEM) {
+ if (res->start < inner.mem_start)
+ inner.mem_start = res->start;
+ if (res->end > inner.mem_end)
+ inner.mem_end = res->end;
+ }
+ }
+ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+ inner.found_vga = 1;
+ }
+
+ /* And for all of the sub-busses. */
+ for (child = bus->children; child; child = child->next)
+ pbus_set_ranges(child, &inner);
+
+ /* Align the values. */
+ inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
+ inner.io_end = ROUND_UP(inner.io_end, 4*1024);
+
+ inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024);
+ inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+ /* Configure the bridge, if possible. */
+ if (bus->self) {
+ struct pci_dev *bridge = bus->self;
+ u32 l;
+
+ /* Set up the top and bottom of the PCI I/O segment
+ for this bus. */
+ pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+ l &= 0xffff0000;
+ l |= (inner.io_start >> 8) & 0x00f0;
+ l |= (inner.io_end - 1) & 0xf000;
+ pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+ /*
+ * Clear out the upper 16 bits of IO base/limit.
+ * Clear out the upper 32 bits of PREF base/limit.
+ */
+ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+ /* Set up the top and bottom of the PCI Memory segment
+ for this bus. */
+ l = (inner.mem_start & 0xfff00000) >> 16;
+ l |= (inner.mem_end - 1) & 0xfff00000;
+ pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+ /*
+ * Turn off downstream PF memory address range, unless
+ * there is a VGA behind this bridge, in which case, we
+ * enable the PREFETCH range to include BIOS ROM at C0000.
+ *
+ * NOTE: this is a bit of a hack, done with PREFETCH for
+ * simplicity, rather than having to add it into the above
+ * non-PREFETCH range, which could then be bigger than we want.
+ * We might assume that we could relocate the BIOS ROM, but
+ * that would depend on having it found by those who need it
+ * (the DEC BIOS emulator would find it, but I do not know
+ * about the Xservers). So, we do it this way for now... ;-)
+ */
+ l = (inner.found_vga) ? 0 : 0x0000ffff;
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+ /*
+ * Tell bridge that there is an ISA bus in the system,
+ * and (possibly) a VGA as well.
+ */
+ l = (inner.found_vga) ? 0x0c : 0x04;
+ pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
+
+ /*
+ * Clear status bits,
+ * turn on I/O enable (for downstream I/O),
+ * turn on memory enable (for downstream memory),
+ * turn on master enable (for upstream memory and I/O).
+ */
+ pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
+ }
+
+ if (outer) {
+ outer->found_vga |= inner.found_vga;
+ if (inner.io_start < outer->io_start)
+ outer->io_start = inner.io_start;
+ if (inner.io_end > outer->io_end)
+ outer->io_end = inner.io_end;
+ if (inner.mem_start < outer->mem_start)
+ outer->mem_start = inner.mem_start;
+ if (inner.mem_end > outer->mem_end)
+ outer->mem_end = inner.mem_end;
+ }
+}
+
+void __init
+pci_set_bus_ranges(void)
+{
+ struct pci_bus *bus;
+ for (bus = pci_root; bus; bus = bus->next)
+ pbus_set_ranges(bus, NULL);
+}
+
+static void
+pdev_fixup_irq(struct pci_dev *dev,
+ u8 (*swizzle)(struct pci_dev *, u8 *),
+ int (*map_irq)(struct pci_dev *, u8, u8))
+{
+ u8 pin, slot;
+ int irq;
+
+ /* If this device is not on the primary bus, we need to figure out
+ which interrupt pin it will come in on. We know which slot it
+ will come in on 'cos that slot is where the bridge is. Each
+ time the interrupt line passes through a PCI-PCI bridge we must
+ apply the swizzle function. */
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ /* Cope with 0 and illegal. */
+ if (pin == 0 || pin > 4)
+ pin = 1;
+
+ /* Follow the chain of bridges, swizzling as we go. */
+ slot = (*swizzle)(dev, &pin);
+
+ irq = (*map_irq)(dev, slot, pin);
+ if (irq == -1)
+ irq = 0;
+ dev->irq = irq;
+
+ DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
+
+ /* Always tell the device, so the driver knows what is
+ the real IRQ to use; the device does not use it. */
+ pcibios_update_irq(dev, irq);
+}
+
+void __init
+pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
+ int (*map_irq)(struct pci_dev *, u8, u8))
+{
+ struct pci_dev *dev;
+ for (dev = pci_devices; dev; dev = dev->next)
+ pdev_fixup_irq(dev, swizzle, map_irq);
+}
--- /dev/null
+/*
+ * pci_syscall.c
+ *
+ * For architectures where we want to allow direct access
+ * to the PCI config stuff - it would probably be preferable
+ * on PCs too, but there people just do it by hand with the
+ * magic northbridge registers..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ struct pci_dev *dev;
+ u8 byte;
+ u16 word;
+ u32 dword;
+ long err, cfg_ret;
+
+ err = -EPERM;
+ if (!capable(CAP_SYS_ADMIN))
+ goto error;
+
+ err = -ENODEV;
+ dev = pci_find_slot(bus, dfn);
+ if (!dev)
+ goto error;
+
+ lock_kernel();
+ switch (len) {
+ case 1:
+ cfg_ret = pci_read_config_byte(dev, off, &byte);
+ break;
+ case 2:
+ cfg_ret = pci_read_config_word(dev, off, &word);
+ break;
+ case 4:
+ cfg_ret = pci_read_config_dword(dev, off, &dword);
+ break;
+ default:
+ err = -EINVAL;
+ unlock_kernel();
+ goto error;
+ };
+ unlock_kernel();
+
+ err = -EIO;
+ if (cfg_ret != PCIBIOS_SUCCESSFUL)
+ goto error;
+
+ switch (len) {
+ case 1:
+ err = put_user(byte, (unsigned char *)buf);
+ break;
+ case 2:
+ err = put_user(word, (unsigned short *)buf);
+ break;
+ case 4:
+ err = put_user(dword, (unsigned int *)buf);
+ break;
+ };
+ return err;
+
+error:
+ /* ??? XFree86 doesn't even check the return value. They
+ just look for 0xffffffff in the output, since that's what
+ they get instead of a machine check on x86. */
+ switch (len) {
+ case 1:
+ put_user(-1, (unsigned char *)buf);
+ break;
+ case 2:
+ put_user(-1, (unsigned short *)buf);
+ break;
+ case 4:
+ put_user(-1, (unsigned int *)buf);
+ break;
+ };
+ return err;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ struct pci_dev *dev;
+ u8 byte;
+ u16 word;
+ u32 dword;
+ int err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!pcibios_present())
+ return -ENOSYS;
+
+ dev = pci_find_slot(bus, dfn);
+ if (!dev)
+ return -ENODEV;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ err = get_user(byte, (u8 *)buf);
+ if (err)
+ break;
+ err = pci_write_config_byte(dev, off, byte);
+ if (err != PCIBIOS_SUCCESSFUL)
+ err = -EIO;
+ break;
+
+ case 2:
+ err = get_user(word, (u16 *)buf);
+ if (err)
+ break;
+ err = pci_write_config_byte(dev, off, word);
+ if (err != PCIBIOS_SUCCESSFUL)
+ err = -EIO;
+ break;
+
+ case 4:
+ err = get_user(dword, (u32 *)buf);
+ if (err)
+ break;
+ pci_write_config_byte(dev, off, dword);
+ if (err != PCIBIOS_SUCCESSFUL)
+ err = -EIO;
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ unlock_kernel();
+
+ return err;
+}
--- /dev/null
+#
+# PCMCIA bus subsystem configuration
+#
+mainmenu_option next_comment
+comment 'PCMCIA/Cardbus support'
+
+tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+ bool ' CardBus support' CONFIG_CARDBUS
+fi
+
+endmenu
--- /dev/null
+#
+# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := pcmcia.o
+
+O_OBJS := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o
+OX_OBJS := ds.o cs.o
+
+ifeq ($(CONFIG_CARDBUS),y)
+ O_OBJS += cardbus.o
+else
+ ifeq ($(CONFIG_CARDBUS),m)
+ MX_OBJS += cardbus.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*======================================================================
+
+ PCMCIA Bulk Memory Services
+
+ bulkmem.c 1.29 1999/08/28 04:01:45
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+/*======================================================================
+
+ This function handles submitting an MTD request, and retrying
+ requests when an MTD is busy.
+
+ An MTD request should never block.
+
+======================================================================*/
+
+static int do_mtd_request(memory_handle_t handle, mtd_request_t *req,
+ caddr_t buf)
+{
+ int ret, tries;
+ client_t *mtd;
+ socket_info_t *s;
+
+ mtd = handle->mtd;
+ if (mtd == NULL)
+ return CS_GENERAL_FAILURE;
+ s = SOCKET(mtd);
+ for (tries = 0; tries < 100; tries++) {
+ mtd->event_callback_args.mtdrequest = req;
+ mtd->event_callback_args.buffer = buf;
+ ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret != CS_BUSY)
+ break;
+ switch (req->Status) {
+ case MTD_WAITREQ:
+ /* Not that we should ever need this... */
+ interruptible_sleep_on_timeout(&mtd->mtd_req, HZ);
+ break;
+ case MTD_WAITTIMER:
+ case MTD_WAITRDY:
+ interruptible_sleep_on_timeout(&mtd->mtd_req, req->Timeout*HZ/1000);
+ req->Function |= MTD_REQ_TIMEOUT;
+ break;
+ case MTD_WAITPOWER:
+ interruptible_sleep_on(&mtd->mtd_req);
+ break;
+ }
+ if (signal_pending(current))
+ printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
+ }
+ if (tries == 20) {
+ printk(KERN_NOTICE "cs: MTD request timed out!\n");
+ ret = CS_GENERAL_FAILURE;
+ }
+ wake_up_interruptible(&mtd->mtd_req);
+ retry_erase_list(&mtd->erase_busy, 0);
+ return ret;
+} /* do_mtd_request */
+
+/*======================================================================
+
+ This stuff is all for handling asynchronous erase requests. It
+ is complicated because all the retry stuff has to be dealt with
+ in timer interrupts or in the card status event handler.
+
+======================================================================*/
+
+static void insert_queue(erase_busy_t *head, erase_busy_t *entry)
+{
+ DEBUG(2, ("cs: adding 0x%p to queue 0x%p\n", entry, head));
+ entry->next = head;
+ entry->prev = head->prev;
+ head->prev->next = entry;
+ head->prev = entry;
+}
+
+static void remove_queue(erase_busy_t *entry)
+{
+ DEBUG(2, ("cs: unqueueing 0x%p\n", entry));
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+}
+
+static void retry_erase(erase_busy_t *busy, u_int cause)
+{
+ eraseq_entry_t *erase = busy->erase;
+ mtd_request_t req;
+ client_t *mtd;
+ socket_info_t *s;
+ int ret;
+
+ DEBUG(2, ("cs: trying erase request 0x%p...\n", busy));
+ if (busy->next)
+ remove_queue(busy);
+ req.Function = MTD_REQ_ERASE | cause;
+ req.TransferLength = erase->Size;
+ req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
+ req.MediaID = erase->Handle->MediaID;
+ mtd = erase->Handle->mtd;
+ s = SOCKET(mtd);
+ mtd->event_callback_args.mtdrequest = &req;
+ ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret == CS_BUSY) {
+ DEBUG(2, (" Status = %d, requeueing.\n", req.Status));
+ switch (req.Status) {
+ case MTD_WAITREQ:
+ case MTD_WAITPOWER:
+ insert_queue(&mtd->erase_busy, busy);
+ break;
+ case MTD_WAITTIMER:
+ case MTD_WAITRDY:
+ if (req.Status == MTD_WAITRDY)
+ insert_queue(&s->erase_busy, busy);
+ busy->timeout.expires = jiffies + req.Timeout*HZ/1000;
+ add_timer(&busy->timeout);
+ break;
+ }
+ } else {
+ /* update erase queue status */
+ DEBUG(2, (" Ret = %d\n", ret));
+ switch (ret) {
+ case CS_SUCCESS:
+ erase->State = ERASE_PASSED; break;
+ case CS_WRITE_PROTECTED:
+ erase->State = ERASE_MEDIA_WRPROT; break;
+ case CS_BAD_OFFSET:
+ erase->State = ERASE_BAD_OFFSET; break;
+ case CS_BAD_SIZE:
+ erase->State = ERASE_BAD_SIZE; break;
+ case CS_NO_CARD:
+ erase->State = ERASE_BAD_SOCKET; break;
+ default:
+ erase->State = ERASE_FAILED; break;
+ }
+ busy->client->event_callback_args.info = erase;
+ EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
+ kfree_s(busy, sizeof(*busy));
+ /* Resubmit anything waiting for a request to finish */
+ wake_up_interruptible(&mtd->mtd_req);
+ retry_erase_list(&mtd->erase_busy, 0);
+ }
+} /* retry_erase */
+
+void retry_erase_list(erase_busy_t *list, u_int cause)
+{
+ erase_busy_t tmp = *list;
+
+ DEBUG(2, ("cs: rescanning erase queue list 0x%p\n", list));
+ if (list->next == list)
+ return;
+ /* First, truncate the original list */
+ list->prev->next = &tmp;
+ list->next->prev = &tmp;
+ list->prev = list->next = list;
+ tmp.prev->next = &tmp;
+ tmp.next->prev = &tmp;
+
+ /* Now, retry each request, in order. */
+ while (tmp.next != &tmp)
+ retry_erase(tmp.next, cause);
+} /* retry_erase_list */
+
+static void handle_erase_timeout(u_long arg)
+{
+ DEBUG(0, ("cs: erase timeout for entry 0x%lx\n", arg));
+ retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
+}
+
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+{
+ erase_busy_t *busy;
+ region_info_t *info;
+
+ if (CHECK_REGION(erase->Handle))
+ erase->State = ERASE_BAD_SOCKET;
+ else {
+ info = &erase->Handle->info;
+ if ((erase->Offset >= info->RegionSize) ||
+ (erase->Offset & (info->BlockSize-1)))
+ erase->State = ERASE_BAD_OFFSET;
+ else if ((erase->Offset+erase->Size > info->RegionSize) ||
+ (erase->Size & (info->BlockSize-1)))
+ erase->State = ERASE_BAD_SIZE;
+ else {
+ erase->State = 1;
+ busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
+ busy->erase = erase;
+ busy->client = handle;
+ busy->timeout.prev = busy->timeout.next = NULL;
+ busy->timeout.data = (u_long)busy;
+ busy->timeout.function = &handle_erase_timeout;
+ busy->prev = busy->next = NULL;
+ retry_erase(busy, 0);
+ }
+ }
+} /* setup_erase_request */
+
+/*======================================================================
+
+ MTD helper functions
+
+======================================================================*/
+
+static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
+{
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ win->ctl.flags = MAP_16BIT | MAP_ACTIVE;
+ if (req->Attributes & WIN_USE_WAIT)
+ win->ctl.flags |= MAP_USE_WAIT;
+ if (req->Attributes & WIN_MEMORY_TYPE)
+ win->ctl.flags |= MAP_ATTRIB;
+ win->ctl.speed = req->AccessSpeed;
+ win->ctl.card_start = req->CardOffset;
+ win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+ return CS_SUCCESS;
+}
+
+static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
+{
+ socket_info_t *s;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ if (req->Vpp1 != req->Vpp2)
+ return CS_BAD_VPP;
+ s = SOCKET(handle);
+ s->socket.Vpp = req->Vpp1;
+ if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+ return CS_BAD_VPP;
+ return CS_SUCCESS;
+}
+
+static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
+{
+ socket_info_t *s;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (req->Mask & CS_EVENT_READY_CHANGE)
+ s->socket.csc_mask |= SS_READY;
+ else
+ s->socket.csc_mask &= ~SS_READY;
+ if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+ return CS_GENERAL_FAILURE;
+ return CS_SUCCESS;
+}
+
+int MTDHelperEntry(int func, void *a1, void *a2)
+{
+ switch (func) {
+ case MTDRequestWindow:
+ return CardServices(RequestWindow, a1, a2, NULL);
+ case MTDReleaseWindow:
+ return CardServices(ReleaseWindow, a1, NULL, NULL);
+ case MTDModifyWindow:
+ return mtd_modify_window(a1, a2); break;
+ case MTDSetVpp:
+ return mtd_set_vpp(a1, a2); break;
+ case MTDRDYMask:
+ return mtd_rdy_mask(a1, a2); break;
+ default:
+ return CS_UNSUPPORTED_FUNCTION; break;
+ }
+} /* MTDHelperEntry */
+
+/*======================================================================
+
+ This stuff is used by Card Services to initialize the table of
+ region info used for subsequent calls to GetFirstRegion and
+ GetNextRegion.
+
+======================================================================*/
+
+static void setup_regions(client_handle_t handle, int attr,
+ memory_handle_t *list)
+{
+ int i, code, has_jedec, has_geo;
+ u_int offset;
+ cistpl_device_t device;
+ cistpl_jedec_t jedec;
+ cistpl_device_geo_t geo;
+ memory_handle_t r;
+
+ DEBUG(1, ("cs: setup_regions(0x%p, %d, 0x%p)\n",
+ handle, attr, list));
+
+ code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
+ if (read_tuple(handle, code, &device) != CS_SUCCESS)
+ return;
+ code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
+ has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
+ if (has_jedec && (device.ndev != jedec.nid)) {
+#ifdef PCMCIA_DEBUG
+ printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n");
+#endif
+ has_jedec = 0;
+ }
+ code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
+ has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
+ if (has_geo && (device.ndev != geo.ngeo)) {
+#ifdef PCMCIA_DEBUG
+ printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n");
+#endif
+ has_geo = 0;
+ }
+
+ offset = 0;
+ for (i = 0; i < device.ndev; i++) {
+ if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
+ (device.dev[i].size != 0)) {
+ r = kmalloc(sizeof(*r), GFP_KERNEL);
+ r->region_magic = REGION_MAGIC;
+ r->state = 0;
+ r->dev_info[0] = '\0';
+ r->mtd = NULL;
+ r->info.Attributes = (attr) ? REGION_TYPE_AM : 0;
+ r->info.CardOffset = offset;
+ r->info.RegionSize = device.dev[i].size;
+ r->info.AccessSpeed = device.dev[i].speed;
+ if (has_jedec) {
+ r->info.JedecMfr = jedec.id[i].mfr;
+ r->info.JedecInfo = jedec.id[i].info;
+ } else
+ r->info.JedecMfr = r->info.JedecInfo = 0;
+ if (has_geo) {
+ r->info.BlockSize = geo.geo[i].buswidth *
+ geo.geo[i].erase_block * geo.geo[i].interleave;
+ r->info.PartMultiple =
+ r->info.BlockSize * geo.geo[i].partition;
+ } else
+ r->info.BlockSize = r->info.PartMultiple = 1;
+ r->info.next = *list; *list = r;
+ }
+ offset += device.dev[i].size;
+ }
+} /* setup_regions */
+
+/*======================================================================
+
+ This is tricky. When get_first_region() is called by Driver
+ Services, we initialize the region info table in the socket
+ structure. When it is called by an MTD, we can just scan the
+ table for matching entries.
+
+======================================================================*/
+
+static int match_region(client_handle_t handle, memory_handle_t list,
+ region_info_t *match)
+{
+ while (list != NULL) {
+ if (!(handle->Attributes & INFO_MTD_CLIENT) ||
+ (strcmp(handle->dev_info, list->dev_info) == 0)) {
+ *match = list->info;
+ return CS_SUCCESS;
+ }
+ list = list->info.next;
+ }
+ return CS_NO_MORE_ITEMS;
+} /* match_region */
+
+int get_first_region(client_handle_t handle, region_info_t *rgn)
+{
+ socket_info_t *s = SOCKET(handle);
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+
+ if ((handle->Attributes & INFO_MASTER_CLIENT) &&
+ (!(s->state & SOCKET_REGION_INFO))) {
+ setup_regions(handle, 0, &s->c_region);
+ setup_regions(handle, 1, &s->a_region);
+ s->state |= SOCKET_REGION_INFO;
+ }
+
+ if (rgn->Attributes & REGION_TYPE_AM)
+ return match_region(handle, s->a_region, rgn);
+ else
+ return match_region(handle, s->c_region, rgn);
+} /* get_first_region */
+
+int get_next_region(client_handle_t handle, region_info_t *rgn)
+{
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ return match_region(handle, rgn->next, rgn);
+} /* get_next_region */
+
+/*======================================================================
+
+ Connect an MTD with a memory region.
+
+======================================================================*/
+
+int register_mtd(client_handle_t handle, mtd_reg_t *reg)
+{
+ memory_handle_t list;
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (reg->Attributes & REGION_TYPE_AM)
+ list = s->a_region;
+ else
+ list = s->c_region;
+ DEBUG(1, ("cs: register_mtd(0x%p, '%s', 0x%x)\n",
+ handle, handle->dev_info, reg->Offset));
+ while (list) {
+ if (list->info.CardOffset == reg->Offset) break;
+ list = list->info.next;
+ }
+ if (list && (list->mtd == NULL) &&
+ (strcmp(handle->dev_info, list->dev_info) == 0)) {
+ list->info.Attributes = reg->Attributes;
+ list->MediaID = reg->MediaID;
+ list->mtd = handle;
+ handle->mtd_count++;
+ return CS_SUCCESS;
+ } else
+ return CS_BAD_OFFSET;
+} /* register_mtd */
+
+/*======================================================================
+
+
+
+======================================================================*/
+
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header)
+{
+ eraseq_t *queue;
+
+ if ((handle == NULL) || CHECK_HANDLE(*handle))
+ return CS_BAD_HANDLE;
+ queue = kmalloc(sizeof(*queue), GFP_KERNEL);
+ queue->eraseq_magic = ERASEQ_MAGIC;
+ queue->handle = *handle;
+ queue->count = header->QueueEntryCnt;
+ queue->entry = header->QueueEntryArray;
+ *handle = (client_handle_t)queue;
+ return CS_SUCCESS;
+} /* register_erase_queue */
+
+int deregister_erase_queue(eraseq_handle_t eraseq)
+{
+ int i;
+ if (CHECK_ERASEQ(eraseq))
+ return CS_BAD_HANDLE;
+ for (i = 0; i < eraseq->count; i++)
+ if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break;
+ if (i < eraseq->count)
+ return CS_BUSY;
+ eraseq->eraseq_magic = 0;
+ kfree_s(eraseq, sizeof(*eraseq));
+ return CS_SUCCESS;
+} /* deregister_erase_queue */
+
+int check_erase_queue(eraseq_handle_t eraseq)
+{
+ int i;
+ if (CHECK_ERASEQ(eraseq))
+ return CS_BAD_HANDLE;
+ for (i = 0; i < eraseq->count; i++)
+ if (eraseq->entry[i].State == ERASE_QUEUED)
+ setup_erase_request(eraseq->handle, &eraseq->entry[i]);
+ return CS_SUCCESS;
+} /* check_erase_queue */
+
+/*======================================================================
+
+ Look up the memory region matching the request, and return a
+ memory handle.
+
+======================================================================*/
+
+int open_memory(client_handle_t *handle, open_mem_t *open)
+{
+ socket_info_t *s;
+ memory_handle_t region;
+
+ if ((handle == NULL) || CHECK_HANDLE(*handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(*handle);
+ if (open->Attributes & MEMORY_TYPE_AM)
+ region = s->a_region;
+ else
+ region = s->c_region;
+ while (region) {
+ if (region->info.CardOffset == open->Offset) break;
+ region = region->info.next;
+ }
+ if (region && region->mtd) {
+ *handle = (client_handle_t)region;
+ DEBUG(1, ("cs: open_memory(0x%p, 0x%x) = 0x%p\n",
+ handle, open->Offset, region));
+ return CS_SUCCESS;
+ } else
+ return CS_BAD_OFFSET;
+} /* open_memory */
+
+/*======================================================================
+
+ Close a memory handle from an earlier call to OpenMemory.
+
+ For the moment, I don't think this needs to do anything.
+
+======================================================================*/
+
+int close_memory(memory_handle_t handle)
+{
+ DEBUG(1, ("cs: close_memory(0x%p)\n", handle));
+ if (CHECK_REGION(handle))
+ return CS_BAD_HANDLE;
+ return CS_SUCCESS;
+} /* close_memory */
+
+/*======================================================================
+
+ Read from a memory device, using a handle previously returned
+ by a call to OpenMemory.
+
+======================================================================*/
+
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+ mtd_request_t mtd;
+ if (CHECK_REGION(handle))
+ return CS_BAD_HANDLE;
+ if (req->Offset >= handle->info.RegionSize)
+ return CS_BAD_OFFSET;
+ if (req->Offset+req->Count > handle->info.RegionSize)
+ return CS_BAD_SIZE;
+
+ mtd.SrcCardOffset = req->Offset + handle->info.CardOffset;
+ mtd.TransferLength = req->Count;
+ mtd.MediaID = handle->MediaID;
+ mtd.Function = MTD_REQ_READ;
+ if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+ mtd.Function |= MTD_REQ_KERNEL;
+ return do_mtd_request(handle, &mtd, buf);
+} /* read_memory */
+
+/*======================================================================
+
+ Write to a memory device, using a handle previously returned by
+ a call to OpenMemory.
+
+======================================================================*/
+
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+ mtd_request_t mtd;
+ if (CHECK_REGION(handle))
+ return CS_BAD_HANDLE;
+ if (req->Offset >= handle->info.RegionSize)
+ return CS_BAD_OFFSET;
+ if (req->Offset+req->Count > handle->info.RegionSize)
+ return CS_BAD_SIZE;
+
+ mtd.DestCardOffset = req->Offset + handle->info.CardOffset;
+ mtd.TransferLength = req->Count;
+ mtd.MediaID = handle->MediaID;
+ mtd.Function = MTD_REQ_WRITE;
+ if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+ mtd.Function |= MTD_REQ_KERNEL;
+ return do_mtd_request(handle, &mtd, buf);
+} /* write_memory */
+
+/*======================================================================
+
+
+======================================================================*/
+
+int copy_memory(memory_handle_t handle, copy_op_t *req)
+{
+ if (CHECK_REGION(handle))
+ return CS_BAD_HANDLE;
+ return CS_UNSUPPORTED_FUNCTION;
+} /* close_memory */
+
--- /dev/null
+/*======================================================================
+
+ Cardbus device configuration
+
+ cardbus.c 1.55 1999/08/28 04:01:45
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+ These routines handle allocating resources for Cardbus cards, as
+ well as setting up and shutting down Cardbus sockets. They are
+ called from cs.c in response to Request/ReleaseConfiguration and
+ Request/ReleaseIO calls.
+
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#ifndef PCMCIA_DEBUG
+#define PCMCIA_DEBUG 1
+#endif
+static int pc_debug = PCMCIA_DEBUG;
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+#define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1)))
+
+#define pci_readb pcibios_read_config_byte
+#define pci_writeb pcibios_write_config_byte
+#define pci_readw pcibios_read_config_word
+#define pci_writew pcibios_write_config_word
+#define pci_readl pcibios_read_config_dword
+#define pci_writel pcibios_write_config_dword
+
+#define CB_BAR(n) (PCI_BASE_ADDRESS_0+(4*(n)))
+#define CB_ROM_BASE 0x0030
+
+/* Offsets in the Expansion ROM Image Header */
+#define ROM_SIGNATURE 0x0000 /* 2 bytes */
+#define ROM_DATA_PTR 0x0018 /* 2 bytes */
+
+/* Offsets in the CardBus PC Card Data Structure */
+#define PCDATA_SIGNATURE 0x0000 /* 4 bytes */
+#define PCDATA_VPD_PTR 0x0008 /* 2 bytes */
+#define PCDATA_LENGTH 0x000a /* 2 bytes */
+#define PCDATA_REVISION 0x000c
+#define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */
+#define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */
+#define PCDATA_CODE_TYPE 0x0014
+#define PCDATA_INDICATOR 0x0015
+
+typedef struct cb_config_t {
+ u_int size[7];
+ struct pci_dev dev;
+} cb_config_t;
+
+#define BASE(dev,n) ((dev).resource[n].start)
+#define ROM(dev) ((dev).resource[6].start)
+
+/* There are three classes of bridge maps: IO ports,
+ non-prefetchable memory, and prefetchable memory */
+typedef enum { B_IO, B_M1, B_M2 } bridge_type;
+
+/*=====================================================================
+
+ Expansion ROM's have a special layout, and pointers specify an
+ image number and an offset within that image. check_rom()
+ verifies that the expansion ROM exists and has the standard
+ layout. xlate_rom_addr() converts an image/offset address to an
+ absolute offset from the ROM's base address.
+
+=====================================================================*/
+
+static int check_rom(u_char *b, u_long len)
+{
+ u_int img = 0, ofs = 0, sz;
+ u_short data;
+ DEBUG(0, ("ROM image dump:\n"));
+ while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+ data = readb(b+ROM_DATA_PTR) +
+ (readb(b+ROM_DATA_PTR+1) << 8);
+ sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+ (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+ DEBUG(0, (" image %d: 0x%06x-0x%06x, signature %c%c%c%c\n",
+ img, ofs, ofs+sz-1,
+ readb(b+data+PCDATA_SIGNATURE),
+ readb(b+data+PCDATA_SIGNATURE+1),
+ readb(b+data+PCDATA_SIGNATURE+2),
+ readb(b+data+PCDATA_SIGNATURE+3)));
+ ofs += sz; img++;
+ if ((readb(b+data+PCDATA_INDICATOR) & 0x80) ||
+ (sz == 0) || (ofs >= len)) break;
+ b += sz;
+ }
+ return img;
+}
+
+static u_int xlate_rom_addr(u_char *b, u_int addr)
+{
+ u_int img = 0, ofs = 0, sz;
+ u_short data;
+ while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+ if (img == (addr >> 28))
+ return (addr & 0x0fffffff) + ofs;
+ data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8);
+ sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+ (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+ if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80))
+ break;
+ b += sz; ofs += sz; img++;
+ }
+ return 0;
+}
+
+/*=====================================================================
+
+ These are similar to setup_cis_mem and release_cis_mem for 16-bit
+ cards. The "result" that is used externally is the cb_cis_virt
+ pointer in the socket_info_t structure.
+
+=====================================================================*/
+
+int cb_setup_cis_mem(socket_info_t *s, int space)
+{
+ cb_bridge_map *m = &s->cb_cis_map;
+ u_long base = 0;
+ u_int sz, br;
+
+ if (space == s->cb_cis_space)
+ return CS_SUCCESS;
+ else if (s->cb_cis_space != 0)
+ cb_release_cis_mem(s);
+ DEBUG(1, ("cs: cb_setup_cis_mem(space %d)\n", space));
+ /* If socket is configured, then use existing memory mapping */
+ if (s->lock_count) {
+ s->cb_cis_virt =
+ ioremap(BASE(s->cb_config[0].dev, space-1),
+ s->cb_config[0].size[space-1] & ~3);
+ s->cb_cis_space = space;
+ return CS_SUCCESS;
+ }
+
+ /* Not configured? Then set up temporary map */
+ br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1);
+ pci_writel(s->cap.cardbus, 0, br, 0xffffffff);
+ pci_readl(s->cap.cardbus, 0, br, &sz);
+ sz &= PCI_BASE_ADDRESS_MEM_MASK;
+ sz = FIND_FIRST_BIT(sz);
+ if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+ if (find_mem_region(&base, sz, "cb_enabler", sz, 0) != 0) {
+ printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+ " CardBus socket %d\n", sz/1024, s->sock);
+ return CS_OUT_OF_RESOURCE;
+ }
+ s->cb_cis_space = space;
+ s->cb_cis_virt = ioremap(base, sz);
+ DEBUG(1, (" phys 0x%08lx-0x%08lx, virt 0x%08lx\n",
+ base, base+sz-1, (u_long)s->cb_cis_virt));
+ pci_writel(s->cap.cardbus, 0, br, base | 1);
+ pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, PCI_COMMAND_MEMORY);
+ m->map = 0; m->flags = MAP_ACTIVE;
+ m->start = base; m->stop = base+sz-1;
+ s->ss_entry(s->sock, SS_SetBridge, m);
+ if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) {
+ printk(KERN_NOTICE "cs: no valid ROM images found!\n");
+ return CS_READ_FAILURE;
+ }
+ return CS_SUCCESS;
+}
+
+void cb_release_cis_mem(socket_info_t *s)
+{
+ cb_bridge_map *m = &s->cb_cis_map;
+ u_int br;
+ if (s->cb_cis_virt) {
+ DEBUG(1, ("cs: cb_release_cis_mem()\n"));
+ iounmap(s->cb_cis_virt);
+ s->cb_cis_virt = NULL;
+ s->cb_cis_space = 0;
+ }
+ if (m->start) {
+ /* This is overkill: we probably only need to release the
+ memory region, but the rest should be safe */
+ br = (s->cb_cis_space == 7) ?
+ CB_ROM_BASE : CB_BAR(s->cb_cis_space-1);
+ m->map = 0; m->flags = 0;
+ s->ss_entry(s->sock, SS_SetBridge, m);
+ pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, 0);
+ pci_writel(s->cap.cardbus, 0, br, 0);
+ release_mem_region(m->start, m->stop - m->start + 1);
+ m->start = 0;
+ }
+}
+
+/*=====================================================================
+
+ This is used by the CIS processing code to read CIS information
+ from a CardBus device.
+
+=====================================================================*/
+
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+ u_int addr, u_int len, void *ptr)
+{
+ DEBUG(3, ("cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len));
+ if (space == 0) {
+ for (; len; addr++, ptr++, len--)
+ pci_readb(s->cap.cardbus, fn, addr, (u_char *)ptr);
+ } else {
+ if (cb_setup_cis_mem(s, space) != 0) {
+ memset(ptr, 0xff, len);
+ return;
+ }
+ if (space == 7) {
+ addr = xlate_rom_addr(s->cb_cis_virt, addr);
+ if (addr == 0) {
+ memset(ptr, 0xff, len);
+ return;
+ }
+ }
+ if (s->cb_cis_virt != NULL)
+ for (; len; addr++, ptr++, len--)
+ *(u_char *)ptr = readb(s->cb_cis_virt+addr);
+ }
+}
+
+/*=====================================================================
+
+ cb_config() has the job of allocating all system resources that
+ a Cardbus card requires. Rather than using the CIS (which seems
+ to not always be present), it treats the card as an ordinary PCI
+ device, and probes the base address registers to determine each
+ function's IO and memory space needs.
+
+ It is called from the RequestIO card service.
+
+======================================================================*/
+
+int cb_config(socket_info_t *s)
+{
+ u_short vend, v, dev;
+ u_char i, j, fn, bus = s->cap.cardbus, *name;
+ u_int sz, align, m, mask[3], num[3], base[3];
+ cb_config_t *c;
+ int irq, try, ret;
+
+ pci_readw(bus, 0, PCI_VENDOR_ID, &vend);
+ pci_readw(bus, 0, PCI_DEVICE_ID, &dev);
+ printk(KERN_INFO "cs: cb_config(bus %d): vendor 0x%04x, "
+ "device 0x%04x\n", bus, vend, dev);
+
+ pci_readb(bus, 0, PCI_HEADER_TYPE, &fn);
+ if (fn & 0x80) {
+ /* Count functions */
+ for (fn = 0; fn < 8; fn++) {
+ pci_readw(bus, fn, PCI_VENDOR_ID, &v);
+ if (v != vend) break;
+ }
+ } else fn = 1;
+ s->functions = fn;
+
+ c = kmalloc(fn * sizeof(struct cb_config_t), GFP_KERNEL);
+ memset(c, 0, fn * sizeof(struct cb_config_t));
+ s->cb_config = c;
+
+ for (i = 0; i < fn; i++) {
+ c[i].dev.bus = s->cap.cb_bus;
+ if (i < fn-1) {
+ c[i].dev.sibling = c[i].dev.next = &c[i+1].dev;
+ }
+ c[i].dev.devfn = i;
+ c[i].dev.vendor = vend; c[i].dev.device = dev;
+ pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class);
+ c[i].dev.class >>= 8;
+ pci_readb(bus, i, PCI_HEADER_TYPE, &j);
+ c[i].dev.hdr_type = j;
+ }
+ s->cap.cb_bus->devices = &c[0].dev;
+
+ /* Determine IO and memory space needs */
+ num[B_IO] = num[B_M1] = num[B_M2] = 0;
+ mask[B_IO] = mask[B_M1] = mask[B_M2] = 0;
+ for (i = 0; i < fn; i++) {
+ for (j = 0; j < 6; j++) {
+ pci_writel(bus, i, CB_BAR(j), 0xffffffff);
+ pci_readl(bus, i, CB_BAR(j), &sz);
+ if (sz == 0) continue;
+ if (sz & PCI_BASE_ADDRESS_SPACE) {
+ m = B_IO;
+ sz &= PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1;
+ sz &= PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ sz = FIND_FIRST_BIT(sz);
+ c[i].size[j] = sz | m;
+ if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE;
+ num[m] += sz; mask[m] |= sz;
+ }
+ pci_writel(bus, i, CB_ROM_BASE, 0xffffffff);
+ pci_readl(bus, i, CB_ROM_BASE, &sz);
+ if (sz != 0) {
+ sz = FIND_FIRST_BIT(sz & ~0x00000001);
+ c[i].size[6] = sz | B_M1;
+ if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+ num[B_M1] += sz; mask[B_M1] |= sz;
+ }
+ }
+
+ /* Allocate system resources */
+ name = "cb_enabler";
+ s->io[0].NumPorts = num[B_IO];
+ s->io[0].BasePort = 0;
+ if (num[B_IO]) {
+ if (find_io_region(&s->io[0].BasePort, num[B_IO], name) != 0) {
+ printk(KERN_NOTICE "cs: could not allocate %d IO ports for"
+ " CardBus socket %d\n", num[B_IO], s->sock);
+ goto failed;
+ }
+ base[B_IO] = s->io[0].BasePort + num[B_IO];
+ }
+ s->win[0].size = num[B_M1];
+ s->win[0].base = 0;
+ if (num[B_M1]) {
+ if (find_mem_region(&s->win[0].base, num[B_M1],
+ name, num[B_M1], 0) != 0) {
+ printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+ " CardBus socket %d\n", num[B_M1]/1024, s->sock);
+ goto failed;
+ }
+ base[B_M1] = s->win[0].base + num[B_M1];
+ }
+ s->win[1].size = num[B_M2];
+ s->win[1].base = 0;
+ if (num[B_M2]) {
+ if (find_mem_region(&s->win[1].base, num[B_M2],
+ name, num[B_M2], 0) != 0) {
+ printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+ " CardBus socket %d\n", num[B_M2]/1024, s->sock);
+ goto failed;
+ }
+ base[B_M2] = s->win[1].base + num[B_M2];
+ }
+
+ /* Set up base address registers */
+ while (mask[B_IO] | mask[B_M1] | mask[B_M2]) {
+ num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO];
+ num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1];
+ num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2];
+ for (i = 0; i < fn; i++) {
+ for (j = 0; j < 7; j++) {
+ sz = c[i].size[j];
+ m = sz & 3; sz &= ~3;
+ align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz;
+ if (sz && (align == num[m])) {
+ base[m] -= align;
+ if (j < 6)
+ printk(KERN_INFO " fn %d bar %d: ", i, j+1);
+ else
+ printk(KERN_INFO " fn %d rom: ", i);
+ printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io",
+ base[m], base[m]+sz-1);
+ BASE(c[i].dev, j) = base[m];
+ }
+ }
+ }
+ }
+
+ /* Allocate interrupt if needed */
+ s->irq.AssignedIRQ = irq = 0; ret = -1;
+ for (i = 0; i < fn; i++) {
+ pci_readb(bus, i, PCI_INTERRUPT_PIN, &j);
+ if (j == 0) continue;
+ if (irq == 0) {
+ if (s->cap.irq_mask & (1 << s->cap.pci_irq)) {
+ irq = s->cap.pci_irq;
+ ret = 0;
+ }
+#ifdef CONFIG_ISA
+ else
+ for (try = 0; try < 2; try++) {
+ for (irq = 0; irq < 32; irq++)
+ if ((s->cap.irq_mask >> irq) & 1) {
+ ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try);
+ if (ret == 0) break;
+ }
+ if (ret == 0) break;
+ }
+ if (ret != 0) {
+ printk(KERN_NOTICE "cs: could not allocate interrupt"
+ " for CardBus socket %d\n", s->sock);
+ goto failed;
+ }
+#endif
+ s->irq.AssignedIRQ = irq;
+ }
+ }
+ c[0].dev.irq = irq;
+
+ return CS_SUCCESS;
+
+failed:
+ cb_release(s);
+ return CS_OUT_OF_RESOURCE;
+}
+
+/*======================================================================
+
+ cb_release() releases all the system resources (IO and memory
+ space, and interrupt) committed for a Cardbus card by a prior call
+ to cb_config().
+
+ It is called from the ReleaseIO() service.
+
+======================================================================*/
+
+void cb_release(socket_info_t *s)
+{
+ cb_config_t *c = s->cb_config;
+
+ DEBUG(0, ("cs: cb_release(bus %d)\n", s->cap.cardbus));
+
+ if (s->win[0].size > 0)
+ release_mem_region(s->win[0].base, s->win[0].size);
+ if (s->win[1].size > 0)
+ release_mem_region(s->win[1].base, s->win[1].size);
+ if (s->io[0].NumPorts > 0)
+ release_region(s->io[0].BasePort, s->io[0].NumPorts);
+ s->io[0].NumPorts = 0;
+#ifdef CONFIG_ISA
+ if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq))
+ undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq);
+#endif
+ kfree(s->cb_config);
+ s->cb_config = NULL;
+}
+
+/*=====================================================================
+
+ cb_enable() has the job of configuring a socket for a Cardbus
+ card, and initializing the card's PCI configuration registers.
+
+ It first sets up the Cardbus bridge windows, for IO and memory
+ accesses. Then, it initializes each card function's base address
+ registers, interrupt line register, and command register.
+
+ It is called as part of the RequestConfiguration card service.
+ It should be called after a previous call to cb_config() (via the
+ RequestIO service).
+
+======================================================================*/
+
+void cb_enable(socket_info_t *s)
+{
+ u_char i, j, bus = s->cap.cardbus;
+ cb_config_t *c = s->cb_config;
+
+ DEBUG(0, ("cs: cb_enable(bus %d)\n", bus));
+
+ /* Configure bridge */
+ if (s->cb_cis_map.start)
+ cb_release_cis_mem(s);
+ for (i = 0; i < 3; i++) {
+ cb_bridge_map m;
+ switch (i) {
+ case B_IO:
+ m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE;
+ m.start = s->io[0].BasePort;
+ m.stop = m.start + s->io[0].NumPorts - 1;
+ break;
+ case B_M1:
+ m.map = 0; m.flags = MAP_ACTIVE;
+ m.start = s->win[0].base;
+ m.stop = m.start + s->win[0].size - 1;
+ break;
+ case B_M2:
+ m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE;
+ m.start = s->win[1].base;
+ m.stop = m.start + s->win[1].size - 1;
+ break;
+ }
+ if (m.start == 0) continue;
+ DEBUG(0, (" bridge %s map %d (flags 0x%x): 0x%x-0x%x\n",
+ (m.flags & MAP_IOSPACE) ? "io" : "mem",
+ m.map, m.flags, m.start, m.stop));
+ s->ss_entry(s->sock, SS_SetBridge, &m);
+ }
+
+ /* Set up base address registers */
+ for (i = 0; i < s->functions; i++) {
+ for (j = 0; j < 6; j++) {
+ if (BASE(c[i].dev, j) != 0)
+ pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j));
+ }
+ if (ROM(c[i].dev) != 0)
+ pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1);
+ }
+
+ /* Set up PCI interrupt and command registers */
+ for (i = 0; i < s->functions; i++) {
+ pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER |
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8);
+ }
+
+ if (s->irq.AssignedIRQ) {
+ for (i = 0; i < s->functions; i++)
+ pci_writeb(bus, i, PCI_INTERRUPT_LINE,
+ s->irq.AssignedIRQ);
+ s->socket.io_irq = s->irq.AssignedIRQ;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ }
+
+ /* Link into PCI device chain */
+ c[s->functions-1].dev.next = pci_devices;
+ pci_devices = &c[0].dev;
+ for (i = 0; i < s->functions; i++)
+ pci_proc_attach_device(&c[i].dev);
+}
+
+/*======================================================================
+
+ cb_disable() unconfigures a Cardbus card previously set up by
+ cb_enable().
+
+ It is called from the ReleaseConfiguration service.
+
+======================================================================*/
+
+void cb_disable(socket_info_t *s)
+{
+ u_char i;
+ cb_bridge_map m = { 0, 0, 0, 0xffff };
+ struct pci_dev **p, *q;
+ cb_config_t *c = s->cb_config;
+
+ /* Unlink from PCI device chain */
+ for (p = &pci_devices; *p; p = &((*p)->next))
+ if (*p == &c[0].dev) break;
+ for (q = *p; q; q = q->next) {
+ if (q->bus != (*p)->bus) break;
+ pci_proc_detach_device(q);
+ }
+ if (*p) *p = q;
+ s->cap.cb_bus->devices = NULL;
+
+ DEBUG(0, ("cs: cb_disable(bus %d)\n", s->cap.cardbus));
+
+ /* Turn off bridge windows */
+ if (s->cb_cis_map.start)
+ cb_release_cis_mem(s);
+ for (i = 0; i < 3; i++) {
+ switch (i) {
+ case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break;
+ case B_M1: m.map = m.flags = 0; break;
+ case B_M2: m.map = 1; m.flags = 0; break;
+ }
+ s->ss_entry(s->sock, SS_SetBridge, &m);
+ }
+}
--- /dev/null
+/*======================================================================
+
+ Cardbus device enabler
+
+ cb_enabler.c 1.21 1999/08/28 04:01:45
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+ The general idea:
+
+ A client driver registers using register_driver(). This module
+ then creates a Card Services pseudo-client and registers it, and
+ configures the socket if this is the first client. It then
+ invokes the appropriate PCI client routines in response to Card
+ Services events.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"cb_enabler.c 1.21 1999/08/28 04:01:45 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+ dev_link_t *(*attach)(void);
+ dev_info_t dev_info;
+ driver_operations *ops;
+ dev_link_t *dev_list;
+} driver_info_t;
+
+static dev_link_t *cb_attach(int n);
+#define MK_ENTRY(fn, n) \
+static dev_link_t *fn(void) { return cb_attach(n); }
+
+#define MAX_DRIVER 4
+
+MK_ENTRY(attach_0, 0);
+MK_ENTRY(attach_1, 1);
+MK_ENTRY(attach_2, 2);
+MK_ENTRY(attach_3, 3);
+
+static driver_info_t driver[4] = {
+ { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 }
+};
+
+typedef struct bus_info_t {
+ u_char bus;
+ int flags, ncfg, nuse;
+ dev_link_t *owner;
+} bus_info_t;
+
+#define DID_REQUEST 1
+#define DID_CONFIG 2
+
+static void cb_release(u_long arg);
+static int cb_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static void cb_detach(dev_link_t *);
+
+static bus_info_t bus_table[MAX_DRIVER];
+
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+struct dev_link_t *cb_attach(int n)
+{
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int ret;
+
+ DEBUG(0, "cb_attach(%d)\n", n);
+
+ MOD_INC_USE_COUNT;
+ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ memset(link, 0, sizeof(struct dev_link_t));
+ link->release.function = &cb_release;
+ link->release.data = (u_long)link;
+
+ link->conf.IntType = INT_CARDBUS;
+ link->conf.Vcc = 33;
+
+ /* Insert into instance chain for this driver */
+ link->priv = &driver[n];
+ link->next = driver[n].dev_list;
+ driver[n].dev_list = link;
+
+ /* Register with Card Services */
+ client_reg.dev_info = &driver[n].dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &cb_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ cb_detach(link);
+ return NULL;
+ }
+ return link;
+}
+
+/*====================================================================*/
+
+static void cb_detach(dev_link_t *link)
+{
+ driver_info_t *dev = link->priv;
+ dev_link_t **linkp;
+ bus_info_t *b = (void *)link->win;
+ u_long flags;
+
+ DEBUG(0, "cb_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+ if (link->state & DEV_RELEASE_PENDING) {
+ del_timer(&link->release);
+ link->state &= ~DEV_RELEASE_PENDING;
+ }
+ restore_flags(flags);
+
+ if (link->state & DEV_CONFIG)
+ cb_release((u_long)link);
+
+ /* Don't drop Card Services connection if we are the bus owner */
+ if ((b->flags != 0) && (link == b->owner)) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ *linkp = link->next;
+ kfree_s(link, sizeof(struct dev_link_t));
+ MOD_DEC_USE_COUNT;
+}
+
+/*====================================================================*/
+
+static void cb_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ driver_info_t *drv = link->priv;
+ dev_locator_t loc;
+ bus_info_t *b;
+ config_info_t config;
+ u_char bus, devfn;
+ int i;
+
+ DEBUG(0, "cb_config(0x%p)\n", link);
+ link->state |= DEV_CONFIG;
+
+ /* Get PCI bus info */
+ CardServices(GetConfigurationInfo, handle, &config);
+ bus = config.Option; devfn = config.Function;
+
+ /* Is this a new bus? */
+ for (i = 0; i < MAX_DRIVER; i++)
+ if (bus == bus_table[i].bus) break;
+ if (i == MAX_DRIVER) {
+ for (i = 0; i < MAX_DRIVER; i++)
+ if (bus_table[i].bus == 0) break;
+ b = &bus_table[i]; link->win = (void *)b;
+ b->bus = bus;
+ b->flags = 0;
+ b->ncfg = b->nuse = 1;
+
+ /* Special hook: CS know what to do... */
+ i = CardServices(RequestIO, handle, NULL);
+ if (i != CS_SUCCESS) {
+ cs_error(handle, RequestIO, i);
+ return;
+ }
+ b->flags |= DID_REQUEST;
+ b->owner = link;
+ i = CardServices(RequestConfiguration, handle, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(handle, RequestConfiguration, i);
+ return;
+ }
+ b->flags |= DID_CONFIG;
+ } else {
+ b = &bus_table[i]; link->win = (void *)b;
+ if (b->flags & DID_CONFIG) {
+ b->ncfg++; b->nuse++;
+ }
+ }
+ loc.bus = LOC_PCI;
+ loc.b.pci.bus = bus;
+ loc.b.pci.devfn = devfn;
+ link->dev = drv->ops->attach(&loc);
+
+ link->state &= ~DEV_CONFIG_PENDING;
+}
+
+/*====================================================================*/
+
+static void cb_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+ driver_info_t *drv = link->priv;
+ bus_info_t *b = (void *)link->win;
+
+ DEBUG(0, "cb_release(0x%p)\n", link);
+
+ if (link->dev != NULL) {
+ drv->ops->detach(link->dev);
+ link->dev = NULL;
+ }
+ if (link->state & DEV_CONFIG) {
+ /* If we're suspended, config was already released */
+ if (link->state & DEV_SUSPEND)
+ b->flags &= ~DID_CONFIG;
+ else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) {
+ CardServices(ReleaseConfiguration, b->owner->handle,
+ &b->owner->conf);
+ b->flags &= ~DID_CONFIG;
+ }
+ if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) {
+ CardServices(ReleaseIO, b->owner->handle, NULL);
+ b->flags &= ~DID_REQUEST;
+ }
+ if (b->flags == 0) {
+ if (b->owner && (b->owner->state & DEV_STALE_LINK))
+ cb_detach(b->owner);
+ b->bus = 0; b->owner = NULL;
+ }
+ }
+ link->state &= ~DEV_CONFIG;
+}
+
+/*====================================================================*/
+
+static int cb_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ driver_info_t *drv = link->priv;
+ bus_info_t *b = (void *)link->win;
+
+ DEBUG(0, "cb_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ link->state |= DEV_RELEASE_PENDING;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ cb_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG) {
+ if (drv->ops->suspend != NULL)
+ drv->ops->suspend(link->dev);
+ b->ncfg--;
+ if (b->ncfg == 0)
+ CardServices(ReleaseConfiguration, link->handle,
+ &link->conf);
+ }
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ b->ncfg++;
+ if (b->ncfg == 1)
+ CardServices(RequestConfiguration, link->handle,
+ &link->conf);
+ if (drv->ops->resume != NULL)
+ drv->ops->resume(link->dev);
+ }
+ break;
+ }
+ return 0;
+}
+
+/*====================================================================*/
+
+int register_driver(struct driver_operations *ops)
+{
+ int i;
+
+ DEBUG(0, "register_driver('%s')\n", ops->name);
+
+ for (i = 0; i < MAX_DRIVER; i++)
+ if (driver[i].ops == NULL) break;
+ if (i == MAX_DRIVER)
+ return -1;
+
+ MOD_INC_USE_COUNT;
+ driver[i].ops = ops;
+ strcpy(driver[i].dev_info, ops->name);
+ register_pccard_driver(&driver[i].dev_info, driver[i].attach,
+ &cb_detach);
+ return 0;
+}
+
+void unregister_driver(struct driver_operations *ops)
+{
+ int i;
+
+ DEBUG(0, "unregister_driver('%s')\n", ops->name);
+ for (i = 0; i < MAX_DRIVER; i++)
+ if (driver[i].ops == ops) break;
+ if (i < MAX_DRIVER) {
+ unregister_pccard_driver(&driver[i].dev_info);
+ driver[i].ops = NULL;
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+/*====================================================================*/
+
+int init_module(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "cb_enabler: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ return 0;
+}
+
+void cleanup_module(void) {
+ DEBUG(0, "cb_enabler: unloading\n");
+}
+
+/*====================================================================*/
--- /dev/null
+/*
+ * cirrus.h 1.3 1999/08/28 04:01:46
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6729
+#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6832
+#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
+#endif
+
+#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */
+#define PD67_FIFO_CTL 0x17 /* FIFO control */
+#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */
+#define PD67_CHIP_INFO 0x1f /* Chip information */
+#define PD67_ATA_CTL 0x026 /* 6730: ATA control */
+#define PD67_EXT_INDEX 0x2e /* Extension index */
+#define PD67_EXT_DATA 0x2f /* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0 0x01 /* Data mask 0 */
+#define PD67_DATA_MASK1 0x02 /* Data mask 1 */
+#define PD67_DMA_CTL 0x03 /* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1 0x03 /* Extension control 1 */
+#define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA 0x0a
+#define PD67_MISC_CTL_3 0x25
+#define PD67_SMB_PWR_CTL 0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w) (0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n) (0x3a + 3*(n))
+#define PD67_TIME_CMD(n) (0x3b + 3*(n))
+#define PD67_TIME_RECOV(n) (0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET 0x01 /* 5v detect */
+#define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT 0x04
+#define PD67_MC1_PULSE_IRQ 0x08
+#define PD67_MC1_SPKR_ENA 0x10
+#define PD67_MC1_INPACK_ENA 0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY 0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS 0x01
+#define PD67_MC2_DYNAMIC_MODE 0x02
+#define PD67_MC2_SUSPEND 0x04
+#define PD67_MC2_5V_CORE 0x08
+#define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */
+#define PD67_MC2_DMA_MODE 0x40
+#define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID 0xc0
+#define PD67_INFO_REV 0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE 0xc0
+#define PD67_TIME_SCALE_1 0x00
+#define PD67_TIME_SCALE_16 0x40
+#define PD67_TIME_SCALE_256 0x80
+#define PD67_TIME_SCALE_4096 0xc0
+#define PD67_TIME_MULT 0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE 0xc0
+#define PD67_DMA_OFF 0x00
+#define PD67_DMA_DREQ_INPACK 0x40
+#define PD67_DMA_DREQ_WP 0x80
+#define PD67_DMA_DREQ_BVD2 0xc0
+#define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK 0x01
+#define PD67_EC1_AUTO_PWR_CLEAR 0x02
+#define PD67_EC1_LED_ENA 0x04
+#define PD67_EC1_INV_CARD_IRQ 0x08
+#define PD67_EC1_INV_MGMT_IRQ 0x10
+#define PD67_EC1_PULLUP_CTL 0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK 0x03
+#define PD67_MC3_IRQ_PCPCI 0x00
+#define PD67_MC3_IRQ_EXTERN 0x01
+#define PD67_MC3_IRQ_PCIWAY 0x02
+#define PD67_MC3_IRQ_PCI 0x03
+#define PD67_MC3_PWR_MASK 0x0c
+#define PD67_MC3_PWR_SERIAL 0x00
+#define PD67_MC3_PWR_TI2202 0x08
+#define PD67_MC3_PWR_SMB 0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2 0x0b
+#define PD68_PCI_SPACE 0x22
+#define PD68_PCCARD_SPACE 0x23
+#define PD68_WINDOW_TYPE 0x24
+#define PD68_EXT_CSC 0x2e
+#define PD68_MISC_CTL_4 0x2f
+#define PD68_MISC_CTL_5 0x30
+#define PD68_MISC_CTL_6 0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP 0x10
+#define PD68_MC3_MM_EXPAND 0x40
+#define PD68_MC3_MM_ARM 0x80
+
+/* Bridge Control Register */
+#define PD6832_BCR_MGMT_IRQ_ENA 0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
--- /dev/null
+/*======================================================================
+
+ PCMCIA Card Information Structure parser
+
+ cistpl.c 1.69 1999/08/28 04:01:45
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bus_ops.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+static const u_char mantissa[] = {
+ 10, 12, 13, 15, 20, 25, 30, 35,
+ 40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+ (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+ (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v) (exponent[(v)&7])
+
+/* Upper limit on reasonable # of tuples */
+#define MAX_TUPLES 200
+
+/*======================================================================
+
+ Low-level functions to read and write CIS memory. I think the
+ write routine is only useful for writing one-byte registers.
+
+======================================================================*/
+
+void read_cis_mem(socket_info_t *s, int attr, u_int addr,
+ u_int len, void *ptr)
+{
+ pccard_mem_map *mem = &s->cis_mem;
+ u_char *sys;
+ u_int inc = 1;
+
+ DEBUG(3, ("cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len));
+ if (setup_cis_mem(s) != 0) {
+ memset(ptr, 0xff, len);
+ return;
+ }
+ mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
+ if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+ sys = s->cis_virt + (addr & (s->cap.map_size-1));
+ mem->card_start = addr & ~(s->cap.map_size-1);
+
+ for (; len > 0; sys = s->cis_virt) {
+ s->ss_entry(s->sock, SS_SetMemMap, mem);
+ DEBUG(3, ("cs: %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+ bus_readb(s->cap.bus, sys),
+ bus_readb(s->cap.bus, sys+inc),
+ bus_readb(s->cap.bus, sys+2*inc),
+ bus_readb(s->cap.bus, sys+3*inc),
+ bus_readb(s->cap.bus, sys+4*inc)));
+ for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+ if (sys == s->cis_virt+s->cap.map_size) break;
+ *(u_char *)ptr = bus_readb(s->cap.bus, sys);
+ }
+ mem->card_start += s->cap.map_size;
+ }
+}
+
+void write_cis_mem(socket_info_t *s, int attr, u_int addr,
+ u_int len, void *ptr)
+{
+ pccard_mem_map *mem = &s->cis_mem;
+ u_char *sys;
+ int inc = 1;
+
+ DEBUG(3, ("cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len));
+ if (setup_cis_mem(s) != 0) return;
+ mem->flags &= ~MAP_ATTRIB;
+ if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+ sys = s->cis_virt + (addr & (s->cap.map_size-1));
+ mem->card_start = addr & ~(s->cap.map_size-1);
+
+ for (; len > 0; sys = s->cis_virt) {
+ s->ss_entry(s->sock, SS_SetMemMap, mem);
+ for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+ if (sys == s->cis_virt+s->cap.map_size) break;
+ bus_writeb(s->cap.bus, *(u_char *)ptr, sys);
+ }
+ mem->card_start += s->cap.map_size;
+ }
+}
+
+/*======================================================================
+
+ This is tricky... when we set up CIS memory, we try to validate
+ the memory window space allocations.
+
+======================================================================*/
+
+/* Scratch pointer to the socket we use for validation */
+static socket_info_t *vs = NULL;
+
+/* Validation function for cards with a valid CIS */
+static int cis_readable(u_long base)
+{
+ cisinfo_t info1, info2;
+ int ret;
+ vs->cis_mem.sys_start = base;
+ vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+ vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+ ret = validate_cis(vs->clients, &info1);
+ /* invalidate mapping and CIS cache */
+ bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+ if ((ret != 0) || (info1.Chains == 0))
+ return 0;
+ vs->cis_mem.sys_start = base+vs->cap.map_size;
+ vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
+ vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
+ vs->cap.map_size);
+ ret = validate_cis(vs->clients, &info2);
+ bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+ return ((ret == 0) && (info1.Chains == info2.Chains));
+}
+
+/* Validation function for simple memory cards */
+static int checksum(u_long base)
+{
+ int i, a, b, d;
+ vs->cis_mem.sys_start = base;
+ vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+ vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+ vs->cis_mem.card_start = 0;
+ vs->cis_mem.flags = MAP_ACTIVE;
+ vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem);
+ /* Don't bother checking every word... */
+ a = 0; b = -1;
+ for (i = 0; i < vs->cap.map_size; i += 44) {
+ d = bus_readl(vs->cap.bus, vs->cis_virt+i);
+ a += d; b &= d;
+ }
+ bus_iounmap(vs->cap.bus, vs->cis_virt);
+ return (b == -1) ? -1 : (a>>1);
+}
+
+static int checksum_match(u_long base)
+{
+ int a = checksum(base), b = checksum(base+vs->cap.map_size);
+ return ((a == b) && (a >= 0));
+}
+
+int setup_cis_mem(socket_info_t *s)
+{
+ if (s->cis_mem.sys_start == 0) {
+ int low = !(s->cap.features & SS_CAP_PAGE_REGS);
+ vs = s;
+ validate_mem(cis_readable, checksum_match, low);
+ s->cis_mem.sys_start = 0;
+ vs = NULL;
+ if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
+ "card services", s->cap.map_size, low)) {
+ printk(KERN_NOTICE "cs: unable to map card memory!\n");
+ return CS_OUT_OF_RESOURCE;
+ }
+ s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
+ s->cis_mem.flags |= MAP_ACTIVE;
+ s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
+ s->cap.map_size);
+ }
+ return 0;
+}
+
+void release_cis_mem(socket_info_t *s)
+{
+ if (s->cis_mem.sys_start != 0) {
+ s->cis_mem.flags &= ~MAP_ACTIVE;
+ s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem);
+ release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
+ bus_iounmap(s->cap.bus, s->cis_virt);
+ s->cis_mem.sys_start = 0;
+ }
+}
+
+/*======================================================================
+
+ This is a wrapper around read_cis_mem, with the same interface,
+ but which caches information, for cards whose CIS may not be
+ readable all the time.
+
+======================================================================*/
+
+static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
+ u_int len, void *ptr)
+{
+ int i;
+ char *caddr;
+
+ if (s->fake_cis) {
+ if (s->fake_cis_len > addr+len)
+ memcpy(ptr, s->fake_cis+addr, len);
+ else
+ memset(ptr, 0xff, len);
+ return;
+ }
+ caddr = s->cis_cache;
+ for (i = 0; i < s->cis_used; i++) {
+ if ((s->cis_table[i].addr == addr) &&
+ (s->cis_table[i].len == len) &&
+ (s->cis_table[i].attr == attr)) break;
+ caddr += s->cis_table[i].len;
+ }
+ if (i < s->cis_used) {
+ memcpy(ptr, caddr, len);
+ return;
+ }
+#ifdef CONFIG_CARDBUS
+ if (s->state & SOCKET_CARDBUS)
+ read_cb_mem(s, 0, attr, addr, len, ptr);
+ else
+#endif
+ read_cis_mem(s, attr, addr, len, ptr);
+ /* Copy data into the cache, if there is room */
+ if ((i < MAX_CIS_TABLE) &&
+ (caddr+len < s->cis_cache+MAX_CIS_DATA)) {
+ s->cis_table[i].addr = addr;
+ s->cis_table[i].len = len;
+ s->cis_table[i].attr = attr;
+ s->cis_used++;
+ memcpy(caddr, ptr, len);
+ }
+}
+
+/*======================================================================
+
+ This verifies if the CIS of a card matches what is in the CIS
+ cache.
+
+======================================================================*/
+
+int verify_cis_cache(socket_info_t *s)
+{
+ char buf[256], *caddr;
+ int i;
+
+ caddr = s->cis_cache;
+ for (i = 0; i < s->cis_used; i++) {
+#ifdef CONFIG_CARDBUS
+ if (s->state & SOCKET_CARDBUS)
+ read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr,
+ s->cis_table[i].len, buf);
+ else
+#endif
+ read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr,
+ s->cis_table[i].len, buf);
+ if (memcmp(buf, caddr, s->cis_table[i].len) != 0)
+ break;
+ caddr += s->cis_table[i].len;
+ }
+ return (i < s->cis_used);
+}
+
+/*======================================================================
+
+ For really bad cards, we provide a facility for uploading a
+ replacement CIS.
+
+======================================================================*/
+
+int replace_cis(client_handle_t handle, cisdump_t *cis)
+{
+ socket_info_t *s;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (s->fake_cis != NULL) {
+ kfree(s->fake_cis);
+ s->fake_cis = NULL;
+ }
+ if (cis->Length > CISTPL_MAX_CIS_SIZE)
+ return CS_BAD_SIZE;
+ s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
+ if (s->fake_cis == NULL)
+ return CS_OUT_OF_RESOURCE;
+ s->fake_cis_len = cis->Length;
+ memcpy(s->fake_cis, cis->Data, cis->Length);
+ return CS_SUCCESS;
+}
+
+/*======================================================================
+
+ The high-level CIS tuple services
+
+======================================================================*/
+
+typedef struct tuple_flags {
+ u_int link_space:3;
+ u_int has_link:1;
+ u_int mfc_fn:3;
+ u_int space:3;
+} tuple_flags;
+
+#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
+#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link)
+#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
+#define SPACE(f) (((tuple_flags *)(&(f)))->space)
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+
+int get_first_tuple(client_handle_t handle, tuple_t *tuple)
+{
+ socket_info_t *s;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ tuple->TupleLink = tuple->Flags = 0;
+#ifdef CONFIG_CARDBUS
+ if (s->state & SOCKET_CARDBUS) {
+ u_int ptr;
+ pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr);
+ tuple->CISOffset = ptr & ~7;
+ SPACE(tuple->Flags) = (ptr & 7);
+ } else
+#endif
+ {
+ /* Assume presence of a LONGLINK_C to address 0 */
+ tuple->CISOffset = tuple->LinkOffset = 0;
+ SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+ }
+ if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
+ !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+ cisdata_t req = tuple->DesiredTuple;
+ tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+ if (get_next_tuple(handle, tuple) == CS_SUCCESS) {
+ tuple->DesiredTuple = CISTPL_LINKTARGET;
+ if (get_next_tuple(handle, tuple) != CS_SUCCESS)
+ return CS_NO_MORE_ITEMS;
+ } else
+ tuple->CISOffset = tuple->TupleLink = 0;
+ tuple->DesiredTuple = req;
+ }
+ return get_next_tuple(handle, tuple);
+}
+
+static int follow_link(socket_info_t *s, tuple_t *tuple)
+{
+ u_char link[5];
+ u_int ofs;
+
+ if (MFC_FN(tuple->Flags)) {
+ /* Get indirect link from the MFC tuple */
+ read_cis_cache(s, LINK_SPACE(tuple->Flags),
+ tuple->LinkOffset, 5, link);
+ ofs = le32_to_cpu(*(u_int *)(link+1));
+ SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+ /* Move to the next indirect link */
+ tuple->LinkOffset += 5;
+ MFC_FN(tuple->Flags)--;
+ } else if (HAS_LINK(tuple->Flags)) {
+ ofs = tuple->LinkOffset;
+ SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+ HAS_LINK(tuple->Flags) = 0;
+ } else {
+ return -1;
+ }
+ if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
+ /* This is ugly, but a common CIS error is to code the long
+ link offset incorrectly, so we check the right spot... */
+ read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+ if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+ (strncmp(link+2, "CIS", 3) == 0))
+ return ofs;
+ /* Then, we try the wrong spot... */
+ ofs = ofs >> 1;
+ }
+ read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+ if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) ||
+ (strncmp(link+2, "CIS", 3) != 0))
+ return -1;
+ return ofs;
+}
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple)
+{
+ socket_info_t *s;
+ u_char link[2], tmp;
+ int ofs, i, attr;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ link[1] = tuple->TupleLink;
+ ofs = tuple->CISOffset + tuple->TupleLink;
+ attr = SPACE(tuple->Flags);
+
+ for (i = 0; i < MAX_TUPLES; i++) {
+ if (link[1] == 0xff) {
+ link[0] = CISTPL_END;
+ } else {
+ read_cis_cache(s, attr, ofs, 2, link);
+ if (link[0] == CISTPL_NULL) {
+ ofs++; continue;
+ }
+ }
+
+ /* End of chain? Follow long link if possible */
+ if (link[0] == CISTPL_END) {
+ if ((ofs = follow_link(s, tuple)) < 0)
+ return CS_NO_MORE_ITEMS;
+ attr = SPACE(tuple->Flags);
+ read_cis_cache(s, attr, ofs, 2, link);
+ }
+
+ /* Is this a link tuple? Make a note of it */
+ if ((link[0] == CISTPL_LONGLINK_A) ||
+ (link[0] == CISTPL_LONGLINK_C) ||
+ (link[0] == CISTPL_LONGLINK_MFC) ||
+ (link[0] == CISTPL_LINKTARGET) ||
+ (link[0] == CISTPL_NO_LINK)) {
+ switch (link[0]) {
+ case CISTPL_LONGLINK_A:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = 1;
+ read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+ break;
+ case CISTPL_LONGLINK_C:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = 0;
+ read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+ break;
+ case CISTPL_LONGLINK_MFC:
+ tuple->LinkOffset = ofs + 3;
+ LINK_SPACE(tuple->Flags) = attr;
+ if (handle->Function == BIND_FN_ALL) {
+ /* Follow all the MFC links */
+ read_cis_cache(s, attr, ofs+2, 1, &tmp);
+ MFC_FN(tuple->Flags) = tmp;
+ } else {
+ /* Follow exactly one of the links */
+ MFC_FN(tuple->Flags) = 1;
+ tuple->LinkOffset += handle->Function * 5;
+ }
+ break;
+ case CISTPL_NO_LINK:
+ HAS_LINK(tuple->Flags) = 0;
+ break;
+ }
+ if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+ (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+ break;
+ } else
+ if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+ break;
+
+ if (link[0] == tuple->DesiredTuple)
+ break;
+ ofs += link[1] + 2;
+ }
+ if (i == MAX_TUPLES) {
+ DEBUG(1, ("cs: overrun in get_next_tuple for socket %d\n",
+ handle->Socket));
+ return CS_NO_MORE_ITEMS;
+ }
+
+ tuple->TupleCode = link[0];
+ tuple->TupleLink = link[1];
+ tuple->CISOffset = ofs + 2;
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int get_tuple_data(client_handle_t handle, tuple_t *tuple)
+{
+ socket_info_t *s;
+ u_int len;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+
+ s = SOCKET(handle);
+
+ if (tuple->TupleLink < tuple->TupleOffset)
+ return CS_NO_MORE_ITEMS;
+ len = tuple->TupleLink - tuple->TupleOffset;
+ tuple->TupleDataLen = tuple->TupleLink;
+ if (len == 0)
+ return CS_SUCCESS;
+ read_cis_cache(s, SPACE(tuple->Flags),
+ tuple->CISOffset + tuple->TupleOffset,
+ MIN(len, tuple->TupleDataMax), tuple->TupleData);
+ return CS_SUCCESS;
+}
+
+/*======================================================================
+
+ Parsing routines for individual tuples
+
+======================================================================*/
+
+static int parse_device(tuple_t *tuple, cistpl_device_t *device)
+{
+ int i;
+ u_char scale;
+ u_char *p, *q;
+
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ device->ndev = 0;
+ for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+
+ if (*p == 0xff) break;
+ device->dev[i].type = (*p >> 4);
+ device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+ switch (*p & 0x07) {
+ case 0: device->dev[i].speed = 0; break;
+ case 1: device->dev[i].speed = 250; break;
+ case 2: device->dev[i].speed = 200; break;
+ case 3: device->dev[i].speed = 150; break;
+ case 4: device->dev[i].speed = 100; break;
+ case 7:
+ if (++p == q) return CS_BAD_TUPLE;
+ if (p == q)
+ return CS_BAD_TUPLE;
+ device->dev[i].speed = SPEED_CVT(*p);
+ while (*p & 0x80)
+ if (++p == q) return CS_BAD_TUPLE;
+ break;
+ default:
+ return CS_BAD_TUPLE;
+ }
+
+ if (++p == q) return CS_BAD_TUPLE;
+ if (*p == 0xff) break;
+ scale = *p & 7;
+ if (scale == 7) return CS_BAD_TUPLE;
+ device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+ device->ndev++;
+ if (++p == q) break;
+ }
+
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
+{
+ u_char *p;
+ if (tuple->TupleDataLen < 5)
+ return CS_BAD_TUPLE;
+ p = (u_char *)tuple->TupleData;
+ csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
+ csum->len = le16_to_cpu(*(u_short *)(p + 2));
+ csum->sum = *(p+4);
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
+{
+ if (tuple->TupleDataLen < 4)
+ return CS_BAD_TUPLE;
+ link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink_mfc(tuple_t *tuple,
+ cistpl_longlink_mfc_t *link)
+{
+ u_char *p;
+ int i;
+
+ p = (u_char *)tuple->TupleData;
+
+ link->nfn = *p; p++;
+ if (tuple->TupleDataLen <= link->nfn*5)
+ return CS_BAD_TUPLE;
+ for (i = 0; i < link->nfn; i++) {
+ link->fn[i].space = *p; p++;
+ link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+ }
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_strings(u_char *p, u_char *q, int max,
+ char *s, u_char *ofs, u_char *found)
+{
+ int i, j, ns;
+
+ if (p == q) return CS_BAD_TUPLE;
+ ns = 0; j = 0;
+ for (i = 0; i < max; i++) {
+ if (*p == 0xff) break;
+ ofs[i] = j;
+ ns++;
+ for (;;) {
+ s[j++] = (*p == 0xff) ? '\0' : *p;
+ if ((*p == '\0') || (*p == 0xff)) break;
+ if (++p == q) return CS_BAD_TUPLE;
+ }
+ if ((*p == 0xff) || (++p == q)) break;
+ }
+ if (found) {
+ *found = ns;
+ return CS_SUCCESS;
+ } else {
+ return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+ }
+}
+
+/*====================================================================*/
+
+static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
+{
+ u_char *p, *q;
+
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ vers_1->major = *p; p++;
+ vers_1->minor = *p; p++;
+ if (p >= q) return CS_BAD_TUPLE;
+
+ return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+ vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+/*====================================================================*/
+
+static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
+{
+ u_char *p, *q;
+
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+ altstr->str, altstr->ofs, &altstr->ns);
+}
+
+/*====================================================================*/
+
+static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
+{
+ u_char *p, *q;
+ int nid;
+
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+ if (p > q-2) break;
+ jedec->id[nid].mfr = p[0];
+ jedec->id[nid].info = p[1];
+ p += 2;
+ }
+ jedec->nid = nid;
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
+{
+ u_short *p;
+ if (tuple->TupleDataLen < 4)
+ return CS_BAD_TUPLE;
+ p = (u_short *)tuple->TupleData;
+ m->manf = le16_to_cpu(p[0]);
+ m->card = le16_to_cpu(p[1]);
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+ u_char *p;
+ if (tuple->TupleDataLen < 2)
+ return CS_BAD_TUPLE;
+ p = (u_char *)tuple->TupleData;
+ f->func = p[0];
+ f->sysinit = p[1];
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
+{
+ u_char *p;
+ int i;
+ if (tuple->TupleDataLen < 1)
+ return CS_BAD_TUPLE;
+ p = (u_char *)tuple->TupleData;
+ f->type = p[0];
+ for (i = 1; i < tuple->TupleDataLen; i++)
+ f->data[i-1] = p[i];
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_config(tuple_t *tuple, cistpl_config_t *config)
+{
+ int rasz, rmsz, i;
+ u_char *p;
+
+ p = (u_char *)tuple->TupleData;
+ rasz = *p & 0x03;
+ rmsz = (*p & 0x3c) >> 2;
+ if (tuple->TupleDataLen < rasz+rmsz+4)
+ return CS_BAD_TUPLE;
+ config->last_idx = *(++p);
+ p++;
+ config->base = 0;
+ for (i = 0; i <= rasz; i++)
+ config->base += p[i] << (8*i);
+ p += rasz+1;
+ for (i = 0; i < 4; i++)
+ config->rmask[i] = 0;
+ for (i = 0; i <= rmsz; i++)
+ config->rmask[i>>2] += p[i] << (8*(i%4));
+ config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+ return CS_SUCCESS;
+}
+
+/*======================================================================
+
+ The following routines are all used to parse the nightmarish
+ config table entries.
+
+======================================================================*/
+
+static u_char *parse_power(u_char *p, u_char *q,
+ cistpl_power_t *pwr)
+{
+ int i;
+ u_int scale;
+
+ if (p == q) return NULL;
+ pwr->present = *p;
+ pwr->flags = 0;
+ p++;
+ for (i = 0; i < 7; i++)
+ if (pwr->present & (1<<i)) {
+ if (p == q) return NULL;
+ pwr->param[i] = POWER_CVT(*p);
+ scale = POWER_SCALE(*p);
+ while (*p & 0x80) {
+ if (++p == q) return NULL;
+ if ((*p & 0x7f) < 100)
+ pwr->param[i] += (*p & 0x7f) * scale / 100;
+ else if (*p == 0x7d)
+ pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+ else if (*p == 0x7e)
+ pwr->param[i] = 0;
+ else if (*p == 0x7f)
+ pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+ else
+ return NULL;
+ }
+ p++;
+ }
+ return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_timing(u_char *p, u_char *q,
+ cistpl_timing_t *timing)
+{
+ u_char scale;
+
+ if (p == q) return NULL;
+ scale = *p;
+ if ((scale & 3) != 3) {
+ if (++p == q) return NULL;
+ timing->wait = SPEED_CVT(*p);
+ timing->waitscale = exponent[scale & 3];
+ } else
+ timing->wait = 0;
+ scale >>= 2;
+ if ((scale & 7) != 7) {
+ if (++p == q) return NULL;
+ timing->ready = SPEED_CVT(*p);
+ timing->rdyscale = exponent[scale & 7];
+ } else
+ timing->ready = 0;
+ scale >>= 3;
+ if (scale != 7) {
+ if (++p == q) return NULL;
+ timing->reserved = SPEED_CVT(*p);
+ timing->rsvscale = exponent[scale];
+ } else
+ timing->reserved = 0;
+ p++;
+ return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
+{
+ int i, j, bsz, lsz;
+
+ if (p == q) return NULL;
+ io->flags = *p;
+
+ if (!(*p & 0x80)) {
+ io->nwin = 1;
+ io->win[0].base = 0;
+ io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+ return p+1;
+ }
+
+ if (++p == q) return NULL;
+ io->nwin = (*p & 0x0f) + 1;
+ bsz = (*p & 0x30) >> 4;
+ if (bsz == 3) bsz++;
+ lsz = (*p & 0xc0) >> 6;
+ if (lsz == 3) lsz++;
+ p++;
+
+ for (i = 0; i < io->nwin; i++) {
+ io->win[i].base = 0;
+ io->win[i].len = 1;
+ for (j = 0; j < bsz; j++, p++) {
+ if (p == q) return NULL;
+ io->win[i].base += *p << (j*8);
+ }
+ for (j = 0; j < lsz; j++, p++) {
+ if (p == q) return NULL;
+ io->win[i].len += *p << (j*8);
+ }
+ }
+ return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
+{
+ int i, j, asz, lsz, has_ha;
+ u_int len, ca, ha;
+
+ if (p == q) return NULL;
+
+ mem->nwin = (*p & 0x07) + 1;
+ lsz = (*p & 0x18) >> 3;
+ asz = (*p & 0x60) >> 5;
+ has_ha = (*p & 0x80);
+ if (++p == q) return NULL;
+
+ for (i = 0; i < mem->nwin; i++) {
+ len = ca = ha = 0;
+ for (j = 0; j < lsz; j++, p++) {
+ if (p == q) return NULL;
+ len += *p << (j*8);
+ }
+ for (j = 0; j < asz; j++, p++) {
+ if (p == q) return NULL;
+ ca += *p << (j*8);
+ }
+ if (has_ha)
+ for (j = 0; j < asz; j++, p++) {
+ if (p == q) return NULL;
+ ha += *p << (j*8);
+ }
+ mem->win[i].len = len << 8;
+ mem->win[i].card_addr = ca << 8;
+ mem->win[i].host_addr = ha << 8;
+ }
+ return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
+{
+ if (p == q) return NULL;
+ irq->IRQInfo1 = *p; p++;
+ if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+ if (p+2 > q) return NULL;
+ irq->IRQInfo2 = (p[1]<<8) + p[0];
+ p += 2;
+ }
+ return p;
+}
+
+/*====================================================================*/
+
+static int parse_cftable_entry(tuple_t *tuple,
+ cistpl_cftable_entry_t *entry)
+{
+ u_char *p, *q, features;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+ entry->index = *p & 0x3f;
+ entry->flags = 0;
+ if (*p & 0x40)
+ entry->flags |= CISTPL_CFTABLE_DEFAULT;
+ if (*p & 0x80) {
+ if (++p == q) return CS_BAD_TUPLE;
+ if (*p & 0x10)
+ entry->flags |= CISTPL_CFTABLE_BVDS;
+ if (*p & 0x20)
+ entry->flags |= CISTPL_CFTABLE_WP;
+ if (*p & 0x40)
+ entry->flags |= CISTPL_CFTABLE_RDYBSY;
+ if (*p & 0x80)
+ entry->flags |= CISTPL_CFTABLE_MWAIT;
+ entry->interface = *p & 0x0f;
+ } else
+ entry->interface = 0;
+
+ /* Process optional features */
+ if (++p == q) return CS_BAD_TUPLE;
+ features = *p; p++;
+
+ /* Power options */
+ if ((features & 3) > 0) {
+ p = parse_power(p, q, &entry->vcc);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vcc.present = 0;
+ if ((features & 3) > 1) {
+ p = parse_power(p, q, &entry->vpp1);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vpp1.present = 0;
+ if ((features & 3) > 2) {
+ p = parse_power(p, q, &entry->vpp2);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vpp2.present = 0;
+
+ /* Timing options */
+ if (features & 0x04) {
+ p = parse_timing(p, q, &entry->timing);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else {
+ entry->timing.wait = 0;
+ entry->timing.ready = 0;
+ entry->timing.reserved = 0;
+ }
+
+ /* I/O window options */
+ if (features & 0x08) {
+ p = parse_io(p, q, &entry->io);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->io.nwin = 0;
+
+ /* Interrupt options */
+ if (features & 0x10) {
+ p = parse_irq(p, q, &entry->irq);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->irq.IRQInfo1 = 0;
+
+ switch (features & 0x60) {
+ case 0x00:
+ entry->mem.nwin = 0;
+ break;
+ case 0x20:
+ entry->mem.nwin = 1;
+ entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].card_addr = 0;
+ entry->mem.win[0].host_addr = 0;
+ p += 2;
+ if (p > q) return CS_BAD_TUPLE;
+ break;
+ case 0x40:
+ entry->mem.nwin = 1;
+ entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].card_addr =
+ le16_to_cpu(*(u_short *)(p+2)) << 8;
+ entry->mem.win[0].host_addr = 0;
+ p += 4;
+ if (p > q) return CS_BAD_TUPLE;
+ break;
+ case 0x60:
+ p = parse_mem(p, q, &entry->mem);
+ if (p == NULL) return CS_BAD_TUPLE;
+ break;
+ }
+
+ /* Misc features */
+ if (features & 0x80) {
+ if (p == q) return CS_BAD_TUPLE;
+ entry->flags |= (*p << 8);
+ while (*p & 0x80)
+ if (++p == q) return CS_BAD_TUPLE;
+ p++;
+ }
+
+ entry->subtuples = q-p;
+
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
+{
+ u_char *p;
+ if (tuple->TupleDataLen < 6)
+ return CS_BAD_TUPLE;
+ p = (u_char *)tuple->TupleData;
+ bar->attr = *p;
+ p += 2;
+ bar->size = le32_to_cpu(*(u_int *)p);
+ return CS_SUCCESS;
+}
+
+static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
+{
+ u_char *p;
+
+ p = (u_char *)tuple->TupleData;
+ if ((*p != 3) || (tuple->TupleDataLen < 6))
+ return CS_BAD_TUPLE;
+ config->last_idx = *(++p);
+ p++;
+ config->base = le32_to_cpu(*(u_int *)p);
+ config->subtuples = tuple->TupleDataLen - 6;
+ return CS_SUCCESS;
+}
+
+static int parse_cftable_entry_cb(tuple_t *tuple,
+ cistpl_cftable_entry_cb_t *entry)
+{
+ u_char *p, *q, features;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+ entry->index = *p & 0x3f;
+ entry->flags = 0;
+ if (*p & 0x40)
+ entry->flags |= CISTPL_CFTABLE_DEFAULT;
+
+ /* Process optional features */
+ if (++p == q) return CS_BAD_TUPLE;
+ features = *p; p++;
+
+ /* Power options */
+ if ((features & 3) > 0) {
+ p = parse_power(p, q, &entry->vcc);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vcc.present = 0;
+ if ((features & 3) > 1) {
+ p = parse_power(p, q, &entry->vpp1);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vpp1.present = 0;
+ if ((features & 3) > 2) {
+ p = parse_power(p, q, &entry->vpp2);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->vpp2.present = 0;
+
+ /* I/O window options */
+ if (features & 0x08) {
+ if (p == q) return CS_BAD_TUPLE;
+ entry->io = *p; p++;
+ } else
+ entry->io = 0;
+
+ /* Interrupt options */
+ if (features & 0x10) {
+ p = parse_irq(p, q, &entry->irq);
+ if (p == NULL) return CS_BAD_TUPLE;
+ } else
+ entry->irq.IRQInfo1 = 0;
+
+ if (features & 0x20) {
+ if (p == q) return CS_BAD_TUPLE;
+ entry->mem = *p; p++;
+ } else
+ entry->mem = 0;
+
+ /* Misc features */
+ if (features & 0x80) {
+ if (p == q) return CS_BAD_TUPLE;
+ entry->flags |= (*p << 8);
+ if (*p & 0x80) {
+ if (++p == q) return CS_BAD_TUPLE;
+ entry->flags |= (*p << 16);
+ }
+ while (*p & 0x80)
+ if (++p == q) return CS_BAD_TUPLE;
+ p++;
+ }
+
+ entry->subtuples = q-p;
+
+ return CS_SUCCESS;
+}
+
+#endif
+
+/*====================================================================*/
+
+static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
+{
+ u_char *p, *q;
+ int n;
+
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+ if (p > q-6) break;
+ geo->geo[n].buswidth = p[0];
+ geo->geo[n].erase_block = 1 << (p[1]-1);
+ geo->geo[n].read_block = 1 << (p[2]-1);
+ geo->geo[n].write_block = 1 << (p[3]-1);
+ geo->geo[n].partition = 1 << (p[4]-1);
+ geo->geo[n].interleave = 1 << (p[5]-1);
+ p += 6;
+ }
+ geo->ngeo = n;
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
+{
+ u_char *p, *q;
+
+ if (tuple->TupleDataLen < 10)
+ return CS_BAD_TUPLE;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ v2->vers = p[0];
+ v2->comply = p[1];
+ v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+ v2->vspec8 = p[6];
+ v2->vspec9 = p[7];
+ v2->nhdr = p[8];
+ p += 9;
+ return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+/*====================================================================*/
+
+static int parse_org(tuple_t *tuple, cistpl_org_t *org)
+{
+ u_char *p, *q;
+ int i;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+ if (p == q) return CS_BAD_TUPLE;
+ org->data_org = *p;
+ if (++p == q) return CS_BAD_TUPLE;
+ for (i = 0; i < 30; i++) {
+ org->desc[i] = *p;
+ if (*p == '\0') break;
+ if (++p == q) return CS_BAD_TUPLE;
+ }
+ return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+ int ret = CS_SUCCESS;
+
+ if (tuple->TupleDataLen > tuple->TupleDataMax)
+ return CS_BAD_TUPLE;
+ switch (tuple->TupleCode) {
+ case CISTPL_DEVICE:
+ case CISTPL_DEVICE_A:
+ ret = parse_device(tuple, &parse->device);
+ break;
+#ifdef CONFIG_CARDBUS
+ case CISTPL_BAR:
+ ret = parse_bar(tuple, &parse->bar);
+ break;
+ case CISTPL_CONFIG_CB:
+ ret = parse_config_cb(tuple, &parse->config);
+ break;
+ case CISTPL_CFTABLE_ENTRY_CB:
+ ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
+ break;
+#endif
+ case CISTPL_CHECKSUM:
+ ret = parse_checksum(tuple, &parse->checksum);
+ break;
+ case CISTPL_LONGLINK_A:
+ case CISTPL_LONGLINK_C:
+ ret = parse_longlink(tuple, &parse->longlink);
+ break;
+ case CISTPL_LONGLINK_MFC:
+ ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+ break;
+ case CISTPL_VERS_1:
+ ret = parse_vers_1(tuple, &parse->version_1);
+ break;
+ case CISTPL_ALTSTR:
+ ret = parse_altstr(tuple, &parse->altstr);
+ break;
+ case CISTPL_JEDEC_A:
+ case CISTPL_JEDEC_C:
+ ret = parse_jedec(tuple, &parse->jedec);
+ break;
+ case CISTPL_MANFID:
+ ret = parse_manfid(tuple, &parse->manfid);
+ break;
+ case CISTPL_FUNCID:
+ ret = parse_funcid(tuple, &parse->funcid);
+ break;
+ case CISTPL_FUNCE:
+ ret = parse_funce(tuple, &parse->funce);
+ break;
+ case CISTPL_CONFIG:
+ ret = parse_config(tuple, &parse->config);
+ break;
+ case CISTPL_CFTABLE_ENTRY:
+ ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+ break;
+ case CISTPL_DEVICE_GEO:
+ case CISTPL_DEVICE_GEO_A:
+ ret = parse_device_geo(tuple, &parse->device_geo);
+ break;
+ case CISTPL_VERS_2:
+ ret = parse_vers_2(tuple, &parse->vers_2);
+ break;
+ case CISTPL_ORG:
+ ret = parse_org(tuple, &parse->org);
+ break;
+ case CISTPL_NO_LINK:
+ case CISTPL_LINKTARGET:
+ ret = CS_SUCCESS;
+ break;
+ default:
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+ return ret;
+}
+
+/*======================================================================
+
+ This is used internally by Card Services to look up CIS stuff.
+
+======================================================================*/
+
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
+{
+ tuple_t tuple;
+ cisdata_t buf[255];
+ int ret;
+
+ tuple.DesiredTuple = code;
+ tuple.Attributes = TUPLE_RETURN_COMMON;
+ ret = CardServices(GetFirstTuple, handle, &tuple, NULL);
+ if (ret != CS_SUCCESS) return ret;
+ tuple.TupleData = buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = sizeof(buf);
+ ret = CardServices(GetTupleData, handle, &tuple, NULL);
+ if (ret != CS_SUCCESS) return ret;
+ ret = CardServices(ParseTuple, handle, &tuple, parse);
+ return ret;
+}
+
+/*======================================================================
+
+ This tries to determine if a card has a sensible CIS. It returns
+ the number of tuples in the CIS, or 0 if the CIS looks bad. The
+ checks include making sure several critical tuples are present and
+ valid; seeing if the total number of tuples is reasonable; and
+ looking for tuples that use reserved codes.
+
+======================================================================*/
+
+int validate_cis(client_handle_t handle, cisinfo_t *info)
+{
+ tuple_t tuple;
+ cisparse_t p;
+ int ret, reserved, errors;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+
+ info->Chains = reserved = errors = 0;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+ tuple.Attributes = TUPLE_RETURN_COMMON;
+ ret = get_first_tuple(handle, &tuple);
+ if (ret != CS_SUCCESS)
+ return CS_SUCCESS;
+
+ /* First tuple should be DEVICE */
+ if (tuple.TupleCode != CISTPL_DEVICE)
+ errors++;
+ /* All cards should have a MANFID tuple */
+ if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS)
+ errors++;
+ /* All cards should have either a VERS_1 or a VERS_2 tuple. But
+ at worst, we'll accept a CFTABLE_ENTRY that parses. */
+ if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) &&
+ (read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) &&
+ (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) &&
+ (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS))
+ errors++;
+ if (errors > 1)
+ return CS_SUCCESS;
+
+ for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
+ ret = get_next_tuple(handle, &tuple);
+ if (ret != CS_SUCCESS) break;
+ if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) ||
+ ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) ||
+ ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff)))
+ reserved++;
+ }
+ if ((info->Chains == MAX_TUPLES) || (reserved > 5))
+ info->Chains = 0;
+
+ return CS_SUCCESS;
+}
+
--- /dev/null
+/*======================================================================
+
+ PCMCIA Card Services -- core services
+
+ cs.c 1.224 1999/08/28 04:01:45
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/bus_ops.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+#endif
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"cs.c 1.224 1999/08/28 04:01:45 (David Hinds)";
+#endif
+
+static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+
+static const char *options = "options: "
+#ifdef CONFIG_PCI
+" [pci]"
+#endif
+#ifdef CONFIG_CARDBUS
+" [cardbus]"
+#endif
+#ifdef CONFIG_APM
+" [apm]"
+#endif
+#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_APM)
+" none"
+#endif
+;
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int setup_delay = HZ/20; /* ticks */
+static int resume_delay = HZ/5; /* ticks */
+static int shutdown_delay = HZ/40; /* ticks */
+static int vcc_settle = HZ*3/10; /* ticks */
+static int reset_time = 10; /* usecs */
+static int unreset_delay = HZ/10; /* ticks */
+static int unreset_check = HZ/10; /* ticks */
+static int unreset_limit = 30; /* unreset_check's */
+
+/* Access speed for attribute memory windows */
+static int cis_speed = 300; /* ns */
+
+/* Access speed for IO windows */
+static int io_speed = 0; /* ns */
+
+/* Optional features */
+#ifdef CONFIG_APM
+static int do_apm = 1;
+MODULE_PARM(do_apm, "i");
+#endif
+
+MODULE_PARM(setup_delay, "i");
+MODULE_PARM(resume_delay, "i");
+MODULE_PARM(shutdown_delay, "i");
+MODULE_PARM(vcc_settle, "i");
+MODULE_PARM(reset_time, "i");
+MODULE_PARM(unreset_delay, "i");
+MODULE_PARM(unreset_check, "i");
+MODULE_PARM(unreset_limit, "i");
+MODULE_PARM(cis_speed, "i");
+MODULE_PARM(io_speed, "i");
+
+/*====================================================================*/
+
+static socket_state_t dead_socket = {
+ 0, SS_DETECT, 0, 0, 0
+};
+
+/* Table of sockets */
+socket_t sockets = 0;
+socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_pccard = NULL;
+#endif
+
+/*====================================================================*/
+
+/* String tables for error messages */
+
+typedef struct lookup_t {
+ int key;
+ char *msg;
+} lookup_t;
+
+static const lookup_t error_table[] = {
+ { CS_SUCCESS, "Operation succeeded" },
+ { CS_BAD_ADAPTER, "Bad adapter" },
+ { CS_BAD_ATTRIBUTE, "Bad attribute", },
+ { CS_BAD_BASE, "Bad base address" },
+ { CS_BAD_EDC, "Bad EDC" },
+ { CS_BAD_IRQ, "Bad IRQ" },
+ { CS_BAD_OFFSET, "Bad offset" },
+ { CS_BAD_PAGE, "Bad page number" },
+ { CS_READ_FAILURE, "Read failure" },
+ { CS_BAD_SIZE, "Bad size" },
+ { CS_BAD_SOCKET, "Bad socket" },
+ { CS_BAD_TYPE, "Bad type" },
+ { CS_BAD_VCC, "Bad Vcc" },
+ { CS_BAD_VPP, "Bad Vpp" },
+ { CS_BAD_WINDOW, "Bad window" },
+ { CS_WRITE_FAILURE, "Write failure" },
+ { CS_NO_CARD, "No card present" },
+ { CS_UNSUPPORTED_FUNCTION, "Usupported function" },
+ { CS_UNSUPPORTED_MODE, "Unsupported mode" },
+ { CS_BAD_SPEED, "Bad speed" },
+ { CS_BUSY, "Resource busy" },
+ { CS_GENERAL_FAILURE, "General failure" },
+ { CS_WRITE_PROTECTED, "Write protected" },
+ { CS_BAD_ARG_LENGTH, "Bad argument length" },
+ { CS_BAD_ARGS, "Bad arguments" },
+ { CS_CONFIGURATION_LOCKED, "Configuration locked" },
+ { CS_IN_USE, "Resource in use" },
+ { CS_NO_MORE_ITEMS, "No more items" },
+ { CS_OUT_OF_RESOURCE, "Out of resource" },
+ { CS_BAD_HANDLE, "Bad handle" },
+ { CS_BAD_TUPLE, "Bad CIS tuple" }
+};
+#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
+
+static const lookup_t service_table[] = {
+ { AccessConfigurationRegister, "AccessConfigurationRegister" },
+ { AddSocketServices, "AddSocketServices" },
+ { AdjustResourceInfo, "AdjustResourceInfo" },
+ { CheckEraseQueue, "CheckEraseQueue" },
+ { CloseMemory, "CloseMemory" },
+ { DeregisterClient, "DeregisterClient" },
+ { DeregisterEraseQueue, "DeregisterEraseQueue" },
+ { GetCardServicesInfo, "GetCardServicesInfo" },
+ { GetClientInfo, "GetClientInfo" },
+ { GetConfigurationInfo, "GetConfigurationInfo" },
+ { GetEventMask, "GetEventMask" },
+ { GetFirstClient, "GetFirstClient" },
+ { GetFirstRegion, "GetFirstRegion" },
+ { GetFirstTuple, "GetFirstTuple" },
+ { GetNextClient, "GetNextClient" },
+ { GetNextRegion, "GetNextRegion" },
+ { GetNextTuple, "GetNextTuple" },
+ { GetStatus, "GetStatus" },
+ { GetTupleData, "GetTupleData" },
+ { MapMemPage, "MapMemPage" },
+ { ModifyConfiguration, "ModifyConfiguration" },
+ { ModifyWindow, "ModifyWindow" },
+ { OpenMemory, "OpenMemory" },
+ { ParseTuple, "ParseTuple" },
+ { ReadMemory, "ReadMemory" },
+ { RegisterClient, "RegisterClient" },
+ { RegisterEraseQueue, "RegisterEraseQueue" },
+ { RegisterMTD, "RegisterMTD" },
+ { ReleaseConfiguration, "ReleaseConfiguration" },
+ { ReleaseIO, "ReleaseIO" },
+ { ReleaseIRQ, "ReleaseIRQ" },
+ { ReleaseWindow, "ReleaseWindow" },
+ { RequestConfiguration, "RequestConfiguration" },
+ { RequestIO, "RequestIO" },
+ { RequestIRQ, "RequestIRQ" },
+ { RequestSocketMask, "RequestSocketMask" },
+ { RequestWindow, "RequestWindow" },
+ { ResetCard, "ResetCard" },
+ { SetEventMask, "SetEventMask" },
+ { ValidateCIS, "ValidateCIS" },
+ { WriteMemory, "WriteMemory" },
+ { BindDevice, "BindDevice" },
+ { BindMTD, "BindMTD" },
+ { ReportError, "ReportError" },
+ { SuspendCard, "SuspendCard" },
+ { ResumeCard, "ResumeCard" },
+ { EjectCard, "EjectCard" },
+ { InsertCard, "InsertCard" },
+ { ReplaceCIS, "ReplaceCIS" }
+};
+#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))
+
+/*======================================================================
+
+ Reset a socket to the default state
+
+======================================================================*/
+
+static void init_socket(socket_info_t *s)
+{
+ int i;
+ pccard_io_map io = { 0, 0, 0, 0, 1 };
+ pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
+
+ mem.sys_stop = s->cap.map_size;
+ s->socket = dead_socket;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ for (i = 0; i < 2; i++) {
+ io.map = i;
+ s->ss_entry(s->sock, SS_SetIOMap, &io);
+ }
+ for (i = 0; i < 5; i++) {
+ mem.map = i;
+ s->ss_entry(s->sock, SS_SetMemMap, &mem);
+ }
+}
+
+/*====================================================================*/
+
+#if defined(CONFIG_PROC_FS) && defined(PCMCIA_DEBUG)
+int proc_read_clients(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ socket_info_t *s = data;
+ client_handle_t c;
+ char *p = buf;
+
+ for (c = s->clients; c; c = c->next)
+ p += sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n",
+ c->Function, c->dev_info, c->Attributes, c->state);
+ return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+ Low-level PC Card interface drivers need to register with Card
+ Services using these calls.
+
+======================================================================*/
+
+static void setup_socket(u_long i);
+static void shutdown_socket(u_long i);
+static void reset_socket(u_long i);
+static void unreset_socket(u_long i);
+static void parse_events(void *info, u_int events);
+
+int register_ss_entry(int nsock, ss_entry_t ss_entry)
+{
+ int i, ns;
+ socket_info_t *s;
+
+ DEBUG(0, ("cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry));
+
+ for (ns = 0; ns < nsock; ns++) {
+ s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+ memset(s, 0, sizeof(socket_info_t));
+
+ s->ss_entry = ss_entry;
+ s->sock = ns;
+ s->setup.data = sockets;
+ s->setup.function = &setup_socket;
+ s->shutdown.data = sockets;
+ s->shutdown.function = &shutdown_socket;
+ /* base address = 0, map = 0 */
+ s->cis_mem.flags = 0;
+ s->cis_mem.speed = cis_speed;
+ s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+
+ for (i = 0; i < sockets; i++)
+ if (socket_table[i] == NULL) break;
+ socket_table[i] = s;
+ if (i == sockets) sockets++;
+
+ init_socket(s);
+ ss_entry(ns, SS_InquireSocket, &s->cap);
+#ifdef CONFIG_PROC_FS
+ if (proc_pccard) {
+ char name[3];
+#ifdef PCMCIA_DEBUG
+ struct proc_dir_entry *ent;
+#endif
+ sprintf(name, "%02d", i);
+ s->proc = create_proc_entry(name, S_IFDIR, proc_pccard);
+#ifdef PCMCIA_DEBUG
+ ent = create_proc_entry("clients", 0, s->proc);
+ ent->read_proc = proc_read_clients;
+ ent->data = s;
+#endif
+ ss_entry(ns, SS_ProcSetup, s->proc);
+ }
+#endif
+ }
+
+ return 0;
+} /* register_ss_entry */
+
+/*====================================================================*/
+
+void unregister_ss_entry(ss_entry_t ss_entry)
+{
+ int i, j;
+ socket_info_t *s = NULL;
+ client_t *client;
+
+ for (;;) {
+ for (i = 0; i < sockets; i++) {
+ s = socket_table[i];
+ if (s->ss_entry == ss_entry) break;
+ }
+ if (i == sockets) {
+ break;
+ } else {
+#ifdef CONFIG_PROC_FS
+ if (proc_pccard) {
+ char name[3];
+ sprintf(name, "%02d", i);
+#ifdef PCMCIA_DEBUG
+ remove_proc_entry("clients", s->proc);
+#endif
+ remove_proc_entry(name, proc_pccard);
+ }
+#endif
+ while (s->clients) {
+ client = s->clients;
+ s->clients = s->clients->next;
+ kfree(client);
+ }
+ init_socket(s);
+ release_cis_mem(s);
+#ifdef CONFIG_CARDBUS
+ cb_release_cis_mem(s);
+#endif
+ s->ss_entry = NULL;
+ kfree(s);
+ socket_table[i] = NULL;
+ for (j = i; j < sockets-1; j++)
+ socket_table[j] = socket_table[j+1];
+ sockets--;
+ }
+ }
+
+} /* unregister_ss_entry */
+
+/*======================================================================
+
+ Shutdown_Socket() and setup_socket() are scheduled using add_timer
+ calls by the main event handler when card insertion and removal
+ events are received. Shutdown_Socket() unconfigures a socket and
+ turns off socket power. Setup_socket() turns on socket power
+ and resets the socket, in two stages.
+
+======================================================================*/
+
+static void free_regions(memory_handle_t *list)
+{
+ memory_handle_t tmp;
+ while (*list != NULL) {
+ tmp = *list;
+ *list = tmp->info.next;
+ tmp->region_magic = 0;
+ kfree(tmp);
+ }
+}
+
+static int send_event(socket_info_t *s, event_t event, int priority);
+
+static void shutdown_socket(u_long i)
+{
+ socket_info_t *s = socket_table[i];
+ client_t **c;
+
+ DEBUG(1, ("cs: shutdown_socket(%ld)\n", i));
+
+ /* Blank out the socket state */
+ s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
+ init_socket(s);
+ s->irq.AssignedIRQ = s->irq.Config = 0;
+ s->functions = 0;
+ s->lock_count = 0;
+ s->cis_used = 0;
+ if (s->fake_cis) {
+ kfree(s->fake_cis);
+ s->fake_cis = NULL;
+ }
+#ifdef CONFIG_CARDBUS
+ cb_release_cis_mem(s);
+#endif
+ if (s->config) {
+ kfree(s->config);
+ s->config = NULL;
+ }
+ for (c = &s->clients; *c; ) {
+ if ((*c)->state & CLIENT_UNBOUND) {
+ client_t *d = *c;
+ *c = (*c)->next;
+ kfree(d);
+ } else {
+ c = &((*c)->next);
+ }
+ }
+ free_regions(&s->a_region);
+ free_regions(&s->c_region);
+} /* shutdown_socket */
+
+static void setup_socket(u_long i)
+{
+ int val;
+ socket_info_t *s = socket_table[i];
+
+ s->ss_entry(s->sock, SS_GetStatus, &val);
+ if (val & SS_DETECT) {
+ DEBUG(1, ("cs: setup_socket(%ld): applying power\n", i));
+ s->state |= SOCKET_PRESENT;
+ s->socket.flags = 0;
+ if (val & SS_3VCARD)
+ s->socket.Vcc = s->socket.Vpp = 33;
+ else if (!(val & SS_XVCARD))
+ s->socket.Vcc = s->socket.Vpp = 50;
+ else {
+ printk(KERN_NOTICE "cs: socket %ld: unsupported "
+ "voltage key\n", i);
+ s->socket.Vcc = 0;
+ }
+ if (val & SS_CARDBUS) {
+ s->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+ printk(KERN_NOTICE "cs: unsupported card type detected!\n");
+#endif
+ }
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ s->setup.function = &reset_socket;
+ s->setup.expires = jiffies + vcc_settle;
+ add_timer(&s->setup);
+ } else
+ DEBUG(0, ("cs: setup_socket(%ld): no card!\n", i));
+} /* setup_socket */
+
+/*======================================================================
+
+ Reset_socket() and unreset_socket() handle hard resets. Resets
+ have several causes: card insertion, a call to reset_socket, or
+ recovery from a suspend/resume cycle. Unreset_socket() sends
+ a CS event that matches the cause of the reset.
+
+======================================================================*/
+
+static void reset_socket(u_long i)
+{
+ socket_info_t *s = socket_table[i];
+
+ DEBUG(1, ("cs: resetting socket %ld\n", i));
+ s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ udelay((long)reset_time);
+ s->socket.flags &= ~SS_RESET;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ s->unreset_timeout = 0;
+ s->setup.expires = jiffies + unreset_delay;
+ s->setup.function = &unreset_socket;
+ add_timer(&s->setup);
+} /* reset_socket */
+
+#define EVENT_MASK \
+(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
+
+static void unreset_socket(u_long i)
+{
+ socket_info_t *s = socket_table[i];
+ int val;
+
+ s->ss_entry(s->sock, SS_GetStatus, &val);
+ if (val & SS_READY) {
+ DEBUG(1, ("cs: reset done on socket %ld\n", i));
+ if (s->state & SOCKET_SUSPEND) {
+ s->state &= ~EVENT_MASK;
+ if (verify_cis_cache(s) != 0)
+ parse_events(s, SS_DETECT);
+ else
+ send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+ } else if (s->state & SOCKET_SETUP_PENDING) {
+ send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ s->state &= ~SOCKET_SETUP_PENDING;
+ } else {
+ send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+ s->reset_handle->event_callback_args.info = NULL;
+ EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
+ CS_EVENT_PRI_LOW);
+ s->state &= ~EVENT_MASK;
+ }
+ } else {
+ DEBUG(2, ("cs: socket %ld not ready yet\n", i));
+ if (s->unreset_timeout > unreset_limit) {
+ printk(KERN_NOTICE "cs: socket %ld timed out during"
+ " reset\n", i);
+ s->state &= ~EVENT_MASK;
+ } else {
+ s->unreset_timeout++;
+ s->setup.expires = jiffies + unreset_check;
+ add_timer(&s->setup);
+ }
+ }
+} /* unreset_socket */
+
+/*======================================================================
+
+ The central event handler. Send_event() sends an event to all
+ valid clients. Parse_events() interprets the event bits from
+ a card status change report. Do_shotdown() handles the high
+ priority stuff associated with a card removal.
+
+======================================================================*/
+
+static int send_event(socket_info_t *s, event_t event, int priority)
+{
+ client_t *client = s->clients;
+ int ret;
+ DEBUG(1, ("cs: send_event(sock %d, event %d, pri %d)\n",
+ s->sock, event, priority));
+ ret = 0;
+ for (; client; client = client->next) {
+ if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ continue;
+ if (client->EventMask & event) {
+ ret = EVENT(client, event, priority);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ return ret;
+} /* send_event */
+
+static void do_shutdown(socket_info_t *s)
+{
+ client_t *client;
+ if (s->state & SOCKET_SHUTDOWN_PENDING)
+ return;
+ s->state |= SOCKET_SHUTDOWN_PENDING;
+ send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+ for (client = s->clients; client; client = client->next)
+ if (!(client->Attributes & INFO_MASTER_CLIENT))
+ client->state |= CLIENT_STALE;
+ if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
+ DEBUG(0, ("cs: flushing pending setup\n"));
+ del_timer(&s->setup);
+ s->state &= ~EVENT_MASK;
+ }
+ s->shutdown.expires = jiffies + shutdown_delay;
+ add_timer(&s->shutdown);
+ s->state &= ~SOCKET_PRESENT;
+}
+
+static void parse_events(void *info, u_int events)
+{
+ socket_info_t *s = info;
+ if (events & SS_DETECT) {
+ int status;
+ u_long flags;
+ spin_lock_irqsave(&s->lock, flags);
+ s->ss_entry(s->sock, SS_GetStatus, &status);
+ if ((s->state & SOCKET_PRESENT) &&
+ (!(s->state & SOCKET_SUSPEND) ||
+ !(status & SS_DETECT)))
+ do_shutdown(s);
+ if (status & SS_DETECT) {
+ if (s->state & SOCKET_SETUP_PENDING) {
+ del_timer(&s->setup);
+ DEBUG(1, ("cs: delaying pending setup\n"));
+ }
+ s->state |= SOCKET_SETUP_PENDING;
+ s->setup.function = &setup_socket;
+ if (s->state & SOCKET_SUSPEND)
+ s->setup.expires = jiffies + resume_delay;
+ else
+ s->setup.expires = jiffies + setup_delay;
+ add_timer(&s->setup);
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ if (events & SS_BATDEAD)
+ send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+ if (events & SS_BATWARN)
+ send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+ if (events & SS_READY) {
+ if (!(s->state & SOCKET_RESET_PENDING))
+ send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+ else DEBUG(1, ("cs: ready change during reset\n"));
+ }
+} /* parse_events */
+
+/*======================================================================
+
+ Another event handler, for power management events.
+
+ This does not comply with the latest PC Card spec for handling
+ power management events.
+
+======================================================================*/
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+ int i, stat;
+ socket_info_t *s;
+ static int down = 0;
+
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ DEBUG(1, ("cs: received suspend notification\n"));
+ if (down) {
+ printk(KERN_DEBUG "cs: received extra suspend event\n");
+ break;
+ }
+ down = 1;
+ for (i = 0; i < sockets; i++) {
+ s = socket_table[i];
+ if ((s->state & SOCKET_PRESENT) &&
+ !(s->state & SOCKET_SUSPEND)){
+ send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+ s->state |= SOCKET_SUSPEND;
+ }
+ }
+ break;
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ DEBUG(1, ("cs: received resume notification\n"));
+ if (!down) {
+ printk(KERN_DEBUG "cs: received bogus resume event\n");
+ break;
+ }
+ down = 0;
+ for (i = 0; i < sockets; i++) {
+ s = socket_table[i];
+ /* Do this just to reinitialize the socket */
+ init_socket(s);
+ s->ss_entry(s->sock, SS_GetStatus, &stat);
+ /* If there was or is a card here, we need to do something
+ about it... but parse_events will sort it all out. */
+ if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
+ parse_events(s, SS_DETECT);
+ }
+ break;
+ }
+ return 0;
+} /* handle_apm_event */
+#endif
+
+/*======================================================================
+
+ Special stuff for managing IO windows, because they are scarce.
+
+======================================================================*/
+
+static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base,
+ ioaddr_t num, char *name)
+{
+ int i;
+ ioaddr_t try;
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (s->io[i].NumPorts == 0) {
+ if (find_io_region(base, num, name) == 0) {
+ s->io[i].Attributes = attr;
+ s->io[i].BasePort = *base;
+ s->io[i].NumPorts = s->io[i].InUse = num;
+ break;
+ } else
+ return 1;
+ } else if (s->io[i].Attributes != attr)
+ continue;
+ /* Try to extend top of window */
+ try = s->io[i].BasePort + s->io[i].NumPorts;
+ if ((*base == 0) || (*base == try))
+ if (find_io_region(&try, num, name) == 0) {
+ *base = try;
+ s->io[i].NumPorts += num;
+ s->io[i].InUse += num;
+ break;
+ }
+ /* Try to extend bottom of window */
+ try = s->io[i].BasePort - num;
+ if ((*base == 0) || (*base == try))
+ if (find_io_region(&try, num, name) == 0) {
+ s->io[i].BasePort = *base = try;
+ s->io[i].NumPorts += num;
+ s->io[i].InUse += num;
+ break;
+ }
+ }
+ return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+static void release_io_space(socket_info_t *s, ioaddr_t base,
+ ioaddr_t num)
+{
+ int i;
+ release_region(base, num);
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if ((s->io[i].BasePort <= base) &&
+ (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+ s->io[i].InUse -= num;
+ /* Free the window if no one else is using it */
+ if (s->io[i].InUse == 0)
+ s->io[i].NumPorts = 0;
+ }
+ }
+}
+
+/*======================================================================
+
+ Access_configuration_register() reads and writes configuration
+ registers in attribute memory. Memory window 0 is reserved for
+ this and the tuple reading services.
+
+======================================================================*/
+
+static int access_configuration_register(client_handle_t handle,
+ conf_reg_t *reg)
+{
+ socket_info_t *s;
+ config_t *c;
+ int addr;
+ u_char val;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (handle->Function == BIND_FN_ALL) {
+ if (reg->Function >= s->functions)
+ return CS_BAD_ARGS;
+ c = &s->config[reg->Function];
+ } else
+ c = CONFIG(handle);
+ if (!(c->state & CONFIG_LOCKED))
+ return CS_CONFIGURATION_LOCKED;
+
+ addr = (c->ConfigBase + reg->Offset) >> 1;
+
+ switch (reg->Action) {
+ case CS_READ:
+ read_cis_mem(s, 1, addr, 1, &val);
+ reg->Value = val;
+ break;
+ case CS_WRITE:
+ val = reg->Value;
+ write_cis_mem(s, 1, addr, 1, &val);
+ break;
+ default:
+ return CS_BAD_ARGS;
+ break;
+ }
+ return CS_SUCCESS;
+} /* access_configuration_register */
+
+/*======================================================================
+
+ Bind_device() associates a device driver with a particular socket.
+ It is normally called by Driver Services after it has identified
+ a newly inserted card. An instance of that driver will then be
+ eligible to register as a client of this socket.
+
+======================================================================*/
+
+static int bind_device(bind_req_t *req)
+{
+ client_t *client;
+ socket_info_t *s;
+
+ if (CHECK_SOCKET(req->Socket))
+ return CS_BAD_SOCKET;
+ s = SOCKET(req);
+
+ client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);
+ memset(client, '\0', sizeof(client_t));
+ client->client_magic = CLIENT_MAGIC;
+ strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+ client->Socket = req->Socket;
+ client->Function = req->Function;
+ client->state = CLIENT_UNBOUND;
+ client->erase_busy.next = &client->erase_busy;
+ client->erase_busy.prev = &client->erase_busy;
+ init_waitqueue_head(&client->mtd_req);
+ client->next = s->clients;
+ s->clients = client;
+ DEBUG(1, ("cs: bind_device(): client 0x%p, sock %d, dev %s\n",
+ client, client->Socket, client->dev_info));
+ return CS_SUCCESS;
+} /* bind_device */
+
+/*======================================================================
+
+ Bind_mtd() associates a device driver with a particular memory
+ region. It is normally called by Driver Services after it has
+ identified a memory device type. An instance of the corresponding
+ driver will then be able to register to control this region.
+
+======================================================================*/
+
+static int bind_mtd(mtd_bind_t *req)
+{
+ socket_info_t *s;
+ memory_handle_t region;
+
+ if (CHECK_SOCKET(req->Socket))
+ return CS_BAD_SOCKET;
+ s = SOCKET(req);
+
+ if (req->Attributes & REGION_TYPE_AM)
+ region = s->a_region;
+ else
+ region = s->c_region;
+
+ while (region) {
+ if (region->info.CardOffset == req->CardOffset) break;
+ region = region->info.next;
+ }
+ if (!region || (region->mtd != NULL))
+ return CS_BAD_OFFSET;
+ strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+
+ DEBUG(1, ("cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
+ req->Attributes, req->CardOffset, (char *)req->dev_info));
+ return CS_SUCCESS;
+} /* bind_mtd */
+
+/*====================================================================*/
+
+static int deregister_client(client_handle_t handle)
+{
+ client_t **client;
+ socket_info_t *s;
+ memory_handle_t region;
+ u_long flags;
+ int i, sn;
+
+ DEBUG(1, ("cs: deregister_client(%p)\n", handle));
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ if (handle->state &
+ (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+ return CS_IN_USE;
+ for (i = 0; i < MAX_WIN; i++)
+ if (handle->state & CLIENT_WIN_REQ(i))
+ return CS_IN_USE;
+
+ /* Disconnect all MTD links */
+ s = SOCKET(handle);
+ if (handle->mtd_count) {
+ for (region = s->a_region; region; region = region->info.next)
+ if (region->mtd == handle) region->mtd = NULL;
+ for (region = s->c_region; region; region = region->info.next)
+ if (region->mtd == handle) region->mtd = NULL;
+ }
+
+ sn = handle->Socket; s = socket_table[sn];
+
+ if ((handle->state & CLIENT_STALE) ||
+ (handle->Attributes & INFO_MASTER_CLIENT)) {
+ spin_lock_irqsave(&s->lock, flags);
+ client = &s->clients;
+ while ((*client) && ((*client) != handle))
+ client = &(*client)->next;
+ if (*client == NULL)
+ return CS_BAD_HANDLE;
+ *client = handle->next;
+ handle->client_magic = 0;
+ kfree(handle);
+ spin_unlock_irqrestore(&s->lock, flags);
+ } else {
+ handle->state = CLIENT_UNBOUND;
+ handle->mtd_count = 0;
+ handle->event_handler = NULL;
+ }
+
+ if (--s->real_clients == 0)
+ s->ss_entry(sn, SS_RegisterCallback, NULL);
+
+ return CS_SUCCESS;
+} /* deregister_client */
+
+/*====================================================================*/
+
+static int get_configuration_info(client_handle_t handle,
+ config_info_t *config)
+{
+ socket_info_t *s;
+ config_t *c;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ if (handle->Function == BIND_FN_ALL) {
+ if (config->Function && (config->Function >= s->functions))
+ return CS_BAD_ARGS;
+ } else
+ config->Function = handle->Function;
+
+#ifdef CONFIG_CARDBUS
+ if (s->state & SOCKET_CARDBUS) {
+ u_char fn = config->Function;
+ memset(config, 0, sizeof(config_info_t));
+ config->Function = fn;
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ config->Option = s->cap.cardbus;
+ if (s->cb_config) {
+ config->Attributes = CONF_VALID_CLIENT;
+ config->IntType = INT_CARDBUS;
+ config->AssignedIRQ = s->irq.AssignedIRQ;
+ if (config->AssignedIRQ)
+ config->Attributes |= CONF_ENABLE_IRQ;
+ config->BasePort1 = s->io[0].BasePort;
+ config->NumPorts1 = s->io[0].NumPorts;
+ }
+ return CS_SUCCESS;
+ }
+#endif
+
+ c = (s->config != NULL) ? &s->config[config->Function] : NULL;
+
+ if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+ config->Attributes = 0;
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ return CS_SUCCESS;
+ }
+
+ /* !!! This is a hack !!! */
+ memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+ config->Attributes |= CONF_VALID_CLIENT;
+ config->CardValues = c->CardValues;
+ config->IRQAttributes = c->irq.Attributes;
+ config->AssignedIRQ = s->irq.AssignedIRQ;
+ config->BasePort1 = c->io.BasePort1;
+ config->NumPorts1 = c->io.NumPorts1;
+ config->Attributes1 = c->io.Attributes1;
+ config->BasePort2 = c->io.BasePort2;
+ config->NumPorts2 = c->io.NumPorts2;
+ config->Attributes2 = c->io.Attributes2;
+ config->IOAddrLines = c->io.IOAddrLines;
+
+ return CS_SUCCESS;
+} /* get_configuration_info */
+
+/*======================================================================
+
+ Return information about this version of Card Services.
+
+======================================================================*/
+
+static int get_card_services_info(servinfo_t *info)
+{
+ info->Signature[0] = 'C';
+ info->Signature[1] = 'S';
+ info->Count = sockets;
+ info->Revision = CS_RELEASE_CODE;
+ info->CSLevel = 0x0210;
+ info->VendorString = (char *)release;
+ return CS_SUCCESS;
+} /* get_card_services_info */
+
+/*======================================================================
+
+ Note that get_first_client() *does* recognize the Socket field
+ in the request structure.
+
+======================================================================*/
+
+static int get_first_client(client_handle_t *handle, client_req_t *req)
+{
+ socket_t s;
+ if (req->Attributes & CLIENT_THIS_SOCKET)
+ s = req->Socket;
+ else
+ s = 0;
+ if (CHECK_SOCKET(req->Socket))
+ return CS_BAD_SOCKET;
+ if (socket_table[s]->clients == NULL)
+ return CS_NO_MORE_ITEMS;
+ *handle = socket_table[s]->clients;
+ return CS_SUCCESS;
+} /* get_first_client */
+
+/*====================================================================*/
+
+static int get_next_client(client_handle_t *handle, client_req_t *req)
+{
+ socket_info_t *s;
+ if ((handle == NULL) || CHECK_HANDLE(*handle))
+ return CS_BAD_HANDLE;
+ if ((*handle)->next == NULL) {
+ if (req->Attributes & CLIENT_THIS_SOCKET)
+ return CS_NO_MORE_ITEMS;
+ s = SOCKET(*handle);
+ if (s->clients == NULL)
+ return CS_NO_MORE_ITEMS;
+ *handle = s->clients;
+ } else
+ *handle = (*handle)->next;
+ return CS_SUCCESS;
+} /* get_next_client */
+
+/*======================================================================
+
+ Get the current socket state bits. We don't support the latched
+ SocketState yet: I haven't seen any point for it.
+
+======================================================================*/
+
+static int get_status(client_handle_t handle, cs_status_t *status)
+{
+ socket_info_t *s;
+ config_t *c;
+ int val;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ s->ss_entry(s->sock, SS_GetStatus, &val);
+ status->CardState = status->SocketState = 0;
+ status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+ status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+ status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+ status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+ if (s->state & SOCKET_SUSPEND)
+ status->CardState |= CS_EVENT_PM_SUSPEND;
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (s->state & SOCKET_SETUP_PENDING)
+ status->CardState |= CS_EVENT_CARD_INSERTION;
+
+ /* Get info from the PRR, if necessary */
+ if (handle->Function == BIND_FN_ALL) {
+ if (status->Function && (status->Function >= s->functions))
+ return CS_BAD_ARGS;
+ c = (s->config != NULL) ? &s->config[status->Function] : NULL;
+ } else
+ c = CONFIG(handle);
+ if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+ (c->IntType & INT_MEMORY_AND_IO)) {
+ u_char reg;
+ if (c->Present & PRESENT_PIN_REPLACE) {
+ read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®);
+ status->CardState |=
+ (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+ status->CardState |=
+ (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+ status->CardState |=
+ (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+ status->CardState |=
+ (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+ } else {
+ /* No PRR? Then assume we're always ready */
+ status->CardState |= CS_EVENT_READY_CHANGE;
+ }
+ if (c->Present & PRESENT_EXT_STATUS) {
+ read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®);
+ status->CardState |=
+ (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+ }
+ return CS_SUCCESS;
+ }
+ status->CardState |=
+ (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+ status->CardState |=
+ (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+ status->CardState |=
+ (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+ status->CardState |=
+ (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+ return CS_SUCCESS;
+} /* get_status */
+
+/*======================================================================
+
+ Change the card address of an already open memory window.
+
+======================================================================*/
+
+static int map_mem_page(window_handle_t win, memreq_t *req)
+{
+ socket_info_t *s;
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ if (req->Page != 0)
+ return CS_BAD_PAGE;
+
+ s = win->sock;
+ win->ctl.card_start = req->CardOffset;
+ if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+ return CS_BAD_OFFSET;
+ return CS_SUCCESS;
+} /* map_mem_page */
+
+/*======================================================================
+
+ Modify a locked socket configuration
+
+======================================================================*/
+
+static int modify_configuration(client_handle_t handle,
+ modconf_t *mod)
+{
+ socket_info_t *s;
+ config_t *c;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle); c = CONFIG(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (!(c->state & CONFIG_LOCKED))
+ return CS_CONFIGURATION_LOCKED;
+
+ if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+ if (mod->Attributes & CONF_ENABLE_IRQ) {
+ c->Attributes |= CONF_ENABLE_IRQ;
+ s->socket.io_irq = s->irq.AssignedIRQ;
+ } else {
+ c->Attributes &= ~CONF_ENABLE_IRQ;
+ s->socket.io_irq = 0;
+ }
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ }
+
+ if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+ return CS_BAD_VCC;
+
+ /* We only allow changing Vpp1 and Vpp2 to the same value */
+ if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+ (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+ if (mod->Vpp1 != mod->Vpp2)
+ return CS_BAD_VPP;
+ c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+ if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+ return CS_BAD_VPP;
+ } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+ (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+ return CS_BAD_VPP;
+
+ return CS_SUCCESS;
+} /* modify_configuration */
+
+/*======================================================================
+
+ Modify the attributes of a window returned by RequestWindow.
+
+======================================================================*/
+
+static int modify_window(window_handle_t win, modwin_t *req)
+{
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+
+ win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE);
+ if (req->Attributes & WIN_MEMORY_TYPE)
+ win->ctl.flags |= MAP_ATTRIB;
+ if (req->Attributes & WIN_ENABLE)
+ win->ctl.flags |= MAP_ACTIVE;
+ if (req->Attributes & WIN_DATA_WIDTH)
+ win->ctl.flags |= MAP_16BIT;
+ if (req->Attributes & WIN_USE_WAIT)
+ win->ctl.flags |= MAP_USE_WAIT;
+ win->ctl.speed = req->AccessSpeed;
+ win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+
+ return CS_SUCCESS;
+} /* modify_window */
+
+/*======================================================================
+
+ Register_client() uses the dev_info_t handle to match the
+ caller with a socket. The driver must have already been bound
+ to a socket with bind_device() -- in fact, bind_device()
+ allocates the client structure that will be used.
+
+======================================================================*/
+
+static int register_client(client_handle_t *handle, client_reg_t *req)
+{
+ client_t *client;
+ socket_info_t *s;
+ socket_t ns;
+
+ /* Look for unbound client with matching dev_info */
+ client = NULL;
+ for (ns = 0; ns < sockets; ns++) {
+ client = socket_table[ns]->clients;
+ while (client != NULL) {
+ if ((strcmp(client->dev_info, (char *)req->dev_info) == 0)
+ && (client->state & CLIENT_UNBOUND)) break;
+ client = client->next;
+ }
+ if (client != NULL) break;
+ }
+ if (client == NULL)
+ return CS_OUT_OF_RESOURCE;
+
+ s = socket_table[ns];
+ if (++s->real_clients == 1) {
+ ss_callback_t call;
+ int status;
+ call.handler = &parse_events;
+ call.info = s;
+ s->ss_entry(ns, SS_RegisterCallback, &call);
+ s->ss_entry(ns, SS_GetStatus, &status);
+ if ((status & SS_DETECT) &&
+ !(s->state & SOCKET_SETUP_PENDING)) {
+ s->state |= SOCKET_SETUP_PENDING;
+ setup_socket(ns);
+ }
+ }
+
+ *handle = client;
+ client->state &= ~CLIENT_UNBOUND;
+ client->Socket = ns;
+ client->Attributes = req->Attributes;
+ client->EventMask = req->EventMask;
+ client->event_handler = req->event_handler;
+ client->event_callback_args = req->event_callback_args;
+ client->event_callback_args.client_handle = client;
+ client->event_callback_args.bus = s->cap.bus;
+
+ if (s->state & SOCKET_CARDBUS)
+ client->state |= CLIENT_CARDBUS;
+
+ if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
+ (client->Function != BIND_FN_ALL)) {
+ cistpl_longlink_mfc_t mfc;
+ if (read_tuple(client, CISTPL_LONGLINK_MFC, &mfc)
+ == CS_SUCCESS)
+ s->functions = mfc.nfn;
+ else
+ s->functions = 1;
+ s->config = kmalloc(sizeof(config_t) * s->functions,
+ GFP_KERNEL);
+ memset(s->config, 0, sizeof(config_t) * s->functions);
+ }
+
+ DEBUG(1, ("cs: register_client(): client 0x%p, sock %d, dev %s\n",
+ client, client->Socket, client->dev_info));
+ if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
+ EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+ if ((socket_table[ns]->state & SOCKET_PRESENT) &&
+ !(socket_table[ns]->state & SOCKET_SETUP_PENDING)) {
+ if (client->EventMask & CS_EVENT_CARD_INSERTION)
+ EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ else
+ client->PendingEvents |= CS_EVENT_CARD_INSERTION;
+ }
+ return CS_SUCCESS;
+} /* register_client */
+
+/*====================================================================*/
+
+static int release_configuration(client_handle_t handle,
+ socket_t *Socket)
+{
+ pccard_io_map io;
+ socket_info_t *s;
+ int i;
+
+ if (CHECK_HANDLE(handle) ||
+ !(handle->state & CLIENT_CONFIG_LOCKED))
+ return CS_BAD_HANDLE;
+ handle->state &= ~CLIENT_CONFIG_LOCKED;
+ s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+ if (handle->state & CLIENT_CARDBUS) {
+ cb_disable(s);
+ s->lock_count = 0;
+ return CS_SUCCESS;
+ }
+#endif
+
+ if (!(handle->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(handle);
+ if (--(s->lock_count) == 0) {
+ s->socket.flags = SS_OUTPUT_ENA;
+ s->socket.Vpp = 0;
+ s->socket.io_irq = 0;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ }
+ if (c->state & CONFIG_IO_REQ)
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (s->io[i].NumPorts == 0)
+ continue;
+ s->io[i].Config--;
+ if (s->io[i].Config != 0)
+ continue;
+ io.map = i;
+ s->ss_entry(s->sock, SS_GetIOMap, &io);
+ io.flags &= ~MAP_ACTIVE;
+ s->ss_entry(s->sock, SS_SetIOMap, &io);
+ }
+ c->state &= ~CONFIG_LOCKED;
+ }
+
+ return CS_SUCCESS;
+} /* release_configuration */
+
+/*======================================================================
+
+ Release_io() releases the I/O ranges allocated by a client. This
+ may be invoked some time after a card ejection has already dumped
+ the actual socket configuration, so if the client is "stale", we
+ don't bother checking the port ranges against the current socket
+ values.
+
+======================================================================*/
+
+static int release_io(client_handle_t handle, io_req_t *req)
+{
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+ return CS_BAD_HANDLE;
+ handle->state &= ~CLIENT_IO_REQ;
+ s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+ if (handle->state & CLIENT_CARDBUS) {
+ cb_release(s);
+ return CS_SUCCESS;
+ }
+#endif
+
+ if (!(handle->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(handle);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if ((c->io.BasePort1 != req->BasePort1) ||
+ (c->io.NumPorts1 != req->NumPorts1) ||
+ (c->io.BasePort2 != req->BasePort2) ||
+ (c->io.NumPorts2 != req->NumPorts2))
+ return CS_BAD_ARGS;
+ c->state &= ~CONFIG_IO_REQ;
+ }
+
+ release_io_space(s, req->BasePort1, req->NumPorts1);
+ if (req->NumPorts2)
+ release_io_space(s, req->BasePort2, req->NumPorts2);
+
+ return CS_SUCCESS;
+} /* release_io */
+
+/*====================================================================*/
+
+static int cs_release_irq(client_handle_t handle, irq_req_t *req)
+{
+ socket_info_t *s;
+ if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+ return CS_BAD_HANDLE;
+ handle->state &= ~CLIENT_IRQ_REQ;
+ s = SOCKET(handle);
+
+ if (!(handle->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(handle);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->irq.Attributes != req->Attributes)
+ return CS_BAD_ATTRIBUTE;
+ if (s->irq.AssignedIRQ != req->AssignedIRQ)
+ return CS_BAD_IRQ;
+ if (--s->irq.Config == 0) {
+ c->state &= ~CONFIG_IRQ_REQ;
+ s->irq.AssignedIRQ = 0;
+ }
+ }
+
+ if (req->Attributes & IRQ_HANDLE_PRESENT) {
+ bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+ }
+
+#ifdef CONFIG_ISA
+ if (req->AssignedIRQ != s->cap.pci_irq)
+ undo_irq(req->Attributes, req->AssignedIRQ);
+#endif
+
+ return CS_SUCCESS;
+} /* cs_release_irq */
+
+/*====================================================================*/
+
+static int release_window(window_handle_t win)
+{
+ socket_info_t *s;
+
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ s = win->sock;
+ if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+ return CS_BAD_HANDLE;
+
+ /* Shut down memory window */
+ win->ctl.flags &= ~MAP_ACTIVE;
+ s->ss_entry(s->sock, SS_SetMemMap, &win->ctl);
+ s->state &= ~SOCKET_WIN_REQ(win->index);
+
+ /* Release system memory */
+ release_mem_region(win->base, win->size);
+ win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+ win->magic = 0;
+
+ return CS_SUCCESS;
+} /* release_window */
+
+/*====================================================================*/
+
+static int request_configuration(client_handle_t handle,
+ config_req_t *req)
+{
+ int i;
+ u_int base;
+ socket_info_t *s;
+ config_t *c;
+ pccard_io_map iomap;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+#ifdef CONFIG_CARDBUS
+ if (handle->state & CLIENT_CARDBUS) {
+ if (!(req->IntType & INT_CARDBUS))
+ return CS_UNSUPPORTED_MODE;
+ if (s->lock_count != 0)
+ return CS_CONFIGURATION_LOCKED;
+ cb_enable(s);
+ handle->state |= CLIENT_CONFIG_LOCKED;
+ s->lock_count++;
+ return CS_SUCCESS;
+ }
+#endif
+
+ if (req->IntType & INT_CARDBUS)
+ return CS_UNSUPPORTED_MODE;
+ c = CONFIG(handle);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+
+ /* Do power control. We don't allow changes in Vcc. */
+ if (s->socket.Vcc != req->Vcc)
+ return CS_BAD_VCC;
+ if (req->Vpp1 != req->Vpp2)
+ return CS_BAD_VPP;
+ s->socket.Vpp = req->Vpp1;
+ if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+ return CS_BAD_VPP;
+
+ c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+
+ /* Pick memory or I/O card, DMA mode, interrupt */
+ c->IntType = req->IntType;
+ c->Attributes = req->Attributes;
+ if (req->IntType & INT_MEMORY_AND_IO)
+ s->socket.flags |= SS_IOCARD;
+ if (req->Attributes & CONF_ENABLE_DMA)
+ s->socket.flags |= SS_DMA_MODE;
+ if (req->Attributes & CONF_ENABLE_SPKR)
+ s->socket.flags |= SS_SPKR_ENA;
+ if (req->Attributes & CONF_ENABLE_IRQ)
+ s->socket.io_irq = s->irq.AssignedIRQ;
+ else
+ s->socket.io_irq = 0;
+ s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+ s->lock_count++;
+
+ /* Set up CIS configuration registers */
+ base = c->ConfigBase = req->ConfigBase;
+ c->Present = c->CardValues = req->Present;
+ if (req->Present & PRESENT_COPY) {
+ c->Copy = req->Copy;
+ write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+ }
+ if (req->Present & PRESENT_OPTION) {
+ if (s->functions == 1)
+ c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+ else {
+ c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+ c->Option |= COR_FUNC_ENA|COR_ADDR_DECODE|COR_IREQ_ENA;
+ }
+ if (c->state & CONFIG_IRQ_REQ)
+ if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+ c->Option |= COR_LEVEL_REQ;
+ write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+ udelay(40*1000);
+ }
+ if (req->Present & PRESENT_STATUS) {
+ c->Status = req->Status;
+ write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+ }
+ if (req->Present & PRESENT_PIN_REPLACE) {
+ c->Pin = req->Pin;
+ write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+ }
+ if (req->Present & PRESENT_EXT_STATUS) {
+ c->ExtStatus = req->ExtStatus;
+ write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+ }
+ if (req->Present & PRESENT_IOBASE_0) {
+ i = c->io.BasePort1 & 0xff;
+ write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &i);
+ i = (c->io.BasePort1 >> 8) & 0xff;
+ write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &i);
+ }
+ if (req->Present & PRESENT_IOSIZE) {
+ i = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+ write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &i);
+ }
+
+ /* Configure I/O windows */
+ if (c->state & CONFIG_IO_REQ) {
+ iomap.speed = io_speed;
+ for (i = 0; i < MAX_IO_WIN; i++)
+ if (s->io[i].NumPorts != 0) {
+ iomap.map = i;
+ iomap.flags = MAP_ACTIVE;
+ switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+ case IO_DATA_PATH_WIDTH_16:
+ iomap.flags |= MAP_16BIT; break;
+ case IO_DATA_PATH_WIDTH_AUTO:
+ iomap.flags |= MAP_AUTOSZ; break;
+ default:
+ break;
+ }
+ iomap.start = s->io[i].BasePort;
+ iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+ s->ss_entry(s->sock, SS_SetIOMap, &iomap);
+ s->io[i].Config++;
+ }
+ }
+
+ c->state |= CONFIG_LOCKED;
+ handle->state |= CLIENT_CONFIG_LOCKED;
+ return CS_SUCCESS;
+} /* request_configuration */
+
+/*======================================================================
+
+ Request_io() reserves ranges of port addresses for a socket.
+ I have not implemented range sharing or alias addressing.
+
+======================================================================*/
+
+static int request_io(client_handle_t handle, io_req_t *req)
+{
+ socket_info_t *s;
+ config_t *c;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ if (handle->state & CLIENT_CARDBUS) {
+#ifdef CONFIG_CARDBUS
+ int ret = cb_config(s);
+ if (ret == CS_SUCCESS)
+ handle->state |= CLIENT_IO_REQ;
+ return ret;
+#else
+ return CS_UNSUPPORTED_FUNCTION;
+#endif
+ }
+
+ if (!req)
+ return CS_UNSUPPORTED_MODE;
+ c = CONFIG(handle);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->state & CONFIG_IO_REQ)
+ return CS_IN_USE;
+ if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+ return CS_BAD_ATTRIBUTE;
+ if ((req->NumPorts2 > 0) &&
+ (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+ return CS_BAD_ATTRIBUTE;
+
+ if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+ req->NumPorts1, handle->dev_info))
+ return CS_IN_USE;
+
+ if (req->NumPorts2) {
+ if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+ req->NumPorts2, handle->dev_info)) {
+ release_io_space(s, req->BasePort1, req->NumPorts1);
+ return CS_IN_USE;
+ }
+ }
+
+ c->io = *req;
+ c->state |= CONFIG_IO_REQ;
+ handle->state |= CLIENT_IO_REQ;
+ return CS_SUCCESS;
+} /* request_io */
+
+/*======================================================================
+
+ Request_irq() reserves an irq for this client.
+
+ Also, since Linux only reserves irq's when they are actually
+ hooked, we don't guarantee that an irq will still be available
+ when the configuration is locked. Now that I think about it,
+ there might be a way to fix this using a dummy handler.
+
+======================================================================*/
+
+static int cs_request_irq(client_handle_t handle, irq_req_t *req)
+{
+ socket_info_t *s;
+ config_t *c;
+ int try, ret = 0, irq = 0;
+ u_int mask;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ c = CONFIG(handle);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->state & CONFIG_IRQ_REQ)
+ return CS_IN_USE;
+
+ /* Short cut: if the interrupt is PCI, there are no options */
+ if (s->cap.irq_mask == (1 << s->cap.pci_irq))
+ irq = s->cap.pci_irq;
+#ifdef CONFIG_ISA
+ else if (s->irq.AssignedIRQ != 0) {
+ /* If the interrupt is already assigned, it must match */
+ irq = s->irq.AssignedIRQ;
+ if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+ mask = req->IRQInfo2 & s->cap.irq_mask;
+ ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS;
+ } else
+ ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS;
+ } else {
+ ret = CS_IN_USE;
+ if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+ mask = req->IRQInfo2 & s->cap.irq_mask;
+ mask &= ~(1 << s->cap.pci_irq);
+ for (try = 0; try < 2; try++) {
+ for (irq = 0; irq < 32; irq++)
+ if ((mask >> irq) & 1) {
+ ret = try_irq(req->Attributes, irq, try);
+ if (ret == 0) break;
+ }
+ if (ret == 0) break;
+ }
+ } else {
+ irq = req->IRQInfo1 & IRQ_MASK;
+ ret = try_irq(req->Attributes, irq, 1);
+ }
+ }
+#endif
+ if (ret != 0) return ret;
+
+ if (req->Attributes & IRQ_HANDLE_PRESENT) {
+ if (bus_request_irq(s->cap.bus, irq, req->Handler,
+ ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+ (s->functions > 1) ||
+ (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,
+ handle->dev_info, req->Instance))
+ return CS_IN_USE;
+ }
+
+ c->irq.Attributes = req->Attributes;
+ s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+ s->irq.Config++;
+
+ c->state |= CONFIG_IRQ_REQ;
+ handle->state |= CLIENT_IRQ_REQ;
+ return CS_SUCCESS;
+} /* cs_request_irq */
+
+/*======================================================================
+
+ Request_window() establishes a mapping between card memory space
+ and system memory space.
+
+======================================================================*/
+
+static int request_window(client_handle_t *handle, win_req_t *req)
+{
+ socket_info_t *s;
+ window_t *win;
+ int w;
+
+ if (CHECK_HANDLE(*handle))
+ return CS_BAD_HANDLE;
+ s = SOCKET(*handle);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+ return CS_BAD_ATTRIBUTE;
+
+ for (w = 0; w < MAX_WIN; w++)
+ if (!(s->state & SOCKET_WIN_REQ(w))) break;
+ if (w == MAX_WIN)
+ return CS_OUT_OF_RESOURCE;
+
+ /* Window size defaults to smallest available */
+ if (req->Size == 0)
+ req->Size = s->cap.map_size;
+
+ /* Allocate system memory window */
+ win = &s->win[w];
+ win->magic = WINDOW_MAGIC;
+ win->index = w;
+ win->handle = *handle;
+ win->sock = s;
+ win->base = req->Base;
+ win->size = req->Size;
+ if (find_mem_region(&win->base, win->size, (*handle)->dev_info,
+ ((s->cap.features & SS_CAP_MEM_ALIGN) ?
+ req->Size : s->cap.map_size),
+ (req->Attributes & WIN_MAP_BELOW_1MB) ||
+ !(s->cap.features & SS_CAP_PAGE_REGS)))
+ return CS_IN_USE;
+ req->Base = win->base;
+ (*handle)->state |= CLIENT_WIN_REQ(w);
+
+ /* Configure the socket controller */
+ win->ctl.map = w+1;
+ win->ctl.flags = 0;
+ win->ctl.speed = req->AccessSpeed;
+ if (req->Attributes & WIN_MEMORY_TYPE)
+ win->ctl.flags |= MAP_ATTRIB;
+ if (req->Attributes & WIN_ENABLE)
+ win->ctl.flags |= MAP_ACTIVE;
+ if (req->Attributes & WIN_DATA_WIDTH)
+ win->ctl.flags |= MAP_16BIT;
+ if (req->Attributes & WIN_USE_WAIT)
+ win->ctl.flags |= MAP_USE_WAIT;
+ win->ctl.sys_start = req->Base;
+ win->ctl.sys_stop = req->Base + req->Size-1;
+ win->ctl.card_start = 0;
+ if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+ return CS_BAD_ARGS;
+ s->state |= SOCKET_WIN_REQ(w);
+
+ /* Return window handle */
+ *handle = (client_handle_t)win;
+
+ return CS_SUCCESS;
+} /* request_window */
+
+/*======================================================================
+
+ I'm not sure which "reset" function this is supposed to use,
+ but for now, it uses the low-level interface's reset, not the
+ CIS register.
+
+======================================================================*/
+
+static int reset_card(client_handle_t handle, client_req_t *req)
+{
+ int i, ret;
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (s->state & SOCKET_RESET_PENDING)
+ return CS_IN_USE;
+ s->state |= SOCKET_RESET_PENDING;
+
+ ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret != 0) {
+ s->state &= ~SOCKET_RESET_PENDING;
+ handle->event_callback_args.info = (void *)(u_long)ret;
+ EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+ } else {
+ DEBUG(1, ("cs: resetting socket %d\n", i));
+ send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+ s->reset_handle = handle;
+ reset_socket(i);
+ }
+ return CS_SUCCESS;
+} /* reset_card */
+
+/*======================================================================
+
+ These shut down or wake up a socket. They are sort of user
+ initiated versions of the APM suspend and resume actions.
+
+======================================================================*/
+
+static int suspend_card(client_handle_t handle, client_req_t *req)
+{
+ int i;
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (s->state & SOCKET_SUSPEND)
+ return CS_IN_USE;
+
+ DEBUG(1, ("cs: suspending socket %d\n", i));
+ send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+ s->state |= SOCKET_SUSPEND;
+
+ return CS_SUCCESS;
+} /* suspend_card */
+
+static int resume_card(client_handle_t handle, client_req_t *req)
+{
+ int i;
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (!(s->state & SOCKET_SUSPEND))
+ return CS_IN_USE;
+
+ DEBUG(1, ("cs: waking up socket %d\n", i));
+ setup_socket(i);
+
+ return CS_SUCCESS;
+} /* resume_card */
+
+/*======================================================================
+
+ These handle user requests to eject or insert a card.
+
+======================================================================*/
+
+static int eject_card(client_handle_t handle, client_req_t *req)
+{
+ int i, ret;
+ socket_info_t *s;
+ u_long flags;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ DEBUG(1, ("cs: user eject request on socket %d\n", i));
+
+ ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret != 0)
+ return ret;
+
+ spin_lock_irqsave(&s->lock, flags);
+ do_shutdown(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ return CS_SUCCESS;
+
+} /* eject_card */
+
+static int insert_card(client_handle_t handle, client_req_t *req)
+{
+ int i, status;
+ socket_info_t *s;
+ u_long flags;
+
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ i = handle->Socket; s = socket_table[i];
+ if (s->state & SOCKET_PRESENT)
+ return CS_IN_USE;
+
+ DEBUG(1, ("cs: user insert request on socket %d\n", i));
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!(s->state & SOCKET_SETUP_PENDING)) {
+ s->state |= SOCKET_SETUP_PENDING;
+ spin_unlock_irqrestore(&s->lock, flags);
+ s->ss_entry(i, SS_GetStatus, &status);
+ if (status & SS_DETECT)
+ setup_socket(i);
+ else {
+ s->state &= ~SOCKET_SETUP_PENDING;
+ return CS_NO_CARD;
+ }
+ } else
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ return CS_SUCCESS;
+} /* insert_card */
+
+/*======================================================================
+
+ Maybe this should send a CS_EVENT_CARD_INSERTION event if we
+ haven't sent one to this client yet?
+
+======================================================================*/
+
+static int set_event_mask(client_handle_t handle, eventmask_t *mask)
+{
+ u_int events, bit;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ if (handle->Attributes & CONF_EVENT_MASK_VALID)
+ return CS_BAD_SOCKET;
+ handle->EventMask = mask->EventMask;
+ events = handle->PendingEvents & handle->EventMask;
+ handle->PendingEvents -= events;
+ while (events != 0) {
+ bit = ((events ^ (events-1)) + 1) >> 1;
+ EVENT(handle, bit, CS_EVENT_PRI_LOW);
+ events -= bit;
+ }
+ return CS_SUCCESS;
+} /* set_event_mask */
+
+/*====================================================================*/
+
+static int report_error(client_handle_t handle, error_info_t *err)
+{
+ int i;
+ char *serv;
+
+ if (CHECK_HANDLE(handle))
+ printk(KERN_NOTICE);
+ else
+ printk(KERN_NOTICE "%s: ", handle->dev_info);
+
+ for (i = 0; i < SERVICE_COUNT; i++)
+ if (service_table[i].key == err->func) break;
+ if (i < SERVICE_COUNT)
+ serv = service_table[i].msg;
+ else
+ serv = "Unknown service number";
+
+ for (i = 0; i < ERROR_COUNT; i++)
+ if (error_table[i].key == err->retcode) break;
+ if (i < ERROR_COUNT)
+ printk("%s: %s\n", serv, error_table[i].msg);
+ else
+ printk("%s: Unknown error code %#x\n", serv, err->retcode);
+
+ return CS_SUCCESS;
+} /* report_error */
+
+/*====================================================================*/
+
+int CardServices(int func, void *a1, void *a2, void *a3)
+{
+
+#ifdef PCMCIA_DEBUG
+ if (pc_debug > 1) {
+ int i;
+ for (i = 0; i < SERVICE_COUNT; i++)
+ if (service_table[i].key == func) break;
+ if (i < SERVICE_COUNT)
+ printk(KERN_DEBUG "cs: CardServices(%s, 0x%p, 0x%p)\n",
+ service_table[i].msg, a1, a2);
+ else
+ printk(KERN_DEBUG "cs: CardServices(Unknown func %d, "
+ "0x%p, 0x%p)\n", func, a1, a2);
+ }
+#endif
+ switch (func) {
+ case AccessConfigurationRegister:
+ return access_configuration_register(a1, a2); break;
+ case AdjustResourceInfo:
+ return adjust_resource_info(a1, a2); break;
+ case CheckEraseQueue:
+ return check_erase_queue(a1); break;
+ case CloseMemory:
+ return close_memory(a1); break;
+ case CopyMemory:
+ return copy_memory(a1, a2); break;
+ case DeregisterClient:
+ return deregister_client(a1); break;
+ case DeregisterEraseQueue:
+ return deregister_erase_queue(a1); break;
+ case GetFirstClient:
+ return get_first_client(a1, a2); break;
+ case GetCardServicesInfo:
+ return get_card_services_info(a1); break;
+ case GetConfigurationInfo:
+ return get_configuration_info(a1, a2); break;
+ case GetNextClient:
+ return get_next_client(a1, a2); break;
+ case GetFirstRegion:
+ return get_first_region(a1, a2); break;
+ case GetFirstTuple:
+ return get_first_tuple(a1, a2); break;
+ case GetNextRegion:
+ return get_next_region(a1, a2); break;
+ case GetNextTuple:
+ return get_next_tuple(a1, a2); break;
+ case GetStatus:
+ return get_status(a1, a2); break;
+ case GetTupleData:
+ return get_tuple_data(a1, a2); break;
+ case MapMemPage:
+ return map_mem_page(a1, a2); break;
+ case ModifyConfiguration:
+ return modify_configuration(a1, a2); break;
+ case ModifyWindow:
+ return modify_window(a1, a2); break;
+ case OpenMemory:
+ return open_memory(a1, a2);
+ case ParseTuple:
+ return parse_tuple(a1, a2, a3); break;
+ case ReadMemory:
+ return read_memory(a1, a2, a3); break;
+ case RegisterClient:
+ return register_client(a1, a2); break;
+ case RegisterEraseQueue:
+ return register_erase_queue(a1, a2); break;
+ case RegisterMTD:
+ return register_mtd(a1, a2); break;
+ case ReleaseConfiguration:
+ return release_configuration(a1, a2); break;
+ case ReleaseIO:
+ return release_io(a1, a2); break;
+ case ReleaseIRQ:
+ return cs_release_irq(a1, a2); break;
+ case ReleaseWindow:
+ return release_window(a1); break;
+ case RequestConfiguration:
+ return request_configuration(a1, a2); break;
+ case RequestIO:
+ return request_io(a1, a2); break;
+ case RequestIRQ:
+ return cs_request_irq(a1, a2); break;
+ case RequestWindow:
+ return request_window(a1, a2); break;
+ case ResetCard:
+ return reset_card(a1, a2); break;
+ case SetEventMask:
+ return set_event_mask(a1, a2); break;
+ case ValidateCIS:
+ return validate_cis(a1, a2); break;
+ case WriteMemory:
+ return write_memory(a1, a2, a3); break;
+ case BindDevice:
+ return bind_device(a1); break;
+ case BindMTD:
+ return bind_mtd(a1); break;
+ case ReportError:
+ return report_error(a1, a2); break;
+ case SuspendCard:
+ return suspend_card(a1, a2); break;
+ case ResumeCard:
+ return resume_card(a1, a2); break;
+ case EjectCard:
+ return eject_card(a1, a2); break;
+ case InsertCard:
+ return insert_card(a1, a2); break;
+ case ReplaceCIS:
+ return replace_cis(a1, a2); break;
+ default:
+ return CS_UNSUPPORTED_FUNCTION; break;
+ }
+
+} /* CardServices */
+
+/*======================================================================
+
+ OS-specific module glue goes here
+
+======================================================================*/
+
+EXPORT_SYMBOL(register_ss_entry);
+EXPORT_SYMBOL(unregister_ss_entry);
+EXPORT_SYMBOL(CardServices);
+EXPORT_SYMBOL(MTDHelperEntry);
+
+static int pcmcia_cs_init(void)
+{
+ printk(KERN_INFO "%s\n", release);
+ printk(KERN_INFO " %s\n", options);
+ DEBUG(0, ("%s\n", version));
+#ifdef CONFIG_APM
+ if (do_apm)
+ apm_register_callback(&handle_apm_event);
+#endif
+#ifdef CONFIG_PROC_FS
+ proc_pccard = create_proc_entry("pccard", S_IFDIR, proc_bus);
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return pcmcia_cs_init();
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO "unloading PCMCIA Card Services\n");
+#ifdef CONFIG_PROC_FS
+ if (proc_pccard) {
+ remove_proc_entry("pccard", proc_bus);
+ }
+#endif
+#ifdef CONFIG_APM
+ if (do_apm)
+ apm_unregister_callback(&handle_apm_event);
+#endif
+ release_resource_db();
+}
+
+#else
+
+extern int pcmcia_ds_init(void);
+extern int pcmcia_i82365_init(void);
+
+int pcmcia_init(void)
+{
+ /* Start core services */
+ pcmcia_cs_init();
+
+ /* Load the socket drivers */
+ pcmcia_i82365_init();
+
+ /* Get the ball rolling.. */
+ return pcmcia_ds_init();
+}
+
+#endif
+
+/*====================================================================*/
--- /dev/null
+/*
+ * cs_internal.h 1.41 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ */
+
+#ifndef _LINUX_CS_INTERNAL_H
+#define _LINUX_CS_INTERNAL_H
+
+typedef struct erase_busy_t {
+ eraseq_entry_t *erase;
+ client_handle_t client;
+ struct timer_list timeout;
+ struct erase_busy_t *prev, *next;
+} erase_busy_t;
+
+#define ERASEQ_MAGIC 0xFA67
+typedef struct eraseq_t {
+ u_short eraseq_magic;
+ client_handle_t handle;
+ int count;
+ eraseq_entry_t *entry;
+} eraseq_t;
+
+#define CLIENT_MAGIC 0x51E6
+typedef struct client_t {
+ u_short client_magic;
+ socket_t Socket;
+ u_char Function;
+ dev_info_t dev_info;
+ u_int Attributes;
+ u_int state;
+ event_t EventMask, PendingEvents;
+ int (*event_handler)(event_t event, int priority,
+ event_callback_args_t *);
+ event_callback_args_t event_callback_args;
+ struct client_t *next;
+ u_int mtd_count;
+ wait_queue_head_t mtd_req;
+ erase_busy_t erase_busy;
+} client_t;
+
+/* Flags in client state */
+#define CLIENT_CONFIG_LOCKED 0x0001
+#define CLIENT_IRQ_REQ 0x0002
+#define CLIENT_IO_REQ 0x0004
+#define CLIENT_UNBOUND 0x0008
+#define CLIENT_STALE 0x0010
+#define CLIENT_WIN_REQ(i) (0x20<<(i))
+#define CLIENT_CARDBUS 0x8000
+
+typedef struct io_window_t {
+ u_int Attributes;
+ ioaddr_t BasePort, NumPorts;
+ ioaddr_t InUse, Config;
+} io_window_t;
+
+#define WINDOW_MAGIC 0xB35C
+typedef struct window_t {
+ u_short magic;
+ u_short index;
+ client_handle_t handle;
+ struct socket_info_t *sock;
+ u_long base;
+ u_long size;
+ pccard_mem_map ctl;
+} window_t;
+
+#define REGION_MAGIC 0xE3C9
+typedef struct region_t {
+ u_short region_magic;
+ u_short state;
+ dev_info_t dev_info;
+ client_handle_t mtd;
+ u_int MediaID;
+ region_info_t info;
+} region_t;
+
+#define REGION_STALE 0x01
+
+/* Each card function gets one of these guys */
+typedef struct config_t {
+ u_int state;
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+ u_int IntType;
+ u_int ConfigBase;
+ u_char Status, Pin, Copy, Option, ExtStatus;
+ u_int Present;
+ u_int CardValues;
+ io_req_t io;
+ struct {
+ u_int Attributes;
+ } irq;
+} config_t;
+
+/* Maximum number of IO windows per socket */
+#define MAX_IO_WIN 2
+
+/* Maximum number of memory windows per socket */
+#define MAX_WIN 4
+
+/* The size of the CIS cache */
+#define MAX_CIS_TABLE 64
+#define MAX_CIS_DATA 512
+
+typedef struct socket_info_t {
+ spinlock_t lock;
+ ss_entry_t ss_entry;
+ u_int sock;
+ socket_state_t socket;
+ socket_cap_t cap;
+ u_int state;
+ u_short functions;
+ u_short lock_count;
+ client_handle_t clients;
+ u_int real_clients;
+ client_handle_t reset_handle;
+ struct timer_list setup, shutdown;
+ u_long unreset_timeout;
+ pccard_mem_map cis_mem;
+ u_char *cis_virt;
+ config_t *config;
+#ifdef CONFIG_CARDBUS
+ u_int cb_cis_space;
+ cb_bridge_map cb_cis_map;
+ u_char *cb_cis_virt;
+ struct cb_config_t *cb_config;
+#endif
+ struct {
+ u_int AssignedIRQ;
+ u_int Config;
+ } irq;
+ io_window_t io[MAX_IO_WIN];
+ window_t win[MAX_WIN];
+ region_t *c_region, *a_region;
+ erase_busy_t erase_busy;
+ int cis_used;
+ struct {
+ u_int addr;
+ u_short len;
+ u_short attr;
+ } cis_table[MAX_CIS_TABLE];
+ char cis_cache[MAX_CIS_DATA];
+ u_int fake_cis_len;
+ char *fake_cis;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc;
+#endif
+} socket_info_t;
+
+/* Flags in config state */
+#define CONFIG_LOCKED 0x01
+#define CONFIG_IRQ_REQ 0x02
+#define CONFIG_IO_REQ 0x04
+
+/* Flags in socket state */
+#define SOCKET_PRESENT 0x0008
+#define SOCKET_SETUP_PENDING 0x0010
+#define SOCKET_SHUTDOWN_PENDING 0x0020
+#define SOCKET_RESET_PENDING 0x0040
+#define SOCKET_SUSPEND 0x0080
+#define SOCKET_WIN_REQ(i) (0x0100<<(i))
+#define SOCKET_IO_REQ(i) (0x1000<<(i))
+#define SOCKET_REGION_INFO 0x4000
+#define SOCKET_CARDBUS 0x8000
+
+#define CHECK_HANDLE(h) \
+ (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
+
+#define CHECK_SOCKET(s) \
+ (((s) >= sockets) || (socket_table[s]->ss_entry == NULL))
+
+#define SOCKET(h) (socket_table[(h)->Socket])
+#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
+
+#define CHECK_REGION(r) \
+ (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
+
+#define CHECK_ERASEQ(q) \
+ (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
+
+#define EVENT(h, e, p) \
+ ((h)->event_handler((e), (p), &(h)->event_callback_args))
+
+/* In cardbus.c */
+int cb_config(socket_info_t *s);
+void cb_release(socket_info_t *s);
+void cb_enable(socket_info_t *s);
+void cb_disable(socket_info_t *s);
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+ u_int addr, u_int len, void *ptr);
+int cb_setup_cis_mem(socket_info_t *s, int space);
+void cb_release_cis_mem(socket_info_t *s);
+
+/* In cistpl.c */
+void read_cis_mem(socket_info_t *s, int attr,
+ u_int addr, u_int len, void *ptr);
+void write_cis_mem(socket_info_t *s, int attr,
+ u_int addr, u_int len, void *ptr);
+int setup_cis_mem(socket_info_t *s);
+void release_cis_mem(socket_info_t *s);
+int verify_cis_cache(socket_info_t *s);
+void preload_cis_cache(socket_info_t *s);
+int get_first_tuple(client_handle_t handle, tuple_t *tuple);
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+int get_tuple_data(client_handle_t handle, tuple_t *tuple);
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse);
+int validate_cis(client_handle_t handle, cisinfo_t *info);
+int replace_cis(client_handle_t handle, cisdump_t *cis);
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse);
+
+/* In bulkmem.c */
+void retry_erase_list(struct erase_busy_t *list, u_int cause);
+int get_first_region(client_handle_t handle, region_info_t *rgn);
+int get_next_region(client_handle_t handle, region_info_t *rgn);
+int register_mtd(client_handle_t handle, mtd_reg_t *reg);
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header);
+int deregister_erase_queue(eraseq_handle_t eraseq);
+int check_erase_queue(eraseq_handle_t eraseq);
+int open_memory(client_handle_t *handle, open_mem_t *open);
+int close_memory(memory_handle_t handle);
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int copy_memory(memory_handle_t handle, copy_op_t *req);
+
+/* In rsrc_mgr */
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+ int force_low);
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name);
+int find_mem_region(u_long *base, u_long num, char *name,
+ u_long align, int force_low);
+int try_irq(u_int Attributes, int irq, int specific);
+void undo_irq(u_int Attributes, int irq);
+int adjust_resource_info(client_handle_t handle, adjust_t *adj);
+void release_resource_db(void);
+int proc_read_io(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data);
+int proc_read_mem(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data);
+
+/* in pnp components */
+int proc_read_irq(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data);
+void pnp_bios_init(void);
+void pnp_proc_init(void);
+void pnp_proc_done(void);
+void pnp_rsrc_init(void);
+void pnp_rsrc_done(void);
+
+#define MAX_SOCK 8
+extern socket_t sockets;
+extern socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_pccard;
+#endif
+
+#ifdef PCMCIA_DEBUG
+#define _printk(args...) printk(KERN_DEBUG args)
+extern int pc_debug;
+#define DEBUG(n, args) do { if (pc_debug>(n)) _printk args; } while (0)
+#else
+#define DEBUG(n, args) do { } while (0)
+#endif
+
+#endif /* _LINUX_CS_INTERNAL_H */
--- /dev/null
+/*======================================================================
+
+ PC Card Driver Services
+
+ ds.c 1.95 1999/08/28 04:01:46
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static const char *version =
+"ds.c 1.95 1999/08/28 04:01:46 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+ dev_info_t dev_info;
+ int use_count;
+ dev_link_t *(*attach)(void);
+ void (*detach)(dev_link_t *);
+ struct driver_info_t *next;
+} driver_info_t;
+
+typedef struct socket_bind_t {
+ driver_info_t *driver;
+ dev_link_t *instance;
+ struct socket_bind_t *next;
+} socket_bind_t;
+
+/* Device user information */
+#define MAX_EVENTS 32
+#define USER_MAGIC 0x7ea4
+#define CHECK_USER(u) \
+ (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+typedef struct user_info_t {
+ u_int user_magic;
+ int event_head, event_tail;
+ event_t event[MAX_EVENTS];
+ struct user_info_t *next;
+} user_info_t;
+
+/* Socket state information */
+typedef struct socket_info_t {
+ client_handle_t handle;
+ int state;
+ user_info_t *user;
+ int req_pending, req_result;
+ wait_queue_head_t queue, request;
+ struct timer_list removal;
+ socket_bind_t *bind;
+} socket_info_t;
+
+#define SOCKET_PRESENT 0x01
+#define SOCKET_BUSY 0x02
+#define SOCKET_REMOVAL_PENDING 0x10
+
+/*====================================================================*/
+
+/* Device driver ID passed to Card Services */
+static dev_info_t dev_info = "Driver Services";
+
+/* Linked list of all registered device drivers */
+static driver_info_t *root_driver = NULL;
+
+static int sockets = 0, major_dev = -1;
+static socket_info_t *socket_table = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+ Register_pccard_driver() and unregister_pccard_driver() are used
+ tell Driver Services that a PC Card client driver is available to
+ be bound to sockets.
+
+======================================================================*/
+
+int register_pccard_driver(dev_info_t *dev_info,
+ dev_link_t *(*attach)(void),
+ void (*detach)(dev_link_t *))
+{
+ driver_info_t *driver;
+ socket_bind_t *b;
+ int i;
+
+ DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
+ for (driver = root_driver; driver; driver = driver->next)
+ if (strncmp((char *)dev_info, (char *)driver->dev_info,
+ DEV_NAME_LEN) == 0)
+ break;
+ if (!driver) {
+ driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+ strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
+ driver->use_count = 0;
+ driver->next = root_driver;
+ root_driver = driver;
+ }
+
+ driver->attach = attach;
+ driver->detach = detach;
+ if (driver->use_count == 0) return 0;
+
+ /* Instantiate any already-bound devices */
+ for (i = 0; i < sockets; i++)
+ for (b = socket_table[i].bind; b; b = b->next) {
+ if (b->driver != driver) continue;
+ b->instance = driver->attach();
+ if (b->instance == NULL)
+ printk(KERN_NOTICE "ds: unable to create instance "
+ "of '%s'!\n", driver->dev_info);
+ }
+
+ return 0;
+} /* register_pccard_driver */
+
+/*====================================================================*/
+
+int unregister_pccard_driver(dev_info_t *dev_info)
+{
+ driver_info_t *target, **d = &root_driver;
+ socket_bind_t *b;
+ int i;
+
+ DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
+ (char *)dev_info);
+ while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info,
+ DEV_NAME_LEN) != 0))
+ d = &(*d)->next;
+ if (*d == NULL)
+ return -1;
+
+ target = *d;
+ if (target->use_count == 0) {
+ *d = target->next;
+ kfree(target);
+ } else {
+ /* Blank out any left-over device instances */
+ target->attach = NULL; target->detach = NULL;
+ for (i = 0; i < sockets; i++)
+ for (b = socket_table[i].bind; b; b = b->next)
+ if (b->driver == target) b->instance = NULL;
+ }
+ return 0;
+} /* unregister_pccard_driver */
+
+/*======================================================================
+
+ These manage a ring buffer of events pending for one user process
+
+======================================================================*/
+
+static int queue_empty(user_info_t *user)
+{
+ return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+ user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+ return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+ user->event_head = (user->event_head+1) % MAX_EVENTS;
+ if (user->event_head == user->event_tail)
+ user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+ user->event[user->event_head] = event;
+}
+
+static void handle_event(socket_info_t *s, event_t event)
+{
+ user_info_t *user;
+ for (user = s->user; user; user = user->next)
+ queue_event(user, event);
+ wake_up_interruptible(&s->queue);
+}
+
+static int handle_request(socket_info_t *s, event_t event)
+{
+ if (s->req_pending != 0)
+ return CS_IN_USE;
+ if (s->state & SOCKET_BUSY)
+ s->req_pending = 1;
+ handle_event(s, event);
+ if (s->req_pending > 0) {
+ interruptible_sleep_on(&s->request);
+ if (signal_pending(current))
+ return CS_IN_USE;
+ else
+ return s->req_result;
+ }
+ return CS_SUCCESS;
+}
+
+static void handle_removal(u_long sn)
+{
+ socket_info_t *s = &socket_table[sn];
+ handle_event(s, CS_EVENT_CARD_REMOVAL);
+ s->state &= ~SOCKET_REMOVAL_PENDING;
+}
+
+/*======================================================================
+
+ The card status event handler.
+
+======================================================================*/
+
+static int ds_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ socket_info_t *s;
+ int i;
+
+ DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
+ event, priority, args->client_handle);
+ s = args->client_data;
+ i = s - socket_table;
+
+ switch (event) {
+
+ case CS_EVENT_CARD_REMOVAL:
+ s->state &= ~SOCKET_PRESENT;
+ if (!(s->state & SOCKET_REMOVAL_PENDING)) {
+ s->state |= SOCKET_REMOVAL_PENDING;
+ s->removal.expires = jiffies + HZ/10;
+ add_timer(&s->removal);
+ }
+ break;
+
+ case CS_EVENT_CARD_INSERTION:
+ s->state |= SOCKET_PRESENT;
+ handle_event(s, event);
+ break;
+
+ case CS_EVENT_EJECTION_REQUEST:
+ return handle_request(s, event);
+ break;
+
+ default:
+ handle_event(s, event);
+ break;
+ }
+
+ return 0;
+} /* ds_event */
+
+/*======================================================================
+
+ bind_mtd() connects a memory region with an MTD client.
+
+======================================================================*/
+
+static int bind_mtd(int i, mtd_info_t *mtd_info)
+{
+ mtd_bind_t bind_req;
+ int ret;
+
+ bind_req.dev_info = &mtd_info->dev_info;
+ bind_req.Attributes = mtd_info->Attributes;
+ bind_req.Socket = i;
+ bind_req.CardOffset = mtd_info->CardOffset;
+ ret = CardServices(BindMTD, &bind_req);
+ if (ret != CS_SUCCESS) {
+ cs_error(NULL, BindMTD, ret);
+ printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
+ " offset 0x%x\n",
+ (char *)bind_req.dev_info, i, bind_req.CardOffset);
+ return -ENODEV;
+ }
+ return 0;
+} /* bind_mtd */
+
+/*======================================================================
+
+ bind_request() connects a socket to a particular client driver.
+ It looks up the specified device ID in the list of registered
+ drivers, binds it to the socket, and tries to create an instance
+ of the device. unbind_request() deletes a driver instance.
+
+======================================================================*/
+
+static int bind_request(int i, bind_info_t *bind_info)
+{
+ struct driver_info_t *driver;
+ socket_bind_t *b;
+ bind_req_t bind_req;
+ socket_info_t *s = &socket_table[i];
+ int ret;
+
+ DEBUG(2, "bind_request(%d, '%s')\n", i,
+ (char *)bind_info->dev_info);
+ for (driver = root_driver; driver; driver = driver->next)
+ if (strcmp((char *)driver->dev_info,
+ (char *)bind_info->dev_info) == 0)
+ break;
+ if (driver == NULL) {
+ driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+ strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN);
+ driver->use_count = 0;
+ driver->next = root_driver;
+ driver->attach = NULL; driver->detach = NULL;
+ root_driver = driver;
+ }
+
+ for (b = s->bind; b; b = b->next)
+ if (driver == b->driver)
+ break;
+ if (b != NULL) {
+ bind_info->instance = b->instance;
+ return -EBUSY;
+ }
+
+ bind_req.Socket = i;
+ bind_req.Function = bind_info->function;
+ bind_req.dev_info = &driver->dev_info;
+ ret = CardServices(BindDevice, &bind_req);
+ if (ret != CS_SUCCESS) {
+ cs_error(NULL, BindDevice, ret);
+ printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+ (char *)dev_info, i);
+ return -ENODEV;
+ }
+
+ /* Add binding to list for this socket */
+ driver->use_count++;
+ b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
+ b->driver = driver;
+ b->instance = NULL;
+ b->next = s->bind;
+ s->bind = b;
+
+ if (driver->attach) {
+ b->instance = driver->attach();
+ if (b->instance == NULL) {
+ printk(KERN_NOTICE "ds: unable to create instance "
+ "of '%s'!\n", (char *)bind_info->dev_info);
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+} /* bind_request */
+
+/*====================================================================*/
+
+static int get_device_info(int i, bind_info_t *bind_info, int first)
+{
+ socket_info_t *s = &socket_table[i];
+ socket_bind_t *b;
+ dev_node_t *node;
+
+ for (b = s->bind; b; b = b->next)
+ if (strcmp((char *)b->driver->dev_info,
+ (char *)bind_info->dev_info) == 0)
+ break;
+ if (b == NULL) return -ENODEV;
+ if ((b->instance == NULL) ||
+ (b->instance->state & DEV_CONFIG_PENDING))
+ return -EAGAIN;
+ if (first)
+ node = b->instance->dev;
+ else
+ for (node = b->instance->dev; node; node = node->next)
+ if (node == bind_info->next) break;
+ if (node == NULL) return -ENODEV;
+
+ strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+ bind_info->name[DEV_NAME_LEN-1] = '\0';
+ bind_info->major = node->major;
+ bind_info->minor = node->minor;
+ bind_info->next = node->next;
+
+ return 0;
+} /* get_device_info */
+
+/*====================================================================*/
+
+static int unbind_request(int i, bind_info_t *bind_info)
+{
+ socket_info_t *s = &socket_table[i];
+ socket_bind_t **b, *c;
+
+ DEBUG(2, "unbind_request(%d, '%s')\n", i,
+ (char *)bind_info->dev_info);
+ for (b = &s->bind; *b; b = &(*b)->next)
+ if (strcmp((char *)(*b)->driver->dev_info,
+ (char *)bind_info->dev_info) == 0)
+ break;
+ if (*b == NULL)
+ return -ENODEV;
+
+ c = *b;
+ c->driver->use_count--;
+ if (c->driver->detach) {
+ if (c->instance)
+ c->driver->detach(c->instance);
+ } else {
+ if (c->driver->use_count == 0) {
+ driver_info_t **d;
+ for (d = &root_driver; *d; d = &((*d)->next))
+ if (c->driver == *d) break;
+ *d = (*d)->next;
+ kfree_s(c->driver, sizeof(driver_info_t));
+ }
+ }
+ *b = c->next;
+ kfree_s(c, sizeof(socket_bind_t));
+
+ return 0;
+} /* unbind_request */
+
+/*======================================================================
+
+ The user-mode PC Card device interface
+
+======================================================================*/
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+ socket_t i = MINOR(inode->i_rdev);
+ socket_info_t *s;
+ user_info_t *user;
+
+ DEBUG(0, "ds_open(socket %d)\n", i);
+ if ((i >= sockets) || (sockets == 0))
+ return -ENODEV;
+ s = &socket_table[i];
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (s->state & SOCKET_BUSY)
+ return -EBUSY;
+ else
+ s->state |= SOCKET_BUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+ user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+ user->event_tail = user->event_head = 0;
+ user->next = s->user;
+ user->user_magic = USER_MAGIC;
+ s->user = user;
+ file->private_data = user;
+
+ if (s->state & SOCKET_PRESENT)
+ queue_event(user, CS_EVENT_CARD_INSERTION);
+ return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+ socket_t i = MINOR(inode->i_rdev);
+ socket_info_t *s;
+ user_info_t *user, **link;
+
+ DEBUG(0, "ds_release(socket %d)\n", i);
+ if ((i >= sockets) || (sockets == 0))
+ return 0;
+ s = &socket_table[i];
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return 0;
+
+ /* Unlink user data structure */
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+ s->state &= ~SOCKET_BUSY;
+ file->private_data = NULL;
+ for (link = &s->user; *link; link = &(*link)->next)
+ if (*link == user) break;
+ if (link == NULL)
+ return 0;
+ *link = user->next;
+ user->user_magic = 0;
+ kfree_s(user, sizeof(user_info_t));
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+ socket_info_t *s;
+ user_info_t *user;
+
+ DEBUG(2, "ds_read(socket %d)\n", i);
+
+ if ((i >= sockets) || (sockets == 0))
+ return -ENODEV;
+ if (count < 4)
+ return -EINVAL;
+ s = &socket_table[i];
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return -EIO;
+
+ if (queue_empty(user)) {
+ interruptible_sleep_on(&s->queue);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ put_user(get_queued_event(user), (int *)buf);
+ return 4;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+ socket_info_t *s;
+ user_info_t *user;
+
+ DEBUG(2, "ds_write(socket %d)\n", i);
+
+ if ((i >= sockets) || (sockets == 0))
+ return -ENODEV;
+ if (count != 4)
+ return -EINVAL;
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return -EBADF;
+ s = &socket_table[i];
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return -EIO;
+
+ if (s->req_pending) {
+ s->req_pending--;
+ get_user(s->req_result, (int *)buf);
+ if ((s->req_result != 0) || (s->req_pending == 0))
+ wake_up_interruptible(&s->request);
+ } else
+ return -EIO;
+
+ return 4;
+} /* ds_write */
+
+/*====================================================================*/
+
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+ socket_info_t *s;
+ user_info_t *user;
+
+ DEBUG(2, "ds_poll(socket %d)\n", i);
+
+ if ((i >= sockets) || (sockets == 0))
+ return POLLERR;
+ s = &socket_table[i];
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return POLLERR;
+ poll_wait(file, &s->queue, wait);
+ if (!queue_empty(user))
+ return POLLIN | POLLRDNORM;
+ return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+ u_int cmd, u_long arg)
+{
+ socket_t i = MINOR(inode->i_rdev);
+ socket_info_t *s;
+ u_int size;
+ int ret, err;
+ ds_ioctl_arg_t buf;
+
+ DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
+
+ if ((i >= sockets) || (sockets == 0))
+ return -ENODEV;
+ s = &socket_table[i];
+
+ size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+ if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+ /* Permission check */
+ if (!(cmd & IOC_OUT) && !suser())
+ return -EPERM;
+
+ if (cmd & IOC_IN) {
+ err = verify_area(VERIFY_READ, (char *)arg, size);
+ if (err) {
+ DEBUG(3, "ds_ioctl(): verify_read = %d\n", err);
+ return err;
+ }
+ }
+ if (cmd & IOC_OUT) {
+ err = verify_area(VERIFY_WRITE, (char *)arg, size);
+ if (err) {
+ DEBUG(3, "ds_ioctl(): verify_write = %d\n", err);
+ return err;
+ }
+ }
+
+ err = ret = 0;
+
+ if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
+
+ switch (cmd) {
+ case DS_ADJUST_RESOURCE_INFO:
+ ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
+ break;
+ case DS_GET_CARD_SERVICES_INFO:
+ ret = CardServices(GetCardServicesInfo, &buf.servinfo);
+ break;
+ case DS_GET_CONFIGURATION_INFO:
+ ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
+ break;
+ case DS_GET_FIRST_TUPLE:
+ ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
+ break;
+ case DS_GET_NEXT_TUPLE:
+ ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
+ break;
+ case DS_GET_TUPLE_DATA:
+ buf.tuple.TupleData = buf.tuple_parse.data;
+ buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
+ ret = CardServices(GetTupleData, s->handle, &buf.tuple);
+ break;
+ case DS_PARSE_TUPLE:
+ buf.tuple.TupleData = buf.tuple_parse.data;
+ ret = CardServices(ParseTuple, s->handle, &buf.tuple,
+ &buf.tuple_parse.parse);
+ break;
+ case DS_RESET_CARD:
+ ret = CardServices(ResetCard, s->handle, NULL);
+ break;
+ case DS_GET_STATUS:
+ ret = CardServices(GetStatus, s->handle, &buf.status);
+ break;
+ case DS_VALIDATE_CIS:
+ ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
+ break;
+ case DS_SUSPEND_CARD:
+ ret = CardServices(SuspendCard, s->handle, NULL);
+ break;
+ case DS_RESUME_CARD:
+ ret = CardServices(ResumeCard, s->handle, NULL);
+ break;
+ case DS_EJECT_CARD:
+ ret = CardServices(EjectCard, s->handle, NULL);
+ break;
+ case DS_INSERT_CARD:
+ ret = CardServices(InsertCard, s->handle, NULL);
+ break;
+ case DS_ACCESS_CONFIGURATION_REGISTER:
+ if ((buf.conf_reg.Action == CS_WRITE) && !suser())
+ return -EPERM;
+ ret = CardServices(AccessConfigurationRegister, s->handle,
+ &buf.conf_reg);
+ break;
+ case DS_GET_FIRST_REGION:
+ ret = CardServices(GetFirstRegion, s->handle, &buf.region);
+ break;
+ case DS_GET_NEXT_REGION:
+ ret = CardServices(GetNextRegion, s->handle, &buf.region);
+ break;
+ case DS_REPLACE_CIS:
+ ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
+ break;
+ case DS_BIND_REQUEST:
+ if (!suser()) return -EPERM;
+ err = bind_request(i, &buf.bind_info);
+ break;
+ case DS_GET_DEVICE_INFO:
+ err = get_device_info(i, &buf.bind_info, 1);
+ break;
+ case DS_GET_NEXT_DEVICE:
+ err = get_device_info(i, &buf.bind_info, 0);
+ break;
+ case DS_UNBIND_REQUEST:
+ err = unbind_request(i, &buf.bind_info);
+ break;
+ case DS_BIND_MTD:
+ if (!suser()) return -EPERM;
+ err = bind_mtd(i, &buf.mtd_info);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if ((err == 0) && (ret != CS_SUCCESS)) {
+ DEBUG(2, "ds_ioctl: ret = %d\n", ret);
+ switch (ret) {
+ case CS_BAD_SOCKET: case CS_NO_CARD:
+ err = -ENODEV; break;
+ case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+ case CS_BAD_TUPLE:
+ err = -EINVAL; break;
+ case CS_IN_USE:
+ err = -EBUSY; break;
+ case CS_OUT_OF_RESOURCE:
+ err = -ENOSPC; break;
+ case CS_NO_MORE_ITEMS:
+ err = -ENODATA; break;
+ case CS_UNSUPPORTED_FUNCTION:
+ err = -ENOSYS; break;
+ default:
+ err = -EIO; break;
+ }
+ }
+
+ if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
+
+ return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+ NULL, /* lseek */
+ ds_read, /* read */
+ ds_write, /* write */
+ NULL, /* readdir */
+ ds_poll, /* poll */
+ ds_ioctl, /* ioctl */
+ NULL, /* mmap */
+ ds_open, /* open */
+ NULL, /* flush */
+ ds_release, /* release */
+ NULL /* fsync */
+};
+
+EXPORT_SYMBOL(register_pccard_driver);
+EXPORT_SYMBOL(unregister_pccard_driver);
+
+/*====================================================================*/
+
+int pcmcia_ds_init(void)
+{
+ client_reg_t client_reg;
+ servinfo_t serv;
+ bind_req_t bind;
+ socket_info_t *s;
+ int i, ret;
+
+ DEBUG(0, "%s\n", version);
+
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "ds: Card Services release does not match!\n");
+ return -1;
+ }
+ if (serv.Count == 0) {
+ printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
+ return -1;
+ }
+
+ sockets = serv.Count;
+ socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
+ for (i = 0, s = socket_table; i < sockets; i++, s++) {
+ s->state = 0;
+ s->user = NULL;
+ s->req_pending = 0;
+ init_waitqueue_head(&s->queue);
+ init_waitqueue_head(&s->request);
+ s->handle = NULL;
+ s->removal.prev = s->removal.next = NULL;
+ s->removal.data = i;
+ s->removal.function = &handle_removal;
+ s->bind = NULL;
+ }
+
+ /* Set up hotline to Card Services */
+ client_reg.dev_info = bind.dev_info = &dev_info;
+ client_reg.Attributes = INFO_MASTER_CLIENT;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &ds_event;
+ client_reg.Version = 0x0210;
+ for (i = 0; i < sockets; i++) {
+ bind.Socket = i;
+ bind.Function = BIND_FN_ALL;
+ ret = CardServices(BindDevice, &bind);
+ if (ret != CS_SUCCESS) {
+ cs_error(NULL, BindDevice, ret);
+ break;
+ }
+ client_reg.event_callback_args.client_data = &socket_table[i];
+ ret = CardServices(RegisterClient, &socket_table[i].handle,
+ &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(NULL, RegisterClient, ret);
+ break;
+ }
+ }
+
+ /* Set up character device for user mode clients */
+ i = register_chrdev(0, "pcmcia", &ds_fops);
+ if (i == -EBUSY)
+ printk(KERN_NOTICE "unable to find a free device # for "
+ "Driver Services\n");
+ else
+ major_dev = i;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+static int init_module(void)
+{
+ return pcmcia_ds_init();
+}
+
+void cleanup_module(void)
+{
+ int i;
+ if (major_dev != -1)
+ unregister_chrdev(major_dev, "pcmcia");
+ for (i = 0; i < sockets; i++)
+ CardServices(DeregisterClient, socket_table[i].handle);
+ sockets = 0;
+ kfree(socket_table);
+}
+
+#endif
--- /dev/null
+/*======================================================================
+
+ Device driver for Intel 82365 and compatible PC Card controllers,
+ and Yenta-compatible PCI-to-CardBus controllers.
+
+ i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+/* ISA-bus controllers */
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "ricoh.h"
+#include "o2micro.h"
+
+/* PCI-bus controllers */
+#include "yenta.h"
+#include "ti113x.h"
+#include "smc34c90.h"
+#include "topic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0)
+static const char *version =
+"i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $ (David Hinds)";
+#else
+#define DEBUG(n, args) do { } while (0)
+#endif
+
+static void irq_count(int, void *, struct pt_regs *);
+static inline int _check_irq(int irq, int flags)
+{
+ if (request_irq(irq, irq_count, flags, "x", NULL) == 0) {
+ free_irq(irq, NULL);
+ return 0;
+ }
+ return -1;
+}
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#ifdef CONFIG_ISA
+/* Default base address for i82365sl and other ISA chips */
+static int i365_base = 0x3e0;
+/* Should we probe at 0x3e2 for an extra ISA controller? */
+static int extra_sockets = 0;
+/* Specify a socket number to ignore */
+static int ignore = -1;
+/* Bit map or list of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+#endif
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
+static int cycle_time = 120;
+
+/* Cirrus options */
+static int has_dma = -1;
+static int has_led = -1;
+static int has_ring = -1;
+static int dynamic_mode = 0;
+static int freq_bypass = -1;
+static int setup_time = -1;
+static int cmd_time = -1;
+static int recov_time = -1;
+
+#ifdef CONFIG_ISA
+/* Vadem options */
+static int async_clock = -1;
+static int cable_mode = -1;
+static int wakeup = 0;
+#endif
+
+#ifdef CONFIG_ISA
+MODULE_PARM(i365_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(extra_sockets, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(async_clock, "i");
+MODULE_PARM(cable_mode, "i");
+MODULE_PARM(wakeup, "i");
+#endif
+
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(cycle_time, "i");
+MODULE_PARM(has_dma, "i");
+MODULE_PARM(has_led, "i");
+MODULE_PARM(has_ring, "i");
+MODULE_PARM(dynamic_mode, "i");
+MODULE_PARM(freq_bypass, "i");
+MODULE_PARM(setup_time, "i");
+MODULE_PARM(cmd_time, "i");
+MODULE_PARM(recov_time, "i");
+
+#ifdef CONFIG_PCI
+/* Scan PCI bus? */
+static int do_pci_probe = 1;
+/* Default memory base address for CardBus controllers */
+static u_int cb_mem_base[] = { 0x68000000, 0xf8000000 };
+static int fast_pci = -1;
+static int hold_time = -1;
+/* Override BIOS interrupt routing mode? */
+static int irq_mode = -1;
+static int has_clkrun = -1;
+static int clkrun_sel = -1;
+static int pci_latency = -1;
+static int cb_latency = -1;
+static int cb_bus_base = 0;
+static int cb_bus_step = 2;
+static int cb_write_post = -1;
+MODULE_PARM(do_pci_probe, "i");
+MODULE_PARM(cb_mem_base, "i");
+MODULE_PARM(fast_pci, "i");
+MODULE_PARM(hold_time, "i");
+MODULE_PARM(irq_mode, "i");
+MODULE_PARM(has_clkrun, "i");
+MODULE_PARM(clkrun_sel, "i");
+MODULE_PARM(pci_latency, "i");
+MODULE_PARM(cb_latency, "i");
+MODULE_PARM(cb_bus_base, "i");
+MODULE_PARM(cb_bus_step, "i");
+MODULE_PARM(cb_write_post, "i");
+#endif
+
+#ifdef CONFIG_ISA
+#ifdef CONFIG_PCI
+/* PCI card status change interrupts? */
+static int pci_csc = 0;
+/* PCI IO card functional interrupts? */
+static int pci_int = 0;
+MODULE_PARM(pci_csc, "i");
+MODULE_PARM(pci_int, "i");
+#else /* no PCI */
+#define pci_csc 0
+#define pci_int 0
+#endif
+#else /* no ISA */
+#ifdef CONFIG_PCI
+#define pci_csc 0
+#define pci_int 1
+#else
+#error "No bus architectures defined!"
+#endif
+#endif
+
+/*====================================================================*/
+
+typedef struct cirrus_state_t {
+ u_char misc1, misc2;
+ u_char timer[6];
+} cirrus_state_t;
+
+typedef struct vg46x_state_t {
+ u_char ctl, ema;
+} vg46x_state_t;
+
+typedef struct ti113x_state_t {
+ u_int sysctl;
+ u_char cardctl, devctl, diag;
+} ti113x_state_t;
+
+typedef struct rl5c4xx_state_t {
+ u_short misc, ctl, io, mem;
+} rl5c4xx_state_t;
+
+typedef struct o2micro_state_t {
+ u_char mode_a, mode_b, mode_c, mode_d;
+ u_char mhpg, fifo, mode_e;
+} o2micro_state_t;
+
+typedef struct topic_state_t {
+ u_char slot, ccr, cdr;
+ u_int rcr;
+} topic_state_t;
+
+typedef struct socket_info_t {
+ u_short type, flags;
+ socket_cap_t cap;
+ u_short ioaddr;
+ u_short psock;
+ u_char cs_irq, intr;
+ void (*handler)(void *info, u_int events);
+ void *info;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc;
+#endif
+#ifdef CONFIG_PCI
+ u_short vendor, device;
+ u_char revision, bus, devfn;
+ u_short bcr;
+ u_char pci_lat, cb_lat, sub_bus;
+ u_char cache, pmcs;
+ u_int cb_phys;
+ char *cb_virt;
+#endif
+ union {
+ cirrus_state_t cirrus;
+ vg46x_state_t vg46x;
+#ifdef CONFIG_PCI
+ o2micro_state_t o2micro;
+ ti113x_state_t ti113x;
+ rl5c4xx_state_t rl5c4xx;
+ topic_state_t topic;
+#endif
+ } state;
+} socket_info_t;
+
+/* Where we keep track of our sockets... */
+static int sockets = 0;
+static socket_info_t socket[8] = {
+ { 0, }, /* ... */
+};
+
+/* Default ISA interrupt mask */
+#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */
+
+static void pcic_interrupt_wrapper(u_long);
+static void pcic_interrupt(int irq, void *dev,
+ struct pt_regs *regs);
+static int pcic_service(u_int sock, u_int cmd, void *arg);
+#ifdef CONFIG_PROC_FS
+static void pcic_proc_remove(u_short sock);
+#endif
+
+#ifdef CONFIG_ISA
+static int grab_irq;
+static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#endif
+static struct timer_list poll_timer;
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL 0x8086
+#endif
+#ifndef PCI_VENDOR_ID_OMEGA
+#define PCI_VENDOR_ID_OMEGA 0x119b
+#endif
+#ifndef PCI_DEVICE_ID_OMEGA_PCMCIA
+#define PCI_DEVICE_ID_OMEGA_PCMCIA 0x1221
+#endif
+
+/* Default settings for PCI command configuration register */
+#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \
+ PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
+
+#endif
+
+/* These definitions must match the pcic table! */
+typedef enum pcic_id {
+#ifdef CONFIG_ISA
+ IS_I82365A, IS_I82365B, IS_I82365DF,
+ IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
+ IS_PD6710, IS_PD672X, IS_VT83C469,
+#endif
+#ifdef CONFIG_PCI
+ IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730,
+ IS_I82092AA, IS_OM82C092G,
+ IS_PD6832, IS_OZ6832, IS_OZ6836,
+ IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478,
+ IS_SMC34C90,
+ IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210,
+ IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225,
+ IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97,
+ IS_UNK_PCI, IS_UNK_CARDBUS
+#endif
+} pcic_id;
+
+/* Flags for classifying groups of controllers */
+#define IS_VADEM 0x0001
+#define IS_CIRRUS 0x0002
+#define IS_TI 0x0004
+#define IS_O2MICRO 0x0008
+#define IS_VIA 0x0010
+#define IS_TOPIC 0x0020
+#define IS_RICOH 0x0040
+#define IS_UNKNOWN 0x0400
+#define IS_VG_PWR 0x0800
+#define IS_DF_PWR 0x1000
+#define IS_PCI 0x2000
+#define IS_CARDBUS 0x4000
+#define IS_ALIVE 0x8000
+
+typedef struct pcic_t {
+ char *name;
+ u_short flags;
+#ifdef CONFIG_PCI
+ u_short vendor, device;
+#endif
+} pcic_t;
+
+static pcic_t pcic[] = {
+#ifdef CONFIG_ISA
+ { "Intel i82365sl A step", 0 },
+ { "Intel i82365sl B step", 0 },
+ { "Intel i82365sl DF", IS_DF_PWR },
+ { "IBM Clone", 0 },
+ { "Ricoh RF5C296/396", 0 },
+ { "VLSI 82C146", 0 },
+ { "Vadem VG-468", IS_VADEM },
+ { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
+ { "Cirrus PD6710", IS_CIRRUS },
+ { "Cirrus PD672x", IS_CIRRUS },
+ { "VIA VT83C469", IS_CIRRUS|IS_VIA },
+#endif
+#ifdef CONFIG_PCI
+ { "Cirrus PD6729", IS_CIRRUS|IS_PCI,
+ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 },
+ { "Cirrus PD6730", IS_CIRRUS|IS_PCI,
+ PCI_VENDOR_ID_CIRRUS, 0xffff },
+ { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+ PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 },
+ { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+ PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 },
+ { "Intel 82092AA", IS_PCI,
+ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_OMEGA_PCMCIA },
+ { "Omega Micro 82C092G", IS_PCI,
+ PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_PCMCIA },
+ { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS,
+ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 },
+ { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+ PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 },
+ { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+ PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 },
+ { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 },
+ { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 },
+ { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 },
+ { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 },
+ { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 },
+ { "SMC 34C90", IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 },
+ { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 },
+ { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 },
+ { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A },
+ { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 },
+ { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 },
+ { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 },
+ { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A },
+ { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B },
+ { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 },
+ { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR,
+ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 },
+ { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A },
+ { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B },
+ { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 },
+ { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 },
+ { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 }
+#endif
+};
+
+#define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t))
+
+/*====================================================================*/
+
+/* Some PCI shortcuts */
+
+#ifdef CONFIG_PCI
+
+#define pci_readb pcibios_read_config_byte
+#define pci_writeb pcibios_write_config_byte
+#define pci_readw pcibios_read_config_word
+#define pci_writew pcibios_write_config_word
+#define pci_readl pcibios_read_config_dword
+#define pci_writel pcibios_write_config_dword
+
+#define cb_readb(s, r) readb(socket[s].cb_virt + (r))
+#define cb_readl(s, r) readl(socket[s].cb_virt + (r))
+#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r))
+#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r))
+
+static void cb_get_power(u_short sock, socket_state_t *state);
+static void cb_set_power(u_short sock, socket_state_t *state);
+#endif
+
+/*====================================================================*/
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+#ifdef CONFIG_PCI
+ if (socket[sock].cb_virt)
+ return cb_readb(sock, 0x0800 + reg);
+ else
+#endif
+ {
+ u_short port = socket[sock].ioaddr;
+ u_char val;
+ reg = I365_REG(socket[sock].psock, reg);
+ outb(reg, port); val = inb(port+1);
+ return val;
+ }
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+#ifdef CONFIG_PCI
+ if (socket[sock].cb_virt)
+ cb_writeb(sock, 0x0800 + reg, data);
+ else
+#endif
+ {
+ u_short port = socket[sock].ioaddr;
+ u_char val = I365_REG(socket[sock].psock, reg);
+ outb(val, port); outb(data, port+1);
+ }
+}
+
+static void i365_bset(u_short sock, u_short reg, u_char mask)
+{
+ u_char d = i365_get(sock, reg);
+ d |= mask;
+ i365_set(sock, reg, d);
+}
+
+static void i365_bclr(u_short sock, u_short reg, u_char mask)
+{
+ u_char d = i365_get(sock, reg);
+ d &= ~mask;
+ i365_set(sock, reg, d);
+}
+
+static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
+{
+ u_char d = i365_get(sock, reg);
+ if (b)
+ d |= mask;
+ else
+ d &= ~mask;
+ i365_set(sock, reg, d);
+}
+
+static u_short i365_get_pair(u_short sock, u_short reg)
+{
+ u_short a, b;
+ a = i365_get(sock, reg);
+ b = i365_get(sock, reg+1);
+ return (a + (b<<8));
+}
+
+static void i365_set_pair(u_short sock, u_short reg, u_short data)
+{
+ i365_set(sock, reg, data & 0xff);
+ i365_set(sock, reg+1, data >> 8);
+}
+
+/*======================================================================
+
+ Code to save and restore global state information for Cirrus
+ PD67xx controllers, and to set and report global configuration
+ options.
+
+ The VIA controllers also use these routines, as they are mostly
+ Cirrus lookalikes, without the timing registers.
+
+======================================================================*/
+
+#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+
+static void cirrus_get_state(u_short s)
+{
+ int i;
+ cirrus_state_t *p = &socket[s].state.cirrus;
+ p->misc1 = i365_get(s, PD67_MISC_CTL_1);
+ p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+ p->misc2 = i365_get(s, PD67_MISC_CTL_2);
+ for (i = 0; i < 6; i++)
+ p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
+}
+
+static void cirrus_set_state(u_short s)
+{
+ int i;
+ u_char misc;
+ cirrus_state_t *p = &socket[s].state.cirrus;
+
+ misc = i365_get(s, PD67_MISC_CTL_2);
+ i365_set(s, PD67_MISC_CTL_2, p->misc2);
+ if (misc & PD67_MC2_SUSPEND) mdelay(50);
+ misc = i365_get(s, PD67_MISC_CTL_1);
+ misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+ i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
+ for (i = 0; i < 6; i++)
+ i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
+}
+
+#ifdef CONFIG_PCI
+static int cirrus_set_irq_mode(u_short s, int pcsc, int pint)
+{
+ flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc);
+ return 0;
+}
+#endif /* CONFIG_PCI */
+
+static u_int cirrus_set_opts(u_short s, char *buf)
+{
+ socket_info_t *t = &socket[s];
+ cirrus_state_t *p = &socket[s].state.cirrus;
+ u_int mask = 0xffff;
+
+ if (has_ring == -1) has_ring = 1;
+ flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
+ flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
+ if (p->misc2 & PD67_MC2_IRQ15_RI)
+ strcat(buf, " [ring]");
+ if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
+ strcat(buf, " [dyn mode]");
+ if (p->misc1 & PD67_MC1_INPACK_ENA)
+ strcat(buf, " [inpack]");
+ if (!(t->flags & (IS_PCI | IS_CARDBUS))) {
+ if (p->misc2 & PD67_MC2_IRQ15_RI)
+ mask &= ~0x8000;
+ if (has_led > 0) {
+ strcat(buf, " [led]");
+ mask &= ~0x1000;
+ }
+ if (has_dma > 0) {
+ strcat(buf, " [dma]");
+ mask &= ~0x0600;
+ flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
+ if (p->misc2 & PD67_MC2_FREQ_BYPASS)
+ strcat(buf, " [freq bypass]");
+ }
+#ifdef CONFIG_PCI
+ } else {
+ p->misc1 &= ~PD67_MC1_MEDIA_ENA;
+ flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci);
+ if (p->misc2 & PD67_MC2_IRQ15_RI)
+ mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000;
+#endif
+ }
+ if (!(t->flags & IS_VIA)) {
+ if (setup_time >= 0)
+ p->timer[0] = p->timer[3] = setup_time;
+ if (cmd_time > 0) {
+ p->timer[1] = cmd_time;
+ p->timer[4] = cmd_time*2+4;
+ }
+ if (p->timer[1] == 0) {
+ p->timer[1] = 6; p->timer[4] = 16;
+ if (p->timer[0] == 0)
+ p->timer[0] = p->timer[3] = 1;
+ }
+ if (recov_time >= 0)
+ p->timer[2] = p->timer[5] = recov_time;
+ buf += strlen(buf);
+ sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
+ p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
+ }
+ return mask;
+}
+
+/*======================================================================
+
+ Code to save and restore global state information for Vadem VG468
+ and VG469 controllers, and to set and report global configuration
+ options.
+
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void vg46x_get_state(u_short s)
+{
+ vg46x_state_t *p = &socket[s].state.vg46x;
+ p->ctl = i365_get(s, VG468_CTL);
+ if (socket[s].type == IS_VG469)
+ p->ema = i365_get(s, VG469_EXT_MODE);
+}
+
+static void vg46x_set_state(u_short s)
+{
+ vg46x_state_t *p = &socket[s].state.vg46x;
+ i365_set(s, VG468_CTL, p->ctl);
+ if (socket[s].type == IS_VG469)
+ i365_set(s, VG469_EXT_MODE, p->ema);
+}
+
+static u_int vg46x_set_opts(u_short s, char *buf)
+{
+ vg46x_state_t *p = &socket[s].state.vg46x;
+
+ flip(p->ctl, VG468_CTL_ASYNC, async_clock);
+ flip(p->ema, VG469_MODE_CABLE, cable_mode);
+ if (p->ctl & VG468_CTL_ASYNC)
+ strcat(buf, " [async]");
+ if (p->ctl & VG468_CTL_INPACK)
+ strcat(buf, " [inpack]");
+ if (socket[s].type == IS_VG469) {
+ u_char vsel = i365_get(s, VG469_VSELECT);
+ if (vsel & VG469_VSEL_EXT_STAT) {
+ strcat(buf, " [ext mode]");
+ if (vsel & VG469_VSEL_EXT_BUS)
+ strcat(buf, " [isa buf]");
+ }
+ if (p->ema & VG469_MODE_CABLE)
+ strcat(buf, " [cable]");
+ if (p->ema & VG469_MODE_COMPAT)
+ strcat(buf, " [c step]");
+ }
+ return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+ Code to save and restore global state information for TI 1130 and
+ TI 1131 controllers, and to set and report global configuration
+ options.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void ti113x_get_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ ti113x_state_t *p = &socket[s].state.ti113x;
+ pci_readl(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, &p->sysctl);
+ pci_readb(t->bus, t->devfn, TI113X_CARD_CONTROL, &p->cardctl);
+ pci_readb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, &p->devctl);
+ pci_readb(t->bus, t->devfn, TI1250_DIAGNOSTIC, &p->diag);
+}
+
+static void ti113x_set_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ ti113x_state_t *p = &socket[s].state.ti113x;
+ pci_writel(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, p->sysctl);
+ pci_writeb(t->bus, t->devfn, TI113X_CARD_CONTROL, p->cardctl);
+ pci_writeb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, p->devctl);
+ pci_writeb(t->bus, t->devfn, TI1250_MULTIMEDIA_CTL, 0);
+ pci_writeb(t->bus, t->devfn, TI1250_DIAGNOSTIC, p->diag);
+ i365_set_pair(s, TI113X_IO_OFFSET(0), 0);
+ i365_set_pair(s, TI113X_IO_OFFSET(1), 0);
+}
+
+static int ti113x_set_irq_mode(u_short s, int pcsc, int pint)
+{
+ socket_info_t *t = &socket[s];
+ ti113x_state_t *p = &t->state.ti113x;
+ t->intr = (pcsc) ? I365_INTR_ENA : 0;
+ if (t->type <= IS_TI1131) {
+ p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA |
+ TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
+ if (pcsc)
+ p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC;
+ if (pint)
+ p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ;
+ } else if (t->type == IS_TI1250A) {
+ p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
+ if (pcsc)
+ p->diag |= TI1250_DIAG_PCI_CSC;
+ if (pint)
+ p->diag |= TI1250_DIAG_PCI_IREQ;
+ }
+ return 0;
+}
+
+static u_int ti113x_set_opts(u_short s, char *buf)
+{
+ socket_info_t *t = &socket[s];
+ ti113x_state_t *p = &t->state.ti113x;
+ u_int mask = 0xffff;
+ int old = (t->type <= IS_TI1131);
+
+ flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun);
+ flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel);
+ flip(p->cardctl, TI113X_CCR_RIENB, has_ring);
+ p->cardctl &= ~TI113X_CCR_ZVENABLE;
+ switch (irq_mode) {
+ case 1:
+ p->devctl &= ~TI113X_DCR_IMODE_MASK;
+ p->devctl |= TI113X_DCR_IMODE_ISA;
+ break;
+ case 2:
+ p->devctl &= ~TI113X_DCR_IMODE_MASK;
+ p->devctl |= TI113X_DCR_IMODE_SERIAL;
+ break;
+ case 3:
+ p->devctl &= ~TI113X_DCR_IMODE_MASK;
+ p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL;
+ break;
+ default:
+ if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0)
+ p->devctl |= TI113X_DCR_IMODE_ISA;
+ }
+ if (p->cardctl & TI113X_CCR_RIENB) {
+ strcat(buf, " [ring]");
+ if (old) mask &= ~0x8000;
+ }
+ if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) {
+ if (p->sysctl & TI113X_SCR_CLKRUN_SEL) {
+ strcat(buf, " [clkrun irq 12]");
+ mask &= ~0x1000;
+ } else {
+ strcat(buf, " [clkrun irq 10]");
+ mask &= ~0x0400;
+ }
+ }
+ if (p->sysctl & TI113X_SCR_PWRSAVINGS)
+ strcat(buf, " [pwr save]");
+ switch (p->devctl & TI113X_DCR_IMODE_MASK) {
+ case TI12XX_DCR_IMODE_PCI_ONLY:
+ strcat(buf, " [pci only]");
+ mask = 0;
+ break;
+ case TI113X_DCR_IMODE_ISA:
+ strcat(buf, " [isa irq]");
+ if (old) mask &= ~0x0018;
+ break;
+ case TI113X_DCR_IMODE_SERIAL:
+ strcat(buf, " [pci + serial irq]");
+ mask = 0xffff;
+ break;
+ case TI12XX_DCR_IMODE_ALL_SERIAL:
+ strcat(buf, " [serial pci & irq]");
+ mask = 0xffff;
+ break;
+ }
+ return mask;
+}
+
+#endif
+
+/*======================================================================
+
+ Code to save and restore global state information for the Ricoh
+ RL5C4XX controllers, and to set and report global configuration
+ options.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void rl5c4xx_get_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+ pci_readw(t->bus, t->devfn, RL5C4XX_MISC, &p->misc);
+ pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_CTL, &p->ctl);
+ pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, &p->io);
+ pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, &p->mem);
+}
+
+static void rl5c4xx_set_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+ pci_writew(t->bus, t->devfn, RL5C4XX_MISC, p->misc);
+ pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_CTL, p->ctl);
+ pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, p->io);
+ pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, p->mem);
+}
+
+static u_int rl5c4xx_set_opts(u_short s, char *buf)
+{
+ rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+ u_int mask = 0xffff;
+ int old = (socket[s].type < IS_RL5C475);
+
+ p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+ if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+
+ if (setup_time >= 0) {
+ p->io = (p->io & ~RL5C4XX_SETUP_MASK) +
+ ((setup_time+1) << RL5C4XX_SETUP_SHIFT);
+ p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) +
+ (setup_time << RL5C4XX_SETUP_SHIFT);
+ }
+ if (cmd_time >= 0) {
+ p->io = (p->io & ~RL5C4XX_CMD_MASK) +
+ (cmd_time << RL5C4XX_CMD_SHIFT);
+ p->mem = (p->mem & ~RL5C4XX_CMD_MASK) +
+ (cmd_time << RL5C4XX_CMD_SHIFT);
+ }
+ if (hold_time >= 0) {
+ p->io = (p->io & ~RL5C4XX_HOLD_MASK) +
+ (hold_time << RL5C4XX_HOLD_SHIFT);
+ p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) +
+ (hold_time << RL5C4XX_HOLD_SHIFT);
+ }
+ if (!old) {
+ switch (irq_mode) {
+ case 1:
+ p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break;
+ case 2:
+ p->misc |= RL5C47X_MISC_SRIRQ_ENA; break;
+ }
+ if (p->misc & RL5C47X_MISC_SRIRQ_ENA)
+ sprintf(buf, " [serial irq]");
+ else
+ sprintf(buf, " [isa irq]");
+ buf += strlen(buf);
+ }
+ sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]",
+ (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+ (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+ (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT,
+ (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+ (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+ (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT);
+ return mask;
+}
+
+#endif
+
+/*======================================================================
+
+ Code to save and restore global state information for O2Micro
+ controllers, and to set and report global configuration options.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void o2micro_get_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ o2micro_state_t *p = &socket[s].state.o2micro;
+ if ((t->revision == 0x34) || (t->revision == 0x62)) {
+ p->mode_a = i365_get(s, O2_MODE_A_2);
+ p->mode_b = i365_get(s, O2_MODE_B_2);
+ } else {
+ p->mode_a = i365_get(s, O2_MODE_A);
+ p->mode_b = i365_get(s, O2_MODE_B);
+ }
+ p->mode_c = i365_get(s, O2_MODE_C);
+ p->mode_d = i365_get(s, O2_MODE_D);
+ if (t->flags & IS_CARDBUS) {
+ p->mhpg = i365_get(s, O2_MHPG_DMA);
+ p->fifo = i365_get(s, O2_FIFO_ENA);
+ p->mode_e = i365_get(s, O2_MODE_E);
+ }
+}
+
+static void o2micro_set_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ o2micro_state_t *p = &socket[s].state.o2micro;
+ if ((t->revision == 0x34) || (t->revision == 0x62)) {
+ i365_set(s, O2_MODE_A_2, p->mode_a);
+ i365_set(s, O2_MODE_B_2, p->mode_b);
+ } else {
+ i365_set(s, O2_MODE_A, p->mode_a);
+ i365_set(s, O2_MODE_B, p->mode_b);
+ }
+ i365_set(s, O2_MODE_C, p->mode_c);
+ i365_set(s, O2_MODE_D, p->mode_d);
+ if (t->flags & IS_CARDBUS) {
+ i365_set(s, O2_MHPG_DMA, p->mhpg);
+ i365_set(s, O2_FIFO_ENA, p->fifo);
+ i365_set(s, O2_MODE_E, p->mode_e);
+ }
+}
+
+static u_int o2micro_set_opts(u_short s, char *buf)
+{
+ socket_info_t *t = &socket[s];
+ o2micro_state_t *p = &socket[s].state.o2micro;
+ u_int mask = 0xffff;
+
+ p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP;
+ flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring);
+ p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK);
+ if (t->flags & IS_CARDBUS) {
+ p->mode_d &= ~O2_MODE_D_W97_IRQ;
+ p->mode_e &= ~O2_MODE_E_MHPG_DMA;
+ p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA;
+ p->mhpg &= ~O2_MHPG_CHANNEL;
+ } else {
+ if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
+ }
+ sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]",
+ p->mode_a, p->mode_b, p->mode_c, p->mode_d);
+ if (t->flags & IS_CARDBUS) {
+ buf += strlen(buf);
+ sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]",
+ p->mhpg, p->fifo, p->mode_e);
+ }
+ return mask;
+}
+
+#endif
+
+/*======================================================================
+
+ Code to save and restore global state information for the Toshiba
+ ToPIC 95 and 97 controllers, and to set and report global
+ configuration options.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void topic_get_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ topic_state_t *p = &socket[s].state.topic;
+ pci_readb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, &p->slot);
+ pci_readb(t->bus, t->devfn, TOPIC_CARD_CONTROL, &p->ccr);
+ pci_readb(t->bus, t->devfn, TOPIC_CARD_DETECT, &p->cdr);
+ pci_readl(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, &p->rcr);
+}
+
+static void topic_set_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ topic_state_t *p = &socket[s].state.topic;
+ pci_writeb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, p->slot);
+ pci_writeb(t->bus, t->devfn, TOPIC_CARD_CONTROL, p->ccr);
+ pci_writeb(t->bus, t->devfn, TOPIC_CARD_DETECT, p->cdr);
+ pci_writel(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, p->rcr);
+}
+
+static int topic_set_irq_mode(u_short s, int pcsc, int pint)
+{
+ if (socket[s].type == IS_TOPIC97) {
+ topic_state_t *p = &socket[s].state.topic;
+ flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc);
+ return 0;
+ } else {
+ return !pcsc;
+ }
+}
+
+static u_int topic_set_opts(u_short s, char *buf)
+{
+ topic_state_t *p = &socket[s].state.topic;
+
+ p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK;
+ p->cdr |= TOPIC_CDR_MODE_PC32;
+ p->cdr &= ~(TOPIC_CDR_SW_DETECT);
+ sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]",
+ p->slot, p->ccr, p->cdr, p->rcr);
+ return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+ Routines to handle common CardBus options
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+
+ pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache);
+ pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat);
+ pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat);
+ pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus);
+ pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus);
+ pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr);
+ {
+ struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn);
+ t->cap.pci_irq = (pdev) ? pdev->irq : 0;
+ }
+ if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0;
+}
+
+static void cb_set_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ if (t->pmcs)
+ pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0);
+ pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0);
+ pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys);
+ pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT);
+ pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache);
+ pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat);
+ pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat);
+ pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus);
+ pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus);
+ pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr);
+}
+
+static int cb_get_irq_mode(u_short s)
+{
+ return (!(socket[s].bcr & CB_BCR_ISA_IRQ));
+}
+
+static int cb_set_irq_mode(u_short s, int pcsc, int pint)
+{
+ socket_info_t *t = &socket[s];
+ flip(t->bcr, CB_BCR_ISA_IRQ, !(pint));
+ if (t->flags & IS_CIRRUS)
+ return cirrus_set_irq_mode(s, pcsc, pint);
+ else if (t->flags & IS_TI)
+ return ti113x_set_irq_mode(s, pcsc, pint);
+ else if (t->flags & IS_TOPIC)
+ return topic_set_irq_mode(s, pcsc, pint);
+ return 0;
+}
+
+static void pci_scan(u_short sock);
+
+static void cb_set_opts(u_short s, char *buf)
+{
+ socket_info_t *t = &socket[s];
+ t->bcr |= CB_BCR_WRITE_POST;
+ /* some TI1130's seem to exhibit problems with write posting */
+ if (((t->type == IS_TI1130) && (t->revision == 4) &&
+ (cb_write_post < 0)) || (cb_write_post == 0))
+ t->bcr &= ~CB_BCR_WRITE_POST;
+ if (t->cache == 0) t->cache = 8;
+ if (pci_latency >= 0) t->pci_lat = pci_latency;
+ if (t->pci_lat == 0) t->pci_lat = 0xa8;
+ if (cb_latency >= 0) t->cb_lat = cb_latency;
+ if (t->cb_lat == 0) t->cb_lat = 0xb0;
+ if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan)
+ pci_scan(s);
+ if (t->cap.pci_irq == 0)
+ strcat(buf, " [no pci irq]");
+ else
+ sprintf(buf, " [pci irq %d]", t->cap.pci_irq);
+ buf += strlen(buf);
+ if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) {
+ if (cb_bus_base <= 0) cb_bus_base = 0x20;
+ t->cap.cardbus = cb_bus_base;
+ t->sub_bus = cb_bus_base+cb_bus_step;
+ cb_bus_base += cb_bus_step+1;
+ }
+ if (!(t->flags & IS_TOPIC))
+ t->cap.features |= SS_CAP_PAGE_REGS;
+ sprintf(buf, " [lat %d/%d] [bus %d/%d]",
+ t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus);
+}
+
+#endif
+
+/*======================================================================
+
+ Generic routines to get and set controller options
+
+======================================================================*/
+
+static void get_host_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+ if (t->flags & IS_CIRRUS)
+ cirrus_get_state(s);
+#ifdef CONFIG_ISA
+ else if (t->flags & IS_VADEM)
+ vg46x_get_state(s);
+#endif
+#ifdef CONFIG_PCI
+ else if (t->flags & IS_O2MICRO)
+ o2micro_get_state(s);
+ else if (t->flags & IS_TI)
+ ti113x_get_state(s);
+ else if (t->flags & IS_RICOH)
+ rl5c4xx_get_state(s);
+ else if (t->flags & IS_TOPIC)
+ topic_get_state(s);
+ if (t->flags & IS_CARDBUS)
+ cb_get_state(s);
+#endif
+}
+
+static void set_host_state(u_short s)
+{
+ socket_info_t *t = &socket[s];
+#ifdef CONFIG_PCI
+ if (t->flags & IS_CARDBUS)
+ cb_set_state(s);
+#endif
+ if (t->flags & IS_CIRRUS)
+ cirrus_set_state(s);
+ else {
+ i365_set(s, I365_GBLCTL, 0x00);
+ i365_set(s, I365_GENCTL, 0x00);
+ }
+ i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
+#ifdef CONFIG_ISA
+ if (t->flags & IS_VADEM)
+ vg46x_set_state(s);
+#endif
+#ifdef CONFIG_PCI
+ if (t->flags & IS_O2MICRO)
+ o2micro_set_state(s);
+ else if (t->flags & IS_TI)
+ ti113x_set_state(s);
+ else if (t->flags & IS_RICOH)
+ rl5c4xx_set_state(s);
+ else if (t->flags & IS_TOPIC)
+ topic_set_state(s);
+#endif
+}
+
+static u_int set_host_opts(u_short s, u_short ns)
+{
+ u_short i;
+ u_int m = 0xffff;
+ char buf[128];
+
+ for (i = s; i < s+ns; i++) {
+ if (socket[i].flags & IS_ALIVE) {
+ printk(KERN_INFO " host opts [%d]: already alive!\n", i);
+ continue;
+ }
+ buf[0] = '\0';
+ get_host_state(i);
+ if (socket[i].flags & IS_CIRRUS)
+ m = cirrus_set_opts(i, buf);
+#ifdef CONFIG_ISA
+ else if (socket[i].flags & IS_VADEM)
+ m = vg46x_set_opts(i, buf);
+#endif
+#ifdef CONFIG_PCI
+ else if (socket[i].flags & IS_O2MICRO)
+ m = o2micro_set_opts(i, buf);
+ else if (socket[i].flags & IS_TI)
+ m = ti113x_set_opts(i, buf);
+ else if (socket[i].flags & IS_RICOH)
+ m = rl5c4xx_set_opts(i, buf);
+ else if (socket[i].flags & IS_TOPIC)
+ m = topic_set_opts(i, buf);
+ if (socket[i].flags & IS_CARDBUS)
+ cb_set_opts(i, buf+strlen(buf));
+#endif
+ set_host_state(i);
+ printk(KERN_INFO " host opts [%d]:%s\n", i,
+ (*buf) ? buf : " none");
+ }
+#ifdef CONFIG_PCI
+ /* Mask out all PCI interrupts */
+ for (i = 0; i < sockets; i++)
+ m &= ~(1<<socket[i].cap.pci_irq);
+ {
+ struct pci_dev *p;
+ for (p = pci_devices; p; p = p->next)
+ m &= ~(1<<p->irq);
+ }
+#endif
+ return m;
+}
+
+/*======================================================================
+
+ Interrupt testing code, for ISA and PCI interrupts
+
+======================================================================*/
+
+static volatile u_int irq_hits;
+static u_short irq_sock;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+#ifdef CONFIG_PCI
+ if (socket[irq_sock].flags & IS_CARDBUS) {
+ cb_writel(irq_sock, CB_SOCKET_EVENT, -1);
+ } else
+#endif
+ i365_get(irq_sock, I365_CSC);
+ irq_hits++;
+ DEBUG(2, ("-> hit on irq %d\n", irq));
+}
+
+static u_int test_irq(u_short sock, int irq, int pci)
+{
+ u_char csc = (pci) ? 0 : irq;
+ DEBUG(2, (" testing %s irq %d\n", pci ? "PCI" : "ISA", irq));
+
+ if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
+ return 1;
+ irq_hits = 0; irq_sock = sock;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/100);
+ if (irq_hits) {
+ free_irq(irq, NULL);
+ DEBUG(2, (" spurious hit!\n"));
+ return 1;
+ }
+
+ /* Generate one interrupt */
+#ifdef CONFIG_PCI
+ if (socket[sock].flags & IS_CARDBUS) {
+ cb_writel(sock, CB_SOCKET_EVENT, -1);
+ i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4));
+ cb_writel(sock, CB_SOCKET_EVENT, -1);
+ cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG);
+ cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG|0x410);
+ udelay(1000);
+ cb_writel(sock, CB_SOCKET_EVENT, -1);
+ cb_writel(sock, CB_SOCKET_MASK, 0);
+ } else
+#endif
+ {
+ i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4));
+ i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
+ udelay(1000);
+ }
+
+ free_irq(irq, NULL);
+
+ /* mask all interrupts */
+ i365_set(sock, I365_CSCINT, 0);
+ DEBUG(2, (" hits = %d\n", irq_hits));
+
+ return (irq_hits != 1);
+}
+
+#ifdef CONFIG_ISA
+
+static u_int isa_scan(u_short sock, u_int mask0)
+{
+ u_int mask1 = 0;
+ int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+ /* Don't probe level-triggered interrupts -- reserved for PCI */
+ mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
+#endif
+
+#ifdef CONFIG_PCI
+ /* Only scan if we can select ISA csc irq's */
+ if (!(socket[sock].flags & IS_CARDBUS) ||
+ (cb_set_irq_mode(sock, 0, 0) == 0))
+#endif
+ if (do_scan) {
+ set_host_state(sock);
+ i365_set(sock, I365_CSCINT, 0);
+ for (i = 0; i < 16; i++)
+ if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
+ mask1 |= (1 << i);
+ for (i = 0; i < 16; i++)
+ if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0))
+ mask1 ^= (1 << i);
+ }
+
+ printk(KERN_INFO " ISA irqs (");
+ if (mask1) {
+ printk("scanned");
+ } else {
+ /* Fallback: just find interrupts that aren't in use */
+ for (i = 0; i < 16; i++)
+ if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0))
+ mask1 |= (1 << i);
+ printk("default");
+ /* If scan failed, default to polled status */
+ if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
+ }
+ printk(") = ");
+
+ for (i = 0; i < 16; i++)
+ if (mask1 & (1<<i))
+ printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+ if (mask1 == 0) printk("none!");
+
+ return mask1;
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_PCI
+
+static void pci_scan(u_short sock)
+{
+ u_int i;
+
+ cb_set_irq_mode(sock, 1, 0);
+ set_host_state(sock);
+ i365_set(sock, I365_CSCINT, 0);
+ /* Only probe irq's 9..11, to be conservative */
+ for (i = 9; i < 12; i++) {
+ if ((test_irq(sock, i, 1) == 0) &&
+ (test_irq(sock, i, 1) == 0))
+ break;
+ }
+ if (i < 12) socket[sock].cap.pci_irq = i;
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+ return ns/cycle_time;
+} /* speed_convert */
+
+static int to_ns(int cycles)
+{
+ return cycle_time*cycles;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static int identify(u_short port, u_short sock)
+{
+ u_char val;
+ int type = -1;
+
+ /* Use the next free entry in the socket table */
+ socket[sockets].ioaddr = port;
+ socket[sockets].psock = sock;
+
+ /* Wake up a sleepy Cirrus controller */
+ if (wakeup) {
+ i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+ /* Pause at least 50 ms */
+ mdelay(50);
+ }
+
+ if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
+ return -1;
+ switch (val) {
+ case 0x82:
+ type = IS_I82365A; break;
+ case 0x83:
+ type = IS_I82365B; break;
+ case 0x84:
+ type = IS_I82365DF; break;
+ case 0x88: case 0x89: case 0x8a:
+ type = IS_IBM; break;
+ }
+
+ /* Check for Vadem VG-468 chips */
+ outb(0x0e, port);
+ outb(0x37, port);
+ i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+ val = i365_get(sockets, I365_IDENT);
+ if (val & I365_IDENT_VADEM) {
+ i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+ type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+ }
+
+ /* Check for Ricoh chips */
+ val = i365_get(sockets, RF5C_CHIP_ID);
+ if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+ type = IS_RF5Cx96;
+
+ /* Check for Cirrus CL-PD67xx chips */
+ i365_set(sockets, PD67_CHIP_INFO, 0);
+ val = i365_get(sockets, PD67_CHIP_INFO);
+ if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+ val = i365_get(sockets, PD67_CHIP_INFO);
+ if ((val & PD67_INFO_CHIP_ID) == 0) {
+ type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+ i365_set(sockets, PD67_EXT_INDEX, 0xe5);
+ if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
+ type = IS_VT83C469;
+ }
+ }
+ return type;
+} /* identify */
+
+#endif
+
+/*======================================================================
+
+ See if a card is present, powered up, in IO mode, and already
+ bound to a (non PC Card) Linux driver. We leave these alone.
+
+ We make an exception for cards that seem to be serial devices.
+
+======================================================================*/
+
+static int is_alive(u_short sock)
+{
+ u_char stat;
+ u_short start, stop;
+
+ stat = i365_get(sock, I365_STATUS);
+ start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
+ stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
+ if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
+ (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
+ (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
+ (check_region(start, stop-start+1) != 0) &&
+ ((start & 0xfeef) != 0x02e8))
+ return 1;
+ else
+ return 0;
+}
+
+/*====================================================================*/
+
+static void add_socket(u_short port, int psock, int type)
+{
+ socket[sockets].ioaddr = port;
+ socket[sockets].psock = psock;
+ socket[sockets].type = type;
+ socket[sockets].flags = pcic[type].flags;
+ if (is_alive(sockets))
+ socket[sockets].flags |= IS_ALIVE;
+ sockets++;
+}
+
+static void add_pcic(int ns, int type)
+{
+ u_int mask = 0, i, base;
+ int use_pci = 0, isa_irq = 0;
+ socket_info_t *t = &socket[sockets-ns];
+
+ base = sockets-ns;
+ if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+
+ if (base == 0) printk("\n");
+ printk(KERN_INFO " %s", pcic[type].name);
+#ifdef CONFIG_PCI
+ if (t->flags & IS_UNKNOWN)
+ printk(" [0x%04x 0x%04x]", t->vendor, t->device);
+ if (t->flags & IS_CARDBUS)
+ printk(" PCI-to-CardBus at bus %d slot %d, mem 0x%08x",
+ t->bus, PCI_SLOT(t->devfn), t->cb_phys);
+ else if (t->flags & IS_PCI)
+ printk(" PCI-to-PCMCIA at bus %d slot %d, port %#x",
+ t->bus, PCI_SLOT(t->devfn), t->ioaddr);
+ else
+#endif
+ printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
+ t->ioaddr, t->psock*0x40);
+ printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
+
+#ifdef CONFIG_ISA
+ /* Set host options, build basic interrupt mask */
+ if (irq_list[0] == -1)
+ mask = irq_mask;
+ else
+ for (i = mask = 0; i < 16; i++)
+ mask |= (1<<irq_list[i]);
+#endif
+ mask &= I365_MASK & set_host_opts(base, ns);
+#ifdef CONFIG_ISA
+ /* Scan for ISA interrupts */
+ mask = isa_scan(base, mask);
+#else
+ printk(KERN_INFO " PCI card interrupts,");
+#endif
+
+#ifdef CONFIG_PCI
+ /* Can we use a PCI interrupt for card status changes? */
+ if (pci_csc && t->cap.pci_irq) {
+ for (i = 0; i < ns; i++)
+ if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break;
+ if (i == ns) {
+ use_pci = 1;
+ printk(" PCI status changes\n");
+ }
+ }
+#endif
+
+#ifdef CONFIG_ISA
+ /* Poll if only two interrupts available */
+ if (!use_pci && !poll_interval) {
+ u_int tmp = (mask & (mask-1));
+ if ((tmp & (tmp-1)) == 0)
+ poll_interval = HZ;
+ }
+ /* Only try an ISA cs_irq if this is the first controller */
+ if (!use_pci && !grab_irq && (cs_irq || !poll_interval)) {
+ /* Avoid irq 12 unless it is explicitly requested */
+ u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+ for (cs_irq = 15; cs_irq > 0; cs_irq--)
+ if ((cs_mask & (1 << cs_irq)) &&
+ (_check_irq(cs_irq, 0) == 0))
+ break;
+ if (cs_irq) {
+ grab_irq = 1;
+ isa_irq = cs_irq;
+ printk(" status change on irq %d\n", cs_irq);
+ }
+ }
+#endif
+
+ if (!use_pci && !isa_irq) {
+ if (poll_interval == 0)
+ poll_interval = HZ;
+ printk(" polling interval = %d ms\n",
+ poll_interval * 1000 / HZ);
+
+ }
+
+ /* Update socket interrupt information, capabilities */
+ for (i = 0; i < ns; i++) {
+ t[i].cap.features |= SS_CAP_PCCARD;
+ t[i].cap.map_size = 0x1000;
+ t[i].cap.irq_mask = mask;
+ if (pci_int && t[i].cap.pci_irq)
+ t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq);
+ t[i].cs_irq = isa_irq;
+#ifdef CONFIG_PCI
+ if (t[i].flags & IS_CARDBUS) {
+ t[i].cap.features |= SS_CAP_CARDBUS;
+ cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq,
+ pci_int && t[i].cap.pci_irq);
+ }
+#endif
+ }
+
+} /* add_pcic */
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+typedef struct pci_dev *pci_id_t;
+static int pci_lookup(u_int class, pci_id_t *id,
+ u_char *bus, u_char *devfn)
+{
+ if ((*id = pci_find_class(class<<8, *id)) != NULL) {
+ *bus = (*id)->bus->number;
+ *devfn = (*id)->devfn;
+ return 0;
+ } else return -1;
+}
+
+static void add_pci_bridge(int type, u_char bus, u_char devfn,
+ u_short v, u_short d)
+{
+ socket_info_t *s = &socket[sockets];
+ u_short i, ns;
+ u_int addr;
+
+ if (type == PCIC_COUNT) type = IS_UNK_PCI;
+ pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &addr);
+ addr &= ~0x1;
+ pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT);
+ for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) {
+ s->bus = bus; s->devfn = devfn;
+ s->vendor = v; s->device = d;
+ add_socket(addr, i, type);
+ ns++; s++;
+ }
+ add_pcic(ns, type);
+}
+
+static void add_cb_bridge(int type, u_char bus, u_char devfn,
+ u_short v, u_short d0)
+{
+ socket_info_t *s = &socket[sockets];
+ u_short d, ns;
+ u_char a, b, r, max;
+
+ /* PCI bus enumeration is broken on some systems */
+ for (ns = 0; ns < sockets; ns++)
+ if ((socket[ns].bus == bus) && (socket[ns].devfn == devfn))
+ return;
+
+ if (type == PCIC_COUNT) type = IS_UNK_CARDBUS;
+ pci_readb(bus, devfn, PCI_HEADER_TYPE, &a);
+ pci_readb(bus, devfn, PCI_CLASS_REVISION, &r);
+ max = (a & 0x80) ? 8 : 1;
+ for (ns = 0; ns < max; ns++, s++, devfn++) {
+ if (pci_readw(bus, devfn, PCI_DEVICE_ID, &d) || (d != d0))
+ break;
+ s->bus = bus; s->devfn = devfn;
+ s->vendor = v; s->device = d; s->revision = r;
+
+ /* Check for power management capabilities */
+ pci_readb(bus, devfn, PCI_STATUS, &a);
+ if (a & PCI_STATUS_CAPLIST) {
+ pci_readb(bus, devfn, PCI_CB_CAPABILITY_POINTER, &b);
+ while (b != 0) {
+ pci_readb(bus, devfn, b+PCI_CAPABILITY_ID, &a);
+ if (a == PCI_CAPABILITY_PM) {
+ s->pmcs = b + PCI_PM_CONTROL_STATUS;
+ break;
+ }
+ pci_readb(bus, devfn, b+PCI_NEXT_CAPABILITY, &b);
+ }
+ }
+ /* If capability exists, make sure we're in D0 state */
+ if (s->pmcs)
+ pci_writew(bus, devfn, s->pmcs, PCI_PMCS_PWR_STATE_D0);
+
+ /* Map CardBus registers if they are not already mapped */
+ pci_writel(bus, devfn, CB_LEGACY_MODE_BASE, 0);
+ pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &s->cb_phys);
+ if (s->cb_phys == 0) {
+ int i;
+ for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) {
+ s->cb_phys = cb_mem_base[i];
+ s->cb_virt = ioremap(s->cb_phys, 0x1000);
+ pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys);
+ /* Simple sanity checks */
+ if (!(readb(s->cb_virt+0x800+I365_IDENT) & 0x70) &&
+ !(readb(s->cb_virt+0x800+I365_CSC) &&
+ readb(s->cb_virt+0x800+I365_CSC) &&
+ readb(s->cb_virt+0x800+I365_CSC)))
+ break;
+ iounmap(s->cb_virt);
+ }
+ if (i == sizeof(cb_mem_base)/sizeof(u_int)) {
+ pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, 0);
+ printk("\n");
+ printk(KERN_NOTICE " Bridge register mapping failed:"
+ " check cb_mem_base setting\n");
+ break;
+ }
+ cb_mem_base[0] = cb_mem_base[i] + PAGE_SIZE;
+ } else {
+ s->cb_virt = ioremap(s->cb_phys, 0x1000);
+ }
+
+ request_mem_region(s->cb_phys, 0x1000, "i82365");
+ add_socket(0, 0, type);
+ }
+ if (ns == 0) return;
+
+ s -= ns;
+ if (ns == 2) {
+ /* Nasty special check for bad bus mapping */
+ pci_readb(bus, s[0].devfn, CB_CARDBUS_BUS, &a);
+ pci_readb(bus, s[1].devfn, CB_CARDBUS_BUS, &b);
+ if (a == b) {
+ pci_writeb(bus, s[0].devfn, CB_CARDBUS_BUS, 0);
+ pci_writeb(bus, s[1].devfn, CB_CARDBUS_BUS, 0);
+ }
+ }
+ add_pcic(ns, type);
+
+ /* Re-do card type & voltage detection */
+ cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/5);
+
+ /* Set up PCI bus bridge structures if needed */
+ for (a = 0; a < ns; a++) {
+ struct pci_dev *self = pci_find_slot(bus, s[a].devfn);
+ struct pci_bus *child, *parent = self->bus;
+ for (child = parent->children; child; child = child->next)
+ if (child->number == s[a].cap.cardbus) break;
+ if (!child) {
+ child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+ memset(child, 0, sizeof(struct pci_bus));
+ child->self = self;
+ child->primary = bus;
+ child->number = child->secondary = s[a].cap.cardbus;
+ child->subordinate = s[a].sub_bus;
+ child->parent = parent;
+ child->next = parent->children;
+ }
+ s[a].cap.cb_bus = parent->children = child;
+ }
+}
+
+static void pci_probe(u_int class, void (add_fn)(int, u_char, u_char,
+ u_short, u_short))
+{
+ u_short i, v, d;
+ u_char bus, devfn;
+ pci_id_t id;
+
+ id = 0;
+ while (pci_lookup(class, &id, &bus, &devfn) == 0) {
+ if (PCI_FUNC(devfn) != 0) continue;
+ pci_readw(bus, devfn, PCI_VENDOR_ID, &v);
+ pci_readw(bus, devfn, PCI_DEVICE_ID, &d);
+ for (i = 0; i < PCIC_COUNT; i++)
+ if ((pcic[i].vendor == v) && (pcic[i].device == d)) break;
+ add_fn(i, bus, devfn, v, d);
+ }
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void isa_probe(void)
+{
+ int i, j, sock, k;
+ int ns, id;
+ u_short port;
+
+ if (check_region(i365_base, 2) != 0) {
+ if (sockets == 0)
+ printk("port conflict at %#x\n", i365_base);
+ return;
+ }
+
+ id = identify(i365_base, 0);
+ if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
+ for (i = 0; i < 4; i++) {
+ if (i == ignore) continue;
+ port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
+ sock = (i & 1) << 1;
+ if (identify(port, sock) == IS_I82365DF) {
+ add_socket(port, sock, IS_VLSI);
+ add_pcic(1, IS_VLSI);
+ }
+ }
+ } else {
+ for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) {
+ port = i365_base + 2*(i>>2);
+ sock = (i & 3);
+ id = identify(port, sock);
+ if (id < 0) continue;
+
+ for (j = ns = 0; j < 2; j++) {
+ /* Does the socket exist? */
+ if ((ignore == i+j) || (identify(port, sock+j) < 0))
+ continue;
+ /* Check for bad socket decode */
+ for (k = 0; k <= sockets; k++)
+ i365_set(k, I365_MEM(0)+I365_W_OFF, k);
+ for (k = 0; k <= sockets; k++)
+ if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
+ break;
+ if (k <= sockets) break;
+ add_socket(port, sock+j, id); ns++;
+ }
+ if (ns != 0) add_pcic(ns, id);
+ }
+ }
+}
+
+#endif
+
+/*====================================================================*/
+
+static int pcic_init(void)
+{
+ DEBUG(0, ("%s\n", version));
+ printk(KERN_INFO "Intel PCIC probe: ");
+ sockets = 0;
+
+#ifdef CONFIG_PCI
+ if (do_pci_probe && pcibios_present()) {
+ pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
+ pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
+ }
+#endif
+
+#ifdef CONFIG_ISA
+ isa_probe();
+#endif
+
+ if (sockets == 0) {
+ printk("not found.\n");
+ return -ENODEV;
+ }
+
+ /* Set up interrupt handler, and/or polling */
+#ifdef CONFIG_ISA
+ if (grab_irq != 0)
+ request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
+#endif
+#ifdef CONFIG_PCI
+ if (pci_csc) {
+ u_int i, irq, mask = 0;
+ for (i = 0; i < sockets; i++) {
+ irq = socket[i].cap.pci_irq;
+ if (irq && !(mask & (1<<irq)))
+ request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
+ mask |= (1<<irq);
+ }
+ }
+#endif
+
+ if (register_ss_entry(sockets, &pcic_service) != 0)
+ printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
+
+ /* Finally, schedule a polling interrupt */
+ if (poll_interval != 0) {
+ poll_timer.function = pcic_interrupt_wrapper;
+ poll_timer.data = 0;
+ poll_timer.prev = poll_timer.next = NULL;
+ poll_timer.expires = jiffies + poll_interval;
+ add_timer(&poll_timer);
+ }
+
+ return 0;
+
+} /* pcic_init */
+
+/*====================================================================*/
+
+static void pcic_finish(void)
+{
+ int i;
+#ifdef CONFIG_PROC_FS
+ for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+#endif
+ unregister_ss_entry(&pcic_service);
+ if (poll_interval != 0)
+ del_timer(&poll_timer);
+#ifdef CONFIG_ISA
+ if (grab_irq != 0)
+ free_irq(cs_irq, NULL);
+#endif
+#ifdef CONFIG_PCI
+ if (pci_csc) {
+ u_int irq, mask = 0;
+ for (i = 0; i < sockets; i++) {
+ irq = socket[i].cap.pci_irq;
+ if (irq && !(mask & (1<<irq)))
+ free_irq(irq, NULL);
+ mask |= (1<<irq);
+ }
+ }
+#endif
+ for (i = 0; i < sockets; i++) {
+ i365_set(i, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+ if (socket[i].cb_virt) {
+ iounmap(socket[i].cb_virt);
+ release_mem_region(socket[i].cb_phys, 0x1000);
+ } else
+#endif
+ release_region(socket[i].ioaddr, 2);
+ }
+} /* pcic_finish */
+
+/*====================================================================*/
+
+static void pcic_interrupt_wrapper(u_long data)
+{
+ pcic_interrupt(0, NULL, NULL);
+ poll_timer.expires = jiffies + poll_interval;
+ add_timer(&poll_timer);
+}
+
+static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ int i, j, csc;
+ u_int events, active;
+#ifdef CONFIG_ISA
+ u_long flags = 0;
+#endif
+
+ DEBUG(4, ("i82365: pcic_interrupt(%d)\n", irq));
+
+ for (j = 0; j < 20; j++) {
+ active = 0;
+ for (i = 0; i < sockets; i++) {
+ if ((socket[i].cs_irq != irq) &&
+ (socket[i].cap.pci_irq != irq))
+ continue;
+#ifdef CONFIG_ISA
+ if (!(socket[i].flags & IS_CARDBUS))
+ spin_lock_irqsave(&isa_lock, flags);
+#endif
+ csc = i365_get(i, I365_CSC);
+ if ((csc == 0) || (!socket[i].handler) ||
+ (i365_get(i, I365_IDENT) & 0x70)) {
+#ifdef CONFIG_ISA
+ if (!(socket[i].flags & IS_CARDBUS))
+ spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+ continue;
+ }
+ events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+ if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+ events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+ else {
+ events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+ events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+ events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+ }
+#ifdef CONFIG_ISA
+ if (!(socket[i].flags & IS_CARDBUS))
+ spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+ DEBUG(2, ("i82365: socket %d event 0x%02x\n", i, events));
+ if (events)
+ socket[i].handler(socket[i].info, events);
+ active |= events;
+ }
+ if (!active) break;
+ }
+ if (j == 20)
+ printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
+
+ DEBUG(4, ("i82365: interrupt done\n"));
+} /* pcic_interrupt */
+
+/*====================================================================*/
+
+static int pcic_register_callback(u_short sock, ss_callback_t *call)
+{
+ if (call == NULL) {
+ socket[sock].handler = NULL;
+ MOD_DEC_USE_COUNT;
+ } else {
+ MOD_INC_USE_COUNT;
+ socket[sock].handler = call->handler;
+ socket[sock].info = call->info;
+ }
+ return 0;
+} /* pcic_register_callback */
+
+/*====================================================================*/
+
+static int pcic_inquire_socket(u_short sock, socket_cap_t *cap)
+{
+ *cap = socket[sock].cap;
+ return 0;
+} /* pcic_inquire_socket */
+
+/*====================================================================*/
+
+static int i365_get_status(u_short sock, u_int *value)
+{
+ u_int status;
+
+ status = i365_get(sock, I365_STATUS);
+ *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+ ? SS_DETECT : 0;
+ if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+ *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+ else {
+ *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+ *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+ }
+ *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+ *value |= (status & I365_CS_READY) ? SS_READY : 0;
+ *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+
+#ifdef CONFIG_PCI
+ if (socket[sock].flags & IS_CARDBUS) {
+ status = cb_readl(sock, CB_SOCKET_STATE);
+#ifndef CONFIG_CARDBUS
+ *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0;
+#endif
+ *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0;
+ *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0;
+ } else if (socket[sock].flags & IS_O2MICRO) {
+ status = i365_get(sock, O2_MODE_B);
+ *value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD;
+ *value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD;
+ }
+#endif
+#ifdef CONFIG_ISA
+ if (socket[sock].type == IS_VG469) {
+ status = i365_get(sock, VG469_VSENSE);
+ if (socket[sock].psock & 1) {
+ *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
+ *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
+ } else {
+ *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
+ *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+ }
+ }
+#endif
+
+ DEBUG(1, ("i82365: GetStatus(%d) = %#4.4x\n", sock, *value));
+ return 0;
+} /* i365_get_status */
+
+/*====================================================================*/
+
+static int i365_get_socket(u_short sock, socket_state_t *state)
+{
+ socket_info_t *t = &socket[sock];
+ u_char reg, vcc, vpp;
+
+ reg = i365_get(sock, I365_POWER);
+ state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+ state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+ vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+ state->Vcc = state->Vpp = 0;
+#ifdef CONFIG_PCI
+ if (t->flags & IS_CARDBUS) {
+ cb_get_power(sock, state);
+ } else
+#endif
+ if (t->flags & IS_CIRRUS) {
+ if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) {
+ if (reg & I365_VCC_5V) state->Vcc = 33;
+ if (vpp == I365_VPP1_5V) state->Vpp = 33;
+ } else {
+ if (reg & I365_VCC_5V) state->Vcc = 50;
+ if (vpp == I365_VPP1_5V) state->Vpp = 50;
+ }
+ if (vpp == I365_VPP1_12V) state->Vpp = 120;
+ } else if (t->flags & IS_VG_PWR) {
+ if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) {
+ if (reg & I365_VCC_5V) state->Vcc = 33;
+ if (vpp == I365_VPP1_5V) state->Vpp = 33;
+ } else {
+ if (reg & I365_VCC_5V) state->Vcc = 50;
+ if (vpp == I365_VPP1_5V) state->Vpp = 50;
+ }
+ if (vpp == I365_VPP1_12V) state->Vpp = 120;
+ } else if (t->flags & IS_DF_PWR) {
+ if (vcc == I365_VCC_3V) state->Vcc = 33;
+ if (vcc == I365_VCC_5V) state->Vcc = 50;
+ if (vpp == I365_VPP1_5V) state->Vpp = 50;
+ if (vpp == I365_VPP1_12V) state->Vpp = 120;
+ } else {
+ if (reg & I365_VCC_5V) {
+ state->Vcc = 50;
+ if (vpp == I365_VPP1_5V) state->Vpp = 50;
+ if (vpp == I365_VPP1_12V) state->Vpp = 120;
+ }
+ }
+
+ /* IO card, RESET flags, IO interrupt */
+ reg = i365_get(sock, I365_INTCTL);
+ state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+ if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+#ifdef CONFIG_PCI
+ if (cb_get_irq_mode(sock) != 0)
+ state->io_irq = t->cap.pci_irq;
+ else
+#endif
+ state->io_irq = reg & I365_IRQ_MASK;
+
+ /* speaker control */
+ if (t->flags & IS_CIRRUS) {
+ if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA)
+ state->flags |= SS_SPKR_ENA;
+ }
+
+ /* Card status change mask */
+ reg = i365_get(sock, I365_CSCINT);
+ state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+ if (state->flags & SS_IOCARD)
+ state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+ else {
+ state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+ state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+ state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+ }
+
+ DEBUG(1, ("i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+ return 0;
+} /* i365_get_socket */
+
+/*====================================================================*/
+
+static int i365_set_socket(u_short sock, socket_state_t *state)
+{
+ socket_info_t *t = &socket[sock];
+ u_char reg;
+
+ DEBUG(1, ("i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+
+ /* First set global controller options */
+#ifdef CONFIG_PCI
+ if ((t->flags & IS_CARDBUS) && t->cap.pci_irq)
+ cb_set_irq_mode(sock, pci_csc,
+ (t->cap.pci_irq == state->io_irq));
+ t->bcr &= ~CB_BCR_CB_RESET;
+#endif
+ set_host_state(sock);
+
+ /* IO card, RESET flag, IO interrupt */
+ reg = t->intr;
+ if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq;
+ reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+ reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+ i365_set(sock, I365_INTCTL, reg);
+
+ reg = I365_PWR_NORESET;
+ if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+ if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+
+#ifdef CONFIG_PCI
+ if (t->flags & IS_CARDBUS) {
+ cb_set_power(sock, state);
+ reg |= i365_get(sock, I365_POWER) &
+ (I365_VCC_MASK|I365_VPP1_MASK);
+ } else
+#endif
+ if (t->flags & IS_CIRRUS) {
+ if (state->Vpp != 0) {
+ if (state->Vpp == 120)
+ reg |= I365_VPP1_12V;
+ else if (state->Vpp == state->Vcc)
+ reg |= I365_VPP1_5V;
+ else return -EINVAL;
+ }
+ if (state->Vcc != 0) {
+ reg |= I365_VCC_5V;
+ if (state->Vcc == 33)
+ i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+ else if (state->Vcc == 50)
+ i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+ else return -EINVAL;
+ }
+ } else if (t->flags & IS_VG_PWR) {
+ if (state->Vpp != 0) {
+ if (state->Vpp == 120)
+ reg |= I365_VPP1_12V;
+ else if (state->Vpp == state->Vcc)
+ reg |= I365_VPP1_5V;
+ else return -EINVAL;
+ }
+ if (state->Vcc != 0) {
+ reg |= I365_VCC_5V;
+ if (state->Vcc == 33)
+ i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
+ else if (state->Vcc == 50)
+ i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
+ else return -EINVAL;
+ }
+ } else if (t->flags & IS_DF_PWR) {
+ switch (state->Vcc) {
+ case 0: break;
+ case 33: reg |= I365_VCC_3V; break;
+ case 50: reg |= I365_VCC_5V; break;
+ default: return -EINVAL;
+ }
+ switch (state->Vpp) {
+ case 0: break;
+ case 50: reg |= I365_VPP1_5V; break;
+ case 120: reg |= I365_VPP1_12V; break;
+ default: return -EINVAL;
+ }
+ } else {
+ switch (state->Vcc) {
+ case 0: break;
+ case 50: reg |= I365_VCC_5V; break;
+ default: return -EINVAL;
+ }
+ switch (state->Vpp) {
+ case 0: break;
+ case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+ case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+ default: return -EINVAL;
+ }
+ }
+
+ if (reg != i365_get(sock, I365_POWER))
+ i365_set(sock, I365_POWER, reg);
+
+ /* Chipset-specific functions */
+ if (t->flags & IS_CIRRUS) {
+ /* Speaker control */
+ i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+ state->flags & SS_SPKR_ENA);
+ }
+
+ /* Card status change interrupt mask */
+ reg = t->cs_irq << 4;
+ if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+ if (state->flags & SS_IOCARD) {
+ if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+ } else {
+ if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
+ if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
+ if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+ }
+ i365_set(sock, I365_CSCINT, reg);
+ i365_get(sock, I365_CSC);
+
+ return 0;
+} /* i365_set_socket */
+
+/*====================================================================*/
+
+static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+ u_char map, ioctl, addr;
+
+ map = io->map;
+ if (map > 1) return -EINVAL;
+ io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
+ io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
+ ioctl = i365_get(sock, I365_IOCTL);
+ addr = i365_get(sock, I365_ADDRWIN);
+ io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
+ io->flags = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
+ io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
+ io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
+ io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
+ DEBUG(1, ("i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+ "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+ io->start, io->stop));
+ return 0;
+} /* i365_get_io_map */
+
+/*====================================================================*/
+
+static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+ u_char map, ioctl;
+
+ DEBUG(1, ("i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+ "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+ io->speed, io->start, io->stop));
+ map = io->map;
+ if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+ (io->stop < io->start)) return -EINVAL;
+ /* Turn off the window before changing anything */
+ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+ i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
+ i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
+ i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
+ ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+ if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
+ if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+ if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+ if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+ i365_set(sock, I365_IOCTL, ioctl);
+ /* Turn on the window if necessary */
+ if (io->flags & MAP_ACTIVE)
+ i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
+ return 0;
+} /* i365_set_io_map */
+
+/*====================================================================*/
+
+static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+ u_short base, i;
+ u_char map, addr;
+
+ map = mem->map;
+ if (map > 4) return -EINVAL;
+ addr = i365_get(sock, I365_ADDRWIN);
+ mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
+ base = I365_MEM(map);
+
+ i = i365_get_pair(sock, base+I365_W_START);
+ mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
+ mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
+ mem->sys_start += ((u_long)(i & 0x0fff) << 12);
+
+ i = i365_get_pair(sock, base+I365_W_STOP);
+ mem->speed = (i & I365_MEM_WS0) ? 1 : 0;
+ mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
+ mem->speed = to_ns(mem->speed);
+ mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
+
+ i = i365_get_pair(sock, base+I365_W_OFF);
+ mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
+ mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0;
+ mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start;
+ mem->card_start &= 0x3ffffff;
+
+#ifdef CONFIG_PCI
+ /* Take care of high byte, for PCI controllers */
+ if (socket[sock].type == IS_PD6729) {
+ i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+ addr = i365_get(sock, PD67_EXT_DATA) << 24;
+ } else if (socket[sock].flags & IS_CARDBUS) {
+ addr = i365_get(sock, CB_MEM_PAGE(map)) << 24;
+ mem->sys_stop += addr; mem->sys_start += addr;
+ }
+#endif
+
+ DEBUG(1, ("i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+ "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+ mem->sys_start, mem->sys_stop, mem->card_start));
+ return 0;
+} /* i365_get_mem_map */
+
+/*====================================================================*/
+
+static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+ u_short base, i;
+ u_char map;
+
+ DEBUG(1, ("i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+ "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
+ mem->sys_start, mem->sys_stop, mem->card_start));
+
+ map = mem->map;
+ if ((map > 4) || (mem->card_start > 0x3ffffff) ||
+ (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+ return -EINVAL;
+ if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) &&
+ ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)))
+ return -EINVAL;
+
+ /* Turn off the window before changing anything */
+ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+ i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+
+#ifdef CONFIG_PCI
+ /* Take care of high byte, for PCI controllers */
+ if (socket[sock].type == IS_PD6729) {
+ i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+ i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24));
+ } else if (socket[sock].flags & IS_CARDBUS)
+ i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24);
+#endif
+
+ base = I365_MEM(map);
+ i = (mem->sys_start >> 12) & 0x0fff;
+ if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+ if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+ i365_set_pair(sock, base+I365_W_START, i);
+
+ i = (mem->sys_stop >> 12) & 0x0fff;
+ switch (to_cycles(mem->speed)) {
+ case 0: break;
+ case 1: i |= I365_MEM_WS0; break;
+ case 2: i |= I365_MEM_WS1; break;
+ default: i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+ }
+ i365_set_pair(sock, base+I365_W_STOP, i);
+
+ i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+ if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+ if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+ i365_set_pair(sock, base+I365_W_OFF, i);
+
+ /* Turn on the window if necessary */
+ if (mem->flags & MAP_ACTIVE)
+ i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+ return 0;
+} /* i365_set_mem_map */
+
+/*======================================================================
+
+ Power control for Cardbus controllers: used both for 16-bit and
+ Cardbus cards.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_power(u_short sock, socket_state_t *state)
+{
+ u_int reg = cb_readl(sock, CB_SOCKET_CONTROL);
+ state->Vcc = state->Vpp = 0;
+ switch (reg & CB_SC_VCC_MASK) {
+ case CB_SC_VCC_3V: state->Vcc = 33; break;
+ case CB_SC_VCC_5V: state->Vcc = 50; break;
+ }
+ switch (reg & CB_SC_VCC_MASK) {
+ case CB_SC_VPP_3V: state->Vpp = 33; break;
+ case CB_SC_VPP_5V: state->Vpp = 50; break;
+ case CB_SC_VPP_12V: state->Vpp = 120; break;
+ }
+}
+
+static void cb_set_power(u_short sock, socket_state_t *state)
+{
+ u_int reg = 0;
+ switch (state->Vcc) {
+ case 33: reg = CB_SC_VCC_3V; break;
+ case 50: reg = CB_SC_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 33: reg |= CB_SC_VPP_3V; break;
+ case 50: reg |= CB_SC_VPP_5V; break;
+ case 120: reg |= CB_SC_VPP_12V; break;
+ }
+ if (reg != cb_readl(sock, CB_SOCKET_CONTROL))
+ cb_writel(sock, CB_SOCKET_CONTROL, reg);
+}
+
+#endif
+
+/*======================================================================
+
+ All the stuff that is strictly for Cardbus cards goes here.
+
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int cb_get_status(u_short sock, u_int *value)
+{
+ u_int s;
+ s = cb_readl(sock, CB_SOCKET_STATE);
+ *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0);
+ *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT;
+ *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0;
+ *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0;
+ *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0;
+ *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0;
+ DEBUG(1, ("yenta: GetStatus(%d) = %#4.4x\n", sock, *value));
+ return 0;
+} /* cb_get_status */
+
+static int cb_get_socket(u_short sock, socket_state_t *state)
+{
+ socket_info_t *s = &socket[sock];
+ u_short bcr;
+
+ cb_get_power(sock, state);
+ pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+ state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0;
+ if (cb_get_irq_mode(sock) != 0)
+ state->io_irq = s->cap.pci_irq;
+ else
+ state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK;
+ DEBUG(1, ("yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+ return 0;
+} /* cb_get_socket */
+
+static int cb_set_socket(u_short sock, socket_state_t *state)
+{
+ socket_info_t *s = &socket[sock];
+ u_int reg;
+
+ DEBUG(1, ("yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask));
+
+ /* First set global controller options */
+ if (s->cap.pci_irq)
+ cb_set_irq_mode(sock, pci_csc,
+ (s->cap.pci_irq == state->io_irq));
+ s->bcr &= ~CB_BCR_CB_RESET;
+ s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0;
+ set_host_state(sock);
+
+ cb_set_power(sock, state);
+
+ /* Handle IO interrupt using ISA routing */
+ reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK;
+ if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
+ i365_set(sock, I365_INTCTL, reg);
+
+ /* Handle CSC mask */
+ reg = (socket[sock].cs_irq << 4);
+ if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+ i365_set(sock, I365_CSCINT, reg);
+ i365_get(sock, I365_CSC);
+
+ return 0;
+} /* cb_set_socket */
+
+static int cb_get_bridge(u_short sock, struct cb_bridge_map *m)
+{
+ socket_info_t *s = &socket[sock];
+ u_char map;
+
+ map = m->map;
+ if (map > 1) return -EINVAL;
+ m->flags &= MAP_IOSPACE;
+ map += (m->flags & MAP_IOSPACE) ? 2 : 0;
+ pci_readl(s->bus, s->devfn, CB_MEM_BASE(map), &m->start);
+ pci_readl(s->bus, s->devfn, CB_MEM_LIMIT(map), &m->stop);
+ if (m->start || m->stop) {
+ m->flags |= MAP_ACTIVE;
+ m->stop |= (map > 1) ? 3 : 0x0fff;
+ }
+ if (map > 1) {
+ u_short bcr;
+ pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+ m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0;
+ }
+ DEBUG(1, ("yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n",
+ sock, map, m->flags, m->start, m->stop));
+ return 0;
+}
+
+static int cb_set_bridge(u_short sock, struct cb_bridge_map *m)
+{
+ socket_info_t *s = &socket[sock];
+ u_char map;
+
+ DEBUG(1, ("yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n",
+ sock, m->map, m->flags, m->start, m->stop));
+ map = m->map;
+ if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start))
+ return -EINVAL;
+ if (m->flags & MAP_IOSPACE) {
+ if ((m->stop > 0xffff) || (m->start & 3) ||
+ ((m->stop & 3) != 3))
+ return -EINVAL;
+ map += 2;
+ } else {
+ u_short bcr;
+ if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff))
+ return -EINVAL;
+ pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+ bcr &= ~CB_BCR_PREFETCH(map);
+ bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0;
+ pci_writew(s->bus, s->devfn, CB_BRIDGE_CONTROL, bcr);
+ }
+ if (m->flags & MAP_ACTIVE) {
+ pci_writel(s->bus, s->devfn, CB_MEM_BASE(map), m->start);
+ pci_writel(s->bus, s->devfn, CB_MEM_LIMIT(map), m->stop);
+ } else {
+ pci_writel(s->bus, s->devfn, CB_IO_BASE(map), 0);
+ pci_writel(s->bus, s->devfn, CB_IO_LIMIT(map), 0);
+ }
+ return 0;
+}
+
+#endif /* CONFIG_CARDBUS */
+
+/*======================================================================
+
+ Routines for accessing socket information and register dumps via
+ /proc/bus/pccard/...
+
+======================================================================*/
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_read_info(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ socket_info_t *s = data;
+ char *p = buf;
+ p += sprintf(p, "type: %s\npsock: %d\n",
+ pcic[s->type].name, s->psock);
+#ifdef CONFIG_PCI
+ if (s->flags & (IS_PCI|IS_CARDBUS))
+ p += sprintf(p, "bus: %02x\ndevfn: %02x.%1x\n",
+ s->bus, PCI_SLOT(s->devfn), PCI_FUNC(s->devfn));
+ if (s->flags & IS_CARDBUS)
+ p += sprintf(p, "cardbus: %02x\n", s->cap.cardbus);
+#endif
+ return (p - buf);
+}
+
+static int proc_read_exca(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ u_short sock = (socket_info_t *)data - socket;
+ char *p = buf;
+ int i, top;
+
+#ifdef CONFIG_ISA
+ u_long flags = 0;
+ if (!(socket[sock].flags & IS_CARDBUS))
+ spin_lock_irqsave(&isa_lock, flags);
+#endif
+ top = 0x40;
+ if (socket[sock].flags & IS_CARDBUS)
+ top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50;
+ for (i = 0; i < top; i += 4) {
+ if (i == 0x50) {
+ p += sprintf(p, "\n");
+ i = 0x100;
+ }
+ p += sprintf(p, "%02x %02x %02x %02x%s",
+ i365_get(sock,i), i365_get(sock,i+1),
+ i365_get(sock,i+2), i365_get(sock,i+3),
+ ((i % 16) == 12) ? "\n" : " ");
+ }
+#ifdef CONFIG_ISA
+ if (!(socket[sock].flags & IS_CARDBUS))
+ spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+ return (p - buf);
+}
+
+
+#ifdef CONFIG_PCI
+static int proc_read_pci(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ socket_info_t *s = data;
+ u_char bus = s->bus, devfn = s->devfn;
+ char *p = buf;
+ u_int a, b, c, d;
+ int i;
+
+ for (i = 0; i < 0xc0; i += 0x10) {
+ pci_readl(bus, devfn, i, &a);
+ pci_readl(bus, devfn, i+4, &b);
+ pci_readl(bus, devfn, i+8, &c);
+ pci_readl(bus, devfn, i+12, &d);
+ p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d);
+ }
+ return (p - buf);
+}
+#endif
+
+#ifdef CONFIG_CARDBUS
+static int proc_read_cardbus(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ u_short sock = (socket_info_t *)data - socket;
+ int len;
+
+ len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n",
+ cb_readl(sock,0), cb_readl(sock,4),
+ cb_readl(sock,8), cb_readl(sock,12),
+ cb_readl(sock,16), cb_readl(sock,32));
+ return len;
+}
+#endif
+
+static void pcic_proc_setup(u_short sock, struct proc_dir_entry *base)
+{
+ socket_info_t *s = &socket[sock];
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("info", 0, base);
+ ent->read_proc = proc_read_info;
+ ent->data = s;
+ ent = create_proc_entry("exca", 0, base);
+ ent->read_proc = proc_read_exca;
+ ent->data = s;
+#ifdef CONFIG_PCI
+ if (s->flags & (IS_PCI|IS_CARDBUS)) {
+ ent = create_proc_entry("pci", 0, base);
+ ent->read_proc = proc_read_pci;
+ ent->data = s;
+ }
+#endif
+#ifdef CONFIG_CARDBUS
+ if (s->flags & IS_CARDBUS) {
+ ent = create_proc_entry("cardbus", 0, base);
+ ent->read_proc = proc_read_cardbus;
+ ent->data = s;
+ }
+#endif
+ s->proc = base;
+}
+
+static void pcic_proc_remove(u_short sock)
+{
+ struct proc_dir_entry *base = socket[sock].proc;
+ if (base == NULL) return;
+ remove_proc_entry("info", base);
+ remove_proc_entry("exca", base);
+#ifdef CONFIG_PCI
+ if (socket[sock].flags & (IS_PCI|IS_CARDBUS))
+ remove_proc_entry("pci", base);
+#endif
+#ifdef CONFIG_CARDBUS
+ if (socket[sock].flags & IS_CARDBUS)
+ remove_proc_entry("cardbus", base);
+#endif
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+
+static subfn_t pcic_service_table[] = {
+ (subfn_t)&pcic_register_callback,
+ (subfn_t)&pcic_inquire_socket,
+ (subfn_t)&i365_get_status,
+ (subfn_t)&i365_get_socket,
+ (subfn_t)&i365_set_socket,
+ (subfn_t)&i365_get_io_map,
+ (subfn_t)&i365_set_io_map,
+ (subfn_t)&i365_get_mem_map,
+ (subfn_t)&i365_set_mem_map,
+#ifdef CONFIG_CARDBUS
+ (subfn_t)&cb_get_bridge,
+ (subfn_t)&cb_set_bridge,
+#else
+ NULL, NULL,
+#endif
+#ifdef CONFIG_PROC_FS
+ (subfn_t)&pcic_proc_setup
+#endif
+};
+
+#define NFUNC (sizeof(pcic_service_table)/sizeof(subfn_t))
+
+static int pcic_service(u_int sock, u_int cmd, void *arg)
+{
+ subfn_t fn;
+
+ DEBUG(2, ("pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg));
+
+ if (cmd >= NFUNC)
+ return -EINVAL;
+
+ if (socket[sock].flags & IS_ALIVE) {
+ if (cmd == SS_GetStatus)
+ *(u_int *)arg = 0;
+ return -EINVAL;
+ }
+
+ fn = pcic_service_table[cmd];
+#ifdef CONFIG_CARDBUS
+ if ((socket[sock].flags & IS_CARDBUS) &&
+ (cb_readl(sock, CB_SOCKET_STATE) & CB_SS_32BIT)) {
+ if (cmd == SS_GetStatus)
+ fn = (subfn_t)&cb_get_status;
+ else if (cmd == SS_GetSocket)
+ fn = (subfn_t)&cb_get_socket;
+ else if (cmd == SS_SetSocket)
+ fn = (subfn_t)&cb_set_socket;
+ }
+#endif
+
+#ifdef CONFIG_ISA
+ if (!(socket[sock].flags & IS_CARDBUS)) {
+ int ret;
+ u_long flags;
+ spin_lock_irqsave(&isa_lock, flags);
+ ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
+ spin_unlock_irqrestore(&isa_lock, flags);
+ return ret;
+ }
+#endif
+ return (fn == NULL) ? -EINVAL : fn(sock, arg);
+} /* pcic_service */
+
+/*====================================================================*/
+
+int pcmcia_i82365_init(void)
+{
+ servinfo_t serv;
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "i82365: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ return pcic_init();
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return pcmcia_i82365_init();
+}
+
+void cleanup_module(void)
+{
+ pcic_finish();
+}
+
+#endif
+
+/*====================================================================*/
+
--- /dev/null
+/*
+ * i82365.h 1.14 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT 0x00 /* Identification and revision */
+#define I365_STATUS 0x01 /* Interface status */
+#define I365_POWER 0x02 /* Power and RESETDRV control */
+#define I365_INTCTL 0x03 /* Interrupt and general control */
+#define I365_CSC 0x04 /* Card status change */
+#define I365_CSCINT 0x05 /* Card status change interrupt control */
+#define I365_ADDRWIN 0x06 /* Address window enable */
+#define I365_IOCTL 0x07 /* I/O control */
+#define I365_GENCTL 0x16 /* Card detect and general control */
+#define I365_GBLCTL 0x1E /* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map) (0x08+((map)<<2))
+#define I365_MEM(map) (0x10+((map)<<3))
+#define I365_W_START 0
+#define I365_W_STOP 2
+#define I365_W_OFF 4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1 0x01
+#define I365_CS_STSCHG 0x01
+#define I365_CS_BVD2 0x02
+#define I365_CS_SPKR 0x02
+#define I365_CS_DETECT 0x0C
+#define I365_CS_WRPROT 0x10
+#define I365_CS_READY 0x20 /* Inverted */
+#define I365_CS_POWERON 0x40
+#define I365_CS_GPI 0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF 0x00 /* Turn off the socket */
+#define I365_PWR_OUT 0x80 /* Output enable */
+#define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */
+#define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */
+#define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+ step has independent Vpp1/Vpp2 control, and the DF step has only
+ Vpp1 control, plus 3V control */
+#define I365_VCC_5V 0x10 /* Vcc = 5.0v */
+#define I365_VCC_3V 0x18 /* Vcc = 3.3v */
+#define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */
+#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */
+#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */
+#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */
+#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */
+#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA 0x80
+#define I365_PC_RESET 0x40
+#define I365_PC_IOCARD 0x20
+#define I365_INTR_ENA 0x10
+#define I365_IRQ_MASK 0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1 0x01
+#define I365_CSC_STSCHG 0x01
+#define I365_CSC_BVD2 0x02
+#define I365_CSC_READY 0x04
+#define I365_CSC_DETECT 0x08
+#define I365_CSC_ANY 0x0F
+#define I365_CSC_GPI 0x10
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map) (0x40 << (map))
+#define I365_ENA_MEM(map) (0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map) (0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map) (0x08 << (map<<2))
+#define I365_IOCTL_0WS(map) (0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map) (0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map) (0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY 0x01
+#define I365_CTL_RESET 0x02
+#define I365_CTL_GPI_ENA 0x04
+#define I365_CTL_GPI_CTL 0x08
+#define I365_CTL_RESUME 0x10
+#define I365_CTL_SW_IRQ 0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN 0x01
+#define I365_GBL_CSC_LEV 0x02
+#define I365_GBL_WRBACK 0x04
+#define I365_GBL_IRQ_0_LEV 0x08
+#define I365_GBL_IRQ_1_LEV 0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT 0x8000 /* In memory start high byte */
+#define I365_MEM_0WS 0x4000
+#define I365_MEM_WS1 0x8000 /* In memory stop high byte */
+#define I365_MEM_WS0 0x4000
+#define I365_MEM_WRPROT 0x8000 /* In offset high byte */
+#define I365_MEM_REG 0x4000
+
+#define I365_REG(slot, reg) (((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
--- /dev/null
+/*
+ * o2micro.h $Revision: 1.9 $ $Date: 1999/08/28 04:01:47 $
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_O2MICRO_H
+#define _LINUX_O2MICRO_H
+
+#ifndef PCI_VENDOR_ID_O2
+#define PCI_VENDOR_ID_O2 0x1217
+#endif
+#ifndef PCI_DEVICE_ID_O2_6729
+#define PCI_DEVICE_ID_O2_6729 0x6729
+#endif
+#ifndef PCI_DEVICE_ID_O2_6730
+#define PCI_DEVICE_ID_O2_6730 0x673a
+#endif
+#ifndef PCI_DEVICE_ID_O2_6832
+#define PCI_DEVICE_ID_O2_6832 0x6832
+#endif
+#ifndef PCI_DEVICE_ID_O2_6836
+#define PCI_DEVICE_ID_O2_6836 0x6836
+#endif
+
+#define O2_MODE_A 0x38
+#define O2_MODE_A_2 0x26 /* For 6833B, 6860C */
+#define O2_MODE_A_CD_PULSE 0x04
+#define O2_MODE_A_SUSP_EDGE 0x08
+#define O2_MODE_A_HOST_SUSP 0x10
+#define O2_MODE_A_PWRCHIP 0x60
+#define O2_MODE_A_QUIET 0x80
+
+#define O2_MODE_B 0x39
+#define O2_MODE_B_2 0x2e /* For 6833B, 6860C */
+#define O2_MODE_B_IDENT 0x03
+#define O2_MODE_B_ID_BSTEP 0x00
+#define O2_MODE_B_ID_CSTEP 0x01
+#define O2_MODE_B_ID_O2 0x02
+#define O2_MODE_B_VS1 0x04
+#define O2_MODE_B_VS2 0x08
+#define O2_MODE_B_IRQ15_RI 0x80
+
+#define O2_MODE_C 0x3a
+#define O2_MODE_C_DREQ_MASK 0x03
+#define O2_MODE_C_DREQ_INPACK 0x01
+#define O2_MODE_C_DREQ_WP 0x02
+#define O2_MODE_C_DREQ_BVD2 0x03
+#define O2_MODE_C_ZVIDEO 0x08
+
+#define O2_MODE_D 0x3b
+#define O2_MODE_D_IRQ_MODE 0x03
+#define O2_MODE_D_SKT_ACTV 0x20
+#define O2_MODE_D_PCI_FIFO 0x40 /* for OZ6729, OZ6730 */
+#define O2_MODE_D_W97_IRQ 0x40 /* for OZ6832 */
+#define O2_MODE_D_ISA_IRQ 0x80
+
+#define O2_MHPG_DMA 0x3c
+#define O2_MHPG_CHANNEL 0x07
+#define O2_MHPG_CINT_ENA 0x08
+#define O2_MHPG_CSC_ENA 0x10
+
+#define O2_FIFO_ENA 0x3d
+#define O2_FIFO_ZVIDEO_3 0x08
+#define O2_FIFO_PCI_FIFO 0x10
+#define O2_FIFO_POSTWR 0x40
+#define O2_FIFO_BUFFER 0x80
+
+#define O2_MODE_E 0x3e
+#define O2_MODE_E_MHPG_DMA 0x01
+#define O2_MODE_E_SPKR_OUT 0x02
+#define O2_MODE_E_LED_OUT 0x08
+#define O2_MODE_E_SKTA_ACTV 0x10
+
+#endif /* _LINUX_O2MICRO_H */
--- /dev/null
+/*
+ * ricoh.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_RICOH_H
+#define _LINUX_RICOH_H
+
+#define RF5C_MODE_CTL 0x1f /* Mode control */
+#define RF5C_PWR_CTL 0x2f /* Mixed voltage control */
+#define RF5C_CHIP_ID 0x3a /* Chip identification */
+#define RF5C_MODE_CTL_3 0x3b /* Mode control 3 */
+
+/* I/O window address offset */
+#define RF5C_IO_OFF(w) (0x36+((w)<<1))
+
+/* Flags for RF5C_MODE_CTL */
+#define RF5C_MODE_ATA 0x01 /* ATA mode */
+#define RF5C_MODE_LED_ENA 0x02 /* IRQ 12 is LED */
+#define RF5C_MODE_CA21 0x04
+#define RF5C_MODE_CA22 0x08
+#define RF5C_MODE_CA23 0x10
+#define RF5C_MODE_CA24 0x20
+#define RF5C_MODE_CA25 0x40
+#define RF5C_MODE_3STATE_BIT7 0x80
+
+/* Flags for RF5C_PWR_CTL */
+#define RF5C_PWR_VCC_3V 0x01
+#define RF5C_PWR_IREQ_HIGH 0x02
+#define RF5C_PWR_INPACK_ENA 0x04
+#define RF5C_PWR_5V_DET 0x08
+#define RF5C_PWR_TC_SEL 0x10 /* Terminal Count: irq 11 or 15 */
+#define RF5C_PWR_DREQ_LOW 0x20
+#define RF5C_PWR_DREQ_OFF 0x00 /* DREQ steering control */
+#define RF5C_PWR_DREQ_INPACK 0x40
+#define RF5C_PWR_DREQ_SPKR 0x80
+#define RF5C_PWR_DREQ_IOIS16 0xc0
+
+/* Values for RF5C_CHIP_ID */
+#define RF5C_CHIP_RF5C296 0x32
+#define RF5C_CHIP_RF5C396 0xb2
+
+/* Flags for RF5C_MODE_CTL_3 */
+#define RF5C_MCTL3_DISABLE 0x01 /* Disable PCMCIA interface */
+#define RF5C_MCTL3_DMA_ENA 0x02
+
+/* Register definitions for Ricoh PCI-to-CardBus bridges */
+
+#ifndef PCI_VENDOR_ID_RICOH
+#define PCI_VENDOR_ID_RICOH 0x1180
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C465
+#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C466
+#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C475
+#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C476
+#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C478
+#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
+#endif
+
+/* Extra bits in CB_BRIDGE_CONTROL */
+#define RL5C46X_BCR_3E0_ENA 0x0800
+#define RL5C46X_BCR_3E2_ENA 0x1000
+
+/* Misc Control Register */
+#define RL5C4XX_MISC 0x0082 /* 16 bit */
+#define RL5C4XX_MISC_HW_SUSPEND_ENA 0x0002
+#define RL5C4XX_MISC_VCCEN_POL 0x0100
+#define RL5C4XX_MISC_VPPEN_POL 0x0200
+#define RL5C46X_MISC_SUSPEND 0x0001
+#define RL5C46X_MISC_PWR_SAVE_2 0x0004
+#define RL5C46X_MISC_IFACE_BUSY 0x0008
+#define RL5C46X_MISC_B_LOCK 0x0010
+#define RL5C46X_MISC_A_LOCK 0x0020
+#define RL5C46X_MISC_PCI_LOCK 0x0040
+#define RL5C47X_MISC_IFACE_BUSY 0x0004
+#define RL5C47X_MISC_PCI_INT_MASK 0x0018
+#define RL5C47X_MISC_PCI_INT_DIS 0x0020
+#define RL5C47X_MISC_SUBSYS_WR 0x0040
+#define RL5C47X_MISC_SRIRQ_ENA 0x0080
+#define RL5C47X_MISC_5V_DISABLE 0x0400
+#define RL5C47X_MISC_LED_POL 0x0800
+
+/* 16-bit Interface Control Register */
+#define RL5C4XX_16BIT_CTL 0x0084 /* 16 bit */
+#define RL5C4XX_16CTL_IO_TIMING 0x0100
+#define RL5C4XX_16CTL_MEM_TIMING 0x0200
+#define RL5C46X_16CTL_LEVEL_1 0x0010
+#define RL5C46X_16CTL_LEVEL_2 0x0020
+
+/* 16-bit IO and memory timing registers */
+#define RL5C4XX_16BIT_IO_0 0x0088 /* 16 bit */
+#define RL5C4XX_16BIT_MEM_0 0x0088 /* 16 bit */
+#define RL5C4XX_SETUP_MASK 0x0007
+#define RL5C4XX_SETUP_SHIFT 0
+#define RL5C4XX_CMD_MASK 0x01f0
+#define RL5C4XX_CMD_SHIFT 4
+#define RL5C4XX_HOLD_MASK 0x1c00
+#define RL5C4XX_HOLD_SHIFT 10
+
+#endif /* _LINUX_RICOH_H */
--- /dev/null
+/*======================================================================
+
+ Resource management routines
+
+ rsrc_mgr.c 1.69 1999/08/28 04:01:46
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Should we probe resources for conflicts? */
+static int probe_mem = 1;
+MODULE_PARM(probe_mem, "i");
+#ifdef CONFIG_ISA
+static int probe_io = 1;
+static int mem_limit = 0x10000;
+MODULE_PARM(probe_io, "i");
+MODULE_PARM(mem_limit, "i");
+#endif
+
+/*======================================================================
+
+ The resource_map_t structures are used to track what resources are
+ available for allocation for PC Card devices.
+
+======================================================================*/
+
+typedef struct resource_map_t {
+ u_long base, num;
+ struct resource_map_t *next;
+} resource_map_t;
+
+/* Memory resource database */
+static resource_map_t mem_db = { 0, 0, &mem_db };
+
+/* IO port resource database */
+static resource_map_t io_db = { 0, 0, &io_db };
+
+#ifdef CONFIG_ISA
+
+typedef struct irq_info_t {
+ u_int Attributes;
+ int time_share, dyn_share;
+ struct socket_info_t *Socket;
+} irq_info_t;
+
+/* Table of IRQ assignments */
+static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
+
+#endif
+
+static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
+
+/*======================================================================
+
+ Linux resource management extensions
+
+======================================================================*/
+
+typedef struct resource_entry_t {
+ u_long base, num;
+ char *name;
+ struct resource_entry_t *next;
+} resource_entry_t;
+
+/* Ordered linked lists of allocated IO and memory blocks */
+static resource_entry_t io_list = { 0, 0, NULL, NULL };
+#ifndef HAVE_MEMRESERVE
+static resource_entry_t mem_list = { 0, 0, NULL, NULL };
+#endif
+
+static resource_entry_t *find_gap(resource_entry_t *root,
+ resource_entry_t *entry)
+{
+ resource_entry_t *p;
+
+ if (entry->base > entry->base+entry->num-1)
+ return NULL;
+ for (p = root; ; p = p->next) {
+ if ((p != root) && (p->base+p->num-1 >= entry->base)) {
+ p = NULL;
+ break;
+ }
+ if ((p->next == NULL) ||
+ (p->next->base > entry->base+entry->num-1))
+ break;
+ }
+ return p;
+}
+
+static int register_my_resource(resource_entry_t *list,
+ u_long base, u_long num, char *name)
+{
+ u_long flags;
+ resource_entry_t *p, *entry;
+
+ entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC);
+ entry->base = base;
+ entry->num = num;
+ entry->name = name;
+
+ spin_lock_irqsave(&rsrc_lock, flags);
+ p = find_gap(list, entry);
+ if (p == NULL) {
+ spin_unlock_irqrestore(&rsrc_lock, flags);
+ kfree(entry);
+ return -EBUSY;
+ }
+ entry->next = p->next;
+ p->next = entry;
+ spin_unlock_irqrestore(&rsrc_lock, flags);
+ return 0;
+}
+
+static void release_my_resource(resource_entry_t *list,
+ u_long base, u_long num)
+{
+ u_long flags;
+ resource_entry_t *p, *q;
+
+ spin_lock_irqsave(&rsrc_lock, flags);
+ for (p = list; ; p = q) {
+ q = p->next;
+ if (q == NULL) break;
+ if ((q->base == base) && (q->num == num)) {
+ p->next = q->next;
+ kfree(q);
+ spin_unlock_irqrestore(&rsrc_lock, flags);
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&rsrc_lock, flags);
+ return;
+}
+
+static int check_my_resource(resource_entry_t *list,
+ u_long base, u_long num)
+{
+ if (register_my_resource(list, base, num, NULL) != 0)
+ return -EBUSY;
+ release_my_resource(list, base, num);
+ return 0;
+}
+
+int check_io_region(u_long base, u_long num)
+{
+ return check_my_resource(&io_list, base, num);
+}
+void request_io_region(u_long base, u_long num, char *name)
+{
+ register_my_resource(&io_list, base, num, name);
+}
+void release_io_region(u_long base, u_long num)
+{
+ release_my_resource(&io_list, base, num);
+}
+#ifdef CONFIG_PROC_FS
+int proc_read_io(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ resource_entry_t *r;
+ u_long flags;
+ char *p = buf;
+
+ spin_lock_irqsave(&rsrc_lock, flags);
+ for (r = io_list.next; r; r = r->next)
+ p += sprintf(p, "%04lx-%04lx : %s\n", r->base,
+ r->base+r->num-1, r->name);
+ spin_unlock_irqrestore(&rsrc_lock, flags);
+ return (p - buf);
+}
+#endif
+
+
+/*======================================================================
+
+ These manage the internal databases of available resources.
+
+======================================================================*/
+
+static int add_interval(resource_map_t *map, u_long base, u_long num)
+{
+ resource_map_t *p, *q;
+
+ for (p = map; ; p = p->next) {
+ if ((p != map) && (p->base+p->num-1 >= base))
+ return -1;
+ if ((p->next == map) || (p->next->base > base+num-1))
+ break;
+ }
+ q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+ q->base = base; q->num = num;
+ q->next = p->next; p->next = q;
+ return 0;
+} /* add_interval */
+
+/*====================================================================*/
+
+static int sub_interval(resource_map_t *map, u_long base, u_long num)
+{
+ resource_map_t *p, *q;
+
+ for (p = map; ; p = q) {
+ q = p->next;
+ if (q == map)
+ break;
+ if ((q->base+q->num > base) && (base+num > q->base)) {
+ if (q->base >= base) {
+ if (q->base+q->num <= base+num) {
+ /* Delete whole block */
+ p->next = q->next;
+ kfree(q);
+ /* don't advance the pointer yet */
+ q = p;
+ } else {
+ /* Cut off bit from the front */
+ q->num = q->base + q->num - base - num;
+ q->base = base + num;
+ }
+ } else if (q->base+q->num <= base+num) {
+ /* Cut off bit from the end */
+ q->num = base - q->base;
+ } else {
+ /* Split the block into two pieces */
+ p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+ p->base = base+num;
+ p->num = q->base+q->num - p->base;
+ q->num = base - q->base;
+ p->next = q->next ; q->next = p;
+ }
+ }
+ }
+ return 0;
+} /* sub_interval */
+
+/*======================================================================
+
+ These routines examine a region of IO or memory addresses to
+ determine what ranges might be genuinely available.
+
+======================================================================*/
+
+#ifdef CONFIG_ISA
+static void do_io_probe(ioaddr_t base, ioaddr_t num)
+{
+
+ ioaddr_t i, j, bad, any;
+ u_char *b, hole, most;
+
+ printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
+ base, base+num-1);
+
+ /* First, what does a floating port look like? */
+ b = kmalloc(256, GFP_KERNEL);
+ memset(b, 0, 256);
+ for (i = base, most = 0; i < base+num; i += 8) {
+ if (check_region(i, 8) || check_io_region(i, 8))
+ continue;
+ hole = inb(i);
+ for (j = 1; j < 8; j++)
+ if (inb(i+j) != hole) break;
+ if ((j == 8) && (++b[hole] > b[most]))
+ most = hole;
+ if (b[most] == 127) break;
+ }
+ kfree(b);
+
+ bad = any = 0;
+ for (i = base; i < base+num; i += 8) {
+ if (check_region(i, 8) || check_io_region(i, 8))
+ continue;
+ for (j = 0; j < 8; j++)
+ if (inb(i+j) != most) break;
+ if (j < 8) {
+ if (!any)
+ printk(" excluding");
+ if (!bad)
+ bad = any = i;
+ } else {
+ if (bad) {
+ sub_interval(&io_db, bad, i-bad);
+ printk(" %#04x-%#04x", bad, i-1);
+ bad = 0;
+ }
+ }
+ }
+ if (bad) {
+ if ((num > 16) && (bad == base) && (i == base+num)) {
+ printk(" nothing: probe failed.\n");
+ return;
+ } else {
+ sub_interval(&io_db, bad, i-bad);
+ printk(" %#04x-%#04x", bad, i-1);
+ }
+ }
+
+ printk(any ? "\n" : " clean.\n");
+}
+#endif
+
+/*======================================================================
+
+ The memory probe. If the memory list includes a 64K-aligned block
+ below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+ least mem_limit free space, we quit.
+
+======================================================================*/
+
+static int do_mem_probe(u_long base, u_long num,
+ int (*is_valid)(u_long), int (*do_cksum)(u_long))
+{
+ u_long i, j, bad, fail, step;
+
+ printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
+ base, base+num-1);
+
+ bad = fail = 0;
+ step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+ for (i = base; i < base+num; i = j + step) {
+ if (!fail) {
+ for (j = i; j < base+num; j += step)
+ if ((check_mem_region(j, step) == 0) && is_valid(j))
+ break;
+ fail = ((i == base) && (j == base+num));
+ }
+ if (fail) {
+ for (j = i; j < base+num; j += 2*step)
+ if ((check_mem_region(j, 2*step) == 0) &&
+ do_cksum(j) && do_cksum(j+step))
+ break;
+ }
+ if (i != j) {
+ if (!bad) printk(" excluding");
+ printk(" %#05lx-%#05lx", i, j-1);
+ sub_interval(&mem_db, i, j-i);
+ bad += j-i;
+ }
+ }
+ printk(bad ? "\n" : " clean.\n");
+
+ return (num - bad);
+}
+
+#ifdef CONFIG_ISA
+
+static u_long inv_probe(int (*is_valid)(u_long),
+ int (*do_cksum)(u_long),
+ resource_map_t *m)
+{
+ u_long ok;
+ if (m == &mem_db)
+ return 0;
+ ok = inv_probe(is_valid, do_cksum, m->next);
+ if (ok) {
+ if (m->base >= 0x100000)
+ sub_interval(&mem_db, m->base, m->num);
+ return ok;
+ }
+ if (m->base < 0x100000)
+ return 0;
+ return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+}
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+ int force_low)
+{
+ resource_map_t *m, *n;
+ static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+ static int hi = 0, lo = 0;
+ u_long b, i, ok = 0;
+
+ if (!probe_mem) return;
+ /* We do up to four passes through the list */
+ if (!force_low) {
+ if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+ return;
+ printk(KERN_NOTICE "cs: warning: no high memory space "
+ "available!\n");
+ }
+ if (lo++) return;
+ for (m = mem_db.next; m != &mem_db; m = n) {
+ n = m->next;
+ /* Only probe < 1 MB */
+ if (m->base >= 0x100000) continue;
+ if ((m->base | m->num) & 0xffff) {
+ ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+ continue;
+ }
+ /* Special probe for 64K-aligned block */
+ for (i = 0; i < 4; i++) {
+ b = order[i] << 12;
+ if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
+ if (ok >= mem_limit)
+ sub_interval(&mem_db, b, 0x10000);
+ else
+ ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+ }
+ }
+ }
+}
+
+#else /* CONFIG_ISA */
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+ int force_low)
+{
+ resource_map_t *m;
+ static int done = 0;
+
+ if (!probe_mem || done++)
+ return;
+ for (m = mem_db.next; m != &mem_db; m = m->next)
+ if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+ return;
+}
+
+#endif /* CONFIG_ISA */
+
+/*======================================================================
+
+ These find ranges of I/O ports or memory addresses that are not
+ currently allocated by other devices.
+
+======================================================================*/
+
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name)
+{
+ ioaddr_t align;
+ resource_map_t *m;
+
+ if (*base != 0) {
+ for (m = io_db.next; m != &io_db; m = m->next) {
+ if ((*base >= m->base) && (*base+num <= m->base+m->num)) {
+ if (check_region(*base, num) ||
+ check_io_region(*base, num)) {
+ return -1;
+ } else {
+ request_region(*base, num, name);
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
+
+ for (align = 1; align < num; align *= 2) ;
+
+ for (m = io_db.next; m != &io_db; m = m->next) {
+ for (*base = (m->base + align - 1) & (~(align-1));
+ *base+align <= m->base + m->num;
+ *base += align)
+ if ((check_region(*base, num) == 0) &&
+ (check_io_region(*base, num) == 0)) {
+ request_region(*base, num, name);
+ return 0;
+ }
+ }
+ return -1;
+} /* find_io_region */
+
+int find_mem_region(u_long *base, u_long num, char *name,
+ u_long align, int force_low)
+{
+ resource_map_t *m;
+
+ if (*base != 0) {
+ for (m = mem_db.next; m != &mem_db; m = m->next) {
+ if ((*base >= m->base) && (*base+num <= m->base+m->num))
+ if (check_mem_region(*base, num) == 0) {
+ request_mem_region(*base, num, name);
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ while (1) {
+ for (m = mem_db.next; m != &mem_db; m = m->next) {
+ /* first pass >1MB, second pass <1MB */
+ if ((force_low != 0) ^ (m->base < 0x100000)) continue;
+ for (*base = (m->base + align - 1) & (~(align-1));
+ *base+num <= m->base+m->num; *base += align)
+ if (check_mem_region(*base, num) == 0) {
+ request_mem_region(*base, num, name);
+ return 0;
+ }
+ }
+ if (force_low) break;
+ force_low++;
+ }
+ return -1;
+} /* find_mem_region */
+
+/*======================================================================
+
+ This checks to see if an interrupt is available, with support
+ for interrupt sharing. We don't support reserving interrupts
+ yet. If the interrupt is available, we allocate it.
+
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void fake_irq(int i, void *d, struct pt_regs *r) { }
+static inline int check_irq(int irq)
+{
+ if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
+ return -1;
+ free_irq(irq, NULL);
+ return 0;
+}
+
+int try_irq(u_int Attributes, int irq, int specific)
+{
+ irq_info_t *info = &irq_table[irq];
+ if (info->Attributes & RES_ALLOCATED) {
+ switch (Attributes & IRQ_TYPE) {
+ case IRQ_TYPE_EXCLUSIVE:
+ return CS_IN_USE;
+ case IRQ_TYPE_TIME:
+ if ((info->Attributes & RES_IRQ_TYPE)
+ != RES_IRQ_TYPE_TIME)
+ return CS_IN_USE;
+ if (Attributes & IRQ_FIRST_SHARED)
+ return CS_BAD_ATTRIBUTE;
+ info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+ info->time_share++;
+ break;
+ case IRQ_TYPE_DYNAMIC_SHARING:
+ if ((info->Attributes & RES_IRQ_TYPE)
+ != RES_IRQ_TYPE_DYNAMIC)
+ return CS_IN_USE;
+ if (Attributes & IRQ_FIRST_SHARED)
+ return CS_BAD_ATTRIBUTE;
+ info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+ info->dyn_share++;
+ break;
+ }
+ } else {
+ if ((info->Attributes & RES_RESERVED) && !specific)
+ return CS_IN_USE;
+ if (check_irq(irq) != 0)
+ return CS_IN_USE;
+ switch (Attributes & IRQ_TYPE) {
+ case IRQ_TYPE_EXCLUSIVE:
+ info->Attributes |= RES_ALLOCATED;
+ break;
+ case IRQ_TYPE_TIME:
+ if (!(Attributes & IRQ_FIRST_SHARED))
+ return CS_BAD_ATTRIBUTE;
+ info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+ info->time_share = 1;
+ break;
+ case IRQ_TYPE_DYNAMIC_SHARING:
+ if (!(Attributes & IRQ_FIRST_SHARED))
+ return CS_BAD_ATTRIBUTE;
+ info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+ info->dyn_share = 1;
+ break;
+ }
+ }
+ return 0;
+} /* try_irq */
+
+#endif
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+void undo_irq(u_int Attributes, int irq)
+{
+ irq_info_t *info;
+
+ info = &irq_table[irq];
+ switch (Attributes & IRQ_TYPE) {
+ case IRQ_TYPE_EXCLUSIVE:
+ info->Attributes &= RES_RESERVED;
+ break;
+ case IRQ_TYPE_TIME:
+ info->time_share--;
+ if (info->time_share == 0)
+ info->Attributes &= RES_RESERVED;
+ break;
+ case IRQ_TYPE_DYNAMIC_SHARING:
+ info->dyn_share--;
+ if (info->dyn_share == 0)
+ info->Attributes &= RES_RESERVED;
+ break;
+ }
+}
+
+#endif
+
+/*======================================================================
+
+ The various adjust_* calls form the external interface to the
+ resource database.
+
+======================================================================*/
+
+static int adjust_memory(adjust_t *adj)
+{
+ u_long base, num;
+ int i;
+
+ base = adj->resource.memory.Base;
+ num = adj->resource.memory.Size;
+ if ((num == 0) || (base+num-1 < base))
+ return CS_BAD_SIZE;
+
+ switch (adj->Action) {
+ case ADD_MANAGED_RESOURCE:
+ if (add_interval(&mem_db, base, num) != 0)
+ return CS_IN_USE;
+ break;
+ case REMOVE_MANAGED_RESOURCE:
+ sub_interval(&mem_db, base, num);
+ for (i = 0; i < sockets; i++) {
+ release_cis_mem(socket_table[i]);
+#ifdef CONFIG_CARDBUS
+ cb_release_cis_mem(socket_table[i]);
+#endif
+ }
+ break;
+ default:
+ return CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+
+ return CS_SUCCESS;
+} /* adjust_mem */
+
+/*====================================================================*/
+
+static int adjust_io(adjust_t *adj)
+{
+ int base, num;
+
+ base = adj->resource.io.BasePort;
+ num = adj->resource.io.NumPorts;
+ if ((base < 0) || (base > 0xffff))
+ return CS_BAD_BASE;
+ if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
+ return CS_BAD_SIZE;
+
+ switch (adj->Action) {
+ case ADD_MANAGED_RESOURCE:
+ if (add_interval(&io_db, base, num) != 0)
+ return CS_IN_USE;
+#ifdef CONFIG_ISA
+ if (probe_io)
+ do_io_probe(base, num);
+#endif
+ break;
+ case REMOVE_MANAGED_RESOURCE:
+ sub_interval(&io_db, base, num);
+ break;
+ default:
+ return CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+
+ return CS_SUCCESS;
+} /* adjust_io */
+
+/*====================================================================*/
+
+static int adjust_irq(adjust_t *adj)
+{
+#ifdef CONFIG_ISA
+ int irq;
+ irq_info_t *info;
+
+ irq = adj->resource.irq.IRQ;
+ if ((irq < 0) || (irq > 15))
+ return CS_BAD_IRQ;
+ info = &irq_table[irq];
+
+ switch (adj->Action) {
+ case ADD_MANAGED_RESOURCE:
+ if (info->Attributes & RES_REMOVED)
+ info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
+ else
+ if (adj->Attributes & RES_ALLOCATED)
+ return CS_IN_USE;
+ if (adj->Attributes & RES_RESERVED)
+ info->Attributes |= RES_RESERVED;
+ else
+ info->Attributes &= ~RES_RESERVED;
+ break;
+ case REMOVE_MANAGED_RESOURCE:
+ if (info->Attributes & RES_REMOVED)
+ return 0;
+ if (info->Attributes & RES_ALLOCATED)
+ return CS_IN_USE;
+ info->Attributes |= RES_ALLOCATED|RES_REMOVED;
+ info->Attributes &= ~RES_RESERVED;
+ break;
+ default:
+ return CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+#endif
+ return CS_SUCCESS;
+} /* adjust_irq */
+
+/*====================================================================*/
+
+int adjust_resource_info(client_handle_t handle, adjust_t *adj)
+{
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+
+ switch (adj->Resource) {
+ case RES_MEMORY_RANGE:
+ return adjust_memory(adj);
+ break;
+ case RES_IO_RANGE:
+ return adjust_io(adj);
+ break;
+ case RES_IRQ:
+ return adjust_irq(adj);
+ break;
+ }
+ return CS_UNSUPPORTED_FUNCTION;
+} /* adjust_resource_info */
+
+/*====================================================================*/
+
+void release_resource_db(void)
+{
+ resource_map_t *p, *q;
+ resource_entry_t *u, *v;
+
+ for (p = mem_db.next; p != &mem_db; p = q) {
+ q = p->next;
+ kfree(p);
+ }
+ for (p = io_db.next; p != &io_db; p = q) {
+ q = p->next;
+ kfree(p);
+ }
+ for (u = io_list.next; u; u = v) {
+ v = u->next;
+ kfree(u);
+ }
+#ifndef HAVE_MEMRESERVE
+ for (u = mem_list.next; u; u = v) {
+ v = u->next;
+ kfree(u);
+ }
+#endif
+}
--- /dev/null
+/*
+ * rsrc_mgr.h 1.18 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _RSRC_MGR_H
+#define _RSRC_MGR_H
+
+#ifdef __BEOS__
+int check_resource(int type, u_long base, u_long num);
+int register_resource(int type, u_long base, u_long num);
+int release_resource(int type, u_long base, u_long num);
+#endif
+
+#endif /* _RSRC_MGR_H */
--- /dev/null
+/*
+ * smc34c90.h 1.6 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SMC34C90_H
+#define _LINUX_SMC34C90_H
+
+#ifndef PCI_VENDOR_ID_SMC
+#define PCI_VENDOR_ID_SMC 0x10b3
+#endif
+
+#ifndef PCI_DEVICE_ID_SMC_34C90
+#define PCI_DEVICE_ID_SMC_34C90 0xb106
+#endif
+
+/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */
+
+/* EEPROM Information Register */
+#define SMC34C90_EEINFO 0x0088
+#define SMC34C90_EEINFO_ONE_SOCKET 0x0001
+#define SMC34C90_EEINFO_5V_ONLY 0x0002
+#define SMC34C90_EEINFO_ISA_IRQ 0x0004
+#define SMC34C90_EEINFO_ZV_PORT 0x0008
+#define SMC34C90_EEINFO_RING 0x0010
+#define SMC34C90_EEINFO_LED 0x0020
+
+#endif /* _LINUX_SMC34C90_H */
--- /dev/null
+/*======================================================================
+
+ Device driver for Databook TCIC-2 PCMCIA controller
+
+ tcic.c 1.104 1999/08/28 04:01:46
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include "tcic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"tcic.c 1.104 1999/08/28 04:01:46 (David Hinds)";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The base port address of the TCIC-2 chip */
+static int tcic_base = TCIC_BASE;
+
+/* Specify a socket number to ignore */
+static int ignore = -1;
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+/* Delay for card status double-checking */
+static int poll_quick = HZ/20;
+
+/* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */
+static int cycle_time = 70;
+
+MODULE_PARM(tcic_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(poll_quick, "i");
+MODULE_PARM(cycle_time, "i");
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs);
+static void tcic_timer(u_long data);
+static int tcic_service(u_int sock, u_int cmd, void *arg);
+
+typedef struct socket_info_t {
+ u_short psock;
+ void (*handler)(void *info, u_int events);
+ void *info;
+ u_char last_sstat;
+ u_char id;
+} socket_info_t;
+
+static struct timer_list poll_timer;
+static int tcic_timer_pending = 0;
+
+static int sockets;
+static socket_info_t socket_table[2];
+
+static socket_cap_t tcic_cap = {
+ /* only 16-bit cards, memory windows must be size-aligned */
+ SS_CAP_PCCARD | SS_CAP_MEM_ALIGN,
+ 0x4cf8, /* irq 14, 11, 10, 7, 6, 5, 4, 3 */
+ 0x1000, /* 4K minimum window size */
+ 0, 0 /* No PCI or CardBus support */
+};
+
+/*====================================================================*/
+
+/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
+ to map to irq 11, but is coded as 0 or 1 in the irq registers. */
+#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
+
+#ifdef PCMCIA_DEBUG_X
+static u_char tcic_getb(u_char reg)
+{
+ u_char val = inb(tcic_base+reg);
+ printk(KERN_DEBUG "tcic_getb(%#x) = %#x\n", tcic_base+reg, val);
+ return val;
+}
+
+static u_short tcic_getw(u_char reg)
+{
+ u_short val = inw(tcic_base+reg);
+ printk(KERN_DEBUG "tcic_getw(%#x) = %#x\n", tcic_base+reg, val);
+ return val;
+}
+
+static void tcic_setb(u_char reg, u_char data)
+{
+ printk(KERN_DEBUG "tcic_setb(%#x, %#x)\n", tcic_base+reg, data);
+ outb(data, tcic_base+reg);
+}
+
+static void tcic_setw(u_char reg, u_short data)
+{
+ printk(KERN_DEBUG "tcic_setw(%#x, %#x)\n", tcic_base+reg, data);
+ outw(data, tcic_base+reg);
+}
+#else
+#define tcic_getb(reg) inb(tcic_base+reg)
+#define tcic_getw(reg) inw(tcic_base+reg)
+#define tcic_setb(reg, data) outb(data, tcic_base+reg)
+#define tcic_setw(reg, data) outw(data, tcic_base+reg)
+#endif
+
+static void tcic_setl(u_char reg, u_int data)
+{
+#ifdef PCMCIA_DEBUG_X
+ printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
+#endif
+ outw(data & 0xffff, tcic_base+reg);
+ outw(data >> 16, tcic_base+reg+2);
+}
+
+static u_char tcic_aux_getb(u_short reg)
+{
+ u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(TCIC_MODE, mode);
+ return tcic_getb(TCIC_AUX);
+}
+
+static void tcic_aux_setb(u_short reg, u_char data)
+{
+ u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(TCIC_MODE, mode);
+ tcic_setb(TCIC_AUX, data);
+}
+
+static u_short tcic_aux_getw(u_short reg)
+{
+ u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(TCIC_MODE, mode);
+ return tcic_getw(TCIC_AUX);
+}
+
+static void tcic_aux_setw(u_short reg, u_short data)
+{
+ u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(TCIC_MODE, mode);
+ tcic_setw(TCIC_AUX, data);
+}
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+ if (ns < 14)
+ return 0;
+ else
+ return 2*(ns-14)/cycle_time;
+}
+
+static int to_ns(int cycles)
+{
+ return (cycles*cycle_time)/2 + 14;
+}
+
+/*====================================================================*/
+
+static volatile u_int irq_hits;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+ irq_hits++;
+}
+
+static u_int try_irq(int irq)
+{
+ u_short cfg;
+
+ irq_hits = 0;
+ if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0)
+ return -1;
+ mdelay(10);
+ if (irq_hits) {
+ free_irq(irq, NULL);
+ return -1;
+ }
+
+ /* Generate one interrupt */
+ cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
+ tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
+ tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
+ tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
+
+ udelay(1000);
+ free_irq(irq, NULL);
+
+ /* Turn off interrupts */
+ tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
+ while (tcic_getb(TCIC_ICSR))
+ tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
+ tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
+
+ return (irq_hits != 1);
+}
+
+static u_int irq_scan(u_int mask0)
+{
+ u_int mask1;
+ int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+ /* Don't probe level-triggered interrupts -- reserved for PCI */
+ int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
+ if (level_mask)
+ mask0 &= ~level_mask;
+#endif
+
+ mask1 = 0;
+ if (do_scan) {
+ for (i = 0; i < 16; i++)
+ if ((mask0 & (1 << i)) && (try_irq(i) == 0))
+ mask1 |= (1 << i);
+ for (i = 0; i < 16; i++)
+ if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
+ mask1 ^= (1 << i);
+ }
+ }
+
+ if (mask1) {
+ printk("scanned");
+ } else {
+ /* Fallback: just find interrupts that aren't in use */
+ for (i = 0; i < 16; i++)
+ if ((mask0 & (1 << i)) &&
+ (request_irq(i, irq_count, 0, "x", NULL) == 0)) {
+ mask1 |= (1 << i);
+ free_irq(i, NULL);
+ }
+ printk("default");
+ }
+
+ printk(") = ");
+ for (i = 0; i < 16; i++)
+ if (mask1 & (1<<i))
+ printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+ printk(" ");
+
+ return mask1;
+}
+
+/*======================================================================
+
+ See if a card is present, powered up, in IO mode, and already
+ bound to a (non-PCMCIA) Linux driver.
+
+ We make an exception for cards that look like serial devices.
+
+======================================================================*/
+
+static int is_active(int s)
+{
+ u_short scf1, ioctl, base, num;
+ u_char pwr, sstat;
+ u_int addr;
+
+ tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+ | TCIC_ADDR_INDREG | TCIC_SCF1(s));
+ scf1 = tcic_getw(TCIC_DATA);
+ pwr = tcic_getb(TCIC_PWR);
+ sstat = tcic_getb(TCIC_SSTAT);
+ addr = TCIC_IWIN(s, 0);
+ tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+ base = tcic_getw(TCIC_DATA);
+ tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+ ioctl = tcic_getw(TCIC_DATA);
+
+ if (ioctl & TCIC_ICTL_TINY)
+ num = 1;
+ else {
+ num = (base ^ (base-1));
+ base = base & (base-1);
+ }
+
+ if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
+ (scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
+ (check_region(base, num) != 0) && ((base & 0xfeef) != 0x02e8))
+ return 1;
+ else
+ return 0;
+}
+
+/*======================================================================
+
+ This returns the revision code for the specified socket.
+
+======================================================================*/
+
+static int get_tcic_id(void)
+{
+ u_short id;
+
+ tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
+ id = tcic_aux_getw(TCIC_AUX_ILOCK);
+ id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+ tcic_aux_setw(TCIC_AUX_TEST, 0);
+ return id;
+}
+
+/*====================================================================*/
+
+int tcic_init(void)
+{
+ int i, sock;
+ u_int mask, scan;
+
+ DEBUG(0, "%s\n", version);
+
+ printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
+ sock = 0;
+
+ if (check_region(tcic_base, 16) == 0) {
+ tcic_setw(TCIC_ADDR, 0);
+ if (tcic_getw(TCIC_ADDR) == 0) {
+ tcic_setw(TCIC_ADDR, 0xc3a5);
+ if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+ }
+ if (sock == 0) {
+ /* See if resetting the controller does any good */
+ tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
+ tcic_setb(TCIC_SCTRL, 0);
+ tcic_setw(TCIC_ADDR, 0);
+ if (tcic_getw(TCIC_ADDR) == 0) {
+ tcic_setw(TCIC_ADDR, 0xc3a5);
+ if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+ }
+ }
+ } else
+ printk("could not allocate ports, ");
+
+ if (sock == 0) {
+ printk("not found.\n");
+ return -ENODEV;
+ }
+
+ request_region(tcic_base, 16, "tcic-2");
+
+ sockets = 0;
+ for (i = 0; i < sock; i++) {
+ if ((i == ignore) || is_active(i)) continue;
+ socket_table[sockets].psock = i;
+ socket_table[sockets].handler = NULL;
+ socket_table[sockets].info = NULL;
+ socket_table[sockets].id = get_tcic_id();
+ sockets++;
+ }
+
+ switch (socket_table[0].id) {
+ case TCIC_ID_DB86082:
+ printk("DB86082"); break;
+ case TCIC_ID_DB86082A:
+ printk("DB86082A"); break;
+ case TCIC_ID_DB86084:
+ printk("DB86084"); break;
+ case TCIC_ID_DB86084A:
+ printk("DB86084A"); break;
+ case TCIC_ID_DB86072:
+ printk("DB86072"); break;
+ case TCIC_ID_DB86184:
+ printk("DB86184"); break;
+ case TCIC_ID_DB86082B:
+ printk("DB86082B"); break;
+ default:
+ printk("Unknown ID 0x%02x", socket_table[0].id);
+ }
+
+ /* Set up polling */
+ poll_timer.function = &tcic_timer;
+ poll_timer.data = 0;
+ poll_timer.prev = poll_timer.next = NULL;
+
+ /* Build interrupt mask */
+ printk(", %d sockets\n" KERN_INFO " irq list (", sockets);
+ if (irq_list[0] == -1)
+ mask = irq_mask;
+ else
+ for (i = mask = 0; i < 16; i++)
+ mask |= (1<<irq_list[i]);
+ mask &= tcic_cap.irq_mask;
+
+ /* Scan interrupts */
+ mask = irq_scan(mask);
+ tcic_cap.irq_mask = mask;
+
+ /* Check for only two interrupts available */
+ scan = (mask & (mask-1));
+ if (((scan & (scan-1)) == 0) && (poll_interval == 0))
+ poll_interval = HZ;
+
+ if (poll_interval == 0) {
+ /* Avoid irq 12 unless it is explicitly requested */
+ u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+ for (i = 15; i > 0; i--)
+ if ((cs_mask & (1 << i)) &&
+ (request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0))
+ break;
+ cs_irq = i;
+ if (cs_irq == 0) poll_interval = HZ;
+ }
+
+ if (tcic_cap.irq_mask & (1 << 11))
+ printk("sktirq is irq 11, ");
+ if (cs_irq != 0)
+ printk("status change on irq %d\n", cs_irq);
+ else
+ printk("polled status, interval = %d ms\n",
+ poll_interval * 1000 / HZ);
+
+ for (i = 0; i < sockets; i++) {
+ tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
+ socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
+ }
+
+ /* jump start interrupt handler, if needed */
+ tcic_interrupt(0, NULL, NULL);
+
+ if (register_ss_entry(sockets, &tcic_service) != 0) {
+ printk(KERN_NOTICE "tcic: register_ss_entry() failed\n");
+ release_region(tcic_base, 16);
+ if (cs_irq != 0)
+ free_irq(cs_irq, NULL);
+ return -ENODEV;
+ }
+
+ return 0;
+
+} /* tcic_init */
+
+/*====================================================================*/
+
+static void tcic_finish(void)
+{
+ u_long flags;
+ unregister_ss_entry(&tcic_service);
+ save_flags(flags);
+ cli();
+ if (cs_irq != 0) {
+ tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
+ free_irq(cs_irq, NULL);
+ }
+ if (tcic_timer_pending)
+ del_timer(&poll_timer);
+ restore_flags(flags);
+ release_region(tcic_base, 16);
+} /* tcic_finish */
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ int i, quick = 0;
+ u_char latch, sstat;
+ u_short psock;
+ u_int events;
+ static volatile int active = 0;
+
+ if (active) {
+ printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
+ return;
+ } else
+ active = 1;
+
+ DEBUG(2, "tcic: tcic_interrupt()\n");
+
+ for (i = 0; i < sockets; i++) {
+ psock = socket_table[i].psock;
+ tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+ | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+ sstat = tcic_getb(TCIC_SSTAT);
+ latch = sstat ^ socket_table[psock].last_sstat;
+ socket_table[i].last_sstat = sstat;
+ if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
+ tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
+ quick = 1;
+ }
+ if ((latch == 0) || (socket_table[psock].handler == NULL))
+ continue;
+ events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+ events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+ if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+ events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+ } else {
+ events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
+ events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+ events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+ }
+ if (events)
+ socket_table[i].handler(socket_table[i].info, events);
+ }
+
+ /* Schedule next poll, if needed */
+ if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
+ poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
+ add_timer(&poll_timer);
+ tcic_timer_pending = 1;
+ }
+ active = 0;
+
+ DEBUG(2, "tcic: interrupt done\n");
+
+} /* tcic_interrupt */
+
+static void tcic_timer(u_long data)
+{
+ DEBUG(2, "tcic: tcic_timer()\n");
+ tcic_timer_pending = 0;
+ tcic_interrupt(0, NULL, NULL);
+} /* tcic_timer */
+
+/*====================================================================*/
+
+static int tcic_register_callback(u_short lsock, ss_callback_t *call)
+{
+ if (call == NULL) {
+ socket_table[lsock].handler = NULL;
+ MOD_DEC_USE_COUNT;
+ } else {
+ MOD_INC_USE_COUNT;
+ socket_table[lsock].handler = call->handler;
+ socket_table[lsock].info = call->info;
+ }
+ return 0;
+} /* tcic_register_callback */
+
+/*====================================================================*/
+
+static int tcic_get_status(u_short lsock, u_int *value)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_char reg;
+
+ tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+ | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+ reg = tcic_getb(TCIC_SSTAT);
+ *value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+ *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+ if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+ *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+ } else {
+ *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
+ *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+ *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+ }
+ reg = tcic_getb(TCIC_PWR);
+ if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
+ *value |= SS_POWERON;
+ DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value);
+ return 0;
+} /* tcic_get_status */
+
+/*====================================================================*/
+
+static int tcic_inquire_socket(u_short lsock, socket_cap_t *cap)
+{
+ *cap = tcic_cap;
+ return 0;
+} /* tcic_inquire_socket */
+
+/*====================================================================*/
+
+static int tcic_get_socket(u_short lsock, socket_state_t *state)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_char reg;
+ u_short scf1, scf2;
+
+ tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+ | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+ scf1 = tcic_getw(TCIC_DATA);
+ state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0;
+ state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0;
+ state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0;
+ if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA)
+ state->flags |= SS_OUTPUT_ENA;
+ state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK;
+ if (state->io_irq == 1) state->io_irq = 11;
+
+ reg = tcic_getb(TCIC_PWR);
+ state->Vcc = state->Vpp = 0;
+ if (reg & TCIC_PWR_VCC(psock)) {
+ if (reg & TCIC_PWR_VPP(psock))
+ state->Vcc = 50;
+ else
+ state->Vcc = state->Vpp = 50;
+ } else {
+ if (reg & TCIC_PWR_VPP(psock)) {
+ state->Vcc = 50;
+ state->Vpp = 120;
+ }
+ }
+ reg = tcic_aux_getb(TCIC_AUX_ILOCK);
+ state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0;
+
+ /* Card status change interrupt mask */
+ tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+ scf2 = tcic_getw(TCIC_DATA);
+ state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT;
+ if (state->flags & SS_IOCARD) {
+ state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG;
+ } else {
+ state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD;
+ state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN;
+ state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY;
+ }
+
+ DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+ return 0;
+} /* tcic_get_socket */
+
+/*====================================================================*/
+
+static int tcic_set_socket(u_short lsock, socket_state_t *state)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_char reg;
+ u_short scf1, scf2;
+
+ DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+ tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
+
+ reg = tcic_getb(TCIC_PWR);
+ reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
+
+ if (state->Vcc == 50) {
+ switch (state->Vpp) {
+ case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
+ case 50: reg |= TCIC_PWR_VCC(psock); break;
+ case 120: reg |= TCIC_PWR_VPP(psock); break;
+ default: return -EINVAL;
+ }
+ } else if (state->Vcc != 0)
+ return -EINVAL;
+
+ if (reg != tcic_getb(TCIC_PWR))
+ tcic_setb(TCIC_PWR, reg);
+
+ reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
+ if (state->flags & SS_OUTPUT_ENA) {
+ tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
+ reg |= TCIC_ILOCK_CRESENA;
+ } else
+ tcic_setb(TCIC_SCTRL, 0);
+ if (state->flags & SS_RESET)
+ reg |= TCIC_ILOCK_CRESET;
+ tcic_aux_setb(TCIC_AUX_ILOCK, reg);
+
+ tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
+ scf1 = TCIC_SCF1_FINPACK;
+ scf1 |= TCIC_IRQ(state->io_irq);
+ if (state->flags & SS_IOCARD) {
+ scf1 |= TCIC_SCF1_IOSTS;
+ if (state->flags & SS_SPKR_ENA)
+ scf1 |= TCIC_SCF1_SPKR;
+ if (state->flags & SS_DMA_MODE)
+ scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
+ }
+ tcic_setw(TCIC_DATA, scf1);
+
+ /* Some general setup stuff, and configure status interrupt */
+ reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
+ tcic_aux_setb(TCIC_AUX_WCTL, reg);
+ tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
+ TCIC_IRQ(cs_irq));
+
+ /* Card status change interrupt mask */
+ tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+ scf2 = TCIC_SCF2_MALL;
+ if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
+ if (state->flags & SS_IOCARD) {
+ if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
+ } else {
+ if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
+ if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
+ if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
+ }
+ tcic_setw(TCIC_DATA, scf2);
+ /* For the ISA bus, the irq should be active-high totem-pole */
+ tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
+
+ return 0;
+} /* tcic_set_socket */
+
+/*====================================================================*/
+
+static int tcic_get_io_map(u_short lsock, struct pccard_io_map *io)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_short base, ioctl;
+ u_int addr;
+
+ if (io->map > 1) return -EINVAL;
+ tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+ addr = TCIC_IWIN(psock, io->map);
+ tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+ base = tcic_getw(TCIC_DATA);
+ tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+ ioctl = tcic_getw(TCIC_DATA);
+
+ if (ioctl & TCIC_ICTL_TINY)
+ io->start = io->stop = base;
+ else {
+ io->start = base & (base-1);
+ io->stop = io->start + (base ^ (base-1));
+ }
+ io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK);
+ io->flags = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0;
+ switch (ioctl & TCIC_ICTL_BW_MASK) {
+ case TCIC_ICTL_BW_DYN:
+ io->flags |= MAP_AUTOSZ; break;
+ case TCIC_ICTL_BW_16:
+ io->flags |= MAP_16BIT; break;
+ default:
+ break;
+ }
+ DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+ "%#4.4x-%#4.4x\n", lsock, io->map, io->flags,
+ io->speed, io->start, io->stop);
+ return 0;
+} /* tcic_get_io_map */
+
+/*====================================================================*/
+
+static int tcic_set_io_map(u_short lsock, struct pccard_io_map *io)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_int addr;
+ u_short base, len, ioctl;
+
+ DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, "
+ "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+ io->speed, io->start, io->stop);
+ if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+ (io->stop < io->start)) return -EINVAL;
+ tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+ addr = TCIC_IWIN(psock, io->map);
+
+ base = io->start; len = io->stop - io->start;
+ /* Check to see that len+1 is power of two, etc */
+ if ((len & (len+1)) || (base & len)) return -EINVAL;
+ base |= (len+1)>>1;
+ tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+ tcic_setw(TCIC_DATA, base);
+
+ ioctl = (psock << TCIC_ICTL_SS_SHFT);
+ ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
+ ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
+ ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
+ if (!(io->flags & MAP_AUTOSZ)) {
+ ioctl |= TCIC_ICTL_QUIET;
+ ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
+ }
+ tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+ tcic_setw(TCIC_DATA, ioctl);
+
+ return 0;
+} /* tcic_set_io_map */
+
+/*====================================================================*/
+
+static int tcic_get_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_short addr, ctl;
+ u_long base, mmap;
+
+ if (mem->map > 3) return -EINVAL;
+ tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+ addr = TCIC_MWIN(psock, mem->map);
+
+ tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+ base = tcic_getw(TCIC_DATA);
+ if (base & TCIC_MBASE_4K_BIT) {
+ mem->sys_start = base & TCIC_MBASE_HA_MASK;
+ mem->sys_stop = mem->sys_start;
+ } else {
+ base &= TCIC_MBASE_HA_MASK;
+ mem->sys_start = (base & (base-1));
+ mem->sys_stop = mem->sys_start + (base ^ (base-1));
+ }
+ mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT;
+ mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff;
+
+ tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+ mmap = tcic_getw(TCIC_DATA);
+ mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0;
+ mmap &= TCIC_MMAP_CA_MASK;
+ mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT);
+ mem->card_start &= 0x3ffffff;
+
+ tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+ ctl = tcic_getw(TCIC_DATA);
+ mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0;
+ mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT;
+ mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0;
+ mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK);
+
+ DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, "
+ "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags,
+ mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+ return 0;
+} /* tcic_get_mem_map */
+
+/*====================================================================*/
+
+static int tcic_set_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+ u_short psock = socket_table[lsock].psock;
+ u_short addr, ctl;
+ u_long base, len, mmap;
+
+ DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, "
+ "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+ mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+ if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
+ (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) ||
+ (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+ return -EINVAL;
+ tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+ addr = TCIC_MWIN(psock, mem->map);
+
+ base = mem->sys_start; len = mem->sys_stop - mem->sys_start;
+ if ((len & (len+1)) || (base & len)) return -EINVAL;
+ if (len == 0x0fff)
+ base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
+ else
+ base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
+ tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+ tcic_setw(TCIC_DATA, base);
+
+ mmap = mem->card_start - mem->sys_start;
+ mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
+ if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
+ tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+ tcic_setw(TCIC_DATA, mmap);
+
+ ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
+ ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
+ ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
+ ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
+ ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
+ tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+ tcic_setw(TCIC_DATA, ctl);
+
+ return 0;
+} /* tcic_set_mem_map */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+
+static subfn_t service_table[] = {
+ (subfn_t)&tcic_register_callback,
+ (subfn_t)&tcic_inquire_socket,
+ (subfn_t)&tcic_get_status,
+ (subfn_t)&tcic_get_socket,
+ (subfn_t)&tcic_set_socket,
+ (subfn_t)&tcic_get_io_map,
+ (subfn_t)&tcic_set_io_map,
+ (subfn_t)&tcic_get_mem_map,
+ (subfn_t)&tcic_set_mem_map,
+};
+
+#define NFUNC (sizeof(service_table)/sizeof(subfn_t))
+
+static int tcic_service(u_int lsock, u_int cmd, void *arg)
+{
+ int err;
+
+ DEBUG(2, "tcic_service(%d, %d, 0x%p)\n", lsock, cmd, arg);
+
+ if (cmd < NFUNC)
+ err = service_table[cmd](lsock, arg);
+ else
+ err = -EINVAL;
+
+ return err;
+} /* tcic_service */
+
+/*====================================================================*/
+
+int pcmcia_tcic_init(void)
+{
+ servinfo_t serv;
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "tcic: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ return tcic_init();
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return pcmcia_tcic_init();
+}
+
+void cleanup_module(void)
+{
+ tcic_finish();
+}
+#endif
--- /dev/null
+/*
+ * tcic.h 1.12 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TCIC_H
+#define _LINUX_TCIC_H
+
+#define TCIC_BASE 0x240
+
+/* offsets of registers from TCIC_BASE */
+#define TCIC_DATA 0x00
+#define TCIC_ADDR 0x02
+#define TCIC_SCTRL 0x06
+#define TCIC_SSTAT 0x07
+#define TCIC_MODE 0x08
+#define TCIC_PWR 0x09
+#define TCIC_EDC 0x0A
+#define TCIC_ICSR 0x0C
+#define TCIC_IENA 0x0D
+#define TCIC_AUX 0x0E
+
+#define TCIC_SS_SHFT 12
+#define TCIC_SS_MASK 0x7000
+
+/* Flags for TCIC_ADDR */
+#define TCIC_ADR2_REG 0x8000
+#define TCIC_ADR2_INDREG 0x0800
+
+#define TCIC_ADDR_REG 0x80000000
+#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16)
+#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16)
+#define TCIC_ADDR_INDREG 0x08000000
+#define TCIC_ADDR_IO 0x04000000
+#define TCIC_ADDR_MASK 0x03ffffff
+
+/* Flags for TCIC_SCTRL */
+#define TCIC_SCTRL_ENA 0x01
+#define TCIC_SCTRL_INCMODE 0x18
+#define TCIC_SCTRL_INCMODE_HOLD 0x00
+#define TCIC_SCTRL_INCMODE_WORD 0x08
+#define TCIC_SCTRL_INCMODE_REG 0x10
+#define TCIC_SCTRL_INCMODE_AUTO 0x18
+#define TCIC_SCTRL_EDCSUM 0x20
+#define TCIC_SCTRL_RESET 0x80
+
+/* Flags for TCIC_SSTAT */
+#define TCIC_SSTAT_6US 0x01
+#define TCIC_SSTAT_10US 0x02
+#define TCIC_SSTAT_PROGTIME 0x04
+#define TCIC_SSTAT_LBAT1 0x08
+#define TCIC_SSTAT_LBAT2 0x10
+#define TCIC_SSTAT_RDY 0x20 /* Inverted */
+#define TCIC_SSTAT_WP 0x40
+#define TCIC_SSTAT_CD 0x80 /* Card detect */
+
+/* Flags for TCIC_MODE */
+#define TCIC_MODE_PGMMASK 0x1f
+#define TCIC_MODE_NORMAL 0x00
+#define TCIC_MODE_PGMWR 0x01
+#define TCIC_MODE_PGMRD 0x02
+#define TCIC_MODE_PGMCE 0x04
+#define TCIC_MODE_PGMDBW 0x08
+#define TCIC_MODE_PGMWORD 0x10
+#define TCIC_MODE_AUXSEL_MASK 0xe0
+
+/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
+#define TCIC_AUX_TCTL (0<<5)
+#define TCIC_AUX_PCTL (1<<5)
+#define TCIC_AUX_WCTL (2<<5)
+#define TCIC_AUX_EXTERN (3<<5)
+#define TCIC_AUX_PDATA (4<<5)
+#define TCIC_AUX_SYSCFG (5<<5)
+#define TCIC_AUX_ILOCK (6<<5)
+#define TCIC_AUX_TEST (7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock) (0x01<<(sock))
+#define TCIC_PWR_VCC_MASK 0x03
+#define TCIC_PWR_VPP(sock) (0x08<<(sock))
+#define TCIC_PWR_VPP_MASK 0x18
+#define TCIC_PWR_CLIMENA 0x40
+#define TCIC_PWR_CLIMSTAT 0x80
+
+/* Flags for TCIC_ICSR */
+#define TCIC_ICSR_CLEAR 0x01
+#define TCIC_ICSR_SET 0x02
+#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
+#define TCIC_ICSR_STOPCPU 0x04
+#define TCIC_ICSR_ILOCK 0x08
+#define TCIC_ICSR_PROGTIME 0x10
+#define TCIC_ICSR_ERR 0x20
+#define TCIC_ICSR_CDCHG 0x40
+#define TCIC_ICSR_IOCHK 0x80
+
+/* Flags for TCIC_IENA */
+#define TCIC_IENA_CFG_MASK 0x03
+#define TCIC_IENA_CFG_OFF 0x00 /* disabled */
+#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */
+#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */
+#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */
+#define TCIC_IENA_ILOCK 0x08
+#define TCIC_IENA_PROGTIME 0x10
+#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */
+#define TCIC_IENA_CDCHG 0x40
+
+/* Flags for TCIC_AUX_WCTL */
+#define TCIC_WAIT_COUNT_MASK 0x001f
+#define TCIC_WAIT_ASYNC 0x0020
+#define TCIC_WAIT_SENSE 0x0040
+#define TCIC_WAIT_SRC 0x0080
+#define TCIC_WCTL_WR 0x0100
+#define TCIC_WCTL_RD 0x0200
+#define TCIC_WCTL_CE 0x0400
+#define TCIC_WCTL_LLBAT1 0x0800
+#define TCIC_WCTL_LLBAT2 0x1000
+#define TCIC_WCTL_LRDY 0x2000
+#define TCIC_WCTL_LWP 0x4000
+#define TCIC_WCTL_LCD 0x8000
+
+/* Flags for TCIC_AUX_SYSCFG */
+#define TCIC_SYSCFG_IRQ_MASK 0x000f
+#define TCIC_SYSCFG_MCSFULL 0x0010
+#define TCIC_SYSCFG_IO1723 0x0020
+#define TCIC_SYSCFG_MCSXB 0x0040
+#define TCIC_SYSCFG_ICSXB 0x0080
+#define TCIC_SYSCFG_NOPDN 0x0100
+#define TCIC_SYSCFG_MPSEL_SHFT 9
+#define TCIC_SYSCFG_MPSEL_MASK 0x0e00
+#define TCIC_SYSCFG_MPSENSE 0x2000
+#define TCIC_SYSCFG_AUTOBUSY 0x4000
+#define TCIC_SYSCFG_ACC 0x8000
+
+#define TCIC_ILOCK_OUT 0x01
+#define TCIC_ILOCK_SENSE 0x02
+#define TCIC_ILOCK_CRESET 0x04
+#define TCIC_ILOCK_CRESENA 0x08
+#define TCIC_ILOCK_CWAIT 0x10
+#define TCIC_ILOCK_CWAITSNS 0x20
+#define TCIC_ILOCK_HOLD_MASK 0xc0
+#define TCIC_ILOCK_HOLD_CCLK 0xc0
+
+#define TCIC_ILOCKTEST_ID_SH 8
+#define TCIC_ILOCKTEST_ID_MASK 0x7f00
+#define TCIC_ILOCKTEST_MCIC_1 0x8000
+
+#define TCIC_ID_DB86082 0x02
+#define TCIC_ID_DB86082A 0x03
+#define TCIC_ID_DB86084 0x04
+#define TCIC_ID_DB86084A 0x08
+#define TCIC_ID_DB86072 0x15
+#define TCIC_ID_DB86184 0x14
+#define TCIC_ID_DB86082B 0x17
+
+#define TCIC_TEST_DIAG 0x8000
+
+/*
+ * Indirectly addressed registers
+ */
+
+#define TCIC_SCF1(sock) ((sock)<<3)
+#define TCIC_SCF2(sock) (((sock)<<3)+2)
+
+/* Flags for SCF1 */
+#define TCIC_SCF1_IRQ_MASK 0x000f
+#define TCIC_SCF1_IRQ_OFF 0x0000
+#define TCIC_SCF1_IRQOC 0x0010
+#define TCIC_SCF1_PCVT 0x0020
+#define TCIC_SCF1_IRDY 0x0040
+#define TCIC_SCF1_ATA 0x0080
+#define TCIC_SCF1_DMA_SHIFT 8
+#define TCIC_SCF1_DMA_MASK 0x0700
+#define TCIC_SCF1_DMA_OFF 0
+#define TCIC_SCF1_DREQ2 2
+#define TCIC_SCF1_IOSTS 0x0800
+#define TCIC_SCF1_SPKR 0x1000
+#define TCIC_SCF1_FINPACK 0x2000
+#define TCIC_SCF1_DELWR 0x4000
+#define TCIC_SCF1_HD7IDE 0x8000
+
+/* Flags for SCF2 */
+#define TCIC_SCF2_RI 0x0001
+#define TCIC_SCF2_IDBR 0x0002
+#define TCIC_SCF2_MDBR 0x0004
+#define TCIC_SCF2_MLBAT1 0x0008
+#define TCIC_SCF2_MLBAT2 0x0010
+#define TCIC_SCF2_MRDY 0x0020
+#define TCIC_SCF2_MWP 0x0040
+#define TCIC_SCF2_MCD 0x0080
+#define TCIC_SCF2_MALL 0x00f8
+
+/* Indirect addresses for memory window registers */
+#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3))
+#define TCIC_MBASE_X 2
+#define TCIC_MMAP_X 4
+#define TCIC_MCTL_X 6
+
+#define TCIC_MBASE_4K_BIT 0x4000
+#define TCIC_MBASE_HA_SHFT 12
+#define TCIC_MBASE_HA_MASK 0x0fff
+
+#define TCIC_MMAP_REG 0x8000
+#define TCIC_MMAP_CA_SHFT 12
+#define TCIC_MMAP_CA_MASK 0x3fff
+
+#define TCIC_MCTL_WSCNT_MASK 0x001f
+#define TCIC_MCTL_WCLK 0x0020
+#define TCIC_MCTL_WCLK_CCLK 0x0000
+#define TCIC_MCTL_WCLK_BCLK 0x0020
+#define TCIC_MCTL_QUIET 0x0040
+#define TCIC_MCTL_WP 0x0080
+#define TCIC_MCTL_ACC 0x0100
+#define TCIC_MCTL_KE 0x0200
+#define TCIC_MCTL_EDC 0x0400
+#define TCIC_MCTL_B8 0x0800
+#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT
+#define TCIC_MCTL_SS_MASK TCIC_SS_MASK
+#define TCIC_MCTL_ENA 0x8000
+
+/* Indirect addresses for I/O window registers */
+#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2))
+#define TCIC_IBASE_X 0
+#define TCIC_ICTL_X 2
+
+#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK
+#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET
+#define TCIC_ICTL_1K 0x0080
+#define TCIC_ICTL_PASS16 0x0100
+#define TCIC_ICTL_ACC TCIC_MCTL_ACC
+#define TCIC_ICTL_TINY 0x0200
+#define TCIC_ICTL_B16 0x0400
+#define TCIC_ICTL_B8 TCIC_MCTL_B8
+#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_BW_DYN 0
+#define TCIC_ICTL_BW_8 TCIC_ICTL_B8
+#define TCIC_ICTL_BW_16 TCIC_ICTL_B16
+#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT
+#define TCIC_ICTL_SS_MASK TCIC_SS_MASK
+#define TCIC_ICTL_ENA TCIC_MCTL_ENA
+
+#endif /* _LINUX_TCIC_H */
--- /dev/null
+/*
+ * ti113x.h 1.14 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TI113X_H
+#define _LINUX_TI113X_H
+
+#ifndef PCI_VENDOR_ID_TI
+#define PCI_VENDOR_ID_TI 0x104c
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_1130
+#define PCI_DEVICE_ID_TI_1130 0xac12
+#endif
+#ifndef PCI_DEVICE_ID_TI_1131
+#define PCI_DEVICE_ID_TI_1131 0xac15
+#endif
+#ifndef PCI_DEVICE_ID_TI_1031
+#define PCI_DEVICE_ID_TI_1031 0xac13
+#endif
+#ifndef PCI_DEVICE_ID_TI_1250A
+#define PCI_DEVICE_ID_TI_1250A 0xac16
+#endif
+#ifndef PCI_DEVICE_ID_TI_1220
+#define PCI_DEVICE_ID_TI_1220 0xac17
+#endif
+#ifndef PCI_DEVICE_ID_TI_1221
+#define PCI_DEVICE_ID_TI_1221 0xac19
+#endif
+#ifndef PCI_DEVICE_ID_TI_1210
+#define PCI_DEVICE_ID_TI_1210 0xac1a
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251A
+#define PCI_DEVICE_ID_TI_1251A 0xac1d
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251B
+#define PCI_DEVICE_ID_TI_1251B 0xac1f
+#endif
+#ifndef PCI_DEVICE_ID_TI_1450
+#define PCI_DEVICE_ID_TI_1450 0xac1b
+#endif
+#ifndef PCI_DEVICE_ID_TI_1225
+#define PCI_DEVICE_ID_TI_1225 0xac1c
+#endif
+
+/* Register definitions for TI 113X PCI-to-CardBus bridges */
+
+/* System Control Register */
+#define TI113X_SYSTEM_CONTROL 0x0080 /* 32 bit */
+#define TI113X_SCR_SMIROUTE 0x04000000
+#define TI113X_SCR_SMISTATUS 0x02000000
+#define TI113X_SCR_SMIENB 0x01000000
+#define TI113X_SCR_VCCPROT 0x00200000
+#define TI113X_SCR_REDUCEZV 0x00100000
+#define TI113X_SCR_CDREQEN 0x00080000
+#define TI113X_SCR_CDMACHAN 0x00070000
+#define TI113X_SCR_SOCACTIVE 0x00002000
+#define TI113X_SCR_PWRSTREAM 0x00000800
+#define TI113X_SCR_DELAYUP 0x00000400
+#define TI113X_SCR_DELAYDOWN 0x00000200
+#define TI113X_SCR_INTERROGATE 0x00000100
+#define TI113X_SCR_CLKRUN_SEL 0x00000080
+#define TI113X_SCR_PWRSAVINGS 0x00000040
+#define TI113X_SCR_SUBSYSRW 0x00000020
+#define TI113X_SCR_CB_DPAR 0x00000010
+#define TI113X_SCR_CDMA_EN 0x00000008
+#define TI113X_SCR_ASYNC_IRQ 0x00000004
+#define TI113X_SCR_KEEPCLK 0x00000002
+#define TI113X_SCR_CLKRUN_ENA 0x00000001
+
+#define TI122X_SCR_SER_STEP 0xc0000000
+#define TI122X_SCR_INTRTIE 0x20000000
+#define TI122X_SCR_CBRSVD 0x00400000
+#define TI122X_SCR_MRBURSTDN 0x00008000
+#define TI122X_SCR_MRBURSTUP 0x00004000
+#define TI122X_SCR_RIMUX 0x00000001
+
+/* Multimedia Control Register */
+#define TI1250_MULTIMEDIA_CTL 0x0084 /* 8 bit */
+#define TI1250_MMC_ZVOUTEN 0x80
+#define TI1250_MMC_PORTSEL 0x40
+#define TI1250_MMC_ZVEN1 0x02
+#define TI1250_MMC_ZVEN0 0x01
+
+#define TI1250_GENERAL_STATUS 0x0085 /* 8 bit */
+#define TI1250_GPIO0_CONTROL 0x0088 /* 8 bit */
+#define TI1250_GPIO1_CONTROL 0x0089 /* 8 bit */
+#define TI1250_GPIO2_CONTROL 0x008a /* 8 bit */
+#define TI1250_GPIO3_CONTROL 0x008b /* 8 bit */
+#define TI122X_IRQMUX 0x008c /* 32 bit */
+
+/* Retry Status Register */
+#define TI113X_RETRY_STATUS 0x0090 /* 8 bit */
+#define TI113X_RSR_PCIRETRY 0x80
+#define TI113X_RSR_CBRETRY 0x40
+#define TI113X_RSR_TEXP_CBB 0x20
+#define TI113X_RSR_MEXP_CBB 0x10
+#define TI113X_RSR_TEXP_CBA 0x08
+#define TI113X_RSR_MEXP_CBA 0x04
+#define TI113X_RSR_TEXP_PCI 0x02
+#define TI113X_RSR_MEXP_PCI 0x01
+
+/* Card Control Register */
+#define TI113X_CARD_CONTROL 0x0091 /* 8 bit */
+#define TI113X_CCR_RIENB 0x80
+#define TI113X_CCR_ZVENABLE 0x40
+#define TI113X_CCR_PCI_IRQ_ENA 0x20
+#define TI113X_CCR_PCI_IREQ 0x10
+#define TI113X_CCR_PCI_CSC 0x08
+#define TI113X_CCR_SPKROUTEN 0x02
+#define TI113X_CCR_IFG 0x01
+
+#define TI1220_CCR_PORT_SEL 0x20
+#define TI122X_CCR_AUD2MUX 0x04
+
+/* Device Control Register */
+#define TI113X_DEVICE_CONTROL 0x0092 /* 8 bit */
+#define TI113X_DCR_5V_FORCE 0x40
+#define TI113X_DCR_3V_FORCE 0x20
+#define TI113X_DCR_IMODE_MASK 0x06
+#define TI113X_DCR_IMODE_ISA 0x02
+#define TI113X_DCR_IMODE_SERIAL 0x04
+
+#define TI12XX_DCR_IMODE_PCI_ONLY 0x00
+#define TI12XX_DCR_IMODE_ALL_SERIAL 0x06
+
+/* Buffer Control Register */
+#define TI113X_BUFFER_CONTROL 0x0093 /* 8 bit */
+#define TI113X_BCR_CB_READ_DEPTH 0x08
+#define TI113X_BCR_CB_WRITE_DEPTH 0x04
+#define TI113X_BCR_PCI_READ_DEPTH 0x02
+#define TI113X_BCR_PCI_WRITE_DEPTH 0x01
+
+/* Diagnostic Register */
+#define TI1250_DIAGNOSTIC 0x0093 /* 8 bit */
+#define TI1250_DIAG_TRUE_VALUE 0x80
+#define TI1250_DIAG_PCI_IREQ 0x40
+#define TI1250_DIAG_PCI_CSC 0x20
+#define TI1250_DIAG_ASYNC_CSC 0x01
+
+/* DMA Registers */
+#define TI113X_DMA_0 0x0094 /* 32 bit */
+#define TI113X_DMA_1 0x0098 /* 32 bit */
+
+/* ExCA IO offset registers */
+#define TI113X_IO_OFFSET(map) (0x36+((map)<<1))
+
+#endif /* _LINUX_TI113X_H */
+
--- /dev/null
+/*
+ * topic.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * topic.h $Release$ 1999/08/28 04:01:47
+ */
+
+#ifndef _LINUX_TOPIC_H
+#define _LINUX_TOPIC_H
+
+#ifndef PCI_VENDOR_ID_TOSHIBA
+#define PCI_VENDOR_ID_TOSHIBA 0x1179
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_A
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A 0x0603
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_B
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_B 0x060a
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC97
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
+#endif
+
+/* Register definitions for Toshiba ToPIC95 controllers */
+
+#define TOPIC_SOCKET_CONTROL 0x0090 /* 32 bit */
+#define TOPIC_SCR_IRQSEL 0x00000001
+
+#define TOPIC_SLOT_CONTROL 0x00a0 /* 8 bit */
+#define TOPIC_SLOT_SLOTON 0x80
+#define TOPIC_SLOT_SLOTEN 0x40
+#define TOPIC_SLOT_ID_LOCK 0x20
+#define TOPIC_SLOT_ID_WP 0x10
+#define TOPIC_SLOT_PORT_MASK 0x0c
+#define TOPIC_SLOT_PORT_SHIFT 2
+#define TOPIC_SLOT_OFS_MASK 0x03
+
+#define TOPIC_CARD_CONTROL 0x00a1 /* 8 bit */
+#define TOPIC_CCR_INTB 0x20
+#define TOPIC_CCR_INTA 0x10
+#define TOPIC_CCR_CLOCK 0x0c
+#define TOPIC_CCR_PCICLK 0x0c
+#define TOPIC_CCR_PCICLK_2 0x08
+#define TOPIC_CCR_CCLK 0x04
+
+#define TOPIC97_INT_CONTROL 0x00a1 /* 8 bit */
+#define TOPIC97_ICR_INTB 0x20
+#define TOPIC97_ICR_INTA 0x10
+#define TOPIC97_ICR_STSIRQNP 0x04
+#define TOPIC97_ICR_IRQNP 0x02
+#define TOPIC97_ICR_IRQSEL 0x01
+
+#define TOPIC_CARD_DETECT 0x00a3 /* 8 bit */
+#define TOPIC_CDR_MODE_PC32 0x80
+#define TOPIC_CDR_VS1 0x04
+#define TOPIC_CDR_VS2 0x02
+#define TOPIC_CDR_SW_DETECT 0x01
+
+#define TOPIC_REGISTER_CONTROL 0x00a4 /* 32 bit */
+#define TOPIC_RCR_RESUME_RESET 0x80000000
+#define TOPIC_RCR_REMOVE_RESET 0x40000000
+#define TOPIC97_RCR_CLKRUN_ENA 0x20000000
+#define TOPIC97_RCR_TESTMODE 0x10000000
+#define TOPIC97_RCR_IOPLUP 0x08000000
+#define TOPIC_RCR_BUFOFF_PWROFF 0x02000000
+#define TOPIC_RCR_BUFOFF_SIGOFF 0x01000000
+#define TOPIC97_RCR_CB_DEV_MASK 0x0000f800
+#define TOPIC97_RCR_CB_DEV_SHIFT 11
+#define TOPIC97_RCR_RI_DISABLE 0x00000004
+#define TOPIC97_RCR_CAUDIO_OFF 0x00000002
+#define TOPIC_RCR_CAUDIO_INVERT 0x00000001
+
+#endif /* _LINUX_TOPIC_H */
--- /dev/null
+/*
+ * vg468.h 1.10 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM 0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK 0x0c
+#define VG468_VPP2_5V 0x04
+#define VG468_VPP2_12V 0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE 0x1f /* Card voltage sense */
+#define VG469_VSELECT 0x2f /* Card voltage select */
+#define VG468_CTL 0x38 /* Control register */
+#define VG468_TIMER 0x39 /* Timer control */
+#define VG468_MISC 0x3a /* Miscellaneous */
+#define VG468_GPIO_CFG 0x3b /* GPIO configuration */
+#define VG469_EXT_MODE 0x3c /* Extended mode register */
+#define VG468_SELECT 0x3d /* Programmable chip select */
+#define VG468_SELECT_CFG 0x3e /* Chip select configuration */
+#define VG468_ATA 0x3f /* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1 0x01
+#define VG469_VSENSE_A_VS2 0x02
+#define VG469_VSENSE_B_VS1 0x04
+#define VG469_VSENSE_B_VS2 0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC 0x03
+#define VG469_VSEL_5V 0x00
+#define VG469_VSEL_3V 0x03
+#define VG469_VSEL_MAX 0x0c
+#define VG469_VSEL_EXT_STAT 0x10
+#define VG469_VSEL_EXT_BUS 0x20
+#define VG469_VSEL_MIXED 0x40
+#define VG469_VSEL_ISA 0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW 0x01 /* 600ns memory timing */
+#define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */
+#define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */
+#define VG468_CTL_DELAY 0x10 /* Card detect debounce */
+#define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */
+#define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */
+#define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */
+#define VG469_CTL_STRETCH 0x10 /* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */
+#define VG468_TIMER_SIGEN 0x20 /* Power up */
+#define VG468_TIMER_STATUS 0x40 /* Activity timer status */
+#define VG468_TIMER_RES 0x80 /* Timer resolution */
+#define VG468_TIMER_MASK 0x0f /* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO 0x04 /* General-purpose IO */
+#define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */
+#define VG469_MISC_LEDENA 0x10 /* LED enable */
+#define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */
+#define VG468_MISC_UNLOCK 0x80 /* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST 0x03 /* Vpp steering control */
+#define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */
+#define VG469_MODE_CABLE 0x08
+#define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */
+#define VG469_MODE_TEST 0x20
+#define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
--- /dev/null
+/*
+ * yenta.h 1.15 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_YENTA_H
+#define _LINUX_YENTA_H
+
+/* PCI Configuration Registers */
+
+#define PCI_STATUS_CAPLIST 0x10
+#define PCI_CB_CAPABILITY_POINTER 0x14 /* 8 bit */
+#define PCI_CAPABILITY_ID 0x00 /* 8 bit */
+#define PCI_CAPABILITY_PM 0x01
+#define PCI_NEXT_CAPABILITY 0x01 /* 8 bit */
+#define PCI_PM_CAPABILITIES 0x02 /* 16 bit */
+#define PCI_PMCAP_PME_D3COLD 0x8000
+#define PCI_PMCAP_PME_D3HOT 0x4000
+#define PCI_PMCAP_PME_D2 0x2000
+#define PCI_PMCAP_PME_D1 0x1000
+#define PCI_PMCAP_PME_D0 0x0800
+#define PCI_PMCAP_D2_CAP 0x0400
+#define PCI_PMCAP_D1_CAP 0x0200
+#define PCI_PMCAP_DYN_DATA 0x0100
+#define PCI_PMCAP_DSI 0x0020
+#define PCI_PMCAP_AUX_PWR 0x0010
+#define PCI_PMCAP_PMECLK 0x0008
+#define PCI_PMCAP_VERSION_MASK 0x0007
+#define PCI_PM_CONTROL_STATUS 0x04 /* 16 bit */
+#define PCI_PMCS_PME_STATUS 0x8000
+#define PCI_PMCS_DATASCALE_MASK 0x6000
+#define PCI_PMCS_DATASCALE_SHIFT 13
+#define PCI_PMCS_DATASEL_MASK 0x1e00
+#define PCI_PMCS_DATASEL_SHIFT 9
+#define PCI_PMCS_PME_ENABLE 0x0100
+#define PCI_PMCS_PWR_STATE_MASK 0x0003
+#define PCI_PMCS_PWR_STATE_D0 0x0000
+#define PCI_PMCS_PWR_STATE_D1 0x0001
+#define PCI_PMCS_PWR_STATE_D2 0x0002
+#define PCI_PMCS_PWR_STATE_D3 0x0003
+#define PCI_PM_BRIDGE_EXT 0x06 /* 8 bit */
+#define PCI_PM_DATA 0x07 /* 8 bit */
+
+#define CB_PRIMARY_BUS 0x18 /* 8 bit */
+#define CB_CARDBUS_BUS 0x19 /* 8 bit */
+#define CB_SUBORD_BUS 0x1a /* 8 bit */
+#define CB_LATENCY_TIMER 0x1b /* 8 bit */
+
+#define CB_MEM_BASE(m) (0x1c + 8*(m))
+#define CB_MEM_LIMIT(m) (0x20 + 8*(m))
+#define CB_IO_BASE(m) (0x2c + 8*(m))
+#define CB_IO_LIMIT(m) (0x30 + 8*(m))
+
+#define CB_BRIDGE_CONTROL 0x3e /* 16 bit */
+#define CB_BCR_PARITY_ENA 0x0001
+#define CB_BCR_SERR_ENA 0x0002
+#define CB_BCR_ISA_ENA 0x0004
+#define CB_BCR_VGA_ENA 0x0008
+#define CB_BCR_MABORT 0x0020
+#define CB_BCR_CB_RESET 0x0040
+#define CB_BCR_ISA_IRQ 0x0080
+#define CB_BCR_PREFETCH(m) (0x0100 << (m))
+#define CB_BCR_WRITE_POST 0x0400
+
+#define CB_LEGACY_MODE_BASE 0x44
+
+/* Memory mapped registers */
+
+#define CB_SOCKET_EVENT 0x0000
+#define CB_SE_CSTSCHG 0x00000001
+#define CB_SE_CCD1 0x00000002
+#define CB_SE_CCD2 0x00000004
+#define CB_SE_PWRCYCLE 0x00000008
+
+#define CB_SOCKET_MASK 0x0004
+#define CB_SM_CSTSCHG 0x00000001
+#define CB_SM_CCD 0x00000006
+#define CB_SM_PWRCYCLE 0x00000008
+
+#define CB_SOCKET_STATE 0x0008
+#define CB_SS_CSTSCHG 0x00000001
+#define CB_SS_CCD1 0x00000002
+#define CB_SS_CCD2 0x00000004
+#define CB_SS_PWRCYCLE 0x00000008
+#define CB_SS_16BIT 0x00000010
+#define CB_SS_32BIT 0x00000020
+#define CB_SS_CINT 0x00000040
+#define CB_SS_BADCARD 0x00000080
+#define CB_SS_DATALOST 0x00000100
+#define CB_SS_BADVCC 0x00000200
+#define CB_SS_5VCARD 0x00000400
+#define CB_SS_3VCARD 0x00000800
+#define CB_SS_XVCARD 0x00001000
+#define CB_SS_YVCARD 0x00002000
+#define CB_SS_5VSOCKET 0x10000000
+#define CB_SS_3VSOCKET 0x20000000
+#define CB_SS_XVSOCKET 0x40000000
+#define CB_SS_YVSOCKET 0x80000000
+
+#define CB_SOCKET_FORCE 0x000c
+#define CB_SF_CVSTEST 0x00004000
+
+#define CB_SOCKET_CONTROL 0x0010
+#define CB_SC_VPP_MASK 0x00000007
+#define CB_SC_VPP_OFF 0x00000000
+#define CB_SC_VPP_12V 0x00000001
+#define CB_SC_VPP_5V 0x00000002
+#define CB_SC_VPP_3V 0x00000003
+#define CB_SC_VPP_XV 0x00000004
+#define CB_SC_VPP_YV 0x00000005
+#define CB_SC_VCC_MASK 0x00000070
+#define CB_SC_VCC_OFF 0x00000000
+#define CB_SC_VCC_5V 0x00000020
+#define CB_SC_VCC_3V 0x00000030
+#define CB_SC_VCC_XV 0x00000040
+#define CB_SC_VCC_YV 0x00000050
+#define CB_SC_CCLK_STOP 0x00000080
+
+#define CB_SOCKET_POWER 0x0020
+#define CB_SP_CLK_CTRL 0x00000001
+#define CB_SP_CLK_CTRL_ENA 0x00010000
+#define CB_SP_CLK_MODE 0x01000000
+#define CB_SP_ACCESS 0x02000000
+
+/* Address bits 31..24 for memory windows for 16-bit cards,
+ accessable only by memory mapping the 16-bit register set */
+#define CB_MEM_PAGE(map) (0x40 + (map))
+
+#endif /* _LINUX_YENTA_H */
-/* $Id: advansys.c,v 1.50 1998/05/08 23:39:15 bobf Exp bobf $ */
-#define ASC_VERSION "3.1E" /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */
+#define ASC_VERSION "3.2F" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
*
- * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * Copyright (c) 1995-1999 Advanced System Products, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
G. Driver Compile Time Options and Debugging
H. Driver LILO Option
I. Release History
- J. Known Problems or Issues
+ J. Known Problems/Fix List
K. Credits
L. AdvanSys Contact Information
A. Linux Kernel Testing
This driver has been tested in the following Linux kernels: v1.2.13,
- v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases
- of Linux or the latest Linux kernel versions available when this version
- of the driver was released. The driver should also work in earlier
- versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver
- is included with all Linux kernels. Please refer to sections C, D, and
- E for instructions on adding or upgrading the AdvanSys driver.
+ v1.3.57, v2.0.38, v2.2.12, and v2.3.16. These kernel versions are major
+ releases of Linux or the latest Linux kernel versions available when
+ this version of the driver was released. The driver should also work
+ in earlier versions of the Linux kernel. Beginning with v1.3.58 the
+ AdvanSys driver is included with all Linux kernels. Please refer to
+ sections C, D, and E for instructions on adding or upgrading the
+ AdvanSys driver.
B. Adapters Supported by this Driver
lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
Connectivity Products:
- ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
- ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
- ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
+ ABP510/5150 - Bus-Master ISA (240 CDB)
+ ABP5140 - Bus-Master ISA PnP (16 CDB)
+ ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+ ABP902/3902 - Bus-Master PCI (16 CDB)
+ ABP3905 - Bus-Master PCI (16 CDB)
+ ABP915 - Bus-Master PCI (16 CDB)
ABP920 - Bus-Master PCI (16 CDB)
- ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
+ ABP3922 - Bus-Master PCI (16 CDB)
+ ABP3925 - Bus-Master PCI (16 CDB)
+ ABP930 - Bus-Master PCI (16 CDB)
ABP930U - Bus-Master PCI Ultra (16 CDB)
ABP930UA - Bus-Master PCI Ultra (16 CDB)
- ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
- ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2)
+ ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+ ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
Single Channel Products:
ABP542 - Bus-Master ISA with floppy (240 CDB)
ABP842 - Bus-Master VL (240 CDB)
ABP940 - Bus-Master PCI (240 CDB)
ABP940U - Bus-Master PCI Ultra (240 CDB)
+ ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
ABP970 - Bus-Master PCI MAC/PC (240 CDB)
ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
- ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB)
+ ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+ ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+ ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
- Multi Channel Products:
+ Multi-Channel Products:
ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+ ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+ ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
- Footnotes:
- 1. This board has been shipped by HP with the 4020i CD-R drive.
- The board has no BIOS so it cannot control a boot device, but
- it can control any secondary SCSI device.
- 2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
- 3. This board has been sold by SIIG as the i540 SpeedMaster.
- 4. This board has been sold by SIIG as the i542 SpeedMaster.
- 5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
-
C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
These directions apply to v1.2.13. For versions that follow v1.2.13.
flag set to allow IRQ sharing with drivers that do not set
the SA_INTERRUPT flag. Also display a more descriptive error
message if request_irq() fails.
- 5. Update to latest Asc and Adv Libraries.
-
- J. Known Problems or Issues
-
- 1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
- the queue depth flow control code when mid-level SCSI changes
- are included in Linux.
+ 6. Update to latest Asc and Adv Libraries.
+
+ 3.2A (7/22/99):
+ 1. Update Adv Library to 4.16 which includes support for
+ the ASC38C0800 (Ultra2/LVD) IC.
+
+ 3.2B (8/23/99):
+ 1. Correct PCI compile time option for v2.1.93 and greater
+ kernels, advansys_info() string, and debug compile time
+ option.
+ 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
+ kernels. This caused an LVD detection/BIST problem problem
+ among other things.
+ 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
+ to be consistent with the BIOS.
+ 4. Update to Asc Library S121 and Adv Library 5.2.
+
+ 3.2C (8/24/99):
+ 1. Correct PCI card detection bug introduced in 3.2B that
+ prevented PCI cards from being detected in kernels older
+ than v2.1.93.
+
+ 3.2D (8/26/99):
+ 1. Correct /proc device synchronous speed information display.
+ Also when re-negotiation is pending for a target device
+ note this condition with an * and footnote.
+ 2. Correct initialization problem with Ultra-Wide cards that
+ have a pre-3.2 BIOS. A microcode variable changed locations
+ in 3.2 and greater BIOSes which caused WDTR to be attempted
+ erroneously with drives that don't support WDTR.
+
+ 3.2E (8/30/99):
+ 1. Fix compile error caused by v2.3.13 PCI structure change.
+ 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
+ checksum error for ISA cards.
+ 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
+ SCSI changes that it depended on were never included in Linux.
+
+ 3.2F (9/3/99):
+ 1. Handle new initial function code added in v2.3.16 for all
+ driver versions.
+
+ J. Known Problems/Fix List (XXX)
+
+ 1. Need to add memory mapping workaround. Test the memory mapping.
+ If it doesn't work revert to I/O port access. Can a test be done
+ safely?
+ 2. Handle an interrupt not working. Keep an interrupt counter in
+ the interrupt handler. In the timeout function if the interrupt
+ has not occurred then print a message and run in polled mode.
+ 3. Allow bus type scanning order to be changed.
+ 4. Need to add support for target mode commands, cf. CAM XPT.
+ 5 Need to add support for new Linux SCSI error handling method.
+ 6. Need to fix sti/cli code in Asc Library.
+ 7. Need to fix abort code in Adv Library.
+ 8. Reduce io_request_lock hold time.
+ 9. Add big-endian support for Alpha.
K. Credits
Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
support in the 3.1A driver.
+ Doug Gilbert <dgilbert@interlog.com> has made changes and
+ suggestions to improve the driver and done testing.
+
L. AdvanSys Contact Information
Mail: Advanced System Products, Inc.
1150 Ringwood Court
San Jose, CA 95131
- Operator: 1-408-383-9400
+ Operator/Sales: 1-408-383-9400
FAX: 1-408-383-9612
- Tech Support: 1-800-525-7440/1-408-467-2930
- BBS: 1-408-383-9540 (14400,N,8,1)
- Interactive FAX: 1-408-383-9753
- Customer Direct Sales: 1-800-525-7443/1-408-383-5777
+ Tech Support: 1-408-467-2930
Tech Support E-Mail: support@advansys.com
FTP Site: ftp.advansys.com (login: anonymous)
Web Site: http://www.advansys.com
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#include <linux/head.h>
+#endif /* verions < v2.1.0 */
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/delay.h>
*/
#define ASC_LIB_VERSION_MAJOR 1
-#define ASC_LIB_VERSION_MINOR 22
-#define ASC_LIB_SERIAL_NUMBER 113
+#define ASC_LIB_VERSION_MINOR 24
+#define ASC_LIB_SERIAL_NUMBER 121
typedef unsigned char uchar;
#define ASC_DVCLIB_CALL_FAILED (0)
#define ASC_DVCLIB_CALL_ERROR (-1)
+/*
+ * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
+ * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
+ * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
+ * SRB structure.
+ */
+#define CC_VERY_LONG_SG_LIST 0
+#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
+
#define PortAddr unsigned short /* port address size */
#define Ptr2Func ulong
#define inp(port) inb(port)
#define SCSI_TYPE_COMM 0x09
#define SCSI_TYPE_UNKNOWN 0x1F
#define SCSI_TYPE_NO_DVC 0xFF
+#define INQ_CLOCKING_ST_ONLY 0x0
+#define INQ_CLOCKING_DT_ONLY 0x1
+#define INQ_CLOCKING_ST_AND_DT 0x3
#define ASC_SCSIDIR_NOCHK 0x00
#define ASC_SCSIDIR_T2H 0x08
#define ASC_SCSIDIR_H2T 0x10
#define ASC_SCSIQ_CDB_BEG 36
#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
+#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
#define ASC_SCSIQ_B_SG_WK_QP 49
#define ASC_SCSIQ_B_SG_WK_IX 50
-#define ASC_SCSIQ_W_REQ_COUNT 52
+#define ASC_SCSIQ_W_ALT_DC1 52
#define ASC_SCSIQ_B_LIST_CNT 6
#define ASC_SCSIQ_B_CUR_LIST_CNT 7
#define ASC_SGQ_B_SG_CNTL 4
ASC_SCSIQ_2 q2;
uchar *cdbptr;
ASC_SG_HEAD *sg_head;
+ ushort remain_sg_entry_cnt;
+ ushort next_sg_index;
} ASC_SCSI_Q;
typedef struct asc_scsi_req_q {
#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
+#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
#define ASC_MAX_QNO 0xF8
#define ASC_DATA_SEC_BEG (ushort)0x0080
#define ASC_DATA_SEC_END (ushort)0x0080
#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) ;
-#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) ;
-#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) ;
-#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) ;
+#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
+#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
+#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
+#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
* --- Adv Library Constants and Macros
*/
-#define ADV_LIB_VERSION_MAJOR 3
-#define ADV_LIB_VERSION_MINOR 45
+#define ADV_LIB_VERSION_MAJOR 5
+#define ADV_LIB_VERSION_MINOR 2
/* d_os_dep.h */
#define ADV_OS_LINUX
#define iounmap vfree
#endif /* version < v2.1.0 */
+#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
+
/*
* Define total number of simultaneous maximum element scatter-gather
* requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
*/
#define ADV_MAX_SG_LIST 64
-/*
- * Scatter-Gather Definitions per request.
- *
- * Because SG block memory is allocated in virtual memory but is
- * referenced by the microcode as physical memory, we need to do
- * calculations to insure there will be enough physically contiguous
- * memory to support ADV_MAX_SG_LIST SG entries.
- */
-
/* Number of SG blocks needed. */
#define ADV_NUM_SG_BLOCK \
- ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
/* Total contiguous memory needed for SG blocks. */
#define ADV_SG_TOTAL_MEM_SIZE \
#define ASC_PAGE_SIZE PAGE_SIZE
-/*
- * Number of page crossings possible for the total contiguous virtual memory
- * needed for SG blocks.
- *
- * We need to allocate this many additional SG blocks in virtual memory to
- * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous
- * scatter-gather blocks.
- */
#define ADV_NUM_PAGE_CROSSING \
((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
-/*
- * Define Adv Library Assertion Macro.
- */
-
#define ADV_ASSERT(a) ASC_ASSERT(a)
/* a_condor.h */
#define ADV_PCI_VENDOR_ID 0x10CD
#define ADV_PCI_DEVICE_ID_REV_A 0x2300
+#define ADV_PCI_DEVID_38C0800_REV1 0x2500
+#define ADV_PCI_DEVID_38C1600_REV1 0x2700
#define ASC_EEP_DVC_CFG_BEGIN (0x00)
#define ASC_EEP_DVC_CFG_END (0x15)
#define ASC_EEP_DELAY_MS 100
-/*
- * EEPROM bits reference by the RISC after initialization.
- */
#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD 0x1000 /* EEPROM Bit 12 */
-/*
- * EEPROM configuration format
- *
- * Field naming convention:
- *
- * *_enable indicates the field enables or disables the feature. The
- * value is never reset.
- *
- * *_able indicates both whether a feature should be enabled or disabled
- * and whether a device isi capable of the feature. At initialization
- * this field may be set, but later if a device is found to be incapable
- * of the feature, the field is cleared.
- *
- * Default values are maintained in a_init.c in the structure
- * Default_EEPROM_Config.
- */
-typedef struct adveep_config
-{
+typedef struct adveep_3550_config
+{
/* Word Offset, Description */
ushort cfg_lsw; /* 00 power up initialization */
ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
ushort saved_adv_err_addr; /* 35 saved last uc error address */
ushort num_of_err; /* 36 number of error */
-} ADVEEP_CONFIG;
+} ADVEEP_3550_CONFIG;
+
+typedef struct adveep_38C0800_config
+{
+ /* Word Offset, Description */
+
+ ushort cfg_lsw; /* 00 power up initialization */
+ /* bit 12 set - CIS Load */
+ /* bit 13 set - Term Polarity Control */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ ushort cfg_msw; /* 01 unused */
+ ushort disc_enable; /* 02 disconnect enable */
+ ushort wdtr_able; /* 03 Wide DTR able */
+ ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
+ ushort start_motor; /* 05 send start up motor */
+ ushort tagqng_able; /* 06 tag queuing able */
+ ushort bios_scan; /* 07 BIOS device control */
+ ushort scam_tolerant; /* 08 no scam */
+
+ uchar adapter_scsi_id; /* 09 Host Adapter ID */
+ uchar bios_boot_delay; /* power up wait */
+
+ uchar scsi_reset_delay; /* 10 reset delay */
+ uchar bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ uchar termination_se; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ uchar termination_lvd; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ ushort bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 set: BIOS don't act as initiator. */
+ /* bit 1 set: BIOS > 1 GB support */
+ /* bit 2 set: BIOS > 2 Disk Support */
+ /* bit 3 set: BIOS don't support removables */
+ /* bit 4 set: BIOS support bootable CD */
+ /* bit 5 set: BIOS scan enabled */
+ /* bit 6 set: BIOS support multiple LUNs */
+ /* bit 7 set: BIOS display of message */
+ /* bit 8 set: */
+ /* bit 9 set: Reset SCSI bus during init. */
+ /* bit 10 set: */
+ /* bit 11 set: No verbose initialization. */
+ /* bit 12 set: SCSI parity enabled */
+ /* bit 13 set: */
+ /* bit 14 set: */
+ /* bit 15 set: */
+ ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
+ ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
+ uchar max_host_qng; /* 15 maximum host queueing */
+ uchar max_dvc_qng; /* maximum per device queuing */
+ ushort dvc_cntl; /* 16 control bit for driver */
+ ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
+ ushort serial_number_word1; /* 18 Board serial number word 1 */
+ ushort serial_number_word2; /* 19 Board serial number word 2 */
+ ushort serial_number_word3; /* 20 Board serial number word 3 */
+ ushort check_sum; /* 21 EEP check sum */
+ uchar oem_name[16]; /* 22 OEM name */
+ ushort dvc_err_code; /* 30 last device driver error code */
+ ushort adv_err_code; /* 31 last uc and Adv Lib error code */
+ ushort adv_err_addr; /* 32 last uc error address */
+ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ ushort saved_adv_err_addr; /* 35 saved last uc error address */
+ ushort reserved36; /* 36 reserved */
+ ushort reserved37; /* 37 reserved */
+ ushort reserved38; /* 38 reserved */
+ ushort reserved39; /* 39 reserved */
+ ushort reserved40; /* 40 reserved */
+ ushort reserved41; /* 41 reserved */
+ ushort reserved42; /* 42 reserved */
+ ushort reserved43; /* 43 reserved */
+ ushort reserved44; /* 44 reserved */
+ ushort reserved45; /* 45 reserved */
+ ushort reserved46; /* 46 reserved */
+ ushort reserved47; /* 47 reserved */
+ ushort reserved48; /* 48 reserved */
+ ushort reserved49; /* 49 reserved */
+ ushort reserved50; /* 50 reserved */
+ ushort reserved51; /* 51 reserved */
+ ushort reserved52; /* 52 reserved */
+ ushort reserved53; /* 53 reserved */
+ ushort reserved54; /* 54 reserved */
+ ushort reserved55; /* 55 reserved */
+ ushort cisptr_lsw; /* 56 CIS PTR LSW */
+ ushort cisprt_msw; /* 57 CIS PTR MSW */
+ ushort subsysvid; /* 58 SubSystem Vendor ID */
+ ushort subsysid; /* 59 SubSystem ID */
+ ushort reserved60; /* 60 reserved */
+ ushort reserved61; /* 61 reserved */
+ ushort reserved62; /* 62 reserved */
+ ushort reserved63; /* 63 reserved */
+} ADVEEP_38C0800_CONFIG;
/*
* EEPROM Commands
#define BIOS_CTRL_INIT_VERBOSE 0x0800
#define BIOS_CTRL_SCSI_PARITY 0x1000
-/*
- * ASC 3550 Internal Memory Size - 8KB
- */
-#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
-/*
- * ASC 3550 I/O Length - 64 bytes
- */
-#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */
+#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
+
+#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
/*
* Byte I/O register address from base of 'iop_base'.
#define IOPB_RES_ADDR_B 0x0B
#define IOPB_RES_ADDR_C 0x0C
#define IOPB_RES_ADDR_D 0x0D
-#define IOPB_RES_ADDR_E 0x0E
+#define IOPB_SOFT_OVER_WR 0x0E
#define IOPB_RES_ADDR_F 0x0F
#define IOPB_MEM_CFG 0x10
-#define IOPB_RES_ADDR_11 0x11
-#define IOPB_RES_ADDR_12 0x12
+#define IOPB_GPIO_CNTL 0x11
+#define IOPB_GPIO_DATA 0x12
#define IOPB_RES_ADDR_13 0x13
#define IOPB_FLASH_PAGE 0x14
#define IOPB_RES_ADDR_15 0x15
#define IOPB_RES_ADDR_35 0x35
#define IOPB_RES_ADDR_36 0x36
#define IOPB_RES_ADDR_37 0x37
-#define IOPB_RES_ADDR_38 0x38
-#define IOPB_RES_ADDR_39 0x39
+#define IOPB_RAM_BIST 0x38
+#define IOPB_PLL_TEST 0x39
#define IOPB_RES_ADDR_3A 0x3A
#define IOPB_RES_ADDR_3B 0x3B
#define IOPB_RFIFO_CNT 0x3C
#define IOPDW_RES_ADDR_8 0x08
#define IOPDW_RES_ADDR_C 0x0C
#define IOPDW_RES_ADDR_10 0x10
-#define IOPDW_RES_ADDR_14 0x14
-#define IOPDW_RES_ADDR_18 0x18
+#define IOPDW_COMMA 0x14
+#define IOPDW_COMMB 0x18
#define IOPDW_RES_ADDR_1C 0x1C
#define IOPDW_SDMA_ADDR0 0x20
#define IOPDW_SDMA_ADDR1 0x24
#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
+#define ADV_TICKLE_NOP 0x00
+#define ADV_TICKLE_A 0x01
+#define ADV_TICKLE_B 0x02
+#define ADV_TICKLE_C 0x03
+
#define ADV_SCSI_CTRL_RSTOUT 0x2000
-#define AdvIsIntPending(port) \
+#define AdvIsIntPending(port) \
(AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
/*
#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
+/*
+ * Addendum for ASC-38C0800 Chip
+ */
+#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
+#define HVD 0x1000 /* HVD Device Detect */
+#define LVD 0x0800 /* LVD Device Detect */
+#define SE 0x0400 /* SE Device Detect */
+#define TERM_LVD 0x00C0 /* LVD Termination Bits */
+#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
+#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
+#define TERM_SE 0x0030 /* SE Termination Bits */
+#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
+#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
+#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
+#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
+#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
+#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
+#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
+#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
+
+
#define CABLE_ILLEGAL_A 0x7
/* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
#define CABLE_ILLEGAL_B 0xB
/* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
-/*
- The following table details the SCSI_CFG1 Termination Polarity,
- Termination Control and Cable Detect bits.
-
- Cable Detect | Termination
- Bit 3 2 1 0 | 5 4 | Notes
- _____________|________|____________________
- 1 1 1 0 | on on | Internal wide only
- 1 1 0 1 | on on | Internal narrow only
- 1 0 1 1 | on on | External narrow only
- 0 x 1 1 | on on | External wide only
- 1 1 0 0 | on off| Internal wide and internal narrow
- 1 0 1 0 | on off| Internal wide and external narrow
- 0 x 1 0 | off off| Internal wide and external wide
- 1 0 0 1 | on off| Internal narrow and external narrow
- 0 x 0 1 | on off| Internal narrow and external wide
- 1 1 1 1 | on on | No devices are attached
- x 0 0 0 | on on | Illegal (all 3 connectors are used)
- 0 x 0 0 | on on | Illegal (all 3 connectors are used)
-
- x means don't-care (either '0' or '1')
-
- If term_pol (bit 13) is '0' (active-low terminator enable), then:
- 'on' is '0' and 'off' is '1'.
-
- If term_pol bit is '1' (meaning active-hi terminator enable), then:
- 'on' is '1' and 'off' is '0'.
- */
-
/*
* MEM_CFG Register bit definitions
*/
#define READ_CMD_MRL 0x02 /* Memory Read Long */
#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
+/*
+ * ASC-38C0800 RAM BIST Register bit definitions
+ */
+#define RAM_TEST_MODE 0x80
+#define PRE_TEST_MODE 0x40
+#define NORMAL_MODE 0x00
+#define RAM_TEST_DONE 0x10
+#define RAM_TEST_STATUS 0x0F
+#define RAM_TEST_HOST_ERROR 0x08
+#define RAM_TEST_INTRAM_ERROR 0x04
+#define RAM_TEST_RISC_ERROR 0x02
+#define RAM_TEST_SCSI_ERROR 0x01
+#define RAM_TEST_SUCCESS 0x00
+#define PRE_TEST_VALUE 0x05
+#define NORMAL_VALUE 0x00
+
/* a_advlib.h */
/*
/*
* ASC_DVC_VAR 'warn_code' values
*/
+#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
*/
#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */
+#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
/*
* Fixed locations of microcode operating variables.
#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
-#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */
-#define ASC_MC_STACK_END 0x0030 /* microcode stack end */
#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
-#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */
#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
-#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */
-#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */
-#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */
-#define ASC_MC_ULTRA_ABLE 0x009C
+#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CHIP_TYPE 0x009A
+#define ASC_MC_INTRB_CODE 0x009B
+#define ASC_MC_WDTR_ABLE 0x009C
#define ASC_MC_SDTR_ABLE 0x009E
#define ASC_MC_TAGQNG_ABLE 0x00A0
#define ASC_MC_DISC_ENABLE 0x00A2
+#define ASC_MC_IDLE_CMD_STATUS 0x00A4
#define ASC_MC_IDLE_CMD 0x00A6
-#define ASC_MC_IDLE_PARA_STAT 0x00A8
+#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
-#define ASC_MC_RISC_NEXT_READY 0x00B4
-#define ASC_MC_RISC_NEXT_DONE 0x00B5
#define ASC_MC_SDTR_DONE 0x00B6
#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
-#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */
#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
#define ASC_MC_WDTR_DONE 0x0124
-#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */
-#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */
+#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_ICQ 0x0160
+#define ASC_MC_IRQ 0x0164
/*
* BIOS LRAM variable absolute offsets.
#define BIOS_CODELEN 0x56
#define BIOS_SIGNATURE 0x58
#define BIOS_VERSION 0x5A
-#define BIOS_SIGNATURE 0x58
/*
* Microcode Control Flags
#define HSHK_CFG_RATE 0x0F00
#define HSHK_CFG_OFFSET 0x001F
-/*
- * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
- *
- * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes
- * starting at LRAM address 0x1200 is 8 bytes and has the following
- * structure. Only 253 of these are actually used for command queues.
- */
-
-#define ASC_MC_RISC_Q_LIST_BASE 0x1200
-#define ASC_MC_RISC_Q_LIST_SIZE 0x0008
-#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */
-#define ASC_MC_RISC_Q_FIRST 0x0001
-#define ASC_MC_RISC_Q_LAST 0x00FF
-
#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
-/* RISC Queue List structure - 8 bytes */
-#define RQL_FWD 0 /* forward pointer (1 byte) */
-#define RQL_BWD 1 /* backward pointer (1 byte) */
-#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */
-#define RQL_TID 3 /* request target id (1 byte) */
-#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */
-
-/* RISC Queue List state values */
-#define ASC_MC_QS_FREE 0x00
-#define ASC_MC_QS_READY 0x01
-#define ASC_MC_QS_DONE 0x40
-#define ASC_MC_QS_ABORTED 0x80
+#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+
+#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
+/*
+ * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
+ * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
+ */
+#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+
+typedef struct adv_carr_t
+{
+ ulong carr_va; /* Carrier Virtual Address */
+ ulong carr_pa; /* Carrier Physical Address */
+ ulong areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+ /*
+ * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
+ *
+ * next_vpa [3:1] Reserved Bits
+ * next_vpa [0] Done Flag set in Response Queue.
+ */
+ ulong next_vpa;
+} ADV_CARR_T;
+
+/*
+ * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
+ */
+#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
-/* RISC Queue List pointer values */
-#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */
-#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */
+#define ASC_RQ_DONE 0x00000001
+#define ASC_CQ_STOPPER 0x00000000
-/* ASC_SCSI_REQ_Q 'cntl' field values */
-#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */
-#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */
-#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */
-#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */
-#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */
-#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */
+#define ASC_GET_CARRP(carrp) ((ADV_CARR_T *) ((carrp) & ASC_NEXT_VPA_MASK))
+#define ADV_PAGE_SIZE 4096 /* Assume 4KB page size. */
+
+#define ADV_CARRIER_NUM_PAGE_CROSSING \
+ (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
+ (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+#define ADV_CARRIER_BUFSIZE \
+ ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
/*
* ASC_SCSI_REQ_Q 'a_flag' definitions
*/
#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
#define ADV_SCSIQ_DONE 0x02 /* request done */
+#define ADV_DONT_RETRY 0x08 /* don't do retry */
+
+#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
/*
* Adapter temporary configuration structure
ushort pci_slot_info; /* high byte device/function number */
/* bits 7-3 device num., bits 2-0 function num. */
/* low byte bus num. */
- ushort bios_boot_wait; /* BIOS boot time delay */
ushort serial1; /* EEPROM serial number word 1 */
ushort serial2; /* EEPROM serial number word 2 */
ushort serial3; /* EEPROM serial number word 3 */
} ADV_DVC_CFG;
+struct adv_dvc_var;
+struct adv_scsi_req_q;
+
+typedef void (* ADV_ISR_CALLBACK)
+ (struct adv_dvc_var *, struct adv_scsi_req_q *);
+
+typedef void (* ADV_ASYNC_CALLBACK)
+ (struct adv_dvc_var *, uchar);
+
/*
* Adapter operation variable structure.
*
AdvPortAddr iop_base; /* I/O port address */
ushort err_code; /* fatal error code */
ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
- Ptr2Func isr_callback; /* pointer to function, called in AdvISR() */
- Ptr2Func sbreset_callback; /* pointer to function, called in AdvISR() */
+ ADV_ISR_CALLBACK isr_callback;
+ ADV_ASYNC_CALLBACK async_callback;
ushort wdtr_able; /* try WDTR for a device */
ushort sdtr_able; /* try SDTR for a device */
ushort ultra_able; /* try SDTR Ultra speed for a device */
+ ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
+ ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
+ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
+ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
ushort tagqng_able; /* try tagged queuing with a device */
uchar max_dvc_qng; /* maximum number of tagged commands per device */
ushort start_motor; /* start motor command allowed */
uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
uchar chip_no; /* should be assigned by caller */
uchar max_host_qng; /* maximum number of Q'ed command allowed */
- uchar cur_host_qng; /* total number of queue command */
uchar irq_no; /* IRQ number */
ushort no_scam; /* scam_tolerant of EEPROM */
- ushort idle_cmd_done; /* microcode idle command done set by AdvISR() */
ulong drv_ptr; /* driver pointer to private structure */
uchar chip_scsi_id; /* chip SCSI target ID */
+ uchar chip_type;
+ uchar bist_err_code;
+ ADV_CARR_T *carrier_buf;
+ ADV_CARR_T *carr_freelist; /* Carrier free list. */
+ ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
+ ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
+ ushort carr_pending_cnt; /* Count of pending carriers. */
/*
* Note: The following fields will not be used after initialization. The
* driver may discard the buffer after initialization is done.
typedef struct asc_sg_block {
uchar reserved1;
uchar reserved2;
- uchar first_entry_no; /* starting entry number */
- uchar last_entry_no; /* last entry number */
+ uchar reserved3;
+ uchar sg_cnt; /* Valid entries in block. */
struct asc_sg_block *sg_ptr; /* links to the next sg block */
struct {
- ulong sg_addr; /* SG element address */
- ulong sg_count; /* SG element count */
+ ulong sg_addr; /* SG element address. */
+ ulong sg_count; /* SG element count. */
} sg_list[NO_OF_SG_PER_BLOCK];
} ADV_SG_BLOCK;
/*
- * ASC_SCSI_REQ_Q - microcode request structure
+ * ADV_SCSI_REQ_Q - microcode request structure
*
* All fields in this structure up to byte 60 are used by the microcode.
* The microcode makes assumptions about the size and ordering of fields
*/
typedef struct adv_scsi_req_q {
uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
- uchar sg_entry_cnt; /* SG element count. Zero for no SG. */
+ uchar reserved;
uchar target_id; /* Device target identifier. */
uchar target_lun; /* Device target logical unit number. */
ulong data_addr; /* Data buffer physical address. */
ulong data_cnt; /* Data count. Ucode sets to residual. */
- ulong sense_addr; /* Sense buffer physical address. */
- ulong srb_ptr; /* Driver request pointer. */
- uchar a_flag; /* Adv Library flag field. */
- uchar sense_len; /* Auto-sense length. Ucode sets to residual. */
+ ulong sense_addr;
+ ulong carr_pa;
+ uchar mflag;
+ uchar sense_len;
uchar cdb_len; /* SCSI CDB length. */
- uchar tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */
+ uchar scsi_cntl;
uchar done_status; /* Completion status. */
uchar scsi_status; /* SCSI status byte. */
uchar host_status; /* Ucode host status. */
- uchar ux_sg_ix; /* Ucode working SG variable. */
+ uchar sg_working_ix;
uchar cdb[12]; /* SCSI command block. */
ulong sg_real_addr; /* SG list physical address. */
- struct adv_scsi_req_q *free_scsiq_link;
- ulong ux_wk_data_cnt; /* Saved data count at disconnection. */
+ ulong scsiq_rptr;
+ ulong sg_working_data_cnt;
struct adv_scsi_req_q *scsiq_ptr;
- ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+ ulong carr_va;
/*
* End of microcode structure - 60 bytes. The rest of the structure
* is used by the Adv Library and ignored by the microcode.
*/
- ulong vsense_addr; /* Sense buffer virtual address. */
+ ulong srb_ptr;
+ ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
ulong vdata_addr; /* Data buffer virtual address. */
- uchar orig_sense_len; /* Original length of sense buffer. */
-} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */
+ uchar a_flag;
+} ADV_SCSI_REQ_Q;
/*
* Microcode idle loop commands
#define IDLE_CMD_SEND_INT 0x0004
#define IDLE_CMD_ABORT 0x0008
#define IDLE_CMD_DEVICE_RESET 0x0010
-#define IDLE_CMD_SCSI_RESET 0x0020
+#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSIREQ 0x0080
+
+#define IDLE_CMD_STATUS_SUCCESS 0x0001
+#define IDLE_CMD_STATUS_FAILURE 0x0002
/*
* AdvSendIdleCmd() flag definitions.
/*
* Wait loop time out values.
*/
-#define SCSI_WAIT_10_SEC 10 /* 10 seconds */
-#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */
+#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
+#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
+#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
+#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
+#define SCSI_MAX_RETRY 10 /* retry count */
+
+#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+
+#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
/*
* Device drivers must define the following functions.
STATIC int AdvISR(ADV_DVC_VAR *);
STATIC int AdvInitGetConfig(ADV_DVC_VAR *);
STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *);
-STATIC int AdvResetSB(ADV_DVC_VAR *);
+STATIC int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+STATIC int AdvResetChipAndSB(ADV_DVC_VAR *);
+STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc);
/*
* Internal Adv Library functions.
*/
-STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int);
-STATIC void AdvResetChip(ADV_DVC_VAR *);
-STATIC int AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong);
STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int AdvInitFromEEP(ADV_DVC_VAR *);
-STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
-STATIC void AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC int AdvInitFrom3550EEP(ADV_DVC_VAR *);
+STATIC int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
STATIC void AdvWaitEEPCmd(AdvPortAddr);
STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
-STATIC void AdvResetSCSIBus(ADV_DVC_VAR *);
/*
* PCI Bus Definitions
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
/* Read byte from a register. */
-#define AdvReadByteRegister(iop_base, reg_off) \
- (inp((iop_base) + (reg_off)))
+#define AdvReadByteRegister(iop_base, reg_off) (inp((iop_base) + (reg_off)))
/* Write byte to a register. */
-#define AdvWriteByteRegister(iop_base, reg_off, byte) \
- (outp((iop_base) + (reg_off), (byte)))
+#define AdvWriteByteRegister(iop_base, reg_off, byte) (outp((iop_base) + (reg_off), (byte)))
/* Read word (2 bytes) from a register. */
-#define AdvReadWordRegister(iop_base, reg_off) \
- (inpw((iop_base) + (reg_off)))
+#define AdvReadWordRegister(iop_base, reg_off) (inpw((iop_base) + (reg_off)))
/* Write word (2 bytes) to a register. */
-#define AdvWriteWordRegister(iop_base, reg_off, word) \
- (outpw((iop_base) + (reg_off), (word)))
+#define AdvWriteWordRegister(iop_base, reg_off, word) (outpw((iop_base) + (reg_off), (word)))
/* Read byte from LRAM. */
#define AdvReadByteLram(iop_base, addr, byte) \
* ADV_TRUE(1) - Queue was successfully aborted.
* ADV_FALSE(0) - Queue was not found on the active queue list.
*/
-#define AdvAbortSRB(asc_dvc, srb_ptr) \
- AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
- (ulong) (srb_ptr), 0)
+#define AdvAbortQueue(asc_dvc, scsiq) \
+ AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+ (ulong) (scsiq))
/*
* Send a Bus Device Reset Message to the specified target ID.
*/
#define AdvResetDevice(asc_dvc, target_id) \
AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
- (ulong) (target_id), 0)
+ (ulong) (target_id))
/*
* SCSI Wide Type definition.
#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
#define QHSTA_M_WTM_TIMEOUT 0x41
#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
-typedef int (* ADV_ISR_CALLBACK)
- (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-
-typedef int (* ADV_SBRESET_CALLBACK)
- (ADV_DVC_VAR *);
/*
* Default EEPROM Configuration structure defined in a_init.c.
*/
-extern ADVEEP_CONFIG Default_EEPROM_Config;
+extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
+extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
/*
* DvcGetPhyAddr() flag arguments
#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
/* Return the address that is aligned at the next doubleword >= to 'addr'. */
#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3)
+#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
/*
* Total contiguous memory needed for driver SG blocks.
#define ADV_ASSERT(a)
#endif /* ADV_ASSERT */
+typedef struct {
+ uchar peri_dvc_type : 5; /* peripheral device type */
+ uchar peri_qualifier : 3; /* peripheral qualifier */
+ uchar dvc_type_modifier : 7; /* device type modifier (for SCSI I) */
+ uchar rmb : 1; /* RMB - removable medium bit */
+ uchar ansi_apr_ver : 3; /* ANSI approved version */
+ uchar ecma_ver : 3; /* ECMA version */
+ uchar iso_ver : 2; /* ISO version */
+ uchar rsp_data_fmt : 4; /* response data format */
+ /* 0 SCSI 1 */
+ /* 1 CCS */
+ /* 2 SCSI-2 */
+ /* 3-F reserved */
+ uchar res1 : 2; /* reserved */
+ uchar TemIOP : 1; /* terminate I/O process bit (see 5.6.22) */
+ uchar aenc : 1; /* asynch. event notification (processor) */
+ uchar add_len; /* additional length */
+ uchar res2; /* reserved */
+ uchar res3; /* reserved */
+ uchar StfRe : 1; /* soft reset implemented */
+ uchar CmdQue : 1; /* command queuing */
+ uchar res4 : 1; /* reserved */
+ uchar Linked : 1; /* linked command for this logical unit */
+ uchar Sync : 1; /* synchronous data transfer */
+ uchar WBus16 : 1; /* wide bus 16 bit data transfer */
+ uchar WBus32 : 1; /* wide bus 32 bit data transfer */
+ uchar RelAdr : 1; /* relative addressing mode */
+ uchar vendor_id[8]; /* vendor identification */
+ uchar product_id[16]; /* product identification */
+ uchar product_rev_level[4]; /* product revision level */
+ uchar vendor_specific[20]; /* vendor specific */
+ uchar IUS : 1; /* information unit supported */
+ uchar QAS : 1; /* quick arbitrate supported */
+ uchar Clocking : 2; /* clocking field */
+ uchar res5 : 4; /* reserved */
+ uchar res6; /* reserved */
+} ADV_SCSI_INQUIRY; /* 58 bytes */
+
/*
* --- Driver Constants and Macros
* are not used when the driver is built as a module, cf. linux/init.h.
*/
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
+#define ASC_INITFUNC(type, func) type func
#define ASC_INITDATA
#define ASC_INIT
#else /* version >= v2.1.23 */
-#define ASC_INITDATA __initdata
-#define ASC_INIT __init
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16)
+#define ASC_INITFUNC(type, func) __initfunc(type func)
+#else /* version >= v2.3.16 */
+#define ASC_INITFUNC(type, func) type __init func
+#endif /* version >= v2.3.16 */
+#define ASC_INITDATA __initdata
+#define ASC_INIT __init
#endif /* version >= v2.1.23 */
#define ASC_INFO_SIZE 128 /* advansys_info() line size */
#define PCI_MAX_BUS 0xFF
#define PCI_IOADDRESS_MASK 0xFFFE
#define ASC_PCI_VENDORID 0x10CD
-#define ASC_PCI_DEVICE_ID_CNT 4 /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT 5 /* PCI Device ID count. */
#define ASC_PCI_DEVICE_ID_1100 0x1100
#define ASC_PCI_DEVICE_ID_1200 0x1200
#define ASC_PCI_DEVICE_ID_1300 0x1300
-#define ASC_PCI_DEVICE_ID_2300 0x2300
+#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */
+#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */
/* PCI IO Port Addresses to generate special cycle */
ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
Scsi_Device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
-#if ASC_QUEUE_FLOW_CONTROL
- ushort nerrcnt[ADV_MAX_TID+1]; /* No error request count */
-#endif /* ASC_QUEUE_FLOW_CONTROL */
ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
union {
- ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
- ADVEEP_CONFIG adv_eep; /* Wide EEPROM config. */
+ ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
+ ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
+ ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
} eep_config;
ulong last_reset; /* Saved last reset time */
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
*/
void *ioremap_addr; /* I/O Memory remap address. */
ushort ioport; /* I/O Port address. */
+ ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
adv_req_t *orig_reqp; /* adv_req_t memory block. */
adv_req_t *adv_reqp; /* Request structures. */
adv_sgblk_t *orig_sgblkp; /* adv_sgblk_t memory block. */
* 16 elements of each structure. v1.3.0 kernels will probably
* not need any more than this number.
*/
+uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 };
uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
#endif /* version >= v1,3,0 */
STATIC int adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void adv_async_callback(ADV_DVC_VAR *, uchar);
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
STATIC int asc_srch_pci_dev(PCI_DEVICE *);
STATIC int asc_prt_line(char *, int, char *fmt, ...);
#endif /* version >= v1.3.0 */
-/* Declaration for Asc Library internal functions reference by driver. */
+/* Declaration for Asc Library internal functions referenced by driver. */
STATIC int AscFindSignature(PortAddr);
STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
int hostno, int inout)
{
#ifdef CONFIG_PROC_FS
-
struct Scsi_Host *shp;
asc_board_t *boardp;
int i;
#else /* CONFIG_PROC_FS */
return 0;
#endif /* CONFIG_PROC_FS */
-
}
#endif /* version >= v1.3.0 */
+
/*
* advansys_detect()
*
* it must not call SCSI mid-level functions including scsi_malloc()
* and scsi_free().
*/
-int ASC_INIT
+ASC_INITFUNC(
+int,
advansys_detect(Scsi_Host_Template *tpnt)
+)
{
static int detect_called = ASC_FALSE;
int iop;
int bus;
- struct Scsi_Host *shp;
- asc_board_t *boardp;
+ struct Scsi_Host *shp = NULL;
+ asc_board_t *boardp = NULL;
ASC_DVC_VAR *asc_dvc_varp = NULL;
ADV_DVC_VAR *adv_dvc_varp = NULL;
int ioport = 0;
int share_irq = FALSE;
+ int iolen = 0;
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
+ int pci_init_search = 0;
+ PCI_DEVICE pci_device[ASC_NUM_BOARD_SUPPORTED];
+ int pci_card_cnt_max = 0;
+ int pci_card_cnt = 0;
PCI_DEVICE pciDevice;
PCI_CONFIG_SPACE pciConfig;
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
#endif /* ASC_CONFIG_PCI */
#else /* version >= v2.1.93 */
#ifdef CONFIG_PCI
+ int pci_init_search = 0;
+ struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+ int pci_card_cnt_max = 0;
+ int pci_card_cnt = 0;
struct pci_dev *pci_devp = NULL;
int pci_device_id_cnt = 0;
unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
ASC_PCI_DEVICE_ID_1100,
ASC_PCI_DEVICE_ID_1200,
ASC_PCI_DEVICE_ID_1300,
- ASC_PCI_DEVICE_ID_2300
+ ASC_PCI_DEVICE_ID_2300,
+ ASC_PCI_DEVICE_ID_2500
};
unsigned long pci_memory_address;
#endif /* CONFIG_PCI */
(AscGetChipVersion(iop, ASC_IS_ISA) &
ASC_CHIP_VER_ISA_BIT) == 0) {
/*
- * Don't clear 'asc_ioport[ioport]'. Try
- * this board again for VL. Increment
- * 'ioport' past this board.
- */
+ * Don't clear 'asc_ioport[ioport]'. Try
+ * this board again for VL. Increment
+ * 'ioport' past this board.
+ */
ioport++;
goto ioport_try_again;
}
iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
break;
+ case ASC_IS_PCI:
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
- case ASC_IS_PCI:
- if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
+ if (pci_init_search == 0) {
+ int i, j;
+
+ pci_init_search = 1;
+
+ /* Find all PCI cards. */
+ while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) {
+ pci_device[pci_card_cnt_max++] = pciDevice;
+ }
+
+ /*
+ * Sort PCI cards in ascending order by PCI Bus, Slot,
+ * and Device Number.
+ */
+ for (i = 0; i < pci_card_cnt_max - 1; i++)
+ {
+ for (j = i + 1; j < pci_card_cnt_max; j++) {
+ if ((pci_device[j].busNumber <
+ pci_device[i].busNumber) ||
+ ((pci_device[j].busNumber ==
+ pci_device[i].busNumber) &&
+ (pci_device[j].slotNumber <
+ pci_device[i].slotNumber)) ||
+ ((pci_device[j].busNumber ==
+ pci_device[i].busNumber) &&
+ (pci_device[j].slotNumber ==
+ pci_device[i].slotNumber) &&
+ (pci_device[j].devFunc <
+ pci_device[i].devFunc))) {
+ pciDevice = pci_device[i];
+ pci_device[i] = pci_device[j];
+ pci_device[j] = pciDevice;
+ }
+ }
+ }
+
+ pci_card_cnt = 0;
+ } else {
+ pci_card_cnt++;
+ }
+
+ if (pci_card_cnt == pci_card_cnt_max) {
iop = 0;
} else {
+ pciDevice = pci_device[pci_card_cnt];
ASC_DBG2(2,
"advansys_detect: slotFound %d, busNumber %d\n",
pciDevice.slotFound, pciDevice.busNumber);
#endif /* ASC_CONFIG_PCI */
#else /* version >= v2.1.93 */
#ifdef CONFIG_PCI
- case ASC_IS_PCI:
- while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
- if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
- pci_device_id[pci_device_id_cnt], pci_devp)) == NULL) {
- pci_device_id_cnt++;
- } else {
- break;
+ if (pci_init_search == 0) {
+ int i, j;
+
+ pci_init_search = 1;
+
+ /* Find all PCI cards. */
+ while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
+ if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+ pci_device_id[pci_device_id_cnt], pci_devp)) ==
+ NULL) {
+ pci_device_id_cnt++;
+ } else {
+ pci_devicep[pci_card_cnt_max++] = pci_devp;
+ }
+ }
+
+ /*
+ * Sort PCI cards in ascending order by PCI Bus, Slot,
+ * and Device Number.
+ */
+ for (i = 0; i < pci_card_cnt_max - 1; i++)
+ {
+ for (j = i + 1; j < pci_card_cnt_max; j++) {
+ if ((pci_devicep[j]->bus->number <
+ pci_devicep[i]->bus->number) ||
+ ((pci_devicep[j]->bus->number ==
+ pci_devicep[i]->bus->number) &&
+ (pci_devicep[j]->devfn <
+ pci_devicep[i]->devfn))) {
+ pci_devp = pci_devicep[i];
+ pci_devicep[i] = pci_devicep[j];
+ pci_devicep[j] = pci_devp;
+ }
+ }
}
+
+ pci_card_cnt = 0;
+ } else {
+ pci_card_cnt++;
}
- if (pci_devp == NULL) {
+
+ if (pci_card_cnt == pci_card_cnt_max) {
iop = 0;
} else {
+ pci_devp = pci_devicep[pci_card_cnt];
+
ASC_DBG2(2,
"advansys_detect: devfn %d, bus number %d\n",
pci_devp->devfn, pci_devp->bus->number);
- iop = pci_devp->resource[0].start;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+ iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
+#else /* version >= v2.3.13 */
+ iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK;
+#endif /* version >= v2.3.13 */
ASC_DBG2(1,
"advansys_detect: vendorID %X, deviceID %X\n",
pci_devp->vendor, pci_devp->device);
ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
iop, pci_devp->irq);
}
- break;
#endif /* CONFIG_PCI */
#endif /* version >= v2.1.93 */
+ break;
default:
ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
if (asc_bus[bus] == ASC_IS_PCI &&
- pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) {
+ (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 ||
+ pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500))
+ {
boardp->flags |= ASC_IS_WIDE_BOARD;
}
#endif /* ASC_CONFIG_PCI */
#else /* version >= v2.1.93 */
#ifdef CONFIG_PCI
if (asc_bus[bus] == ASC_IS_PCI &&
- pci_devp->device == ASC_PCI_DEVICE_ID_2300) {
+ (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
+ pci_devp->device == ASC_PCI_DEVICE_ID_2500))
+ {
boardp->flags |= ASC_IS_WIDE_BOARD;
}
#endif /* CONFIG_PCI */
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
adv_dvc_varp->drv_ptr = (ulong) boardp;
adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
- adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback;
+ adv_dvc_varp->isr_callback = adv_isr_callback;
+ adv_dvc_varp->async_callback = adv_async_callback;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
+ if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300)
+ {
+ ASC_DBG(1, "advansys_detect: ASC-3550\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+ } else
+ {
+ ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+ }
+#endif /* ASC_CONFIG_PCI */
+#else /* version >= v2.1.93 */
+#ifdef CONFIG_PCI
+ if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+ {
+ ASC_DBG(1, "advansys_detect: ASC-3550\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+ } else
+ {
+ ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+ }
+#endif /* CONFIG_PCI */
+#endif /* version >= v2.1.93 */
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
adv_dvc_varp->iop_base = iop;
* PCI register base address will not cross a page
* boundary.
*/
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ iolen = ADV_3550_IOLEN;
+ } else {
+ iolen = ADV_38C0800_IOLEN;
+ }
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
pci_memory_address = pciConfig.baseAddress[1];
+ ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+ pci_memory_address);
if ((boardp->ioremap_addr =
ioremap(pci_memory_address & PAGE_MASK,
PAGE_SIZE)) == 0) {
ASC_PRINT3(
"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
- boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+ boardp->id, pci_memory_address, iolen);
scsi_unregister(shp);
asc_board_count--;
continue;
}
+ ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+ (ulong) boardp->ioremap_addr);
adv_dvc_varp->iop_base = (AdvPortAddr)
(boardp->ioremap_addr +
(pci_memory_address - (pci_memory_address & PAGE_MASK)));
+ ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+ adv_dvc_varp->iop_base);
#endif /* ASC_CONFIG_PCI */
#else /* version >= v2.1.93 */
#ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+ pci_memory_address = pci_devp->base_address[1];
+#else /* version >= v2.3.13 */
pci_memory_address = pci_devp->resource[1].start;
+#endif /* version >= v2.3.13 */
+ ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+ pci_memory_address);
if ((boardp->ioremap_addr =
ioremap(pci_memory_address & PAGE_MASK,
PAGE_SIZE)) == 0) {
ASC_PRINT3(
"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
- boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+ boardp->id, pci_memory_address, iolen);
scsi_unregister(shp);
asc_board_count--;
continue;
}
+ ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+ (ulong) boardp->ioremap_addr);
adv_dvc_varp->iop_base = (AdvPortAddr)
(boardp->ioremap_addr +
(pci_memory_address - (pci_memory_address & PAGE_MASK)));
+ ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+ adv_dvc_varp->iop_base);
#endif /* CONFIG_PCI */
#endif /* version >= v2.1.93 */
#endif /* version >= v1,3,0 */
* displayed.
*/
boardp->ioport = iop;
+
+ ASC_DBG2(1, "iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
+ (ushort) inp(iop + 1), (ushort) inpw(iop));
}
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
adv_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pciDevice.busNumber,
- pciDevice.slotFound,
- pciDevice.devFunc);
+ ASC_PCI_MKID(pciDevice.busNumber,
+ pciDevice.slotFound,
+ pciDevice.devFunc);
shp->unchecked_isa_dma = FALSE;
share_irq = TRUE;
#endif /* ASC_CONFIG_PCI */
shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
adv_dvc_varp->cfg->pci_device_id = pci_devp->device;
adv_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pci_devp->bus->number,
- PCI_SLOT(pci_devp->devfn),
- PCI_FUNC(pci_devp->devfn));
+ ASC_PCI_MKID(pci_devp->bus->number,
+ PCI_SLOT(pci_devp->devfn),
+ PCI_FUNC(pci_devp->devfn));
shp->unchecked_isa_dma = FALSE;
share_irq = TRUE;
#endif /* CONFIG_PCI */
* longer be used. If the bus_type field must be
* referenced only use the bit-wise AND operator "&".
*/
- ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+ ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
switch(ret = AscInitGetConfig(asc_dvc_varp)) {
case 0: /* No error */
break;
shp->irq = asc_dvc_varp->irq_no;
}
} else {
-
- ADVEEP_CONFIG *ep;
+ ADVEEP_3550_CONFIG *ep_3550;
+ ADVEEP_38C0800_CONFIG *ep_38C0800;
/*
* Save Wide EEP Configuration Information.
*/
- ep = &boardp->eep_config.adv_eep;
-
- ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
- ep->max_host_qng = adv_dvc_varp->max_host_qng;
- ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
- ep->termination = adv_dvc_varp->cfg->termination;
- ep->disc_enable = adv_dvc_varp->cfg->disc_enable;
- ep->bios_ctrl = adv_dvc_varp->bios_ctrl;
- ep->wdtr_able = adv_dvc_varp->wdtr_able;
- ep->sdtr_able = adv_dvc_varp->sdtr_able;
- ep->ultra_able = adv_dvc_varp->ultra_able;
- ep->tagqng_able = adv_dvc_varp->tagqng_able;
- ep->start_motor = adv_dvc_varp->start_motor;
- ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
- ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait;
- ep->serial_number_word1 = adv_dvc_varp->cfg->serial1;
- ep->serial_number_word2 = adv_dvc_varp->cfg->serial2;
- ep->serial_number_word3 = adv_dvc_varp->cfg->serial3;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+ ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+ ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep_3550->termination = adv_dvc_varp->cfg->termination;
+ ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+ ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+ ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+ ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_3550->start_motor = adv_dvc_varp->start_motor;
+ ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+ ep_3550->serial_number_word1 =
+ adv_dvc_varp->cfg->serial1;
+ ep_3550->serial_number_word2 =
+ adv_dvc_varp->cfg->serial2;
+ ep_3550->serial_number_word3 =
+ adv_dvc_varp->cfg->serial3;
+ } else
+ {
+ ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+ ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+ ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep_38C0800->termination_lvd =
+ adv_dvc_varp->cfg->termination;
+ ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
+ ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+ ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+ ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+ ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+ ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+ ep_38C0800->scsi_reset_delay =
+ adv_dvc_varp->scsi_reset_wait;
+ ep_38C0800->serial_number_word1 =
+ adv_dvc_varp->cfg->serial1;
+ ep_38C0800->serial_number_word2 =
+ adv_dvc_varp->cfg->serial2;
+ ep_38C0800->serial_number_word3 =
+ adv_dvc_varp->cfg->serial3;
+ }
/*
* Set the adapter's target id bit in the 'init_tidmask' field.
* Memory Mapped I/O.
*/
shp->io_port = iop;
- shp->n_io_port = ADV_CONDOR_IOLEN;
+ shp->n_io_port = iolen;
shp->this_id = adv_dvc_varp->chip_scsi_id;
warn_code, err_code);
}
} else {
+ ADV_CARR_T *carrp;
int req_cnt;
adv_req_t *reqp = NULL;
- int sg_cnt;
+ int sg_cnt = 0;
adv_sgblk_t *sgp = NULL;
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+ carrp = (ADV_CARR_T *) &adv_carr_buf[0];
req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
reqp = (adv_req_t *) &adv_req_buf[0];
sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
#else /* version >= v1.3.0 */
+ /*
+ * Allocate buffer carrier structures.
+ */
+ carrp =
+ (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+ ASC_DBG1(1, "advansys_detect: carrp %x\n", (unsigned) carrp);
+
+ if (carrp == NULL) {
+ goto kmalloc_error;
+ }
+
/*
* Allocate up to 'max_host_qng' request structures for
* the Wide board.
break;
}
}
+ if (reqp == NULL)
+ {
+ goto kmalloc_error;
+ }
/*
* Allocate up to ADV_TOT_SG_LIST request structures for
break;
}
}
-#endif /* version >= v1.3.0 */
/*
* If no request structures or scatter-gather structures could
* be allocated, then return an error. Otherwise continue with
* initialization.
*/
- if (reqp == NULL) {
+ kmalloc_error:
+ if (carrp == NULL)
+ {
+ ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else if (reqp == NULL) {
+ kfree(carrp);
ASC_PRINT1(
"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
boardp->id);
err_code = ADV_ERROR;
} else if (sgp == NULL) {
+ kfree(carrp);
kfree(reqp);
ASC_PRINT1(
"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
err_code = ADV_ERROR;
} else {
+ /* Save carrier buffer pointer. */
+ boardp->orig_carrp = carrp;
+
/*
* Save original pointer for kfree() in case the
* driver is built as a module and can be unloaded.
*/
boardp->orig_reqp = reqp;
+ /*
+ * Save original pointer for kfree() in case the
+ * driver is built as a module and can be unloaded.
+ */
+ boardp->orig_sgblkp = sgp;
+#endif /* version >= v1.3.0 */
+
+ adv_dvc_varp->carrier_buf = carrp;
+
/*
* Point 'adv_reqp' to the request structures and
* link them together.
}
boardp->adv_reqp = &reqp[0];
- /*
- * Save original pointer for kfree() in case the
- * driver is built as a module and can be unloaded.
- */
- boardp->orig_sgblkp = sgp;
-
/*
* Point 'adv_sgblkp' to the request structures and
* link them together.
}
boardp->adv_sgblkp = &sgp[0];
- ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n");
- warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ ASC_DBG(2,
+ "advansys_detect: AdvInitAsc3550Driver()\n");
+ warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+ } else {
+ ASC_DBG(2,
+ "advansys_detect: AdvInitAsc38C0800Driver()\n");
+ warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
+ }
err_code = adv_dvc_varp->err_code;
if (warn_code || err_code) {
ASC_PRINT3(
-"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n",
+"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n",
boardp->id, warn_code, adv_dvc_varp->err_code);
}
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
}
+#endif /* version >= v1,3,0 */
}
if (err_code != 0) {
release_region(shp->io_port, shp->n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ if (ASC_WIDE_BOARD(boardp)) {
iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+ if (boardp->orig_carrp) {
+ kfree(boardp->orig_carrp);
+ boardp->orig_carrp = NULL;
+ }
if (boardp->orig_reqp) {
kfree(boardp->orig_reqp);
boardp->orig_reqp = boardp->adv_reqp = NULL;
boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
}
}
+#endif /* version >= v1,3,0 */
if (shp->dma_channel != NO_ISA_DMA) {
free_dma(shp->dma_channel);
}
free_dma(shp->dma_channel);
}
release_region(shp->io_port, shp->n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ if (ASC_WIDE_BOARD(boardp)) {
iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+ if (boardp->orig_carrp) {
+ kfree(boardp->orig_carrp);
+ boardp->orig_carrp = NULL;
+ }
if (boardp->orig_reqp) {
kfree(boardp->orig_reqp);
boardp->orig_reqp = boardp->adv_reqp = NULL;
boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
}
}
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
ASC_ASSERT(boardp->prtbuf != NULL);
kfree(boardp->prtbuf);
#endif /* version >= v1.3.0 */
ASC_DVC_VAR *asc_dvc_varp;
ADV_DVC_VAR *adv_dvc_varp;
char *busname;
+ int iolen;
+ char *widename = NULL;
boardp = ASC_BOARDP(shp);
if (ASC_NARROW_BOARD(boardp)) {
* I/O address is displayed through the driver /proc file.
*/
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ iolen = ADV_3550_IOLEN;
+ widename = "Ultra-Wide";
+ } else {
+ iolen = ADV_38C0800_IOLEN;
+ widename = "Ultra2-Wide";
+ }
if (boardp->bios_signature == 0x55AA) {
sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u",
ASC_VERSION,
+ widename,
boardp->bios_codeseg << 4,
boardp->bios_codelen > 0 ?
(boardp->bios_codelen << 9) - 1 : 0,
- (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1,
+ (unsigned) boardp->ioport, iolen - 1,
shp->irq);
} else {
sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u",
ASC_VERSION,
+ widename,
(unsigned) boardp->ioport,
- (ADV_CONDOR_IOLEN - 1),
+ (iolen - 1),
shp->irq);
}
}
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
scp->result = HOST_BYTE(DID_ABORT);
- /* sti(); - FIXME!!! Enable interrupts for AscAbortSRB() must be careful about io_lock. */
+ /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */
ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
(unsigned) scp);
switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
scp->result = HOST_BYTE(DID_ABORT);
- ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n",
+ ASC_DBG1(1, "advansys_abort: before AdvAbortQueue(), scp %x\n",
(unsigned) scp);
- switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) {
+#if 0 /* XXX */
+ switch (AdvAbortQueue(adv_dvc_varp, (ulong) XXX)) {
case ASC_TRUE:
/* asc_isr_callback() will be called */
- ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n");
+ ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n");
ret = SCSI_ABORT_PENDING;
break;
case ASC_FALSE:
/* Request has apparently already completed. */
- ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n");
+ ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n");
ret = SCSI_ABORT_NOT_RUNNING;
break;
case ASC_ERROR:
default:
- ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n");
+ ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n");
ret = SCSI_ABORT_ERROR;
break;
}
* been processed by calling AdvISR().
*/
(void) AdvISR(adv_dvc_varp);
+#else /* XXX */
+ (void) AdvResetChipAndSB(adv_dvc_varp);
+ ret = SCSI_ABORT_SUCCESS;
+#endif /* XXX */
}
/*
scp_found = asc_rmqueue(&boardp->done, scp);
ASC_ASSERT(scp_found == ASC_TRUE);
}
-
} else {
/*
* The command was not found on the active or waiting queues.
}
scp->result = HOST_BYTE(DID_ERROR);
ret = SCSI_RESET_ERROR;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
} else if (time_after_eq(jiffies, boardp->last_reset) &&
time_before(jiffies, boardp->last_reset + (10 * HZ))) {
+#else /* version < v2.1.0 */
+ } else if (jiffies >= boardp->last_reset &&
+ jiffies < (boardp->last_reset + (10 * HZ))) {
+#endif /* version < v2.1.0 */
/*
* Don't allow a reset to be attempted within 10 seconds
* of the last reset.
* Reset the target's SCSI bus.
*/
ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
- /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */
+ /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
status = AscResetSB(asc_dvc_varp);
- /* cli(); FIXME!!! */
+ /* cli(); XXX */
switch (status) {
case ASC_TRUE:
ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
ASC_DBG1(1,
"advansys_reset: before AscResetDevice(), target %d\n",
scp->target);
- /* sti(); FIXME!!! Enable interrupts for AscResetDevice(). */
+ /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */
status = AscResetDevice(asc_dvc_varp, scp->target);
- /* cli(); FIXME!!! */
+ /* cli(); XXX */
switch (status) {
case ASC_TRUE:
default:
ASC_DBG(1,
"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
- /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */
+ /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
status = AscResetSB(asc_dvc_varp);
- /* cli(); */
+ /* cli(); XXX */
switch (status) {
case ASC_TRUE:
ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
/*
* Reset the target's SCSI bus.
*/
- ASC_DBG(1, "advansys_reset: before AdvResetSB()\n");
- switch (AdvResetSB(adv_dvc_varp)) {
+ ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+ switch (AdvResetChipAndSB(adv_dvc_varp)) {
case ASC_TRUE:
- ASC_DBG(1, "advansys_reset: AdvResetSB() success\n");
+ ASC_DBG(1,
+ "advansys_reset: AdvResetChipAndSB() success\n");
ret = SCSI_RESET_SUCCESS;
break;
case ASC_FALSE:
default:
- ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n");
+ ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n");
ret = SCSI_RESET_ERROR;
break;
}
case ASC_FALSE:
default:
ASC_DBG(1,
-"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n");
+"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n");
- switch (AdvResetSB(adv_dvc_varp)) {
+ switch (AdvResetChipAndSB(adv_dvc_varp)) {
case ASC_TRUE:
- ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n");
+ ASC_DBG(1,
+ "advansys_reset: AdvResetChipAndSB() TRUE\n");
ret = SCSI_RESET_SUCCESS;
break;
case ASC_FALSE:
default:
- ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n");
+ ASC_DBG(1,
+ "advansys_reset: AdvResetChipAndSB() ERROR\n");
ret = SCSI_RESET_ERROR;
break;
}
* ints[2] - second argument
* ...
*/
-void ASC_INIT
+ASC_INITFUNC(
+void,
advansys_setup(char *str, int *ints)
+)
{
int i;
*/
boardp->reqcnt[scp->target]++;
-#if ASC_QUEUE_FLOW_CONTROL
- /*
- * Conditionally increment the device queue depth.
- *
- * If no error occurred and there have been 100 consecutive
- * successful requests and the current queue depth is less
- * than the maximum queue depth, then increment the current
- * queue depth.
- */
- if (boardp->nerrcnt[scp->target]++ > 100) {
- boardp->nerrcnt[scp->target] = 0;
- if (device != NULL &&
- (device->queue_curr_depth < device->queue_depth) &&
- (!(boardp->queue_full &
- ADV_TID_TO_TIDMASK(scp->target)) ||
- (boardp->queue_full_cnt[scp->target] >
- device->queue_curr_depth))) {
- device->queue_curr_depth++;
- }
- }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
asc_enqueue(&boardp->active, scp, ASC_BACK);
ASC_DBG(1,
"asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
case ASC_BUSY:
/* Caller must enqueue request and retry later. */
ASC_STATS(scp->host, exe_busy);
-#if ASC_QUEUE_FLOW_CONTROL
- /*
- * Clear consecutive no error counter and if possible decrement
- * queue depth.
- */
- boardp->nerrcnt[scp->target] = 0;
- if (device != NULL && device->queue_curr_depth > 1) {
- device->queue_curr_depth--;
- }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
break;
case ASC_ERROR:
ASC_PRINT2(
"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
boardp->id, asc_dvc_varp->err_code);
ASC_STATS(scp->host, exe_error);
-#if ASC_QUEUE_FLOW_CONTROL
- /* Clear consecutive no error counter. */
- boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
scp->result = HOST_BYTE(DID_ERROR);
asc_enqueue(&boardp->done, scp, ASC_BACK);
break;
"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
boardp->id, asc_dvc_varp->err_code);
ASC_STATS(scp->host, exe_unknown);
-#if ASC_QUEUE_FLOW_CONTROL
- /* Clear consecutive no error counter. */
- boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
scp->result = HOST_BYTE(DID_ERROR);
asc_enqueue(&boardp->done, scp, ASC_BACK);
break;
scsiqp->target_id = scp->target;
scsiqp->target_lun = scp->lun;
- scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0];
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
#else /* version >= v2.0.0 */
ADV_SG_BLOCK *sg_block; /* virtual address of a SG */
ulong sg_block_next_addr; /* block and its next */
ulong sg_block_physical_addr;
- int sg_block_index, i; /* how many SG entries */
+ int i;
struct scatterlist *slp;
int sg_elem_cnt;
sg_block_physical_addr);
scsiqp->sg_real_addr = sg_block_physical_addr;
- sg_block_index = 0;
do
{
- sg_block->first_entry_no = sg_block_index;
for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
{
sg_block->sg_list[i].sg_addr =
if (--sg_elem_cnt == 0)
{ /* last entry, get out */
- scsiqp->sg_entry_cnt = sg_block_index + i + 1;
- sg_block->last_entry_no = sg_block_index + i;
+ sg_block->sg_cnt = i + 1;
sg_block->sg_ptr = 0L; /* next link = NULL */
return ADV_SUCCESS;
}
slp++;
}
+ sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
sg_block_next_addr += sizeof(ADV_SG_BLOCK);
sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
sg_block_physical_addr);
- sg_block_index += NO_OF_SG_PER_BLOCK;
sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
- sg_block->last_entry_no = sg_block_index - 1;
sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
}
while (1);
* command that has been completed.
*
* Note: The adv_req_t request structure and adv_sgblk_t structure,
- * if any, * dropped, because a board structure pointer can not be
+ * if any, are dropped, because a board structure pointer can not be
* determined.
*/
scp = reqp->cmndp;
return;
}
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
+/*
+ * adv_async_callback() - Adv Library asynchronous event callback function.
+ */
+STATIC void
+adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+{
+ switch (code)
+ {
+ case ADV_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+ break;
+
+ case ADV_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the SCSI Bus and
+ * possibly the chip if it is unresponsive. Log the error
+ * with a unique code.
+ */
+ ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+ AdvResetChipAndSB(adv_dvc_varp);
+ break;
+
+ case ADV_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+ break;
+
+ default:
+ ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+ break;
+ }
+}
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
/*
* Search for an AdvanSys PCI device in the PCI configuration space.
*/
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+)
{
int ret = PCI_DEVICE_NOT_FOUND;
/*
* Determine the access method to be used for 'pciDevice'.
*/
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
asc_scan_method(void)
+)
{
ushort data;
PCI_DATA pciData;
*
* Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
*/
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
asc_pci_find_dev(PCI_DEVICE *pciDevice)
+)
{
PCI_DATA pciData;
ushort vendorid, deviceid;
((deviceid == ASC_PCI_DEVICE_ID_1100) ||
(deviceid == ASC_PCI_DEVICE_ID_1200) ||
(deviceid == ASC_PCI_DEVICE_ID_1300) ||
- (deviceid == ASC_PCI_DEVICE_ID_2300))) {
+ (deviceid == ASC_PCI_DEVICE_ID_2300) ||
+ (deviceid == ASC_PCI_DEVICE_ID_2500))) {
pciDevice->slotFound = lslot;
ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
return PCI_DEVICE_FOUND;
/*
* Read PCI configuration data into 'pciConfig'.
*/
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+)
{
PCI_DATA pciData;
uchar counter;
*
* The configuration mechanism is checked for the correct access method.
*/
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
asc_get_cfg_word(PCI_DATA *pciData)
+)
{
ushort tmp;
ulong address;
/* set for type 1 cycle, if needed */
outp(0xCFA, pciData->bus);
/* set the function number */
- outp(0xCF8, 0x10 | (pciData->func << 1)) ;
+ outp(0xCF8, 0x10 | (pciData->func << 1));
/*
* Read the configuration space type 2 locations.
*
* The configuration mechanism is checked for the correct access method.
*/
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
asc_get_cfg_byte(PCI_DATA *pciData)
+)
{
uchar tmp;
ulong address;
/*
* Write a byte to the PCI configuration space.
*/
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
+)
{
ulong tmpl;
ulong address;
STATIC int
asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
{
- asc_board_t *boardp;
- ADV_DVC_VAR *adv_dvc_varp;
- int leftlen;
- int totlen;
- int len;
- int i;
- char *termstr;
- uchar serialstr[13];
- ADVEEP_CONFIG *ep;
+ asc_board_t *boardp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ int leftlen;
+ int totlen;
+ int len;
+ int i;
+ char *termstr;
+ uchar serialstr[13];
+ ADVEEP_3550_CONFIG *ep_3550 = NULL;
+ ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
+ ushort word;
+ ushort *wordp;
+ ushort sdtr_speed = 0;
boardp = ASC_BOARDP(shp);
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- ep = &boardp->eep_config.adv_eep;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ ep_3550 = &boardp->eep_config.adv_3550_eep;
+ } else
+ {
+ ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+ }
leftlen = cplen;
totlen = len = 0;
"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
ASC_PRT_NEXT();
- if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) ==
- ASC_TRUE) {
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ wordp = &ep_3550->serial_number_word1;
+ } else
+ {
+ wordp = &ep_38C0800->serial_number_word1;
+ }
+
+ if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
ASC_PRT_NEXT();
} else {
ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen,
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ len = asc_prt_line(cp, leftlen,
" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng);
- ASC_PRT_NEXT();
-
- switch (ep->termination) {
+ ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
+ ep_3550->max_dvc_qng);
+ ASC_PRT_NEXT();
+ } else
+ {
+ len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
+ ep_38C0800->max_dvc_qng);
+ ASC_PRT_NEXT();
+ }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ word = ep_3550->termination;
+ } else
+ {
+ word = ep_38C0800->termination_lvd;
+ }
+ switch (word) {
case 1:
termstr = "Low Off/High Off";
break;
break;
}
- len = asc_prt_line(cp, leftlen,
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ len = asc_prt_line(cp, leftlen,
" termination: %u (%s), bios_ctrl: %x\n",
- ep->termination, termstr, ep->bios_ctrl);
- ASC_PRT_NEXT();
+ ep_3550->termination, termstr, ep_3550->bios_ctrl);
+ ASC_PRT_NEXT();
+ } else
+ {
+ len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: %x\n",
+ ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
+ ASC_PRT_NEXT();
+ }
len = asc_prt_line(cp, leftlen,
" Target ID: ");
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ word = ep_3550->disc_enable;
+ } else
+ {
+ word = ep_38C0800->disc_enable;
+ }
len = asc_prt_line(cp, leftlen,
" Disconnects: ");
ASC_PRT_NEXT();
for (i = 0; i <= ADV_MAX_TID; i++) {
len = asc_prt_line(cp, leftlen, " %c",
- (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ word = ep_3550->tagqng_able;
+ } else
+ {
+ word = ep_38C0800->tagqng_able;
+ }
len = asc_prt_line(cp, leftlen,
" Command Queuing: ");
ASC_PRT_NEXT();
for (i = 0; i <= ADV_MAX_TID; i++) {
len = asc_prt_line(cp, leftlen, " %c",
- (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ word = ep_3550->start_motor;
+ } else
+ {
+ word = ep_38C0800->start_motor;
+ }
len = asc_prt_line(cp, leftlen,
" Start Motor: ");
ASC_PRT_NEXT();
for (i = 0; i <= ADV_MAX_TID; i++) {
len = asc_prt_line(cp, leftlen, " %c",
- (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ len = asc_prt_line(cp, leftlen,
" Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ len = asc_prt_line(cp, leftlen,
" Ultra Transfer: ");
ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ {
+ word = ep_3550->wdtr_able;
+ } else
+ {
+ word = ep_38C0800->wdtr_able;
+ }
len = asc_prt_line(cp, leftlen,
" Wide Transfer: ");
ASC_PRT_NEXT();
for (i = 0; i <= ADV_MAX_TID; i++) {
len = asc_prt_line(cp, leftlen, " %c",
- (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+ {
+ len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer Speed (Mhz):\n ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ char *speed_str;
+
+ if (i == 0)
+ {
+ sdtr_speed = adv_dvc_varp->sdtr_speed1;
+ } else if (i == 4)
+ {
+ sdtr_speed = adv_dvc_varp->sdtr_speed2;
+ } else if (i == 8)
+ {
+ sdtr_speed = adv_dvc_varp->sdtr_speed3;
+ } else if (i == 12)
+ {
+ sdtr_speed = adv_dvc_varp->sdtr_speed4;
+ }
+ switch (sdtr_speed & ADV_MAX_TID)
+ {
+ case 0: speed_str = "Off"; break;
+ case 1: speed_str = " 5"; break;
+ case 2: speed_str = " 10"; break;
+ case 3: speed_str = " 20"; break;
+ case 4: speed_str = " 40"; break;
+ case 5: speed_str = " 80"; break;
+ default: speed_str = "Unk"; break;
+ }
+ len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+ ASC_PRT_NEXT();
+ if (i == 7)
+ {
+ len = asc_prt_line(cp, leftlen, "\n ");
+ ASC_PRT_NEXT();
+ }
+ sdtr_speed >>= 4;
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+ }
+
return totlen;
}
}
#endif /* version >= v1.3.89 */
-#if ASC_QUEUE_FLOW_CONTROL
- if (ASC_NARROW_BOARD(boardp)) {
- len = asc_prt_line(cp, leftlen, " queue_curr_depth:");
- ASC_PRT_NEXT();
- /* Use ASC_MAX_TID for Narrow Board. */
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- if (boardp->device[i] == NULL) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %d:%d",
- i, boardp->device[i]->queue_curr_depth);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " queue_count:");
- ASC_PRT_NEXT();
- /* Use ASC_MAX_TID for Narrow Board. */
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- if (boardp->device[i] == NULL) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %d:%d",
- i, boardp->device[i]->queue_count);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
-
return totlen;
}
asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
{
asc_board_t *boardp;
+ int chip_scsi_id;
int leftlen;
int totlen;
int len;
ASC_DVC_VAR *v;
ASC_DVC_CFG *c;
int i;
+ int renegotiate = 0;
boardp = ASC_BOARDP(shp);
v = &boardp->dvc_var.asc_dvc_var;
c = &boardp->dvc_cfg.asc_dvc_cfg;
+ chip_scsi_id = c->chip_scsi_id;
leftlen = cplen;
totlen = len = 0;
" Command Queuing:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %d:%c",
+ len = asc_prt_line(cp, leftlen, " %X:%c",
i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
" Command Queue Pending:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
+ len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
" Command Queue Limit:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
+ len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
" Command Queue Full:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %d:Y-%d",
+ len = asc_prt_line(cp, leftlen, " %X:Y-%d",
i, boardp->queue_full_cnt[i]);
} else {
- len = asc_prt_line(cp, leftlen, " %d:N", i);
+ len = asc_prt_line(cp, leftlen, " %X:N", i);
}
ASC_PRT_NEXT();
}
" Synchronous Transfer:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %d:%c",
+ len = asc_prt_line(cp, leftlen, " %X:%c",
i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
for (i = 0; i <= ASC_MAX_TID; i++) {
uchar syn_period_ix;
- if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+ ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
+
+ len = asc_prt_line(cp, leftlen, " %X:", i);
+ ASC_PRT_NEXT();
+
+ if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
+ {
+ len = asc_prt_line(cp, leftlen, " Asynchronous");
+ ASC_PRT_NEXT();
+ } else
+ {
+ syn_period_ix =
+ (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+
+ len = asc_prt_line(cp, leftlen,
+ " Transfer Period Factor: %d (%d.%d Mhz),",
+ v->sdtr_period_tbl[syn_period_ix],
+ 250 / v->sdtr_period_tbl[syn_period_ix],
+ ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+ boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+ ASC_PRT_NEXT();
+ }
+
if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- continue;
+ len = asc_prt_line(cp, leftlen, "*\n");
+ renegotiate = 1;
+ } else
+ {
+ len = asc_prt_line(cp, leftlen, "\n");
}
- syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
- len = asc_prt_line(cp, leftlen, " %d:", i);
ASC_PRT_NEXT();
+ }
+ if (renegotiate)
+ {
len = asc_prt_line(cp, leftlen,
- " Transfer Period Factor: %d (%d.%d Mhz),",
- v->sdtr_period_tbl[syn_period_ix],
- 250 / v->sdtr_period_tbl[syn_period_ix],
- ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
- boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+ " * = Re-negotiation pending before next command.\n");
ASC_PRT_NEXT();
}
ushort chip_scsi_id;
ushort lramword;
uchar lrambyte;
- ushort sdtr_able;
- ushort period;
+ ushort tagqng_able;
+ ushort sdtr_able, wdtr_able;
+ ushort wdtr_done, sdtr_done;
+ ushort period = 0;
+ int renegotiate = 0;
boardp = ASC_BOARDP(shp);
v = &boardp->dvc_var.adv_dvc_var;
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n",
+" iop_base %lx, cable_detect: %X, err_code %u\n",
v->iop_base,
AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
- v->err_code, v->idle_cmd_done);
+ v->err_code);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
len = asc_prt_line(cp, leftlen,
" Queuing Enabled:");
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword);
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
len = asc_prt_line(cp, leftlen,
" Wide Enabled:");
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
len = asc_prt_line(cp, leftlen,
" Transfer Bit Width:");
ASC_PRT_NEXT();
AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
lramword);
+
len = asc_prt_line(cp, leftlen, " %X:%d",
i, (lramword & 0x8000) ? 16 : 8);
ASC_PRT_NEXT();
+
+ if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+ (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+ len = asc_prt_line(cp, leftlen, "*");
+ ASC_PRT_NEXT();
+ renegotiate = 1;
+ }
}
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
for (i = 0; i <= ADV_MAX_TID; i++) {
AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
lramword &= ~0x8000;
if ((chip_scsi_id == i) ||
- ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) ||
- (lramword == 0)) {
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+ ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
len = asc_prt_line(cp, leftlen, " %X:", i);
ASC_PRT_NEXT();
-
- period = (((lramword >> 8) * 25) + 50)/4;
- len = asc_prt_line(cp, leftlen,
- " Transfer Period Factor: %d (%d.%d Mhz),",
- period, 250/period, ASC_TENTHS(250, period));
+ if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
+ {
+ len = asc_prt_line(cp, leftlen, " Asynchronous");
+ ASC_PRT_NEXT();
+ } else
+ {
+ len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
+ ASC_PRT_NEXT();
+
+ if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
+ {
+ len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+ ASC_PRT_NEXT();
+ } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
+ {
+ len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+ ASC_PRT_NEXT();
+ } else /* 20 Mhz or below. */
+ {
+ period = (((lramword >> 8) * 25) + 50)/4;
+
+ if (period == 0) /* Should never happen. */
+ {
+ len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
+ ASC_PRT_NEXT();
+ } else
+ {
+ len = asc_prt_line(cp, leftlen,
+ "%d (%d.%d Mhz),",
+ period, 250/period, ASC_TENTHS(250, period));
+ ASC_PRT_NEXT();
+ }
+ }
+
+ len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+ lramword & 0x1F);
+ ASC_PRT_NEXT();
+ }
+
+ if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+ len = asc_prt_line(cp, leftlen, "*\n");
+ renegotiate = 1;
+ } else
+ {
+ len = asc_prt_line(cp, leftlen, "\n");
+ }
ASC_PRT_NEXT();
+ }
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
- lramword & 0x1F);
+ if (renegotiate)
+ {
+ len = asc_prt_line(cp, leftlen,
+ " * = Re-negotiation pending before next command.\n");
ASC_PRT_NEXT();
}
{
va_list args;
int ret;
- char s[ASC_PRTLINE_SIZE];
+ char s[ASC_PRTLINE_SIZE];
va_start(args, fmt);
ret = vsprintf(s, fmt, args);
STATIC void
DvcSleepMilliSecond(ulong n)
{
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+ ulong i;
+#endif /* version < v2.1.0 */
+
ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
mdelay(n);
+#else /* version < v2.1.0 */
+ for (i = 0; i < n; i++) {
+ udelay(1000);
+ }
+#endif /* version < v2.1.0 */
}
STATIC int
/*
* Read a PCI configuration byte.
*/
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
DvcReadPCIConfigByte(
ASC_DVC_VAR asc_ptr_type *asc_dvc,
ushort offset)
+)
{
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
/*
* Write a PCI configuration byte.
*/
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
DvcWritePCIConfigByte(
ASC_DVC_VAR asc_ptr_type *asc_dvc,
ushort offset,
uchar byte_data)
+)
{
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
* Return the BIOS address of the adapter at the specified
* I/O port and with the specified bus type.
*/
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscGetChipBiosAddress(
PortAddr iop_base,
ushort bus_type
)
+)
{
- ushort cfg_lsw ;
- ushort bios_addr ;
+ ushort cfg_lsw;
+ ushort bios_addr;
/*
* The PCI BIOS is re-located by the motherboard BIOS. Because
if((bus_type & ASC_IS_EISA) != 0)
{
- cfg_lsw = AscGetEisaChipCfg(iop_base) ;
- cfg_lsw &= 0x000F ;
+ cfg_lsw = AscGetEisaChipCfg(iop_base);
+ cfg_lsw &= 0x000F;
bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
- (cfg_lsw * ASC_BIOS_BANK_SIZE)) ;
- return(bios_addr) ;
+ (cfg_lsw * ASC_BIOS_BANK_SIZE));
+ return(bios_addr);
}/* if */
- cfg_lsw = AscGetChipCfgLsw(iop_base) ;
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
/*
* ISA PnP uses the top bit as the 32K BIOS flag
}/* if */
bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
- ASC_BIOS_MIN_ADDR) ;
- return(bios_addr) ;
+ ASC_BIOS_MIN_ADDR);
+ return(bios_addr);
}
/*
* Read a PCI configuration byte.
*/
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
DvcAdvReadPCIConfigByte(
ADV_DVC_VAR *asc_dvc,
ushort offset)
+)
{
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
/*
* Write a PCI configuration byte.
*/
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
DvcAdvWritePCIConfigByte(
ADV_DVC_VAR *asc_dvc,
ushort offset,
uchar byte_data)
+)
{
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
#ifdef ASC_CONFIG_PCI
(unsigned) s->hostt, (unsigned) s->block);
printk(
-" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
- s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
- s->irq, s->dma_channel);
+" wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n",
+ s->wish_block, (ulong) s->base, (ulong) s->io_port, s->n_io_port,
+ s->irq);
printk(
-" this_id %d, can_queue %d,\n", s->this_id, s->can_queue);
+" dma_channel %d, this_id %d, can_queue %d,\n",
+ s->dma_channel, s->this_id, s->can_queue);
printk(
" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
(unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
printk(
-" max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n",
- (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng,
- (unsigned) h->max_dvc_qng);
+" max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n",
+ (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
+ (ulong) h->carr_freelist);
+
printk(
-" no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n",
- (unsigned) h->no_scam, (unsigned) h->tagqng_able,
- (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+" icq_sp %lx, irq_sp %lx\n",
+ (ulong) h->icq_sp,
+ (ulong) h->irq_sp);
+
+ printk(
+" no_scam 0x%x, tagqng_able 0x%x\n",
+ (unsigned) h->no_scam, (unsigned) h->tagqng_able);
+ printk(
+" chip_scsi_id 0x%x, cfg %lx\n",
+ (unsigned) h->chip_scsi_id, (ulong) h->cfg);
}
/*
STATIC void
asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
{
- int i;
+ int sg_blk_cnt;
struct asc_sg_block *sg_ptr;
printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
q->cntl, q->data_addr, q->vdata_addr);
+ printk(
+" cntl 0x%x, data_addr %lx, vdata_addr %lx\n",
+ q->cntl, q->data_addr, q->vdata_addr);
+
printk(
" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
q->data_cnt, q->sense_addr, q->sense_len);
q->cdb_len, q->done_status, q->host_status, q->scsi_status);
printk(
-" vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n",
- (ulong) q->vsense_addr, (ulong) q->scsiq_ptr,
- (ulong) q->ux_wk_data_cnt);
-
- printk(
-" sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n",
- (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt);
+" sg_working_ix %x, sg_working_data_cnt %lx, reserved %u\n",
+ q->sg_working_ix, q->sg_working_data_cnt, q->reserved);
printk(
-" ux_sg_ix %u, orig_sense_len %u\n",
- q->ux_sg_ix, q->orig_sense_len);
+" scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n",
+ q->scsiq_rptr, q->sg_real_addr, (ulong) q->sg_list_ptr);
/* Display the request's ADV_SG_BLOCK structures. */
- for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL;
- sg_ptr = sg_ptr->sg_ptr, i++) {
- /*
- * 'sg_ptr' is a physical address. Convert it to a virtual
- * address by indexing 'i' into the virtual address array
- * 'sg_list_ptr'.
- *
- * At the end of the each iteration of the loop 'sg_ptr' is
- * converted back into a physical address by setting 'sg_ptr'
- * to the next pointer 'sg_ptr->sg_ptr'.
- */
- sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]);
- asc_prt_adv_sgblock(i, sg_ptr);
+ if (q->sg_list_ptr != NULL)
+ {
+ sg_blk_cnt = 0;
+ while (1) {
+ /*
+ * 'sg_ptr' is a physical address. Convert it to a virtual
+ * address by indexing 'sg_blk_cnt' into the virtual address
+ * array 'sg_list_ptr'.
+ *
+ * XXX - Assumes all SG physical blocks are virtually contiguous.
+ */
+ sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
+ asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+ if (sg_ptr->sg_ptr == NULL)
+ {
+ break;
+ }
+ sg_blk_cnt++;
+ }
}
}
STATIC void
asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
{
- int i, s;
-
- /* Calculate starting entry number for the current block. */
- s = sgblockno * NO_OF_SG_PER_BLOCK;
+ int i;
- printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n",
- (ulong) b, (ulong) sgblockno);
- printk(
-" first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n",
- (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr);
- ASC_ASSERT(b->first_entry_no - s >= 0);
- ASC_ASSERT(b->last_entry_no - s >= 0);
- ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK);
- ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
- ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
- ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s);
- for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) {
- printk(" [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n",
- (ulong) i, (ulong) b->sg_list[i].sg_addr,
- (ulong) b->sg_list[i].sg_count);
+ printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n",
+ (ulong) b, sgblockno);
+ printk(" sg_cnt %u, sg_ptr %lx\n",
+ b->sg_cnt, (ulong) b->sg_ptr);
+ ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+ if (b->sg_ptr != NULL)
+ {
+ ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+ }
+ for (i = 0; i < b->sg_cnt; i++) {
+ printk(" [%u]: sg_addr %lx, sg_count %lx\n",
+ i, b->sg_list[i].sg_addr, b->sg_list[i].sg_count);
}
}
k = 8;
m = 0;
} else {
- m = (l - i) % 4 ;
+ m = (l - i) % 4;
}
for (j = 0; j < k; j++) {
* --- Asc Library Functions
*/
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscGetEisaChipCfg(
PortAddr iop_base
)
+)
{
PortAddr eisa_cfg_iop;
return (inpw(eisa_cfg_iop));
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscSetChipScsiID(
PortAddr iop_base,
uchar new_host_id
)
+)
{
ushort cfg_lsw;
return (AscGetChipScsiID(iop_base));
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscGetChipScsiCtrl(
PortAddr iop_base
)
+)
{
uchar sc;
return (sc);
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscGetChipVersion(
PortAddr iop_base,
ushort bus_type
)
+)
{
if ((bus_type & ASC_IS_EISA) != 0) {
PortAddr eisa_iop;
return (AscGetChipVerNo(iop_base));
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscGetChipBusType(
PortAddr iop_base
)
+)
{
ushort chip_ver;
return (0);
}
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
AscLoadMicroCode(
PortAddr iop_base,
ushort s_addr,
ushort *mcode_buf,
ushort mcode_size
)
+)
{
ulong chksum;
ushort mcode_word_size;
return (chksum);
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscFindSignature(
PortAddr iop_base
)
+)
{
ushort sig_word;
ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
};
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
AscSearchIOPortAddr(
PortAddr iop_beg,
ushort bus_type
)
+)
{
if (bus_type & ASC_IS_VL) {
while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
return (0);
}
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
AscSearchIOPortAddr11(
PortAddr s_addr
)
+)
{
int i;
PortAddr iop_base;
return (0);
}
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AscToggleIRQAct(
PortAddr iop_base
)
+)
{
AscSetChipStatus(iop_base, CIW_IRQ_ACT);
AscSetChipStatus(iop_base, 0);
return;
}
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AscSetISAPNPWaitForKey(
void)
+)
{
outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
return;
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscGetChipIRQ(
PortAddr iop_base,
ushort bus_type
)
+)
{
ushort cfg_lsw;
uchar chip_irq;
return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscSetChipIRQ(
PortAddr iop_base,
uchar irq_no,
ushort bus_type
)
+)
{
ushort cfg_lsw;
return (0);
}
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AscEnableIsaDma(
uchar dma_channel
)
+)
{
if (dma_channel < 4) {
outp(0x000B, (ushort) (0xC0 | dma_channel));
tid_no = ASC_TIX_TO_TID(target_ix);
target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-
asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
} else {
asyn_sdtr = 0;
*/
boardp->queue_full |= target_id;
boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
-#if ASC_QUEUE_FLOW_CONTROL
- if (boardp->device[tid_no] != NULL &&
- boardp->device[tid_no]->queue_curr_depth >
- cur_dvc_qng) {
- boardp->device[tid_no]->queue_curr_depth =
- cur_dvc_qng;
- }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
}
}
}
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
return (0);
+ } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
+ {
+ uchar q_no;
+ ushort q_addr;
+ ulong srb_ptr;
+ uchar sg_wk_q_no;
+ uchar first_sg_wk_q_no;
+ ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
+ ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
+ ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
+ ushort sg_list_dwords;
+ ushort sg_entry_cnt;
+ uchar next_qp;
+ int i;
+
+ q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
+ if (q_no == ASC_QLINK_END)
+ {
+ return(0);
+ }
+
+ q_addr = ASC_QNO_TO_QADDR(q_no);
+
+ /* Read request's SRB pointer. */
+ srb_ptr = AscReadLramDWord(iop_base,
+ (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR));
+
+ /*
+ * Get request's first and working SG queue.
+ */
+ sg_wk_q_no = AscReadLramByte(iop_base,
+ (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+
+ first_sg_wk_q_no = AscReadLramByte(iop_base,
+ (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+ /*
+ * Reset request's working SG queue back to the
+ * first SG queue.
+ */
+ AscWriteLramByte(iop_base,
+ (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
+ first_sg_wk_q_no);
+
+ /*
+ * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+ * structure pointer using a macro provided by the driver.
+ * The ASC_SCSI_REQ pointer provides a pointer to the
+ * host ASC_SG_HEAD structure.
+ */
+ scsiq = (ASC_SCSI_Q *) ASC_SRB2SCSIQ(srb_ptr);
+
+ sg_head = scsiq->sg_head;
+
+ /*
+ * Set sg_entry_cnt to the number of SG elements
+ * that will be completed on this interrupt.
+ *
+ * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+ * SG elements. The data_cnt and data_addr fields which
+ * add 1 to the SG element capacity are not used when
+ * restarting SG handling after a halt.
+ */
+ if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
+ {
+ sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+ /*
+ * Keep track of remaining number of SG elements that will
+ * need to be handled on the next interrupt.
+ */
+ scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+ } else
+ {
+ sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+ scsiq->remain_sg_entry_cnt = 0;
+ }
+
+ /*
+ * Copy SG elements into the list of allocated SG queues.
+ *
+ * Last index completed is saved in scsiq->next_sg_index.
+ */
+ next_qp = first_sg_wk_q_no;
+ q_addr = ASC_QNO_TO_QADDR(next_qp);
+ scsi_sg_q.sg_head_qp = q_no;
+ scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+ for( i = 0; i < sg_head->queue_cnt; i++)
+ {
+ scsi_sg_q.seq_no = i + 1;
+ if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
+ {
+ sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+ sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+ /*
+ * After very first SG queue RISC FW uses next
+ * SG queue first element then checks sg_list_cnt
+ * against zero and then decrements, so set
+ * sg_list_cnt 1 less than number of SG elements
+ * in each SG queue.
+ */
+ scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+ scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+ } else {
+ /*
+ * This is the last SG queue in the list of
+ * allocated SG queues. If there are more
+ * SG elements than will fit in the allocated
+ * queues, then set the QCSG_SG_XFER_MORE flag.
+ */
+ if (scsiq->remain_sg_entry_cnt != 0)
+ {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+ } else
+ {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ }
+ /* equals sg_entry_cnt * 2 */
+ sg_list_dwords = sg_entry_cnt << 1;
+ scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+ scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+ sg_entry_cnt = 0;
+ }
+
+ scsi_sg_q.q_no = next_qp;
+ AscMemWordCopyToLram(iop_base,
+ (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
+ (ushort *) &scsi_sg_q,
+ (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
+
+ AscMemDWordCopyToLram( iop_base,
+ (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
+ (ulong *) &sg_head->sg_list[scsiq->next_sg_index],
+ (ushort) sg_list_dwords);
+
+ scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+ /*
+ * If the just completed SG queue contained the
+ * last SG element, then no more SG queues need
+ * to be written.
+ */
+ if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
+ {
+ break;
+ }
+
+ next_qp = AscReadLramByte( iop_base,
+ ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
+ q_addr = ASC_QNO_TO_QADDR( next_qp );
+ }
+
+ /*
+ * Clear the halt condition so the RISC will be restarted
+ * after the return.
+ */
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return(0);
}
return (0);
}
(ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
scsiq->sense_len = (uchar) _val;
scsiq->extra_bytes = (uchar) (_val >> 8);
- scsiq->remain_bytes = AscReadLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+ /*
+ * Read high word of remain bytes from alternate location.
+ */
+ scsiq->remain_bytes = (((ulong) AscReadLramWord( iop_base,
+ (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
+ /*
+ * Read low word of remain bytes from original location.
+ */
+ scsiq->remain_bytes += AscReadLramWord(iop_base,
+ (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
scsiq->remain_bytes &= max_dma_count;
return (sg_queue_cnt);
}
iop_base = asc_dvc->iop_base;
int_pending = FALSE;
+
+ if (AscIsIntPending(iop_base) == 0)
+ {
+ return int_pending;
+ }
+
if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
|| (asc_dvc->isr_callback == 0)
) {
chipstat = AscGetChipStatus(iop_base);
if (chipstat & CSW_SCSI_RESET_LATCH) {
if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+ int i = 10;
int_pending = TRUE;
asc_dvc->sdtr_done = 0;
saved_ctrl_reg &= (uchar) (~CC_HALT);
- while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+ while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
+ (i-- > 0))
+ {
+ DvcSleepMilliSecond(100);
+ }
AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
AscSetChipControl(iop_base, CC_HALT);
AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x91, 0x10, 0x0A, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00,
0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80,
0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
- 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00,
+ 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00,
0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1,
- 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0xA6, 0x97, 0xCE, 0x81, 0x00, 0x33,
- 0x02, 0x00, 0xC0, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00,
- 0x84, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x03, 0xDE,
- 0x00, 0x33, 0x05, 0x00, 0xC0, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60,
- 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63,
- 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC0, 0x88, 0x03, 0x07, 0x02, 0x01,
- 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98,
- 0xCD, 0x04, 0x15, 0x23, 0xF6, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03,
- 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC0, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01,
- 0x00, 0x33, 0x0B, 0x00, 0xC0, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC0, 0x88,
- 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01,
- 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
- 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01,
- 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D,
- 0x00, 0x33, 0x1B, 0x00, 0xC0, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
- 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01,
- 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE,
- 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
- 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0,
- 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB,
- 0x11, 0x23, 0xF6, 0x88, 0x04, 0x98, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x32, 0x02,
- 0x7C, 0x95, 0x06, 0xA6, 0x3C, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0xC0, 0x88, 0x04, 0x01, 0x03, 0xD8,
- 0xB2, 0x98, 0x6A, 0x96, 0x4E, 0x82, 0xFE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D,
- 0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02,
- 0x00, 0x33, 0x10, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x50, 0x82, 0x60, 0x96, 0x50, 0x82, 0x04, 0x23,
- 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61,
- 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01,
- 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xB6, 0x02, 0x07, 0xA6, 0x66, 0x02,
- 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xC0, 0x02, 0x00, 0xA6, 0xC0, 0x02,
- 0x00, 0x33, 0x12, 0x00, 0xC0, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x98, 0x02,
- 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
- 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xF6, 0x82, 0x18, 0x23, 0x04, 0x61,
- 0x18, 0xA0, 0xEE, 0x02, 0x04, 0x01, 0x9C, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xC0, 0x88, 0x08, 0x31,
- 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x20, 0x03, 0x00, 0xA6,
- 0x20, 0x03, 0x07, 0xA6, 0x18, 0x03, 0x06, 0xA6, 0x1C, 0x03, 0x03, 0xA6, 0x20, 0x04, 0x02, 0xA6,
- 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0xFA, 0x82, 0x60, 0x96, 0xFA, 0x82,
- 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01,
- 0x00, 0xA2, 0x60, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, 0x7E, 0x98, 0x00, 0xA6,
- 0x22, 0x03, 0x07, 0xA6, 0x58, 0x03, 0x03, 0xA6, 0x3C, 0x04, 0x06, 0xA6, 0x5C, 0x03, 0x01, 0xA6,
- 0x22, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x3E, 0x83, 0x60, 0x96, 0x3E, 0x83,
- 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC0, 0x88, 0x00, 0x01, 0x05, 0x05,
- 0xFF, 0xA2, 0x7E, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x3A, 0x83, 0x05, 0x05, 0x15, 0x01,
- 0x00, 0xA2, 0x9E, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
- 0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0x9A, 0x03, 0x12, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
- 0xA8, 0x03, 0x00, 0xA6, 0xC0, 0x03, 0x12, 0x84, 0xA6, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA8, 0x03,
- 0x07, 0xA6, 0xB6, 0x03, 0xD8, 0x83, 0x7C, 0x95, 0xAC, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC0, 0x88,
- 0xA6, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xC0, 0x03, 0x07, 0xA6, 0xCE, 0x03, 0xD8, 0x83, 0x7C, 0x95,
- 0xC4, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC0, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
- 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x12, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0xF6, 0x03, 0x80, 0x6B,
- 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x10, 0x04, 0x07, 0xA6, 0x08, 0x04, 0x06, 0xA6,
- 0x0C, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0xF6, 0x83, 0x60, 0x96, 0xF6, 0x83,
- 0x20, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
+ 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
+ 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, 0x84, 0x97, 0x07, 0xA6,
+ 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00,
+ 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
+ 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x34, 0x01, 0x00, 0x33,
+ 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04,
+ 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, 0x00, 0x33, 0x0A, 0x00,
+ 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04,
+ 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
+ 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x3C, 0x01, 0x00, 0x05,
+ 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01,
+ 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
+ 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23,
+ 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0,
+ 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84, 0x97,
+ 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80,
+ 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
+ 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x04, 0x98, 0xF0, 0x80,
+ 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6,
+ 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, 0x07, 0xA6, 0x5A, 0x02,
+ 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96,
+ 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
+ 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01,
+ 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02,
+ 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
+ 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43,
+ 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01,
+ 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
+ 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, 0x00, 0x33, 0x1F, 0x00,
+ 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6,
+ 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
+ 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xEE, 0x82,
+ 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8,
+ 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
+ 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x3C, 0x04, 0x06, 0xA6,
+ 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83,
+ 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
+ 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x7A, 0x03,
+ 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03,
+ 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
+ 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, 0xA4, 0x03, 0x00, 0xA6,
+ 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03,
+ 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
+ 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, 0xC0, 0x83, 0x00, 0x33,
+ 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23,
+ 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, 0x06, 0xA6, 0x0A, 0x04,
+ 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84,
+ 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, 0x38, 0x04, 0x00, 0x33,
- 0x30, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC,
+ 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC,
0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
- 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01,
+ 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01,
0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1D, 0x00, 0xC0, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
- 0xC0, 0x88, 0x42, 0x23, 0xF6, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3,
+ 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
+ 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3,
0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23,
- 0xF6, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF6, 0x88, 0x04, 0x98,
- 0x00, 0xA2, 0xC0, 0x04, 0xB2, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF0, 0x81,
- 0x47, 0x23, 0xF6, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB2, 0x98, 0x00, 0x33, 0x00, 0x81,
- 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xF6, 0x88, 0x04, 0x23,
+ 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
+ 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xE8, 0x81,
+ 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81,
+ 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xF4, 0x04, 0x00, 0x33,
- 0x27, 0x00, 0xC0, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01,
+ 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01,
0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, 0x46, 0x97, 0xCD, 0x04,
0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85,
0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01,
0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xF8, 0x05,
- 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC0, 0x88, 0x04, 0xA0,
+ 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0,
0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x62, 0x97, 0x04, 0x85,
0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0,
0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, 0x80, 0x67, 0x80, 0x63,
- 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, 0xF6, 0x88, 0x07, 0x23,
+ 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23,
0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC0, 0x88, 0x1D, 0x01, 0x01, 0xD6,
+ 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6,
0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61,
0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01,
0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43,
0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x07, 0xA6, 0xD6, 0x06,
- 0x00, 0x33, 0x2A, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6,
- 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC0, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
+ 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6,
+ 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01,
0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33,
- 0x2C, 0x00, 0xC0, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
- 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC0, 0x88, 0x00, 0x00, 0x80, 0x67,
+ 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
+ 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00, 0x80, 0x67,
0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61,
0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05,
0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00,
0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC4, 0x07, 0x00, 0x33,
- 0x07, 0x00, 0xC0, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01,
+ 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01,
0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63,
0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02,
0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5A, 0x88, 0x02, 0x01,
0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08,
0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
- 0x00, 0x33, 0x3E, 0x00, 0xC0, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B,
+ 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B,
0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09,
0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
- 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E,
- 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB2, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63,
- 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23,
- 0xF6, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62,
- 0xE0, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7,
- 0x41, 0x23, 0xF6, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
+ 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
+ 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
+ 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+ 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
+ 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
+ 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
};
STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
-STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012B5442UL;
+STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
n_q_required = 1;
if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
- asc_dvc->sdtr_done &= ~scsiq->q1.target_id ;
+ asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
AscMsgOutSDTR(asc_dvc,
asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
DvcLeaveCritical(last_int_level);
return (ERR);
}
- if (sg_entry_cnt > ASC_MAX_SG_LIST) {
- return (ERR);
+#if !CC_VERY_LONG_SG_LIST
+ if (sg_entry_cnt > ASC_MAX_SG_LIST)
+ {
+ return(ERR);
}
+#endif /* !CC_VERY_LONG_SG_LIST */
if (sg_entry_cnt == 1) {
- scsiq->q1.data_addr = sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+ scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
}
sg_entry_cnt_minus_one = sg_entry_cnt - 1;
if (scsiq->q1.cntl & QC_SG_HEAD) {
data_cnt = 0;
for (i = 0; i < sg_entry_cnt; i++) {
- data_cnt += sg_head->sg_list[i].bytes;
+ data_cnt += (ulong) sg_head->sg_list[i].bytes;
}
} else {
data_cnt = scsiq->q1.data_cnt;
if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
if ((scsi_cmd == SCSICMD_Read6) ||
(scsi_cmd == SCSICMD_Read10)) {
- addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
- sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+ addr =
+ (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+ (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
extra_bytes = (uchar) ((ushort) addr & 0x0003);
if ((extra_bytes != 0) &&
((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
}
}
sg_head->entry_to_copy = sg_head->entry_cnt;
+ /*
+ * Set the sg_entry_cnt to the maximum possible. The rest of
+ * the SG elements will be copied when the RISC completes the
+ * SG elements that fit and halts.
+ */
+ if (sg_entry_cnt > ASC_MAX_SG_LIST)
+ {
+ sg_entry_cnt = ASC_MAX_SG_LIST;
+ }
n_q_required = AscSgListToQueue(sg_entry_cnt);
if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
(uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
sg_head = scsiq->sg_head;
saved_data_addr = scsiq->q1.data_addr;
saved_data_cnt = scsiq->q1.data_cnt;
- scsiq->q1.data_addr = sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
- sg_entry_cnt = sg_head->entry_cnt - 1;
+ scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
+ /*
+ * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+ * then not all SG elements will fit in the allocated queues.
+ * The rest of the SG elements will be copied when the RISC
+ * completes the SG elements that fit and halts.
+ */
+ if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+ {
+ /*
+ * Set sg_entry_cnt to be the number of SG elements that
+ * will fit in the allocated SG queues. It is minus 1 because
+ * first SG element handled above. ASC_MAX_SG_LIST is already
+ * inflated by 1 to account for this. For example it may
+ * be 50 which is 1 + 7 queues * 7 SG elements.
+ */
+ sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+ /*
+ * Keep track of remaining number of SG elements that will
+ * need to be handled from a_isr.c.
+ */
+ scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
+ } else
+ {
+ /*
+ * Set sg_entry_cnt to be the number of SG elements that
+ * will fit in the allocated SG queues. Refer to comment
+ * above regarding why it is - 1.
+ */
+ sg_entry_cnt = sg_head->entry_cnt - 1;
+ }
if (sg_entry_cnt != 0) {
scsiq->q1.cntl |= QC_SG_HEAD;
q_addr = ASC_QNO_TO_QADDR(q_no);
scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
}
} else {
- scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ /*
+ * This is the last SG queue in the list of
+ * allocated SG queues. If there are more
+ * SG elements than will fit in the allocated
+ * queues, then set the QCSG_SG_XFER_MORE flag.
+ */
+ if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+ {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+ } else
+ {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ }
sg_list_dwords = sg_entry_cnt << 1;
if (i == 0) {
scsi_sg_q.sg_list_cnt = sg_entry_cnt;
(ulong *) & sg_head->sg_list[sg_index],
(ushort) sg_list_dwords);
sg_index += ASC_SG_LIST_PER_Q;
+ scsiq->next_sg_index = sg_index;
}
} else {
scsiq->q1.cntl &= ~QC_SG_HEAD;
if (org_id == (0x01 << i))
break;
}
- org_id = i;
+ org_id = (ASC_SCSI_BIT_ID_TYPE) i;
AscWriteChipDvcID(iop_base, id);
if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
AscSetBank(iop_base, 0);
uchar q_status;
int count = 0;
- while (scsiq->q1.q_no == 0) ;
+ while (scsiq->q1.q_no == 0);
q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
do {
q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
period_table = asc_dvc->sdtr_period_tbl;
max_index = (int) asc_dvc->max_sdtr_index;
- min_index = (int)asc_dvc->host_init_sdtr_index ;
+ min_index = (int)asc_dvc->host_init_sdtr_index;
if ((syn_time <= period_table[max_index])) {
for (i = min_index; i < (max_index - 1); i++) {
if (syn_time <= period_table[i]) {
if (sg_head.entry_cnt > 1) {
return (0L);
}
- return (sg_head.sg_list[0].addr);
+ return ((ulong) sg_head.sg_list[0].addr);
}
STATIC void
udelay((nano_sec + 999)/1000);
}
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
AscGetEisaProductID(
PortAddr iop_base
)
+)
{
PortAddr eisa_iop;
ushort product_id_high, product_id_low;
return (product_id);
}
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
AscSearchIOPortAddrEISA(
PortAddr iop_base
)
+)
{
ulong eisa_product_id;
)
{
PortAddr iop_base;
+ int i = 10;
iop_base = asc_dvc->iop_base;
- while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+ while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
+ {
+ DvcSleepMilliSecond(100);
+ }
AscStopChip(iop_base);
AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
DvcDelayNanoSecond(asc_dvc, 60000);
return (AscIsChipHalted(iop_base));
}
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
AscGetMaxDmaCount(
ushort bus_type
)
+)
{
if (bus_type & ASC_IS_ISA)
return (ASC_MAX_ISA_DMA_COUNT);
return (ASC_MAX_PCI_DMA_COUNT);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscGetIsaDmaChannel(
PortAddr iop_base
)
+)
{
ushort channel;
return (channel + 4);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscSetIsaDmaChannel(
PortAddr iop_base,
ushort dma_channel
)
+)
{
ushort cfg_lsw;
uchar value;
return (0);
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscSetIsaDmaSpeed(
PortAddr iop_base,
uchar speed_value
)
+)
{
speed_value &= 0x07;
AscSetBank(iop_base, 1);
return (AscGetIsaDmaSpeed(iop_base));
}
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
AscGetIsaDmaSpeed(
PortAddr iop_base
)
+)
{
uchar speed_value;
return (speed_value);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscReadPCIConfigWord(
ASC_DVC_VAR asc_ptr_type *asc_dvc,
ushort pci_config_offset)
+)
{
uchar lsb, msb;
return ((ushort) ((msb << 8) | lsb));
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitGetConfig(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
ushort warn_code;
PortAddr iop_base;
return(warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitSetConfig(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
ushort warn_code = 0;
return (warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitFromAscDvcVar(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
PortAddr iop_base;
ushort cfg_msw;
return (warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitAsc1000Driver(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
ushort warn_code;
PortAddr iop_base;
- extern ushort _asc_mcode_size;
- extern ulong _asc_mcode_chksum;
- extern uchar _asc_mcode_buf[];
iop_base = asc_dvc->iop_base;
warn_code = 0;
return (warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitAscDvcVar(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
int i;
PortAddr iop_base;
asc_dvc->no_scam = 0;
asc_dvc->unit_not_ready = 0;
asc_dvc->queue_full_or_busy = 0;
- asc_dvc->redo_scam = 0 ;
- asc_dvc->res2 = 0 ;
- asc_dvc->host_init_sdtr_index = 0 ;
- asc_dvc->res7 = 0 ;
- asc_dvc->res8 = 0 ;
- asc_dvc->cfg->can_tagged_qng = 0 ;
+ asc_dvc->redo_scam = 0;
+ asc_dvc->res2 = 0;
+ asc_dvc->host_init_sdtr_index = 0;
+ asc_dvc->res7 = 0;
+ asc_dvc->res8 = 0;
+ asc_dvc->cfg->can_tagged_qng = 0;
asc_dvc->cfg->cmd_qng_enabled = 0;
asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
asc_dvc->init_sdtr = 0;
return (warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitFromEEP(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
ASCEEP_CONFIG eep_config_buf;
ASCEEP_CONFIG *eep_config;
/* Indicate EEPROM-less board. */
eep_config->adapter_info[5] = 0xBB;
} else {
- write_eep = 1 ;
- warn_code |= ASC_WARN_EEPROM_CHKSUM ;
+ write_eep = 1;
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
}
}
- asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr ;
+ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
asc_dvc->cfg->disc_enable = eep_config->disc_enable;
asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
return (warn_code);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscInitMicroCodeVar(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
int i;
ushort warn_code;
return (warn_code);
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscTestExternalLram(
ASC_DVC_VAR asc_ptr_type * asc_dvc
)
+)
{
PortAddr iop_base;
ushort q_addr;
return (sta);
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscWriteEEPCmdReg(
PortAddr iop_base,
uchar cmd_reg
)
+)
{
uchar read_back;
int retry;
}
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscWriteEEPDataReg(
PortAddr iop_base,
ushort data_reg
)
+)
{
ushort read_back;
int retry;
}
}
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AscWaitEEPRead(
void
)
+)
{
DvcSleepMilliSecond(1);
return;
}
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AscWaitEEPWrite(
void
)
+)
{
DvcSleepMilliSecond(20);
return;
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscReadEEPWord(
PortAddr iop_base,
uchar addr
)
+)
{
ushort read_wval;
uchar cmd_reg;
return (read_wval);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscWriteEEPWord(
PortAddr iop_base,
uchar addr,
ushort word_val
)
+)
{
ushort read_wval;
return (read_wval);
}
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AscGetEEPConfig(
PortAddr iop_base,
ASCEEP_CONFIG * cfg_buf, ushort bus_type
)
+)
{
ushort wval;
ushort sum;
return (sum);
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscSetEEPConfigOnce(
PortAddr iop_base,
ASCEEP_CONFIG * cfg_buf, ushort bus_type
)
+)
{
int n_error;
ushort *wbuf;
return (n_error);
}
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AscSetEEPConfig(
PortAddr iop_base,
ASCEEP_CONFIG * cfg_buf, ushort bus_type
)
+)
{
int retry;
int n_error;
uchar tid_no,
ASC_SCSI_INQUIRY *inq)
{
- uchar dvc_type;
- ASC_SCSI_BIT_ID_TYPE tid_bits;
+ uchar dvc_type;
+ ASC_SCSI_BIT_ID_TYPE tid_bits;
dvc_type = inq->byte0.peri_dvc_type;
tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
- if (!(asc_dvc->init_sdtr & tid_bits)) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
+ {
+ if (!(asc_dvc->init_sdtr & tid_bits))
+ {
if ((dvc_type == SCSI_TYPE_CDROM) &&
(AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "HP ", 3) == 0)) {
+ (uchar *) "HP ", 3) == 0))
+ {
asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
}
asc_dvc->pci_fix_asyn_xfer |= tid_bits;
if ((dvc_type == SCSI_TYPE_PROC) ||
- (dvc_type == SCSI_TYPE_SCANNER)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
- if ((dvc_type == SCSI_TYPE_SASD) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "TANDBERG", 8) == 0) &&
- (AscCompareString((uchar *) inq->product_id,
- (uchar *) " TDC 36", 7) == 0)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
- if ((dvc_type == SCSI_TYPE_SASD) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "WANGTEK ", 8) == 0)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
-
- if ((dvc_type == SCSI_TYPE_CDROM) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "NEC ", 8) == 0) &&
- (AscCompareString((uchar *) inq->product_id,
- (uchar *) "CD-ROM DRIVE ", 16) == 0)) {
+ (dvc_type == SCSI_TYPE_SCANNER) ||
+ (dvc_type == SCSI_TYPE_CDROM) ||
+ (dvc_type == SCSI_TYPE_SASD))
+ {
asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
}
- if ((dvc_type == SCSI_TYPE_CDROM) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "YAMAHA", 6) == 0) &&
- (AscCompareString((uchar *) inq->product_id,
- (uchar *) "CDR400", 6) == 0)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
- if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+ if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+ {
AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
- ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+ ASYN_SDTR_DATA_FIX_PCI_REV_AB);
}
}
}
* --- Adv Library Functions
*/
-/* a_qswap.h */
-STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = {
- 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x44, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0xD6, 0x11, 0x00, 0x00, 0x70, 0x01,
- 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x10, 0x2D, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD6, 0x0A,
- 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC,
- 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0xA6, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47,
- 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B,
- 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00,
- 0x00, 0xF2, 0x68, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x49, 0x44,
- 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x44, 0x58, 0x00, 0xF2,
- 0xE2, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00,
- 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4,
- 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00,
- 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2,
- 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4,
- 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01,
- 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02,
- 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10,
- 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1E, 0x11, 0x50, 0x10, 0x06, 0xFC,
- 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4E, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00,
- 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x2C, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00,
- 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x58, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C,
- 0x00, 0xF2, 0x1C, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00,
- 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54,
- 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6,
- 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x38, 0x10, 0x00, 0xF2,
- 0x54, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x02, 0xF6, 0xD0, 0x00,
- 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x9C, 0x0F,
- 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x14, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43,
- 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0xA6, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0,
- 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0xA6, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03,
- 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x06, 0x0A, 0x0C, 0x1C,
- 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00,
- 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00,
- 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x70, 0x03, 0x00, 0xF2, 0x60, 0x0B,
- 0x06, 0xF0, 0x80, 0x03, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A,
- 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xAC, 0x04, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2,
- 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x01, 0xF0,
- 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B, 0xBF, 0x57, 0x77, 0x57,
- 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x96, 0xF0, 0xBC, 0x03,
- 0xB1, 0xF0, 0xC0, 0x03, 0x1E, 0xF0, 0xFC, 0x09, 0x85, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0xBE, 0x00,
- 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11,
- 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A,
- 0x01, 0x48, 0x55, 0xF0, 0x98, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00, 0x9B, 0x57, 0x40, 0x12,
- 0x69, 0x18, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x42, 0x04, 0x69, 0x08, 0x00, 0xF2, 0x12, 0x11,
- 0x85, 0xF0, 0x02, 0x0A, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48, 0x03, 0xF6, 0xE0, 0x00,
- 0x00, 0xF2, 0x68, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xCC, 0x01, 0x48, 0x55, 0xF0,
- 0x98, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x14, 0x10, 0x08, 0x10,
- 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00, 0x28, 0x12,
- 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00,
- 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00,
- 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00,
- 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x82, 0xE7,
- 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D,
- 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0xA0, 0x04, 0x42, 0x5B, 0x06, 0xF7,
- 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00, 0x07, 0x80, 0x31, 0x44,
- 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x56, 0x13, 0x20, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x4E, 0x12,
- 0x00, 0xFC, 0xA2, 0x00, 0x98, 0x57, 0x55, 0xF0, 0x1C, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC,
- 0xA0, 0x00, 0x98, 0x57, 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x89, 0x48, 0x00, 0xF2,
- 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00,
- 0x5B, 0xF0, 0x0C, 0x05, 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x10, 0x05, 0x00, 0xE6, 0x20, 0x00,
- 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2,
- 0xA2, 0x0D, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80,
- 0x18, 0xE4, 0x10, 0x00, 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x01, 0xE6, 0x06, 0x00,
- 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4E, 0x0D,
- 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x04, 0xE6, 0x02, 0x00,
- 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0x20, 0x01,
- 0x98, 0x57, 0x34, 0x12, 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2,
- 0xF6, 0x0E, 0x86, 0xF0, 0xA8, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x8C, 0x0E, 0x85, 0xF0,
- 0x9E, 0x05, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC,
- 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12,
- 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00,
- 0x98, 0x57, 0x04, 0x13, 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01,
- 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6,
- 0x0F, 0x00, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x86, 0xF0, 0x0A, 0x06, 0x00, 0xF2, 0xBA, 0x0E,
- 0x85, 0xF0, 0x00, 0x06, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00,
- 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2,
- 0xF6, 0x0E, 0x9C, 0x32, 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x82, 0xE7,
- 0x04, 0x00, 0xB1, 0xF0, 0x22, 0x06, 0x0A, 0xF0, 0x3E, 0x06, 0x05, 0xF0, 0xD6, 0x06, 0x06, 0xF0,
- 0xDC, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x04, 0x80,
- 0x18, 0xE4, 0x20, 0x00, 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80,
- 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2,
- 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x12, 0x11,
- 0x09, 0xE7, 0x00, 0x00, 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7,
- 0x1B, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2,
- 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2,
- 0x12, 0x11, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0,
- 0x0C, 0x09, 0xBB, 0x55, 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0,
- 0xE2, 0x06, 0xB1, 0xF0, 0xC2, 0x06, 0x0A, 0xF0, 0xBA, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0,
- 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00,
- 0x41, 0x10, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA,
- 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54,
- 0x1F, 0x40, 0x00, 0xF2, 0xB4, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50,
- 0x9C, 0x32, 0x0C, 0x92, 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40,
- 0x0C, 0x1C, 0x00, 0xF6, 0x03, 0x00, 0xB1, 0xF0, 0x26, 0x07, 0x9E, 0xF0, 0x3A, 0x07, 0x01, 0x48,
- 0x55, 0xF0, 0xFC, 0x09, 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5E, 0x07, 0x0C, 0xF0,
- 0x62, 0x07, 0x05, 0xF0, 0x52, 0x07, 0x06, 0xF0, 0x58, 0x07, 0x09, 0xF0, 0x24, 0x09, 0x00, 0xF0,
- 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C,
- 0x02, 0x10, 0x2C, 0x1C, 0xAA, 0xF0, 0x64, 0x07, 0xAC, 0xF0, 0x72, 0x07, 0x40, 0x10, 0x34, 0x1C,
- 0xF3, 0x10, 0xAD, 0xF0, 0x7C, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x82, 0x08,
- 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x82, 0x08, 0x76, 0x18,
- 0x18, 0xF4, 0x03, 0x00, 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12,
- 0x0B, 0xF0, 0x64, 0x07, 0x0C, 0xF0, 0x64, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54,
- 0xB9, 0x54, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12,
- 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12,
- 0x1F, 0x40, 0x34, 0x91, 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49,
- 0xBB, 0x55, 0x82, 0x81, 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x1A, 0x08, 0x4A, 0xE4,
- 0x17, 0x00, 0xD5, 0xF0, 0xFA, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA,
- 0xB8, 0x00, 0x04, 0x91, 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50,
- 0x2C, 0x51, 0xAE, 0x51, 0x00, 0xF2, 0xB6, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB4, 0x0D, 0x56, 0x10,
- 0x34, 0x91, 0xB6, 0x91, 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91,
- 0x8E, 0x91, 0x04, 0x80, 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10,
- 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4,
- 0x20, 0x00, 0x10, 0x13, 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x78, 0x07, 0x0C, 0x58, 0x8D, 0x58,
- 0x00, 0xF0, 0x64, 0x07, 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81,
- 0xBB, 0x55, 0x10, 0x90, 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0,
- 0x64, 0x07, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10,
- 0x6C, 0x19, 0x0C, 0x51, 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13,
- 0x6A, 0x10, 0x01, 0x58, 0xD2, 0xF0, 0xC0, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12,
- 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10,
- 0xD1, 0xF0, 0xCA, 0x08, 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD4, 0x08, 0x9E, 0xE7,
- 0x19, 0x00, 0x38, 0x10, 0xCF, 0xF0, 0xDE, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0,
- 0xE8, 0x08, 0x9E, 0xE7, 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xF2, 0x08, 0x9E, 0xE7, 0x22, 0x00,
- 0x1A, 0x10, 0xCC, 0xF0, 0x04, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7,
- 0x12, 0x00, 0x08, 0x10, 0xCB, 0xF0, 0x0C, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x0C, 0x09,
- 0x05, 0xF0, 0x1E, 0x09, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0xE4, 0x10, 0x00, 0xF2,
- 0x60, 0x0B, 0xE9, 0x10, 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2,
- 0x12, 0x11, 0x85, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x01, 0xF0, 0x44, 0x09, 0x1E, 0xF0, 0xFC, 0x09,
- 0x00, 0xF0, 0x38, 0x09, 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6,
- 0x01, 0x00, 0xB3, 0x45, 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4,
- 0x02, 0x00, 0x36, 0x12, 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2,
- 0xC8, 0x11, 0x03, 0xF6, 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01,
- 0x9E, 0xE7, 0x44, 0x00, 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10,
- 0x00, 0xF2, 0xA2, 0x0D, 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0xA2, 0x0D, 0x19, 0x82,
- 0x34, 0x46, 0x0A, 0x13, 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80,
- 0x30, 0xE4, 0x20, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x82, 0xE7,
- 0x01, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00,
- 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12,
- 0x04, 0x80, 0x18, 0xE4, 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xEA, 0x09, 0x1C, 0x1C,
- 0x9D, 0xF0, 0xF0, 0x09, 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00,
- 0x04, 0x10, 0x9E, 0xE7, 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02,
- 0x04, 0xE6, 0x04, 0x00, 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7,
- 0x00, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58,
- 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2, 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x3C, 0x14, 0x1E, 0x1C,
- 0x00, 0xF0, 0x80, 0x01, 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59,
- 0x03, 0xDC, 0x73, 0x57, 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57,
- 0x33, 0x54, 0x3B, 0x54, 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC,
- 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00,
- 0x0E, 0x12, 0x48, 0xE4, 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11,
- 0xC1, 0x5A, 0x3A, 0x55, 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF6, 0x0D, 0x83, 0x58,
- 0x30, 0xE7, 0x00, 0x00, 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90,
- 0x10, 0x5C, 0x80, 0x5C, 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4,
- 0xE0, 0x00, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D,
- 0x00, 0xF2, 0x38, 0x10, 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18,
- 0x18, 0xF4, 0x8F, 0xE1, 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58,
- 0x00, 0xFC, 0xB0, 0x00, 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6,
- 0x0F, 0x00, 0x00, 0xEA, 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00,
- 0x18, 0x1C, 0x14, 0x1C, 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14,
- 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0xA2, 0x0D,
- 0x02, 0x4B, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58,
- 0x45, 0x58, 0x9E, 0xE7, 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2,
- 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x7A, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16,
- 0x69, 0x08, 0x48, 0xE4, 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4,
- 0x03, 0x00, 0x1A, 0x12, 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12,
- 0x48, 0xE4, 0x07, 0x00, 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2,
- 0x12, 0x11, 0x05, 0xF0, 0x60, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00,
- 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0xE7, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xE1, 0x12, 0x01, 0xE6,
- 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7,
- 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4,
- 0x10, 0x00, 0x1C, 0x12, 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xE2, 0x0D,
- 0x30, 0xE7, 0x08, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01,
- 0x6C, 0x19, 0xED, 0x19, 0x5D, 0xF0, 0xD4, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x52, 0x0C,
- 0x04, 0x55, 0xA5, 0x55, 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44,
- 0x2E, 0x13, 0x01, 0xEC, 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4,
- 0x11, 0x00, 0x59, 0xF0, 0x2E, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B,
- 0x88, 0x90, 0xAC, 0x50, 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80,
- 0x10, 0x44, 0x02, 0x4B, 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB4, 0x0D, 0x04, 0x55, 0xA5, 0x55,
- 0x9F, 0x10, 0x0C, 0x51, 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50,
- 0xB2, 0x50, 0x34, 0x90, 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10,
- 0xB1, 0xF0, 0x70, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12,
- 0x4B, 0xE4, 0x02, 0x00, 0x01, 0x13, 0xB1, 0xF0, 0x86, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0x69, 0x08,
- 0x48, 0xE4, 0x03, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0xCA, 0x0B,
- 0xE8, 0x09, 0x3C, 0x56, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4,
- 0x00, 0x00, 0x08, 0x12, 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14,
- 0x30, 0x1C, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57,
- 0x02, 0x13, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57,
- 0x00, 0xFA, 0x24, 0x01, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B,
- 0x00, 0xF2, 0x8C, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0xB1, 0xF0, 0xF8, 0x0C, 0x85, 0xF0, 0x86, 0x0B,
- 0x69, 0x08, 0x48, 0xE4, 0x01, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14,
- 0x80, 0x14, 0x30, 0x1C, 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x86, 0x0B, 0x4A, 0xF4, 0x01, 0x00,
- 0x0E, 0x12, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B,
- 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2,
- 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B, 0x00, 0xF2, 0xBA, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0x4C, 0x1C,
- 0xB1, 0xF0, 0x50, 0x0D, 0x85, 0xF0, 0x5C, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x64, 0x0D,
- 0x4E, 0x1C, 0x89, 0x48, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58,
- 0x00, 0xDC, 0x18, 0xF4, 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01,
- 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C,
- 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58,
- 0x00, 0x16, 0x03, 0xF6, 0x24, 0x01, 0x00, 0xF2, 0x58, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2,
- 0x58, 0x0A, 0x00, 0x16, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54,
- 0x00, 0x54, 0x00, 0x54, 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD,
- 0x01, 0xDD, 0x02, 0xDD, 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51,
- 0x00, 0x16, 0x45, 0x5A, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4,
- 0x02, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56,
- 0x05, 0xF4, 0x00, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56,
- 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x82, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x12, 0x11,
- 0x85, 0xF0, 0x82, 0x0E, 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0,
- 0x36, 0x0E, 0xBD, 0x56, 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x48, 0x0E, 0x01, 0xF6,
- 0x0C, 0x00, 0x00, 0xF6, 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13,
- 0x4B, 0xF4, 0x64, 0x00, 0x59, 0xF0, 0x64, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00,
- 0x00, 0xF6, 0x01, 0x00, 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x76, 0x0E, 0x04, 0xF4, 0x00, 0x01,
- 0x43, 0xF4, 0x19, 0x00, 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57,
- 0x08, 0x13, 0x3C, 0x56, 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00,
- 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x12, 0x11,
- 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E,
- 0x4E, 0x1C, 0x89, 0x49, 0x00, 0xF2, 0x12, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2,
- 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0,
- 0xF2, 0x0E, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x89, 0x49,
- 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x12, 0x11,
- 0x00, 0x16, 0x3C, 0x56, 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13,
- 0x38, 0x44, 0x00, 0xEA, 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10,
- 0x4C, 0x1C, 0x01, 0xEC, 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x02, 0x14, 0x00, 0x16,
- 0x85, 0xF0, 0x52, 0x0F, 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x02, 0x80,
- 0x48, 0xE4, 0x06, 0x00, 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12,
- 0x04, 0x80, 0x30, 0xE4, 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00,
- 0x04, 0x40, 0x00, 0x16, 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48,
- 0x22, 0x12, 0x00, 0x4E, 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4,
- 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59,
- 0x00, 0x4E, 0x00, 0x16, 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E,
- 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00,
- 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C,
- 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12,
- 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55,
- 0x02, 0xCC, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD,
- 0x01, 0xCC, 0x4A, 0x46, 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10,
- 0xC5, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00,
- 0x05, 0x57, 0x08, 0x10, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C,
- 0x05, 0x17, 0x00, 0x16, 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2,
- 0xE2, 0x0D, 0x02, 0x80, 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00,
- 0x06, 0x14, 0x00, 0xF2, 0x54, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C,
- 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0,
- 0x4E, 0x10, 0x9C, 0x14, 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00,
- 0xAF, 0x19, 0x03, 0x42, 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4,
- 0x02, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x3E, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6,
- 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7,
- 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x9C, 0x10,
- 0x4E, 0x14, 0x01, 0x48, 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0,
- 0x82, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC,
- 0xE2, 0x08, 0x00, 0xEC, 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xCC, 0x10,
- 0x1E, 0x14, 0x01, 0x48, 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19,
- 0x82, 0x48, 0x00, 0x16, 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xBA, 0x10, 0x00, 0xF0, 0x9E, 0x02,
- 0x39, 0xF0, 0xF8, 0x10, 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13,
- 0x61, 0x18, 0x00, 0x16, 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12,
- 0xE3, 0x10, 0x30, 0x44, 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x18, 0x11, 0x00, 0x16, 0x3E, 0x57,
- 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A,
- 0x00, 0xF2, 0xF6, 0x0D, 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00,
- 0x18, 0x12, 0x9C, 0xE7, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2,
- 0x7A, 0x0A, 0x1E, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40,
- 0x00, 0xF2, 0xE2, 0x0D, 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC,
- 0x01, 0x4A, 0x24, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00,
- 0x00, 0xF2, 0x38, 0x10, 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2,
- 0x14, 0x10, 0xA7, 0x10, 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47,
- 0x5A, 0xF0, 0x20, 0x11, 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00,
- 0x03, 0xFC, 0xAA, 0x00, 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00,
- 0x10, 0x44, 0x00, 0xEA, 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A,
- 0x10, 0x44, 0x00, 0x4C, 0x00, 0x16
-};
-
-unsigned short _adv_mcode_size ASC_INITDATA =
- sizeof(_adv_mcode_buf); /* 0x11D6 */
-unsigned long _adv_mcode_chksum ASC_INITDATA = 0x03494981UL;
+/* a_mcode.h */
+STATIC unsigned char _adv_asc3550_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x01, 0xf6,
+ 0x00, 0xf6, 0x18, 0xe4, 0x0a, 0x19, 0x18, 0x80, 0x02, 0x00, 0xff, 0xff, 0x03, 0xf6, 0x00, 0xfa,
+ 0xff, 0x00, 0x82, 0xe7, 0x9e, 0xe7, 0x01, 0xfa, 0x06, 0x0e, 0x09, 0xe7, 0x00, 0xea, 0x01, 0xe6,
+ 0x03, 0x00, 0x08, 0x00, 0x18, 0xf4, 0x55, 0xf0, 0x3e, 0x01, 0x3e, 0x57, 0x04, 0x00, 0x1e, 0xf0,
+ 0x85, 0xf0, 0x00, 0xe6, 0x00, 0xec, 0x32, 0xf0, 0x86, 0xf0, 0xa4, 0x0c, 0xd0, 0x01, 0xd5, 0xf0,
+ 0xf6, 0x18, 0x38, 0x54, 0x98, 0x57, 0xbc, 0x00, 0xb1, 0xf0, 0xb4, 0x00, 0x01, 0xfc, 0x02, 0x13,
+ 0x03, 0xfc, 0x9e, 0x0c, 0x00, 0x57, 0x01, 0xf0, 0x03, 0xe6, 0x0c, 0x1c, 0x10, 0x00, 0x18, 0x40,
+ 0x30, 0x12, 0x3e, 0x1c, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x48, 0x02, 0x80, 0x3c, 0x00, 0x4e, 0x01,
+ 0x66, 0x15, 0x6c, 0x01, 0x6e, 0x01, 0xbb, 0x00, 0xda, 0x12, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea,
+ 0x08, 0x12, 0x30, 0xe4, 0x6a, 0x0f, 0xa8, 0x0c, 0xae, 0x0f, 0xb6, 0x00, 0xb9, 0x54, 0x00, 0x80,
+ 0x04, 0x12, 0x06, 0xf7, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x3c, 0x56, 0x3e, 0x00,
+ 0x4b, 0xe4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
+ 0x78, 0x01, 0x00, 0x01, 0x02, 0xee, 0x02, 0xfc, 0x03, 0x58, 0x03, 0xf7, 0x04, 0x80, 0x05, 0xfc,
+ 0x08, 0x44, 0x09, 0xf0, 0x0a, 0x15, 0x10, 0x44, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, 0x40, 0x00,
+ 0x4b, 0xf4, 0x4e, 0x1c, 0x5b, 0xf0, 0x5d, 0xf0, 0x80, 0x00, 0xaa, 0x00, 0xaa, 0x14, 0xb6, 0x08,
+ 0xb8, 0x0f, 0xbb, 0x55, 0xbd, 0x56, 0xbe, 0x00, 0xc0, 0x00, 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a,
+ 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x08, 0x13, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x0f, 0x00,
+ 0x19, 0x00, 0x20, 0x00, 0x2a, 0x01, 0x32, 0x1c, 0x36, 0x00, 0x38, 0x12, 0x3c, 0x0b, 0x45, 0x5a,
+ 0x56, 0x14, 0x59, 0xf0, 0x62, 0x0a, 0x69, 0x08, 0x83, 0x59, 0xae, 0x17, 0xb8, 0xf0, 0xba, 0x0f,
+ 0xba, 0x17, 0xf0, 0x00, 0xf6, 0x0d, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6,
+ 0x04, 0xfc, 0x05, 0x00, 0x06, 0x00, 0x06, 0x12, 0x0a, 0x10, 0x0b, 0xf0, 0x0c, 0xf0, 0x12, 0x10,
+ 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, 0x40, 0x5c, 0x4a, 0xe4, 0x5a, 0x14, 0x62, 0x1a,
+ 0x64, 0x0a, 0x68, 0x08, 0x68, 0x54, 0x83, 0x55, 0x83, 0x5a, 0x91, 0x44, 0x98, 0x12, 0x9a, 0x16,
+ 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xce, 0x45, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
+ 0xec, 0x0d, 0x00, 0x54, 0x01, 0x48, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, 0x03, 0xa1, 0x04, 0x13,
+ 0x05, 0xe6, 0x06, 0x0b, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0,
+ 0x0c, 0x04, 0x0c, 0x10, 0x0c, 0x12, 0x0e, 0x13, 0x10, 0x10, 0x12, 0x1c, 0x17, 0x00, 0x18, 0x0e,
+ 0x19, 0xe4, 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c,
+ 0x20, 0xe7, 0x22, 0x01, 0x26, 0x01, 0x2a, 0x12, 0x30, 0xe7, 0x41, 0x58, 0x43, 0x48, 0x44, 0x55,
+ 0x46, 0x1c, 0x4e, 0xe4, 0x5c, 0xf0, 0x72, 0x02, 0x74, 0x03, 0x77, 0x57, 0x88, 0x12, 0x89, 0x48,
+ 0x92, 0x13, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x12, 0xb9, 0x00,
+ 0xba, 0x06, 0xbf, 0x57, 0xc0, 0x01, 0xc0, 0x08, 0xc2, 0x01, 0xfe, 0x9c, 0xf0, 0x26, 0x02, 0xfe,
+ 0xc6, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xfc, 0xfe, 0x18, 0x19, 0x00, 0xfa, 0xfe, 0x80, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0x2f, 0xfe, 0x01, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d, 0xff, 0x09, 0x00, 0x00,
+ 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff,
+ 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04,
+ 0xf7, 0xfa, 0x35, 0x51, 0x0c, 0x01, 0xfe, 0xb6, 0x0e, 0xfe, 0x04, 0xf7, 0xfa, 0x51, 0x0c, 0x1d,
+ 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x20, 0xf0, 0xd0, 0x04, 0x55, 0x50, 0x02, 0xfe,
+ 0xe2, 0x0c, 0x01, 0xfe, 0x42, 0x0d, 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x04, 0x03, 0xfe, 0x28, 0x1c,
+ 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x4e, 0x13, 0xfe, 0xa6, 0x00, 0xc3, 0xfe, 0x48, 0xf0,
+ 0xfe, 0x7c, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x96, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb4, 0x02, 0xfe,
+ 0x46, 0xf0, 0xfe, 0x46, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3a,
+ 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x42, 0x02, 0x07, 0x0c, 0x9d,
+ 0x07, 0x06, 0x13, 0xb8, 0x02, 0x26, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe,
+ 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x0e, 0x17, 0xfe, 0xe7, 0x10, 0xfe,
+ 0x06, 0xfc, 0xf5, 0x0e, 0x7b, 0x01, 0xc0, 0x02, 0x26, 0x17, 0x54, 0x47, 0xba, 0x01, 0xfe, 0x2c,
+ 0x0f, 0x0e, 0x7b, 0x01, 0x9a, 0xfe, 0xbd, 0x10, 0x0e, 0x7b, 0x01, 0x9a, 0xfe, 0xad, 0x10, 0xfe,
+ 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x07, 0x06, 0x13, 0xb8, 0x35, 0x1f, 0x26, 0xfe, 0x3d, 0xf0, 0xfe,
+ 0xf8, 0x01, 0x27, 0xfe, 0x8a, 0x02, 0xfe, 0x5a, 0x1c, 0xd5, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30,
+ 0x00, 0x47, 0xba, 0x01, 0xfe, 0x1c, 0x0f, 0x07, 0x06, 0x13, 0xb8, 0x02, 0xfc, 0x22, 0x2b, 0x05,
+ 0x10, 0x2f, 0xfe, 0x69, 0x10, 0x07, 0x06, 0x13, 0xb8, 0xfe, 0x04, 0xec, 0x2b, 0x08, 0x2b, 0x07,
+ 0x3a, 0x1d, 0x01, 0x40, 0x7f, 0xfe, 0x05, 0xf6, 0xf5, 0x01, 0xfe, 0x40, 0x16, 0x0b, 0x49, 0x89,
+ 0x37, 0x11, 0x43, 0x1d, 0xca, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x6a, 0x02, 0x26, 0x0e, 0x3b, 0x01,
+ 0x14, 0x05, 0x10, 0xd3, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0xfe, 0x28, 0x10, 0x0e, 0xbd, 0x01,
+ 0x14, 0xe5, 0x0e, 0x7c, 0x01, 0x14, 0xfe, 0x49, 0x54, 0x72, 0xfe, 0x12, 0x03, 0x08, 0x1c, 0x07,
+ 0x3f, 0x01, 0x6a, 0x02, 0x26, 0x35, 0x7f, 0xfe, 0x02, 0xe8, 0x2d, 0xf9, 0xfe, 0x9e, 0x43, 0xed,
+ 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xd0, 0xfe, 0x40, 0x1c, 0x1f, 0xec, 0xfe, 0x26, 0xf0, 0xfe,
+ 0x70, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x5e, 0x03, 0xfe, 0x11, 0xf0, 0xd0, 0xfe, 0x0e, 0x10, 0xfe,
+ 0x9f, 0xf0, 0xfe, 0x7e, 0x03, 0xe8, 0x12, 0xfe, 0x11, 0x00, 0x02, 0x4b, 0x35, 0xfe, 0x48, 0x1c,
+ 0xe8, 0x1f, 0xec, 0x33, 0xec, 0xfe, 0x82, 0xf0, 0xfe, 0x84, 0x03, 0x29, 0x22, 0xbb, 0x68, 0x16,
+ 0xbb, 0x0e, 0x7c, 0x01, 0x14, 0x68, 0x7d, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x40, 0x11, 0x3b, 0x08,
+ 0x3b, 0x07, 0x99, 0x01, 0x6a, 0xf3, 0x11, 0xfe, 0xe4, 0x00, 0x2c, 0xfe, 0xca, 0x03, 0x1f, 0x31,
+ 0x20, 0xfe, 0xda, 0x03, 0x01, 0x4a, 0xcb, 0xfe, 0xea, 0x03, 0x69, 0x8e, 0xcf, 0xfe, 0xaa, 0x06,
+ 0x02, 0x25, 0x04, 0x7b, 0x2a, 0x1b, 0xfe, 0x1c, 0x05, 0x17, 0x84, 0x01, 0x38, 0x01, 0x95, 0x01,
+ 0x98, 0x33, 0xfe, 0x5c, 0x02, 0x02, 0xeb, 0xe8, 0x35, 0x51, 0x18, 0xfe, 0x67, 0x1b, 0xf9, 0xed,
+ 0xfe, 0x48, 0x1c, 0x8b, 0x01, 0xee, 0xa8, 0xfe, 0x96, 0xf0, 0xfe, 0x24, 0x04, 0x2c, 0xfe, 0x28,
+ 0x04, 0x33, 0x26, 0x0e, 0x3b, 0x01, 0x14, 0x05, 0x10, 0x1b, 0xfe, 0x08, 0x05, 0x3c, 0x92, 0x9e,
+ 0x2d, 0x81, 0x6d, 0x1f, 0x31, 0x20, 0x25, 0x04, 0x7b, 0x2a, 0xfe, 0x10, 0x12, 0x17, 0x84, 0x01,
+ 0x38, 0x33, 0xfe, 0x5c, 0x02, 0x02, 0xeb, 0x30, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e,
+ 0x12, 0x0b, 0x09, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x28, 0x93, 0x01, 0x0a, 0x81, 0x6d, 0x20, 0xfe,
+ 0xd8, 0x04, 0x23, 0x28, 0x93, 0x01, 0x0a, 0x20, 0x25, 0x23, 0x28, 0xb1, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x32, 0x12, 0x56, 0xfe, 0x44, 0x48, 0x08, 0xd6, 0xfe, 0x4c, 0x54, 0x72, 0xfe, 0x08, 0x05, 0x7f,
+ 0x9e, 0x2d, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, 0x13, 0x3d, 0x05, 0xfe, 0xcc, 0x00,
+ 0xfe, 0x40, 0x13, 0x0b, 0x09, 0x06, 0x8d, 0xfe, 0x06, 0x10, 0x23, 0x28, 0xb1, 0x0b, 0x09, 0x36,
+ 0xdb, 0x17, 0xa2, 0x0b, 0x09, 0x06, 0x50, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x38, 0x33, 0xfe, 0x86,
+ 0x0c, 0x02, 0x25, 0x39, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xac, 0x03, 0x17, 0xa2, 0x01,
+ 0x38, 0x33, 0x26, 0x1f, 0x26, 0x02, 0xfe, 0x10, 0x05, 0xfe, 0x42, 0x5b, 0x51, 0x18, 0xfe, 0x46,
+ 0x59, 0xf9, 0xed, 0x17, 0x74, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0b, 0x09, 0x0c, 0xfe, 0x78,
+ 0x13, 0xfe, 0x20, 0x80, 0x05, 0x18, 0xfe, 0x70, 0x12, 0x6c, 0x09, 0x06, 0xfe, 0x60, 0x13, 0x04,
+ 0xfe, 0xa2, 0x00, 0x2a, 0x1b, 0xfe, 0xa8, 0x05, 0xfe, 0x31, 0xe4, 0x6f, 0x6c, 0x09, 0x0c, 0xfe,
+ 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x2a, 0xfe, 0x42, 0x12, 0x59, 0x2c, 0xfe, 0x68, 0x05, 0x1f,
+ 0x31, 0xef, 0x01, 0x0a, 0x24, 0xfe, 0xc0, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x29, 0x6c, 0xfe, 0x4a,
+ 0xf0, 0xfe, 0x92, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x8c, 0x05, 0xd1, 0x21, 0xfe, 0x21, 0x00, 0xa4,
+ 0x21, 0xfe, 0x22, 0x00, 0x9d, 0x21, 0x89, 0xfe, 0x09, 0x48, 0x01, 0x0a, 0x24, 0xfe, 0xc0, 0x05,
+ 0xfe, 0xe2, 0x08, 0x6c, 0x09, 0xda, 0x50, 0x01, 0xb6, 0x21, 0x06, 0x16, 0xe2, 0x47, 0xfe, 0x27,
+ 0x01, 0x0b, 0x09, 0x36, 0xe3, 0x4e, 0x01, 0xae, 0x17, 0xa2, 0x0b, 0x09, 0x06, 0x50, 0x17, 0xfe,
+ 0x0d, 0x00, 0x01, 0x38, 0x01, 0x95, 0x01, 0x98, 0x33, 0xfe, 0x86, 0x0c, 0x02, 0x25, 0x04, 0xfe,
+ 0x9c, 0x00, 0x2a, 0xfe, 0x3e, 0x12, 0x04, 0x52, 0x2a, 0xfe, 0x36, 0x13, 0x4e, 0x01, 0xae, 0x24,
+ 0xfe, 0x38, 0x06, 0x0e, 0x06, 0x6c, 0x09, 0x19, 0xfe, 0x02, 0x12, 0x79, 0x01, 0xfe, 0xf0, 0x13,
+ 0x20, 0xfe, 0x2e, 0x06, 0x11, 0xbe, 0x01, 0x4a, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x52, 0xb9, 0x0f,
+ 0x52, 0x04, 0xf4, 0x2a, 0xfe, 0x62, 0x12, 0x04, 0x4d, 0x2a, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x60,
+ 0x18, 0x01, 0xfe, 0xb2, 0x18, 0xe6, 0xc8, 0x19, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e,
+ 0x1a, 0x4f, 0xc7, 0xc8, 0x87, 0x4e, 0x01, 0xae, 0x24, 0xfe, 0xa2, 0x06, 0x6c, 0x09, 0x1e, 0xa3,
+ 0x7a, 0x0e, 0x54, 0x01, 0xfe, 0x1e, 0x14, 0x20, 0xfe, 0x98, 0x06, 0x11, 0xbe, 0x01, 0x4a, 0x11,
+ 0xfe, 0xe5, 0x00, 0x04, 0x4d, 0xb9, 0x0f, 0x4d, 0x07, 0x06, 0x01, 0xae, 0xf3, 0x71, 0x8b, 0x01,
+ 0xee, 0xa8, 0x11, 0xfe, 0xe2, 0x00, 0x2c, 0xf8, 0x1f, 0x31, 0xcf, 0xfe, 0xd6, 0x06, 0x80, 0xfe,
+ 0x74, 0x07, 0xcb, 0xfe, 0x7c, 0x07, 0x69, 0x8e, 0x02, 0x25, 0x0b, 0x09, 0x0c, 0xfe, 0x2e, 0x12,
+ 0x15, 0x18, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a,
+ 0xfe, 0x99, 0xa4, 0x01, 0x0a, 0x15, 0x00, 0x02, 0xfe, 0x3a, 0x08, 0x66, 0x09, 0x1e, 0x8d, 0x0b,
+ 0x09, 0x1e, 0xfe, 0x30, 0x13, 0x15, 0xfe, 0x1b, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15,
+ 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x06, 0x01, 0x0a, 0x15, 0x00, 0x02, 0xc9, 0x79,
+ 0xfe, 0x9a, 0x81, 0x65, 0x89, 0xfe, 0x09, 0x6f, 0xfe, 0x93, 0x45, 0x1b, 0xfe, 0x84, 0x07, 0x2c,
+ 0xfe, 0x5c, 0x07, 0x1f, 0x31, 0xcf, 0xfe, 0x54, 0x07, 0x69, 0x8e, 0x80, 0xfe, 0x74, 0x07, 0x02,
+ 0x25, 0x01, 0x4a, 0x02, 0xf8, 0x15, 0x19, 0x02, 0xf8, 0xfe, 0x9c, 0xf7, 0xfe, 0xf0, 0x07, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x73, 0xfe, 0xd2, 0x07, 0x0f, 0x5c, 0x13, 0x5d, 0x0b, 0x49, 0x6f,
+ 0x37, 0x01, 0xfe, 0xf6, 0x17, 0x05, 0x10, 0x82, 0xfe, 0x83, 0xe7, 0x88, 0xa4, 0xfe, 0x03, 0x40,
+ 0x0b, 0x49, 0x74, 0x37, 0x01, 0xb7, 0xab, 0xfe, 0x1f, 0x40, 0x16, 0x60, 0x01, 0xf6, 0xfe, 0x08,
+ 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0f, 0x5a, 0x13, 0x5b, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50,
+ 0x0f, 0x41, 0x13, 0x42, 0xfe, 0x4a, 0x10, 0x0b, 0x09, 0x6f, 0xe3, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x0f, 0x5c, 0x13, 0x5d, 0x0b, 0x09, 0x74, 0xc7, 0x01, 0xb7, 0xfe, 0x1f, 0x80, 0x16, 0x60,
+ 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0f, 0x5e, 0x13, 0x5f, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0f, 0x5a, 0x13, 0x5b, 0xfe, 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0f, 0x41, 0x13, 0x42, 0x0f, 0x3e,
+ 0x13, 0x57, 0x0b, 0x49, 0x19, 0x37, 0x35, 0x08, 0xa1, 0x2c, 0xfe, 0x50, 0x08, 0xfe, 0x9e, 0xf0,
+ 0xfe, 0x64, 0x08, 0xc2, 0x1b, 0x31, 0x35, 0x6b, 0xfe, 0xed, 0x10, 0xa5, 0xfe, 0x88, 0x08, 0xa6,
+ 0xfe, 0xa4, 0x08, 0x80, 0xfe, 0x7c, 0x08, 0xcb, 0xfe, 0x82, 0x08, 0x69, 0x8e, 0x02, 0x25, 0x01,
+ 0x4a, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x66, 0x09, 0x06, 0xfe, 0x10, 0x12, 0x66,
+ 0x09, 0x0c, 0x48, 0x0b, 0x09, 0x0c, 0xfe, 0x66, 0x12, 0xfe, 0x2e, 0x1c, 0xa7, 0x66, 0x09, 0x06,
+ 0x48, 0x66, 0x09, 0x0c, 0xfe, 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x24, 0x09,
+ 0xfe, 0xac, 0xf0, 0xfe, 0xc4, 0x08, 0xfe, 0x92, 0x10, 0xfe, 0x34, 0x1c, 0xfe, 0xf3, 0x10, 0xfe,
+ 0xad, 0xf0, 0xfe, 0xd0, 0x08, 0x02, 0xfe, 0x32, 0x0a, 0xfe, 0x36, 0x1c, 0xfe, 0xe7, 0x10, 0xfe,
+ 0x2b, 0xf0, 0xb0, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xfe, 0xdb, 0xc3, 0xfe, 0xd2, 0xf0, 0xb0,
+ 0xfe, 0x76, 0x18, 0x1a, 0x18, 0x1b, 0xb0, 0x04, 0xe1, 0x1a, 0x06, 0x1b, 0xb0, 0xa5, 0x77, 0xa6,
+ 0x77, 0xfe, 0x34, 0x1c, 0xfe, 0x36, 0x1c, 0xfe, 0xb1, 0x10, 0x8b, 0x59, 0x39, 0x17, 0xa2, 0x01,
+ 0x38, 0x12, 0xfe, 0x35, 0x00, 0x33, 0x4b, 0x12, 0x8c, 0x02, 0x4b, 0xfe, 0x74, 0x18, 0x1a, 0xfe,
+ 0x00, 0xf8, 0x1b, 0x77, 0x51, 0x1e, 0x01, 0xfe, 0x42, 0x0d, 0xd2, 0x08, 0x1c, 0x07, 0x3f, 0x01,
+ 0x6a, 0x22, 0x2d, 0x3c, 0x51, 0x18, 0x02, 0x77, 0xfe, 0x98, 0x80, 0xd8, 0x0c, 0x27, 0xfe, 0x14,
+ 0x0a, 0x0b, 0x09, 0x6f, 0xfe, 0x82, 0x12, 0x0b, 0x09, 0x19, 0xfe, 0x66, 0x13, 0x22, 0x60, 0x68,
+ 0xc6, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91,
+ 0x62, 0x2d, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x73, 0xfb, 0x04, 0x5c, 0x2e, 0x5d, 0x0f, 0xaa,
+ 0x13, 0x8c, 0x9b, 0x5c, 0x9c, 0x5d, 0x01, 0xb7, 0xab, 0x62, 0x2d, 0x16, 0x60, 0xa0, 0x3e, 0x67,
+ 0x57, 0x63, 0x5e, 0x30, 0x5f, 0xe7, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x3e, 0xfe, 0x05, 0xfa,
+ 0x57, 0x01, 0xf6, 0xfe, 0x36, 0x10, 0x29, 0x0f, 0xaa, 0x0f, 0x8c, 0x63, 0x5e, 0x30, 0x5f, 0xa7,
+ 0x0b, 0x09, 0x19, 0x1b, 0xfb, 0x63, 0x41, 0x30, 0x42, 0x0b, 0x09, 0xfe, 0xf7, 0x00, 0x37, 0x04,
+ 0x5a, 0x2e, 0x5b, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02,
+ 0x77, 0x0b, 0x09, 0x19, 0x1b, 0xfb, 0x0b, 0x09, 0xfe, 0xf7, 0x00, 0x37, 0xfe, 0x3a, 0x55, 0xfe,
+ 0x19, 0x81, 0x79, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x3d, 0x05, 0xbf, 0x1b,
+ 0xfe, 0xcc, 0x08, 0x11, 0xbf, 0xfe, 0x98, 0x80, 0xd8, 0x0c, 0xfe, 0x14, 0x13, 0x04, 0x41, 0x2e,
+ 0x42, 0x73, 0xfe, 0xcc, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x77, 0x29, 0x4e, 0xfe,
+ 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0b, 0x09, 0x0c, 0xa3, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe,
+ 0x94, 0x10, 0xfe, 0x6c, 0x19, 0x9b, 0x41, 0xfe, 0xed, 0x19, 0x9c, 0x42, 0xfe, 0x0c, 0x51, 0xfe,
+ 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xff, 0x2f, 0xfe, 0x7a, 0x10, 0xc3, 0xfe, 0xd2,
+ 0xf0, 0xfe, 0xac, 0x0a, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0xce, 0x04, 0xe1, 0x1a, 0x06, 0x83, 0x12,
+ 0xfe, 0x16, 0x00, 0x02, 0x4b, 0xfe, 0xd1, 0xf0, 0xfe, 0xe2, 0x0a, 0x17, 0xa1, 0x01, 0x38, 0x12,
+ 0xd6, 0xfe, 0x48, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, 0x0a, 0x12, 0xfe, 0x21, 0x00, 0x02, 0x4b,
+ 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x12, 0xfe, 0x22, 0x00, 0x02, 0x4b, 0xfe, 0xcb, 0xf0, 0xfe,
+ 0xe2, 0x0a, 0x12, 0xfe, 0x24, 0x00, 0x02, 0x4b, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x12, 0x88,
+ 0xd9, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x12, 0x89, 0xd4, 0xfe, 0xcc, 0xf0, 0xc9, 0xfe, 0x84,
+ 0x80, 0xd8, 0x19, 0xfe, 0xd5, 0x12, 0x12, 0xfe, 0x12, 0x00, 0x2c, 0xc9, 0x1f, 0x31, 0xa5, 0x25,
+ 0xa6, 0x25, 0x35, 0xf3, 0x2c, 0xfe, 0x1a, 0x0b, 0x1f, 0x31, 0x80, 0xfe, 0x36, 0x0b, 0x69, 0x8e,
+ 0xa5, 0xfe, 0xf0, 0x07, 0xa6, 0xfe, 0xf0, 0x07, 0x02, 0x25, 0x01, 0x4a, 0xfe, 0xdb, 0x10, 0x11,
+ 0xfe, 0xe8, 0x00, 0x8b, 0x81, 0x6d, 0xfe, 0x89, 0xf0, 0x25, 0x23, 0x28, 0xfe, 0xe9, 0x09, 0x01,
+ 0x0a, 0x81, 0x6d, 0x20, 0x25, 0x23, 0x28, 0x93, 0x33, 0xfe, 0x6e, 0x0b, 0x1f, 0x31, 0x02, 0xfe,
+ 0x62, 0x0b, 0xc2, 0x48, 0x12, 0xfe, 0x42, 0x00, 0x02, 0x4b, 0x9f, 0x06, 0xfe, 0x81, 0x49, 0xfe,
+ 0xcc, 0x12, 0x0b, 0x09, 0x0c, 0xfe, 0x5a, 0x13, 0x12, 0x00, 0x58, 0x0c, 0xfe, 0x6a, 0x12, 0x58,
+ 0xfe, 0x28, 0x00, 0x27, 0xfe, 0xb4, 0x0c, 0x0e, 0x7c, 0x01, 0x14, 0x05, 0x00, 0x83, 0x34, 0xfe,
+ 0x28, 0x00, 0x02, 0xfe, 0xb4, 0x0c, 0x01, 0x95, 0x01, 0x98, 0x0e, 0xbd, 0x01, 0xfe, 0x10, 0x0e,
+ 0xaf, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0x02,
+ 0x26, 0x12, 0xfe, 0x44, 0x00, 0x58, 0x0c, 0xa3, 0x34, 0x0c, 0xfe, 0xc0, 0x10, 0x01, 0xb6, 0x34,
+ 0x0c, 0xfe, 0xb6, 0x10, 0x01, 0xb6, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x34,
+ 0x0c, 0x12, 0xfe, 0x43, 0x00, 0xfe, 0xa2, 0x10, 0x0b, 0x49, 0x0c, 0x37, 0x01, 0x95, 0x01, 0x98,
+ 0xaf, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0x51,
+ 0x0c, 0xaf, 0x1d, 0xca, 0x02, 0xfe, 0x48, 0x03, 0x0b, 0x09, 0x0c, 0xce, 0x34, 0x0c, 0x12, 0x00,
+ 0xfe, 0x54, 0x10, 0x66, 0x09, 0x1e, 0xfe, 0x50, 0x12, 0x0b, 0x09, 0x1e, 0xfe, 0x48, 0x13, 0xfe,
+ 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x72, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x78,
+ 0x0c, 0x0b, 0x49, 0x1e, 0x37, 0xfe, 0x95, 0x10, 0x12, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0c,
+ 0x79, 0xfe, 0x26, 0x10, 0x12, 0xfe, 0x13, 0x00, 0xd4, 0x12, 0xfe, 0x47, 0x00, 0xa4, 0x12, 0xfe,
+ 0x41, 0x00, 0x9d, 0x12, 0xfe, 0x24, 0x00, 0x04, 0x7b, 0x2a, 0x27, 0xeb, 0x79, 0xfe, 0x04, 0xe6,
+ 0x1e, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0xaf, 0x01, 0xd7, 0x02, 0x26, 0xd5, 0x17, 0x0c, 0x47,
+ 0xf2, 0xdf, 0x17, 0xfe, 0x31, 0x00, 0x47, 0xba, 0x01, 0xfe, 0x1c, 0x0f, 0x02, 0xfc, 0x1d, 0xfe,
+ 0x06, 0xec, 0xf7, 0x85, 0x34, 0x36, 0xbc, 0x2f, 0x1d, 0xfe, 0x06, 0xea, 0xf7, 0xfe, 0x47, 0x4b,
+ 0x7a, 0xfe, 0x75, 0x57, 0x04, 0x55, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0e, 0x7c, 0xfe, 0xfa,
+ 0x14, 0x4e, 0xe5, 0x0e, 0xbd, 0xfe, 0xf0, 0x14, 0xfe, 0x49, 0x54, 0x91, 0xfe, 0x28, 0x0d, 0x0e,
+ 0x1c, 0xfe, 0xe4, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x48, 0x03, 0x0e, 0x55, 0xfe, 0xc8, 0x14,
+ 0x85, 0x34, 0x36, 0xbc, 0x2f, 0x1d, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x26, 0x22, 0x2b,
+ 0x05, 0x10, 0xfe, 0x78, 0x12, 0x29, 0x16, 0x54, 0x16, 0xa9, 0x22, 0x43, 0x4e, 0x47, 0x43, 0xc2,
+ 0xfe, 0x0c, 0x13, 0xfe, 0xbc, 0xf0, 0xfe, 0xc4, 0x0d, 0x08, 0x06, 0x16, 0x54, 0x01, 0xfe, 0xd0,
+ 0x15, 0x04, 0xfe, 0x38, 0x01, 0x2e, 0xfe, 0x3a, 0x01, 0x73, 0xfe, 0xc8, 0x0d, 0x04, 0xfe, 0x38,
+ 0x01, 0x1a, 0xfe, 0xf0, 0xff, 0x0f, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0f, 0xfe, 0x62,
+ 0x01, 0x21, 0x06, 0x16, 0x43, 0xfe, 0x04, 0xec, 0x2b, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x01, 0x40,
+ 0x7f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x40, 0x16, 0x11, 0x43, 0xca, 0x08, 0x06,
+ 0x03, 0x29, 0x03, 0x22, 0x54, 0xfe, 0xf7, 0x12, 0x22, 0xa9, 0x68, 0x16, 0xa9, 0x05, 0xa1, 0xfe,
+ 0x93, 0x13, 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x47, 0xf2, 0xdf, 0xfe, 0xd9, 0x10, 0x94, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x94, 0xfe, 0x03, 0xdc, 0x29, 0xfe, 0x70, 0x57,
+ 0xfe, 0x33, 0x54, 0xfe, 0x3b, 0x54, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x94, 0x29, 0xfe,
+ 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0x94, 0x7d, 0x03, 0x01, 0xfe, 0x70, 0x16, 0x3d, 0x05, 0x43,
+ 0xfe, 0x0a, 0x13, 0x08, 0x1c, 0x07, 0x3f, 0xd4, 0x01, 0x95, 0x01, 0x98, 0x08, 0x3b, 0x07, 0x99,
+ 0x01, 0x40, 0x11, 0xfe, 0xe9, 0x00, 0x0b, 0x09, 0x89, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x02, 0x16,
+ 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0x0f, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0f, 0xfe, 0x66,
+ 0x01, 0x0b, 0x09, 0x74, 0x8d, 0xfe, 0x03, 0x80, 0x6b, 0x3c, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a,
+ 0x1d, 0x92, 0x01, 0x6a, 0xfe, 0x62, 0x08, 0x68, 0x3c, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a, 0x1d,
+ 0x92, 0x01, 0x6a, 0x62, 0x2d, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x92, 0x01, 0x76, 0x03,
+ 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07,
+ 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe,
+ 0x0a, 0x1c, 0x21, 0x87, 0x16, 0xf7, 0x29, 0x0f, 0x52, 0x0f, 0x4d, 0x21, 0x10, 0x16, 0x2b, 0x16,
+ 0x3a, 0x56, 0x9f, 0xd6, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x01, 0x76, 0x7f, 0x11, 0x75, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xf6, 0x0e, 0xd5, 0x8b, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x03, 0x1d, 0xfe, 0x0c, 0x14, 0x85, 0xfe, 0x07, 0xe6, 0x36, 0xfe, 0xce, 0x47, 0xfe,
+ 0xf5, 0x13, 0x03, 0x01, 0xb6, 0x0e, 0x3b, 0x01, 0x14, 0x05, 0x10, 0xd3, 0x0e, 0x1c, 0x01, 0x14,
+ 0x05, 0x10, 0xdb, 0xfe, 0x44, 0x58, 0x3c, 0xfe, 0x01, 0xec, 0xba, 0xfe, 0x9e, 0x40, 0xfe, 0x9d,
+ 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1e, 0x9e, 0x2d, 0x01, 0xd7, 0xfe, 0xc9, 0x10, 0x03, 0x35, 0x81,
+ 0x6d, 0x23, 0x28, 0xb1, 0x05, 0x1e, 0xfe, 0x48, 0x12, 0x05, 0x0c, 0xfe, 0x4c, 0x12, 0x05, 0x18,
+ 0x38, 0x05, 0xcc, 0x1b, 0xfe, 0xc0, 0x10, 0x05, 0xfe, 0x23, 0x00, 0x1b, 0xfe, 0xcc, 0x10, 0x05,
+ 0x06, 0x1b, 0xfe, 0x2a, 0x11, 0x05, 0x19, 0xfe, 0x12, 0x12, 0x05, 0x00, 0x1b, 0x25, 0x17, 0xcc,
+ 0x01, 0x38, 0xc4, 0x39, 0x01, 0x0a, 0x80, 0x4a, 0x03, 0x39, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x26,
+ 0x39, 0x3d, 0x05, 0xbf, 0xfe, 0xe3, 0x13, 0x63, 0x41, 0x30, 0x42, 0x73, 0xfe, 0x7e, 0x10, 0x0b,
+ 0x09, 0x6f, 0xfe, 0x72, 0x12, 0xa0, 0x3e, 0x67, 0x57, 0xe7, 0xfe, 0xe5, 0x55, 0x91, 0xfe, 0x48,
+ 0x10, 0x22, 0x60, 0xfe, 0x26, 0x13, 0x04, 0xaa, 0x2e, 0x8c, 0x73, 0xfe, 0x98, 0x0c, 0x0f, 0x5c,
+ 0x13, 0x5d, 0x29, 0x0f, 0xaa, 0x0f, 0x8c, 0x01, 0xb7, 0x21, 0x87, 0x6b, 0x16, 0x60, 0x01, 0xf6,
+ 0xa0, 0x3e, 0x67, 0x57, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x3e, 0xfe, 0x05,
+ 0xfa, 0x57, 0xfe, 0x91, 0x10, 0x04, 0x5e, 0x2e, 0x5f, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0f,
+ 0x5e, 0x13, 0x5f, 0xd1, 0xa0, 0x3e, 0x67, 0x57, 0xe7, 0xfe, 0xe5, 0x55, 0x04, 0x5a, 0x2e, 0x5b,
+ 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0f, 0x5a, 0x13, 0x5b, 0x0b, 0x09, 0x6f, 0xfe, 0x1e, 0x12,
+ 0x22, 0x60, 0xfe, 0x1f, 0x40, 0x04, 0x5c, 0x2e, 0x5d, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04,
+ 0x5e, 0x2e, 0x5f, 0xfe, 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x5a, 0x2e, 0x5b, 0xfe, 0x08, 0x50,
+ 0xfe, 0x8a, 0x50, 0x04, 0x41, 0x2e, 0x42, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x97, 0x21,
+ 0x06, 0x16, 0xf1, 0x02, 0x78, 0x39, 0x01, 0x0a, 0x20, 0x4c, 0x23, 0x28, 0xb1, 0x05, 0x06, 0x27,
+ 0x4c, 0x3d, 0x05, 0xbf, 0x27, 0x78, 0x01, 0xee, 0x1a, 0x4f, 0x1b, 0x4c, 0x0b, 0x09, 0x0c, 0xde,
+ 0x63, 0x41, 0x30, 0x42, 0xfe, 0x0a, 0x55, 0x2f, 0xfe, 0x8b, 0x55, 0x9b, 0x41, 0x9c, 0x42, 0xfe,
+ 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x78, 0xfe, 0x19, 0x81, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41,
+ 0x02, 0x78, 0x39, 0x01, 0x0a, 0x20, 0xfe, 0xc2, 0x0f, 0x23, 0x28, 0xfe, 0xe9, 0x09, 0x58, 0x18,
+ 0xfe, 0x94, 0x12, 0x58, 0x0c, 0x50, 0x02, 0x4c, 0x2c, 0xfe, 0x4a, 0x11, 0x1f, 0x31, 0x20, 0xfe,
+ 0xc2, 0x0f, 0x23, 0x28, 0x93, 0x05, 0x18, 0x27, 0x4c, 0x01, 0x0a, 0x20, 0xfe, 0xc2, 0x0f, 0x23,
+ 0x28, 0xfe, 0xe8, 0x09, 0x56, 0x04, 0xfe, 0x9c, 0x00, 0x2a, 0x2f, 0xfe, 0xbb, 0x45, 0x58, 0x00,
+ 0x48, 0x34, 0x06, 0x9f, 0x4f, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xa8, 0x3d, 0x05, 0xbe, 0xfe,
+ 0x16, 0x13, 0x04, 0xf4, 0x2a, 0xce, 0x04, 0x4d, 0x2a, 0x2f, 0x59, 0x02, 0x78, 0xfe, 0xc0, 0x5d,
+ 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, 0x04, 0x52, 0xb9, 0x0f, 0x52, 0x59, 0x39, 0x01, 0x0a, 0x24,
+ 0x97, 0x01, 0xfe, 0xf0, 0x13, 0x02, 0x97, 0x2c, 0xfe, 0xd4, 0x11, 0x1f, 0x31, 0x20, 0x4c, 0x23,
+ 0x28, 0x93, 0x05, 0x06, 0x27, 0x4c, 0xfe, 0xf6, 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe,
+ 0x92, 0x14, 0xa8, 0xfe, 0x4a, 0xf4, 0x0c, 0x1b, 0x4c, 0xfe, 0x4a, 0xf4, 0x06, 0xd2, 0x3d, 0x05,
+ 0xbe, 0xc7, 0x02, 0x78, 0x04, 0x4d, 0xb9, 0x0f, 0x4d, 0x59, 0x39, 0x01, 0x0a, 0x24, 0x97, 0x01,
+ 0xfe, 0x1e, 0x14, 0x02, 0x97, 0x24, 0xfe, 0x3c, 0x12, 0x71, 0xef, 0x71, 0x03, 0x33, 0x8d, 0x69,
+ 0x8d, 0x59, 0x39, 0x01, 0x0a, 0xfe, 0xe3, 0x10, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e,
+ 0x1a, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x61, 0xff, 0x02, 0x00,
+ 0x57, 0x64, 0x7e, 0x1a, 0x4f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x61, 0xff, 0x02,
+ 0x00, 0x57, 0x64, 0x7e, 0x03, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e, 0xfe, 0x0b, 0x58,
+ 0x03, 0x0e, 0x52, 0x01, 0x9a, 0x0e, 0x4d, 0x01, 0x9a, 0x03, 0xc6, 0x1a, 0x10, 0xff, 0x03, 0x00,
+ 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x64, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
+ 0x03, 0x7c, 0x62, 0x2d, 0x0f, 0x5a, 0x13, 0x5b, 0x9b, 0x5e, 0x9c, 0x5f, 0x03, 0xfe, 0x62, 0x18,
+ 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a, 0xb4, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x60, 0x18, 0xfe,
+ 0x42, 0x48, 0x79, 0x56, 0x7a, 0x01, 0x0a, 0x20, 0xfe, 0xe8, 0x13, 0x23, 0x28, 0xfe, 0xe9, 0x09,
+ 0xfe, 0xc1, 0x59, 0x01, 0x0a, 0x20, 0xfe, 0xe8, 0x13, 0x23, 0x28, 0xfe, 0xe8, 0x0a, 0x04, 0xf4,
+ 0x2a, 0xfe, 0xc2, 0x12, 0x29, 0xad, 0x1e, 0xde, 0x58, 0xcd, 0x72, 0xfe, 0x38, 0x13, 0x50, 0x08,
+ 0x06, 0x07, 0xcd, 0x9f, 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa4, 0xff,
+ 0x02, 0x83, 0x55, 0xad, 0x18, 0xfe, 0x12, 0x13, 0x70, 0xfe, 0x30, 0x00, 0x91, 0xf0, 0x07, 0x84,
+ 0x08, 0x06, 0xfe, 0x56, 0x10, 0xad, 0x0c, 0xfe, 0x16, 0x13, 0x70, 0xfe, 0x64, 0x00, 0x91, 0xf0,
+ 0x0e, 0xfe, 0x64, 0x00, 0x07, 0x88, 0x08, 0x06, 0xfe, 0x28, 0x10, 0xad, 0x06, 0xfe, 0x5e, 0x13,
+ 0x70, 0xfe, 0xc8, 0x00, 0x91, 0xf0, 0x0e, 0xfe, 0xc8, 0x00, 0x07, 0x54, 0x08, 0x06, 0xd1, 0x70,
+ 0xfe, 0x90, 0x01, 0xea, 0xfe, 0x9e, 0x13, 0x7a, 0xa7, 0xfe, 0x43, 0xf4, 0xa9, 0xfe, 0x56, 0xf0,
+ 0xfe, 0xb0, 0x13, 0xfe, 0x04, 0xf4, 0x61, 0xfe, 0x43, 0xf4, 0x88, 0xfe, 0xf3, 0x10, 0xac, 0x01,
+ 0xfe, 0x7a, 0x12, 0x1a, 0x4f, 0xd3, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x87, 0xea, 0xfe, 0xe2,
+ 0x13, 0x7a, 0xfe, 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xea, 0xfe, 0xe2, 0x13,
+ 0xc8, 0x19, 0x9d, 0x56, 0x7a, 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x56, 0x08,
+ 0x0c, 0x03, 0x15, 0x06, 0x01, 0x0a, 0x24, 0xdc, 0x15, 0x0c, 0x01, 0x0a, 0x24, 0xdc, 0x15, 0x18,
+ 0x01, 0x0a, 0x24, 0xdc, 0x71, 0xfe, 0x89, 0x49, 0x01, 0x0a, 0x03, 0x15, 0x06, 0x01, 0x0a, 0x24,
+ 0x90, 0x15, 0x18, 0x01, 0x0a, 0x24, 0x90, 0x15, 0x06, 0x01, 0x0a, 0x24, 0x90, 0xfe, 0x89, 0x49,
+ 0x01, 0x0a, 0x24, 0x90, 0x71, 0xfe, 0x89, 0x4a, 0x01, 0x0a, 0x03, 0x56, 0x03, 0x22, 0xe2, 0x05,
+ 0x06, 0xfe, 0x44, 0x13, 0xab, 0x16, 0xe2, 0xfe, 0x49, 0xf4, 0x00, 0x50, 0x71, 0xc4, 0x59, 0xfe,
+ 0x01, 0xec, 0xfe, 0x27, 0x01, 0xef, 0x01, 0x0a, 0x3d, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13,
+ 0x20, 0xfe, 0xa0, 0x14, 0x29, 0x16, 0xf1, 0x01, 0x4a, 0x22, 0xf1, 0x05, 0x06, 0x48, 0x0b, 0x49,
+ 0x06, 0x37, 0x03, 0x0f, 0x53, 0x13, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x14, 0x05, 0x10, 0xfe, 0x1e,
+ 0x12, 0x45, 0xe6, 0x8f, 0x01, 0x44, 0xfe, 0x90, 0x4d, 0xe0, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x44,
+ 0xfe, 0x8d, 0x56, 0xb4, 0x45, 0x03, 0x45, 0x30, 0x8a, 0x01, 0x14, 0x45, 0x8f, 0x01, 0x44, 0xe4,
+ 0x10, 0xe0, 0x10, 0x30, 0x53, 0x70, 0x1c, 0x83, 0x0e, 0x55, 0x01, 0xc0, 0x03, 0x0f, 0x53, 0x13,
+ 0x8a, 0xfe, 0xc3, 0x58, 0x01, 0x14, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x45, 0xe6, 0x8f, 0x01, 0x44,
+ 0xe4, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x44, 0x45, 0x03, 0x45, 0x30, 0x53, 0x01,
+ 0x14, 0x45, 0x8f, 0x01, 0x44, 0xe4, 0x10, 0xe0, 0x10, 0x30, 0x53, 0x70, 0x1c, 0x83, 0x0e, 0x55,
+ 0x01, 0xc0, 0x03, 0x0f, 0x53, 0x13, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x14, 0xfe, 0x42, 0x48, 0x8f,
+ 0x01, 0x44, 0xfe, 0xc0, 0x5a, 0xac, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xde,
+ 0x94, 0x7d, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x67, 0x53, 0xfe, 0x4d, 0xf4, 0x1c, 0xfe, 0x1c, 0x13,
+ 0x0e, 0x55, 0x01, 0x9a, 0xa7, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x44, 0xfe, 0x00, 0x07,
+ 0x7d, 0x05, 0x10, 0x83, 0x67, 0x8a, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01,
+ 0x44, 0xfe, 0x8d, 0x56, 0xb4, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x07, 0x10, 0x6e, 0x65,
+ 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xdd, 0x36, 0x96, 0xfe,
+ 0xe4, 0x15, 0x01, 0xfe, 0xea, 0x16, 0xfe, 0x0c, 0x13, 0x86, 0x36, 0x65, 0xfe, 0x2c, 0x01, 0xfe,
+ 0x2f, 0x19, 0x03, 0xb5, 0x27, 0xfe, 0xd4, 0x15, 0xfe, 0xda, 0x10, 0x07, 0x10, 0x6e, 0x04, 0xfe,
+ 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58,
+ 0x86, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x65, 0xfe, 0x38, 0x00,
+ 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x96, 0xfe, 0x2e, 0x16, 0xfe, 0xb6, 0x14, 0x2f, 0x03,
+ 0xb5, 0x27, 0xfe, 0x06, 0x16, 0xfe, 0x9c, 0x10, 0x07, 0x10, 0x6e, 0xb4, 0xfe, 0x18, 0xdf, 0xfe,
+ 0x19, 0xdf, 0xdd, 0x3e, 0x96, 0xfe, 0x50, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10, 0x13, 0x86, 0x3e,
+ 0x65, 0x1e, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x03, 0xb5, 0x27, 0xfe, 0x44, 0x16, 0xfe,
+ 0x6c, 0x10, 0x07, 0x10, 0x6e, 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x86, 0xda, 0x65, 0x1e, 0xfe,
+ 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xda, 0x96, 0xfe, 0x88, 0x16, 0xfe, 0x5c, 0x14, 0x2f, 0x03, 0xb5,
+ 0x27, 0xfe, 0x74, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x6e, 0xfe, 0x18, 0xfe, 0x5c,
+ 0xfe, 0x19, 0xfe, 0x5d, 0xc6, 0xdd, 0x74, 0x96, 0xfe, 0xae, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c,
+ 0x13, 0x86, 0x74, 0x4e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81,
+ 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x62, 0x2d, 0x03, 0x62, 0x2d, 0xfe, 0x12, 0x45, 0x27, 0xfe,
+ 0x9e, 0x16, 0x17, 0x06, 0x47, 0xf2, 0xdf, 0x02, 0x26, 0xfe, 0x39, 0xf0, 0xfe, 0xf2, 0x16, 0x29,
+ 0x03, 0xfe, 0x7e, 0x18, 0x1a, 0x18, 0x82, 0x08, 0x0d, 0x03, 0x6e, 0x04, 0xe1, 0x1a, 0x06, 0xfe,
+ 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1d, 0x0e, 0x1c, 0x01, 0x14, 0x05, 0x10, 0x48, 0x3c, 0xfe, 0x78,
+ 0x14, 0xfe, 0x34, 0x12, 0x4f, 0x85, 0x34, 0x36, 0xbc, 0xfe, 0xe9, 0x13, 0x1d, 0x0e, 0x3b, 0x01,
+ 0x14, 0x05, 0x10, 0x48, 0x3c, 0x90, 0xe3, 0x4f, 0x85, 0x34, 0x36, 0xbc, 0xfe, 0xe9, 0x13, 0x07,
+ 0x0c, 0x03, 0xfe, 0x9c, 0xe7, 0x0c, 0x12, 0xfe, 0x15, 0x00, 0x92, 0x9e, 0x2d, 0x01, 0xd7, 0x07,
+ 0x06, 0x03, 0x0b, 0x49, 0x36, 0x37, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c,
+ 0x07, 0x3f, 0x01, 0x76, 0x07, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x63, 0xf5, 0x30,
+ 0x75, 0xfe, 0x48, 0x55, 0x2f, 0xfe, 0xc9, 0x55, 0x03, 0x22, 0xbb, 0x6b, 0x16, 0xbb, 0x03, 0x0e,
+ 0xbd, 0x01, 0x14, 0xe5, 0x0e, 0x7c, 0x01, 0x14, 0xfe, 0x49, 0x44, 0x27, 0xfe, 0xe8, 0x17, 0x0e,
+ 0x1c, 0x01, 0x14, 0x05, 0x10, 0x48, 0x0e, 0x55, 0x01, 0xc0, 0x0e, 0x7c, 0x01, 0x14, 0x6b, 0x7d,
+ 0x03, 0xfe, 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x22, 0x3a, 0x05, 0x10, 0xfe, 0x52,
+ 0x12, 0x3c, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00,
+ 0xfe, 0x10, 0x13, 0xfe, 0xe2, 0x08, 0x6b, 0x3c, 0x3d, 0x05, 0x75, 0xa3, 0xfe, 0x82, 0x48, 0xfe,
+ 0x01, 0x80, 0xfe, 0xd7, 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2b, 0x07, 0x3a, 0xfe, 0x40, 0x5f, 0x1d,
+ 0x01, 0x40, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2b, 0x07, 0x3a, 0x01, 0x40, 0x11,
+ 0xfe, 0xdd, 0x00, 0xfe, 0x40, 0x4a, 0x68, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48,
+ 0xfe, 0x04, 0x17, 0x03, 0xe9, 0x18, 0x72, 0xfe, 0x70, 0x18, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a,
+ 0x45, 0xfe, 0x2c, 0x10, 0xe9, 0xcc, 0x72, 0xfe, 0x82, 0x18, 0x04, 0xfe, 0x92, 0x00, 0xc5, 0x1e,
+ 0xd9, 0xe9, 0xfe, 0x0b, 0x00, 0x72, 0xfe, 0x94, 0x18, 0x04, 0xfe, 0x94, 0x00, 0xc5, 0x19, 0xfe,
+ 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00, 0xc5, 0x84, 0xfe, 0x4e, 0x45, 0xd2, 0xfe, 0x0a, 0x45, 0xff,
+ 0x04, 0x68, 0x54, 0xfe, 0xf1, 0x10, 0x1a, 0x87, 0x03, 0x05, 0xa1, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0,
+ 0x18, 0x21, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1e, 0xfe, 0x5a, 0xf0, 0xfe, 0xce, 0x18,
+ 0x21, 0xcd, 0xfe, 0x26, 0x10, 0x05, 0x18, 0x82, 0x21, 0x84, 0xd9, 0x05, 0x0c, 0x82, 0x21, 0x88,
+ 0xfe, 0x0e, 0x10, 0x05, 0x06, 0x82, 0x21, 0x54, 0xc4, 0xab, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01,
+ 0x38, 0x2c, 0xfe, 0xfe, 0x18, 0x04, 0x6d, 0xac, 0x03, 0x1f, 0xfe, 0x16, 0x19, 0xfe, 0x14, 0xf0,
+ 0x0a, 0x2c, 0xfe, 0x12, 0x19, 0x03, 0xff, 0x34, 0x00, 0x00,};
+
+STATIC unsigned short _adv_asc3550_size =
+ sizeof(_adv_asc3550_buf); /* 0x13AA */
+STATIC unsigned long _adv_asc3550_chksum =
+ 0x04F4788EUL; /* Expanded checksum. */
+
+STATIC unsigned char _adv_asc38C0800_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x00, 0xf6,
+ 0x18, 0xe4, 0x01, 0xf6, 0x18, 0x80, 0x02, 0x00, 0x02, 0x1a, 0xff, 0xff, 0x00, 0xfa, 0x03, 0xf6,
+ 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0xe6, 0x0e, 0x00, 0xea, 0x01, 0xe6,
+ 0x03, 0x00, 0x1e, 0xf0, 0x55, 0xf0, 0x18, 0xf4, 0x3e, 0x57, 0x04, 0x00, 0x3e, 0x01, 0x85, 0xf0,
+ 0x00, 0xe6, 0x03, 0xfc, 0x08, 0x00, 0x32, 0xf0, 0x38, 0x54, 0x84, 0x0d, 0x86, 0xf0, 0xd4, 0x01,
+ 0xd5, 0xf0, 0xee, 0x19, 0x00, 0xec, 0x01, 0xfc, 0x98, 0x57, 0xbc, 0x00, 0x10, 0x13, 0xb1, 0xf0,
+ 0x02, 0x13, 0x3c, 0x00, 0x7e, 0x0d, 0xb4, 0x00, 0x00, 0x57, 0x01, 0xf0, 0x02, 0xfc, 0x03, 0xe6,
+ 0x0c, 0x1c, 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x80, 0x3e, 0x00,
+ 0x46, 0x16, 0x4a, 0x10, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54, 0xba, 0x13,
+ 0xbb, 0x00, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x02, 0x48, 0x02, 0xfa, 0x08, 0x12, 0x30, 0xe4,
+ 0x3c, 0x56, 0x4e, 0x01, 0x5d, 0xf0, 0x7a, 0x01, 0x88, 0x0d, 0x8e, 0x10, 0xb6, 0x00, 0xc4, 0x08,
+ 0x00, 0x80, 0x04, 0x12, 0x05, 0xfc, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x40, 0x00,
+ 0x4b, 0xe4, 0x4b, 0xf4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x78, 0x01,
+ 0x7c, 0x01, 0xbb, 0x55, 0x00, 0x01, 0x02, 0xee, 0x03, 0x58, 0x03, 0xf7, 0x03, 0xfa, 0x04, 0x80,
+ 0x08, 0x44, 0x09, 0xf0, 0x10, 0x44, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, 0x4e, 0x1c, 0x5b, 0xf0,
+ 0x80, 0x00, 0x8a, 0x15, 0x98, 0x10, 0xaa, 0x00, 0xbd, 0x56, 0xbe, 0x00, 0xc0, 0x00, 0x00, 0x4c,
+ 0x00, 0xdc, 0x02, 0x4a, 0x04, 0xfc, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x06, 0xf7, 0x08, 0x13,
+ 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x0f, 0x00, 0x1c, 0x0c, 0x20, 0x00, 0x2a, 0x01, 0x32, 0x1c,
+ 0x36, 0x00, 0x42, 0x54, 0x44, 0x0b, 0x44, 0x55, 0x45, 0x5a, 0x59, 0xf0, 0x5c, 0xf0, 0x62, 0x0a,
+ 0x69, 0x08, 0x78, 0x13, 0x83, 0x59, 0x8e, 0x18, 0x9a, 0x10, 0x9a, 0x18, 0xb8, 0xf0, 0xd6, 0x0e,
+ 0xea, 0x15, 0xf0, 0x00, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6, 0x05, 0x00, 0x06, 0x00, 0x06, 0x12,
+ 0x0a, 0x10, 0x0a, 0x12, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x12, 0x10, 0x19, 0x00, 0x19, 0xe4,
+ 0x2a, 0x12, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x36, 0x15, 0x38, 0x44, 0x3a, 0x15, 0x40, 0x5c,
+ 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x7a, 0x17, 0x83, 0x55, 0x83, 0x5a, 0x91, 0x44,
+ 0xa2, 0x10, 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xcc, 0x0e, 0xce, 0x45, 0xd0, 0x00,
+ 0xe1, 0x00, 0xe5, 0x55, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x48, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6,
+ 0x03, 0xa1, 0x04, 0x13, 0x05, 0xe6, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0xf0,
+ 0x0c, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x04, 0x10, 0x10, 0x12, 0x1c, 0x19, 0x81, 0x1a, 0x10,
+ 0x1c, 0x00, 0x1c, 0x12, 0x1c, 0x13, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01,
+ 0x26, 0x01, 0x30, 0xe7, 0x38, 0x12, 0x3a, 0x55, 0x3f, 0x00, 0x41, 0x58, 0x43, 0x48, 0x46, 0x1c,
+ 0x4e, 0xe4, 0x5a, 0x13, 0x68, 0x13, 0x72, 0x14, 0x76, 0x02, 0x77, 0x57, 0x78, 0x03, 0x89, 0x48,
+ 0x8a, 0x13, 0x98, 0x80, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0xfe, 0x9c, 0xf0, 0x27, 0x02, 0xfe,
+ 0xa6, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc6, 0x01, 0xfe, 0x18, 0x1a, 0x00, 0xfe, 0xc4, 0x01,
+ 0xfe, 0x84, 0x01, 0xff, 0x03, 0x00, 0x00, 0x30, 0xfe, 0x01, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d,
+ 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
+ 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21,
+ 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x38, 0x86, 0x0b, 0x01, 0xfe, 0x96, 0x0f, 0xfe,
+ 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x86, 0x0b, 0x1c, 0x38, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0xfe,
+ 0x20, 0xf0, 0xdb, 0x04, 0x5e, 0x59, 0x02, 0xfe, 0xc2, 0x0d, 0x01, 0xfe, 0x22, 0x0e, 0xfe, 0xe9,
+ 0x12, 0x02, 0xfe, 0x08, 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x46,
+ 0x12, 0xfe, 0xa6, 0x00, 0xcd, 0xfe, 0x48, 0xf0, 0xfe, 0x80, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x9a,
+ 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb8, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x4a, 0x02, 0xfe, 0x47, 0xf0,
+ 0xfe, 0x50, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x42, 0x02, 0xfe,
+ 0x45, 0xf0, 0xfe, 0x46, 0x02, 0x09, 0x0b, 0xa2, 0x09, 0x06, 0x12, 0xc1, 0x02, 0x27, 0xfe, 0x00,
+ 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10,
+ 0x01, 0xfe, 0xee, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xfe, 0xa8, 0x00, 0x0f, 0x7d, 0x01,
+ 0xc5, 0x02, 0x27, 0x17, 0x5d, 0x4b, 0xc3, 0x01, 0xab, 0x0f, 0x7d, 0x01, 0x9f, 0xfe, 0xbd, 0x10,
+ 0x0f, 0x7d, 0x01, 0x9f, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x09, 0x06, 0x12,
+ 0xc1, 0x38, 0x19, 0x27, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0x28, 0xfe, 0x8e, 0x02, 0xfe, 0x5a,
+ 0x1c, 0xdd, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4b, 0xc3, 0x01, 0xfe, 0xfc, 0x0f, 0x09,
+ 0x06, 0x12, 0xc1, 0x02, 0xfe, 0xc6, 0x01, 0x2a, 0x2d, 0x05, 0x10, 0x30, 0xfe, 0x69, 0x10, 0x09,
+ 0x06, 0x12, 0xc1, 0xfe, 0x04, 0xec, 0x2d, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x40, 0x81, 0xfe,
+ 0x05, 0xf6, 0xfe, 0xa8, 0x00, 0x01, 0xfe, 0x20, 0x17, 0x0a, 0x4f, 0x8d, 0x3a, 0x11, 0x48, 0x1c,
+ 0xd3, 0x07, 0x1e, 0x09, 0x51, 0x01, 0xa0, 0x02, 0x27, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0xda,
+ 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0xfe, 0x28, 0x10, 0x0f, 0xc7, 0x01, 0x15, 0xed, 0x0f, 0x7e,
+ 0x01, 0x15, 0xfe, 0x49, 0x54, 0x77, 0xfe, 0x16, 0x03, 0x07, 0x1e, 0x09, 0x51, 0x01, 0xa0, 0x02,
+ 0x27, 0x38, 0x81, 0xfe, 0x02, 0xe8, 0x33, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xf5, 0xfe, 0x07,
+ 0x4b, 0xfe, 0x20, 0xf0, 0xdb, 0xfe, 0x40, 0x1c, 0x19, 0xf6, 0xfe, 0x26, 0xf0, 0xfe, 0x74, 0x03,
+ 0xfe, 0xa0, 0xf0, 0xfe, 0x62, 0x03, 0xfe, 0x11, 0xf0, 0xdb, 0xfe, 0x0e, 0x10, 0xfe, 0x9f, 0xf0,
+ 0xfe, 0x82, 0x03, 0xef, 0x13, 0xfe, 0x11, 0x00, 0x02, 0x54, 0x38, 0xfe, 0x48, 0x1c, 0xef, 0x19,
+ 0xf6, 0x35, 0xf6, 0xfe, 0x82, 0xf0, 0xfe, 0x88, 0x03, 0x24, 0x2a, 0xc4, 0x70, 0x16, 0xc4, 0x0f,
+ 0x7e, 0x01, 0x15, 0x70, 0x7f, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x40, 0x11, 0x3d, 0x07, 0x3d, 0x09,
+ 0xa1, 0x01, 0xa0, 0xfc, 0x11, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xce, 0x03, 0x19, 0x32, 0x1f, 0xfe,
+ 0xde, 0x03, 0x01, 0x41, 0xd4, 0xfe, 0xee, 0x03, 0x71, 0x8c, 0xd7, 0xfe, 0xae, 0x06, 0x02, 0x25,
+ 0x04, 0x7d, 0x2c, 0x1a, 0xfe, 0x20, 0x05, 0x17, 0x88, 0x01, 0x2e, 0x01, 0x9b, 0x01, 0x9d, 0x35,
+ 0xfe, 0x60, 0x02, 0x02, 0xf4, 0xef, 0x38, 0x86, 0x18, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xf5,
+ 0xfe, 0x48, 0x1c, 0x8f, 0x01, 0xf2, 0xb1, 0xfe, 0x96, 0xf0, 0xfe, 0x28, 0x04, 0x2f, 0xfe, 0x2c,
+ 0x04, 0x35, 0x27, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x1a, 0xfe, 0x0c, 0x05, 0x4c, 0x97, 0xa3,
+ 0x33, 0x84, 0x74, 0x19, 0x32, 0x1f, 0x25, 0x04, 0x7d, 0x2c, 0xfe, 0x10, 0x12, 0x17, 0x88, 0x01,
+ 0x2e, 0x35, 0xfe, 0x60, 0x02, 0x02, 0xf4, 0x21, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e,
+ 0x12, 0x0a, 0x08, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x29, 0x98, 0x01, 0x0c, 0x84, 0x74, 0x1f, 0xfe,
+ 0xdc, 0x04, 0x23, 0x29, 0x98, 0x01, 0x0c, 0x1f, 0x25, 0x23, 0x29, 0xba, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x32, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x07, 0xfe, 0x93, 0x00, 0xfe, 0x4c, 0x54, 0x77, 0xfe, 0x0c,
+ 0x05, 0x81, 0xa3, 0x33, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, 0x13, 0x3e, 0x05, 0xfe,
+ 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x08, 0x06, 0xea, 0xfe, 0x06, 0x10, 0x23, 0x29, 0xba, 0x0a,
+ 0x08, 0x39, 0xe1, 0x17, 0xa6, 0x0a, 0x08, 0x06, 0x59, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x2e, 0x35,
+ 0xfe, 0x66, 0x0d, 0x02, 0x25, 0x3b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb7, 0x03, 0x17,
+ 0xa6, 0x01, 0x2e, 0x35, 0x27, 0x19, 0x27, 0x02, 0xfe, 0x14, 0x05, 0xfe, 0x42, 0x5b, 0x86, 0x18,
+ 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xf5, 0x17, 0x78, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a,
+ 0x08, 0x0b, 0x99, 0xfe, 0x20, 0x80, 0x05, 0x18, 0xfe, 0x70, 0x12, 0x73, 0x08, 0x06, 0xfe, 0x60,
+ 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x2c, 0x1a, 0xfe, 0xac, 0x05, 0xfe, 0x31, 0xe4, 0x5f, 0x73, 0x08,
+ 0x0b, 0xfe, 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x2c, 0xfe, 0x42, 0x12, 0x62, 0x2f, 0xfe, 0x6c,
+ 0x05, 0x19, 0x32, 0xf7, 0x01, 0x0c, 0x26, 0xfe, 0xc4, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x24, 0x73,
+ 0xfe, 0x4a, 0xf0, 0xfe, 0x96, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x90, 0x05, 0xab, 0x20, 0xfe, 0x21,
+ 0x00, 0xa8, 0x20, 0xfe, 0x22, 0x00, 0xa2, 0x20, 0x8d, 0xfe, 0x09, 0x48, 0x01, 0x0c, 0x26, 0xfe,
+ 0xc4, 0x05, 0xfe, 0xe2, 0x08, 0x73, 0x08, 0xe0, 0x59, 0x01, 0x99, 0x20, 0x06, 0x16, 0xe8, 0x4b,
+ 0xfe, 0x27, 0x01, 0x0a, 0x08, 0x39, 0xb0, 0x46, 0x01, 0xb6, 0x17, 0xa6, 0x0a, 0x08, 0x06, 0x59,
+ 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x2e, 0x01, 0x9b, 0x01, 0x9d, 0x35, 0xfe, 0x66, 0x0d, 0x02, 0x25,
+ 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0xfe, 0x3e, 0x12, 0x04, 0x5b, 0x2c, 0xfe, 0x36, 0x13, 0x46, 0x01,
+ 0xb6, 0x26, 0xfe, 0x3c, 0x06, 0x0f, 0x06, 0x73, 0x08, 0x22, 0xfe, 0x02, 0x12, 0x69, 0x01, 0xfe,
+ 0xd0, 0x14, 0x1f, 0xfe, 0x32, 0x06, 0x11, 0xc8, 0x01, 0x41, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x5b,
+ 0xc2, 0x0e, 0x5b, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0x62, 0x12, 0x04, 0x56, 0x2c, 0xf1, 0x01,
+ 0xfe, 0x40, 0x19, 0x01, 0xfe, 0xaa, 0x19, 0xee, 0xd2, 0xec, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57,
+ 0x6c, 0x80, 0x1b, 0x58, 0xd1, 0xd2, 0x8b, 0x46, 0x01, 0xb6, 0x26, 0xfe, 0xa6, 0x06, 0x73, 0x08,
+ 0x1d, 0xa7, 0x7c, 0x0f, 0x5d, 0x01, 0xfe, 0xfe, 0x14, 0x1f, 0xfe, 0x9c, 0x06, 0x11, 0xc8, 0x01,
+ 0x41, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x56, 0xc2, 0x0e, 0x56, 0x09, 0x06, 0x01, 0xb6, 0xfc, 0x76,
+ 0x8f, 0x01, 0xf2, 0xb1, 0x11, 0xfe, 0xe2, 0x00, 0x2f, 0xfe, 0xbe, 0x06, 0x19, 0x32, 0xd7, 0xfe,
+ 0xda, 0x06, 0x83, 0xfe, 0x78, 0x07, 0xd4, 0xfe, 0x80, 0x07, 0x71, 0x8c, 0x02, 0x25, 0x0a, 0x08,
+ 0x0b, 0xfe, 0x2e, 0x12, 0x14, 0x18, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c,
+ 0x14, 0x00, 0x01, 0x0c, 0xfe, 0x99, 0xa4, 0x01, 0x0c, 0x14, 0x00, 0x02, 0xfe, 0x3e, 0x08, 0x6f,
+ 0x08, 0x1d, 0xea, 0x0a, 0x08, 0x1d, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x0c, 0x14,
+ 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x06, 0x01, 0x0c, 0x14,
+ 0x00, 0x02, 0xfe, 0xe6, 0x0b, 0x69, 0xfe, 0x9a, 0x81, 0x6d, 0x8d, 0xfe, 0x09, 0x6f, 0xfe, 0x93,
+ 0x45, 0x1a, 0xfe, 0x88, 0x07, 0x2f, 0xfe, 0x60, 0x07, 0x19, 0x32, 0xd7, 0xfe, 0x58, 0x07, 0x71,
+ 0x8c, 0x83, 0xfe, 0x78, 0x07, 0x02, 0x25, 0x01, 0x41, 0x02, 0xfe, 0xbe, 0x06, 0x14, 0x22, 0x02,
+ 0xfe, 0xbe, 0x06, 0xfe, 0x9c, 0xf7, 0xfe, 0xf4, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x52,
+ 0xfe, 0xd6, 0x07, 0x0e, 0x65, 0x12, 0x66, 0x0a, 0x4f, 0x5f, 0x3a, 0x01, 0xfe, 0xd6, 0x18, 0x05,
+ 0x10, 0x85, 0xfe, 0x83, 0xe7, 0xfe, 0x95, 0x00, 0xa8, 0xfe, 0x03, 0x40, 0x0a, 0x4f, 0x78, 0x3a,
+ 0x01, 0xbc, 0xb5, 0xfe, 0x1f, 0x40, 0x16, 0x67, 0x01, 0xf8, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50,
+ 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0e, 0x63, 0x12, 0x64,
+ 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x0e, 0x42, 0x12, 0x43,
+ 0x41, 0x0a, 0x08, 0x5f, 0xb0, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0e, 0x65, 0x12, 0x66, 0x0a,
+ 0x08, 0x78, 0xd1, 0x01, 0xbc, 0xfe, 0x1f, 0x80, 0x16, 0x67, 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90,
+ 0x0e, 0x44, 0x12, 0x45, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0e, 0x63, 0x12, 0x64, 0xfe, 0x28,
+ 0x90, 0xfe, 0xaa, 0x90, 0x0e, 0x42, 0x12, 0x43, 0x0e, 0x31, 0x12, 0x3f, 0x24, 0x0e, 0x53, 0x0e,
+ 0x68, 0x0a, 0x4f, 0x22, 0x3a, 0x38, 0x07, 0xa5, 0x2f, 0xfe, 0x5e, 0x08, 0xfe, 0x9e, 0xf0, 0xfe,
+ 0x72, 0x08, 0xcc, 0x1a, 0x32, 0x38, 0x72, 0xfe, 0xed, 0x10, 0xaa, 0xfe, 0x96, 0x08, 0xac, 0xfe,
+ 0xb2, 0x08, 0x83, 0xfe, 0x8a, 0x08, 0xd4, 0xfe, 0x90, 0x08, 0x71, 0x8c, 0x02, 0x25, 0x01, 0x41,
+ 0xfe, 0xc9, 0x10, 0x14, 0x22, 0xfe, 0xc9, 0x10, 0x6f, 0x08, 0x06, 0xfe, 0x10, 0x12, 0x6f, 0x08,
+ 0x0b, 0x4e, 0x0a, 0x08, 0x0b, 0xfe, 0x8e, 0x12, 0xfe, 0x2e, 0x1c, 0xad, 0x6f, 0x08, 0x06, 0x4e,
+ 0x6f, 0x08, 0x0b, 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xcc, 0x09, 0xfe,
+ 0xac, 0xf0, 0xfe, 0xfa, 0x08, 0x02, 0xfe, 0xd8, 0x09, 0xfe, 0xb7, 0xf0, 0xfe, 0xf6, 0x08, 0xfe,
+ 0x02, 0xf6, 0x1d, 0x69, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55,
+ 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x19, 0x92, 0xfe, 0x8c,
+ 0xf0, 0xfe, 0xf6, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xea, 0x08, 0xfe, 0x34, 0x1c, 0xfe, 0xcb, 0x10,
+ 0xfe, 0xad, 0xf0, 0xfe, 0x06, 0x09, 0x02, 0xfe, 0x12, 0x0b, 0xfe, 0x36, 0x1c, 0xfe, 0xbf, 0x10,
+ 0xfe, 0x2b, 0xf0, 0x92, 0xfe, 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xfe, 0xe1, 0xcd, 0xfe, 0xd2, 0xf0,
+ 0x92, 0xfe, 0x76, 0x18, 0x1b, 0x18, 0x1a, 0x92, 0x04, 0xe7, 0x1b, 0x06, 0x1a, 0x92, 0xaa, 0x57,
+ 0xac, 0x57, 0xfe, 0x34, 0x1c, 0xfe, 0x36, 0x1c, 0xfe, 0x89, 0x10, 0x8f, 0x62, 0x3b, 0x17, 0xa6,
+ 0x01, 0x2e, 0x13, 0xfe, 0x35, 0x00, 0x35, 0x54, 0x13, 0x90, 0x02, 0x54, 0xf9, 0xaf, 0x0b, 0xfe,
+ 0x1a, 0x12, 0x50, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xeb, 0xde, 0xfe, 0x74,
+ 0x18, 0x91, 0x93, 0x1a, 0xfe, 0xc8, 0x08, 0x02, 0x57, 0x0a, 0x08, 0x5f, 0x2e, 0x04, 0x31, 0x2b,
+ 0x3f, 0x0e, 0x44, 0x12, 0x45, 0x82, 0x31, 0x5a, 0x3f, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, 0xfe,
+ 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x36, 0x44, 0x21, 0x45, 0x04, 0x53, 0x2b, 0x68, 0x91, 0xfe, 0xe3,
+ 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x91, 0xfe, 0xe3, 0x54, 0x93, 0xc9, 0x52, 0xfe, 0xc8,
+ 0x08, 0x02, 0x57, 0xfe, 0x37, 0xf0, 0xfe, 0xd4, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x5a, 0x09, 0x02,
+ 0x57, 0xf9, 0xaf, 0x0b, 0x28, 0xfe, 0xf4, 0x0a, 0x36, 0x53, 0x21, 0x68, 0x52, 0xfe, 0x38, 0x0a,
+ 0x07, 0xfe, 0xc0, 0x07, 0x46, 0x61, 0x00, 0xd9, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x06,
+ 0x0a, 0x91, 0x96, 0xfe, 0x1e, 0x0a, 0x36, 0x53, 0x91, 0xfe, 0xe3, 0x54, 0x4d, 0x53, 0x6e, 0x68,
+ 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x57, 0x36, 0x53, 0x21, 0x68, 0xfe, 0x14, 0x59, 0xfe,
+ 0x95, 0x59, 0xeb, 0x4d, 0x53, 0x4d, 0x68, 0x02, 0x57, 0x0a, 0x08, 0x5f, 0xfe, 0x82, 0x12, 0x0a,
+ 0x08, 0x22, 0xfe, 0x66, 0x13, 0x2a, 0x67, 0x70, 0xd0, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe,
+ 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6b, 0x33, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59,
+ 0x52, 0xfe, 0xd0, 0x08, 0x04, 0x65, 0x2b, 0x66, 0x0e, 0xb3, 0x12, 0x90, 0x4d, 0x65, 0x6e, 0x66,
+ 0x01, 0xbc, 0xb5, 0x6b, 0x33, 0x16, 0x67, 0x82, 0x31, 0x5a, 0x3f, 0x36, 0x44, 0x21, 0x45, 0x93,
+ 0xc9, 0xfe, 0x04, 0xfa, 0x31, 0xfe, 0x05, 0xfa, 0x3f, 0x01, 0xf8, 0xfe, 0x36, 0x10, 0x24, 0x0e,
+ 0xb3, 0x0e, 0x90, 0x36, 0x44, 0x21, 0x45, 0xad, 0x0a, 0x08, 0x22, 0x1a, 0xfe, 0xd0, 0x08, 0x36,
+ 0x42, 0x21, 0x43, 0x0a, 0x08, 0xfe, 0xf7, 0x00, 0x3a, 0x04, 0x63, 0x2b, 0x64, 0xfe, 0x10, 0x58,
+ 0xfe, 0x91, 0x58, 0x4d, 0x53, 0x6e, 0x68, 0x02, 0xfe, 0xee, 0x09, 0x0a, 0x08, 0x22, 0x1a, 0xfe,
+ 0xd0, 0x08, 0x0a, 0x08, 0xfe, 0xf7, 0x00, 0x3a, 0xeb, 0xde, 0x69, 0xfe, 0x10, 0x90, 0xfe, 0x92,
+ 0x90, 0xfe, 0xd3, 0x10, 0x3e, 0x05, 0xca, 0x1a, 0xfe, 0x02, 0x09, 0x11, 0xca, 0xf9, 0xaf, 0x0b,
+ 0xfe, 0x14, 0x13, 0x04, 0x42, 0x2b, 0x43, 0x52, 0xfe, 0x02, 0x09, 0xfe, 0x0c, 0x58, 0xfe, 0x8d,
+ 0x58, 0x02, 0x57, 0x24, 0x46, 0xfe, 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0a, 0x08, 0x0b, 0xa7, 0xfe,
+ 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x94, 0x10, 0xfe, 0x6c, 0x19, 0x4d, 0x42, 0xfe, 0xed, 0x19,
+ 0x6e, 0x43, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xff, 0x30,
+ 0xfe, 0x7a, 0x10, 0xcd, 0xfe, 0xd2, 0xf0, 0xfe, 0x8c, 0x0b, 0xfe, 0x76, 0x18, 0x1b, 0x18, 0xa9,
+ 0x04, 0xe7, 0x1b, 0x06, 0x87, 0x13, 0xfe, 0x16, 0x00, 0x02, 0x54, 0xfe, 0xd1, 0xf0, 0xfe, 0xc2,
+ 0x0b, 0x17, 0xa5, 0x01, 0x2e, 0x13, 0xfe, 0x17, 0x00, 0xfe, 0x48, 0x10, 0xfe, 0xce, 0xf0, 0xfe,
+ 0xaa, 0x0b, 0x13, 0xfe, 0x21, 0x00, 0x02, 0x54, 0xfe, 0xcd, 0xf0, 0xfe, 0xb6, 0x0b, 0x13, 0xfe,
+ 0x22, 0x00, 0x02, 0x54, 0xfe, 0xcb, 0xf0, 0xfe, 0xc2, 0x0b, 0x13, 0xfe, 0x24, 0x00, 0x02, 0x54,
+ 0xfe, 0xd0, 0xf0, 0xfe, 0xcc, 0x0b, 0x13, 0xae, 0xdf, 0xfe, 0xcf, 0xf0, 0xfe, 0xd6, 0x0b, 0x13,
+ 0x8d, 0xdc, 0xfe, 0xcc, 0xf0, 0xfe, 0xe6, 0x0b, 0xfe, 0x84, 0x80, 0xaf, 0x22, 0xfe, 0xd5, 0x12,
+ 0x13, 0xfe, 0x12, 0x00, 0x2f, 0xfe, 0xe6, 0x0b, 0x19, 0x32, 0xaa, 0x25, 0xac, 0x25, 0x38, 0xfc,
+ 0x2f, 0xfe, 0xfa, 0x0b, 0x19, 0x32, 0x83, 0xfe, 0x16, 0x0c, 0x71, 0x8c, 0xaa, 0xfe, 0xf4, 0x07,
+ 0xac, 0xfe, 0xf4, 0x07, 0x02, 0x25, 0x01, 0x41, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0x8f,
+ 0x84, 0x74, 0xfe, 0x89, 0xf0, 0x25, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0x01, 0x0c, 0x84, 0x74, 0x1f,
+ 0x25, 0x23, 0x29, 0x98, 0x35, 0xfe, 0x4e, 0x0c, 0x19, 0x32, 0x02, 0xfe, 0x42, 0x0c, 0xcc, 0x4e,
+ 0x13, 0xfe, 0x42, 0x00, 0x02, 0x54, 0xa4, 0x06, 0xfe, 0x81, 0x49, 0xfe, 0xcc, 0x12, 0x0a, 0x08,
+ 0x0b, 0xf1, 0x13, 0x00, 0x60, 0x0b, 0xfe, 0x6a, 0x12, 0x60, 0xfe, 0x28, 0x00, 0x28, 0xfe, 0x94,
+ 0x0d, 0x0f, 0x7e, 0x01, 0x15, 0x05, 0x00, 0x87, 0x37, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0x94, 0x0d,
+ 0x01, 0x9b, 0x01, 0x9d, 0x0f, 0xc7, 0x01, 0xfe, 0xf0, 0x0e, 0xb9, 0x07, 0x3d, 0x09, 0xa1, 0x01,
+ 0x40, 0x11, 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0x02, 0x27, 0x13, 0xfe, 0x44, 0x00, 0x60,
+ 0x0b, 0xa7, 0x37, 0x0b, 0xfe, 0xc0, 0x10, 0x01, 0x99, 0x37, 0x0b, 0xfe, 0xb6, 0x10, 0x01, 0x99,
+ 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x37, 0x0b, 0x13, 0xfe, 0x43, 0x00, 0xc0,
+ 0x0a, 0x4f, 0x0b, 0x3a, 0x01, 0x9b, 0x01, 0x9d, 0xb9, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40, 0x11,
+ 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0x86, 0x0b, 0xb9, 0x1c, 0xd3, 0x02, 0xfe, 0x4c, 0x03,
+ 0x0a, 0x08, 0x0b, 0xa9, 0x37, 0x0b, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x6f, 0x08, 0x1d, 0xfe, 0x50,
+ 0x12, 0x0a, 0x08, 0x1d, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x52, 0x0d,
+ 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x58, 0x0d, 0x0a, 0x4f, 0x1d, 0x3a, 0xfe, 0x95, 0x10,
+ 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x69, 0xfe, 0x26, 0x10, 0x13, 0xfe, 0x13, 0x00,
+ 0xdc, 0x13, 0xfe, 0x47, 0x00, 0xa8, 0x13, 0xfe, 0x41, 0x00, 0xa2, 0x13, 0xfe, 0x24, 0x00, 0x04,
+ 0x7d, 0x2c, 0x28, 0xf4, 0x69, 0xfe, 0x04, 0xe6, 0x1d, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0xb9,
+ 0x01, 0xfe, 0xf8, 0x0e, 0x02, 0x27, 0xdd, 0x17, 0x0b, 0x4b, 0xfb, 0xe5, 0x17, 0xfe, 0x31, 0x00,
+ 0x4b, 0xc3, 0x01, 0xfe, 0xfc, 0x0f, 0x02, 0xfe, 0xc6, 0x01, 0x1c, 0xfe, 0x06, 0xec, 0xfe, 0xb9,
+ 0x00, 0x89, 0x37, 0x39, 0xc6, 0x30, 0x1c, 0xfe, 0x06, 0xea, 0xfe, 0xb9, 0x00, 0xfe, 0x47, 0x4b,
+ 0x7c, 0xfe, 0x75, 0x57, 0x04, 0x5e, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0f, 0x7e, 0xfe, 0xfa,
+ 0x14, 0x46, 0xed, 0x0f, 0xc7, 0xfe, 0xf0, 0x14, 0xfe, 0x49, 0x54, 0x95, 0xfe, 0x08, 0x0e, 0x0f,
+ 0x1e, 0xfe, 0xe4, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x4c, 0x03, 0x0f, 0x5e, 0xfe, 0xc8, 0x14,
+ 0x89, 0x37, 0x39, 0xc6, 0x30, 0x1c, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x27, 0x2a, 0x2d,
+ 0x05, 0x10, 0xfe, 0x78, 0x12, 0x24, 0x16, 0x5d, 0x16, 0xb2, 0x2a, 0x48, 0x46, 0x4b, 0x48, 0xcc,
+ 0xd9, 0xfe, 0xbc, 0xf0, 0xfe, 0xa4, 0x0e, 0x07, 0x06, 0x16, 0x5d, 0x01, 0xfe, 0xb0, 0x16, 0x04,
+ 0xfe, 0x38, 0x01, 0x2b, 0xfe, 0x3a, 0x01, 0x52, 0xfe, 0xa8, 0x0e, 0x04, 0xfe, 0x38, 0x01, 0x1b,
+ 0xfe, 0xf0, 0xff, 0x0e, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0e, 0xfe, 0x62, 0x01, 0x20,
+ 0x06, 0x16, 0x48, 0xfe, 0x04, 0xec, 0x2d, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x40, 0x81, 0xfe,
+ 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x20, 0x17, 0x11, 0x48, 0xd3, 0x07, 0x06, 0x03, 0x24,
+ 0x03, 0x2a, 0x5d, 0xfe, 0xf7, 0x12, 0x2a, 0xb2, 0x70, 0x16, 0xb2, 0x05, 0xa5, 0xfe, 0x93, 0x13,
+ 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x4b, 0xfb, 0xe5, 0xfe, 0xd9, 0x10, 0x9a, 0xfe, 0x03, 0xdc, 0xfe,
+ 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x9a, 0xfe, 0x03, 0xdc, 0x24, 0xfe, 0x70, 0x57, 0xfe, 0x33,
+ 0x54, 0xfe, 0x3b, 0x54, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x9a, 0x24, 0xfe, 0x00, 0xcc,
+ 0x03, 0xfe, 0x03, 0x57, 0x9a, 0x7f, 0x03, 0x01, 0xfe, 0x50, 0x17, 0x3e, 0x05, 0x48, 0xfe, 0x0a,
+ 0x13, 0x07, 0x1e, 0x09, 0x51, 0xdc, 0x01, 0x9b, 0x01, 0x9d, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40,
+ 0x11, 0xfe, 0xe9, 0x00, 0x0a, 0x08, 0x8d, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0xe2, 0x16, 0xfe, 0x1e,
+ 0x1c, 0xfe, 0x14, 0x90, 0x0e, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0e, 0xfe, 0x66, 0x01, 0x0a,
+ 0x08, 0x78, 0xea, 0xfe, 0x03, 0x80, 0x72, 0x4c, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97,
+ 0x01, 0xa0, 0xfe, 0x62, 0x08, 0x70, 0x4c, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97, 0x01,
+ 0xa0, 0x6b, 0x33, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97, 0x01, 0x79, 0x03, 0xfe, 0x08,
+ 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04,
+ 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x20, 0x8b, 0x16, 0xfe, 0xb9, 0x00, 0x24, 0x0e, 0x5b, 0x0e, 0x56, 0x20, 0x10, 0x16, 0x2d, 0x16,
+ 0x3c, 0x50, 0xa4, 0xfe, 0x93, 0x00, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x79, 0x81, 0x11, 0x7b,
+ 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xd6, 0x0f, 0xdd, 0x8f, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
+ 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1c, 0xfe, 0x0c, 0x14, 0x89, 0xfe, 0x07, 0xe6, 0x39, 0xfe, 0xce,
+ 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x99, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0xda, 0x0f, 0x1e,
+ 0x01, 0x15, 0x05, 0x10, 0xe1, 0xfe, 0x44, 0x58, 0x4c, 0xfe, 0x01, 0xec, 0xc3, 0xfe, 0x9e, 0x40,
+ 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1d, 0xa3, 0x33, 0x01, 0xfe, 0xf8, 0x0e, 0xfe, 0xc9,
+ 0x10, 0x03, 0x38, 0x84, 0x74, 0x23, 0x29, 0xba, 0x05, 0x1d, 0xfe, 0x48, 0x12, 0x05, 0x0b, 0xfe,
+ 0x4c, 0x12, 0x05, 0x18, 0xfe, 0x30, 0x12, 0x05, 0xd5, 0x1a, 0xfe, 0xa0, 0x11, 0x05, 0xfe, 0x23,
+ 0x00, 0x1a, 0xfe, 0xac, 0x11, 0x05, 0x06, 0x1a, 0xa9, 0x05, 0x22, 0xfe, 0x12, 0x12, 0x05, 0x00,
+ 0x1a, 0x25, 0x17, 0xd5, 0x01, 0x2e, 0xce, 0x3b, 0x01, 0x0c, 0x83, 0x41, 0x03, 0x3b, 0x11, 0xfe,
+ 0xcc, 0x00, 0x02, 0x27, 0x3b, 0x3e, 0x05, 0xca, 0xfe, 0xe3, 0x13, 0x36, 0x42, 0x21, 0x43, 0x52,
+ 0xfe, 0x5e, 0x11, 0x0a, 0x08, 0x5f, 0xfe, 0x72, 0x12, 0x82, 0x31, 0x5a, 0x3f, 0x93, 0xc9, 0x95,
+ 0xfe, 0x28, 0x11, 0x2a, 0x67, 0xfe, 0x26, 0x13, 0x04, 0xb3, 0x2b, 0x90, 0x52, 0xfe, 0x78, 0x0d,
+ 0x0e, 0x65, 0x12, 0x66, 0x24, 0x0e, 0xb3, 0x0e, 0x90, 0x01, 0xbc, 0x20, 0x8b, 0x72, 0x16, 0x67,
+ 0x01, 0xf8, 0x82, 0x31, 0x5a, 0x3f, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x31,
+ 0xfe, 0x05, 0xfa, 0x3f, 0xfe, 0x91, 0x10, 0x04, 0x44, 0x2b, 0x45, 0xfe, 0x40, 0x56, 0xfe, 0xe1,
+ 0x56, 0x0e, 0x44, 0x12, 0x45, 0xab, 0x82, 0x31, 0x5a, 0x3f, 0x93, 0xc9, 0x04, 0x63, 0x2b, 0x64,
+ 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0e, 0x63, 0x12, 0x64, 0x0a, 0x08, 0x5f, 0xfe, 0x1e, 0x12,
+ 0x2a, 0x67, 0xfe, 0x1f, 0x40, 0x04, 0x65, 0x2b, 0x66, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04,
+ 0x44, 0x2b, 0x45, 0xfe, 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x63, 0x2b, 0x64, 0xfe, 0x08, 0x50,
+ 0xfe, 0x8a, 0x50, 0x04, 0x42, 0x2b, 0x43, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x9c, 0x20,
+ 0x06, 0x16, 0xfa, 0x02, 0x7a, 0x3b, 0x01, 0x0c, 0x1f, 0x55, 0x23, 0x29, 0xba, 0x05, 0x06, 0x28,
+ 0x55, 0x3e, 0x05, 0xca, 0x28, 0x7a, 0x01, 0xf2, 0x1b, 0x58, 0x1a, 0x55, 0x0a, 0x08, 0x0b, 0xe4,
+ 0x36, 0x42, 0x21, 0x43, 0xfe, 0x0a, 0x55, 0x30, 0xfe, 0x8b, 0x55, 0x4d, 0x42, 0x6e, 0x43, 0xfe,
+ 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x7a, 0xde, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7a,
+ 0x3b, 0x01, 0x0c, 0x1f, 0xc0, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0x60, 0x18, 0xfe, 0x94, 0x12, 0x60,
+ 0x0b, 0x59, 0x02, 0x55, 0x2f, 0xb0, 0x19, 0x32, 0x1f, 0xc0, 0x23, 0x29, 0x98, 0x05, 0x18, 0x28,
+ 0x55, 0x01, 0x0c, 0x1f, 0xc0, 0x23, 0x29, 0xfe, 0xe8, 0x09, 0x50, 0x04, 0xfe, 0x9c, 0x00, 0x2c,
+ 0x30, 0xfe, 0xbb, 0x45, 0x60, 0x00, 0x4e, 0x37, 0x06, 0xa4, 0x58, 0xfe, 0xc0, 0x14, 0xfe, 0xf8,
+ 0x14, 0xb1, 0x3e, 0x05, 0xc8, 0xfe, 0x16, 0x13, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xa9, 0x04, 0x56,
+ 0x2c, 0x30, 0x62, 0x02, 0x7a, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, 0x04, 0x5b,
+ 0xc2, 0x0e, 0x5b, 0x62, 0x3b, 0x01, 0x0c, 0x26, 0x9c, 0x01, 0xfe, 0xd0, 0x14, 0x02, 0x9c, 0x2f,
+ 0xfe, 0xb4, 0x12, 0x19, 0x32, 0x1f, 0x55, 0x23, 0x29, 0x98, 0x05, 0x06, 0x28, 0x55, 0xfe, 0xf6,
+ 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xb1, 0xfe, 0x4a, 0xf4, 0x0b, 0x1a,
+ 0x55, 0xfe, 0x4a, 0xf4, 0x06, 0xd8, 0x3e, 0x05, 0xc8, 0xd1, 0x02, 0x7a, 0x04, 0x56, 0xc2, 0x0e,
+ 0x56, 0x62, 0x3b, 0x01, 0x0c, 0x26, 0x9c, 0x01, 0xfe, 0xfe, 0x14, 0x02, 0x9c, 0x26, 0xe2, 0x76,
+ 0xf7, 0x76, 0x03, 0x35, 0xfe, 0x18, 0x13, 0x71, 0xfe, 0x18, 0x13, 0x62, 0x3b, 0x01, 0x0c, 0xfe,
+ 0xe3, 0x10, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x1b, 0xfe, 0xff, 0x7f, 0xfe, 0x30,
+ 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x1b, 0x58, 0xfe,
+ 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x03, 0x07,
+ 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0xfe, 0x0b, 0x58, 0x03, 0x0f, 0x5b, 0x01, 0x9f, 0x0f,
+ 0x56, 0x01, 0x9f, 0x03, 0xd0, 0x1b, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x22, 0x6c,
+ 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6b, 0x33, 0x0e, 0x63,
+ 0x12, 0x64, 0x4d, 0x44, 0x6e, 0x45, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a,
+ 0xbe, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x40, 0x19, 0xfe, 0x42, 0x48, 0x69, 0x50, 0x7c, 0x01,
+ 0x0c, 0x1f, 0xfe, 0xc8, 0x14, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0c, 0x1f,
+ 0xfe, 0xc8, 0x14, 0x23, 0x29, 0xfe, 0xe8, 0x0a, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0xc2, 0x12,
+ 0x24, 0xb8, 0x1d, 0xe4, 0x60, 0xd6, 0x77, 0xfe, 0x18, 0x14, 0x59, 0x07, 0x06, 0x09, 0xd6, 0xa4,
+ 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa8, 0xff, 0x02, 0x83, 0x55, 0xb8,
+ 0x18, 0xfe, 0x12, 0x13, 0x61, 0xfe, 0x30, 0x00, 0x95, 0xf3, 0x09, 0x88, 0x07, 0x06, 0xfe, 0x56,
+ 0x10, 0xb8, 0x0b, 0xfe, 0x16, 0x13, 0x61, 0xfe, 0x64, 0x00, 0x95, 0xf3, 0x0f, 0xfe, 0x64, 0x00,
+ 0x09, 0xae, 0x07, 0x06, 0xfe, 0x28, 0x10, 0xb8, 0x06, 0xfe, 0x5e, 0x13, 0x61, 0xfe, 0xc8, 0x00,
+ 0x95, 0xf3, 0x0f, 0xfe, 0xc8, 0x00, 0x09, 0x5d, 0x07, 0x06, 0xab, 0x61, 0xfe, 0x90, 0x01, 0x96,
+ 0xfe, 0x7e, 0x14, 0x7c, 0xad, 0xfe, 0x43, 0xf4, 0xb2, 0xfe, 0x56, 0xf0, 0xfe, 0x90, 0x14, 0xfe,
+ 0x04, 0xf4, 0x6a, 0xfe, 0x43, 0xf4, 0xae, 0xfe, 0xf3, 0x10, 0xb7, 0x01, 0xf1, 0x1b, 0x58, 0xda,
+ 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x8b, 0x96, 0xfe, 0xc2, 0x14, 0x7c, 0xfe, 0x14, 0x10, 0xfe,
+ 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0xec, 0x96, 0xfe, 0xc2, 0x14, 0xd2, 0xec, 0xa2, 0x50, 0x7c, 0x07,
+ 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x50, 0x07, 0x0b, 0x03, 0x14, 0x06, 0x01, 0x0c,
+ 0x26, 0xfe, 0xfc, 0x14, 0x14, 0x0b, 0x01, 0x0c, 0x26, 0xfe, 0xfc, 0x14, 0x14, 0x18, 0x01, 0x0c,
+ 0x26, 0xfe, 0xfc, 0x14, 0x76, 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0c, 0x26,
+ 0xb4, 0x14, 0x18, 0x01, 0x0c, 0x26, 0xb4, 0x14, 0x06, 0x01, 0x0c, 0x26, 0xb4, 0xfe, 0x89, 0x49,
+ 0x01, 0x0c, 0x26, 0xb4, 0x76, 0xfe, 0x89, 0x4a, 0x01, 0x0c, 0x03, 0x50, 0x03, 0x2a, 0xe8, 0x05,
+ 0x06, 0xfe, 0x44, 0x13, 0xb5, 0x16, 0xe8, 0xfe, 0x49, 0xf4, 0x00, 0x59, 0x76, 0xce, 0x62, 0xfe,
+ 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf7, 0x01, 0x0c, 0x3e, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13,
+ 0x1f, 0xfe, 0x80, 0x15, 0x24, 0x16, 0xfa, 0x01, 0x41, 0x2a, 0xfa, 0x05, 0x06, 0x4e, 0x0a, 0x4f,
+ 0x06, 0x3a, 0x03, 0x0e, 0x5c, 0x12, 0x8e, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1e,
+ 0x12, 0x49, 0xee, 0x94, 0x01, 0x47, 0xfe, 0x90, 0x4d, 0xe6, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x47,
+ 0xfe, 0x8d, 0x56, 0xbe, 0x49, 0x03, 0x49, 0x21, 0x8e, 0x01, 0x15, 0x49, 0x94, 0x01, 0x47, 0xe9,
+ 0x10, 0xe6, 0x10, 0x21, 0x5c, 0x61, 0x1e, 0x87, 0x0f, 0x5e, 0x01, 0xc5, 0x03, 0x0e, 0x5c, 0x12,
+ 0x8e, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x49, 0xee, 0x94, 0x01, 0x47,
+ 0xe9, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x47, 0x49, 0x03, 0x49, 0x21, 0x5c, 0x01,
+ 0x15, 0x49, 0x94, 0x01, 0x47, 0xe9, 0x10, 0xe6, 0x10, 0x21, 0x5c, 0x61, 0x1e, 0x87, 0x0f, 0x5e,
+ 0x01, 0xc5, 0x03, 0x0e, 0x5c, 0x12, 0x8e, 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, 0x42, 0x48, 0x94,
+ 0x01, 0x47, 0xfe, 0xc0, 0x5a, 0xb7, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xe4,
+ 0x9a, 0x7f, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x5a, 0x5c, 0xfe, 0x4d, 0xf4, 0x1e, 0xe2, 0x0f, 0x5e,
+ 0x01, 0x9f, 0xad, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x47, 0xfe, 0x00, 0x07, 0x7f, 0x05,
+ 0x10, 0x87, 0x5a, 0x8e, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01, 0x47, 0xfe,
+ 0x8d, 0x56, 0xbe, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, 0x10, 0x75, 0x6d, 0xfe, 0x60,
+ 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xe3, 0x39, 0x9e, 0xfe, 0xc4, 0x16,
+ 0x01, 0xfe, 0xca, 0x17, 0xd9, 0x8a, 0x39, 0x6d, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xbf,
+ 0x28, 0xfe, 0xb4, 0x16, 0xfe, 0xda, 0x10, 0x09, 0x10, 0x75, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00,
+ 0xf4, 0x22, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x8a, 0x22, 0xfe, 0x3c,
+ 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6d, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe,
+ 0x1c, 0xf7, 0x22, 0x9e, 0xfe, 0x0e, 0x17, 0xfe, 0xb6, 0x14, 0x30, 0x03, 0xbf, 0x28, 0xfe, 0xe6,
+ 0x16, 0xfe, 0x9c, 0x10, 0x09, 0x10, 0x75, 0xbe, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xe3, 0x31,
+ 0x9e, 0xfe, 0x30, 0x17, 0xfe, 0x94, 0x14, 0x2e, 0x8a, 0x31, 0x6d, 0x1d, 0xfe, 0xaf, 0x19, 0xfe,
+ 0x98, 0xe7, 0x00, 0x03, 0xbf, 0x28, 0xfe, 0x24, 0x17, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x75, 0xfe,
+ 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x8a, 0xe0, 0x6d, 0x1d, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xe0,
+ 0x9e, 0xfe, 0x68, 0x17, 0xfe, 0x5c, 0x14, 0x30, 0x03, 0xbf, 0x28, 0xfe, 0x54, 0x17, 0xfe, 0x42,
+ 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x75, 0xfe, 0x18, 0xfe, 0x65, 0xfe, 0x19, 0xfe, 0x66, 0xd0, 0xe3,
+ 0x78, 0x9e, 0xfe, 0x8e, 0x17, 0xfe, 0x36, 0x14, 0xe2, 0x8a, 0x78, 0x46, 0xfe, 0x83, 0x58, 0xfe,
+ 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x6b, 0x33,
+ 0x03, 0x6b, 0x33, 0xfe, 0x12, 0x45, 0x28, 0xfe, 0x7e, 0x17, 0x17, 0x06, 0x4b, 0xfb, 0xe5, 0x02,
+ 0x27, 0xfe, 0x39, 0xf0, 0xfe, 0xd2, 0x17, 0x24, 0x03, 0xfe, 0x7e, 0x18, 0x1b, 0x18, 0x85, 0x07,
+ 0x0d, 0x03, 0x75, 0x04, 0xe7, 0x1b, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1c, 0x0f, 0x1e,
+ 0x01, 0x15, 0x05, 0x10, 0x4e, 0x4c, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12, 0x58, 0x89, 0x37, 0x39,
+ 0xc6, 0xfe, 0xe9, 0x13, 0x1c, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x4e, 0x4c, 0xfe, 0x56, 0x14,
+ 0xb0, 0x58, 0x89, 0x37, 0x39, 0xc6, 0xfe, 0xe9, 0x13, 0x09, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b,
+ 0x13, 0xfe, 0x15, 0x00, 0x97, 0xa3, 0x33, 0x01, 0xfe, 0xf8, 0x0e, 0x09, 0x06, 0x03, 0x0a, 0x4f,
+ 0x39, 0x3a, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40, 0x11, 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79,
+ 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x36, 0xfe, 0xa8, 0x00, 0x21, 0x7b, 0xfe,
+ 0x48, 0x55, 0x30, 0xfe, 0xc9, 0x55, 0x03, 0x2a, 0xc4, 0x72, 0x16, 0xc4, 0x03, 0x0f, 0xc7, 0x01,
+ 0x15, 0xed, 0x0f, 0x7e, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x28, 0xfe, 0xc8, 0x18, 0x0f, 0x1e, 0x01,
+ 0x15, 0x05, 0x10, 0x4e, 0x0f, 0x5e, 0x01, 0xc5, 0x0f, 0x7e, 0x01, 0x15, 0x72, 0x7f, 0x03, 0xfe,
+ 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x2a, 0x3c, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x4c,
+ 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0x2e, 0xfe,
+ 0xe2, 0x08, 0x72, 0x4c, 0x3e, 0x05, 0x7b, 0xa7, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7,
+ 0x10, 0xfe, 0xc4, 0x48, 0x07, 0x2d, 0x09, 0x3c, 0xfe, 0x40, 0x5f, 0x1c, 0x01, 0x40, 0x11, 0xfe,
+ 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x07, 0x2d, 0x09, 0x3c, 0x01, 0x40, 0x11, 0xfe, 0xdd, 0x00, 0xfe,
+ 0x40, 0x4a, 0x70, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03,
+ 0xf0, 0x18, 0x77, 0xfe, 0x50, 0x19, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
+ 0xf0, 0xd5, 0x77, 0xfe, 0x62, 0x19, 0x04, 0xfe, 0x92, 0x00, 0xcf, 0x1d, 0xdf, 0xf0, 0xfe, 0x0b,
+ 0x00, 0x77, 0xfe, 0x74, 0x19, 0x04, 0xfe, 0x94, 0x00, 0xcf, 0x22, 0xfe, 0x08, 0x10, 0x04, 0xfe,
+ 0x96, 0x00, 0xcf, 0x88, 0xfe, 0x4e, 0x45, 0xd8, 0xfe, 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe,
+ 0xf1, 0x10, 0x1b, 0x8b, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4,
+ 0xfe, 0x00, 0x04, 0xd8, 0xfe, 0x48, 0xf4, 0x18, 0x96, 0xfe, 0xa8, 0x19, 0x07, 0x18, 0x03, 0x05,
+ 0xa5, 0xfe, 0x5a, 0xf0, 0xfe, 0xb8, 0x19, 0x20, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1d,
+ 0xfe, 0x5a, 0xf0, 0xfe, 0xc6, 0x19, 0x20, 0xd6, 0xfe, 0x26, 0x10, 0x05, 0x18, 0x85, 0x20, 0x88,
+ 0xdf, 0x05, 0x0b, 0x85, 0x20, 0xae, 0xfe, 0x0e, 0x10, 0x05, 0x06, 0x85, 0x20, 0x5d, 0xce, 0xb5,
+ 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x2e, 0x2f, 0xfe, 0xf6, 0x19, 0x04, 0x74, 0xb7, 0x03, 0x19,
+ 0xfe, 0x16, 0x1a, 0xfe, 0x14, 0xf0, 0x0c, 0x2f, 0xfe, 0x0a, 0x1a, 0x19, 0xfe, 0x16, 0x1a, 0xfe,
+ 0x82, 0xf0, 0xfe, 0x0e, 0x1a, 0x03, 0xff, 0x34, 0x00, 0x00,};
+
+STATIC unsigned short _adv_asc38C0800_size =
+ sizeof(_adv_asc38C0800_buf); /* 0x14AA */
+STATIC unsigned long _adv_asc38C0800_chksum =
+ 0x05297A65UL; /* Expanded checksum. */
/* a_init.c */
/*
* Additional structure information can be found in a_condor.h where
* the structure is defined.
*/
-STATIC ADVEEP_CONFIG
-Default_EEPROM_Config ASC_INITDATA = {
+STATIC ADVEEP_3550_CONFIG
+Default_3550_EEPROM_Config ASC_INITDATA = {
ADV_EEPROM_BIOS_ENABLE, /* cfg_msw */
0x0000, /* cfg_lsw */
0xFFFF, /* disc_enable */
0, /* bios_id_lun */
0, /* termination */
0, /* reserved1 */
- 0xFFEF, /* bios_ctrl */
+ 0xFFE7, /* bios_ctrl */
0xFFFF, /* ultra_able */
0, /* reserved2 */
ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
0 /* num_of_err */
};
+STATIC ADVEEP_38C0800_CONFIG
+Default_38C0800_EEPROM_Config ASC_INITDATA = {
+ ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_msw */
+ 0x0000, /* 01 cfg_lsw */
+ 0xFFFF, /* 02 disc_enable */
+ 0xFFFF, /* 03 wdtr_able */
+ 0x4444, /* 04 sdtr_speed1 */
+ 0xFFFF, /* 05 start_motor */
+ 0xFFFF, /* 06 tagqng_able */
+ 0xFFFF, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 7, /* 09 adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* 10 scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* 11 termination_se */
+ 0, /* termination_lvd */
+ 0xFFE7, /* 12 bios_ctrl */
+ 0x4444, /* 13 sdtr_speed2 */
+ 0x4444, /* 14 sdtr_speed3 */
+ ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ 0x4444, /* 17 sdtr_speed4 */
+ 0, /* 18 serial_number_word1 */
+ 0, /* 19 serial_number_word2 */
+ 0, /* 20 serial_number_word3 */
+ 0, /* 21 check_sum */
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ 0, /* 36 reserved */
+ 0, /* 37 reserved */
+ 0, /* 38 reserved */
+ 0, /* 39 reserved */
+ 0, /* 40 reserved */
+ 0, /* 41 reserved */
+ 0, /* 42 reserved */
+ 0, /* 43 reserved */
+ 0, /* 44 reserved */
+ 0, /* 45 reserved */
+ 0, /* 46 reserved */
+ 0, /* 47 reserved */
+ 0, /* 48 reserved */
+ 0, /* 49 reserved */
+ 0, /* 50 reserved */
+ 0, /* 51 reserved */
+ 0, /* 52 reserved */
+ 0, /* 53 reserved */
+ 0, /* 54 reserved */
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ ADV_PCI_VENDOR_ID, /* 58 subsysvid */
+ ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+ 0 /* 63 reserved */
+};
+
/*
* Initialize the ADV_DVC_VAR structure.
*
* For a non-fatal error return a warning code. If there are no warnings
* then 0 is returned.
*/
-int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+)
{
ushort warn_code;
AdvPortAddr iop_base;
/*
* Save the state of the PCI Configuration Command Register
* "Parity Error Response Control" Bit. If the bit is clear (0),
- * in AdvInitAsc3550Driver() tell the microcode to ignore DMA
- * parity errors.
+ * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+ * DMA parity errors.
*/
asc_dvc->cfg->control_flag = 0;
if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
}
- asc_dvc->cur_host_qng = 0;
-
asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
ADV_LIB_VERSION_MINOR;
asc_dvc->cfg->chip_version =
AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+ ASC_DBG2(1, "iopb_chip_id_1: %x %x\n",
+ (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+ (ushort) ADV_CHIP_ID_BYTE);
+
+ ASC_DBG2(1, "iopw_chip_id_0: %x %x\n",
+ (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+ (ushort) ADV_CHIP_ID_WORD);
+
/*
* Reset the chip to start and allow register writes.
*/
return ADV_ERROR;
}
else {
-
- AdvResetChip(asc_dvc);
-
- if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR)
+ /*
+ * The caller must set 'chip_type' to a valid setting.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
{
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
return ADV_ERROR;
}
- warn_code |= status;
/*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed.
+ * Reset Chip.
*/
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
{
- AdvResetSCSIBus(asc_dvc);
+ if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
+ {
+ return ADV_ERROR;
+ }
+ } else
+ {
+ if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
+ {
+ return ADV_ERROR;
+ }
}
+ warn_code |= status;
}
return warn_code;
}
/*
- * Initialize the ASC3550.
+ * Initialize the ASC-3550.
*
* On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
* For a non-fatal error return a warning code. If there are no warnings
* then 0 is returned.
*/
-int ASC_INIT
+STATIC int
AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ulong sum;
int begin_addr;
int end_addr;
- int code_sum;
+ ushort code_sum;
int word;
- int rql_addr; /* RISC Queue List address */
+ int j;
+ int adv_asc3550_expanded_size;
+ ADV_CARR_T *carrp;
+ ulong contig_len;
+ long buf_size;
+ ulong carr_paddr;
int i;
ushort scsi_cfg1;
- uchar biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory 0x40-0x8F. */
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able = 0, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
/* If there is already an error, don't continue. */
if (asc_dvc->err_code != 0)
return ADV_ERROR;
}
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
+ {
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
+
warn_code = 0;
iop_base = asc_dvc->iop_base;
* Note: This code makes the assumption, which is currently true,
* that a chip reset does not clear RISC LRAM.
*/
- for (i = 0; i < ASC_MC_BIOSLEN; i++)
+ for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+ }
+
+ /*
+ * Save current per TID negotiated values.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+ {
+ ushort bios_version, major, minor;
+
+ bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
+ major = (bios_version >> 12) & 0xF;
+ minor = (bios_version >> 8) & 0xF;
+ if (major <= 3 || (major == 3 && minor == 1))
+ {
+ /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+ AdvReadWordLram(iop_base, 0x120, wdtr_able);
+ } else
+ {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ }
+ }
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
{
- AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
/*
* Write the microcode image to RISC memory starting at address 0.
*/
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- for (word = 0; word < _adv_mcode_size; word += 2)
+ /* Assume the following compressed format of the microcode buffer:
+ *
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ */
+ word = 0;
+ for (i = 253 * 2; i < _adv_asc3550_size; i++)
{
- AdvWriteWordAutoIncLram(iop_base,
- *((ushort *) (&_adv_mcode_buf[word])));
+ if (_adv_asc3550_buf[i] == 0xff)
+ {
+ for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) (&_adv_asc3550_buf[i + 2])));
+ word++;
+ }
+ i += 3;
+ } else if (_adv_asc3550_buf[i] == 0xfe)
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) (&_adv_asc3550_buf[i + 1])));
+ i += 2;
+ word++;
+ } else
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) &_adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+ word++;
+ }
}
/*
- * Clear the rest of Condor's Internal RAM (8KB).
+ * Set 'word' for later use to clear the rest of memory and save
+ * the expanded mcode size.
+ */
+ word *= 2;
+ adv_asc3550_expanded_size = word;
+
+ /*
+ * Clear the rest of ASC-3550 Internal RAM (8KB).
*/
- for (; word < ADV_CONDOR_MEMSIZE; word += 2)
+ for (; word < ADV_3550_MEMSIZE; word += 2)
{
AdvWriteWordAutoIncLram(iop_base, 0);
}
*/
sum = 0;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- for (word = 0; word < _adv_mcode_size; word += 2)
+
+ for (word = 0; word < adv_asc3550_expanded_size; word += 2)
{
sum += AdvReadWordAutoIncLram(iop_base);
}
- if (sum != _adv_mcode_chksum)
+ if (sum != _adv_asc3550_chksum)
{
asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
return ADV_ERROR;
/*
* Restore the RISC memory BIOS region.
*/
- for (i = 0; i < ASC_MC_BIOSLEN; i++)
+ for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
{
- AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+ AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
}
/*
* Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
*/
AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
for (word = begin_addr; word < end_addr; word += 2)
{
- code_sum += *((ushort *) (&_adv_mcode_buf[word]));
+ code_sum += AdvReadWordAutoIncLram(iop_base);
}
AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
/*
- * Read microcode version and date.
+ * Read and save microcode version and date.
*/
AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
/*
- * Initialize microcode operating variables
+ * Set the chip type to indicate the ASC3550.
*/
- AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID,
- asc_dvc->chip_scsi_id);
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
/*
* If the PCI Configuration Command Register "Parity Error Response
*/
if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
{
- /*
+ /*
* Note: Don't remove the use of a temporary variable in
* the following code, otherwise the Microsoft C compiler
* will turn the following lines into a no-op.
}
/*
- * Set default microcode operating variables for WDTR, SDTR, and
- * command tag queuing based on the EEPROM configuration values.
+ * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+ * threshold of 128 bytes. This register is only accessible to the host.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
+
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in AdvInquiryHandling() based on what a
+ * device reports it is capable of in Inquiry byte 7.
*
- * These ADV_DVC_VAR fields and the microcode variables will be
- * changed in AdvInquiryHandling() if it is found a device is
- * incapable of a particular feature.
+ * If SCSI Bus Resets haev been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
*/
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+ }
/*
- * Set the microcode ULTRA target mask from EEPROM value. The
- * SDTR target mask overrides the ULTRA target mask in the
- * microcode so it is safe to set this value without determining
- * whether the device supports SDTR.
- *
- * Note: There is no way to know whether a device supports ULTRA
- * speed without attempting a SDTR ULTRA speed negotiation with
- * the device. The device will reject the speed if it does not
- * support it by responding with an SDTR message containing a
- * slower speed.
+ * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+ * bitmask. These values determine the maximum SDTR speed negotiated
+ * with a device.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ *
+ * 4-bit speed SDTR speed name
+ * =========== ===============
+ * 0000b (0x0) SDTR disabled
+ * 0001b (0x1) 5 Mhz
+ * 0010b (0x2) 10 Mhz
+ * 0011b (0x3) 20 Mhz (Ultra)
+ * 0100b (0x4) 40 Mhz (LVD/Ultra2)
+ * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
+ * 0110b (0x6) Undefined
+ * .
+ * 1111b (0xF) Undefined
+ */
+ word = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
+ {
+ /* Set Ultra speed for TID 'tid'. */
+ word |= (0x3 << (4 * (tid % 4)));
+ } else
+ {
+ /* Set Fast speed for TID 'tid'. */
+ word |= (0x2 << (4 * (tid % 4)));
+ }
+ if (tid == 3) /* Check if done with sdtr_speed1. */
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+ word = 0;
+ } else if (tid == 7) /* Check if done with sdtr_speed2. */
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+ word = 0;
+ } else if (tid == 11) /* Check if done with sdtr_speed3. */
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+ word = 0;
+ } else if (tid == 15) /* Check if done with sdtr_speed4. */
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+ /* End of loop. */
+ }
+ }
+
+ /*
+ * Set microcode operating variable for the disconnect per TID bitmask.
*/
- AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able);
AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
-
+
/*
* Determine SCSI_CFG1 Microcode Default Value.
*
if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
(scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
{
- asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
- return ADV_ERROR;
+ asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+ return ADV_ERROR;
}
/*
* termination value based on a table listed in a_condor.h.
*
* If manual termination was specified with an EEPROM setting
- * then 'termination' was set-up in AdvInitFromEEP() and
+ * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
* is ready to be 'ored' into SCSI_CFG1.
*/
if (asc_dvc->cfg->termination == 0)
* after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
- FLTR_11_TO_20NS | scsi_cfg1);
+ FLTR_11_TO_20NS | scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-3550 has 8KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_8KB);
/*
* Set SEL_MASK Microcode Default Value
* after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
/*
- * Link all the RISC Queue Lists together in a doubly-linked
- * NULL terminated list.
+ * Build carrier freelist.
*
- * Skip the NULL (0) queue which is not used.
+ * Driver must have already allocated memory and set 'carrier_buf'.
*/
- for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE;
- i < ASC_MC_RISC_Q_TOTAL_CNT;
- i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE)
+ ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
{
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else
+ {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
+
+ do {
+ /*
+ * Get physical address of the carrier 'carrp'.
+ */
+ contig_len = sizeof(ADV_CARR_T);
+ carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+ (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+ buf_size -= sizeof(ADV_CARR_T);
+
+ /*
+ * If the current carrier is not physically contiguous, then
+ * maybe there was a page crossing. Try the next carrier aligned
+ * start address.
+ */
+ if (contig_len < sizeof(ADV_CARR_T))
+ {
+ carrp++;
+ continue;
+ }
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = (ulong) carrp;
+
/*
- * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers
- * in a one word write and set the state (RQL_STATE) to free.
+ * Insert the carrier at the beginning of the freelist.
*/
- AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8)));
- AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+ carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+ asc_dvc->carr_freelist = carrp;
+
+ carrp++;
}
+ while (buf_size > 0);
/*
- * Set the Host and RISC Queue List pointers.
- *
- * Both sets of pointers are initialized with the same values:
- * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+ {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+
+ /*
+ * Set RISC ICQ physical address start value.
*/
- AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST);
- AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+ AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+ {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
- AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST);
- AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
/*
- * Finally, set up the last RISC Queue List (255) with
- * a NULL forward pointer.
+ * Set RISC IRQ physical address start value.
*/
- AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8)));
- AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+ AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+ (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
- /*
+ /*
* Note: Don't remove the use of a temporary variable in
* the following code, otherwise the Microsoft C compiler
* will turn the following lines into a no-op.
/* finally, finally, gentlemen, start your engine */
AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
-
- return warn_code;
-}
-/*
- * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
- * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
- * all of this is done.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+ {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+ {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else
+ {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE)
+ {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+STATIC int
+AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ulong sum;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int j;
+ int adv_asc38C0800_expanded_size;
+ ADV_CARR_T *carrp;
+ ulong contig_len;
+ long buf_size;
+ ulong carr_paddr;
+ int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
+
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ {
+ return ADV_ERROR;
+ }
+
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+ {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
+
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+ }
+
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ /*
+ * RAM BIST (RAM Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
+
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++)
+ {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+ {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE)
+ {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+ }
+
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
+
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+ {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
+
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ /* Assume the following compressed format of the microcode buffer:
+ *
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ */
+ word = 0;
+ for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+ {
+ if (_adv_asc38C0800_buf[i] == 0xff)
+ {
+ for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) (&_adv_asc38C0800_buf[i + 2])));
+ word++;
+ }
+ i += 3;
+ } else if (_adv_asc38C0800_buf[i] == 0xfe)
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) (&_adv_asc38C0800_buf[i + 1])));
+ i += 2;
+ word++;
+ } else
+ {
+ AdvWriteWordAutoIncLram(iop_base, *((ushort *)
+ &_adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+ word++;
+ }
+ }
+
+ /*
+ * Set 'word' for later use to clear the rest of memory and save
+ * the expanded mcode size.
+ */
+ word *= 2;
+ adv_asc38C0800_expanded_size = word;
+
+ /*
+ * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+ */
+ for (; word < ADV_38C0800_MEMSIZE; word += 2)
+ {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ }
+
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
+ {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
+
+ if (sum != _adv_asc38C0800_chksum)
+ {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return ADV_ERROR;
+ }
+
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+ }
+
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2)
+ {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC38C0800.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+ {
+ /*
+ * Note: Don't remove the use of a temporary variable in
+ * the following code, otherwise the Microsoft C compiler
+ * will turn the following lines into a no-op.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
+
+ /*
+ * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+ * bits for the default FIFO threshold.
+ *
+ * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+ *
+ * For DMA Errata #4 set the BC_THRESH_ENB bit.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in AdvInquiryHandling() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+ {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+ }
+
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+ {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * All kind of combinations of devices attached to one of four connectors
+ * are acceptable except HVD device attached. For example, LVD device can
+ * be attached to SE connector while SE device attached to LVD connector.
+ * If LVD device attached to SE connector, it only runs up to Ultra speed.
+ *
+ * If an HVD device is attached to one of LVD connectors, return an error.
+ * However, there is no way to detect HVD device attached to SE connectors.
+ */
+ if (scsi_cfg1 & HVD)
+ {
+ asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If either SE or LVD automatic termination control is enabled, then
+ * set the termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting then
+ * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+ * be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0)
+ {
+ /* SE automatic termination control is enabled. */
+ switch(scsi_cfg1 & C_DET_SE)
+ {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1: case 0x2: case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
+
+ /* TERM_SE_HI: on, TERM_SE_LO: off */
+ case 0x0:
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ break;
+ }
+ }
+
+ if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
+ {
+ /* LVD automatic termination control is enabled. */
+ switch(scsi_cfg1 & C_DET_LVD)
+ {
+ /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+ case 0x4: case 0x8: case 0xC:
+ asc_dvc->cfg->termination |= TERM_LVD;
+ break;
+
+ /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+ case 0x0:
+ break;
+ }
+ }
+
+ /*
+ * Clear any set TERM_SE and TERM_LVD bits.
+ */
+ scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+
+ /*
+ * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+ /*
+ * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+ * and set possibly modified termination control bits in the Microcode
+ * SCSI_CFG1 Register Value.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control and reset DIS_TERM_DRV
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C0800 has 16KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ /*
+ * Build the carrier freelist.
+ *
+ * Driver must have already allocated memory and set 'carrier_buf'.
+ */
+
+ ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+ {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else
+ {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
+
+ do {
+ /*
+ * Get physical address for the carrier 'carrp'.
+ */
+ contig_len = sizeof(ADV_CARR_T);
+ carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+ (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+ buf_size -= sizeof(ADV_CARR_T);
+
+ /*
+ * If the current carrier is not physically contiguous, then
+ * maybe there was a page crossing. Try the next carrier aligned
+ * start address.
+ */
+ if (contig_len < sizeof(ADV_CARR_T))
+ {
+ carrp++;
+ continue;
+ }
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = (ulong) carrp;
+
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+ asc_dvc->carr_freelist = carrp;
+
+ carrp++;
+ }
+ while (buf_size > 0);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+ {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+
+ /*
+ * Set RISC ICQ physical address start value.
+ */
+ AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+ {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+ /*
+ * Note: Don't remove the use of a temporary variable in
+ * the following code, otherwise the Microsoft C compiler
+ * will turn the following lines into a no-op.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+ {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+ {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else
+ {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE)
+ {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADVEEP_38C0800_CONFIG eep_config;
+ int i;
+ uchar tid, termination;
+ ushort sdtr_speed = 0;
+
+ iop_base = asc_dvc->iop_base;
+
+ warn_code = 0;
+
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+ {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+ {
+ *((uchar *) &eep_config + i) =
+ *((uchar *) &Default_38C0800_EEPROM_Config + i);
+ }
+
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+
+ AdvSet38C0800EEPConfig(iop_base, &eep_config);
+ }
+ /*
+ * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ asc_dvc->wdtr_able = eep_config.wdtr_able;
+ asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+ asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+ asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+ asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+ asc_dvc->tagqng_able = eep_config.tagqng_able;
+ asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+ asc_dvc->start_motor = eep_config.start_motor;
+ asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+ asc_dvc->no_scam = eep_config.scam_tolerant;
+ asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+ asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+ asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+ /*
+ * For every Target ID if any of its 'sdtr_speed[1234]' bits
+ * are set, then set an 'sdtr_able' bit for it.
+ */
+ asc_dvc->sdtr_able = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ if (tid == 0)
+ {
+ sdtr_speed = asc_dvc->sdtr_speed1;
+ } else if (tid == 4)
+ {
+ sdtr_speed = asc_dvc->sdtr_speed2;
+ } else if (tid == 8)
+ {
+ sdtr_speed = asc_dvc->sdtr_speed3;
+ } else if (tid == 12)
+ {
+ sdtr_speed = asc_dvc->sdtr_speed4;
+ }
+ if (sdtr_speed & ADV_MAX_TID)
+ {
+ asc_dvc->sdtr_able |= (1 << tid);
+ }
+ sdtr_speed >>= 4;
+ }
+
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+ {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+ {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0)
+ {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else
+ {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
+
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+ {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0)
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
+
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+ {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
+
+ /*
+ * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ADV_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ADV_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination_se == 0)
+ {
+ termination = 0; /* auto termination for SE */
+ } else
+ {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_se == 1)
+ {
+ termination = 0;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_se == 2)
+ {
+ termination = TERM_SE_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_se == 3)
+ {
+ termination = TERM_SE;
+ } else
+ {
+ /*
+ * The EEPROM 'termination_se' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
+
+ if (eep_config.termination_lvd == 0)
+ {
+ asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+ } else
+ {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_lvd == 1)
+ {
+ asc_dvc->cfg->termination = termination;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_lvd == 2)
+ {
+ asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_lvd == 3)
+ {
+ asc_dvc->cfg->termination =
+ termination | TERM_LVD;
+ } else
+ {
+ /*
+ * The EEPROM 'termination_lvd' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ asc_dvc->cfg->termination = termination;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
* For a non-fatal error return a warning code. If there are no warnings
* then 0 is returned.
*
* Note: Chip is stopped on entry.
*/
-STATIC int ASC_INIT
-AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+)
{
AdvPortAddr iop_base;
ushort warn_code;
- ADVEEP_CONFIG eep_config;
+ ADVEEP_3550_CONFIG eep_config;
int i;
iop_base = asc_dvc->iop_base;
*
* Set default values if a bad checksum is found.
*/
- if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+ if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
{
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_CONFIG); i++)
+ for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
{
*((uchar *) &eep_config + i) =
- *((uchar *) &Default_EEPROM_Config + i);
+ *((uchar *) &Default_3550_EEPROM_Config + i);
}
/*
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
eep_config.serial_number_word2 =
AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
eep_config.serial_number_word1 =
AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
- AdvSetEEPConfig(iop_base, &eep_config);
- }
+ AdvSet3550EEPConfig(iop_base, &eep_config);
+ }
/*
- * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+ * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
* EEPROM configuration that was read.
*
* This is the mapping of EEPROM fields to Adv Library fields.
asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
asc_dvc->start_motor = eep_config.start_motor;
asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
- asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay;
asc_dvc->bios_ctrl = eep_config.bios_ctrl;
asc_dvc->no_scam = eep_config.scam_tolerant;
asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
}
/*
- * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng'
+ * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
* values based on possibly adjusted EEPROM values.
*/
asc_dvc->max_host_qng = eep_config.max_host_qng;
*
* Return a checksum based on the EEPROM configuration read.
*/
-STATIC ushort ASC_INIT
-AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+ ADVEEP_38C0800_CONFIG *cfg_buf)
+)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+
+ wbuf = (ushort *) cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+ eep_addr < ASC_EEP_DVC_CFG_END;
+ eep_addr++, wbuf++)
+ {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval;
+ *wbuf = wval;
+ }
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+ eep_addr < ASC_EEP_MAX_WORD_ADDR;
+ eep_addr++, wbuf++)
+ {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ }
+ return chksum;
+}
+
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+)
{
ushort wval, chksum;
ushort *wbuf;
/*
* Read the EEPROM from specified location
*/
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+)
{
AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
ASC_EEP_CMD_READ | eep_word_addr);
/*
* Wait for EEPROM command to complete
*/
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
AdvWaitEEPCmd(AdvPortAddr iop_base)
+)
{
int eep_delay_ms;
/*
* Write the EEPROM from 'cfg_buf'.
*/
-STATIC void ASC_INIT
-AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+void
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+ ushort *wbuf;
+ ushort addr, chksum;
+
+ wbuf = (ushort *) cfg_buf;
+ chksum = 0;
+
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
+
+ /*
+ * Write EEPROM from word 0 to word 20
+ */
+ for (addr = ASC_EEP_DVC_CFG_BEGIN;
+ addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+ {
+ chksum += *wbuf;
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+ }
+
+ /*
+ * Write EEPROM checksum at word 21
+ */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++; /* skip over check_sum */
+
+ /*
+ * Write EEPROM OEM name at words 22 to 29
+ */
+ for (addr = ASC_EEP_DVC_CTL_BEGIN;
+ addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+ {
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+ return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
+ ADVEEP_38C0800_CONFIG *cfg_buf)
{
- ushort *wbuf;
- ushort addr, chksum;
+ ushort *wbuf;
+ ushort addr, chksum;
wbuf = (ushort *) cfg_buf;
chksum = 0;
AdvWaitEEPCmd(iop_base);
/*
- * Write EEPROM from word 0 to word 15
+ * Write EEPROM from word 0 to word 20
*/
for (addr = ASC_EEP_DVC_CFG_BEGIN;
addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
}
/*
- * Write EEPROM checksum at word 18
+ * Write EEPROM checksum at word 21
*/
AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
wbuf++; /* skip over check_sum */
/*
- * Write EEPROM OEM name at words 19 to 26
+ * Write EEPROM OEM name at words 22 to 29
*/
for (addr = ASC_EEP_DVC_CTL_BEGIN;
addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
return;
}
+/* a_advlib.c */
/*
- * This function resets the chip and SCSI bus
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
*
- * It is up to the caller to add a delay to let the bus settle after
- * calling this function.
+ * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ * add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ * RISC to notify it a new command is ready to be executed.
*
- * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
- * AdvInitAsc3550Driver(). Here when doing a write to one of these
- * registers read first and then write.
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
*
- * Note: A SCSI Bus Reset can not be done until after the EEPROM
- * configuration is read to determine whether SCSI Bus Resets
- * should be performed.
+ * Return:
+ * ADV_SUCCESS(1) - The request was successfully queued.
+ * ADV_BUSY(0) - Resource unavailable; Retry again after pending
+ * request completes.
+ * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
+ * host IC error.
*/
-STATIC void ASC_INIT
-AdvResetChip(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+ ADV_SCSI_REQ_Q *scsiq)
{
- AdvPortAddr iop_base;
- ushort word;
- uchar byte;
+ int last_int_level;
+ AdvPortAddr iop_base;
+ long req_size;
+ ulong req_paddr;
+ ADV_CARR_T *new_carrp;
+
+ ADV_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+
+ /*
+ * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+ */
+ if (scsiq->target_id > ADV_MAX_TID)
+ {
+ scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+ scsiq->done_status = QD_WITH_ERROR;
+ return ADV_ERROR;
+ }
iop_base = asc_dvc->iop_base;
+ last_int_level = DvcEnterCritical();
+
/*
- * Reset Chip.
+ * Allocate a carrier ensuring at least one carrier always
+ * remains on the freelist and initialize fields.
*/
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+ if ((new_carrp = asc_dvc->carr_freelist) == NULL)
+ {
+ return ADV_BUSY;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *) new_carrp->next_vpa;
+ asc_dvc->carr_pending_cnt++;
/*
- * Initialize Chip registers.
- *
- * Note: Don't remove the use of a temporary variable in the following
- * code, otherwise the Microsoft C compiler will turn the following lines
- * into a no-op.
+ * Set the carrier to be a stopper by setting 'next_vpa'
+ * to the stopper value. The current stopper will be changed
+ * below to point to the new stopper.
+ */
+ new_carrp->next_vpa = ASC_CQ_STOPPER;
+
+ /*
+ * Clear the ADV_SCSI_REQ_Q done flag.
*/
- byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG);
- byte |= RAM_SZ_8KB;
- AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte);
+ scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+ req_size = sizeof(ADV_SCSI_REQ_Q);
+ req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+ (long *) &req_size, ADV_IS_SCSIQ_FLAG);
+
+ ADV_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
+ ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+ /* Save virtual and physical address of ADV_SCSI_REQ_Q and Carrier. */
+ scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+ scsiq->scsiq_rptr = req_paddr;
+
+ /* XXX - Could have the RISC set these values. */
+ scsiq->carr_va = (ulong) asc_dvc->icq_sp;
+ scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
- word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- word &= ~BIG_ENDIAN;
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word);
+ /*
+ * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+ * the microcode. The newly allocated stopper will become the new
+ * stopper.
+ */
+ asc_dvc->icq_sp->areq_vpa = (ulong) req_paddr;
/*
- * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
- * of 128 bytes. This register is only accessible to the host.
+ * Set the 'next_vpa' pointer for the old stopper to be the
+ * physical address of the new stopper. The RISC can only
+ * follow physical addresses.
*/
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- START_CTL_EMFU | READ_CMD_MRM);
-}
+ asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
-/* a_advlib.c */
-/*
- * Description:
- * Send a SCSI request to the ASC3550 chip
- *
- * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
- *
- * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
- * called. It is assumed the caller has already initialized 'sg_real_addr'.
- *
- * Return:
- * ADV_SUCCESS(1) - the request is in the mailbox
- * ADV_BUSY(0) - total request count > 253, try later
- * ADV_ERROR(-1) - invalid scsi request Q
- */
-STATIC int
-AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
- ADV_SCSI_REQ_Q *scsiq)
-{
- if (scsiq == (ADV_SCSI_REQ_Q *) 0L)
+ /*
+ * Set the host adapter stopper pointer to point to the new carrier.
+ */
+ asc_dvc->icq_sp = new_carrp;
+
+ /*
+ * Tickle the RISC to tell it to read its Command Queue Head pointer.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
{
- /* 'scsiq' should never be NULL. */
- ADV_ASSERT(0);
- return ADV_ERROR;
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_a' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
}
- return AdvSendScsiCmd(asc_dvc, scsiq);
+ DvcLeaveCritical(last_int_level);
+
+ return ADV_SUCCESS;
}
/*
* Reset SCSI Bus and purge all outstanding requests.
*
* Return Value:
- * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
- *
- * Note: Should always return ADV_TRUE.
+ * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ * ADV_FALSE(0) - Microcode command failed.
+ * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ * may be hung which requires driver recovery.
*/
STATIC int
AdvResetSB(ADV_DVC_VAR *asc_dvc)
{
int status;
- status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0);
+ /*
+ * Send the SCSI Bus Reset idle start idle command which asserts
+ * the SCSI Bus Reset signal.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
+ if (status != ADV_TRUE)
+ {
+ return status;
+ }
+
+ /*
+ * Delay for the specified SCSI Bus Reset hold time.
+ *
+ * The hold time delay is done on the host because the RISC has no
+ * microsecond accurate timer.
+ */
+ DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+
+ /*
+ * Send the SCSI Bus Reset end idle command which de-asserts
+ * the SCSI Bus Reset signal and purges any pending requests.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
+ if (status != ADV_TRUE)
+ {
+ return status;
+ }
- AdvResetSCSIBus(asc_dvc);
+ DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
return status;
}
/*
- * Reset SCSI Bus and delay.
+ * Reset chip and SCSI Bus.
+ *
+ * Return Value:
+ * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
+ * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
*/
-STATIC void
-AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort scsi_ctrl;
+ int status;
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ uchar tid, max_cmd[ADV_MAX_TID + 1];
+ AdvPortAddr iop_base;
+ ushort bios_sig;
iop_base = asc_dvc->iop_base;
/*
- * The microcode currently sets the SCSI Bus Reset signal while
- * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
- * But the SCSI Bus Reset Hold Time in the microcode is not deterministic
- * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
- * Therefore on return the Adv Library sets the SCSI Bus Reset signal
- * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
- * than 25 us.
+ * Save current per TID negotiated values.
*/
- scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
- scsi_ctrl | ADV_SCSI_CTRL_RSTOUT);
- DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
- scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT);
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
-}
+ /*
+ * Force the AdvInitAsc3550/38C0800Driver() function to
+ * perform a SCSI Bus Reset by clearing the BIOS signature word.
+ * The initialization functions assumes a SCSI Bus Reset is not
+ * needed if the BIOS signature word is present.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+ /*
+ * Stop chip and reset it.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+ /*
+ * Reset Adv Library error code, if any, and try
+ * re-initializing the chip.
+ */
+ asc_dvc->err_code = 0;
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+ {
+ status = AdvInitAsc38C0800Driver(asc_dvc);
+ } else
+ {
+ status = AdvInitAsc3550Driver(asc_dvc);
+ }
+
+ /* Translate initialization return value to status value. */
+ if (status == 0)
+ {
+ status = ADV_TRUE;
+ } else
+ {
+ status = ADV_FALSE;
+ }
+
+ /*
+ * Restore the BIOS signature word.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++)
+ {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ return status;
+}
/*
* Adv Library Interrupt Service Routine
{
AdvPortAddr iop_base;
uchar int_stat;
- ushort next_done_loc, target_bit;
- int completed_q;
+ ushort target_bit;
+ ADV_CARR_T *free_carrp;
+ ulong irq_next_vpa;
int flags;
ADV_SCSI_REQ_Q *scsiq;
- ASC_REQ_SENSE *sense_data;
- int ret;
flags = DvcEnterCritical();
- iop_base = asc_dvc->iop_base;
- if (AdvIsIntPending(iop_base))
- {
- ret = ADV_TRUE;
- } else
- {
- ret = ADV_FALSE;
- }
+ iop_base = asc_dvc->iop_base;
/* Reading the register clears the interrupt. */
int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
- if (int_stat & ADV_INTR_STATUS_INTRB)
+ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+ ADV_INTR_STATUS_INTRC)) == 0)
{
- asc_dvc->idle_cmd_done = ADV_TRUE;
+ return ADV_FALSE;
}
/*
- * Notify the driver of a hardware detected SCSI Bus Reset.
+ * Notify the driver of an asynchronous microcode condition by
+ * calling the ADV_DVC_VAR.async_callback function. The function
+ * is passed the microcode ASC_MC_INTRB_CODE byte value.
*/
- if (int_stat & ADV_INTR_STATUS_INTRC)
+ if (int_stat & ADV_INTR_STATUS_INTRB)
{
- if (asc_dvc->sbreset_callback != 0)
+ uchar intrb_code;
+
+ AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+ if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+ asc_dvc->carr_pending_cnt != 0)
+ {
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+ {
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ }
+ }
+
+ if (asc_dvc->async_callback != 0)
{
- (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc);
+ (*asc_dvc->async_callback)(asc_dvc, intrb_code);
}
}
/*
- * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
- * Queue List request. Its forward pointer (RQL_FWD) points to the
- * current completed RISC Queue List request.
+ * Check if the IRQ stopper carrier contains a completed request.
*/
- AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc);
- next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
- (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
-
- AdvReadByteLram(iop_base, next_done_loc, completed_q);
-
- /* Loop until all completed Q's are processed. */
- while (completed_q != ASC_MC_NULL_Q)
+ while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0)
{
- AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q);
-
- next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
- (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+ /*
+ * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+ * The RISC will have set 'areq_vpa' to a virtual address.
+ */
+ scsiq = (ADV_SCSI_REQ_Q *) asc_dvc->irq_sp->areq_vpa;
/*
- * Read the ADV_SCSI_REQ_Q virtual address pointer from
- * the RISC list entry. The microcode has changed the
- * ADV_SCSI_REQ_Q physical address to its virtual address.
- *
- * Refer to comments at the end of AdvSendScsiCmd() for
- * more information on the RISC list structure.
+ * Advance the stopper pointer to the next carrier
+ * ignoring the lower four bits. Free the previous
+ * stopper carrier.
*/
- {
- ushort lsw, msw;
- AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw);
- AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw);
+ free_carrp = asc_dvc->irq_sp;
+ asc_dvc->irq_sp = ASC_GET_CARRP(irq_next_vpa);
+
+ free_carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+ asc_dvc->carr_freelist = (ADV_CARR_T *) free_carrp;
+ asc_dvc->carr_pending_cnt--;
- scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw);
- }
- ADV_ASSERT(scsiq != NULL);
+ ADV_ASSERT(scsiq != NULL);
target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
/*
* Check Condition handling
*/
if ((scsiq->done_status == QD_WITH_ERROR) &&
- (scsiq->scsi_status == SS_CHK_CONDITION) &&
- (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
- (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN)
+ (scsiq->scsi_status == SS_CHK_CONDITION)
+ )
{
- /*
- * Command returned with a check condition and valid
- * sense data.
- */
}
/*
* If the command that completed was a SCSI INQUIRY and
* command information for the device.
*/
else if (scsiq->done_status == QD_NO_ERROR &&
- scsiq->cdb[0] == SCSICMD_Inquiry &&
- scsiq->target_lun == 0)
+ scsiq->cdb[0] == SCSICMD_Inquiry &&
+ scsiq->target_lun == 0)
{
AdvInquiryHandling(asc_dvc, scsiq);
}
-
- /* Change the RISC Queue List state to free. */
- AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
-
- /* Get the RISC Queue List forward pointer. */
- AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q);
-
/*
* Notify the driver of the completed request by passing
* the ADV_SCSI_REQ_Q pointer to its callback function.
*/
- ADV_ASSERT(asc_dvc->cur_host_qng > 0);
- asc_dvc->cur_host_qng--;
scsiq->a_flag |= ADV_SCSIQ_DONE;
- (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq);
+ (*asc_dvc->isr_callback)(asc_dvc, scsiq);
/*
* Note: After the driver callback function is called, 'scsiq'
* can no longer be referenced.
(void) DvcEnterCritical();
}
DvcLeaveCritical(flags);
- return ret;
+ return ADV_TRUE;
}
/*
* Send an idle command to the chip and wait for completion.
*
- * Interrupts do not have to be enabled on entry.
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
*
* Return Values:
* ADV_TRUE - command completed successfully
* ADV_FALSE - command failed
+ * ADV_ERROR - command timed out
*/
STATIC int
AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
ushort idle_cmd,
- ulong idle_cmd_parameter,
- int flags)
+ ulong idle_cmd_parameter)
{
int last_int_level;
- ulong i;
+ int result;
+ ulong i, j;
AdvPortAddr iop_base;
- int ret;
-
- asc_dvc->idle_cmd_done = 0;
last_int_level = DvcEnterCritical();
+
iop_base = asc_dvc->iop_base;
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ * The non-zero result is one of the IDLE_CMD_STATUS_* values
+ * defined in a_advlib.h.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
+
/*
* Write the idle command value after the idle command parameter
* has been written to avoid a race condition. If the order is not
* followed, the microcode may process the idle command before the
* parameters have been written to LRAM.
*/
- AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter);
+ AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+ idle_cmd_parameter);
AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
- DvcLeaveCritical(last_int_level);
/*
- * If the 'flags' argument contains the ADV_NOWAIT flag, then
- * return with success.
+ * Tickle the RISC to tell it to process the idle command.
*/
- if (flags & ADV_NOWAIT)
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
{
- return ADV_TRUE;
- }
-
- for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++)
- {
- /*
- * 'idle_cmd_done' is set by AdvISR().
- */
- if (asc_dvc->idle_cmd_done)
- {
- break;
- }
- DvcSleepMilliSecond(1);
-
/*
- * If interrupts were disabled on entry to AdvSendIdleCmd(),
- * then they will still be disabled here. Call AdvISR() to
- * check for the idle command completion.
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_b' does not work unless the host
+ * value is cleared.
*/
- (void) AdvISR(asc_dvc);
- }
-
- last_int_level = DvcEnterCritical();
-
- if (asc_dvc->idle_cmd_done == ADV_FALSE)
- {
- ADV_ASSERT(0); /* The idle command should never timeout. */
- return ADV_FALSE;
- } else
- {
- AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret);
- return ret;
- }
-}
-
-/*
- * Send the SCSI request block to the adapter
- *
- * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
- * following structure:
- *
- * 0: RQL_FWD - RISC list forward pointer (1 byte)
- * 1: RQL_BWD - RISC list backward pointer (1 byte)
- * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
- * 3: RQL_TID - request target id (1 byte)
- * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes)
- *
- * Return:
- * ADV_SUCCESS(1) - the request is in the mailbox
- * ADV_BUSY(0) - total request count > 253, try later
- */
-STATIC int
-AdvSendScsiCmd(
- ADV_DVC_VAR *asc_dvc,
- ADV_SCSI_REQ_Q *scsiq)
-{
- ushort next_ready_loc;
- uchar next_ready_loc_fwd;
- int last_int_level;
- AdvPortAddr iop_base;
- long req_size;
- ulong q_phy_addr;
-
- /*
- * The ADV_SCSI_REQ_Q 'target_id' field should never be equal
- * to the host adapter ID or exceed ADV_MAX_TID.
- */
- if (scsiq->target_id == asc_dvc->chip_scsi_id ||
- scsiq->target_id > ADV_MAX_TID)
- {
- scsiq->host_status = QHSTA_M_INVALID_DEVICE;
- scsiq->done_status = QD_WITH_ERROR;
- return ADV_ERROR;
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
}
- iop_base = asc_dvc->iop_base;
-
- last_int_level = DvcEnterCritical();
-
- if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng)
- {
- DvcLeaveCritical(last_int_level);
- return ADV_BUSY;
- } else
+ /* Wait for up to 100 millisecond for the idle command to timeout. */
+ for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
{
- ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT);
- asc_dvc->cur_host_qng++;
+ /* Poll once each microsecond for command completion. */
+ for (j = 0; j < SCSI_US_PER_MSEC; j++)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
+ if (result != 0)
+ {
+ DvcLeaveCritical(last_int_level);
+ return result;
+ }
+ DvcDelayMicroSecond(asc_dvc, (ushort) 1);
+ }
}
- /*
- * Clear the ADV_SCSI_REQ_Q done flag.
- */
- scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
- /*
- * Save the original sense buffer length.
- *
- * After the request completes 'sense_len' will be set to the residual
- * byte count of the Auto-Request Sense if a command returns CHECK
- * CONDITION and the Sense Data is valid indicated by 'host_status' not
- * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
- * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
- */
- scsiq->orig_sense_len = scsiq->sense_len;
-
- AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc);
- next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
- (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
-
- /*
- * Write the physical address of the Q to the mailbox.
- * We need to skip the first four bytes, because the microcode
- * uses them internally for linking Q's together.
- */
- req_size = sizeof(ADV_SCSI_REQ_Q);
- q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq,
- (uchar *) scsiq, &req_size,
- ADV_IS_SCSIQ_FLAG);
- ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr);
- ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
- scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
-
- /*
- * The RISC list structure, which 'next_ready_loc' is a pointer
- * to in microcode LRAM, has the format detailed in the comment
- * header for this function.
- *
- * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request.
- */
- AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr);
-
- /* Write target_id to 'next_ready_loc' request. */
- AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id);
-
- /*
- * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
- * the 'next_ready_loc' request forward pointer.
- *
- * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
- * After the state is changed to QS_READY 'RQL_FWD' will be changed
- * by the microcode.
- *
- * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
- * prevent some compilers from optimizing out 'AdvReadByteLram()' if
- * it were used as the 3rd argument to 'AdvWriteByteLram()'.
- */
- AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd);
- AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd);
-
- /*
- * Change the state of 'next_ready_loc' request from QS_FREE to
- * QS_READY which will cause the microcode to pick it up and
- * execute it.
- *
- * Can't reference 'next_ready_loc' after changing the request
- * state to QS_READY. The microcode now owns the request.
- */
- AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY);
-
+ ADV_ASSERT(0); /* The idle command should never timeout. */
DvcLeaveCritical(last_int_level);
- return ADV_SUCCESS;
+ return ADV_ERROR;
}
/*
* Inquiry Information Byte 7 Handling
*
* Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag
+ * microcode operating variables that affect WDTR, SDTR, and Tag
* Queuing.
*/
STATIC void
AdvInquiryHandling(
- ADV_DVC_VAR *asc_dvc,
- ADV_SCSI_REQ_Q *scsiq)
+ ADV_DVC_VAR *asc_dvc,
+ ADV_SCSI_REQ_Q *scsiq)
{
- AdvPortAddr iop_base;
- uchar tid;
- ASC_SCSI_INQUIRY *inq;
- ushort tidmask;
- ushort cfg_word;
+ AdvPortAddr iop_base;
+ uchar tid;
+ ADV_SCSI_INQUIRY *inq;
+ ushort tidmask;
+ ushort cfg_word;
/*
* AdvInquiryHandling() requires up to INQUIRY information Byte 7
* length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
* microcode to the transfer residual count.
*/
+
if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
{
return;
iop_base = asc_dvc->iop_base;
tid = scsiq->target_id;
- inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+ inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
/*
* WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
*/
- if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2)
+ if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2)
{
return;
} else
* device's 'wdtr_able' bit and write the new value to the
* microcode.
*/
- if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16)
+ if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16)
{
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
if ((cfg_word & tidmask) == 0)
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
/*
- * Clear the microcode "WDTR negotiation" done indicator
- * for the target to cause it to negotiate with the new
- * setting set above.
+ * Clear the microcode "SDTR negotiation" and "WDTR
+ * negotiation" done indicators for the target to cause
+ * it to negotiate with the new setting set above.
+ * WDTR when accepted causes the target to enter
+ * asynchronous mode, so SDTR must be negotiated.
*/
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
cfg_word &= ~tidmask;
AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
* supports synchronous transfers, then turn on the device's
* 'sdtr_able' bit. Write the new value to the microcode.
*/
- if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync)
+ if ((asc_dvc->sdtr_able & tidmask) && inq->Sync)
{
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
if ((cfg_word & tidmask) == 0)
}
/*
- * If the EEPROM enabled Tag Queuing for device and the
- * device supports Tag Queuing, then turn on the device's
+ * If the EEPROM enabled Tag Queuing for the device and the
+ * device supports Tag Queueing, then turn on the device's
* 'tagqng_enable' bit in the microcode and set the microcode
* maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
* value.
* disabling Tag Queuing in the BIOS devices with Tag Queuing
* bugs will at least work with the BIOS.
*/
- if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue)
+ if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue)
{
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
cfg_word |= tidmask;
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+
AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
asc_dvc->max_dvc_qng);
}
* 09/24/98 hl - v1.01b Fixed reset.
* 10/05/98 hl - v1.02 split the source code and release.
* 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
+ * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
+ * 08/08/99 bv - v1.02c Use waitForPause again.
**************************************************************************/
#ifndef CVT_LINUX_VERSION
#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S)
#endif
+#include <linux/version.h>
#include <linux/sched.h>
#include <asm/io.h>
#include "i60uscsi.h"
+#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
+#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
/* ---- INTERNAL FUNCTIONS ---- */
static UCHAR waitChipReady(ORC_HCS * hcsp);
/***************************************************************************/
static void waitForPause(unsigned amount)
{
- ULONG the_time = jiffies + amount; /* 0.01 seconds per jiffy */
+ ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
while (time_before_eq(jiffies, the_time));
{
int i;
- for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */
return (TRUE);
- waitForPause(5); /* wait 500ms before try again */
+ waitForPause(100); /* wait 100ms before try again */
}
return (FALSE);
}
{
int i;
- for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */
return (TRUE);
- waitForPause(5); /* wait 500ms before try again */
+ waitForPause(100); /* wait 100ms before try again */
}
return (FALSE);
}
{
int i;
- for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */
return (TRUE);
- waitForPause(5); /* wait 500ms before try again */
+ waitForPause(100); /* wait 100ms before try again */
}
return (FALSE);
}
{
int i;
- for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */
return (TRUE);
- waitForPause(5); /* wait 500ms before try again */
+ waitForPause(100); /* wait 100ms before try again */
}
return (FALSE);
}
{
int i;
- for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
return (TRUE); /* Wait HDI set */
- waitForPause(5); /* wait 500ms before try again */
+ waitForPause(100); /* wait 100ms before try again */
}
return (FALSE);
}
pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
for (i = 0; i < orc_num_scb; i++) {
-#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
- pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i));
- pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb);
- pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb);
-#else
pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
-#endif
pVirScb->SCB_EScb = pVirEscb;
pVirScb->SCB_ScbIdx = i;
pVirScb++;
* 12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up.
**************************************************************************/
-#include <linux/config.h>
-
#define ULONG unsigned long
#define PVOID void *
#define USHORT unsigned short
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
-in2000__INITFUNC( void in2000_setup (char *str, int *ints) )
+void __init in2000_setup (char *str, int *ints)
{
int i;
char *p1,*p2;
/* check_setup_args() returns index if key found, 0 if not
*/
-in2000__INITFUNC( static int check_setup_args(char *key, int *flags, int *val, char *buf) )
+static int __init check_setup_args(char *key, int *flags, int *val, char *buf)
{
int x;
char *cp;
};
-in2000__INITFUNC( int in2000_detect(Scsi_Host_Template * tpnt) )
+int __init in2000_detect(Scsi_Host_Template * tpnt)
{
struct Scsi_Host *instance;
struct IN2000_hostdata *hostdata;
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
#include <stdarg.h>
+#include <asm/io.h>
#include <asm/irq.h>
+#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
#include <linux/bios32.h>
#endif
#include <linux/pci.h>
+#include <linux/proc_fs.h>
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
#include <linux/init.h>
#endif
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
#include <asm/spinlock.h>
#endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "inia100.h"
#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
#else
+#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
-#include <asm/system.h>
-#include "../block/blk.h"
-#endif
-
-#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
+
#include <linux/sched.h>
#include <linux/proc_fs.h>
+#include <asm/system.h>
#include <asm/io.h>
+#include "../block/blk.h"
#include "scsi.h"
#include "sd.h"
#include "hosts.h"
#include <linux/malloc.h>
#include "inia100.h"
+#endif
#ifdef MODULE
Scsi_Host_Template driver_template = INIA100;
char *inia100_Copyright = "Copyright (C) 1998-99";
char *inia100_InitioName = "by Initio Corporation";
char *inia100_ProductName = "INI-A100U2W";
-char *inia100_Version = "v1.02a";
+char *inia100_Version = "v1.02c";
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
struct proc_dir_entry proc_scsi_inia100 =
extern int inia100_biosparam(Disk *, int, int *); /*for linux v1.13 */
#endif
-#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a"
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c"
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
#define INIA100 { \
scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
scsi_CDs[i].needs_sector_size = 1;
} else {
+#if 0
if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
- (long*)&scsi_CDs[i].capacity)) {
+ (long*)&scsi_CDs[i].capacity))
+#endif
scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
(buffer[1] << 16) |
(buffer[2] << 8) |
buffer[3]);
- }
scsi_CDs[i].sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
switch (scsi_CDs[i].sector_size) {
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
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate 'ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+fi
dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
if [ "$CONFIG_VISWS" = "y" ]; then
dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
* removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
* 12.08.99 0.27 module_init/__setup fixes
* 19.08.99 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ * 31.08.99 0.29 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * replaced current->state = x with set_current_state(x)
*
* some important things missing in Ensoniq documentation:
*
if (s->dma_dac1.mapped || !s->dma_dac1.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac1.wait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac1.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
if (s->dma_dac2.mapped || !s->dma_dac2.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac2.wait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac2.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (file->f_flags & O_NONBLOCK) {
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = (count * HZ) / 3100;
DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
}
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
}
down(&s->open_sem);
s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
};
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
static int __init init_es1370(void)
{
struct es1370_state *s;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1370: version v0.28 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
- if (pcidev->resource[0].flags == 0 ||
- (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ if (!RSRCISIOREGION(pcidev, 0))
continue;
if (pcidev->irq == 0)
continue;
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
s->magic = ES1370_MAGIC;
- s->io = pcidev->resource[0].start;
+ s->io = RSRCADDRESS(pcidev, 0);
s->irq = pcidev->irq;
if (check_region(s->io, ES1370_EXTENT)) {
printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
static int __init es1370_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned __initlocaldata nr_dev = 0;
if (nr_dev >= NR_DEVICE)
return 0;
+ (void)
( (get_option(&str,&joystick[nr_dev]) == 2)
&& (get_option(&str,&lineout [nr_dev]) == 2)
&& get_option(&str,&micbias [nr_dev])
* added a /proc file system for dumping hardware state
* updated SRC and CODEC w/r functions to accomodate bugs
* in some versions of the ES137x chips.
+ * 31.08.99 0.17 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * replaced current->state = x with set_current_state(x)
*
*/
if (s->dma_dac1.mapped || !s->dma_dac1.ready)
return 0;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac1.wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
for (;;) {
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac1.count;
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac1.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
if (s->dma_dac2.mapped || !s->dma_dac2.ready)
return 0;
+ __set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&s->dma_dac2.wait, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
for (;;) {
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac2.count;
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac2.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (file->f_flags & O_NONBLOCK) {
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = (count * HZ) / 3100;
printk(KERN_DEBUG "es1371: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
}
down(&s->open_sem);
s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
{ SOUND_MIXER_WRITE_IGAIN, 0x4040 }
};
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
static int __init init_es1371(void)
{
struct es1371_state *s;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1371: version v0.15 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
- if (pcidev->resource[0].flags == 0 ||
- (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ if (!RSRCISIOREGION(pcidev, 0))
continue;
if (pcidev->irq == 0)
continue;
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
s->magic = ES1371_MAGIC;
- s->io = pcidev->resource[0].start;
+ s->io = RSRCADDRESS(pcidev, 0);
s->irq = pcidev->irq;
pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
if (check_region(s->io, ES1371_EXTENT)) {
static int __init es1371_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned __initlocaldata nr_dev = 0;
if (nr_dev >= NR_DEVICE)
return 0;
if (get_option(&str, &joystick[nr_dev]) == 2)
- get_option(&str, &spdif[nr_dev]);
+ (void)get_option(&str, &spdif[nr_dev]);
nr_dev++;
return 1;
}
* The fun part is that the Windows Solo1 driver doesn't
* seem to do these tricks.
* Bugs remaining: plops and clicks when starting/stopping playback
+ * 31.08.99 0.7 add spin_lock_init
+ * replaced current->state = x with set_current_state(x)
*
*/
if (s->dma_dac.mapped)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
printk(KERN_DEBUG "solo1: dma timed out??\n");
}
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (file->f_flags & O_NONBLOCK) {
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = (count * HZ) / 3100;
printk(KERN_DEBUG "solo1: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
}
down(&s->open_sem);
s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
{ SOUND_MIXER_WRITE_MIC, 0x4040 }
};
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
static int __init init_solo1(void)
{
struct solo1_state *s;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
- if (pcidev->resource[0].start == 0 ||
- (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
- pcidev->resource[1].start == 0 ||
- (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
- pcidev->resource[2].start == 0 ||
- (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
- pcidev->resource[3].start == 0 ||
- (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ if (!RSRCISIOREGION(pcidev, 0) ||
+ !RSRCISIOREGION(pcidev, 1) ||
+ !RSRCISIOREGION(pcidev, 2) ||
+ !RSRCISIOREGION(pcidev, 3))
continue;
if (pcidev->irq == 0)
continue;
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
s->magic = SOLO1_MAGIC;
s->pcidev = pcidev;
- s->iobase = pcidev->resource[0].start;
- s->sbbase = pcidev->resource[1].start;
- s->vcbase = pcidev->resource[2].start;
+ s->iobase = RSRCADDRESS(pcidev, 0);
+ s->sbbase = RSRCADDRESS(pcidev, 1);
+ s->vcbase = RSRCADDRESS(pcidev, 2);
s->ddmabase = s->vcbase + DDMABASE_OFFSET;
- s->mpubase = pcidev->resource[3].start;
- s->gpbase = pcidev->resource[4].start;
+ s->mpubase = RSRCADDRESS(pcidev, 3);
+ s->gpbase = RSRCADDRESS(pcidev, 4);
s->irq = pcidev->irq;
if (check_region(s->iobase, IOBASE_EXTENT) ||
check_region(s->sbbase, SBBASE_EXTENT) ||
* 03.08.99 0.17 adapt to Linus' new __setup/__initcall
* added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
* 12.08.99 0.18 module_init/__setup fixes
+ * 24.08.99 0.19 get rid of the dmaio kludge, replace with allocate_resource
+ * 31.08.99 0.20 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * use new resource allocation to allocate DDMA IO space
+ * replaced current->state = x with set_current_state(x)
*
*/
#define SV_EXTENT_GAME 0x8
#define SV_EXTENT_DMA 0x10
+#define RESOURCE_SB 0
+#define RESOURCE_ENH 1
+#define RESOURCE_SYNTH 2
+#define RESOURCE_MIDI 3
+#define RESOURCE_GAME 4
+#define RESOURCE_DDMA 7
#define SV_MIDI_DATA 0
#define SV_MIDI_COMMAND 1
if (s->dma_dac.mapped || !s->dma_dac.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (nonblock) {
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
printk(KERN_DEBUG "sv: dma timed out??\n");
}
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
spin_lock_irqsave(&s->lock, flags);
break;
if (file->f_flags & O_NONBLOCK) {
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
return -EBUSY;
}
tmo = (count * HZ) / 3100;
printk(KERN_DEBUG "sv: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
}
down(&s->open_sem);
s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
static int wavetable[NR_DEVICE] = { 0, };
#endif
-static unsigned dmaio = 0xac00;
-
MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
#if 0
MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
#endif
-MODULE_PARM(dmaio, "i");
-MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address");
-
MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
MODULE_DESCRIPTION("S3 SonicVibes Driver");
{ SOUND_MIXER_WRITE_PCM, 0x4040 }
};
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
static int __init init_sonicvibes(void)
{
struct sv_state *s;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.18 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
#endif
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) {
- if (pcidev->resource[1].flags == 0 ||
- (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
- continue;
- if (pcidev->resource[2].flags == 0 ||
- (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
- continue;
- if (pcidev->resource[3].flags == 0 ||
- (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_GAME))
continue;
if (pcidev->irq == 0)
continue;
+ /* try to allocate a DDMA resource if not already available */
+ if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
+ /* take care of ISA aliases */
+ if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA,
+ 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024)) {
+ printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
+ continue;
+ }
+ pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
+ }
if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
printk(KERN_WARNING "sv: out of memory\n");
continue;
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
s->magic = SV_MAGIC;
- s->iosb = pcidev->resource[0].start;
- s->ioenh = pcidev->resource[1].start;
- s->iosynth = pcidev->resource[2].start;
- s->iomidi = pcidev->resource[3].start;
- s->iogame = pcidev->resource[4].start;
- pci_read_config_dword(pcidev, 0x40, &s->iodmaa);
- pci_read_config_dword(pcidev, 0x48, &s->iodmac);
- dmaio &= ~(SV_EXTENT_DMA-1);
- s->iodmaa &= ~(SV_EXTENT_DMA-1);
- s->iodmac &= ~(SV_EXTENT_DMA-1);
- if (!(s->iodmaa)) {
- s->iodmaa = dmaio;
- dmaio += SV_EXTENT_DMA;
- printk(KERN_INFO "sv: BIOS did not allocate DDMA channel A io, allocated at %#x\n",
- s->iodmaa);
- }
- if (!(s->iodmac)) {
- s->iodmac = dmaio;
- dmaio += SV_EXTENT_DMA;
- printk(KERN_INFO "sv: BIOS did not allocate DDMA channel C io, allocated at %#x\n",
- s->iodmac);
- }
+ s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB);
+ s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH);
+ s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH);
+ s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI);
+ s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME);
+ s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA);
+ s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
- if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0)
- continue;
s->irq = pcidev->irq;
/* hack */
wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
- //outb(0xff, s->iodmaa + SV_DMA_RESET);
- //outb(0xff, s->iodmac + SV_DMA_RESET);
+ /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+ /* outb(0xff, s->iodmac + SV_DMA_RESET); */
inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
static int __init sonicvibes_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned __initlocaldata nr_dev = 0;
if (nr_dev >= NR_DEVICE)
return 0;
#if 0
if (get_option(&str, &reverb[nr_dev]) == 2)
- get_option(&str, &wavetable[nr_dev]);
+ (void)get_option(&str, &wavetable[nr_dev]);
#else
- get_option(&str, &reverb[nr_dev]);
+ (void)get_option(&str, &reverb[nr_dev]);
#endif
nr_dev++;
return 1;
}
-static int __init sonicvibesdmaio_setup(char *str)
-{
- int io;
-
- if (get_option(&str, &io))
- dmaio = io;
- return 1;
-}
-
__setup("sonicvibes=", sonicvibes_setup);
-__setup("sonicvibesdmaio=", sonicvibesdmaio_setup);
#endif /* MODULE */
ham <ham@unsuave.com>
Bradley M Keryan <keryan@andrew.cmu.edu>
Paul Mackerras <paulus@cs.anu.edu.au>
+ David E. Nelson <dnelson@jump.net>
Vojtech Pavlik <vojtech@twilight.ucw.cz>
Gregory P. Smith <greg@electricrain.com>
Linus Torvalds <torvalds@transmeta.com>
dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+ dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
MIX_OBJS += mouse.o
endif
+ifeq ($(CONFIG_USB_HP_SCANNER),y)
+ L_OBJS += hp_scanner.o
+endif
+ifeq ($(CONFIG_USB_HP_SCANNER),m)
+ M_OBJS +=hp_scanner.o
+ MIX_OBJS +=hp_scanner.o
+endif
+
ifeq ($(CONFIG_USB_HUB),y)
L_OBJS += hub.o
endif
--- /dev/null
+August 30, 1999
+
+
+Overview
+
+This README will address issues regarding how to configure the kernel
+to access a USB HP Scanner. The scanner should support the Scanner
+Control Language (SCL) so that applications such as SANE can access it
+properly. Refer to the document README.hp_scanner_sane for guidance
+on how to configure SANE to use the USB HP Scanner.
+
+
+Requirements
+
+A host with a USB port. Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work. However, I've only
+been able to really use an OHCI controller. I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results.
+
+A Linux kernel with USB support (preferably 2.3.15+).
+
+A Linux kernel with USB HP Scanner support.
+
+
+Configuration
+
+Add both USB controller support and USB HP Scanner support using `make
+menuconfig`. If you decide to use the ohci-hcd driver, don't forget
+to add HUB support. Compile and install the modules. Testing was
+performed only as modules, YMMV.
+
+Add a device for the USB scanner: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner. Both read and write
+permissions are needed for proper operation.
+
+Load the appropriate modules:
+
+ OHCI:
+
+ modprobe usb-ohci
+ modprobe hp_scanner
+
+ OHCI-HCD:
+ modprobe usb-ohci-hcd
+ modprobe hub
+ modprobe hp_scanner
+
+That's it. SANE should now be able to access the device.
+
+There is a small test program (hp_scan.c) that can be used to test the
+scanner device. It's purpose is to test the driver(s) without having
+to retrieve/configure SANE. Hp_scan.c will scan the entire bed and
+put the output into a file called out.dat in the current directory.
+The data in the file is raw data.
+
+David /\/elson
+dnelson@jump.net
--- /dev/null
+August 30, 1999
+
+NOTE: This is all VERY alpha. Use at your own risk. There is no
+warranty expressed nor implied.
+
+
+Introduction
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface. The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C. All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C). Of course as HP releases new scanners this information
+may change.
+
+
+Requirements
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB HP Scanner support. Please refer to README.hp_scanner
+for issues pertaining to Linux USB and USB HP Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/. Testing has been performed using
+version SANE-1.0.1. For instructions on building and installing SANE,
+refer to the various README files within the distribution.
+
+
+Ok, so what do I do?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed. It may
+be /usr/local, /usr, /opt or somewhere else. If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+ dll.conf: Make sure that the 'hp' entry is present and uncommented.
+
+ hp.conf: This should contain two lines:
+
+ option connect-device
+ /dev/usbscanner
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE. If you have other entries uncommented in dll.conf, you my have
+to specify the device to (x)scanimage. The xscanimage (1) man page
+has info on how to get 'The Gimp' to work with xscanimage. Note that
+Gimp support must be compiled into SANE for it work. If you are
+dealing with a RedHat system, you'll also need to install the
+gimp-devel rpm package.
+
+NOTE: Most of the time xscanimage will run without incident, then on
+the next invocation it'll core dump at different locations. I don't
+know why yet and I don't have a work around either other than to try
+again. But once you get it started, it'll scan without any problems
+(or at least it does for me).
+
+David /\/elson
+dnelson@jump.net
/* First for desc. [0] */
id = cpia->sbuf [0].isodesc;
id->start_type = START_ASAP;
- id->callback_frames = 1; /* on every frame */
+ id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
- id->data = cpia->sbuf [0].data;
+ id->data = cpia->sbuf[0].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
/* and the desc. [1] */
id = cpia->sbuf [1].isodesc;
id->start_type = 0; /* will follow the first desc. */
- id->callback_frames = 1; /* on every frame */
+ id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
- id->data = cpia->sbuf [1].data;
+ id->data = cpia->sbuf[1].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
- usb_run_isoc (cpia->sbuf [0].isodesc, NULL);
- usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc);
+ usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
+ usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
#if 0
usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
-#define FRAMES_PER_DESC 500
+#define FRAMES_PER_DESC 10
#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
enum {
* bulk reads.
* Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
* Preliminary ISO support
+ * 0.3 01.09.99 Async Bulk and ISO support
+ * 0.4 01.09.99
*
*/
/*****************************************************************************/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/socket.h>
-#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
#include "usb.h"
#include "ezusb.h"
static struct ezusb {
struct semaphore mutex;
struct usb_device *usbdev;
- struct list_head iso;
+ struct list_head async_pending;
+ struct list_head async_completed;
+ wait_queue_head_t wait;
+ spinlock_t lock;
} ezusb[NREZUSB];
-struct isodesc {
- struct list_head isolist;
- spinlock_t lock;
- struct usb_device *usbdev;
- unsigned int ep;
- unsigned int pipe;
- unsigned int pktsz;
- unsigned int framesperint;
- unsigned int rd, wr, buflen;
- unsigned int flags;
- unsigned int schedcnt, unschedcnt;
+struct async {
+ struct list_head asynclist;
+ struct ezusb *ez;
+ void *data;
+ unsigned dataorder;
+ void *userdata;
+ unsigned datalen;
+ union {
+ struct usb_isoc_desc *iso;
+ void *bulk;
+ } desc;
+ unsigned numframes; /* 0 means bulk, > 0 means iso */
+ struct ezusb_asynccompleted completed;
+};
- void *hcbuf[2];
- void *hcisodesc[2];
- unsigned char *buf;
-};
+/* --------------------------------------------------------------------- */
-#define ISOFLG_ACTIVE (1<<0)
+extern inline unsigned ld2(unsigned int x)
+{
+ unsigned r = 0;
+
+ if (x >= 0x10000) {
+ x >>= 16;
+ r += 16;
+ }
+ if (x >= 0x100) {
+ x >>= 8;
+ r += 8;
+ }
+ if (x >= 0x10) {
+ x >>= 4;
+ r += 4;
+ }
+ if (x >= 4) {
+ x >>= 2;
+ r += 2;
+ }
+ if (x >= 2)
+ r++;
+ return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void async_removelist(struct async *as)
+{
+ struct ezusb *ez = as->ez;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+ struct ezusb *ez = as->ez;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ list_add_tail(&as->asynclist, &ez->async_pending);
+ spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_movetocompleted(struct async *as)
+{
+ struct ezusb *ez = as->ez;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ list_del(&as->asynclist);
+ list_add_tail(&as->asynclist, &ez->async_completed);
+ spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct ezusb *ez)
+{
+ unsigned long flags;
+ struct async *as = NULL;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ if (!list_empty(&ez->async_completed)) {
+ as = list_entry(ez->async_completed.next, struct async, asynclist);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ }
+ spin_unlock_irqrestore(&ez->lock, flags);
+ return as;
+}
+
+extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context)
+{
+ unsigned long flags;
+ struct async *as;
+ struct list_head *p;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ for (p = ez->async_pending.next; p != &ez->async_pending; ) {
+ as = list_entry(p, struct async, asynclist);
+ p = p->next;
+ if (as->completed.context != context)
+ continue;
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ez->lock, flags);
+ return as;
+ }
+ spin_unlock_irqrestore(&ez->lock, flags);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+ struct async *as = (struct async *)dev_id;
+ struct ezusb *ez = as->ez;
+ unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+ as->completed.length = rval;
+ if (as->numframes > 0) {
+ as->completed.status = USB_ST_NOERROR;
+ for (cnt = 0; cnt < as->numframes; cnt++) {
+ as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+ as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+ }
+ } else
+ as->completed.status = status;
+ spin_lock(&ez->lock);
+ list_del(&as->asynclist);
+ list_add_tail(&as->asynclist, &ez->async_completed);
+ spin_unlock(&ez->lock);
+ wake_up(&ez->wait);
+ return 0;
+}
+
+static void remove_async(struct async *as)
+{
+ if (as->data && as->dataorder)
+ free_pages((unsigned long)as->data, as->dataorder);
+ if (as->numframes)
+ usb_free_isoc(as->desc.iso);
+ kfree(as);
+}
+
+static void kill_async(struct async *as)
+{
+ struct ezusb *ez = as->ez;
+
+ if (as->numframes)
+ /* ISO case */
+ usb_kill_isoc(as->desc.iso);
+ else
+ usb_terminate_bulk(ez->usbdev, as->desc.bulk);
+ as->completed.status = USB_ST_REMOVED;
+ async_movetocompleted(as);
+}
+
+static void destroy_all_async(struct ezusb *ez)
+{
+ struct async *as;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ez->lock, flags);
+ if (!list_empty(&ez->async_completed)) {
+ as = list_entry(ez->async_pending.next, struct async, asynclist);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ez->lock, flags);
+ kill_async(as);
+ spin_lock_irqsave(&ez->lock, flags);
+ }
+ spin_unlock_irqrestore(&ez->lock, flags);
+ while ((as = async_getcompleted(ez)))
+ remove_async(as);
+}
/* --------------------------------------------------------------------- */
up(&ez->mutex);
file->f_pos = 0;
file->private_data = ez;
+ MOD_INC_USE_COUNT;
return 0;
}
static int ezusb_release(struct inode *inode, struct file *file)
{
struct ezusb *ez = (struct ezusb *)file->private_data;
+
+ down(&ez->mutex);
+ destroy_all_async(ez);
+ up(&ez->mutex);
+ MOD_DEC_USE_COUNT;
return 0;
}
-static void iso_schedrcv(struct isodesc *isodesc)
+static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
+ unsigned char request, unsigned short value,
+ unsigned short index, unsigned short length,
+ void *data)
{
- unsigned diff;
-
- if (!(isodesc->flags & ISOFLG_ACTIVE))
- return;
- diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
- if (diff < isodesc->framesperint * isodesc->pktsz)
- return;
- for (;;) {
- diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
- if (diff >= 2)
- return;
- usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
- diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
- isodesc->schedcnt++;
+ unsigned char *tbuf = NULL;
+ unsigned int pipe;
+ int i;
+
+ if (length > PAGE_SIZE)
+ return -EINVAL;
+ /* __range_ok is broken;
+ with unsigned short size, it gave
+ addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx
+ */
+ if (requesttype & 0x80) {
+ pipe = usb_rcvctrlpipe(usbdev, 0);
+ if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length))
+ return -EFAULT;
+ } else
+ pipe = usb_sndctrlpipe(usbdev, 0);
+ if (length > 0) {
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (!(requesttype & 0x80)) {
+ if (copy_from_user(tbuf, data, length)) {
+ free_page((unsigned long)tbuf);
+ return -EFAULT;
+ }
+ }
}
+ i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+ if (i) {
+ if (length > 0)
+ free_page((unsigned long)tbuf);
+ printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n",
+ requesttype, request, length, i);
+ return -ENXIO;
+ }
+ if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length))
+ i = -EFAULT;
+ if (length > 0)
+ free_page((unsigned long)tbuf);
+ return i;
}
-static void iso_schedsnd(struct isodesc *isodesc)
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
{
- unsigned diff, bcnt, x;
- unsigned char *p1, *p2;
-
- if (!(isodesc->flags & ISOFLG_ACTIVE))
- return;
- for (;;) {
- diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
- if (diff >= 2)
- return;
- bcnt = (isodesc->buflen - isodesc->rd + isodesc->wr) % isodesc->buflen;
- if (bcnt < isodesc->framesperint * isodesc->pktsz)
- return;
- p2 = isodesc->hcbuf[isodesc->schedcnt & 1];
- for (bcnt = 0; bcnt < isodesc->framesperint; bcnt++) {
- p1 = isodesc->buf + isodesc->rd;
- if (isodesc->rd + isodesc->pktsz > isodesc->buflen) {
- x = isodesc->buflen - isodesc->rd;
- memcpy(p2, p1, x);
- memcpy(p2+x, isodesc->buf, isodesc->pktsz - x);
- } else
- memcpy(p2, p1, isodesc->pktsz);
- isodesc->rd = (isodesc->rd + isodesc->pktsz) % isodesc->buflen;
- p2 += isodesc->pktsz;
- if (((unsigned long)p2 ^ ((unsigned long)p2 + isodesc->pktsz - 1)) & (~(PAGE_SIZE - 1)))
- p2 = (void *)(((unsigned long)p2 + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)));
- }
- usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
- diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
- isodesc->schedcnt++;
+ unsigned char *tbuf = NULL;
+ unsigned int pipe;
+ unsigned long len2 = 0;
+ int ret = 0;
+
+ if (length > PAGE_SIZE)
+ return -EINVAL;
+ if ((ep & ~0x80) >= 16)
+ return -EINVAL;
+ if (ep & 0x80) {
+ pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f);
+ if (length > 0 && !access_ok(VERIFY_WRITE, data, length))
+ return -EFAULT;
+ } else
+ pipe = usb_sndbulkpipe(usbdev, ep & 0x7f);
+ if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80)))
+ return -EINVAL;
+ if (length > 0) {
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (!(ep & 0x80)) {
+ if (copy_from_user(tbuf, data, length)) {
+ free_page((unsigned long)tbuf);
+ return -EFAULT;
+ }
+ }
+ }
+ ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+ if (ret) {
+ if (length > 0)
+ free_page((unsigned long)tbuf);
+ printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n",
+ ep, length, ret);
+ return -ENXIO;
}
+ if (len2 > length)
+ len2 = length;
+ ret = len2;
+ if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2))
+ ret = -EFAULT;
+ if (length > 0)
+ free_page((unsigned long)tbuf);
+ return ret;
}
-static int ezusb_isorcv_irq(int status, void *__buffer, int __len, void *dev_id)
+static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep)
{
- struct isodesc *isodesc = (struct isodesc *)dev_id;
- unsigned int len, len2;
- unsigned char *p1;
-
- spin_lock(&isodesc->lock);
- usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
- len = usb_compress_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
- printk(KERN_DEBUG "ezusb_isorcv_irq: %u bytes recvd\n", len);
- p1 = isodesc->hcbuf[isodesc->unschedcnt & 1];
- while (len > 0) {
- len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
- if (!len2)
- break;
- if (isodesc->wr + len2 > isodesc->buflen)
- len2 = isodesc->buflen - isodesc->wr;
- if (len2 > len)
- len2 = len;
- memcpy(isodesc->buf + isodesc->wr, p1, len2);
- isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
- p1 += len2;
- len -= len2;
- }
- isodesc->unschedcnt++;
- iso_schedrcv(isodesc);
- spin_unlock(&isodesc->lock);
- return 1;
+ if ((ep & ~0x80) >= 16)
+ return -EINVAL;
+ usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0);
+ return 0;
+}
+
+static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting)
+{
+ if (usb_set_interface(usbdev, interface, altsetting))
+ return -EINVAL;
+ return 0;
}
-static int ezusb_isosnd_irq(int status, void *__buffer, int len, void *dev_id)
+static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config)
{
- struct isodesc *isodesc = (struct isodesc *)dev_id;
-
- spin_lock(&isodesc->lock);
- usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
- isodesc->unschedcnt++;
- iso_schedsnd(isodesc);
- spin_unlock(&isodesc->lock);
- return 1;
+ if (usb_set_configuration(usbdev, config))
+ return -EINVAL;
+ return 0;
}
-static struct isodesc *findiso(struct ezusb *ez, unsigned int ep)
+static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
{
- struct list_head *head = &ez->iso;
- struct list_head *tmp = head->next;
- struct isodesc *id;
+ struct async *as = NULL;
+ unsigned int pipe;
+
+ if (ab->len > PAGE_SIZE)
+ return -EINVAL;
+ if ((ab->ep & ~0x80) >= 16)
+ return -EINVAL;
+ if (ab->ep & 0x80) {
+ pipe = usb_rcvbulkpipe(ez->usbdev, ab->ep & 0x7f);
+ if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len))
+ return -EFAULT;
+ } else
+ pipe = usb_sndbulkpipe(ez->usbdev, ab->ep & 0x7f);
+ if (!usb_maxpacket(ez->usbdev, pipe, !(ab->ep & 0x80)))
+ return -EINVAL;
+ if (!(as = kmalloc(sizeof(struct async), GFP_KERNEL)))
+ return -ENOMEM;
+ INIT_LIST_HEAD(&as->asynclist);
+ as->ez = ez;
+ as->userdata = ab->data;
+ as->numframes = 0;
+ as->data = 0;
+ as->dataorder = 0;
+ as->datalen = ab->len;
+ as->completed.context = ab->context;
+ if (ab->len > 0) {
+ as->dataorder = 1;
+ if (!(as->data = (unsigned char *)__get_free_page(GFP_KERNEL))) {
+ kfree(as);
+ return -ENOMEM;
+ }
+ if (!(ab->ep & 0x80)) {
+ if (copy_from_user(as->data, ab->data, ab->len))
+ goto err_fault;
+ as->datalen = 0; /* no need to copy back at completion */
+ }
+ }
+ async_newpending(as);
+ if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+ async_removelist(as);
+ goto err_inval;
+ }
+ return 0;
- while (tmp != head) {
- id = list_entry(tmp, struct isodesc, isolist);
- if (id->ep == ep)
- return id;
- tmp = tmp->next;
+ err_fault:
+ if (as) {
+ if (as->data)
+ free_page((unsigned long)as->data);
+ kfree(as);
}
- return NULL;
+ return -EFAULT;
+
+ err_inval:
+ if (as) {
+ if (as->data)
+ free_page((unsigned long)as->data);
+ kfree(as);
+ }
+ return -EINVAL;
+}
+
+static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd)
+{
+ struct async *as;
+ unsigned int maxpkt, pipe;
+ unsigned int dsize, order, assize, j;
+ int i;
+
+ if ((ai->ep & ~0x80) >= 16 || ai->framecnt < 1 || ai->framecnt > 128)
+ return -EINVAL;
+ if (ai->ep & 0x80)
+ pipe = usb_rcvisocpipe(ez->usbdev, ai->ep & 0x7f);
+ else
+ pipe = usb_sndisocpipe(ez->usbdev, ai->ep & 0x7f);
+ if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
+ return -EINVAL;
+ dsize = maxpkt * ai->framecnt;
+ if (dsize > 65536)
+ return -EINVAL;
+ order = ld2(dsize >> PAGE_SHIFT);
+ if (dsize > (PAGE_SIZE << order))
+ order++;
+ if (ai->ep & 0x80)
+ if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize))
+ return -EFAULT;
+ assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
+ if (!(as = kmalloc(assize, GFP_KERNEL)))
+ return -ENOMEM;
+ memset(as, 0, assize);
+ INIT_LIST_HEAD(&as->asynclist);
+ as->ez = ez;
+ as->userdata = ai->data;
+ as->numframes = ai->framecnt;
+ as->data = 0;
+ as->dataorder = order;
+ as->datalen = dsize;
+ as->completed.context = ai->context;
+ as->desc.iso = NULL;
+ if (dsize > 0) {
+ if (!(as->data = (unsigned char *)__get_free_pages(GFP_KERNEL, order))) {
+ kfree(as);
+ return -ENOMEM;
+ }
+ if (!(ai->ep & 0x80)) {
+ if (copy_from_user(as->data, ai->data, dsize))
+ goto err_fault;
+ as->datalen = 0; /* no need to copy back at completion */
+ }
+ }
+ if ((i = usb_init_isoc(ez->usbdev, pipe, ai->framecnt, as, &as->desc.iso))) {
+ printk(KERN_DEBUG "ezusb: usb_init_isoc error %d\n", i);
+ goto err_inval;
+ }
+ as->desc.iso->start_type = START_ASAP;
+ as->desc.iso->callback_frames = 0;
+ as->desc.iso->callback_fn = async_completed;
+ as->desc.iso->data = as->data;
+ as->desc.iso->buf_size = dsize;
+ for (j = 0; j < ai->framecnt; j++) {
+ if (get_user(i, (int *)(cmd + j * sizeof(struct ezusb_isoframestat)))) {
+ usb_free_isoc(as->desc.iso);
+ kfree(as);
+ return -EFAULT;
+ }
+ if (i < 0)
+ i = 0;
+ as->desc.iso->frames[j].frame_length = i;
+ }
+ async_newpending(as);
+ if ((i = usb_run_isoc(as->desc.iso, NULL))) {
+ printk(KERN_DEBUG "ezusb: usb_run_isoc error %d\n", i);
+ async_removelist(as);
+ goto err_inval;
+ }
+ return 0;
+
+ err_fault:
+ if (as) {
+ if (as->desc.iso)
+ usb_free_isoc(as->desc.iso);
+ if (as->data)
+ free_page((unsigned long)as->data);
+ kfree(as);
+ }
+ return -EFAULT;
+
+ err_inval:
+ if (as) {
+ if (as->desc.iso)
+ usb_free_isoc(as->desc.iso);
+ if (as->data)
+ free_page((unsigned long)as->data);
+ kfree(as);
+ }
+ return -EINVAL;
+}
+
+static int ezusb_terminateasync(struct ezusb *ez, void *context)
+{
+ struct async *as;
+ int ret = 0;
+
+ while ((as = async_getpending(ez, context))) {
+ kill_async(as);
+ ret++;
+ }
+ return ret;
+}
+
+static int ezusb_asynccompl(struct async *as, void *arg)
+{
+ if (as->datalen > 0) {
+ if (copy_to_user(as->userdata, as->data, as->datalen)) {
+ remove_async(as);
+ return -EFAULT;
+ }
+ }
+ if (copy_to_user(arg, &as->completed,
+ sizeof(struct ezusb_asynccompleted) +
+ as->numframes * sizeof(struct ezusb_isoframestat))) {
+ remove_async(as);
+ return -EFAULT;
+ }
+ remove_async(as);
+ return 0;
}
static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct ezusb *ez = (struct ezusb *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ struct usb_proc_ctrltransfer pctrl;
+ struct usb_proc_bulktransfer pbulk;
+ struct usb_proc_setinterface psetintf;
struct ezusb_ctrltransfer ctrl;
struct ezusb_bulktransfer bulk;
struct ezusb_setinterface setintf;
- unsigned int len1, ep, pipe, cnt;
- unsigned long len2;
- unsigned char tbuf[1024];
- int i;
- struct ezusb_isotransfer isot;
- struct ezusb_isodata isod;
- struct isodesc *isodesc;
- usb_device_irq isocompl;
- unsigned long flags;
- unsigned char *p1, *p2;
+ struct ezusb_asyncbulk abulk;
+ struct ezusb_asynciso aiso;
+ struct async *as;
+ void *context;
+ unsigned int ep, cfg;
+ int i, ret = 0;
+ down(&ez->mutex);
+ if (!ez->usbdev) {
+ up(&ez->mutex);
+ return -EIO;
+ }
switch (cmd) {
+ case USB_PROC_CONTROL:
+ if (copy_from_user(&pctrl, (void *)arg, sizeof(pctrl))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request,
+ pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+ break;
+
+ case USB_PROC_BULK:
+ if (copy_from_user(&pbulk, (void *)arg, sizeof(pbulk))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+ break;
+
+ case USB_PROC_RESETEP:
+ if (get_user(ep, (unsigned int *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_resetep(ez->usbdev, ep);
+ break;
+
+ case USB_PROC_SETINTERFACE:
+ if (copy_from_user(&psetintf, (void *)arg, sizeof(psetintf))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_setinterface(ez->usbdev, psetintf.interface, psetintf.altsetting);
+ break;
+
+ case USB_PROC_SETCONFIGURATION:
+ if (get_user(cfg, (unsigned int *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_setconfiguration(ez->usbdev, cfg);
+ break;
+
case EZUSB_CONTROL:
- copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
- if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024)
- return -EINVAL;
- if (ctrl.requesttype & 0x80) {
- if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen))
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0),
- (devrequest *)&ctrl, tbuf, ctrl.dlen);
- up(&ez->mutex);
- if (!i && ctrl.dlen) {
- copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
- }
- } else {
- if (ctrl.dlen) {
- copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
- }
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0),
- (devrequest *)&ctrl, tbuf, ctrl.dlen);
- up(&ez->mutex);
+ if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) {
+ ret = -EFAULT;
+ break;
}
- if (i) {
- printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n",
- ctrl.requesttype, ctrl.request, ctrl.length, i);
- return -ENXIO;
+ if (ctrl.dlen != ctrl.length) {
+ ret = -EINVAL;
+ break;
}
- return 0;
+ ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request,
+ ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+ break;
case EZUSB_BULK:
- copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
- if (bulk.ep & 0x80)
- pipe = usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f);
- if (!usb_maxpacket(ez->usbdev, pipe, !(bulk.ep & 0x80)))
- return -EINVAL;
- len1 = bulk.len;
- if (len1 > sizeof(tbuf))
- len1 = sizeof(tbuf);
- if (bulk.ep & 0x80) {
- if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1))
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
- up(&ez->mutex);
- if (!i && len2) {
- copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
- }
- } else {
- if (len1) {
- copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
- }
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
- up(&ez->mutex);
- }
- if (i) {
- printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n",
- bulk.ep, bulk.len, i);
- return -ENXIO;
+ if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) {
+ ret = -EFAULT;
+ break;
}
- return len2;
+ ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+ break;
case EZUSB_RESETEP:
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0);
- return 0;
-
+ if (get_user(ep, (unsigned int *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_resetep(ez->usbdev, ep);
+ break;
+
case EZUSB_SETINTERFACE:
- copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT);
- if (usb_set_interface(ez->usbdev, setintf.interface, setintf.altsetting))
- return -EINVAL;
- return 0;
-
- case EZUSB_STARTISO:
- copy_from_user_ret(&isot, (void *)arg, sizeof(isot), -EFAULT);
- len1 = isot.framesperint * isot.pktsz;
- if (len1 > PAGE_SIZE) {
- len1 = PAGE_SIZE / isot.pktsz;
- len1 = PAGE_SIZE * ((isot.framesperint + len1 - 1) / len1);
- }
- len2 = (isot.pktsz * 1000 + PAGE_SIZE - 1) & (PAGE_SIZE-1);
- if (len2 > 32*PAGE_SIZE)
- len2 = PAGE_SIZE;
- if ((isot.ep & ~0x80) >= 16 || isot.pktsz < 1 || isot.pktsz > 1023 ||
- isot.framesperint < 1 || isot.framesperint > 1000 ||
- len1 > 4*PAGE_SIZE)
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
+ if (copy_from_user(&setintf, (void *)arg, sizeof(setintf))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_setinterface(ez->usbdev, setintf.interface, setintf.altsetting);
+ break;
+
+ case EZUSB_SETCONFIGURATION:
+ if (get_user(cfg, (unsigned int *)arg)) {
+ ret = -EFAULT;
+ break;
}
- if (findiso(ez, isod.ep)) {
+ ret = ezusb_setconfiguration(ez->usbdev, cfg);
+ break;
+
+ case EZUSB_ASYNCCOMPLETED:
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&ez->wait, &wait);
+ for (;;) {
+ if (!ez->usbdev)
+ break;
+ if ((as = async_getcompleted(ez)))
+ break;
+ if (signal_pending(current))
+ break;
up(&ez->mutex);
- return -EBUSY;
+ schedule();
+ down(&ez->mutex);
}
- if (isot.ep & 0x80) {
- pipe = usb_rcvisocpipe(ez->usbdev, isot.ep & 15);
- isocompl = ezusb_isorcv_irq;
- } else {
- pipe = usb_sndisocpipe(ez->usbdev, isot.ep & 15);
- isocompl = ezusb_isosnd_irq;
+ remove_wait_queue(&ez->wait, &wait);
+ current->state = TASK_RUNNING;
+ if (as) {
+ ret = ezusb_asynccompl(as, (void *)arg);
+ break;
}
- if (!(isodesc = kmalloc(sizeof(struct isodesc), GFP_KERNEL))) {
- up(&ez->mutex);
- return -ENOMEM;
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
}
- memset(isodesc, 0, sizeof(struct isodesc));
- INIT_LIST_HEAD(&isodesc->isolist);
- spin_lock_init(&isodesc->lock);
- isodesc->usbdev = ez->usbdev;
- isodesc->ep = isot.ep;
- isodesc->pktsz = isot.pktsz;
- isodesc->framesperint = isot.framesperint;
- isodesc->buflen = len2;
- if (!(isodesc->hcbuf[0] = kmalloc(len1, GFP_KERNEL)) ||
- !(isodesc->hcbuf[1] = kmalloc(len1, GFP_KERNEL)))
- goto startisomemerr;
- if (!(isodesc->hcisodesc[0] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[0],
- len1, isodesc->pktsz, isocompl, isodesc)) ||
- !(isodesc->hcisodesc[1] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[1],
- len1, isodesc->pktsz, isocompl, isodesc)))
- goto startisomemerr;
- if (!(isodesc->buf = vmalloc(isodesc->buflen)))
- goto startisomemerr;
- up(&ez->mutex);
- return 0;
-
- startisomemerr:
- if (isodesc->hcisodesc[0])
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
- if (isodesc->hcisodesc[1])
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
- if (isodesc->hcbuf[0])
- kfree(isodesc->hcbuf[0]);
- if (isodesc->hcbuf[1])
- kfree(isodesc->hcbuf[1]);
- if (isodesc->buf)
- vfree(isodesc->buf);
- up(&ez->mutex);
- return -ENOMEM;
+ ret = -EIO;
+ break;
- case EZUSB_STOPISO:
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
+ case EZUSB_ASYNCCOMPLETEDNB:
+ if ((as = async_getcompleted(ez))) {
+ ret = ezusb_asynccompl(as, (void *)arg);
+ break;
}
- if (!(isodesc = findiso(ez, ep))) {
- up(&ez->mutex);
- return -EINVAL;
- }
- list_del(&isodesc->isolist);
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
- kfree(isodesc->hcbuf[0]);
- kfree(isodesc->hcbuf[1]);
- vfree(isodesc->buf);
- up(&ez->mutex);
- return 0;
-
- case EZUSB_ISODATA:
- copy_from_user_ret(&isod, (void *)arg, sizeof(isod), -EFAULT);
- if ((isod.ep & ~0x80) >= 16)
- return -EINVAL;
- if (isod.size)
- if (!access_ok((isod.ep & 0x80) ? VERIFY_WRITE : VERIFY_READ, isod.data, isod.size))
- return -EFAULT;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
+ ret = -EAGAIN;
+ break;
+
+ case EZUSB_REQUESTBULK:
+ if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) {
+ ret = -EFAULT;
+ break;
}
- if (!(isodesc = findiso(ez, ep))) {
- up(&ez->mutex);
- return -EINVAL;
- }
- if (isod.ep & 0x80) {
- cnt = 0;
- p1 = isod.data;
- while (cnt < isod.size) {
- spin_lock_irqsave(&isodesc->lock, flags);
- p2 = isodesc->buf + isodesc->rd;
- len2 = (isodesc->rd >= isodesc->wr) ? isodesc->buflen : isodesc->wr;
- len2 -= isodesc->rd;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- if (len2 <= 0)
- break;
- if (len2 >= isod.size - cnt)
- len2 = isod.size - cnt;
- if (__copy_to_user(p1, p2, len2)) {
- up(&ez->mutex);
- return -EFAULT;
- }
- p1 += len2;
- cnt += len2;
- spin_lock_irqsave(&isodesc->lock, flags);
- isodesc->rd = (isodesc->rd + len2) % isodesc->buflen;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- }
- isod.size = cnt;
- iso_schedrcv(isodesc);
- } else {
- cnt = 0;
- p1 = isod.data;
- while (cnt < isod.size) {
- spin_lock_irqsave(&isodesc->lock, flags);
- p2 = isodesc->buf + isodesc->wr;
- len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
- if (isodesc->wr + len2 > isodesc->buflen)
- len2 = isodesc->buflen - isodesc->wr;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- if (len2 <= 0)
- break;
- if (len2 >= isod.size - cnt)
- len2 = isod.size - cnt;
- if (__copy_from_user(p2, p1, len2)) {
- up(&ez->mutex);
- return -EFAULT;
- }
- p1 += len2;
- cnt += len2;
- spin_lock_irqsave(&isodesc->lock, flags);
- isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- }
- isod.size = cnt;
- iso_schedsnd(isodesc);
+ ret = ezusb_requestbulk(ez, &abulk);
+ break;
+
+ case EZUSB_REQUESTISO:
+ if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) {
+ ret = -EFAULT;
+ break;
}
- spin_lock_irqsave(&isodesc->lock, flags);
- isod.bufqueued = (isodesc->buflen + isodesc->wr - isodesc->rd) % isodesc->buflen;
- isod.buffree = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- up(&ez->mutex);
- copy_to_user_ret((void *)arg, &isod, sizeof(isod), -EFAULT);
- return 0;
-
- case EZUSB_PAUSEISO:
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- if (!(isodesc = findiso(ez, ep)))
- return -EINVAL;
- spin_lock_irqsave(&isodesc->lock, flags);
- isodesc->flags &= ~ISOFLG_ACTIVE;
- spin_unlock_irqrestore(&isodesc->lock, flags);
- return 0;
-
- case EZUSB_RESUMEISO:
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
+ ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso));
+ break;
+
+ case EZUSB_TERMINATEASYNC:
+ if (get_user(context, (void **)arg)) {
+ ret = -EFAULT;
+ break;
}
- if (!(isodesc = findiso(ez, ep))) {
- up(&ez->mutex);
- return -EINVAL;
- }
- spin_lock_irqsave(&isodesc->lock, flags);
- isodesc->flags |= ISOFLG_ACTIVE;
- if (isot.ep & 0x80)
- iso_schedrcv(isodesc);
- else
- iso_schedsnd(isodesc);
- spin_unlock_irqrestore(&isodesc->lock, flags);
- up(&ez->mutex);
- return 0;
+ ret = ezusb_terminateasync(ez, context);
+ break;
+
+ case EZUSB_GETFRAMENUMBER:
+ i = usb_get_current_frame_number(ez->usbdev);
+ ret = put_user(i, (int *)arg);
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
}
- return -ENOIOCTLCMD;
+ up(&ez->mutex);
+ return ret;
}
static struct file_operations ezusb_fops = {
static void ezusb_disconnect(struct usb_device *usbdev)
{
struct ezusb *ez = (struct ezusb *)usbdev->private;
- struct isodesc *isodesc;
down(&ez->mutex);
- while (!list_empty(&ez->iso)) {
- isodesc = list_entry(ez->iso.next, struct isodesc, isolist);
- list_del(ez->iso.next);
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
- usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
- kfree(isodesc->hcbuf[0]);
- kfree(isodesc->hcbuf[1]);
- vfree(isodesc->buf);
- }
+ destroy_all_async(ez);
ez->usbdev = NULL;
up(&ez->mutex);
+ wake_up(&ez->wait);
usbdev->private = NULL;
MOD_DEC_USE_COUNT;
}
for (u = 0; u < NREZUSB; u++) {
init_MUTEX(&ezusb[u].mutex);
ezusb[u].usbdev = NULL;
- INIT_LIST_HEAD(&ezusb[u].iso);
+ INIT_LIST_HEAD(&ezusb[u].async_pending);
+ INIT_LIST_HEAD(&ezusb[u].async_completed);
+ init_waitqueue_head(&ezusb[u].wait);
+ spin_lock_init(&ezusb[u].lock);
}
/* register misc device */
if (misc_register(&ezusb_misc)) {
--- /dev/null
+/* -*- linux-c -*- */
+
+/*
+ * Driver for USB HP Scanners
+ *
+ * David E. Nelson (dnelson@jump.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the 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.
+ *
+ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ * 0.1 8/31/1999
+ *
+ * Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ * support short packes during bulk xfer mode. Some testing was
+ * done with ohci-hcd but the performace was low. Very limited
+ * testing was performed with uhci but I was unable to get it to
+ * work. Initial relase to the linux-usb development effort.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+/* stall/wait timeout for scanner */
+#define NAK_TIMEOUT (HZ)
+
+/* For some reason, an IBUF_SIZE of 8192 causes REALLY big problems
+ * with linux-2.3.15. Anything more than 4k seems to not have an
+ * effect on increasing performance. Anything smaller than 4k hurts
+ * it. */
+#define IBUF_SIZE 4096
+
+/* This is a scanner, so not much data is sent to it. The largest
+ * stuff may be some kind of maps and stuff but that's kinda rare. */
+#define OBUF_SIZE 128
+
+#define USB_SCANNER_MAJOR 16
+
+struct hpscan_usb_data {
+ struct usb_device *hpscan_dev; /* init: probe_scanner */
+ __u8 isopen; /* nz if open */
+
+ __u8 present; /* Device is present on the bus */
+ char *obuf; /* transfer buffers */
+ char *ibuf;
+ wait_queue_head_t wait_q; /* for timeouts */
+};
+
+static struct hpscan_usb_data hpscan;
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ if (hps->isopen) {
+ return -EBUSY;
+ }
+ hps->isopen = 1;
+
+ init_waitqueue_head(&hps->wait_q);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ hps->isopen = 0;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ unsigned long copy_size;
+ unsigned long bytes_written = 0;
+ unsigned long partial;
+
+ int result = 0;
+ int maxretry;
+
+ do {
+ unsigned long thistime;
+ char *obuf = hps->obuf;
+
+ thistime = copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count;
+ if (copy_from_user(hps->obuf, buffer, copy_size))
+ return -EFAULT;
+ maxretry = 5;
+ while (thistime) {
+ if (!hps->hpscan_dev)
+ return -ENODEV;
+ if (signal_pending(current)) {
+ return bytes_written ? bytes_written : -EINTR;
+ }
+
+ result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial);
+
+ //printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
+
+ if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */
+ if(!maxretry--) {
+ return -ETIME;
+ }
+ interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+ continue;
+ } else if (!result & partial) {
+ obuf += partial;
+ thistime -= partial;
+ } else
+ break;
+ };
+ if (result) {
+ printk("Write Whoops - %x\n", result);
+ return -EIO;
+ }
+ bytes_written += copy_size;
+ count -= copy_size;
+ buffer += copy_size;
+ } while ( count > 0 );
+
+ return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ ssize_t read_count;
+
+ unsigned long partial;
+
+ int this_read;
+ int result;
+
+/* Wait for the scanner to get it's act together. This may involve
+ * resetting the head, warming up the lamp, etc. maxretry is number
+ * of seconds. */
+ int maxretry = 30;
+
+ char *ibuf = hps->ibuf;
+
+ read_count = 0;
+
+ while (count) {
+ if (signal_pending(current)) {
+ return read_count ? read_count : -EINTR;
+ }
+ if (!hps->hpscan_dev)
+ return -ENODEV;
+ this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
+
+ result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial);
+
+ printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
+
+ if (partial) {
+ count = this_read = partial;
+ } else if (result == USB_ST_TIMEOUT || result == 15) {
+ if(!maxretry--) {
+ printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
+ return -ETIME;
+ }
+ interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+ continue;
+ } else if (result != USB_ST_DATAUNDERRUN) {
+ printk("Read Whoops - result:%u partial:%lu this_read:%u\n", result, partial, this_read);
+ return -EIO;
+ } else {
+ return (0);
+ }
+
+ if (this_read) {
+ if (copy_to_user(buffer, ibuf, this_read))
+ return -EFAULT;
+ count -= this_read;
+ read_count += this_read;
+ buffer += this_read;
+ }
+ }
+ return read_count;
+}
+
+static int
+probe_scanner(struct usb_device *dev)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ /*
+ * Don't bother using an HP 4200C since it does NOT understand
+ * SCL and HP isn't going to be releasing the specs any time
+ * soon. */
+ if (dev->descriptor.idVendor != 0x3f0 ) {
+ printk(KERN_INFO "Scanner is not an HP Scanner.\n");
+ return -1;
+ }
+
+ if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */
+ dev->descriptor.idProduct != 0x202 && /* HP 5100C */
+ dev->descriptor.idProduct != 0x601) { /* HP 6300C */
+ printk(KERN_INFO "Scanner model not supported/tested.\n");
+ return -1;
+ }
+
+ printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum);
+
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+ printk(KERN_DEBUG "Failed to set configuration\n");
+ return -1;
+ }
+
+ hps->present = 1;
+ hps->hpscan_dev = dev;
+
+ if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+
+ if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ if (hps->isopen) {
+ /* better let it finish - the release will do whats needed */
+ hps->hpscan_dev = NULL;
+ return;
+ }
+ kfree(hps->ibuf);
+ kfree(hps->obuf);
+
+ dev->private = NULL; /* just in case */
+ hps->present = 0;
+}
+
+static struct
+usb_driver scanner_driver = {
+ "usbscanner",
+ probe_scanner,
+ disconnect_scanner,
+ { NULL, NULL }
+};
+
+static struct
+file_operations usb_scanner_fops = {
+ NULL, /* seek */
+ read_scanner,
+ write_scanner,
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ open_scanner,
+ NULL, /* flush */
+ close_scanner,
+ NULL,
+ NULL, /* fasync */
+};
+
+int
+usb_hp_scanner_init(void)
+{
+ int result;
+
+ if ((result = register_chrdev(USB_SCANNER_MAJOR, "usbscanner", &usb_scanner_fops)) < 0) {
+ printk(KERN_WARNING "hp_scanner: Cannot register device\n");
+ return result;
+ }
+ usb_register(&scanner_driver);
+ printk(KERN_DEBUG "USB Scanner support registered.\n");
+ return 0;
+}
+
+
+void
+usb_hp_scanner_cleanup(void)
+{
+ struct hpscan_usb_data *hps = &hpscan;
+
+ hps->present = 0;
+ usb_deregister(&scanner_driver);
+ unregister_chrdev(USB_SCANNER_MAJOR, "usbscanner");
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+ return usb_hp_scanner_init();
+}
+
+void
+cleanup_module(void)
+{
+ usb_hp_scanner_cleanup();
+}
+#endif
+
int usb_printer_init(void);
void usb_hub_cleanup(void);
void usb_mouse_cleanup(void);
+int usb_scsi_init(void);
int proc_usb_init (void);
void proc_usb_cleanup (void);
*
* Brad Keryan 4/3/1999
*
+ * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse
+ * disconnect and suspend/resume. Added module parameter "force=1"
+ * to allow opening of the mouse driver before mouse has been plugged
+ * in (enables consistent XF86Config settings). Fixed module use count.
+ * Documented missing blocking/non-blocking read handling (not fixed).
+ *
* version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
* correctly. Events are added together, not queued, to keep the rodent sober.
*
int present; /* this mouse is plugged in */
int active; /* someone is has this mouse's device open */
int ready; /* the mouse has changed state since the last read */
+ int suspended; /* mouse disconnected */
wait_queue_head_t wait; /* for polling */
struct fasync_struct *fasync;
/* later, add a list here to support multiple mice */
spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
+static int force=0; /* allow the USB mouse to be opened even if not there (yet) */
+MODULE_PARM(force,"i");
+
static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
{
signed char *data = __buffer;
/* finding the mouse is easy when there's only one */
struct mouse_state *mouse = &static_mouse_state;
+ if (state)
+ printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d, dp %p\n",
+ __FILE__, __LINE__, state, __buffer, len, dev_id);
+
+ /*
+ * USB_ST_NOERROR is the normal case.
+ * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume
+ * USB_ST_INTERNALERROR occurs if system suspended then mouse removed
+ * followed by resume. On UHCI could then occur every second
+ * In both cases, suspend the mouse
+ * On other states, ignore
+ */
+ switch (state) {
+ case USB_ST_REMOVED:
+ case USB_ST_INTERNALERROR:
+ printk(KERN_DEBUG "%s(%d): Suspending\n",
+ __FILE__, __LINE__);
+ mouse->suspended = 1;
+ return 0; /* disable */
+ case USB_ST_NOERROR: break;
+ default: return 1; /* ignore */
+ }
+
/* if a mouse moves with no one listening, do we care? no */
if(!mouse->active)
return 1;
fasync_mouse(-1, file, 0);
+ printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__);
MOD_DEC_USE_COUNT;
if (--mouse->active == 0) {
+ mouse->suspended = 0;
/* stop polling the mouse while its not in use */
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
{
struct mouse_state *mouse = &static_mouse_state;
+ printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__);
+ /*
+ * First open may fail since mouse_probe() may get called after this
+ * if module load is in response to the open
+ * mouse_probe() sets mouse->present. This open can be delayed by
+ * specifying force=1 in module load
+ * This helps if you want to insert the USB mouse after starting X
+ */
if (!mouse->present)
- return -EINVAL;
+ {
+ if (force) /* always load the driver even if no mouse (yet) */
+ {
+ printk(KERN_DEBUG "%s(%d): forced open\n",
+ __FILE__, __LINE__);
+ mouse->suspended = 1;
+ }
+ else
+ return -EINVAL;
+ }
+
+ /* prevent the driver from being unloaded while its in use */
+ printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__);
+ /* Increment use count even if already active */
+ MOD_INC_USE_COUNT;
+
if (mouse->active++)
return 0;
/* flush state */
mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
- /* prevent the driver from being unloaded while its in use */
- MOD_INC_USE_COUNT;
+ if (!mouse->present) /* only get here if force == 1 */
+ return 0;
/* start the usb controller's polling of the mouse */
mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
static int state = 0;
struct mouse_state *mouse = &static_mouse_state;
+ /*
+ * FIXME - Other mouse drivers handle blocking and nonblocking reads
+ * differently here...
+ */
if (count) {
mouse->ready = 0;
switch (state) {
mouse->bInterval = endpoint->bInterval;
mouse->present = 1;
+
+ /* This appears to let USB mouse survive disconnection and */
+ /* APM suspend/resume */
+ if (mouse->suspended)
+ {
+ printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
+ /* restart the usb controller's polling of the mouse */
+ mouse->irq_handle = usb_request_irq(mouse->dev,
+ usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+ mouse_irq, mouse->bInterval, NULL);
+ mouse->suspended = 0;
+ }
+
return 0;
}
if (mouse->present) {
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
- mouse->irq_handle = NULL;
}
mouse->irq_handle = NULL;
{
struct mouse_state *mouse = &static_mouse_state;
- mouse->present = mouse->active = 0;
+ mouse->present = mouse->active = mouse->suspended = 0;
mouse->irq_handle = NULL;
init_waitqueue_head(&mouse->wait);
mouse->fasync = NULL;
return ohci_generic_trans(usb_dev, pipe,
TOGGLE_AUTO,
- 1 /* round */, 1 /* autofree */,
+ 0 /* round */, 1 /* autofree */,
dev_id, handler, data, len,
HCD_ED_BULK,
NULL /* no setup_td */, NULL /* no status_td */ );
#endif
/* only count TDs that were completed successfully */
- if (stats == USB_ST_NOERROR)
+ if (stats == USB_ST_NOERROR || stats == USB_ST_DATAUNDERRUN) /*DEN*/
req->_bytes_done += len;
#ifdef OHCI_DEBUG
/* 4/4/1999 added data toggle for interrupt pipes -keryan */
/* 5/16/1999 added global toggles for bulk and control */
/* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */
+/*
+ * 1999-09-02: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Added explicit frame list manipulation routines
+ * for inserting/removing iso td's to/from the frame list.
+ * START_ABSOLUTE fixes
+ */
#include <linux/config.h>
#include <linux/module.h>
spin_unlock_irqrestore(&irqlist_lock, flags);
}
+/*
+ * frame list manipulation. Used for Isochronous transfers.
+ * the list of (iso) TD's enqueued in a frame list entry
+ * is basically a doubly linked list with link being
+ * the forward pointer and backptr the backward ptr.
+ * the frame list entry itself doesn't have a back ptr
+ * (therefore the list is not circular), and the forward pointer
+ * stops at link entries having the UHCI_PTR_TERM or the UHCI_PTR_QH
+ * bit set. Maybe it could be extended to handle the QH's also,
+ * but it doesn't seem necessary right now.
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh
+ */
+
+static spinlock_t framelist_lock = SPIN_LOCK_UNLOCKED;
+
+static void uhci_add_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+ unsigned long flags;
+ struct uhci_td *nexttd;
+
+ framenum %= UHCI_NUMFRAMES;
+ spin_lock_irqsave(&framelist_lock, flags);
+ td->backptr = &uhci->fl->frame[framenum];
+ td->link = uhci->fl->frame[framenum];
+ if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+ nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+ nexttd->backptr = &td->link;
+ }
+ wmb();
+ uhci->fl->frame[framenum] = virt_to_bus(td);
+ spin_unlock_irqrestore(&framelist_lock, flags);
+}
+
+static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td)
+{
+ unsigned long flags;
+ struct uhci_td *nexttd;
+
+ if (!td->backptr)
+ return;
+ spin_lock_irqsave(&framelist_lock, flags);
+ *(td->backptr) = td->link;
+ if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+ nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+ nexttd->backptr = td->backptr;
+ }
+ spin_unlock_irqrestore(&framelist_lock, flags);
+ td->backptr = NULL;
+ /*
+ * attention: td->link might still be in use by the
+ * hardware if the td is still active and the hardware
+ * was processing it. So td->link should be preserved
+ * until the frame number changes. Don't know what to do...
+ * udelay(1000) doesn't sound nice, and schedule()
+ * can't be used as this is called from within interrupt context.
+ */
+ /* for now warn if there's a possible problem */
+ if (td->status & TD_CTRL_ACTIVE) {
+ unsigned frn = inw(uhci->io_addr + USBFRNUM);
+ __u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES];
+ if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+ struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15);
+ for (;;) {
+ if (tdl == td) {
+ printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n");
+ break;
+ }
+ if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH))
+ break;
+ tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15);
+ }
+ }
+ }
+}
+
+
/*
* This function removes and disallocates all structures set up for a transfer.
* It takes the qh out of the skeleton, removes the tq and the td's.
struct usb_isoc_desc **isocdesc)
{
struct usb_isoc_desc *id;
+ int i;
#ifdef BANDWIDTH_ALLOCATION
/* TBD: add bandwidth allocation/checking/management HERE. */
*isocdesc = NULL;
/* Check some parameters. */
- if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) {
+ if ((frame_count <= 0) || (frame_count > UHCI_NUMFRAMES)) {
#ifdef CONFIG_USB_DEBUG_ISOC
printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n",
frame_count);
if (!id)
return -ENOMEM;
+ memset (id, 0, sizeof (*id) +
+ (sizeof (struct isoc_frame_desc) * frame_count));
+
id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL);
if (!id->td) {
kfree (id);
return -ENOMEM;
}
- memset (id, 0, sizeof (*id) +
- (sizeof (struct isoc_frame_desc) * frame_count));
memset (id->td, 0, sizeof (struct uhci_td) * frame_count);
+ for (i = 0; i < frame_count; i++)
+ INIT_LIST_HEAD(&((struct uhci_td *)(id->td))[i].irq_list);
+
id->frame_count = frame_count;
id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe));
/* TBD: or make this a parameter to allow for frame_size
cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev);
/* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */
- if (!pr_isocdesc)
+ if (!pr_isocdesc) {
if (isocdesc->start_type == START_RELATIVE) {
if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > CAN_SCHEDULE_FRAMES)) {
#ifdef CONFIG_USB_DEBUG_ISOC
}
} /* end START_RELATIVE */
else
- if (isocdesc->start_type == START_ABSOLUTE) {
- if (isocdesc->start_frame > cur_frame) {
- if ((isocdesc->start_frame - cur_frame) > CAN_SCHEDULE_FRAMES) {
+ if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
+ ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame);
+ if (ix < START_FRAME_FUDGE || /* too small */
+ ix > CAN_SCHEDULE_FRAMES) { /* too large */
#ifdef CONFIG_USB_DEBUG_ISOC
printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
isocdesc->start_frame);
}
}
} /* end START_ABSOLUTE */
+ }
/*
* Set the start/end frame numbers.
} else if (isocdesc->start_type == START_ASAP) {
isocdesc->start_frame = cur_frame + START_FRAME_FUDGE;
}
- /* else for start_type == START_ABSOLUTE, use start_frame as is. */
/* and see if start_frame needs any correction */
- if (isocdesc->start_frame >= UHCI_NUMFRAMES)
- isocdesc->start_frame -= UHCI_NUMFRAMES;
+ /* only wrap to USB frame numbers, the frame_list insertion routine
+ takes care of the wrapping to the frame_list size */
+ isocdesc->start_frame = USB_WRAP_FRAMENR(isocdesc->start_frame);
/* and fix the end_frame value */
- isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1;
- if (isocdesc->end_frame >= UHCI_NUMFRAMES)
- isocdesc->end_frame -= UHCI_NUMFRAMES;
+ isocdesc->end_frame = USB_WRAP_FRAMENR(isocdesc->start_frame + isocdesc->frame_count - 1);
isocdesc->prev_completed_frame = -1;
isocdesc->cur_completed_frame = -1;
td->status |= TD_CTRL_IOC;
td->completed = isocdesc->callback_fn;
cb_frames = 0;
+ uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context);
}
bufptr += fd->frame_length; /* or isocdesc->frame_size; */
/*
* Insert the TD in the frame list.
*/
- td->backptr = &uhci->fl->frame [cur_frame];
- td->link = uhci->fl->frame [cur_frame];
- uhci->fl->frame [cur_frame] = virt_to_bus (td);
+ uhci_add_frame_list(uhci, td, cur_frame);
- if (++cur_frame >= UHCI_NUMFRAMES)
- cur_frame = 0;
+ cur_frame = USB_WRAP_FRAMENR(cur_frame+1);
} /* end for ix */
/*
* Add IOC on the last TD.
*/
td--;
- td->status |= TD_CTRL_IOC;
- uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
-
+ if (!(td->status & TD_CTRL_IOC)) {
+ td->status |= TD_CTRL_IOC;
+ td->completed = isocdesc->callback_fn;
+ uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
+ }
return 0;
} /* end uhci_run_isoc */
struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev);
struct uhci *uhci = dev->uhci;
struct uhci_td *td;
- int ix, cur_frame;
+ int ix;
- if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= UHCI_NUMFRAMES)) {
+ if (USB_WRAP_FRAMENR(isocdesc->start_frame) != isocdesc->start_frame) {
#ifdef CONFIG_USB_DEBUG_ISOC
printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n",
isocdesc->start_frame);
return -EINVAL;
}
- for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame;
- ix < isocdesc->frame_count; ix++, td++) {
+ for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) {
+ uhci_remove_frame_list(uhci, td);
td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
- uhci->fl->frame [cur_frame] = td->link;
-
- if (++cur_frame >= UHCI_NUMFRAMES)
- cur_frame = 0;
} /* end for ix */
isocdesc->start_frame = -1;
static void uhci_free_isoc (struct usb_isoc_desc *isocdesc)
{
+ int i;
+
/* If still Active, kill it. */
if (isocdesc->start_frame >= 0)
- uhci_kill_isoc (isocdesc);
+ uhci_kill_isoc(isocdesc);
- /* Remove it from the IRQ list. */
- uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1]));
+ /* Remove all td's from the IRQ list. */
+ for(i = 0; i < isocdesc->frame_count; i++)
+ uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i);
/* Free the associate memory. */
if (isocdesc->td)
- kfree (isocdesc->td);
+ kfree(isocdesc->td);
- kfree (isocdesc);
+ kfree(isocdesc);
} /* end uhci_free_isoc */
/*
td, isocdesc, first_comp, cur_comp, num_comp);
#endif
- for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp];
+ for (ix = 0, fx = first_comp, prtd = ((struct uhci_td *)(isocdesc->td))+first_comp, frm = &isocdesc->frames [first_comp];
ix < num_comp; ix++) {
frm->frame_length = uhci_actual_length (prtd->status);
isocdesc->total_length += frm->frame_length;
/* Don't clobber the frame */
td->link = uhci->fl->frame[0];
+ td->backptr = &uhci->fl->frame[0];
td->status = TD_CTRL_IOC;
td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; /* (ignored) input packet, 16 bytes, device 127 */
td->buffer = 0;
# ifdef CONFIG_USB_MOUSE
usb_mouse_init();
# endif
+# ifdef CONFIG_USB_HP_SCANNER
+ usb_hp_scanner_init();
+# endif
# ifdef CONFIG_USB_KBD
usb_kbd_init();
# endif
# ifdef CONFIG_USB_MOUSE
usb_mouse_cleanup();
# endif
+# ifdef CONFIG_USB_HP_SCANNER
+ usb_hp_scanner_cleanup();
+# endif
#endif
}
*/
#define START_FRAME_FUDGE 3
+#define USB_WRAP_FRAMENR(x) ((x) & 2047)
+
/* for start_type: */
enum {
START_ASAP = 0,
extern void usb_destroy_configuration(struct usb_device *dev);
-extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len,
- int maxsze, usb_device_irq completed, void *dev_id);
-extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc);
-extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
-extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc);
-extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc);
-
int usb_get_current_frame_number (struct usb_device *usb_dev);
int usb_init_isoc (struct usb_device *usb_dev,
int ip_wanted; /* needed */
int pid; /* control thread */
struct semaphore *notify; /* wait for thread to begin */
+ void *irq_handle; /* for USB interrupt requests */
};
/*
__u8 status[2];
devrequest dr;
int retry = 5;
+ void *irq_handle;
US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
switch (us->protocol) {
/* add interrupt transfer, marked for removal */
us->ip_wanted = 1;
- result = us->pusb_dev->bus->op->request_irq(us->pusb_dev,
+ irq_handle = us->pusb_dev->bus->op->request_irq(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev, us->ep_int),
pop_CBI_irq, 0, (void *)us);
- if (result) {
- US_DEBUGP("No interrupt for CBI %x\n", result);
+ if (!irq_handle) {
+ US_DEBUGP("No interrupt for CBI\n");
return DID_ABORT << 16;
}
+ us->irq_handle = irq_handle;
+
sleep_on(&us->ip_waitq);
if (us->ip_wanted) {
US_DEBUGP("Did not get interrupt on CBI\n");
struct us_data *us = (struct us_data *)psh->hostdata[0];
struct us_data *prev = (struct us_data *)&us_list;
+ if (us->irq_handle) {
+ usb_release_irq(us->pusb_dev, us->irq_handle);
+ us->irq_handle = NULL;
+ }
if (us->filter)
us->filter->release(us->fdata);
if (us->pusb_dev)
usb_deregister(&scsi_driver);
/* FIXME - leaves hanging host template copy */
- /* (bacause scsi layer uses it after removal !!!) */
+ /* (because scsi layer uses it after removal !!!) */
while(prev->next != us)
prev = prev->next;
prev->next = us->next;
dev->descriptor.idProduct == 0x0001) {
devrequest dr;
__u8 qstat[2];
+ void *irq_handle;
/* shuttle E-USB */
dr.requesttype = 0xC0;
ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
init_waitqueue_head(&ss->ip_waitq);
- ss->pusb_dev->bus->op->request_irq(ss->pusb_dev,
+ irq_handle = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev,
usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int),
pop_CBI_irq, 0, (void *)ss);
+ if (!irq_handle)
+ return -1;
+ ss->irq_handle = irq_handle;
interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5);
} else if (ss->protocol == US_PR_CBI)
if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
bool ' Root file system on NFS' CONFIG_ROOT_NFS
fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'NFS server support' CONFIG_NFSD
- if [ "$CONFIG_NFSD" != "n" ]; then
- bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
- fi
+ # considering that RedHat-6.0 ships with this on, I guess it's not really experimental
+ tristate 'NFS server support' CONFIG_NFSD
+ if [ "$CONFIG_NFSD" != "n" ]; then
+ bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
fi
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_bool CONFIG_SUNRPC y
*/
void __bforget(struct buffer_head * buf)
{
+ /* grab the lru lock here to block bdflush. */
spin_lock(&lru_list_lock);
write_lock(&hash_table_lock);
- if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
- touch_buffer(buf);
- atomic_dec(&buf->b_count);
- } else {
- atomic_set(&buf->b_count, 0);
- buf->b_state = 0;
- if (buf->b_pprev)
- __hash_unlink(buf);
- __remove_from_lru_list(buf, buf->b_list);
- put_last_free(buf);
- }
+ if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
+ goto in_use;
+ if (buf->b_pprev)
+ __hash_unlink(buf);
+ write_unlock(&hash_table_lock);
+ __remove_from_lru_list(buf, buf->b_list);
+ spin_unlock(&lru_list_lock);
+ buf->b_state = 0;
+ put_last_free(buf);
+ return;
+
+ in_use:
write_unlock(&hash_table_lock);
spin_unlock(&lru_list_lock);
}
*/
if (offset <= curr_off) {
if (buffer_mapped(bh)) {
- atomic_inc(&bh->b_count);
- wait_on_buffer(bh);
- if (bh->b_dev == B_FREE)
- BUG();
mark_buffer_clean(bh);
+ wait_on_buffer(bh);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
bh->b_blocknr = 0;
- atomic_dec(&bh->b_count);
}
}
curr_off = next_off;
* instead.
*/
if (!offset) {
- if (!try_to_free_buffers(page))
- {
+ if (!try_to_free_buffers(page)) {
atomic_add(PAGE_CACHE_SIZE, &buffermem);
return 0;
}
unsigned int flags;
retval = -EPERM;
- if ((iattr->ia_attr_flags &
- (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
- (inode->u.ext2_i.i_flags &
- (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+ if (iattr->ia_valid & ATTR_ATTR_FLAG &&
+ ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) !=
+ !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) ||
+ (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) !=
+ !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) {
if (!capable(CAP_LINUX_IMMUTABLE))
goto out;
} else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
instructions adding the wait_table waitqueues in the
waitqueue-head before going to calculate the mask-retval. */
__set_current_state(TASK_INTERRUPTIBLE);
- if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
+ if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
int timed_out;
if (timeout > max_timeout) {
/* JEJB/JSP 2/7/94
* that the parent is still our parent and
* that we are still hashed onto it..
*
- * This is requied in case two processes race
+ * This is required in case two processes race
* on removing (or moving) the same entry: the
* parent lock will serialize them, but the
* other process will be too late..
+ *
+ * Note that this nfsd_check_parent is different
+ * than the one in linux/include/dcache_func.h.
*/
-#define check_parent(dir, dentry) \
+#define nfsd_check_parent(dir, dentry) \
((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
/*
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
err = -ENOENT;
/* GAM3 check for parent changes after locking. */
- if (check_parent(fdir, odentry) &&
- check_parent(tdir, ndentry)) {
+ if (nfsd_check_parent(fdir, odentry) &&
+ nfsd_check_parent(tdir, ndentry)) {
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
fhp->fh_locked = 1;
err = -ENOENT;
- if (check_parent(dirp, rdentry))
+ if (nfsd_check_parent(dirp, rdentry))
err = vfs_rmdir(dirp, rdentry);
rdentry->d_count--;
/* Define to experiment with fitting everything into one 512MB HAE window. */
#define CIA_ONE_HAE_WINDOW 1
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/compiler.h>
#ifndef __ALPHA_LCA__H__
#define __ALPHA_LCA__H__
-#include <linux/config.h>
#include <asm/system.h>
#include <asm/compiler.h>
One window per bus, that is. */
#define MCPCIA_ONE_HAE_WINDOW 1
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/compiler.h>
#ifndef __ALPHA_POLARIS__H__
#define __ALPHA_POLARIS__H__
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/compiler.h>
#ifndef __ALPHA_PYXIS__H__
#define __ALPHA_PYXIS__H__
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/compiler.h>
#ifndef __ALPHA_TSUNAMI__H__
#define __ALPHA_TSUNAMI__H__
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/compiler.h>
#define FOURPORT_FLAGS ASYNC_FOURPORT
#define ACCENT_FLAGS 0
#define BOCA_FLAGS 0
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 4
#endif
#define STD_SERIAL_PORT_DEFNS \
#ifdef __SMP__
-#include <linux/tasks.h>
+#include <linux/threads.h>
struct cpuinfo_alpha {
unsigned long loops_per_sec;
#ifndef __ASM_HARDIRQ_H
#define __ASM_HARDIRQ_H
-#include <linux/tasks.h>
+#include <linux/threads.h>
extern unsigned int local_irq_count[NR_CPUS];
+#include <linux/config.h>
#ifndef __ASSEMBLER__
#define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2))
static void __init copro_timeout(void)
{
fpu_error = 1;
- timer_table[COPRO_TIMER].expires = jiffies+100;
+ timer_table[COPRO_TIMER].expires = jiffies+HZ;
timer_active |= 1<<COPRO_TIMER;
printk(KERN_ERR "387 failed: trying to reset\n");
send_sig(SIGFPE, current, 1);
#include <asm/apic.h>
#include <asm/page.h>
#ifdef CONFIG_BIGMEM
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
#ifndef __ASM_MIPS_HARDIRQ_H
#define __ASM_MIPS_HARDIRQ_H
-#include <linux/tasks.h>
+#include <linux/threads.h>
extern unsigned int local_irq_count[NR_CPUS];
#ifndef __ASMPPC_GEMINI_SERIAL_H
#define __ASMPPC_GEMINI_SERIAL_H
+#include <linux/config.h>
#include <asm/gemini.h>
/* Rate for the 24.576 Mhz clock for the onboard serial chip */
* Copyright (C) 1998 Paul Mackerras.
*/
-#include <linux/config.h>
/*
* PMU commands
*/
* I don't know of any Super-H bugs yet.
*/
-#include <linux/config.h>
#include <asm/processor.h>
__initfunc(static void check_bugs(void))
* ELF register definitions..
*/
+#include <linux/config.h>
#include <asm/ptrace.h>
#include <asm/user.h>
#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/ap1000/apservice.h>
#include <asm/ap1000/apbif.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
/*
* Macros for accessing I/O registers.
#ifdef __KERNEL__
-#include <linux/types.h>
#include <linux/fs.h>
#include <linux/tqueue.h>
#include <linux/wait.h>
#ifdef __KERNEL__
-#include <linux/types.h>
#include <linux/fs.h>
#include <linux/tqueue.h>
#include <linux/wait.h>
#ifndef _ASM_SPARC64_DMA_H
#define _ASM_SPARC64_DMA_H
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#ifndef __SPARC64_HARDIRQ_H
#define __SPARC64_HARDIRQ_H
-#include <linux/tasks.h>
+#include <linux/threads.h>
#ifndef __SMP__
extern unsigned int local_irq_count;
* cd1400.h -- cd1400 UART hardware info.
*
* Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* 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
* cdk.h -- CDK interface definitions.
*
* Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* 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
* comstats.h -- Serial Port Stats.
*
* Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* 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
char dev_name[8]; /* linux /dev name if available */
};
-#ifdef CONFIG_I2O_PCI_MODULE
/*
* Resource data for each PCI I2O controller
*/
{
int irq;
};
-#endif
+
/*
* Each I2O controller has one of these objects
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
+#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
+
extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
/* Compatibility cruft */
#define check_region(start,n) __check_region(&ioport_resource, (start), (n))
#define release_region(start,n) __release_region(&ioport_resource, (start), (n))
+#define check_mem_region(start,n) __check_region(&iomem_resource, (start), (n))
+#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n))
+
extern int __check_region(struct resource *, unsigned long, unsigned long);
extern void __release_region(struct resource *, unsigned long, unsigned long);
* istallion.h -- stallion intelligent multiport serial driver.
*
* Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* 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
long pgrp;
unsigned int rxmarkmsk;
struct tty_struct *tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *raw_wait;
+#else
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t raw_wait;
+#endif
struct tq_struct tqhangup;
struct termios normaltermios;
struct termios callouttermios;
___wait_on_page(page);
}
-extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
-
#endif
#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010
#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020
+#define PCI_VENDOR_ID_MYLEX 0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2 0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3 0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020
+
#define PCI_VENDOR_ID_PICOP 0x1066
#define PCI_DEVICE_ID_PICOP_PT86C52X 0x0001
#define PCI_DEVICE_ID_PICOP_PT80C524 0x8002
#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004
#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005
+#define PCI_VENDOR_ID_INTERPHASE 0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005
+
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded
void pcibios_init(void);
void pcibios_fixup_bus(struct pci_bus *);
char *pcibios_setup (char *str);
-int pcibios_assign_resource(struct pci_dev *, int i);
+void pcibios_update_resource(struct pci_dev *, struct resource *,
+ struct resource *, int);
+void pcibios_update_irq(struct pci_dev *, int irq);
/* Backward compatibility, don't use in new code! */
struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
int pci_find_capability (struct pci_dev *dev, int cap);
+int pci_claim_resource(struct pci_dev *, int);
+void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
+void pci_set_bus_ranges(void);
+void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
+ int (*)(struct pci_dev *, u8, u8));
+
#define PCI_ANY_ID (~0)
int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
* For definitions of the flags field, see tty.h
*/
+#include <linux/config.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
#include <linux/wait.h>
* stallion.h -- stallion multiport serial driver.
*
* Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
- * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer.
*
* 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
unsigned long hwid;
void *uartp;
struct tty_struct *tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+#else
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
+#endif
struct termios normaltermios;
struct termios callouttermios;
struct tq_struct tqueue;
extern int lp_init(void);
extern int pty_init(void);
extern int tty_init(void);
+extern int ip2_init(void);
extern int pcxe_init(void);
extern int pc_init(void);
extern int vcs_init(void);
--- /dev/null
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * bulkmem.h 1.3 1995/05/27 04:49:49
+ */
+
+#ifndef _LINUX_BULKMEM_H
+#define _LINUX_BULKMEM_H
+
+/* For GetFirstRegion and GetNextRegion */
+typedef struct region_info_t {
+ u_int Attributes;
+ u_int CardOffset;
+ u_int RegionSize;
+ u_int AccessSpeed;
+ u_int BlockSize;
+ u_int PartMultiple;
+ u_char JedecMfr, JedecInfo;
+ memory_handle_t next;
+} region_info_t;
+
+#define REGION_TYPE 0x0001
+#define REGION_TYPE_CM 0x0000
+#define REGION_TYPE_AM 0x0001
+#define REGION_PREFETCH 0x0008
+#define REGION_CACHEABLE 0x0010
+#define REGION_BAR_MASK 0xe000
+#define REGION_BAR_SHIFT 13
+
+/* For OpenMemory */
+typedef struct open_mem_t {
+ u_int Attributes;
+ u_int Offset;
+} open_mem_t;
+
+/* Attributes for OpenMemory */
+#define MEMORY_TYPE 0x0001
+#define MEMORY_TYPE_CM 0x0000
+#define MEMORY_TYPE_AM 0x0001
+#define MEMORY_EXCLUSIVE 0x0002
+#define MEMORY_PREFETCH 0x0008
+#define MEMORY_CACHEABLE 0x0010
+#define MEMORY_BAR_MASK 0xe000
+#define MEMORY_BAR_SHIFT 13
+
+typedef struct eraseq_entry_t {
+ memory_handle_t Handle;
+ u_char State;
+ u_int Size;
+ u_int Offset;
+ void *Optional;
+} eraseq_entry_t;
+
+typedef struct eraseq_hdr_t {
+ int QueueEntryCnt;
+ eraseq_entry_t *QueueEntryArray;
+} eraseq_hdr_t;
+
+#define ERASE_QUEUED 0x00
+#define ERASE_IN_PROGRESS(n) (((n) > 0) && ((n) < 0x80))
+#define ERASE_IDLE 0xff
+#define ERASE_PASSED 0xe0
+#define ERASE_FAILED 0xe1
+
+#define ERASE_MISSING 0x80
+#define ERASE_MEDIA_WRPROT 0x84
+#define ERASE_NOT_ERASABLE 0x85
+#define ERASE_BAD_OFFSET 0xc1
+#define ERASE_BAD_TECH 0xc2
+#define ERASE_BAD_SOCKET 0xc3
+#define ERASE_BAD_VCC 0xc4
+#define ERASE_BAD_VPP 0xc5
+#define ERASE_BAD_SIZE 0xc6
+
+/* For CopyMemory */
+typedef struct copy_op_t {
+ u_int Attributes;
+ u_int SourceOffset;
+ u_int DestOffset;
+ u_int Count;
+} copy_op_t;
+
+/* For ReadMemory and WriteMemory */
+typedef struct mem_op_t {
+ u_int Attributes;
+ u_int Offset;
+ u_int Count;
+} mem_op_t;
+
+#define MEM_OP_BUFFER 0x01
+#define MEM_OP_BUFFER_USER 0x00
+#define MEM_OP_BUFFER_KERNEL 0x01
+#define MEM_OP_DISABLE_ERASE 0x02
+#define MEM_OP_VERIFY 0x04
+
+/* For RegisterMTD */
+typedef struct mtd_reg_t {
+ u_int Attributes;
+ u_int Offset;
+ u_long MediaID;
+} mtd_reg_t;
+
+/*
+ * Definitions for MTD requests
+ */
+
+typedef struct mtd_request_t {
+ u_int SrcCardOffset;
+ u_int DestCardOffset;
+ u_int TransferLength;
+ u_int Function;
+ u_long MediaID;
+ u_int Status;
+ u_int Timeout;
+} mtd_request_t;
+
+/* Fields in MTD Function */
+#define MTD_REQ_ACTION 0x003
+#define MTD_REQ_ERASE 0x000
+#define MTD_REQ_READ 0x001
+#define MTD_REQ_WRITE 0x002
+#define MTD_REQ_COPY 0x003
+#define MTD_REQ_NOERASE 0x004
+#define MTD_REQ_VERIFY 0x008
+#define MTD_REQ_READY 0x010
+#define MTD_REQ_TIMEOUT 0x020
+#define MTD_REQ_LAST 0x040
+#define MTD_REQ_FIRST 0x080
+#define MTD_REQ_KERNEL 0x100
+
+/* Status codes */
+#define MTD_WAITREQ 0x00
+#define MTD_WAITTIMER 0x01
+#define MTD_WAITRDY 0x02
+#define MTD_WAITPOWER 0x03
+
+/*
+ * Definitions for MTD helper functions
+ */
+
+/* For MTDModifyWindow */
+typedef struct mtd_mod_win_t {
+ u_int Attributes;
+ u_int AccessSpeed;
+ u_int CardOffset;
+} mtd_mod_win_t;
+
+/* For MTDSetVpp */
+typedef struct mtd_vpp_req_t {
+ u_char Vpp1, Vpp2;
+} mtd_vpp_req_t;
+
+/* For MTDRDYMask */
+typedef struct mtd_rdy_req_t {
+ u_int Mask;
+} mtd_rdy_req_t;
+
+enum mtd_helper {
+ MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
+ MTDSetVpp, MTDRDYMask
+};
+
+#ifdef IN_CARD_SERVICES
+extern int MTDHelperEntry(int func, void *a1, void *a2);
+#else
+extern int MTDHelperEntry(int func, ...);
+#endif
+
+#endif /* _LINUX_BULKMEM_H */
--- /dev/null
+/*
+ * bus_ops.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_BUS_OPS_H
+#define _LINUX_BUS_OPS_H
+
+typedef struct bus_operations {
+ void *priv;
+ u32 (*b_in)(void *bus, u32 port, s32 sz);
+ void (*b_ins)(void *bus, u32 port, void *buf,
+ u32 count, s32 sz);
+ void (*b_out)(void *bus, u32 val, u32 port, s32 sz);
+ void (*b_outs)(void *bus, u32 port, void *buf,
+ u32 count, s32 sz);
+ void *(*b_ioremap)(void *bus, u_long ofs, u_long sz);
+ void (*b_iounmap)(void *bus, void *addr);
+ u32 (*b_read)(void *bus, void *addr, s32 sz);
+ void (*b_write)(void *bus, u32 val, void *addr, s32 sz);
+ void (*b_copy_from)(void *bus, void *d, void *s, u32 count);
+ void (*b_copy_to)(void *bus, void *d, void *s, u32 count);
+ int (*b_request_irq)(void *bus, u_int irq,
+ void (*handler)(int, void *,
+ struct pt_regs *),
+ u_long flags, const char *device,
+ void *dev_id);
+ void (*b_free_irq)(void *bus, u_int irq, void *dev_id);
+} bus_operations;
+
+#ifdef CONFIG_VIRTUAL_BUS
+
+#define bus_inb(b,p) (b)->b_in((b),(p),0)
+#define bus_inw(b,p) (b)->b_in((b),(p),1)
+#define bus_inl(b,p) (b)->b_in((b),(p),2)
+#define bus_inw_ns(b,p) (b)->b_in((b),(p),-1)
+#define bus_inl_ns(b,p) (b)->b_in((b),(p),-2)
+
+#define bus_insb(b,p,a,c) (b)->b_ins((b),(p),(a),(c),0)
+#define bus_insw(b,p,a,c) (b)->b_ins((b),(p),(a),(c),1)
+#define bus_insl(b,p,a,c) (b)->b_ins((b),(p),(a),(c),2)
+#define bus_insw_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-1)
+#define bus_insl_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-2)
+
+#define bus_outb(b,v,p) (b)->b_out((b),(v),(p),0)
+#define bus_outw(b,v,p) (b)->b_out((b),(v),(p),1)
+#define bus_outl(b,v,p) (b)->b_out((b),(v),(p),2)
+#define bus_outw_ns(b,v,p) (b)->b_out((b),(v),(p),-1)
+#define bus_outl_ns(b,v,p) (b)->b_out((b),(v),(p),-2)
+
+#define bus_outsb(b,p,a,c) (b)->b_outs((b),(p),(a),(c),0)
+#define bus_outsw(b,p,a,c) (b)->b_outs((b),(p),(a),(c),1)
+#define bus_outsl(b,p,a,c) (b)->b_outs((b),(p),(a),(c),2)
+#define bus_outsw_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-1)
+#define bus_outsl_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-2)
+
+#define bus_readb(b,a) (b)->b_read((b),(a),0)
+#define bus_readw(b,a) (b)->b_read((b),(a),1)
+#define bus_readl(b,a) (b)->b_read((b),(a),2)
+#define bus_readw_ns(b,a) (b)->b_read((b),(a),-1)
+#define bus_readl_ns(b,a) (b)->b_read((b),(a),-2)
+
+#define bus_writeb(b,v,a) (b)->b_write((b),(v),(a),0)
+#define bus_writew(b,v,a) (b)->b_write((b),(v),(a),1)
+#define bus_writel(b,v,a) (b)->b_write((b),(v),(a),2)
+#define bus_writew_ns(b,v,a) (b)->b_write((b),(v),(a),-1)
+#define bus_writel_ns(b,v,a) (b)->b_write((b),(v),(a),-2)
+
+#define bus_ioremap(b,s,n) (b)->b_ioremap((b),(s),(n))
+#define bus_iounmap(b,a) (b)->b_iounmap((b),(a))
+#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n))
+#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n))
+
+#define bus_request_irq(b,i,h,f,n,d) \
+ (b)->b_request_irq((b),(i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d) (b)->b_free_irq((b),(i),(d))
+
+#else
+
+#define bus_inb(b,p) inb(p)
+#define bus_inw(b,p) inw(p)
+#define bus_inl(b,p) inl(p)
+#define bus_inw_ns(b,p) inw_ns(p)
+#define bus_inl_ns(b,p) inl_ns(p)
+
+#define bus_insb(b,p,a,c) insb(p,a,c)
+#define bus_insw(b,p,a,c) insw(p,a,c)
+#define bus_insl(b,p,a,c) insl(p,a,c)
+#define bus_insw_ns(b,p,a,c) insw_ns(p,a,c)
+#define bus_insl_ns(b,p,a,c) insl_ns(p,a,c)
+
+#define bus_outb(b,v,p) outb(b,v,p)
+#define bus_outw(b,v,p) outw(b,v,p)
+#define bus_outl(b,v,p) outl(b,v,p)
+#define bus_outw_ns(b,v,p) outw_ns(b,v,p)
+#define bus_outl_ns(b,v,p) outl_ns(b,v,p)
+
+#define bus_outsb(b,p,a,c) outsb(p,a,c)
+#define bus_outsw(b,p,a,c) outsw(p,a,c)
+#define bus_outsl(b,p,a,c) outsl(p,a,c)
+#define bus_outsw_ns(b,p,a,c) outsw_ns(p,a,c)
+#define bus_outsl_ns(b,p,a,c) outsl_ns(p,a,c)
+
+#define bus_readb(b,a) readb(a)
+#define bus_readw(b,a) readw(a)
+#define bus_readl(b,a) readl(a)
+#define bus_readw_ns(b,a) readw_ns(a)
+#define bus_readl_ns(b,a) readl_ns(a)
+
+#define bus_writeb(b,v,a) writeb(v,a)
+#define bus_writew(b,v,a) writew(v,a)
+#define bus_writel(b,v,a) writel(v,a)
+#define bus_writew_ns(b,v,a) writew_ns(v,a)
+#define bus_writel_ns(b,v,a) writel_ns(v,a)
+
+#define bus_ioremap(b,s,n) ioremap(s,n)
+#define bus_iounmap(b,a) iounmap(a)
+#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n)
+#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n)
+
+#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d) free_irq((i),(d))
+
+#endif /* CONFIG_VIRTUAL_BUS */
+
+#endif /* _LINUX_BUS_OPS_H */
--- /dev/null
+/*
+ * ciscode.h 1.38 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISCODE_H
+#define _LINUX_CISCODE_H
+
+/* Manufacturer and Product ID codes */
+
+#define MANFID_3COM 0x0101
+#define PRODID_3COM_3CXEM556 0x0035
+#define PRODID_3COM_3CCFEM556 0x0556
+#define PRODID_3COM_3C562 0x0562
+
+#define MANFID_ACCTON 0x01bf
+#define PRODID_ACCTON_EN2226 0x010a
+
+#define MANFID_ADAPTEC 0x012f
+#define PRODID_ADAPTEC_SCSI 0x0001
+
+#define MANFID_ATT 0xffff
+#define PRODID_ATT_KIT 0x0100
+
+#define MANFID_CONTEC 0xc001
+
+#define MANFID_FUJITSU 0x0004
+#define PRODID_FUJITSU_MBH10302 0x0004
+#define PRODID_FUJITSU_MBH10304 0x1003
+#define PRODID_FUJITSU_LA501 0x2000
+
+#define MANFID_IBM 0x00a4
+#define PRODID_IBM_HOME_AND_AWAY 0x002e
+
+#define MANFID_INTEL 0x0089
+#define PRODID_INTEL_DUAL_RS232 0x0301
+#define PRODID_INTEL_2PLUS 0x8422
+
+#define MANFID_LINKSYS 0x0143
+#define PRODID_LINKSYS_PCMLM28 0xc0ab
+#define PRODID_LINKSYS_3400 0x3341
+
+#define MANFID_MEGAHERTZ 0x0102
+#define PRODID_MEGAHERTZ_VARIOUS 0x0000
+#define PRODID_MEGAHERTZ_EM3288 0x0006
+
+#define MANFID_MACNICA 0xc00b
+
+#define MANFID_MOTOROLA 0x0109
+#define PRODID_MOTOROLA_MARINER 0x0501
+
+#define MANFID_NATINST 0x010b
+#define PRODID_NATINST_QUAD_RS232 0xd180
+
+#define MANFID_NEW_MEDIA 0x0057
+
+#define MANFID_OLICOM 0x0121
+#define PRODID_OLICOM_OC2231 0x3122
+#define PRODID_OLICOM_OC2232 0x3222
+
+#define MANFID_OMEGA 0x0137
+#define PRODID_OMEGA_QSP_100 0x0025
+
+#define MANFID_OSITECH 0x0140
+#define PRODID_OSITECH_JACK_144 0x0001
+#define PRODID_OSITECH_JACK_288 0x0002
+#define PRODID_OSITECH_JACK_336 0x0007
+#define PRODID_OSITECH_SEVEN 0x0008
+
+#define MANFID_PSION 0x016c
+
+#define MANFID_QUATECH 0x0137
+#define PRODID_QUATECH_SPP100 0x0003
+#define PRODID_QUATECH_DUAL_RS232 0x0012
+#define PRODID_QUATECH_DUAL_RS232_D1 0x0007
+#define PRODID_QUATECH_QUAD_RS232 0x001b
+
+#define MANFID_SMC 0x0108
+#define PRODID_SMC_ETHER 0x0105
+
+#define MANFID_SOCKET 0x0104
+#define PRODID_SOCKET_DUAL_RS232 0x0006
+#define PRODID_SOCKET_LPE 0x000d
+
+#define MANFID_SUNDISK 0x0045
+
+#define MANFID_TDK 0x0105
+
+#define MANFID_XIRCOM 0x0105
+
+#endif /* _LINUX_CISCODE_H */
--- /dev/null
+/*
+ * cisreg.h 1.13 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISREG_H
+#define _LINUX_CISREG_H
+
+/* Offsets from ConfigBase for CIS registers */
+#define CISREG_COR 0x00
+#define CISREG_CCSR 0x02
+#define CISREG_PRR 0x04
+#define CISREG_SCR 0x06
+#define CISREG_ESR 0x08
+#define CISREG_IOBASE_0 0x0a
+#define CISREG_IOBASE_1 0x0c
+#define CISREG_IOBASE_2 0x0e
+#define CISREG_IOBASE_3 0x10
+#define CISREG_IOSIZE 0x12
+
+/*
+ * Configuration Option Register
+ */
+#define COR_CONFIG_MASK 0x3f
+#define COR_MFC_CONFIG_MASK 0x38
+#define COR_FUNC_ENA 0x01
+#define COR_ADDR_DECODE 0x02
+#define COR_IREQ_ENA 0x04
+#define COR_LEVEL_REQ 0x40
+#define COR_SOFT_RESET 0x80
+
+/*
+ * Card Configuration and Status Register
+ */
+#define CCSR_INTR_ACK 0x01
+#define CCSR_INTR_PENDING 0x02
+#define CCSR_POWER_DOWN 0x04
+#define CCSR_AUDIO_ENA 0x08
+#define CCSR_IOIS8 0x20
+#define CCSR_SIGCHG_ENA 0x40
+#define CCSR_CHANGED 0x80
+
+/*
+ * Pin Replacement Register
+ */
+#define PRR_WP_STATUS 0x01
+#define PRR_READY_STATUS 0x02
+#define PRR_BVD2_STATUS 0x04
+#define PRR_BVD1_STATUS 0x08
+#define PRR_WP_EVENT 0x10
+#define PRR_READY_EVENT 0x20
+#define PRR_BVD2_EVENT 0x40
+#define PRR_BVD1_EVENT 0x80
+
+/*
+ * Socket and Copy Register
+ */
+#define SCR_SOCKET_NUM 0x0f
+#define SCR_COPY_NUM 0x70
+
+/*
+ * Extended Status Register
+ */
+#define ESR_REQ_ATTN_ENA 0x01
+#define ESR_REQ_ATTN 0x10
+
+/*
+ * CardBus Function Status Registers
+ */
+#define CBFN_EVENT 0x00
+#define CBFN_MASK 0x04
+#define CBFN_STATE 0x08
+#define CBFN_FORCE 0x0c
+
+/*
+ * These apply to all the CardBus function registers
+ */
+#define CBFN_WP 0x0001
+#define CBFN_READY 0x0002
+#define CBFN_BVD2 0x0004
+#define CBFN_BVD1 0x0008
+#define CBFN_GWAKE 0x0010
+#define CBFN_INTR 0x8000
+
+/*
+ * Extra bits in the Function Event Mask Register
+ */
+#define FEMR_BAM_ENA 0x0020
+#define FEMR_PWM_ENA 0x0040
+#define FEMR_WKUP_MASK 0x4000
+
+#endif /* _LINUX_CISREG_H */
--- /dev/null
+/*
+ * cistpl.h 1.30 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_LONGLINK_CB 0x02
+#define CISTPL_CONFIG_CB 0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC 0x06
+#define CISTPL_BAR 0x07
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_DEVICE_OC 0x1c
+#define CISTPL_DEVICE_OA 0x1d
+#define CISTPL_DEVICE_GEO 0x1e
+#define CISTPL_DEVICE_GEO_A 0x1f
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_END 0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2 0x40
+#define CISTPL_FORMAT 0x41
+#define CISTPL_GEOMETRY 0x42
+#define CISTPL_BYTEORDER 0x43
+#define CISTPL_DATE 0x44
+#define CISTPL_BATTERY 0x45
+/* Layer 3 tuples */
+#define CISTPL_ORG 0x46
+
+typedef struct cistpl_longlink_t {
+ u_int addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+ u_short addr;
+ u_short len;
+ u_char sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS 8
+#define CISTPL_MFC_ATTR 0x00
+#define CISTPL_MFC_COMMON 0x01
+
+typedef struct cistpl_longlink_mfc_t {
+ u_char nfn;
+ struct {
+ u_char space;
+ u_int addr;
+ } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS 4
+
+typedef struct cistpl_altstr_t {
+ u_char ns;
+ u_char ofs[CISTPL_MAX_ALTSTR_STRINGS];
+ char str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL 0x00
+#define CISTPL_DTYPE_ROM 0x01
+#define CISTPL_DTYPE_OTPROM 0x02
+#define CISTPL_DTYPE_EPROM 0x03
+#define CISTPL_DTYPE_EEPROM 0x04
+#define CISTPL_DTYPE_FLASH 0x05
+#define CISTPL_DTYPE_SRAM 0x06
+#define CISTPL_DTYPE_DRAM 0x07
+#define CISTPL_DTYPE_FUNCSPEC 0x0d
+#define CISTPL_DTYPE_EXTEND 0x0e
+
+#define CISTPL_MAX_DEVICES 4
+
+typedef struct cistpl_device_t {
+ u_char ndev;
+ struct {
+ u_char type;
+ u_char wp;
+ u_int speed;
+ u_int size;
+ } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT 0x01
+#define CISTPL_DEVICE_3VCC 0x02
+
+typedef struct cistpl_device_o_t {
+ u_char flags;
+ cistpl_device_t device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS 4
+
+typedef struct cistpl_vers_1_t {
+ u_char major;
+ u_char minor;
+ u_char ns;
+ u_char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+ char str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+ u_char nid;
+ struct {
+ u_char mfr;
+ u_char info;
+ } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+ u_short manf;
+ u_short card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI 0x00
+#define CISTPL_FUNCID_MEMORY 0x01
+#define CISTPL_FUNCID_SERIAL 0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED 0x04
+#define CISTPL_FUNCID_VIDEO 0x05
+#define CISTPL_FUNCID_NETWORK 0x06
+#define CISTPL_FUNCID_AIMS 0x07
+#define CISTPL_FUNCID_SCSI 0x08
+
+#define CISTPL_SYSINIT_POST 0x01
+#define CISTPL_SYSINIT_ROM 0x02
+
+typedef struct cistpl_funcid_t {
+ u_char func;
+ u_char sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+ u_char type;
+ u_char data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+ Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF 0x00
+#define CISTPL_FUNCE_SERIAL_CAP 0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250 0x00
+#define CISTPL_SERIAL_UART_16450 0x01
+#define CISTPL_SERIAL_UART_16550 0x02
+#define CISTPL_SERIAL_UART_8251 0x03
+#define CISTPL_SERIAL_UART_8530 0x04
+#define CISTPL_SERIAL_UART_85230 0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE 0x01
+#define CISTPL_SERIAL_UART_MARK 0x02
+#define CISTPL_SERIAL_UART_ODD 0x04
+#define CISTPL_SERIAL_UART_EVEN 0x08
+#define CISTPL_SERIAL_UART_5BIT 0x01
+#define CISTPL_SERIAL_UART_6BIT 0x02
+#define CISTPL_SERIAL_UART_7BIT 0x04
+#define CISTPL_SERIAL_UART_8BIT 0x08
+#define CISTPL_SERIAL_UART_1STOP 0x10
+#define CISTPL_SERIAL_UART_MSTOP 0x20
+#define CISTPL_SERIAL_UART_2STOP 0x40
+
+typedef struct cistpl_serial_t {
+ u_char uart_type;
+ u_char uart_cap_0;
+ u_char uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+ u_char flow;
+ u_char cmd_buf;
+ u_char rcv_buf_0, rcv_buf_1, rcv_buf_2;
+ u_char xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103 0x01
+#define CISTPL_SERIAL_MOD_V21 0x02
+#define CISTPL_SERIAL_MOD_V23 0x04
+#define CISTPL_SERIAL_MOD_V22 0x08
+#define CISTPL_SERIAL_MOD_212A 0x10
+#define CISTPL_SERIAL_MOD_V22BIS 0x20
+#define CISTPL_SERIAL_MOD_V26 0x40
+#define CISTPL_SERIAL_MOD_V26BIS 0x80
+#define CISTPL_SERIAL_MOD_V27BIS 0x01
+#define CISTPL_SERIAL_MOD_V29 0x02
+#define CISTPL_SERIAL_MOD_V32 0x04
+#define CISTPL_SERIAL_MOD_V32BIS 0x08
+#define CISTPL_SERIAL_MOD_V34 0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4 0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM 0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS 0x01
+#define CISTPL_SERIAL_CMPR_MNP5 0x02
+
+#define CISTPL_SERIAL_CMD_AT1 0x01
+#define CISTPL_SERIAL_CMD_AT2 0x02
+#define CISTPL_SERIAL_CMD_AT3 0x04
+#define CISTPL_SERIAL_CMD_MNP_AT 0x08
+#define CISTPL_SERIAL_CMD_V25BIS 0x10
+#define CISTPL_SERIAL_CMD_V25A 0x20
+#define CISTPL_SERIAL_CMD_DMCL 0x40
+
+typedef struct cistpl_data_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+ u_char modulation_0;
+ u_char modulation_1;
+ u_char error_control;
+ u_char compression;
+ u_char cmd_protocol;
+ u_char escape;
+ u_char encrypt;
+ u_char misc_features;
+ u_char ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+ u_char modulation;
+ u_char encrypt;
+ u_char features_0;
+ u_char features_1;
+ u_char ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+ LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH 0x01
+#define CISTPL_FUNCE_LAN_SPEED 0x02
+#define CISTPL_FUNCE_LAN_MEDIA 0x03
+#define CISTPL_FUNCE_LAN_NODE_ID 0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR 0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET 0x01
+#define CISTPL_LAN_TECH_ETHERNET 0x02
+#define CISTPL_LAN_TECH_TOKENRING 0x03
+#define CISTPL_LAN_TECH_LOCALTALK 0x04
+#define CISTPL_LAN_TECH_FDDI 0x05
+#define CISTPL_LAN_TECH_ATM 0x06
+#define CISTPL_LAN_TECH_WIRELESS 0x07
+
+typedef struct cistpl_lan_tech_t {
+ u_char tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+ u_int speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP 0x01
+#define CISTPL_LAN_MEDIA_STP 0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX 0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX 0x04
+#define CISTPL_LAN_MEDIA_FIBER 0x05
+#define CISTPL_LAN_MEDIA_900MHZ 0x06
+#define CISTPL_LAN_MEDIA_2GHZ 0x07
+#define CISTPL_LAN_MEDIA_5GHZ 0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR 0x09
+#define CISTPL_LAN_MEDIA_PTP_IR 0x0a
+
+typedef struct cistpl_lan_media_t {
+ u_char media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+ u_char nb;
+ u_char id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+ u_char code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+ IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE 0x01
+
+typedef struct cistpl_ide_interface_t {
+ u_char interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON 0x04
+#define CISTPL_IDE_UNIQUE 0x08
+#define CISTPL_IDE_DUAL 0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP 0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE 0x04
+#define CISTPL_IDE_LOW_POWER 0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX 0x20
+#define CISTPL_IDE_IOIS16 0x40
+
+typedef struct cistpl_ide_feature_t {
+ u_char feature1;
+ u_char feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER 0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/*======================================================================
+
+ Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE 0x07
+#define CISTPL_BAR_SPACE_IO 0x10
+#define CISTPL_BAR_PREFETCH 0x20
+#define CISTPL_BAR_CACHEABLE 0x40
+#define CISTPL_BAR_1MEG_MAP 0x80
+
+typedef struct cistpl_bar_t {
+ u_char attr;
+ u_int size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+ u_char last_idx;
+ u_int base;
+ u_int rmask[4];
+ u_char subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM 0
+#define CISTPL_POWER_VMIN 1
+#define CISTPL_POWER_VMAX 2
+#define CISTPL_POWER_ISTATIC 3
+#define CISTPL_POWER_IAVG 4
+#define CISTPL_POWER_IPEAK 5
+#define CISTPL_POWER_IDOWN 6
+
+#define CISTPL_POWER_HIGHZ_OK 0x01
+#define CISTPL_POWER_HIGHZ_REQ 0x02
+
+typedef struct cistpl_power_t {
+ u_char present;
+ u_char flags;
+ u_int param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+ u_int wait, waitscale;
+ u_int ready, rdyscale;
+ u_int reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK 0x1f
+#define CISTPL_IO_8BIT 0x20
+#define CISTPL_IO_16BIT 0x40
+#define CISTPL_IO_RANGE 0x80
+
+#define CISTPL_IO_MAX_WIN 16
+
+typedef struct cistpl_io_t {
+ u_char flags;
+ u_char nwin;
+ struct {
+ u_int base;
+ u_int len;
+ } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+ u_int IRQInfo1;
+ u_int IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN 8
+
+typedef struct cistpl_mem_t {
+ u_char flags;
+ u_char nwin;
+ struct {
+ u_int len;
+ u_int card_addr;
+ u_int host_addr;
+ } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT 0x0001
+#define CISTPL_CFTABLE_BVDS 0x0002
+#define CISTPL_CFTABLE_WP 0x0004
+#define CISTPL_CFTABLE_RDYBSY 0x0008
+#define CISTPL_CFTABLE_MWAIT 0x0010
+#define CISTPL_CFTABLE_AUDIO 0x0800
+#define CISTPL_CFTABLE_READONLY 0x1000
+#define CISTPL_CFTABLE_PWRDOWN 0x2000
+
+typedef struct cistpl_cftable_entry_t {
+ u_char index;
+ u_short flags;
+ u_char interface;
+ cistpl_power_t vcc, vpp1, vpp2;
+ cistpl_timing_t timing;
+ cistpl_io_t io;
+ cistpl_irq_t irq;
+ cistpl_mem_t mem;
+ u_char subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER 0x000100
+#define CISTPL_CFTABLE_INVALIDATE 0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE 0x000400
+#define CISTPL_CFTABLE_PARITY 0x000800
+#define CISTPL_CFTABLE_WAIT 0x001000
+#define CISTPL_CFTABLE_SERR 0x002000
+#define CISTPL_CFTABLE_FAST_BACK 0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO 0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+ u_char index;
+ u_int flags;
+ cistpl_power_t vcc, vpp1, vpp2;
+ u_char io;
+ cistpl_irq_t irq;
+ u_char mem;
+ u_char subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+ u_char ngeo;
+ struct {
+ u_char buswidth;
+ u_int erase_block;
+ u_int read_block;
+ u_int write_block;
+ u_int partition;
+ u_int interleave;
+ } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+ u_char vers;
+ u_char comply;
+ u_short dindex;
+ u_char vspec8, vspec9;
+ u_char nhdr;
+ u_char vendor, info;
+ char str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+ u_char data_org;
+ char desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS 0x00
+#define CISTPL_ORG_APPSPEC 0x01
+#define CISTPL_ORG_XIP 0x02
+
+typedef union cisparse_t {
+ cistpl_device_t device;
+ cistpl_checksum_t checksum;
+ cistpl_longlink_t longlink;
+ cistpl_longlink_mfc_t longlink_mfc;
+ cistpl_vers_1_t version_1;
+ cistpl_altstr_t altstr;
+ cistpl_jedec_t jedec;
+ cistpl_manfid_t manfid;
+ cistpl_funcid_t funcid;
+ cistpl_funce_t funce;
+ cistpl_bar_t bar;
+ cistpl_config_t config;
+ cistpl_cftable_entry_t cftable_entry;
+ cistpl_cftable_entry_cb_t cftable_entry_cb;
+ cistpl_device_geo_t device_geo;
+ cistpl_vers_2_t vers_2;
+ cistpl_org_t org;
+} cisparse_t;
+
+typedef struct tuple_t {
+ u_int Attributes;
+ cisdata_t DesiredTuple;
+ u_int Flags; /* internal use */
+ u_int LinkOffset; /* internal use */
+ u_int CISOffset; /* internal use */
+ cisdata_t TupleCode;
+ cisdata_t TupleLink;
+ cisdata_t TupleOffset;
+ cisdata_t TupleDataMax;
+ cisdata_t TupleDataLen;
+ cisdata_t *TupleData;
+} tuple_t;
+
+/* Special cisdata_t value */
+#define RETURN_FIRST_TUPLE 0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK 0x01
+#define TUPLE_RETURN_COMMON 0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+ u_int Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE 0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+ u_int Length;
+ cisdata_t Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+#endif /* LINUX_CISTPL_H */
--- /dev/null
+/*
+ * cs.h 1.66 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_H
+#define _LINUX_CS_H
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+ u_char Function;
+ u_int Action;
+ off_t Offset;
+ u_int Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ 1
+#define CS_WRITE 2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+ u_int Action;
+ u_int Resource;
+ u_int Attributes;
+ union {
+ struct memory {
+ u_long Base;
+ u_long Size;
+ } memory;
+ struct io {
+ ioaddr_t BasePort;
+ ioaddr_t NumPorts;
+ u_int IOAddrLines;
+ } io;
+ struct irq {
+ u_int IRQ;
+ } irq;
+ } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE 1
+#define ADD_MANAGED_RESOURCE 2
+#define GET_FIRST_MANAGED_RESOURCE 3
+#define GET_NEXT_MANAGED_RESOURCE 4
+/* Resource field */
+#define RES_MEMORY_RANGE 1
+#define RES_IO_RANGE 2
+#define RES_IRQ 3
+/* Attribute field */
+#define RES_IRQ_TYPE 0x03
+#define RES_IRQ_TYPE_EXCLUSIVE 0
+#define RES_IRQ_TYPE_TIME 1
+#define RES_IRQ_TYPE_DYNAMIC 2
+#define RES_IRQ_CSC 0x04
+#define RES_SHARED 0x08
+#define RES_RESERVED 0x10
+#define RES_ALLOCATED 0x20
+#define RES_REMOVED 0x40
+
+typedef struct servinfo_t {
+ char Signature[2];
+ u_int Count;
+ u_int Revision;
+ u_int CSLevel;
+ char *VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+ client_handle_t client_handle;
+ void *info;
+ void *mtdrequest;
+ void *buffer;
+ void *misc;
+ void *client_data;
+ struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+ u_char Function;
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+ u_int IntType;
+ u_int ConfigBase;
+ u_char Status, Pin, Copy, Option, ExtStatus;
+ u_int Present;
+ u_int CardValues;
+ u_int AssignedIRQ;
+ u_int IRQAttributes;
+ ioaddr_t BasePort1;
+ ioaddr_t NumPorts1;
+ u_int Attributes1;
+ ioaddr_t BasePort2;
+ ioaddr_t NumPorts2;
+ u_int Attributes2;
+ u_int IOAddrLines;
+} config_info_t;
+
+/* For CardValues field */
+#define CV_OPTION_VALUE 0x01
+#define CV_STATUS_VALUE 0x02
+#define CV_PIN_REPLACEMENT 0x04
+#define CV_COPY_VALUE 0x08
+#define CV_EXT_STATUS 0x10
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+ socket_t Socket;
+ u_int Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET 0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+ dev_info_t *dev_info;
+ u_int Attributes;
+ u_int EventMask;
+ int (*event_handler)(event_t event, int priority,
+ event_callback_args_t *);
+ event_callback_args_t event_callback_args;
+ u_int Version;
+} client_reg_t;
+
+/* ModifyConfiguration */
+typedef struct modconf_t {
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+} modconf_t;
+
+/* Attributes for ModifyConfiguration */
+#define CONF_IRQ_CHANGE_VALID 0x100
+#define CONF_VCC_CHANGE_VALID 0x200
+#define CONF_VPP1_CHANGE_VALID 0x400
+#define CONF_VPP2_CHANGE_VALID 0x800
+
+/* For RequestConfiguration */
+typedef struct config_req_t {
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+ u_int IntType;
+ u_int ConfigBase;
+ u_char Status, Pin, Copy, ExtStatus;
+ u_char ConfigIndex;
+ u_int Present;
+} config_req_t;
+
+/* Attributes for RequestConfiguration */
+#define CONF_ENABLE_IRQ 0x01
+#define CONF_ENABLE_DMA 0x02
+#define CONF_ENABLE_SPKR 0x04
+#define CONF_VALID_CLIENT 0x100
+
+/* IntType field */
+#define INT_MEMORY 0x01
+#define INT_MEMORY_AND_IO 0x02
+#define INT_CARDBUS 0x04
+
+/* For RequestIO and ReleaseIO */
+typedef struct io_req_t {
+ ioaddr_t BasePort1;
+ ioaddr_t NumPorts1;
+ u_int Attributes1;
+ ioaddr_t BasePort2;
+ ioaddr_t NumPorts2;
+ u_int Attributes2;
+ u_int IOAddrLines;
+} io_req_t;
+
+/* Attributes for RequestIO and ReleaseIO */
+#define IO_SHARED 0x01
+#define IO_FIRST_SHARED 0x02
+#define IO_FORCE_ALIAS_ACCESS 0x04
+#define IO_DATA_PATH_WIDTH 0x18
+#define IO_DATA_PATH_WIDTH_8 0x00
+#define IO_DATA_PATH_WIDTH_16 0x08
+#define IO_DATA_PATH_WIDTH_AUTO 0x10
+
+/* For RequestIRQ and ReleaseIRQ */
+typedef struct irq_req_t {
+ u_int Attributes;
+ u_int AssignedIRQ;
+ u_int IRQInfo1, IRQInfo2;
+ void *Handler;
+ void *Instance;
+} irq_req_t;
+
+/* Attributes for RequestIRQ and ReleaseIRQ */
+#define IRQ_TYPE 0x03
+#define IRQ_TYPE_EXCLUSIVE 0x00
+#define IRQ_TYPE_TIME 0x01
+#define IRQ_TYPE_DYNAMIC_SHARING 0x02
+#define IRQ_FORCED_PULSE 0x04
+#define IRQ_FIRST_SHARED 0x08
+#define IRQ_HANDLE_PRESENT 0x10
+#define IRQ_PULSE_ALLOCATED 0x100
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK 0x0f
+#define IRQ_NMI_ID 0x01
+#define IRQ_IOCK_ID 0x02
+#define IRQ_BERR_ID 0x04
+#define IRQ_VEND_ID 0x08
+#define IRQ_INFO2_VALID 0x10
+#define IRQ_LEVEL_ID 0x20
+#define IRQ_PULSE_ID 0x40
+#define IRQ_SHARE_ID 0x80
+
+typedef struct eventmask_t {
+ u_int Attributes;
+ u_int EventMask;
+} eventmask_t;
+
+#define CONF_EVENT_MASK_VALID 0x01
+
+/* Configuration registers present */
+#define PRESENT_OPTION 0x001
+#define PRESENT_STATUS 0x002
+#define PRESENT_PIN_REPLACE 0x004
+#define PRESENT_COPY 0x008
+#define PRESENT_EXT_STATUS 0x010
+#define PRESENT_IOBASE_0 0x020
+#define PRESENT_IOBASE_1 0x040
+#define PRESENT_IOBASE_2 0x080
+#define PRESENT_IOBASE_3 0x100
+#define PRESENT_IOSIZE 0x200
+
+/* Attributes for Request/GetConfiguration */
+#define CONF_ENABLE_IRQ 0x01
+#define EXCLUSIVE_USE 0x02
+#define VALID_CLIENT 0x04
+
+/* For MapMemPage */
+typedef struct memreq_t {
+ u_int CardOffset;
+ page_t Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+ u_int Attributes;
+ u_int AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+ u_int Attributes;
+ u_long Base;
+ u_int Size;
+ u_int AccessSpeed;
+} win_req_t;
+
+/* Attributes for RequestWindow */
+#define WIN_ADDR_SPACE 0x0001
+#define WIN_ADDR_SPACE_MEM 0x0000
+#define WIN_ADDR_SPACE_IO 0x0001
+#define WIN_MEMORY_TYPE 0x0002
+#define WIN_MEMORY_TYPE_CM 0x0000
+#define WIN_MEMORY_TYPE_AM 0x0002
+#define WIN_ENABLE 0x0004
+#define WIN_DATA_WIDTH 0x0018
+#define WIN_DATA_WIDTH_8 0x0000
+#define WIN_DATA_WIDTH_16 0x0008
+#define WIN_DATA_WIDTH_32 0x0010
+#define WIN_PAGED 0x0020
+#define WIN_SHARED 0x0040
+#define WIN_FIRST_SHARED 0x0080
+#define WIN_USE_WAIT 0x0100
+#define WIN_MAP_BELOW_1MB 0x0400
+#define WIN_PREFETCH 0x0800
+#define WIN_CACHEABLE 0x1000
+#define WIN_BAR_MASK 0xe000
+#define WIN_BAR_SHIFT 13
+
+/* Attributes for RegisterClient */
+#define INFO_MASTER_CLIENT 0x01
+#define INFO_IO_CLIENT 0x02
+#define INFO_MTD_CLIENT 0x04
+#define INFO_MEM_CLIENT 0x08
+#define MAX_NUM_CLIENTS 3
+
+#define INFO_CARD_SHARE 0x10
+#define INFO_CARD_EXCL 0x20
+
+typedef struct cs_status_t {
+ u_char Function;
+ event_t CardState;
+ event_t SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+ int func;
+ int retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+ socket_t Socket;
+ u_char Function;
+ dev_info_t *dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL 0xff
+
+typedef struct mtd_bind_t {
+ socket_t Socket;
+ u_int Attributes;
+ u_int CardOffset;
+ dev_info_t *dev_info;
+} mtd_bind_t;
+
+/* Events */
+#define CS_EVENT_PRI_LOW 0
+#define CS_EVENT_PRI_HIGH 1
+
+#define CS_EVENT_WRITE_PROTECT 0x000001
+#define CS_EVENT_CARD_LOCK 0x000002
+#define CS_EVENT_CARD_INSERTION 0x000004
+#define CS_EVENT_CARD_REMOVAL 0x000008
+#define CS_EVENT_BATTERY_DEAD 0x000010
+#define CS_EVENT_BATTERY_LOW 0x000020
+#define CS_EVENT_READY_CHANGE 0x000040
+#define CS_EVENT_CARD_DETECT 0x000080
+#define CS_EVENT_RESET_REQUEST 0x000100
+#define CS_EVENT_RESET_PHYSICAL 0x000200
+#define CS_EVENT_CARD_RESET 0x000400
+#define CS_EVENT_REGISTRATION_COMPLETE 0x000800
+#define CS_EVENT_RESET_COMPLETE 0x001000
+#define CS_EVENT_PM_SUSPEND 0x002000
+#define CS_EVENT_PM_RESUME 0x004000
+#define CS_EVENT_INSERTION_REQUEST 0x008000
+#define CS_EVENT_EJECTION_REQUEST 0x010000
+#define CS_EVENT_MTD_REQUEST 0x020000
+#define CS_EVENT_ERASE_COMPLETE 0x040000
+#define CS_EVENT_REQUEST_ATTENTION 0x080000
+#define CS_EVENT_CB_DETECT 0x100000
+#define CS_EVENT_3VCARD 0x200000
+#define CS_EVENT_XVCARD 0x400000
+
+/* Return codes */
+#define CS_SUCCESS 0x00
+#define CS_BAD_ADAPTER 0x01
+#define CS_BAD_ATTRIBUTE 0x02
+#define CS_BAD_BASE 0x03
+#define CS_BAD_EDC 0x04
+#define CS_BAD_IRQ 0x06
+#define CS_BAD_OFFSET 0x07
+#define CS_BAD_PAGE 0x08
+#define CS_READ_FAILURE 0x09
+#define CS_BAD_SIZE 0x0a
+#define CS_BAD_SOCKET 0x0b
+#define CS_BAD_TYPE 0x0d
+#define CS_BAD_VCC 0x0e
+#define CS_BAD_VPP 0x0f
+#define CS_BAD_WINDOW 0x11
+#define CS_WRITE_FAILURE 0x12
+#define CS_NO_CARD 0x14
+#define CS_UNSUPPORTED_FUNCTION 0x15
+#define CS_UNSUPPORTED_MODE 0x16
+#define CS_BAD_SPEED 0x17
+#define CS_BUSY 0x18
+#define CS_GENERAL_FAILURE 0x19
+#define CS_WRITE_PROTECTED 0x1a
+#define CS_BAD_ARG_LENGTH 0x1b
+#define CS_BAD_ARGS 0x1c
+#define CS_CONFIGURATION_LOCKED 0x1d
+#define CS_IN_USE 0x1e
+#define CS_NO_MORE_ITEMS 0x1f
+#define CS_OUT_OF_RESOURCE 0x20
+#define CS_BAD_HANDLE 0x21
+
+#define CS_BAD_TUPLE 0x40
+
+#ifdef __KERNEL__
+
+/*
+ * Calls to set up low-level "Socket Services" drivers
+ */
+
+typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg);
+extern int register_ss_entry(int nsock, ss_entry_t entry);
+extern void unregister_ss_entry(ss_entry_t entry);
+
+/*
+ * The main Card Services entry point
+ */
+
+enum service {
+ AccessConfigurationRegister, AddSocketServices,
+ AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+ DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+ GetClientInfo, GetConfigurationInfo, GetEventMask,
+ GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+ GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+ GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+ MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+ OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+ RegisterEraseQueue, RegisterMTD, RegisterTimer,
+ ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+ ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+ RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+ RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+ SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+ WriteMemory, BindDevice, BindMTD, ReportError,
+ SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS
+};
+
+#ifdef IN_CARD_SERVICES
+extern int CardServices(int func, void *a1, void *a2, void *a3);
+#else
+extern int CardServices(int func, ...);
+#endif
+
+#ifdef __BEOS__
+#define SS_MODULE_NAME(s) ("busses/pcmcia/" s "/v1")
+#define MTD_MODULE_NAME(s) ("busses/pcmcia/" s "/v1")
+#define CS_CLIENT_MODULE_NAME "bus_managers/pcmcia_cs/client/v1"
+typedef struct cs_client_module_info {
+ bus_manager_info binfo;
+ int (*_CardServices)(int, ...);
+ int (*_MTDHelperEntry)(int, ...);
+ void (*_add_timer)(struct timer_list *);
+ void (*_del_timer)(struct timer_list *);
+} cs_client_module_info;
+#define CS_SOCKET_MODULE_NAME "bus_managers/pcmcia_cs/socket/v1"
+typedef struct cs_socket_module_info {
+ bus_manager_info binfo;
+ int (*_register_ss_entry)(int, ss_entry_t);
+ void (*_unregister_ss_entry)(ss_entry_t);
+ void (*_add_timer)(struct timer_list *);
+ void (*_del_timer)(struct timer_list *);
+ int (*register_resource)(int, u_long, u_long);
+ int (*release_resource)(int, u_long, u_long);
+ int (*check_resource)(int, u_long, u_long);
+} cs_socket_module_info;
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_CS_H */
--- /dev/null
+/*
+ * cs_types.h 1.15 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_TYPES_H
+#define _LINUX_CS_TYPES_H
+
+#ifdef __linux__
+#include <linux/types.h>
+#endif
+
+typedef u_short socket_t;
+typedef u_short ioaddr_t;
+typedef u_int event_t;
+typedef u_char cisdata_t;
+typedef u_short page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+#endif /* _LINUX_CS_TYPES_H */
--- /dev/null
+/*
+ * driver_ops.h 1.13 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DRIVER_OPS_H
+#define _LINUX_DRIVER_OPS_H
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+#ifdef __KERNEL__
+
+typedef struct dev_node_t {
+ char dev_name[DEV_NAME_LEN];
+ u_short major, minor;
+ struct dev_node_t *next;
+} dev_node_t;
+
+typedef struct dev_locator_t {
+ enum { LOC_ISA, LOC_PCI } bus;
+ union {
+ struct {
+ u_short io_base_1, io_base_2;
+ u_long mem_base;
+ u_char irq, dma;
+ } isa;
+ struct {
+ u_char bus;
+ u_char devfn;
+ } pci;
+ } b;
+} dev_locator_t;
+
+typedef struct driver_operations {
+ char *name;
+ dev_node_t *(*attach) (dev_locator_t *loc);
+ void (*suspend) (dev_node_t *dev);
+ void (*resume) (dev_node_t *dev);
+ void (*detach) (dev_node_t *dev);
+} driver_operations;
+
+int register_driver(struct driver_operations *ops);
+void unregister_driver(struct driver_operations *ops);
+
+#ifdef __BEOS__
+#define CB_ENABLER_MODULE_NAME "bus_managers/cb_enabler/v1"
+typedef struct cb_enabler_module_info {
+ bus_manager_info binfo;
+ int (*register_driver)(struct driver_operations *ops);
+ void (*unregister_driver)(struct driver_operations *ops);
+} cb_enabler_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DRIVER_OPS_H */
--- /dev/null
+/*
+ * ds.h 1.53 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DS_H
+#define _LINUX_DS_H
+
+#include <pcmcia/driver_ops.h>
+#include <pcmcia/bulkmem.h>
+
+typedef struct tuple_parse_t {
+ tuple_t tuple;
+ cisdata_t data[255];
+ cisparse_t parse;
+} tuple_parse_t;
+
+typedef struct bind_info_t {
+ dev_info_t dev_info;
+ u_char function;
+ struct dev_link_t *instance;
+ char name[DEV_NAME_LEN];
+ u_short major, minor;
+ void *next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+ dev_info_t dev_info;
+ u_int Attributes;
+ u_int CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+ servinfo_t servinfo;
+ adjust_t adjust;
+ config_info_t config;
+ tuple_t tuple;
+ tuple_parse_t tuple_parse;
+ client_req_t client_req;
+ cs_status_t status;
+ conf_reg_t conf_reg;
+ cisinfo_t cisinfo;
+ region_info_t region;
+ bind_info_t bind_info;
+ mtd_info_t mtd_info;
+ cisdump_t cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t)
+#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
+#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t)
+#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t)
+#define DS_RESET_CARD _IO ('d', 8)
+#define DS_GET_STATUS _IOWR('d', 9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD _IO ('d', 12)
+#define DS_RESUME_CARD _IO ('d', 13)
+#define DS_EJECT_CARD _IO ('d', 14)
+#define DS_INSERT_CARD _IO ('d', 15)
+#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t)
+
+#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t)
+#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t)
+#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t)
+
+#ifdef __KERNEL__
+
+typedef struct dev_link_t {
+ dev_node_t *dev;
+ u_int state, open;
+ wait_queue_head_t pending;
+ struct timer_list release;
+ client_handle_t handle;
+ io_req_t io;
+ irq_req_t irq;
+ config_req_t conf;
+ window_handle_t win;
+ void *priv;
+ struct dev_link_t *next;
+} dev_link_t;
+
+/* Flags for device state */
+#define DEV_PRESENT 0x01
+#define DEV_CONFIG 0x02
+#define DEV_STALE_CONFIG 0x04 /* release on close */
+#define DEV_STALE_LINK 0x08 /* detach on release */
+#define DEV_CONFIG_PENDING 0x10
+#define DEV_RELEASE_PENDING 0x20
+#define DEV_SUSPEND 0x40
+#define DEV_BUSY 0x80
+
+#define DEV_OK(l) \
+ ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
+
+int register_pccard_driver(dev_info_t *dev_info,
+ dev_link_t *(*attach)(void),
+ void (*detach)(dev_link_t *));
+
+int unregister_pccard_driver(dev_info_t *dev_info);
+
+#define register_pcmcia_driver register_pccard_driver
+#define unregister_pcmcia_driver unregister_pccard_driver
+
+#ifdef __BEOS__
+#define DS_MODULE_NAME "bus_managers/pcmcia_ds/v1"
+typedef struct ds_module_info {
+ bus_manager_info binfo;
+ int (*_register_pccard_driver)(dev_info_t *,
+ dev_link_t *(*)(void),
+ void (*)(dev_link_t *));
+ int (*_unregister_pccard_driver)(dev_info_t *);
+ struct driver_info_t **root_driver;
+ int *sockets;
+ struct socket_info_t **socket_table;
+ sem_id *list_sem;
+} ds_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DS_H */
--- /dev/null
+/*
+ * ftl.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_FTL_H
+#define _LINUX_FTL_H
+
+typedef struct erase_unit_header_t {
+ u_char LinkTargetTuple[5];
+ u_char DataOrgTuple[10];
+ u_char NumTransferUnits;
+ u_int EraseCount;
+ u_short LogicalEUN;
+ u_char BlockSize;
+ u_char EraseUnitSize;
+ u_short FirstPhysicalEUN;
+ u_short NumEraseUnits;
+ u_int FormattedSize;
+ u_int FirstVMAddress;
+ u_short NumVMPages;
+ u_char Flags;
+ u_char Code;
+ u_int SerialNumber;
+ u_int AltEUHOffset;
+ u_int BAMOffset;
+ u_char Reserved[12];
+ u_char EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA 0x01
+#define REVERSE_POLARITY 0x02
+#define DOUBLE_BAI 0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b) ((b) == 0xffffffff)
+#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b) ((b) & 0x7f)
+#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
+#define BLOCK_NUMBER(b) ((b) >> 9)
+#define BLOCK_CONTROL 0x30
+#define BLOCK_DATA 0x40
+#define BLOCK_REPLACEMENT 0x60
+#define BLOCK_BAD 0x70
+
+#endif /* _LINUX_FTL_H */
--- /dev/null
+/*
+ * mem_op.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEM_OP_H
+#define _LINUX_MEM_OP_H
+
+#include <asm/uaccess.h>
+
+/*
+ If UNSAFE_MEMCPY is defined, we use the (optimized) system routines
+ to copy between a card and kernel memory. These routines do 32-bit
+ operations which may not work with all PCMCIA controllers. The
+ safe versions defined here will do only 8-bit and 16-bit accesses.
+*/
+
+#ifdef UNSAFE_MEMCPY
+
+#define copy_from_pc memcpy_fromio
+#define copy_to_pc memcpy_toio
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+ size_t odd = (n & 3);
+ n -= odd;
+ while (n) {
+ put_user(readl_ns(from), (int *)to);
+ (char *)from += 4; (char *)to += 4; n -= 4;
+ }
+ while (odd--)
+ put_user(readb((char *)from++), (char *)to++);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+ int l;
+ char c;
+ size_t odd = (n & 3);
+ n -= odd;
+ while (n) {
+ get_user(l, (int *)from);
+ writel_ns(l, to);
+ (char *)to += 4; (char *)from += 4; n -= 4;
+ }
+ while (odd--) {
+ get_user(c, (char *)from++);
+ writeb(c, (char *)to++);
+ }
+}
+
+#else /* UNSAFE_MEMCPY */
+
+static inline void copy_from_pc(void *to, const void *from, size_t n)
+{
+ size_t odd = (n & 1);
+ n -= odd;
+ while (n) {
+ *(u_short *)to = __raw_readw(from);
+ (char *)to += 2; (char *)from += 2; n -= 2;
+ }
+ if (odd)
+ *(u_char *)to = readb(from);
+}
+
+static inline void copy_to_pc(void *to, const void *from, size_t n)
+{
+ size_t odd = (n & 1);
+ n -= odd;
+ while (n) {
+ __raw_writew(*(u_short *)from, to);
+ (char *)to += 2; (char *)from += 2; n -= 2;
+ }
+ if (odd)
+ writeb(*(u_char *)from, to);
+}
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+ size_t odd = (n & 1);
+ n -= odd;
+ while (n) {
+ put_user(__raw_readw(from), (short *)to);
+ (char *)to += 2; (char *)from += 2; n -= 2;
+ }
+ if (odd)
+ put_user(readb(from), (char *)to);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+ short s;
+ char c;
+ size_t odd = (n & 1);
+ n -= odd;
+ while (n) {
+ get_user(s, (short *)from);
+ __raw_writew(s, to);
+ (char *)to += 2; (char *)from += 2; n -= 2;
+ }
+ if (odd) {
+ get_user(c, (char *)from);
+ writeb(c, to);
+ }
+}
+
+#endif /* UNSAFE_MEMCPY */
+
+#endif /* _LINUX_MEM_OP_H */
--- /dev/null
+/*
+ * memory.h 1.5 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEMORY_H
+#define _LINUX_MEMORY_H
+
+typedef struct erase_info_t {
+ u_long Offset;
+ u_long Size;
+} erase_info_t;
+
+#define MEMGETINFO _IOR('M', 1, region_info_t)
+#define MEMERASE _IOW('M', 2, erase_info_t)
+
+#endif /* _LINUX_MEMORY_H */
--- /dev/null
+/*
+ * ss.h 1.24 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SS_H
+#define _LINUX_SS_H
+
+/* For RegisterCallback */
+typedef struct ss_callback_t {
+ void (*handler)(void *info, u_int events);
+ void *info;
+} ss_callback_t;
+
+/* Definitions for card status flags for GetStatus */
+#define SS_WRPROT 0x0001
+#define SS_CARDLOCK 0x0002
+#define SS_EJECTION 0x0004
+#define SS_INSERTION 0x0008
+#define SS_BATDEAD 0x0010
+#define SS_BATWARN 0x0020
+#define SS_READY 0x0040
+#define SS_DETECT 0x0080
+#define SS_POWERON 0x0100
+#define SS_GPI 0x0200
+#define SS_STSCHG 0x0400
+#define SS_CARDBUS 0x0800
+#define SS_3VCARD 0x1000
+#define SS_XVCARD 0x2000
+
+/* for InquireSocket */
+typedef struct socket_cap_t {
+ u_int features;
+ u_int irq_mask;
+ u_int map_size;
+ u_char pci_irq;
+ u_char cardbus;
+ struct pci_bus *cb_bus;
+ struct bus_operations *bus;
+} socket_cap_t;
+
+/* InquireSocket capabilities */
+#define SS_CAP_PAGE_REGS 0x0001
+#define SS_CAP_VIRTUAL_BUS 0x0002
+#define SS_CAP_MEM_ALIGN 0x0004
+#define SS_CAP_PCCARD 0x4000
+#define SS_CAP_CARDBUS 0x8000
+
+/* for GetSocket, SetSocket */
+typedef struct socket_state_t {
+ u_int flags;
+ u_int csc_mask;
+ u_char Vcc, Vpp;
+ u_char io_irq;
+} socket_state_t;
+
+/* Socket configuration flags */
+#define SS_PWR_AUTO 0x0010
+#define SS_IOCARD 0x0020
+#define SS_RESET 0x0040
+#define SS_DMA_MODE 0x0080
+#define SS_SPKR_ENA 0x0100
+#define SS_OUTPUT_ENA 0x0200
+
+/* Flags for I/O port and memory windows */
+#define MAP_ACTIVE 0x01
+#define MAP_16BIT 0x02
+#define MAP_AUTOSZ 0x04
+#define MAP_0WS 0x08
+#define MAP_WRPROT 0x10
+#define MAP_ATTRIB 0x20
+#define MAP_USE_WAIT 0x40
+#define MAP_PREFETCH 0x80
+
+/* Use this just for bridge windows */
+#define MAP_IOSPACE 0x20
+
+typedef struct pccard_io_map {
+ u_char map;
+ u_char flags;
+ u_short speed;
+ u_short start, stop;
+} pccard_io_map;
+
+typedef struct pccard_mem_map {
+ u_char map;
+ u_char flags;
+ u_short speed;
+ u_long sys_start, sys_stop;
+ u_int card_start;
+} pccard_mem_map;
+
+typedef struct cb_bridge_map {
+ u_char map;
+ u_char flags;
+ u_int start, stop;
+} cb_bridge_map;
+
+enum ss_service {
+ SS_RegisterCallback, SS_InquireSocket,
+ SS_GetStatus, SS_GetSocket, SS_SetSocket,
+ SS_GetIOMap, SS_SetIOMap, SS_GetMemMap, SS_SetMemMap,
+ SS_GetBridge, SS_SetBridge, SS_ProcSetup
+};
+
+#endif /* _LINUX_SS_H */
--- /dev/null
+/* version.h 1.72 1999/08/05 06:09:53 (David Hinds) */
+
+#define CS_RELEASE "3.1.0"
+#define CS_RELEASE_CODE 0x3100
extern void sysctl_init(void);
extern void filescache_init(void);
extern void signals_init(void);
+extern int pcmcia_init(void);
extern void free_initmem(void);
extern void filesystem_setup(void);
#ifdef CONFIG_IRDA
irda_device_init(); /* Must be done after protocol initialization */
#endif
-
+#ifdef CONFIG_PCMCIA
+ pcmcia_init(); /* Do this last */
+#endif
/* Mount the root filesystem.. */
mount_root();
/* resource handling */
EXPORT_SYMBOL(request_resource);
EXPORT_SYMBOL(release_resource);
+EXPORT_SYMBOL(allocate_resource);
EXPORT_SYMBOL(__request_region);
EXPORT_SYMBOL(__check_region);
EXPORT_SYMBOL(__release_region);
struct dentry * dentry = file->f_dentry;
struct inode * inode = dentry->d_inode;
struct page * page, **hash;
- unsigned long old_page, new_page = 0;
+ unsigned long old_page;
unsigned long offset = address - area->vm_start + area->vm_offset;
* and possibly copy it over to another page..
*/
old_page = page_address(page);
- if (!no_share) {
- flush_page_to_ram(old_page);
- return old_page;
- }
+ if (no_share) {
+ unsigned long new_page = page_cache_alloc();
- new_page = page_cache_alloc();
- if (new_page) {
- copy_page(new_page, old_page);
- flush_page_to_ram(new_page);
+ if (new_page) {
+ copy_page(new_page, old_page);
+ flush_page_to_ram(new_page);
+ }
+ page_cache_release(page);
+ return new_page;
}
- page_cache_release(page);
- return new_page;
+
+ flush_page_to_ram(old_page);
+ return old_page;
no_cached_page:
/*
* mm layer so, possibly freeing the page cache page first.
*/
page_cache_release(page);
- if (new_page)
- page_cache_free(new_page);
return 0;
}
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <net/checksum.h>
+#include <net/sock.h>
/*
* Verify iovec. The caller must ensure that the iovec is big enough
*/
-static char NoPerm[] = "403 Permission denied\r\nServer: kHTTPd 0.1.6\r\n\r\n Permission denied";
-static char TryLater[] = "500 Try again later\r\nServer: kHTTPd 0.1.6\r\n\r\n Try again later";
-static char NotModified[] = "304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char NoPerm[] = "HTTP/1.0 403 Forbidden\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char TryLater[] = "HTTP/1.0 503 Service Unavailable\r\nServer: kHTTPd 0.1.6\r\nContent-Length: 15\r\n\r\nTry again later";
+static char NotModified[] = "HTTP/1.0 304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
void Send403(struct socket *sock)
void Send304(struct socket *sock)
{
EnterFunction("Send304");
- (void)SendBuffer(sock,NotModified,strlen(NoPerm));
+ (void)SendBuffer(sock,NotModified,strlen(NotModified));
LeaveFunction("Send304");
}