summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
commit95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch)
tree27a92a942821cde1edda9a1b088718d436b3efe4 /drivers
parent45b27b0a0652331d104c953a5b192d843fff88f8 (diff)
Merge with Linux 2.3.40.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile11
-rw-r--r--drivers/acorn/block/fd1772.c6
-rw-r--r--drivers/acorn/block/mfmhd.c112
-rw-r--r--drivers/acorn/scsi/Config.in10
-rw-r--r--drivers/ap1000/ap.c2
-rw-r--r--drivers/ap1000/ddv.c34
-rw-r--r--drivers/atm/nicstar.c2
-rw-r--r--drivers/block/Config.in24
-rw-r--r--drivers/block/DAC960.c26
-rw-r--r--drivers/block/Makefile8
-rw-r--r--drivers/block/acsi.c72
-rw-r--r--drivers/block/aec6210.c2
-rw-r--r--drivers/block/alim15x3.c564
-rw-r--r--drivers/block/amd7409.c290
-rw-r--r--drivers/block/amiflop.c10
-rw-r--r--drivers/block/ataflop.c6
-rw-r--r--drivers/block/cmd646.c289
-rw-r--r--drivers/block/cmd64x.c340
-rw-r--r--drivers/block/cpqarray.c40
-rw-r--r--drivers/block/cy82c693.c6
-rw-r--r--drivers/block/floppy.c16
-rw-r--r--drivers/block/genhd.c4
-rw-r--r--drivers/block/hd.c65
-rw-r--r--drivers/block/hpt34x.c2
-rw-r--r--drivers/block/hpt366.c53
-rw-r--r--drivers/block/ide-cd.c81
-rw-r--r--drivers/block/ide-disk.c73
-rw-r--r--drivers/block/ide-dma.c2
-rw-r--r--drivers/block/ide-features.c22
-rw-r--r--drivers/block/ide-geometry.c19
-rw-r--r--drivers/block/ide-pci.c94
-rw-r--r--drivers/block/ide-probe.c2
-rw-r--r--drivers/block/ide-tape.c540
-rw-r--r--drivers/block/ide.c118
-rw-r--r--drivers/block/loop.c7
-rw-r--r--drivers/block/md.c17
-rw-r--r--drivers/block/nbd.c4
-rw-r--r--drivers/block/paride/pd.c89
-rw-r--r--drivers/block/paride/pf.c15
-rw-r--r--drivers/block/pdc202xx.c4
-rw-r--r--drivers/block/piix.c2
-rw-r--r--drivers/block/ps2esdi.c30
-rw-r--r--drivers/block/raid0.c6
-rw-r--r--drivers/block/rd.c9
-rw-r--r--drivers/block/sis5513.c5
-rw-r--r--drivers/block/swim3.c2
-rw-r--r--drivers/block/swim_iop.c2
-rw-r--r--drivers/block/via82cxxx.c2
-rw-r--r--drivers/block/xd.c79
-rw-r--r--drivers/block/xd.h2
-rw-r--r--drivers/block/z2ram.c2
-rw-r--r--drivers/cdrom/aztcd.c3
-rw-r--r--drivers/cdrom/cdrom.c8
-rw-r--r--drivers/cdrom/gscd.c3
-rw-r--r--drivers/cdrom/optcd.c3
-rw-r--r--drivers/cdrom/sjcd.c3
-rw-r--r--drivers/cdrom/sonycd535.c6
-rw-r--r--drivers/char/Config.in32
-rw-r--r--drivers/char/Makefile16
-rw-r--r--drivers/char/acquirewdt.c2
-rw-r--r--drivers/char/bttv.c144
-rw-r--r--drivers/char/bttv.h28
-rw-r--r--drivers/char/cyclades.c245
-rw-r--r--drivers/char/keyboard.c3
-rw-r--r--drivers/char/moxa.c3320
-rw-r--r--drivers/char/msp3400.c174
-rw-r--r--drivers/char/mxser.c2451
-rw-r--r--drivers/char/pcmcia/Config.in28
-rw-r--r--drivers/char/pcmcia/serial_cb.c9
-rw-r--r--drivers/char/pcmcia/serial_cs.c33
-rw-r--r--drivers/char/pcwd.c6
-rw-r--r--drivers/char/radio-cadet.c1
-rw-r--r--drivers/char/stradis.c2
-rw-r--r--drivers/char/tda8425.c6
-rw-r--r--drivers/char/tda9855.c13
-rw-r--r--drivers/char/tea6300.c6
-rw-r--r--drivers/char/tty_io.c8
-rw-r--r--drivers/char/vc_screen.c2
-rw-r--r--drivers/fc4/Makefile2
-rw-r--r--drivers/i2o/i2o_block.c21
-rw-r--r--drivers/i2o/i2o_config.c316
-rw-r--r--drivers/i2o/i2o_core.c630
-rw-r--r--drivers/i2o/i2o_lan.c142
-rw-r--r--drivers/i2o/i2o_lan.h2
-rw-r--r--drivers/i2o/i2o_proc.c367
-rw-r--r--drivers/ieee1394/.cvsignore4
-rw-r--r--drivers/ieee1394/Config.in24
-rw-r--r--drivers/ieee1394/Makefile75
-rw-r--r--drivers/ieee1394/aic5800.c897
-rw-r--r--drivers/ieee1394/aic5800.h292
-rw-r--r--drivers/ieee1394/csr.c435
-rw-r--r--drivers/ieee1394/csr.h55
-rw-r--r--drivers/ieee1394/highlevel.c402
-rw-r--r--drivers/ieee1394/highlevel.h133
-rw-r--r--drivers/ieee1394/hosts.c344
-rw-r--r--drivers/ieee1394/hosts.h192
-rw-r--r--drivers/ieee1394/ieee1394.h66
-rw-r--r--drivers/ieee1394/ieee1394_core.c698
-rw-r--r--drivers/ieee1394/ieee1394_core.h152
-rw-r--r--drivers/ieee1394/ieee1394_syms.c59
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c514
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h69
-rw-r--r--drivers/ieee1394/ieee1394_types.h86
-rw-r--r--drivers/ieee1394/ohci1394.c1403
-rw-r--r--drivers/ieee1394/ohci1394.h290
-rw-r--r--drivers/ieee1394/pcilynx.c1469
-rw-r--r--drivers/ieee1394/pcilynx.h528
-rw-r--r--drivers/ieee1394/raw1394.c823
-rw-r--r--drivers/ieee1394/raw1394.h110
-rw-r--r--drivers/net/3c509.c5
-rw-r--r--drivers/net/3c527.c37
-rw-r--r--drivers/net/Config.in3
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/lance.c12
-rw-r--r--drivers/net/oaknet.c544
-rw-r--r--drivers/net/pcmcia/3c574_cs.c148
-rw-r--r--drivers/net/pcmcia/3c575_cb.c108
-rw-r--r--drivers/net/pcmcia/3c589_cs.c137
-rw-r--r--drivers/net/pcmcia/Config.in4
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c152
-rw-r--r--drivers/net/pcmcia/netwave_cs.c88
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c417
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c77
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c372
-rw-r--r--drivers/net/pcmcia/tulip_cb.c323
-rw-r--r--drivers/net/pcmcia/wavelan_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c193
-rw-r--r--drivers/net/pcnet32.c1
-rw-r--r--drivers/net/plip.c24
-rw-r--r--drivers/net/setup.c8
-rw-r--r--drivers/net/shaper.c7
-rw-r--r--drivers/net/smc-ultra.c8
-rw-r--r--drivers/net/tlan.c79
-rw-r--r--drivers/net/tlan.h5
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tokenring/olympic.c108
-rw-r--r--drivers/net/tokenring/olympic.h3
-rw-r--r--drivers/net/tokenring/tms380tr.c4
-rw-r--r--drivers/net/tulip.c5
-rw-r--r--drivers/net/wan/cycx_drv.c57
-rw-r--r--drivers/net/wan/cycx_main.c68
-rw-r--r--drivers/net/wan/cycx_x25.c191
-rw-r--r--drivers/net/wan/syncppp.c6
-rw-r--r--drivers/net/wan/z85230.c119
-rw-r--r--drivers/net/wan/z85230.h3
-rw-r--r--drivers/parport/Config.in2
-rw-r--r--drivers/parport/ieee1284_ops.c1
-rw-r--r--drivers/parport/parport_pc.c25
-rw-r--r--drivers/pci/Makefile4
-rw-r--r--drivers/pci/helper.c69
-rw-r--r--drivers/pci/pci.c133
-rw-r--r--drivers/pci/pci.ids9
-rw-r--r--drivers/pci/pcisyms.c10
-rw-r--r--drivers/pci/proc.c4
-rw-r--r--drivers/pci/setup-bus.c (renamed from drivers/pci/setup.c)177
-rw-r--r--drivers/pci/setup-irq.c71
-rw-r--r--drivers/pci/setup-res.c164
-rw-r--r--drivers/pci/syscall.c4
-rw-r--r--drivers/pcmcia/bulkmem.c7
-rw-r--r--drivers/pcmcia/cardbus.c147
-rw-r--r--drivers/pcmcia/cb_enabler.c18
-rw-r--r--drivers/pcmcia/cistpl.c112
-rw-r--r--drivers/pcmcia/cs.c126
-rw-r--r--drivers/pcmcia/ds.c91
-rw-r--r--drivers/pcmcia/i82365.c1
-rw-r--r--drivers/pcmcia/pci_socket.c7
-rw-r--r--drivers/pcmcia/pci_socket.h11
-rw-r--r--drivers/pcmcia/ricoh.h72
-rw-r--r--drivers/pcmcia/rsrc_mgr.c47
-rw-r--r--drivers/pcmcia/tcic.c7
-rw-r--r--drivers/pcmcia/ti113x.h125
-rw-r--r--drivers/pcmcia/yenta.c204
-rw-r--r--drivers/pnp/Makefile28
-rw-r--r--drivers/pnp/isapnp.c50
-rw-r--r--drivers/pnp/isapnp_proc.c265
-rw-r--r--drivers/pnp/quirks.c10
-rw-r--r--drivers/sbus/char/envctrl.c6
-rw-r--r--drivers/sbus/char/pcikbd.c2
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx6
-rw-r--r--drivers/scsi/ChangeLog.sym53c8xx6
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/g_NCR5380.c4
-rw-r--r--drivers/scsi/ide-scsi.c12
-rw-r--r--drivers/scsi/megaraid.c618
-rw-r--r--drivers/scsi/megaraid.h36
-rw-r--r--drivers/scsi/ncr53c8xx.c64
-rw-r--r--drivers/scsi/psi240i.h3
-rw-r--r--drivers/scsi/scsi.c10
-rw-r--r--drivers/scsi/scsi_lib.c8
-rw-r--r--drivers/scsi/scsi_queue.c3
-rw-r--r--drivers/scsi/sd.c54
-rw-r--r--drivers/scsi/seagate.c4
-rw-r--r--drivers/scsi/sym53c416.h2
-rw-r--r--drivers/scsi/sym53c8xx.c17
-rw-r--r--drivers/scsi/sym53c8xx.h2
-rw-r--r--drivers/scsi/sym53c8xx_defs.h2
-rw-r--r--drivers/sound/cmpci.c3
-rw-r--r--drivers/sound/es1370.c48
-rw-r--r--drivers/sound/es1371.c48
-rw-r--r--drivers/sound/esssolo1.c221
-rw-r--r--drivers/sound/msnd.c41
-rw-r--r--drivers/sound/msnd.h10
-rw-r--r--drivers/sound/msnd_classic.h6
-rw-r--r--drivers/sound/msnd_pinnacle.c53
-rw-r--r--drivers/sound/msnd_pinnacle.h22
-rw-r--r--drivers/sound/sonicvibes.c44
-rw-r--r--drivers/sound/sscape.c679
-rw-r--r--drivers/sound/trident.c19
-rw-r--r--drivers/telephony/ixj.c2
-rw-r--r--drivers/usb/Config.in20
-rw-r--r--drivers/usb/Makefile7
-rw-r--r--drivers/usb/acm.c206
-rw-r--r--drivers/usb/dc2xx.c210
-rw-r--r--drivers/usb/devices.c526
-rw-r--r--drivers/usb/devio.c1021
-rw-r--r--drivers/usb/drivers.c126
-rw-r--r--drivers/usb/ezusb.c1096
-rw-r--r--drivers/usb/ezusb.h126
-rw-r--r--drivers/usb/graphire.c186
-rw-r--r--drivers/usb/hid-debug.h4
-rw-r--r--drivers/usb/hid.c158
-rw-r--r--drivers/usb/hid.h66
-rw-r--r--drivers/usb/hub.c31
-rw-r--r--drivers/usb/hub.h7
-rw-r--r--drivers/usb/inode.c729
-rw-r--r--drivers/usb/joydev.c6
-rw-r--r--drivers/usb/keybdev.c29
-rw-r--r--drivers/usb/mousedev.c4
-rw-r--r--drivers/usb/ohci-hcd.c109
-rw-r--r--drivers/usb/ohci-hcd.h7
-rw-r--r--drivers/usb/ov511.c709
-rw-r--r--drivers/usb/ov511.h53
-rw-r--r--drivers/usb/printer.c713
-rw-r--r--drivers/usb/proc_usb.c1189
-rw-r--r--drivers/usb/scanner.c11
-rw-r--r--drivers/usb/usb-core.c22
-rw-r--r--drivers/usb/usb-debug.c28
-rw-r--r--drivers/usb/usb-serial.c854
-rw-r--r--drivers/usb/usb.c160
-rw-r--r--drivers/usb/usb.h201
-rw-r--r--drivers/usb/usb_scsi.c47
-rw-r--r--drivers/usb/usbdevice_fs.h168
-rw-r--r--drivers/usb/usbkbd.c31
-rw-r--r--drivers/usb/whiteheat.h1542
-rw-r--r--drivers/usb/wmforce.c165
-rw-r--r--drivers/video/aty128.h279
-rw-r--r--drivers/video/atyfb.c92
-rw-r--r--drivers/video/dummycon.c2
248 files changed, 29089 insertions, 9611 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 1585fed46..71ee973cf 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -9,7 +9,7 @@
SUB_DIRS := block char net parport sound misc
MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
+ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o ieee1394 \
macintosh video dio zorro fc4 usb \
nubus tc ap1000 atm pcmcia i2c telephony
@@ -100,6 +100,15 @@ else
endif
endif
+ifeq ($(CONFIG_IEEE1394),y)
+SUB_DIRS += ieee1394
+MOD_SUB_DIRS += ieee1394
+else
+ ifeq ($(CONFIG_IEEE1394),m)
+ MOD_SUB_DIRS += ieee1394
+ endif
+endif
+
ifeq ($(CONFIG_PNP),y)
SUB_DIRS += pnp
MOD_SUB_DIRS += pnp
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index cd2513b42..54ed9ac6b 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -1556,11 +1556,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
static void floppy_release(struct inode *inode, struct file *filp)
{
- int drive;
-
- drive = MINOR(inode->i_rdev) & 3;
-
- block_fsync(inode, filp);
+ int drive = MINOR(inode->i_rdev) & 3;
if (fd_ref[drive] < 0)
fd_ref[drive] = 0;
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 5931e1d93..d30251fbb 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -115,6 +115,7 @@
#define MAJOR_NR MFM_ACORN_MAJOR
#include <linux/blk.h>
+#include <linux/blkpg.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -975,7 +976,7 @@ static void mfm_request(void)
DBG("mfm_request: Dropping out bottom\n");
}
-static void do_mfm_request(void)
+static void do_mfm_request(request_queue_t *q)
{
DBG("do_mfm_request: about to mfm_request\n");
mfm_request();
@@ -1017,8 +1018,7 @@ static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs
/*
- * Tell the user about the drive if we decided it exists. Also,
- * set the size of the drive.
+ * Tell the user about the drive if we decided it exists.
*/
static void mfm_geometry (int drive)
{
@@ -1027,8 +1027,6 @@ static void mfm_geometry (int drive)
mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096,
mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors,
mfm_info[drive].lowcurrent, mfm_info[drive].precomp);
- mfm[drive << 6].start_sect = 0;
- mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2;
}
#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
@@ -1210,24 +1208,6 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
return -EFAULT;
return 0;
- case BLKFLSBUF:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- fsync_dev(dev);
- invalidate_buffers(dev);
- return 0;
-
- case BLKRASET:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (arg > 0xff)
- return -EINVAL;
- read_ahead[major] = arg;
- return 0;
-
- case BLKRAGET:
- return put_user(read_ahead[major], (long *)arg);
-
case BLKGETSIZE:
return put_user (mfm[minor].nr_sects, (long *)arg);
@@ -1248,7 +1228,13 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
return -EACCES;
return mfm_reread_partitions(dev);
- RO_IOCTLS(dev, arg);
+ case BLKFLSBUF:
+ case BLKROSET:
+ case BLKROGET:
+ case BLKRASET:
+ case BLKRAGET:
+ case BLKPG:
+ return blk_ioctl(dev, cmd, arg);
default:
return -EINVAL;
@@ -1276,7 +1262,6 @@ static int mfm_open(struct inode *inode, struct file *file)
*/
static int mfm_release(struct inode *inode, struct file *file)
{
- fsync_dev(inode->i_rdev);
mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--;
MOD_DEC_USE_COUNT;
return 0;
@@ -1295,6 +1280,7 @@ void mfm_setup(char *str, int *ints)
* Set the CHS from the ADFS boot block if it is present. This is not ideal
* since if there are any non-ADFS partitions on the disk, this won't work!
* Hence, I want to get rid of this...
+ * Please, do. It does seriously sucking things.
*/
void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
unsigned long discsize, unsigned int secsize)
@@ -1320,18 +1306,16 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
if (raw_cmd.dev == drive)
mfm_specify ();
mfm_geometry (drive);
+ mfm[drive << 6].start_sect = 0;
+ mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2;
}
}
-static void mfm_geninit (struct gendisk *gdev);
-
static struct gendisk mfm_gendisk = {
MAJOR_NR, /* Major number */
"mfm", /* Major name */
6, /* Bits to shift to get real from partition */
1 << 6, /* Number of partitions per real */
- MFM_MAXDRIVES, /* maximum number of real */
- mfm_geninit, /* init function */
mfm, /* hd struct */
mfm_sizes, /* block sizes */
0, /* number */
@@ -1339,17 +1323,30 @@ static struct gendisk mfm_gendisk = {
NULL /* next */
};
-static void mfm_geninit (struct gendisk *gdev)
+static struct block_device_operations mfm_fops =
+{
+ open: mfm_open,
+ release: mfm_release,
+ ioctl: mfm_ioctl,
+};
+
+static void mfm_geninit (void)
{
int i;
- mfm_drives = mfm_initdrives();
+ for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
+ /* Can't increase this - if you do all hell breaks loose */
+ mfm_blocksizes[i] = 1024;
+ mfm_sectsizes[i] = 512;
+ }
+ blksize_size[MAJOR_NR] = mfm_blocksizes;
+ hardsect_size[MAJOR_NR] = mfm_sectsizes;
- printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s");
- gdev->nr_real = mfm_drives;
+ mfm_drives = mfm_initdrives();
- for (i = 0; i < mfm_drives; i++)
- mfm_geometry (i);
+ printk("mfm: detected %d hard drive%s\n", mfm_drives,
+ mfm_drives == 1 ? "" : "s");
+ mfm_gendisk.nr_real = mfm_drives;
if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL))
printk("mfm: unable to get IRQ%d\n", mfm_irq);
@@ -1357,22 +1354,15 @@ static void mfm_geninit (struct gendisk *gdev)
if (mfm_irqenable)
outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */
- for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
- mfm_blocksizes[i] = 1024; /* Can't increase this - if you do all hell breaks loose */
- mfm_sectsizes[i] = 512;
+ for (i = 0; i < mfm_drives; i++) {
+ mfm_geometry (i);
+ register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6,
+ &mfm_fops,
+ mfm_info[i].cylinders * mfm_info[i].heads *
+ mfm_info[i].sectors / 2);
}
- blksize_size[MAJOR_NR] = mfm_blocksizes;
- hardsect_size[MAJOR_NR] = mfm_sectsizes;
}
-static struct block_device_operations mfm_fops =
-{
- open: mfm_open,
- release: mfm_release,
- ioctl: mfm_ioctl,
-};
-
-
static struct expansion_card *ecs;
/*
@@ -1422,11 +1412,6 @@ int mfm_init (void)
{
unsigned char irqmask;
- if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
- printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
- return -1;
- }
-
if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
mfm_addr = ONBOARD_MFM_ADDRESS;
mfm_IRQPollLoc = IOC_IRQSTATB;
@@ -1449,6 +1434,12 @@ int mfm_init (void)
ecard_claim(ecs);
}
+ if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
+ printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
+ ecard_release(ecs);
+ return -1;
+ }
+
printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
request_region (mfm_addr, 10, "mfm");
@@ -1457,7 +1448,7 @@ int mfm_init (void)
hdc63463_irqpolladdress = ioaddr(mfm_IRQPollLoc);
hdc63463_irqpollmask = irqmask;
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB?) read ahread */
#ifndef MODULE
@@ -1468,6 +1459,7 @@ int mfm_init (void)
Busy = 0;
lastspecifieddrive = -1;
+ mfm_geninit();
return 0;
}
@@ -1506,10 +1498,10 @@ static int mfm_reread_partitions(kdev_t dev)
mfm_gendisk.part[minor].nr_sects = 0;
}
- mfm_gendisk.part[start].nr_sects = mfm_info[target].heads *
- mfm_info[target].cylinders * mfm_info[target].sectors / 2;
+ /* Divide by 2, since sectors are 2 times smaller than usual ;-) */
- resetup_one_dev(&mfm_gendisk, target);
+ grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads *
+ mfm_info[target].cylinders * mfm_info[target].sectors / 2);
mfm_info[target].busy = 0;
wake_up (&mfm_wait_open);
@@ -1519,11 +1511,7 @@ static int mfm_reread_partitions(kdev_t dev)
#ifdef MODULE
int init_module(void)
{
- int ret;
- ret = mfm_init();
- if (!ret)
- mfm_geninit(&mfm_gendisk);
- return ret;
+ return mfm_init();
}
void cleanup_module(void)
diff --git a/drivers/acorn/scsi/Config.in b/drivers/acorn/scsi/Config.in
index 28030bc32..60a5e0a80 100644
--- a/drivers/acorn/scsi/Config.in
+++ b/drivers/acorn/scsi/Config.in
@@ -6,12 +6,12 @@ if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then
bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'ARXE SCSI support (EXPERIMENTAL)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
- dep_tristate 'CumanaSCSI II support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
- dep_tristate 'EESOX support (EXPERIMENTAL)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
- dep_tristate 'PowerTec support (EXPERIMENTAL)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
+dep_tristate 'ARXE SCSI support' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
+dep_tristate 'CumanaSCSI II support' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
+dep_tristate 'EESOX support' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
+dep_tristate 'PowerTec support' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
comment 'The following drivers are not fully supported'
dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
diff --git a/drivers/ap1000/ap.c b/drivers/ap1000/ap.c
index 66c37290c..6e05d7cb5 100644
--- a/drivers/ap1000/ap.c
+++ b/drivers/ap1000/ap.c
@@ -274,6 +274,8 @@ int ap_init(void)
blksize_size[MAJOR_NR] = ap_blocksizes;
read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
+ for (i=0;i<NUM_APDEVS;i++)
+ register_disk(NILL, MKDEV(MAJOR_NR,i), 1, &ap_fops, 0);
return(0);
}
diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c
index 4ab72a361..3e32c9c83 100644
--- a/drivers/ap1000/ddv.c
+++ b/drivers/ap1000/ddv.c
@@ -76,7 +76,7 @@ extern void ddv_load_kernel(char *opcodep);
extern int ddv_restart_cpu(void);
extern int ddv_mlist_available(void);
static int ddv_revalidate(kdev_t dev, struct gendisk *gdev);
-static void ddv_geninit(struct gendisk *ignored);
+static void ddv_geninit(void);
static void ddv_release(struct inode * inode, struct file * filp);
static void ddv_request1(void);
@@ -109,12 +109,6 @@ static struct gendisk ddv_gendisk = {
DEVICE_NAME, /* Major name */
PARTN_BITS, /* Bits to shift to get real from partition */
1 << PARTN_BITS, /* Number of partitions per real */
- 1, /* maximum number of real */
-#ifdef MODULE
- NULL, /* called from init_module */
-#else
- ddv_geninit, /* init function */
-#endif
partition_tables,/* hd struct */
ddv_blk_length, /* block sizes */
1, /* number */
@@ -122,7 +116,6 @@ static struct gendisk ddv_gendisk = {
NULL /* next */
};
-
struct ddv_geometry {
unsigned char heads;
unsigned char sectors;
@@ -166,7 +159,6 @@ static void ddv_release(struct inode * inode, struct file * filp)
#if DEBUG
printk("ddv_release started\n");
#endif
- sync_dev(inode->i_rdev);
#if DEBUG
printk("ddv_release done\n");
#endif
@@ -386,10 +378,11 @@ static int ddv_daemon(void *unused)
save_flags(flags); cli();
while (!rem_queue) {
- spin_lock_irq(&current->sigmask_lock);
+ spin_lock(&current->sigmask_lock);
flush_signals(current);
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock(&current->sigmask_lock);
interruptible_sleep_on(&ddv_daemon_wait);
+ __sti(); cli();
}
rem = rem_queue;
@@ -695,6 +688,7 @@ static void ddv_open_reply(struct cap_request *creq)
wake_up(&busy_wait);
}
+extern struct block_device_operations ddv_fops;
static void ddv_load_opiu(void)
{
@@ -738,11 +732,10 @@ static void ddv_load_opiu(void)
ddv_geometry.cylinders = ddv_sect_length[0] /
(ddv_geometry.heads*ddv_geometry.sectors);
- ddv_gendisk.part[0].start_sect = 0;
- ddv_gendisk.part[0].nr_sects = ddv_sect_length[0];
-
- resetup_one_dev(&ddv_gendisk, 0);
+ register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<<PARTN_BITS,
+ &ddv_fops, ddv_sect_length[0]);
+ /* FIXME. The crap below is, well, crap. Pseudo-RAID and unsafe one */
for (i=0;i<PARDISK_BASE;i++) {
ddv_sect_length[i] = ddv_gendisk.part[i].nr_sects;
ddv_blk_length[i] = ddv_gendisk.part[i].nr_sects >> 1;
@@ -794,8 +787,7 @@ static int ddv_revalidate(kdev_t dev, struct gendisk *gdev)
ddv_sect_length[start] = DiskInfo->blocks;
ddv_blk_length[start] = DiskInfo->blocks >> 1;
- gdev->part[start].nr_sects = ddv_sect_length[start];
- resetup_one_dev(gdev, target);
+ grok_partitions(gdev, target, 1<<PARTN_BITS, ddv_sect_length[start]);
printk("sect_length[%d]=%d blk_length[%d]=%d\n",
start,ddv_sect_length[start],
@@ -936,11 +928,13 @@ int ddv_init(void)
kernel_thread(ddv_daemon, NULL, 0);
+ ddv_geninit();
+
return(0);
}
-static void ddv_geninit(struct gendisk *ignored)
+static void ddv_geninit(void)
{
int i;
static int done = 0;
@@ -981,10 +975,8 @@ static void ddv_geninit(struct gendisk *ignored)
int init_module(void)
{
int error = ddv_init();
- if (!error) {
- ddv_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+ if (!error)
printk(KERN_INFO "DDV: Loaded as module.\n");
- }
return error;
}
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 97c768ace..c9c6f7533 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -502,7 +502,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
for (j = 1; j < 4; j++)
{
- if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0);
+ if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
break;
}
if (j == 4)
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index c47050df9..e27fb0109 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -37,6 +37,9 @@ else
if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
fi
+ if [ "$CONFIG_ISAPNP" = "y" ]; then
+ bool ' ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP
+ fi
if [ "$CONFIG_PCI" = "y" ]; then
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
@@ -53,22 +56,29 @@ else
fi
bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then
- bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING
- fi
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then
+ bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING
+ fi
+ bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X
+ if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+ bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID
+ fi
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
- bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
fi
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+ bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+ bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409
+ fi
bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA
fi
bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then
- bool ' HPT366 Fast Interrupt support (EXPERIMENTAL)' HPT366_FAST_IRQ_PREDICTION
+ bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' HPT366_FAST_IRQ_PREDICTION
+ bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' HPT366_MODE3
fi
if [ "$CONFIG_X86" = "y" ]; then
bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
@@ -225,7 +235,9 @@ fi
if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
"$CONFIG_BLK_DEV_AEC6210" = "y" -o \
"$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+ "$CONFIG_BLK_DEV_AMD7409" = "y" -o \
"$CONFIG_BLK_DEV_CMD640" = "y" -o \
+ "$CONFIG_BLK_DEV_CMD64X" = "y" -o \
"$CONFIG_BLK_DEV_CY82C693" = "y" -o \
"$CONFIG_BLK_DEV_HPT34X" = "y" -o \
"$CONFIG_BLK_DEV_HPT366" = "y" -o \
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 256c492ba..b21c6c1a9 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1066,8 +1066,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
Controller->GenericDiskInfo.major_name = "rd";
Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
- Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
- Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
Controller->GenericDiskInfo.real_devices = Controller;
Controller->GenericDiskInfo.next = NULL;
@@ -1166,6 +1164,7 @@ static void DAC960_InitializeController(DAC960_Controller_T *Controller)
Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
add_timer(&Controller->MonitoringTimer);
Controller->ControllerInitialized = true;
+ DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
}
else DAC960_FinalizeController(Controller);
}
@@ -2439,7 +2438,6 @@ static int DAC960_Open(Inode_T *Inode, File_T *File)
Controller->LogicalDriveInitialState[LogicalDriveNumber] =
DAC960_LogicalDrive_Online;
DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
- resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
}
if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
return -ENXIO;
@@ -2467,10 +2465,6 @@ static int DAC960_Release(Inode_T *Inode, File_T *File)
File != NULL && (File->f_flags & O_NONBLOCK))
goto ModuleOnly;
/*
- Force any buffered data to be written.
- */
- fsync_dev(Inode->i_rdev);
- /*
Decrement the Logical Drive and Controller Usage Counts.
*/
Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
@@ -2577,7 +2571,13 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
*/
set_blocksize(Device, BLOCK_SIZE);
}
- resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+ /*
+ * Leonard, I'll tie you, draw around you a pentagram
+ * and read this file. Aloud.
+ */
+ grok_partitions(
+ &Controller->GenericDiskInfo, LogicalDriveNumber, DAC960_MaxPartitions,
+ Controller->LogicalDriveInformation[Controller->LogicalDriveInformationIndex][LogicalDriveNumber].LogicalDriveSize);
return 0;
}
return -EINVAL;
@@ -2899,8 +2899,10 @@ static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
for (LogicalDriveNumber = 0;
LogicalDriveNumber < Controller->LogicalDriveCount;
LogicalDriveNumber++)
- GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
- LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+ register_disk(GenericDiskInfo, MKDEV(GenericDiskInfo->major,
+ LogicalDriveNumber*DAC960_MaxPartitions),
+ DAC960_MaxPartitions, &DAC960_FileOperations,
+ LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize);
}
@@ -3522,10 +3524,6 @@ int init_module(void)
DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL) continue;
DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
}
return 0;
}
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 7225b7120..dca5831d7 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -114,6 +114,10 @@ ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
IDE_OBJS += alim15x3.o
endif
+ifeq ($(CONFIG_BLK_DEV_AMD7409),y)
+IDE_OBJS += amd7409.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_BUDDHA),y)
IDE_OBJS += buddha.o
endif
@@ -122,8 +126,8 @@ ifeq ($(CONFIG_BLK_DEV_CMD640),y)
IDE_OBJS += cmd640.o
endif
-ifeq ($(CONFIG_BLK_DEV_CMD646),y)
-IDE_OBJS += cmd646.o
+ifeq ($(CONFIG_BLK_DEV_CMD64X),y)
+IDE_OBJS += cmd64x.o
endif
ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index b9178e98a..ef9e3fa7c 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -369,7 +369,7 @@ static int acsi_release( struct inode * inode, struct file * file );
static void acsi_prevent_removal( int target, int flag );
static int acsi_change_blk_size( int target, int lun);
static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
-static void acsi_geninit( struct gendisk *gd );
+static void acsi_geninit(void);
static int revalidate_acsidisk( int dev, int maxusage );
static int acsi_revalidate (dev_t);
@@ -1216,11 +1216,7 @@ static int acsi_open( struct inode * inode, struct file * filp )
static int acsi_release( struct inode * inode, struct file * file )
{
- int device;
-
- sync_dev(inode->i_rdev);
-
- device = DEVICE_NR(MINOR(inode->i_rdev));
+ int device = DEVICE_NR(MINOR(inode->i_rdev));
if (--access_count[device] == 0 && acsi_info[device].removable)
acsi_prevent_removal(device, 0);
MOD_DEC_USE_COUNT;
@@ -1390,21 +1386,15 @@ static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd )
static struct gendisk acsi_gendisk = {
- MAJOR_NR, /* Major number */
- "ad", /* Major name */
- 4, /* Bits to shift to get real from partition */
- 1 << 4, /* Number of partitions per real */
- MAX_DEV, /* maximum number of real */
-#ifdef MODULE
- NULL, /* called from init_module() */
-#else
- acsi_geninit, /* init function */
-#endif
- acsi_part, /* hd struct */
- acsi_sizes, /* block sizes */
- 0, /* number */
+ MAJOR_NR, /* Major number */
+ "ad", /* Major name */
+ 4, /* Bits to shift to get real from partition */
+ 1 << 4, /* Number of partitions per real */
+ acsi_part, /* hd struct */
+ acsi_sizes, /* block sizes */
+ 0, /* number */
(void *)acsi_info, /* internal */
- NULL /* next */
+ NULL /* next */
};
#define MAX_SCSI_DEVICE_CODE 10
@@ -1663,7 +1653,15 @@ EXPORT_SYMBOL(acsi_attach_SLMs);
int SLM_devices[8];
#endif
-static void acsi_geninit( struct gendisk *gd )
+static struct block_device_operations acsi_fops = {
+ open: acsi_open,
+ release: acsi_release,
+ ioctl: acsi_ioctl,
+ check_media_change: acsi_media_change,
+ revalidate: acsi_revalidate,
+};
+
+static void acsi_geninit(void)
{
int i, target, lun;
struct acsi_info_struct *aip;
@@ -1745,14 +1743,15 @@ static void acsi_geninit( struct gendisk *gd )
NDevices, n_slm );
#endif
- for( i = 0; i < NDevices; ++i ) {
- acsi_part[i<<4].start_sect = 0;
- acsi_part[i<<4].nr_sects = acsi_info[i].size;
- }
- acsi_gendisk.nr_real = NDevices;
for( i = 0; i < (MAX_DEV << 4); i++ )
acsi_blocksizes[i] = 1024;
blksize_size[MAJOR_NR] = acsi_blocksizes;
+ for( i = 0; i < NDevices; ++i )
+ register_disk(&acsi_gendisk, MKDEV(MAJOR_NR,i<<4),
+ (acsi_info[i].type==HARDDISK)?1<<4:1,
+ &acsi_fops,
+ acsi_info[i].size);
+ acsi_gendisk.nr_real = NDevices;
}
#ifdef CONFIG_ATARI_SLM_MODULE
@@ -1770,18 +1769,11 @@ void acsi_attach_SLMs( int (*attach_func)( int, int ) )
}
#endif /* CONFIG_ATARI_SLM_MODULE */
-static struct block_device_operations acsi_fops = {
- open: acsi_open,
- release: acsi_release,
- ioctl: acsi_ioctl,
- check_media_change: acsi_media_change,
- revalidate: acsi_revalidate,
-};
-
int acsi_init( void )
{
+ int err = 0;
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI))
return 0;
@@ -1805,10 +1797,11 @@ int acsi_init( void )
gendisk_head = &acsi_gendisk;
#ifdef CONFIG_ATARI_SLM
- return( slm_init() );
-#else
- return 0;
+ err = slm_init();
#endif
+ if (!err)
+ acsi_geninit();
+ return err;
}
@@ -1820,7 +1813,6 @@ int init_module(void)
if ((err = acsi_init()))
return( err );
printk( KERN_INFO "ACSI driver loaded as module.\n");
- acsi_geninit( &(struct gendisk){ 0,0,0,0,0,0,0,0,0,0,0 } );
return( 0 );
}
@@ -1918,9 +1910,7 @@ static int revalidate_acsidisk( int dev, int maxusage )
ENABLE_IRQ();
stdma_release();
- gdev->part[start].nr_sects = aip->size;
- if (aip->type == HARDDISK && aip->size > 0)
- resetup_one_dev(gdev, device);
+ grok_partitions(gdev, device, (aip->type==HARDDISK)?1<<4:1, aip->size);
DEVICE_BUSY = 0;
wake_up(&busy_wait);
diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c
index 59f6dea63..f74103d9a 100644
--- a/drivers/block/aec6210.c
+++ b/drivers/block/aec6210.c
@@ -287,8 +287,6 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif)
if (hwif->dma_base) {
hwif->dmaproc = &aec6210_dmaproc;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c
index 5c06b91a4..7cecae978 100644
--- a/drivers/block/alim15x3.c
+++ b/drivers/block/alim15x3.c
@@ -1,10 +1,10 @@
/*
- * linux/drivers/block/alim15x3.c Version 0.07 Dec. 13, 1999
+ * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000
*
- * Copyright (C) 1998-99 Michel Aubry, Maintainer
- * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
*
- * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* (U)DMA capable version of ali 1533/1543(C), 1535(D)
@@ -274,8 +274,8 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
if (r_clc >= 16)
r_clc = 0;
}
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
/*
* PIO mode => ATA FIFO on, ATAPI FIFO off
@@ -297,7 +297,7 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
pci_write_config_byte(dev, port, s_clc);
pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
- restore_flags(flags);
+ __restore_flags(flags);
/*
* setup active rec
@@ -311,280 +311,170 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
}
-static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
+static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
{
- if (bits & 0x04)
- return XFER_MW_DMA_2;
- if (bits & 0x02)
- return XFER_MW_DMA_1;
- return XFER_MW_DMA_0;
-}
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte unit = (drive->select.b.unit & 0x01);
+ byte tmpbyte = 0x00;
+ int m5229_udma = hwif->channel? 0x57 : 0x56;
+ int err = 0;
+
+ if (speed < XFER_UDMA_0) {
+ byte ultra_enable = (unit) ? 0x7f : 0xf7;
+ /*
+ * clear "ultra enable" bit
+ */
+ pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+ tmpbyte &= ultra_enable;
+ pci_write_config_byte(dev, m5229_udma, tmpbyte);
+ }
-static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
-{
- if (bits & 0x10)
- return XFER_UDMA_4;
- if (bits & 0x08)
- return XFER_UDMA_3;
- if (bits & 0x04)
- return XFER_UDMA_2;
- if (bits & 0x02)
- return XFER_UDMA_1;
- return XFER_UDMA_0;
-}
+ err = ide_config_drive_speed(drive, speed);
-static __inline__ int wait_for_ready(ide_drive_t *drive)
-{
- int timeout = 20000; /* (old value: 100) */
- byte stat;
+ if (speed >= XFER_SW_DMA_0) {
+ unsigned long dma_base = hwif->dma_base;
- while (--timeout) {
- stat = GET_STAT();
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+ tmpbyte &= (0x0f << ((1-unit) << 2));
/*
- * printk("STAT(%2x) ", stat);
+ * enable ultra dma and set timing
*/
- if (!(stat & BUSY_STAT)) {
- if ((stat & READY_STAT) || (stat & ERR_STAT)) {
- break;
- }
+ tmpbyte |= ((0x08 | (4-speed)) << (unit << 2));
+ pci_write_config_byte(dev, m5229_udma, tmpbyte);
+ if (speed >= XFER_UDMA_3) {
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ tmpbyte |= 1;
+ pci_write_config_byte(dev, 0x4b, tmpbyte);
}
- /*
- * (old value: 100)
- */
- udelay(150);
}
- if ((stat & ERR_STAT) || timeout <= 0)
- return 1;
- return 0;
-}
-static void ali15x3_do_setfeature(ide_drive_t *drive, byte command)
-{
- unsigned long flags;
- byte old_select;
-
- save_flags(flags);
- cli();
-
- /* save old selected device */
- old_select = IN_BYTE(IDE_SELECT_REG);
- /* "SELECT " */
- OUT_BYTE(drive->select.all, IDE_SELECT_REG);
- /* "SETXFER " */
- OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
- /* "CMND " */
- OUT_BYTE(command, IDE_NSECTOR_REG);
-
- if(wait_for_ready(drive)) /* "wait " */
- goto out;
-
- /* "SETFEATURE " */
- OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
- /* "wait " */
- (void) wait_for_ready(drive);
-
-out:
- /*
- * restore to old "selected device"
- */
- OUT_BYTE(old_select, IDE_SELECT_REG);
- restore_flags(flags);
+ return (err);
}
-static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
{
- byte unit = (drive->select.b.unit & 0x01);
- byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
- byte ultra = (unit) ? 0x7f : 0xf7;
- byte tmpbyte;
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long flags;
- int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
-
- ali15x3_do_setfeature(drive, dma2_bits_to_command(bits));
-
- /*
- * clear "ultra enable" bit
- */
- pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
-#if 0
- if (unit) {
- tmpbyte &= 0x7f;
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ byte speed = 0x00;
+ byte ultra66 = ((hwif->udma_four) && (id->hw_config & 0x2000)) ? 1 : 0;
+ int rval;
+
+ if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) {
+ speed = XFER_UDMA_4;
+ } else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) {
+ speed = XFER_UDMA_3;
+ } else if ((id->dma_ultra & 0x0004) && (ultra33)) {
+ speed = XFER_UDMA_2;
+ } else if ((id->dma_ultra & 0x0002) && (ultra33)) {
+ speed = XFER_UDMA_1;
+ } else if ((id->dma_ultra & 0x0001) && (ultra33)) {
+ speed = XFER_UDMA_0;
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else if (id->dma_1word & 0x0004) {
+ speed = XFER_SW_DMA_2;
+ } else if (id->dma_1word & 0x0002) {
+ speed = XFER_SW_DMA_1;
+ } else if (id->dma_1word & 0x0001) {
+ speed = XFER_SW_DMA_0;
} else {
- tmpbyte &= 0xf7;
- }
-#else
- tmpbyte &= ultra;
-#endif
- save_flags(flags);
- cli();
- pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
- restore_flags(flags);
- drive->id->dma_ultra = 0x00;
-
- /*
- * Enable DMA
- */
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- printk("ALI15X3: MultiWord DMA enabled\n");
-}
-
-static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base)
-{
- byte unit = (drive->select.b.unit & 0x01);
- byte bits = drive->id->dma_ultra & 0x1f;
- byte tmpbyte;
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long flags;
- unsigned char udma_mode = 0;
- int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
-
- if (bits & 0x18) {
- /*
- * 00011000, disk: ultra66
- */
- if (m5229_revision < 0xc2) {
- /*
- * controller: ultra33
- */
- bits = 0x04;
- /*
- * 00000100, use ultra33, mode 2
- */
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0004;
- } else {
- /*
- * controller: ultra66
- *
- * Try to detect word93 bit13 and
- * 80-pin cable (from host view)
- */
- if (!((drive->id->word93 & 0x2000) &&
- cable_80_pin[hwif->channel])) {
- bits = 0x04;
- /*
- * 00000100, use ultra33, mode 2
- */
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0004;
- }
- }
+ return ((int) ide_dma_off_quietly);
}
- /*
- * set feature regardless
- */
- ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits));
- udma_mode &= 0x0f; /* get UDMA mode */
+ (void) ali15x3_tune_chipset(drive, speed);
- /*
- * Enable DMA and UltraDMA
- */
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- /*
- * m5229 ultra
- */
- pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
- /*
- * clear bit0~3 or bit 4~7
- */
- tmpbyte &= (0x0f << ((1-unit) << 2));
- /*
- * enable ultra dma and set timing
- */
- tmpbyte |= ((0x08 | (4-udma_mode)) << (unit << 2));
- /*
- * set to m5229
- */
- save_flags(flags);
- cli();
- pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
- restore_flags(flags);
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
- if (udma_mode >= 3) {
- /*
- * ultra 66
- */
- pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte);
- tmpbyte |= 1;
- save_flags(flags);
- cli();
- pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte);
- restore_flags(flags);
- }
+ return rval;
+}
- printk("ALI15X3: Ultra DMA enabled\n");
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ ali15x3_tune_drive(drive, 5);
}
-static int ali15x3_dma_onoff(ide_drive_t *drive, int enable)
+
+static byte ali15x3_can_ultra (ide_drive_t *drive)
{
- if (enable) {
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long dma_base = hwif->dma_base;
- struct hd_driveid *id = drive->id;
-
- if ((id->field_valid & 0x0004) &&
- (id->dma_ultra & 0x001f)) {
- /*
- * 1543C_E, in ultra mode, WDC "harddisk"
- * will cause "CRC" errors (even if no CRC problem),
- * so we try to use "DMA" here
- */
- if (m5229_revision <= 0x20) {
- /*
- * Normal MultiWord DMA modes.
- */
- ali15x3_dma2_enable(drive, dma_base);
- } else if ((m5229_revision < 0xC2) &&
- ((drive->media!=ide_disk) ||
- (chip_is_1543c_e &&
- strstr(id->model, "WDC ")))) {
- /*
- * Normal MultiWord DMA modes.
- */
- ali15x3_dma2_enable(drive, dma_base);
- } else {
- /*
- * m5229_revision >= 0xC2 for UltraDMA modes.
- */
- ali15x3_udma_enable(drive, dma_base);
- }
- } else {
- /*
- * Normal MultiWord DMA modes.
- */
- ali15x3_dma2_enable(drive, dma_base);
- }
+ struct hd_driveid *id = drive->id;
+
+ if (m5229_revision <= 0x20) {
+ return 0;
+ } else if ((m5229_revision < 0xC2) &&
+ ((drive->media!=ide_disk) ||
+ (chip_is_1543c_e &&
+ strstr(id->model, "WDC ")))) {
+ return 0;
+ } else {
+ return 1;
}
-
- drive->using_dma = enable; /* on, off */
- return 0;
}
static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_dma_action_t dma_func = ide_dma_on;
+ byte can_ultra_dma = ali15x3_can_ultra(drive);
if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
return hwif->dmaproc(ide_dma_off_quietly, drive);
- /*
- * Even if the drive is not _currently_ in a DMA
- * mode, we succeed, and we'll enable it manually
- * below in alim15x3_dma_onoff
- */
- if ((id != NULL) && (id->capability & 1) && hwif->autodma) {
- if (id->field_valid & 0x0004) {
- if (id->dma_ultra & 0x001F)
- return hwif->dmaproc(ide_dma_on, drive);
+
+ if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
}
- if (id->field_valid & 0x0002) {
- if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007))
- return hwif->dmaproc(ide_dma_on, drive);
+ dma_func = ide_dma_off_quietly;
+ if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+ if (id->dma_ultra & 0x001F) {
+ /* Force if Capable UltraDMA */
+ dma_func = config_chipset_for_dma(drive, can_ultra_dma);
+ if ((id->field_valid & 2) &&
+ (dma_func != ide_dma_on))
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+try_dma_modes:
+ if ((id->dma_mword & 0x0007) ||
+ (id->dma_1word & 0x0007)) {
+ /* Force if Capable regular DMA modes */
+ dma_func = config_chipset_for_dma(drive, can_ultra_dma);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ }
+ } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ if (id->eide_dma_time > 150) {
+ goto no_dma_set;
+ }
+ /* Consult the list of known "good" drives */
+ dma_func = config_chipset_for_dma(drive, can_ultra_dma);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
}
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+ config_chipset_for_pio(drive);
}
- return hwif->dmaproc(ide_dma_off_quietly, drive);
+ return hwif->dmaproc(dma_func, drive);
}
static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
@@ -592,10 +482,6 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
switch(func) {
case ide_dma_check:
return ali15x3_config_drive_for_dma(drive);
- case ide_dma_on:
- case ide_dma_off:
- case ide_dma_off_quietly:
- return ali15x3_dma_onoff(drive, (func == ide_dma_on));
case ide_dma_write:
if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
return 1; /* try PIO instead of DMA */
@@ -610,8 +496,6 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
{
unsigned long fixdma_base = dev->resource[4].start;
- byte tmpbyte;
- unsigned long flags;
pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
@@ -630,14 +514,22 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
if (inb(fixdma_base+2) & 0x80)
printk("%s: simplex device: DMA will fail!!\n", name);
}
+ return 0;
+}
- /*
- * FIXME !!! This detection needs to be in "ata66_ali15x3()"
- * below as a standard detection return.
- */
+unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ byte ata66mask = hwif->channel ? 0x02 : 0x01;
+ unsigned int ata66 = 0;
+
+ unsigned long flags;
+ byte tmpbyte;
+
+ __save_flags(flags);
+ __cli();
if (m5229_revision >= 0xC2) {
- unsigned long flags;
/*
* 1543C-B?, 1535, 1535D, 1553
* Note 1: not all "motherboard" support this detection
@@ -645,8 +537,6 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
* but in this case, we will not set the device to
* ultra 66, the detection result is not important
*/
- save_flags(flags);
- cli();
/*
* enable "Cable Detection", m5229, 0x4b, bit3
@@ -669,7 +559,6 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
*/
pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
}
- restore_flags(flags);
/*
* Ultra66 cable detection (from Host View)
* m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
@@ -679,30 +568,23 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
* 0x4a, bit0 is 0 => primary channel
* has 80-pin (from host view)
*/
- if (!(tmpbyte & 0x01))
- cable_80_pin[0] = 1;
+ if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
/*
* 0x4a, bit1 is 0 => secondary channel
* has 80-pin (from host view)
*/
- if (!(tmpbyte & 0x02))
- cable_80_pin[1] = 1;
+ if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
} else {
- unsigned long flags;
/*
* revision 0x20 (1543-E, 1543-F)
* revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
* clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
*/
pci_read_config_byte(dev, 0x4b, &tmpbyte);
- save_flags(flags);
- cli();
/*
* clear bit 7
*/
pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
- restore_flags(flags);
-
/*
* check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
*/
@@ -710,131 +592,17 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
}
- if (m5229_revision == 0x20) {
- /*
- * check M1533 revision (offset 0x08)
- */
- pci_read_config_byte(isa_dev, 0x08, &tmpbyte);
- if (tmpbyte == 0x0A) {
- unsigned long flags;
- pci_read_config_byte(dev, 0x4e, &tmpbyte);
- save_flags(flags);
- cli();
- /*
- * set bit 6
- */
- pci_write_config_byte(dev, 0x4e, tmpbyte | 0x40);
- restore_flags(flags);
-
- /*
- * this special version is similar to revision 0xC2
- * but does not support UDMA66
- * (cable_80_pin[0] = 0; cable_80_pin[1] = 0;)
- */
- m5229_revision = 0xC2;
- }
- }
-
/*
* CD_ROM DMA on (m5229, 0x53, bit0)
- * Enable this bit even if we want to use PIO
+ * Enable this bit even if we want to use PIO
* PIO FIFO off (m5229, 0x53, bit1)
- * The hardware will use 0x54h and 0x55h to control PIO FIFO
+ * The hardware will use 0x54h and 0x55h to control PIO FIFO
*/
pci_read_config_byte(dev, 0x53, &tmpbyte);
tmpbyte = (tmpbyte & (~0x02)) | 0x01;
- save_flags(flags);
- cli();
- pci_write_config_byte(dev, 0x53, tmpbyte);
- restore_flags(flags);
-
- return 0;
-}
-
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
-{
-#if 0
- /*
- * FIXME !!! This detection needs to be in "ata66_ali15x3()"
- * below as a standard detection return.
- */
-
- if (m5229_revision >= 0xC2) {
- unsigned long flags;
- /*
- * 1543C-B?, 1535, 1535D, 1553
- * Note 1: not all "motherboard" support this detection
- * Note 2: if no udma 66 device, the detection may "error".
- * but in this case, we will not set the device to
- * ultra 66, the detection result is not important
- */
- save_flags(flags);
- cli();
-
- /*
- * enable "Cable Detection", m5229, 0x4b, bit3
- */
- pci_read_config_byte(dev, 0x4b, &tmpbyte);
- pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
- /*
- * set south-bridge's enable bit, m1533, 0x79
- */
- pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
- if (m5229_revision == 0xC2) {
- /*
- * 1543C-B0 (m1533, 0x79, bit 2)
- */
- pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
- } else if (m5229_revision == 0xC3) {
- /*
- * 1553/1535 (m1533, 0x79, bit 1)
- */
- pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
- }
- restore_flags(flags);
- /*
- * Ultra66 cable detection (from Host View)
- * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
- */
- pci_read_config_byte(dev, 0x4a, &tmpbyte);
- /*
- * 0x4a, bit0 is 0 => primary channel
- * has 80-pin (from host view)
- */
- if (!(tmpbyte & 0x01))
- cable_80_pin[0] = 1;
- /*
- * 0x4a, bit1 is 0 => secondary channel
- * has 80-pin (from host view)
- */
- if (!(tmpbyte & 0x02))
- cable_80_pin[1] = 1;
- } else {
- unsigned long flags;
- /*
- * revision 0x20 (1543-E, 1543-F)
- * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
- * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
- */
- pci_read_config_byte(dev, 0x4b, &tmpbyte);
- save_flags(flags);
- cli();
- /*
- * clear bit 7
- */
- pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
- restore_flags(flags);
- /*
- * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
- */
- pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
- chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
- }
+ pci_write_config_byte(dev, 0x53, tmpbyte);
- byte ata66mask = hwif->channel ? 0x02 : 0x01;
- unsigned int ata66 = 0;
/*
* Ultra66 cable detection (from Host View)
* m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
@@ -845,12 +613,11 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
* 0x4a, bit1 is 0 => secondary channel
* has 80-pin (from host view)
*/
- pci_read_config_byte(hwif->pci_dev, 0x4a, &tmpbyte);
+ pci_read_config_byte(dev, 0x4a, &tmpbyte);
ata66 = (!(tmpbyte & ata66mask)) ? 0 : 1;
+ __restore_flags(flags);
+
return(ata66);
-#else
- return 0;
-#endif
}
void __init ide_init_ali15x3 (ide_hwif_t *hwif)
@@ -871,8 +638,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
ideic = ideic & 0x03;
/* get IRQ for IDE Controller */
- if ((hwif->channel && ideic == 0x03) ||
- (!hwif->channel && !ideic)) {
+ if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
/*
* get SIRQ1 routing table
*/
@@ -905,9 +671,11 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
}
#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
- ali_proc = 1;
- bmide_dev = hwif->pci_dev;
- ali_display_info = &ali_get_info;
+ if (!ali_proc) {
+ ali_proc = 1;
+ bmide_dev = hwif->pci_dev;
+ ali_display_info = &ali_get_info;
+ }
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
return;
diff --git a/drivers/block/amd7409.c b/drivers/block/amd7409.c
new file mode 100644
index 000000000..46d5f36af
--- /dev/null
+++ b/drivers/block/amd7409.c
@@ -0,0 +1,290 @@
+/*
+ * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000
+ *
+ * Copyright (C) 2000 Andre Hedrick <andre@suse.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+/*
+ * Here is where all the hard work goes to program the chipset.
+ *
+ */
+static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int err = 0;
+ int drive_number = ((HWIF(drive)->channel ? 2 : 0) +
+ (drive->select.b.unit & 0x01));
+ byte drive_pci = 0x00;
+ byte drive_pci2 = 0x00;
+ byte drive_timing = 0x00;
+ byte pio_timing = 0x00;
+
+ switch (drive_number) {
+ case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
+ case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
+ case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
+ case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
+ default:
+ return ((int) ide_dma_off_quietly);
+ }
+
+ pci_read_config_byte(dev, drive_pci, &drive_timing);
+ pci_read_config_byte(dev, drive_pci2, &pio_timing);
+
+ printk("%s: UDMA 0x%02x PIO 0x%02x ",
+ drive->name, drive_timing, pio_timing);
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ drive_timing &= ~0xC7;
+ drive_timing |= 0x45;
+ pci_write_config_byte(dev, drive_pci, drive_timing);
+ break;
+ case XFER_UDMA_3:
+ drive_timing &= ~0xC7;
+ drive_timing |= 0x44;
+ pci_write_config_byte(dev, drive_pci, drive_timing);
+ break;
+ case XFER_UDMA_2:
+ drive_timing &= ~0xC7;
+ drive_timing |= 0x40;
+ pci_write_config_byte(dev, drive_pci, drive_timing);
+ break;
+ case XFER_UDMA_1:
+ drive_timing &= ~0xC7;
+ drive_timing |= 0x41;
+ pci_write_config_byte(dev, drive_pci, drive_timing);
+ break;
+ case XFER_UDMA_0:
+ drive_timing &= ~0xC7;
+ drive_timing |= 0x42;
+ pci_write_config_byte(dev, drive_pci, drive_timing);
+ break;
+ case XFER_MW_DMA_2:break;
+ case XFER_MW_DMA_1:break;
+ case XFER_MW_DMA_0:break;
+ case XFER_SW_DMA_2:break;
+ case XFER_SW_DMA_1:break;
+ case XFER_SW_DMA_0:break;
+ case XFER_PIO_4:break;
+ case XFER_PIO_3:break;
+ case XFER_PIO_2:break;
+ case XFER_PIO_1:break;
+ case XFER_PIO_0:break;
+ default: break;
+ }
+
+ printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing);
+
+ err = ide_config_drive_speed(drive, speed);
+ return (err);
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte speed = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) {
+ speed = XFER_UDMA_4;
+ } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) {
+ speed = XFER_UDMA_3;
+ } else if (id->dma_ultra & 0x0004) {
+ speed = XFER_UDMA_2;
+ } else if (id->dma_ultra & 0x0002) {
+ speed = XFER_UDMA_1;
+ } else if (id->dma_ultra & 0x0001) {
+ speed = XFER_UDMA_0;
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else if (id->dma_1word & 0x0004) {
+ speed = XFER_SW_DMA_2;
+ } else if (id->dma_1word & 0x0002) {
+ speed = XFER_SW_DMA_1;
+ } else if (id->dma_1word & 0x0001) {
+ speed = XFER_SW_DMA_0;
+ } else {
+ return ((int) ide_dma_off_quietly);
+ }
+
+ (void) amd7409_tune_chipset(drive, speed);
+
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+
+ return rval;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+ break;
+ }
+ (void) amd7409_tune_chipset(drive, speed);
+}
+
+static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ switch(pio) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default: speed = XFER_PIO_0;break;
+ }
+ (void) amd7409_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_dma_action_t dma_func = ide_dma_on;
+
+ if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
+ }
+ dma_func = ide_dma_off_quietly;
+ if (id->field_valid & 4) {
+ if (id->dma_ultra & 0x001F) {
+ /* Force if Capable UltraDMA */
+ dma_func = config_chipset_for_dma(drive);
+ if ((id->field_valid & 2) &&
+ (dma_func != ide_dma_on))
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+try_dma_modes:
+ if ((id->dma_mword & 0x0007) ||
+ (id->dma_1word & 0x0007)) {
+ /* Force if Capable regular DMA modes */
+ dma_func = config_chipset_for_dma(drive);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ }
+ } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ if (id->eide_dma_time > 150) {
+ goto no_dma_set;
+ }
+ /* Consult the list of known "good" drives */
+ dma_func = config_chipset_for_dma(drive);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
+ }
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+
+ config_chipset_for_pio(drive);
+ }
+ return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * amd7409_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+
+int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return config_drive_xfer_rate(drive);
+ default:
+ break;
+ }
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+}
+
+unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
+{
+#if 0
+ byte ata66 = 0;
+
+ pci_read_config_byte(hwif->pci_dev, 0x48, &ata66);
+ return ((ata66 & 0x02) ? 0 : 1);
+#else
+ return 0;
+#endif
+}
+
+void __init ide_init_amd7409 (ide_hwif_t *hwif)
+{
+ hwif->tuneproc = &amd7409_tune_drive;
+ if (hwif->dma_base) {
+ hwif->dmaproc = &amd7409_dmaproc;
+ } else {
+ hwif->autodma = 0;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ }
+}
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2dfeb1c82..d9655d275 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1686,16 +1686,6 @@ static int floppy_release(struct inode * inode, struct file * filp)
#endif
int drive = MINOR(inode->i_rdev) & 3;
- fsync_dev(inode->i_rdev);
-
-#ifdef DEBUG
- /* This is now handled in floppy_change, but still useful for debugging */
- sb = get_super(inode->i_rdev);
- if (sb)
- invalidate_inodes(sb);
- invalidate_buffers(inode->i_rdev);
-#endif
-
if (unit[drive].dirty == 1) {
del_timer (flush_track_timer + drive);
non_int_flush_track (drive);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 497734372..b1e20b7d3 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1941,11 +1941,7 @@ static int floppy_open( struct inode *inode, struct file *filp )
static int floppy_release( struct inode * inode, struct file * filp )
{
- int drive;
-
- drive = MINOR(inode->i_rdev) & 3;
-
- block_fsync (filp, filp->f_dentry);
+ int drive = MINOR(inode->i_rdev) & 3;
if (fd_ref[drive] < 0)
fd_ref[drive] = 0;
diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c
deleted file mode 100644
index 05cf7c2bf..000000000
--- a/drivers/block/cmd646.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* $Id: cmd646.c,v 1.15 1999/07/23 01:48:37 davem Exp $
- * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines.
- * Note, this driver is not used at all on other systems because
- * there the "BIOS" has done all of the following already.
- * Due to massive hardware bugs, UltraDMA is only supported
- * on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static int cmd646_config_drive_for_dma(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
-
- /* Even if the drive is not _currently_ in a DMA
- * mode, we succeed, and we'll enable it manually
- * below in cmd646_dma_onoff.
- *
- * This is done for disks only, CDROMs and other
- * IDE devices are just too quirky.
- */
- if((id != NULL) &&
- ((id->capability & 1) != 0) &&
- hwif->autodma &&
- (drive->media == ide_disk)) {
- if(id->field_valid & 0x0004) {
- if(id->dma_ultra & 0x0007)
- return hwif->dmaproc(ide_dma_on, drive);
- }
- if(id->field_valid & 0x0002)
- if((id->dma_mword & 0x0004) || (id->dma_1word & 0x0004))
- return hwif->dmaproc(ide_dma_on, drive);
- }
- return hwif->dmaproc(ide_dma_off_quietly, drive);
-}
-
-/* This is fun. -DaveM */
-#define IDE_SETXFER SETFEATURES_XFER
-#define IDE_SETFEATURE WIN_SETFEATURES
-#define IDE_DMA2_ENABLE XFER_MW_DMA_2
-#define IDE_DMA1_ENABLE XFER_MW_DMA_1
-#define IDE_DMA0_ENABLE XFER_MW_DMA_0
-#define IDE_UDMA2_ENABLE XFER_UDMA_2
-#define IDE_UDMA1_ENABLE XFER_UDMA_1
-#define IDE_UDMA0_ENABLE XFER_UDMA_0
-
-static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
-{
- if(bits & 0x04)
- return IDE_DMA2_ENABLE;
- if(bits & 0x02)
- return IDE_DMA1_ENABLE;
- return IDE_DMA0_ENABLE;
-}
-
-static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
-{
- if(bits & 0x04)
- return IDE_UDMA2_ENABLE;
- if(bits & 0x02)
- return IDE_UDMA1_ENABLE;
- return IDE_UDMA0_ENABLE;
-}
-
-static __inline__ int wait_for_ready(ide_drive_t *drive)
-{
- int timeout = 100;
- byte stat;
-
- while(--timeout) {
- stat = GET_STAT();
-
- printk("STAT(%2x) ", stat);
- if(!(stat & BUSY_STAT)) {
- if((stat & READY_STAT) || (stat & ERR_STAT))
- break;
- }
- udelay(100);
- }
- if((stat & ERR_STAT) || timeout <= 0)
- return 1;
- return 0;
-}
-
-static void cmd646_do_setfeature(ide_drive_t *drive, byte command)
-{
-#if 0
- (void) ide_config_drive_speed(drive, command);
-#else
- unsigned long flags;
- byte old_select;
-
- save_flags(flags);
- cli();
- printk("SELECT ");
- old_select = IN_BYTE(IDE_SELECT_REG);
- OUT_BYTE(drive->select.all, IDE_SELECT_REG);
- printk("SETXFER ");
- OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
- printk("CMND ");
- OUT_BYTE(command, IDE_NSECTOR_REG);
- printk("wait ");
- if(wait_for_ready(drive))
- goto out;
- printk("SETFEATURE ");
- OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
- printk("wait ");
- (void) wait_for_ready(drive);
-out:
- OUT_BYTE(old_select, IDE_SELECT_REG);
- restore_flags(flags);
-#endif
-}
-
-static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
-{
- byte unit = (drive->select.b.unit & 0x01);
- byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
-
- printk("CMD646: MDMA enable [");
- if((((drive->id->dma_mword & 0x0007) << 8) !=
- (drive->id->dma_mword & 0x0700)))
- cmd646_do_setfeature(drive, dma2_bits_to_command(bits));
- printk("DMA_CAP ");
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- printk("DONE]\n");
-}
-
-static void cmd646_udma_enable(ide_drive_t *drive, unsigned long dma_base)
-{
- byte unit = (drive->select.b.unit & 0x01);
- byte udma_ctrl, bits = drive->id->dma_ultra & 0x07;
- byte udma_timing_bits;
-
- printk("CMD646: UDMA enable [");
- if(((drive->id->dma_ultra & 0x0007) << 8) !=
- (drive->id->dma_ultra & 0x0700))
- cmd646_do_setfeature(drive, udma2_bits_to_command(bits));
-
- /* Enable DMA and UltraDMA */
- printk("DMA_CAP ");
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-
- udma_ctrl = inb(dma_base + 3);
-
- /* Put this channel into UDMA mode. */
- printk("UDMA_CTRL ");
- udma_ctrl |= (1 << unit);
-
- /* Set UDMA2 usable timings. */
- if(bits & 0x04)
- udma_timing_bits = 0x10;
- else if(bits & 0x02)
- udma_timing_bits = 0x20;
- else
- udma_timing_bits = 0x30;
- udma_ctrl &= ~(0x30 << (unit * 2));
- udma_ctrl |= (udma_timing_bits << (unit * 2));
-
- outb(udma_ctrl, dma_base+3);
- printk("DONE]\n");
-}
-
-static int cmd646_dma_onoff(ide_drive_t *drive, int enable)
-{
- if(enable) {
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long dma_base = hwif->dma_base;
- struct hd_driveid *id = drive->id;
- unsigned int class_rev;
-
- /* UltraDMA only supported on PCI646U and PCI646U2,
- * which correspond to revisions 0x03 and 0x05 respectively.
- * Actually, although the CMD tech support people won't
- * tell me the details, the 0x03 revision cannot support
- * UDMA correctly without hardware modifications, and even
- * then it only works with Quantum disks due to some
- * hold time assumptions in the 646U part which are fixed
- * in the 646U2.
- * So we only do UltraDMA on revision 0x05 chipsets.
- */
- pci_read_config_dword(hwif->pci_dev,
- PCI_CLASS_REVISION,
- &class_rev);
- class_rev &= 0xff;
- if((class_rev == 0x05) &&
- (id->field_valid & 0x0004) &&
- (id->dma_ultra & 0x07)) {
- /* UltraDMA modes. */
- cmd646_udma_enable(drive, dma_base);
- } else {
- /* Normal MultiWord DMA modes. */
- cmd646_dma2_enable(drive, dma_base);
- }
- }
- drive->using_dma = enable;
- return 0;
-}
-
-static int cmd646_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
- if(func == ide_dma_check)
- return cmd646_config_drive_for_dma(drive);
- else if(func == ide_dma_on || func == ide_dma_off || func == ide_dma_off_quietly)
- return cmd646_dma_onoff(drive, (func == ide_dma_on));
-
- /* Other cases are done by generic IDE-DMA code. */
- return ide_dmaproc(func, drive);
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-static int cmd646_1_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long dma_base = hwif->dma_base;
- byte dma_stat;
-
- if (func == ide_dma_end) {
- drive->waiting_for_dma = 0;
- dma_stat = inb(dma_base+2); /* get DMA status */
- outb(inb(dma_base)&~1, dma_base); /* stop DMA */
- outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
- return (dma_stat & 7) != 4; /* verify good DMA status */
- }
-
- /* Other cases are done by generic IDE-DMA code. */
- return cmd646_dmaproc(func, drive);
-}
-
-void __init ide_init_cmd646 (ide_hwif_t *hwif)
-{
- struct pci_dev *dev = hwif->pci_dev;
- unsigned char mrdmode;
- unsigned int class_rev;
-
- pci_read_config_dword(hwif->pci_dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- hwif->chipset = ide_cmd646;
-
- /* Set a good latency timer and cache line size value. */
- (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
- (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
- /* Setup interrupts. */
- (void) pci_read_config_byte(dev, 0x71, &mrdmode);
- mrdmode &= ~(0x30);
- (void) pci_write_config_byte(dev, 0x71, mrdmode);
-
- /* Use MEMORY READ LINE for reads.
- * NOTE: Although not mentioned in the PCI0646U specs,
- * these bits are write only and won't be read
- * back as set or not. The PCI0646U2 specs clarify
- * this point.
- */
- (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02);
-
- /* Set reasonable active/recovery/address-setup values. */
- (void) pci_write_config_byte(dev, 0x53, 0x40);
- (void) pci_write_config_byte(dev, 0x54, 0x3f);
- (void) pci_write_config_byte(dev, 0x55, 0x40);
- (void) pci_write_config_byte(dev, 0x56, 0x3f);
- (void) pci_write_config_byte(dev, 0x57, 0x5c);
- (void) pci_write_config_byte(dev, 0x58, 0x3f);
- (void) pci_write_config_byte(dev, 0x5b, 0x3f);
-
- if (hwif->dma_base) {
- if (class_rev == 0x01) {
- hwif->dmaproc = &cmd646_1_dmaproc;
- } else {
- hwif->dmaproc = &cmd646_dmaproc;
- }
- }
-}
diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c
new file mode 100644
index 000000000..6eaa0f3bb
--- /dev/null
+++ b/drivers/block/cmd64x.c
@@ -0,0 +1,340 @@
+/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ * Note, this driver is not used at all on other systems because
+ * there the "BIOS" has done all of the following already.
+ * Due to massive hardware bugs, UltraDMA is only supported
+ * on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1999 Andre Hedrick (andre@suse.com)
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...) printk(##x)
+#else
+#define cmdprintk(x...)
+#endif
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long dma_base = hwif->dma_base;
+
+ byte unit = (drive->select.b.unit & 0x01);
+ byte speed = 0x00;
+ byte udma_timing_bits = 0x00;
+ byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
+ byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+ /* int drive_number = ((hwif->channel ? 2 : 0) + unit); */
+ int rval;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ case PCI_DEVICE_ID_CMD_646:
+ case PCI_DEVICE_ID_CMD_648:
+ default:
+ break;
+ }
+
+ if (drive->media != ide_disk) {
+ cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
+ return ((int) ide_dma_off);
+ }
+
+ /* UltraDMA only supported on PCI646U and PCI646U2,
+ * which correspond to revisions 0x03, 0x05 and 0x07 respectively.
+ * Actually, although the CMD tech support people won't
+ * tell me the details, the 0x03 revision cannot support
+ * UDMA correctly without hardware modifications, and even
+ * then it only works with Quantum disks due to some
+ * hold time assumptions in the 646U part which are fixed
+ * in the 646U2.
+ * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+ */
+
+ if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
+ speed = XFER_UDMA_4;
+ udma_timing_bits = 0x10; /* 2 clock */
+ } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
+ speed = XFER_UDMA_3;
+ udma_timing_bits = 0x20; /* 3 clock */
+ } else if ((id->dma_ultra & 0x0004) && (udma_33)) {
+ speed = XFER_UDMA_2;
+ udma_timing_bits = 0x10; /* 2 clock */
+ } else if ((id->dma_ultra & 0x0002) && (udma_33)) {
+ speed = XFER_UDMA_1;
+ udma_timing_bits = 0x20; /* 3 clock */
+ } else if ((id->dma_ultra & 0x0001) && (udma_33)) {
+ speed = XFER_UDMA_0;
+ udma_timing_bits = 0x30; /* 4 clock */
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else if (id->dma_1word & 0x0004) {
+ speed = XFER_SW_DMA_2;
+ } else if (id->dma_1word & 0x0002) {
+ speed = XFER_SW_DMA_1;
+ } else if (id->dma_1word & 0x0001) {
+ speed = XFER_SW_DMA_0;
+ } else {
+ return ((int) ide_dma_off_quietly);
+ }
+
+ (void) ide_config_drive_speed(drive, speed);
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+
+ if (speed >= XFER_UDMA_0) {
+ byte udma_ctrl = inb(dma_base + 3);
+ /* Put this channel into UDMA mode. */
+ udma_ctrl |= (1 << unit);
+ udma_ctrl &= ~(0x04 << unit);
+ if (udma_66)
+ udma_ctrl |= (0x04 << unit);
+ udma_ctrl &= ~(0x30 << (unit * 2));
+ udma_ctrl |= (udma_timing_bits << (unit * 2));
+ outb(udma_ctrl, dma_base+3);
+ }
+
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+
+ return rval;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev)
+{
+ /* FIXME!! figure out some PIOing junk.... */
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int class_rev = 0;
+ byte can_ultra_33 = 0;
+ byte can_ultra_66 = 0;
+ ide_dma_action_t dma_func = ide_dma_on;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ can_ultra_33 = 1;
+ can_ultra_66 = 0;
+ break;
+ case PCI_DEVICE_ID_CMD_646:
+ can_ultra_33 = (class_rev >= 0x05) ? 1 : 0;
+ can_ultra_66 = 0;
+ break;
+ case PCI_DEVICE_ID_CMD_648:
+ can_ultra_33 = 1;
+ can_ultra_66 = 1;
+ break;
+ default:
+ return hwif->dmaproc(ide_dma_off, drive);
+ }
+
+ if ((id != NULL) && ((id->capability & 1) != 0) &&
+ hwif->autodma && (drive->media == ide_disk)) {
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
+ }
+ dma_func = ide_dma_off_quietly;
+ if ((id->field_valid & 4) && (can_ultra_33)) {
+ if (id->dma_ultra & 0x001F) {
+ /* Force if Capable UltraDMA */
+ dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
+ if ((id->field_valid & 2) &&
+ (dma_func != ide_dma_on))
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+try_dma_modes:
+ if ((id->dma_mword & 0x0007) ||
+ (id->dma_1word & 0x0007)) {
+ /* Force if Capable regular DMA modes */
+ dma_func = config_chipset_for_dma(drive, class_rev, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ }
+ } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ if (id->eide_dma_time > 150) {
+ goto no_dma_set;
+ }
+ /* Consult the list of known "good" drives */
+ dma_func = config_chipset_for_dma(drive, class_rev, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
+ }
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+ config_chipset_for_pio(drive, class_rev);
+ }
+ return hwif->dmaproc(dma_func, drive);
+}
+
+static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return cmd64x_config_drive_for_dma(drive);
+ default:
+ break;
+ }
+ /* Other cases are done by generic IDE-DMA code. */
+ return ide_dmaproc(func, drive);
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte dma_stat;
+
+ if (func == ide_dma_end) {
+ drive->waiting_for_dma = 0;
+ dma_stat = inb(dma_base+2); /* get DMA status */
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA */
+ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
+ return (dma_stat & 7) != 4; /* verify good DMA status */
+ }
+
+ /* Other cases are done by generic IDE-DMA code. */
+ return cmd64x_dmaproc(func, drive);
+}
+
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+ unsigned char mrdmode;
+ unsigned int class_rev;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ break;
+ case PCI_DEVICE_ID_CMD_646:
+ printk("%s: chipset revision 0x%02X, ", name, class_rev);
+ switch(class_rev) {
+ case 0x07:
+ case 0x05:
+ printk("UltraDMA Capable");
+ break;
+ case 0x03:
+ printk("MultiWord DMA Force Limited");
+ break;
+ case 0x01:
+ default:
+ printk("MultiWord DMA Limited, IRQ workaround enabled");
+ break;
+ }
+ printk("\n");
+ break;
+ case PCI_DEVICE_ID_CMD_648:
+ break;
+ default:
+ break;
+ }
+
+ /* Set a good latency timer and cache line size value. */
+ (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+ (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+ /* Setup interrupts. */
+ (void) pci_read_config_byte(dev, 0x71, &mrdmode);
+ mrdmode &= ~(0x30);
+ (void) pci_write_config_byte(dev, 0x71, mrdmode);
+
+ /* Use MEMORY READ LINE for reads.
+ * NOTE: Although not mentioned in the PCI0646U specs,
+ * these bits are write only and won't be read
+ * back as set or not. The PCI0646U2 specs clarify
+ * this point.
+ */
+ (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02);
+
+ /* Set reasonable active/recovery/address-setup values. */
+ (void) pci_write_config_byte(dev, 0x53, 0x40);
+ (void) pci_write_config_byte(dev, 0x54, 0x3f);
+ (void) pci_write_config_byte(dev, 0x55, 0x40);
+ (void) pci_write_config_byte(dev, 0x56, 0x3f);
+ (void) pci_write_config_byte(dev, 0x57, 0x5c);
+ (void) pci_write_config_byte(dev, 0x58, 0x3f);
+ (void) pci_write_config_byte(dev, 0x5b, 0x3f);
+ return 0;
+}
+
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+ byte ata66 = 0;
+ byte mask = (hwif->channel) ? 0x02 : 0x01;
+
+ pci_read_config_byte(hwif->pci_dev, 0x79, &ata66);
+ return (ata66 & mask) ? 1 : 0;
+}
+
+void __init ide_init_cmd64x (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int class_rev;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ if (!hwif->dma_base)
+ return;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ hwif->dmaproc = &cmd64x_dmaproc;
+ break;
+ case PCI_DEVICE_ID_CMD_646:
+ hwif->chipset = ide_cmd646;
+ if (class_rev == 0x01) {
+ hwif->dmaproc = &cmd646_1_dmaproc;
+ } else {
+ hwif->dmaproc = &cmd64x_dmaproc;
+ }
+ break;
+ case PCI_DEVICE_ID_CMD_648:
+ hwif->dmaproc = &cmd64x_dmaproc;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 8eac89eba..78269edf3 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -171,9 +171,8 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset,
int length, int *eof, void *data) {}
#endif
-static void ida_geninit(struct gendisk *g)
+static void ida_geninit(int ctlr)
{
- int ctlr = g-ida_gendisk;
int i,j;
drv_info_t *drv;
@@ -317,13 +316,6 @@ int __init init_module(void)
cpqarray_init();
if (nr_ctlr == 0)
return -EIO;
-
- for(i=0; i<nr_ctlr; i++) {
- ida_geninit(&ida_gendisk[i]);
- for(j=0; j<NWD; j++)
- if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
- resetup_one_dev(&ida_gendisk[i], j);
- }
return 0;
}
@@ -375,7 +367,7 @@ void __init cpqarray_init(void)
do_ida_request4, do_ida_request5,
do_ida_request6, do_ida_request7,
};
- int i;
+ int i,j;
/* detect controllers */
cpqarray_pci_detect();
@@ -460,22 +452,21 @@ void __init cpqarray_init(void)
hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
ida_procinit(i);
- ida_gendisk[i].major = MAJOR_NR + i;
- ida_gendisk[i].major_name = "ida";
- ida_gendisk[i].minor_shift = NWD_SHIFT;
- ida_gendisk[i].max_p = 16;
- ida_gendisk[i].max_nr = 16;
- ida_gendisk[i].init = ida_geninit;
- ida_gendisk[i].part = ida + (i*256);
- ida_gendisk[i].sizes = ida_sizes + (i*256);
- /* ida_gendisk[i].nr_real is handled by getgeometry */
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]);
blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0);
blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
+
read_ahead[MAJOR_NR+i] = READ_AHEAD;
+ ida_gendisk[i].major = MAJOR_NR + i;
+ ida_gendisk[i].major_name = "ida";
+ ida_gendisk[i].minor_shift = NWD_SHIFT;
+ ida_gendisk[i].max_p = 16;
+ ida_gendisk[i].part = ida + (i*256);
+ ida_gendisk[i].sizes = ida_sizes + (i*256);
+ /* ida_gendisk[i].nr_real is handled by getgeometry */
/* Get on the disk list */
ida_gendisk[i].next = gendisk_head;
@@ -487,6 +478,10 @@ void __init cpqarray_init(void)
hba[i]->timer.function = ida_timer;
add_timer(&hba[i]->timer);
+ ida_geninit(i);
+ for(j=0; j<NWD; j++)
+ register_disk(&ida_gendisk[i], MKDEV(MAJOR_NR+i,j<<4),
+ 16, &ida_fops, hba[i]->drv[j].nr_blks);
}
/* done ! */
return;
@@ -837,7 +832,6 @@ static int ida_release(struct inode *inode, struct file *filep)
int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
- fsync_dev(inode->i_rdev);
hba[ctlr]->drv[dsk].usage_count--;
hba[ctlr]->usage_count--;
@@ -1495,7 +1489,7 @@ static int revalidate_allvol(kdev_t dev)
getgeometry(ctlr);
hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
- ida_geninit(&ida_gendisk[ctlr]);
+ ida_geninit(ctlr);
for(i=0; i<NWD; i++)
if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
@@ -1546,8 +1540,8 @@ static int revalidate_logvol(kdev_t dev, int maxusage)
blksize_size[MAJOR_NR+ctlr][minor] = 1024;
}
- gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blks;
- resetup_one_dev(gdev, target);
+ /* 16 minors per disk... */
+ grok_partitions(gdev, target, 16, hba[ctlr]->drv[target].nr_blks);
hba[ctlr]->drv[target].usage_count--;
return 0;
}
diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c
index 8756713ac..412f403c3 100644
--- a/drivers/block/cy82c693.c
+++ b/drivers/block/cy82c693.c
@@ -275,9 +275,9 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
/* select primary or secondary channel */
if (hwif->index > 0) { /* drive is on the secondary channel */
- dev = pci_find_slot(dev, dev->devfn+1);
+ dev = pci_find_slot(dev->bus->number, dev->devfn+1);
if (!dev) {
- printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n");
+ printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
return;
}
}
@@ -434,8 +434,6 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif)
hwif->tuneproc = &cy82c693_tune_drive;
if (hwif->dma_base) {
hwif->dmaproc = &cy82c693_dmaproc;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 3619cd54f..34f8a3c98 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3629,11 +3629,7 @@ static void config_types(void)
static int floppy_release(struct inode * inode, struct file * filp)
{
- int drive;
-
- drive = DRIVE(inode->i_rdev);
-
- block_fsync(filp, filp->f_dentry);
+ int drive = DRIVE(inode->i_rdev);
if (UDRS->fd_ref < 0)
UDRS->fd_ref=0;
@@ -4170,6 +4166,16 @@ int __init floppy_init(void)
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
unregister_blkdev(MAJOR_NR,"fd");
}
+
+ for (drive = 0; drive < N_DRIVE; drive++) {
+ if (!(allowed_drive_mask & (1 << drive)))
+ continue;
+ if (fdc_state[FDC(drive)].version == FDC_NONE)
+ continue;
+ for (i = 0; i<NUMBER(floppy_type); i++)
+ register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4),
+ 1, &floppy_fops, 0);
+ }
return have_no_fdc;
}
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 3c9a35b97..95999e273 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -28,6 +28,7 @@ extern int soc_probe(void);
extern int atmdev_init(void);
extern int i2o_init(void);
extern int cpqarray_init(void);
+extern void ieee1394_init(void);
void __init device_init(void)
{
@@ -54,6 +55,9 @@ void __init device_init(void)
#ifdef CONFIG_SCSI
scsi_dev_init();
#endif
+#ifdef CONFIG_IEEE1394
+ ieee1394_init();
+#endif
#ifdef CONFIG_BLK_CPQ_DA
cpqarray_init();
#endif
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index e6d03518e..05a17a0c1 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -657,23 +657,16 @@ static int hd_open(struct inode * inode, struct file * filp)
*/
static int hd_release(struct inode * inode, struct file * file)
{
- int target;
- sync_dev(inode->i_rdev);
-
- target = DEVICE_NR(inode->i_rdev);
+ int target = DEVICE_NR(inode->i_rdev);
access_count[target]--;
return 0;
}
-static void hd_geninit(struct gendisk *);
-
static struct gendisk hd_gendisk = {
MAJOR_NR, /* Major number */
"hd", /* Major name */
6, /* Bits to shift to get real from partition */
1 << 6, /* Number of partitions per real */
- MAX_HD, /* maximum number of real */
- hd_geninit, /* init function */
hd, /* hd struct */
hd_sizes, /* block sizes */
0, /* number */
@@ -693,6 +686,12 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
}
+static struct block_device_operations hd_fops = {
+ open: hd_open,
+ release: hd_release,
+ ioctl: hd_ioctl,
+};
+
/*
* This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
* means we run the IRQ-handler with interrupts disabled: this is bad for
@@ -702,10 +701,17 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* We enable interrupts in some of the routines after making sure it's
* safe.
*/
-static void hd_geninit(struct gendisk *ignored)
+static void hd_geninit(void)
{
int drive;
+ for(drive=0; drive < (MAX_HD << 6); drive++) {
+ hd_blocksizes[drive] = 1024;
+ hd_hardsectsizes[drive] = 512;
+ }
+ blksize_size[MAJOR_NR] = hd_blocksizes;
+ hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+
#ifdef __i386__
if (!NR_HD) {
extern struct drive_info drive_info;
@@ -768,37 +774,30 @@ static void hd_geninit(struct gendisk *ignored)
#endif
for (drive=0 ; drive < NR_HD ; drive++) {
- hd[drive<<6].nr_sects = hd_info[drive].head *
- hd_info[drive].sect * hd_info[drive].cyl;
printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
hd_info[drive].head, hd_info[drive].sect);
}
- if (NR_HD) {
- if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
- printk("hd: unable to get IRQ%d for the hard disk driver\n",HD_IRQ);
- NR_HD = 0;
- } else {
- request_region(HD_DATA, 8, "hd");
- request_region(HD_CMD, 1, "hd(cmd)");
- }
+ if (!NR_HD)
+ return;
+
+ if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+ printk("hd: unable to get IRQ%d for the hard disk driver\n",
+ HD_IRQ);
+ NR_HD = 0;
+ return;
}
+ request_region(HD_DATA, 8, "hd");
+ request_region(HD_CMD, 1, "hd(cmd)");
+
hd_gendisk.nr_real = NR_HD;
- for(drive=0; drive < (MAX_HD << 6); drive++) {
- hd_blocksizes[drive] = 1024;
- hd_hardsectsizes[drive] = 512;
- }
- blksize_size[MAJOR_NR] = hd_blocksizes;
- hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+ for(drive=0; drive < NR_HD; drive++)
+ register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
+ &hd_fops, hd_info[drive].head * hd_info[drive].sect *
+ hd_info[drive].cyl);
}
-static struct block_device_operations hd_fops = {
- open: hd_open,
- release: hd_release,
- ioctl: hd_ioctl,
-};
-
int __init hd_init(void)
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
@@ -810,6 +809,7 @@ int __init hd_init(void)
hd_gendisk.next = gendisk_head;
gendisk_head = &hd_gendisk;
timer_table[HD_TIMER].fn = hd_times_out;
+ hd_geninit();
return 0;
}
@@ -870,8 +870,7 @@ static int revalidate_hddisk(kdev_t dev, int maxusage)
MAYBE_REINIT;
#endif
- gdev->part[start].nr_sects = CAPACITY;
- resetup_one_dev(gdev, target);
+ grok_partitions(gdev, target, 1<<6, CAPACITY);
DEVICE_BUSY = 0;
wake_up(&busy_wait);
diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c
index 104feade5..f01d93152 100644
--- a/drivers/block/hpt34x.c
+++ b/drivers/block/hpt34x.c
@@ -377,8 +377,6 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif)
#endif
#endif /* CONFIG_BLK_DEV_HPT34X_DMA */
hwif->dmaproc = &hpt34x_dmaproc;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c
index 0c5450185..1b497fecc 100644
--- a/drivers/block/hpt366.c
+++ b/drivers/block/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hpt366.c Version 0.14 Dec. 13, 1999
+ * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999
*
* Copyright (C) 1999 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -30,6 +30,7 @@
#include "ide_modes.h"
const char *bad_ata66_4[] = {
+ "QUANTUM FIREBALLP KA9.1",
"WDC AC310200R",
NULL
};
@@ -121,6 +122,7 @@ struct chipset_bus_clock_list_entry twenty_five_base [] = {
extern char *ide_xfer_verbose (byte xfer_rate);
byte hpt363_shared_irq = 0;
+byte hpt363_shared_pin = 0;
static int check_in_drive_lists (ide_drive_t *drive, const char **list)
{
@@ -421,34 +423,31 @@ no_dma_set:
int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
-#if 0
- byte reg50h = 0, reg52h = 0;
-#endif
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
-#if 0
- case ide_dma_lostirq:
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
- printk("%s: (ide_dma_lostirq) reg52h=0x%02x\n", drive->name, reg52h);
- break;
case ide_dma_timeout:
- (void) ide_dmaproc(ide_dma_off_quietly, drive);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
- printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h);
- if (reg52h & 0x04) {
+ /* ide_do_reset(drive); */
+
+ if (0) {
+ byte reg50h = 0, reg52h = 0;
+ (void) ide_dmaproc(ide_dma_off_quietly, drive);
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
+ printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h);
+ if (reg52h & 0x04) {
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h);
+ }
pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h);
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
+ printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h);
+ (void) ide_dmaproc(ide_dma_on, drive);
+ if (reg52h & 0x04)
+ (void) ide_dmaproc(ide_dma_off, drive);
}
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
- printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h);
- (void) ide_dmaproc(ide_dma_on, drive);
- if (reg52h & 0x04)
- (void) ide_dmaproc(ide_dma_off, drive);
- return 1;
-#endif
+ break;
default:
break;
}
@@ -502,15 +501,15 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif)
hwif->mate->mate = hwif;
hwif->serialized = hwif->mate->serialized = 1;
}
+
+ if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) {
+
+ }
#endif
hwif->tuneproc = &hpt366_tune_drive;
if (hwif->dma_base) {
hwif->dmaproc = &hpt366_dmaproc;
-#if 0
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
-#endif
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c
index ebfef4273..48cf87c81 100644
--- a/drivers/block/ide-cd.c
+++ b/drivers/block/ide-cd.c
@@ -2005,9 +2005,60 @@ int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
return cdrom_lockdoor (drive, lock);
}
+#undef __ACER50__
+
+#ifdef __ACER50__
+/*
+ * the buffer struct used by ide_cdrom_get_capabilities()
+ */
+struct get_capabilities_buf {
+ char pad[8];
+ struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */
+ char extra_cap[4]; /* Acer 50X needs the regulation size buffer */
+};
+
+static
+int ide_cdrom_get_capabilities (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf)
+{
+ int stat, attempts = 3, buflen = sizeof(*buf);
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct cdrom_generic_command cgc;
+
+ /*
+ * Most drives don't care about the buffer size;
+ * they return as much info as there's room for.
+ * But some older drives (?) had trouble with the
+ * standard size, preferring 4 bytes less.
+ * And the modern Acer 50X rejects anything smaller
+ * than the standard size.
+ */
+ if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX")))
+ buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */
+
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+ if (stat == 0) {
+ /*
+ * The ACER/AOpen 24X cdrom has the speed
+ * fields byte-swapped from the standard.
+ */
+ if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) {
+ buf->cap.curspeed = ntohs(buf->cap.curspeed);
+ buf->cap.maxspeed = ntohs(buf->cap.maxspeed);
+ }
+ CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176;
+ return 0;
+ }
+ } while (--attempts);
+ return stat;
+}
+#endif /* __ACER50__ */
+
static
int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
{
+#ifndef __ACER50__
int stat, attempts = 3;
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
struct cdrom_generic_command cgc;
@@ -2015,11 +2066,19 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
char pad[8];
struct atapi_capabilities_page cap;
} buf;
+#else
+ int stat;
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct cdrom_generic_command cgc;
+ struct get_capabilities_buf buf;
+#endif /* __ACER50__ */
if ((stat = cdrom_select_speed (drive, speed)) < 0)
return stat;
init_cdrom_command(&cgc, &buf, sizeof(buf));
+
+#ifndef __ACER50__
/* Now with that done, update the speed fields */
do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
if (attempts-- <= 0)
@@ -2039,6 +2098,11 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
CDROM_CONFIG_FLAGS (drive)->max_speed =
(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
}
+#else
+ if (ide_cdrom_get_capabilities(cdi,&buf))
+ return 0;
+#endif /* __ACER50__ */
+
cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
return 0;
}
@@ -2216,12 +2280,18 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
{
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo;
+#ifndef __ACER50__
int stat, nslots = 1, attempts = 3;
struct cdrom_generic_command cgc;
struct {
char pad[8];
struct atapi_capabilities_page cap;
} buf;
+#else
+ int nslots = 1;
+ struct cdrom_generic_command cgc;
+ struct get_capabilities_buf buf;
+#endif /* __ACER50__ */
if (CDROM_CONFIG_FLAGS (drive)->nec260) {
CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
@@ -2238,12 +2308,17 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
*/
cdi->handle = (ide_drive_t *) drive;
cdi->ops = &ide_cdrom_dops;
+#ifndef __ACER50__
/* we seem to get stat=0x01,err=0x00 the first time (??) */
do {
if (attempts-- <= 0)
return 0;
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
} while (stat);
+#else
+ if (ide_cdrom_get_capabilities(cdi,&buf))
+ return 0;
+#endif /* __ACER50__ */
if (buf.cap.lock == 0)
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
@@ -2282,6 +2357,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
}
}
+#ifndef __ACER50__
/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
CDROM_STATE_FLAGS (drive)->current_speed =
@@ -2294,6 +2370,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
CDROM_CONFIG_FLAGS (drive)->max_speed =
(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
}
+#endif /* __ACER50__ */
/* don't print speed if the drive reported 0.
*/
@@ -2321,7 +2398,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
if (drive->using_dma) {
if ((drive->id->field_valid & 4) &&
- (drive->id->word93 & 0x2000) &&
+ (drive->id->hw_config & 0x2000) &&
(HWIF(drive)->udma_four) &&
(drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) {
printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
@@ -2598,7 +2675,7 @@ void __exit ide_cdrom_exit(void)
}
#endif /* MODULE */
-int __init ide_cdrom_init (void)
+int ide_cdrom_init (void)
{
ide_drive_t *drive;
struct cdrom_info *info;
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 3efbe8912..14952a049 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -139,10 +139,20 @@ static ide_startstop_t read_intr (ide_drive_t *drive)
int i;
unsigned int msect, nsect;
struct request *rq;
-
+#if 0
if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
return ide_error(drive, "read_intr", stat);
}
+#else /* new way for dealing with premature shared PCI interrupts */
+ if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ return ide_error(drive, "read_intr", stat);
+ }
+ /* no data yet, so wait for another interrupt */
+ ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+#endif
msect = drive->mult_count;
read_next:
@@ -163,7 +173,7 @@ read_next:
rq->buffer += nsect<<9;
rq->errors = 0;
i = (rq->nr_sectors -= nsect);
- if ((rq->current_nr_sectors -= nsect) <= 0)
+ if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
ide_end_request(1, HWGROUP(drive));
if (i > 0) {
if (msect)
@@ -198,7 +208,7 @@ static ide_startstop_t write_intr (ide_drive_t *drive)
rq->errors = 0;
i = --rq->nr_sectors;
--rq->current_nr_sectors;
- if (rq->current_nr_sectors <= 0)
+ if (((long)rq->current_nr_sectors) <= 0)
ide_end_request(1, hwgroup);
if (i > 0) {
idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
@@ -207,8 +217,8 @@ static ide_startstop_t write_intr (ide_drive_t *drive)
}
return ide_stopped;
}
- printk("%s: write_intr error2: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
- }
+ return ide_stopped; /* the original code did this here (?) */
+ }
return ide_error(drive, "write_intr", stat);
}
@@ -221,12 +231,22 @@ static ide_startstop_t write_intr (ide_drive_t *drive)
int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
{
ide_hwgroup_t *hwgroup= HWGROUP(drive);
+
+ /*
+ * This may look a bit odd, but remember wrq is a copy of the
+ * request not the original. The pointers are real however so the
+ * bh's are not copies. Remember that or bad stuff will happen
+ *
+ * At the point we are called the drive has asked us for the
+ * data, and its our job to feed it, walking across bh boundaries
+ * if need be.
+ */
+
struct request *rq = &hwgroup->wrq;
do {
unsigned long flags;
unsigned int nsect = rq->current_nr_sectors;
-
if (nsect > mcount)
nsect = mcount;
mcount -= nsect;
@@ -241,9 +261,11 @@ int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
#ifdef CONFIG_BLK_DEV_PDC4030
rq->sector += nsect;
#endif
- if ((rq->nr_sectors -= nsect) <= 0) {
+ if (((long)(rq->nr_sectors -= nsect)) <= 0) {
+#ifdef DEBUG
printk("%s: multwrite: count=%d, current=%ld\n",
drive->name, nsect, rq->nr_sectors);
+#endif
spin_unlock_irqrestore(&io_request_lock, flags);
break;
}
@@ -253,11 +275,14 @@ int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
rq->buffer = rq->bh->b_data;
} else {
spin_unlock_irqrestore(&io_request_lock, flags);
- printk("%s: buffer list corrupted\n", drive->name);
+ printk("%s: buffer list corrupted (%ld, %ld, %d)\n",
+ drive->name, rq->current_nr_sectors,
+ rq->nr_sectors, nsect);
ide_end_request(0, hwgroup);
return 1;
}
} else {
+ /* Fix the pointer.. we ate data */
rq->buffer += nsect << 9;
}
spin_unlock_irqrestore(&io_request_lock, flags);
@@ -277,6 +302,10 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive)
if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
if (stat & DRQ_STAT) {
+ /*
+ * The drive wants data. Remember rq is the copy
+ * of the request
+ */
if (rq->nr_sectors) {
if (ide_multwrite(drive, drive->mult_count))
return ide_stopped;
@@ -284,6 +313,10 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive)
return ide_started;
}
} else {
+ /*
+ * If the copy has all the blocks completed then
+ * we can end the original request.
+ */
if (!rq->nr_sectors) { /* all done? */
rq = hwgroup->rq;
for (i = rq->nr_sectors; i > 0;){
@@ -293,6 +326,7 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive)
return ide_stopped;
}
}
+ return ide_stopped; /* the original code did this here (?) */
}
return ide_error(drive, "multwrite_intr", stat);
}
@@ -302,13 +336,9 @@ static ide_startstop_t multwrite_intr (ide_drive_t *drive)
*/
static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
{
- byte stat = GET_STAT();
+ byte stat;
-#if 0
- if (OK_STAT(stat,READY_STAT,BAD_STAT) || drive->mult_req == 0) {
-#else
- if (OK_STAT(stat,READY_STAT,BAD_STAT)) {
-#endif
+ if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
drive->mult_count = drive->mult_req;
} else {
drive->mult_req = drive->mult_count = 0;
@@ -323,11 +353,16 @@ static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
*/
static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
{
- byte stat = GET_STAT();
+ byte stat;
- if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+ if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+ return ide_stopped;
+
+ if (stat & (ERR_STAT|DRQ_STAT))
return ide_error(drive, "set_geometry_intr", stat);
- return ide_stopped;
+
+ ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+ return ide_started;
}
/*
@@ -419,6 +454,8 @@ static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsig
* of data to be written. If we hit an error (corrupted buffer list)
* in ide_multwrite(), then we need to remove the handler/timer
* before returning. Fortunately, this NEVER happens (right?).
+ *
+ * Except when you get an error it seems...
*/
hwgroup->wrq = *rq; /* scratchpad */
ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
@@ -772,7 +809,7 @@ static void idedisk_setup (ide_drive_t *drive)
drive->bios_cyl, drive->bios_head, drive->bios_sect);
if (drive->using_dma) {
- if ((id->field_valid & 4) && (id->word93 & 0x2000) &&
+ if ((id->field_valid & 4) && (id->hw_config & 0x2000) &&
(HWIF(drive)->udma_four) &&
(id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index 083039e62..f265180ab 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -358,7 +358,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
return hwif->dmaproc(ide_dma_off, drive);
/* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */
- if ((id->field_valid & 4) && (hwif->udma_four) && (id->word93 & 0x2000))
+ if ((id->field_valid & 4) && (hwif->udma_four) && (id->hw_config & 0x2000))
if ((id->dma_ultra & (id->dma_ultra >> 11) & 3))
return hwif->dmaproc(ide_dma_on, drive);
/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
diff --git a/drivers/block/ide-features.c b/drivers/block/ide-features.c
index 3167dc7fd..87b7cacb4 100644
--- a/drivers/block/ide-features.c
+++ b/drivers/block/ide-features.c
@@ -188,7 +188,7 @@ int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature)
printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
return 1;
}
- if ((drive->id->word93 & 0x2000) == 0) {
+ if ((drive->id->hw_config & 0x2000) == 0) {
printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
return 1;
}
@@ -213,6 +213,22 @@ int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature)
return 0;
}
+#if 0
+ide_startstop_t set_drive_speed_intr (ide_drive_t *drive)
+{
+ byte stat;
+
+ if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+/*
+ * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT))
+ * if (stat != DRIVE_READY)
+ */
+ (void) ide_dump_status(drive, "set_drive_speed_status", stat);
+
+ return ide_stopped;
+}
+#endif
+
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
unsigned long flags;
@@ -244,6 +260,10 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
__restore_flags(flags); /* local CPU only */
+#if 0
+ ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL);
+#endif
+
stat = GET_STAT();
if (stat != DRIVE_READY)
(void) ide_dump_status(drive, "set_drive_speed_status", stat);
diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c
index 79abaca2b..0f24b0ac3 100644
--- a/drivers/block/ide-geometry.c
+++ b/drivers/block/ide-geometry.c
@@ -60,6 +60,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
/* Extract drive geometry from CMOS+BIOS if not already setup */
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
+#if 0
if ((cmos_disks & (0xf0 >> (unit*4))) &&
!drive->present && !drive->nobios) {
drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
@@ -67,6 +68,22 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
drive->sect = drive->bios_sect = *(BIOS+14);
drive->ctl = *(BIOS+8);
}
+#else
+ if ((cmos_disks & (0xf0 >> (unit*4)))
+ && !drive->present && !drive->nobios) {
+ unsigned short cyl = *(unsigned short *)BIOS;
+ unsigned char head = *(BIOS+2);
+ unsigned char sect = *(BIOS+14);
+ if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
+ drive->cyl = drive->bios_cyl = cyl;
+ drive->head = drive->bios_head = head;
+ drive->sect = drive->bios_sect = sect;
+ drive->ctl = *(BIOS+8);
+ } else {
+ printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit, cyl, head, sect);
+ }
+ }
+#endif
BIOS += 16;
}
#endif
@@ -78,7 +95,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
* Otherwise: find out how OnTrack Disk Manager would translate the disk.
*/
static void
-ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) {
+ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
const byte *headp = dm_head_vals;
unsigned long total, tracks;
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
index 5823e1b0d..6ee45c49d 100644
--- a/drivers/block/ide-pci.c
+++ b/drivers/block/ide-pci.c
@@ -41,6 +41,7 @@
#define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640})
#define DEVID_CMD643 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643})
#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646})
+#define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648})
#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513})
#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621})
#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558})
@@ -60,7 +61,7 @@
#define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693})
#define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013})
#define DEVID_CX5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, 0x7409})
+#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409})
#define IDE_IGNORE ((void *)-1)
@@ -93,14 +94,31 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
#define DMA_ALI15X3 NULL
#endif
-#ifdef CONFIG_BLK_DEV_CMD646
-extern void ide_init_cmd646(ide_hwif_t *);
-#define INIT_CMD646 &ide_init_cmd646
+#ifdef CONFIG_BLK_DEV_AMD7409
+extern unsigned int ata66_amd7409(ide_hwif_t *);
+extern void ide_init_amd7409(ide_hwif_t *);
+#define ATA66_AMD7409 &ata66_amd7409
+#define INIT_AMD7409 &ide_init_amd7409
#else
+#define ATA66_AMD7409 NULL
+#define INIT_AMD7409 NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_CMD64X
+extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
+extern unsigned int ata66_cmd64x(ide_hwif_t *);
+extern void ide_init_cmd64x(ide_hwif_t *);
+extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
+#define PCI_CMD64X &pci_init_cmd64x
+#define ATA66_CMD64X &ata66_cmd64x
+#define INIT_CMD64X &ide_init_cmd64x
+#else
+#define PCI_CMD64X NULL
+#define ATA66_CMD64X NULL
#ifdef __sparc_v9__
-#define INIT_CMD646 IDE_IGNORE
+#define INIT_CMD64X IDE_IGNORE
#else
-#define INIT_CMD646 NULL
+#define INIT_CMD64X NULL
#endif
#endif
@@ -128,6 +146,7 @@ extern void ide_init_hpt34x(ide_hwif_t *);
#ifdef CONFIG_BLK_DEV_HPT366
extern byte hpt363_shared_irq;
+extern byte hpt363_shared_pin;
extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
extern unsigned int ata66_hpt366(ide_hwif_t *);
extern void ide_init_hpt366(ide_hwif_t *);
@@ -138,6 +157,7 @@ extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
#define DMA_HPT366 &ide_dmacapable_hpt366
#else
static byte hpt363_shared_irq = 0;
+static byte hpt363_shared_pin = 0;
#define PCI_HPT366 NULL
#define ATA66_HPT366 NULL
#define INIT_HPT366 NULL
@@ -271,8 +291,9 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 },
{DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 },
- {DEVID_CMD643, "CMD643", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
- {DEVID_CMD646, "CMD646", NULL, NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_CMD643, "CMD643", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
{DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
@@ -289,7 +310,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_CX5530, "CX5530", NULL, NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
- {DEVID_AMD7409, "AMD7409", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
{IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }};
/*
@@ -496,6 +517,8 @@ check_if_enabled:
printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
pciirq = 0;
} else {
+ if (d->init_chipset)
+ (void) d->init_chipset(dev, d->name);
#ifdef __sparc__
printk("%s: 100%% native mode on irq %s\n",
d->name, __irq_itoa(pciirq));
@@ -642,8 +665,9 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_devic
(PCI_FUNC(findev->devfn) & 1)) {
dev2 = findev;
pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
- hpt363_shared_irq = (pin1 != pin2) ? 1 : 0;
- if (hpt363_shared_irq) {
+ hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
+ hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
+ if (hpt363_shared_pin && hpt363_shared_irq) {
d->bootable = ON_BOARD;
printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
}
@@ -656,6 +680,15 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_devic
return;
d2 = d;
printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+ if (hpt363_shared_pin && !hpt363_shared_irq) {
+ printk("%s: IDE controller run unsupported mode three!!!\n", d2->name);
+#ifndef HPT366_MODE3
+ printk("%s: IDE controller report to <andre@suse.com>\n", d->name);
+ return;
+#else /* HPT366_MODE3 */
+ printk("%s: OVERRIDE IDE controller not advisable this mode!!!\n", d2->name);
+#endif /* HPT366_MODE3 */
+ }
ide_setup_pci_device(dev2, d2);
}
@@ -663,7 +696,7 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_devic
* ide_scan_pcibus() gets invoked at boot time from ide.c.
* It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
*/
-void __init ide_scan_pcibus (void)
+void __init ide_forward_scan_pcibus (void)
{
struct pci_dev *dev;
ide_pci_devid_t devid;
@@ -693,3 +726,40 @@ void __init ide_scan_pcibus (void)
}
}
}
+
+void __init ide_reverse_scan_pcibus (void)
+{
+ struct pci_dev *dev;
+ ide_pci_devid_t devid;
+ ide_pci_device_t *d;
+
+ pci_for_each_dev_reverse(dev) {
+ devid.vid = dev->vendor;
+ devid.did = dev->device;
+ for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+ if (d->init_hwif == IDE_IGNORE)
+ printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
+ continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+ continue; /* CY82C693 is more than only a IDE controller */
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
+ continue; /* UM8886A/BF pair */
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
+ hpt366_device_order_fixup(dev, d);
+ else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
+ printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
+ d->name, dev->bus->number, dev->devfn, devid.vid, devid.did);
+ else
+ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+ ide_setup_pci_device(dev, d);
+ }
+ }
+}
+
+void __init ide_scan_pcibus (int scan_direction)
+{
+ if (!scan_direction) ide_forward_scan_pcibus();
+ else ide_reverse_scan_pcibus();
+}
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 5f0ebb7b6..efb4705f3 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -687,9 +687,7 @@ static void init_gendisk (ide_hwif_t *hwif)
gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */
gd->minor_shift = PARTN_BITS; /* num bits for partitions */
gd->max_p = 1<<PARTN_BITS; /* 1 + max partitions / drive */
- gd->max_nr = units; /* max num real drives */
gd->nr_real = units; /* current num real drives */
- gd->init = &ide_geninit; /* initialization function */
gd->real_devices= hwif; /* ptr to internal data */
gd->next = NULL; /* linked list of major devs */
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 7b8945ae0..429888f32 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.16e Oct 3, 1999
+ * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999
*
* Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
*
@@ -224,6 +224,57 @@
* case the tape block size is larger than PAGE_SIZE.
* Decrease the default disconnection time to tn.
* Ver 1.16e Oct 3 99 Minor fixes.
+ * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen,
+ * niessen@iae.nl / arnold.niessen@philips.com
+ * GO-1) Undefined code in idetape_read_position
+ * according to Gadi's email
+ * AJN-1) Minor fix asc == 11 should be asc == 0x11
+ * in idetape_issue_packet_command (did effect
+ * debugging output only)
+ * AJN-2) Added more debugging output, and
+ * added ide-tape: where missing. I would also
+ * like to add tape->name where possible
+ * AJN-3) Added different debug_level's
+ * via /proc/ide/hdc/settings
+ * "debug_level" determines amount of debugging output;
+ * can be changed using /proc/ide/hdx/settings
+ * 0 : almost no debugging output
+ * 1 : 0+output errors only
+ * 2 : 1+output all sensekey/asc
+ * 3 : 2+follow all chrdev related procedures
+ * 4 : 3+follow all procedures
+ * 5 : 4+include pc_stack rq_stack info
+ * 6 : 5+USE_COUNT updates
+ * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ * from 5 to 10 minutes
+ * AJN-5) Changed maximum number of blocks to skip when
+ * reading tapes with multiple consecutive write
+ * errors from 100 to 1000 in idetape_get_logical_blk
+ * Proposed changes to code:
+ * 1) output "logical_blk_num" via /proc
+ * 2) output "current_operation" via /proc
+ * 3) Either solve or document the fact that `mt rewind' is
+ * required after reading from /dev/nhtx to be
+ * able to rmmod the idetape module;
+ * Also, sometimes an application finishes but the
+ * device remains `busy' for some time. Same cause ?
+ * Proposed changes to release-notes:
+ * 4) write a simple `quickstart' section in the
+ * release notes; I volunteer if you don't want to
+ * 5) include a pointer to video4linux in the doc
+ * to stimulate video applications
+ * 6) release notes lines 331 and 362: explain what happens
+ * if the application data rate is higher than 1100 KB/s;
+ * similar approach to lower-than-500 kB/s ?
+ * 7) 6.6 Comparison; wouldn't it be better to allow different
+ * strategies for read and write ?
+ * Wouldn't it be better to control the tape buffer
+ * contents instead of the bandwidth ?
+ * 8) line 536: replace will by would (if I understand
+ * this section correctly, a hypothetical and unwanted situation
+ * is being described)
+ * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames.
+ *
*
* Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well:
@@ -361,7 +412,7 @@
/*
* OnStream support
*/
-#define ONSTREAM_DEBUG (0)
+#define ONSTREAM_DEBUG (1)
#define OS_CONFIG_PARTITION (0xff)
#define OS_DATA_PARTITION (0)
#define OS_PARTITION_VERSION (1)
@@ -502,7 +553,7 @@ typedef struct os_header_s {
* is verified to be stable enough. This will make it much more
* esthetic.
*/
-#define IDETAPE_DEBUG_LOG 0
+#define IDETAPE_DEBUG_LOG 1
#define IDETAPE_DEBUG_BUGS 1
/*
@@ -755,7 +806,7 @@ typedef struct {
* NULL if we do not need to retry any packet command. This is
* required since an additional packet command is needed before the
* retry, to get detailed information on what went wrong.
- */
+ */
idetape_pc_t *pc; /* Current packet command */
idetape_pc_t *failed_pc; /* Last failed packet command */
idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
@@ -941,6 +992,19 @@ typedef struct {
int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head;
unsigned long controlled_previous_head_time, uncontrolled_previous_head_time;
int restart_speed_control_req;
+
+ /*
+ * Debug_level determines amount of debugging output;
+ * can be changed using /proc/ide/hdx/settings
+ * 0 : almost no debugging output
+ * 1 : 0+output errors only
+ * 2 : 1+output all sensekey/asc
+ * 3 : 2+follow all chrdev related procedures
+ * 4 : 3+follow all procedures
+ * 5 : 4+include pc_stack rq_stack info
+ * 6 : 5+USE_COUNT updates
+ */
+ int debug_level;
} idetape_tape_t;
/*
@@ -1386,7 +1450,8 @@ static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+ if (tape->debug_level >= 5)
+ printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
#endif /* IDETAPE_DEBUG_LOG */
if (tape->pc_stack_index==IDETAPE_PC_STACK)
tape->pc_stack_index=0;
@@ -1411,7 +1476,8 @@ static struct request *idetape_next_rq_storage (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+ if (tape->debug_level >= 5)
+ printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
#endif /* IDETAPE_DEBUG_LOG */
if (tape->rq_stack_index==IDETAPE_PC_STACK)
tape->rq_stack_index=0;
@@ -1450,7 +1516,8 @@ static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_resu
* Without debugging, we only log an error if we decided to
* give up retrying.
*/
- printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
+ if (tape->debug_level >= 1)
+ printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
#endif /* IDETAPE_DEBUG_LOG */
if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
@@ -1494,7 +1561,8 @@ static void idetape_abort_pipeline (ide_drive_t *drive)
idetape_stage_t *stage = tape->next_stage;
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
#endif
while (stage) {
if (stage->rq.cmd == IDETAPE_WRITE_RQ)
@@ -1515,7 +1583,8 @@ static void idetape_active_next_stage (ide_drive_t *drive)
struct request *rq = &stage->rq;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_active_next_stage\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
#endif /* IDETAPE_DEBUG_LOG */
#if IDETAPE_DEBUG_BUGS
if (stage == NULL) {
@@ -1544,7 +1613,8 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_increase_max_pipeline_stages\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
#endif /* IDETAPE_DEBUG_LOG */
tape->max_stages += increase;
@@ -1592,7 +1662,8 @@ static void idetape_remove_stage_head (ide_drive_t *drive)
idetape_stage_t *stage;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_remove_stage_head\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
#endif /* IDETAPE_DEBUG_LOG */
#if IDETAPE_DEBUG_BUGS
if (tape->first_stage == NULL) {
@@ -1638,7 +1709,8 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
#endif
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_end_request\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
#endif /* IDETAPE_DEBUG_LOG */
switch (uptodate) {
@@ -1657,17 +1729,20 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
tape->nr_pending_stages--;
if (rq->cmd == IDETAPE_WRITE_RQ) {
#if ONSTREAM_DEBUG
- if (tape->onstream) {
- stage = tape->first_stage;
- aux = stage->aux;
- p = stage->bh->b_data;
- if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
- printk(KERN_INFO "finished writing logical blk %lu (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
+ if (tape->debug_level >= 2) {
+ if (tape->onstream) {
+ stage = tape->first_stage;
+ aux = stage->aux;
+ p = stage->bh->b_data;
+ if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
+ printk(KERN_INFO "ide-tape: finished writing logical blk %lu (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
+ }
}
#endif
if (tape->onstream && !tape->raw) {
if (tape->first_frame_position == 0xba4) {
#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 2)
printk("ide-tape: %s: skipping over config parition..\n", tape->name);
#endif
tape->onstream_write_error = 2;
@@ -1723,13 +1798,14 @@ static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
#endif /* IDETAPE_DEBUG_LOG */
if (!tape->pc->error) {
idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer);
idetape_end_request (1,HWGROUP (drive));
} else {
- printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+ printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
idetape_end_request (0,HWGROUP (drive));
}
return ide_stopped;
@@ -1802,7 +1878,8 @@ static void idetape_postpone_request (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "idetape_postpone_request\n");
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
#endif
tape->postponed_rq = HWGROUP(drive)->rq;
ide_stall_queue(drive, tape->dsc_polling_frequency);
@@ -1831,7 +1908,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
#endif
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
#endif /* IDETAPE_DEBUG_LOG */
status.all = GET_STAT(); /* Clear the interrupt */
@@ -1856,7 +1934,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
idetape_update_buffers (pc);
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: DMA finished\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: DMA finished\n");
#endif /* IDETAPE_DEBUG_LOG */
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1865,7 +1944,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
#endif /* IDETAPE_DEBUG_LOG */
clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
@@ -1881,14 +1961,16 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
status.b.check = 0;
if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
+ if (tape->debug_level >= 1)
+ printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
#endif /* IDETAPE_DEBUG_LOG */
if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
return ide_do_reset (drive);
}
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "[cmd %x]: check condition\n", pc->c[0]);
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
#endif
return idetape_retry_pc (drive); /* Retry operation */
}
@@ -1922,7 +2004,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
}
if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */
printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
- printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
+ printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
return ide_do_reset (drive);
}
if (!test_bit (PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */
@@ -1935,7 +2017,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
return ide_started;
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+ if (tape->debug_level >= 2)
+ printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
#endif /* IDETAPE_DEBUG_LOG */
}
}
@@ -1953,7 +2036,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "[cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
#endif
ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */
return ide_started;
@@ -2061,7 +2145,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
if (!(pc->c[0] == 0 && tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
- if (tape->onstream && pc->c[0] == 8 && tape->sense_key == 3 && tape->asc == 11)
+ if (tape->onstream && pc->c[0] == 8 && tape->sense_key == 3 && tape->asc == 0x11) /* AJN-1: 11 should be 0x11 */
printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
}
pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */
@@ -2070,7 +2154,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
return pc->callback(drive);
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Retry number - %d\n",pc->retries);
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: Retry number - %d\n",pc->retries);
#endif /* IDETAPE_DEBUG_LOG */
pc->retries++;
@@ -2117,7 +2202,8 @@ static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
#endif /* IDETAPE_DEBUG_LOG */
idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
@@ -2163,7 +2249,8 @@ static ide_startstop_t idetape_onstream_buffer_fill_callback (ide_drive_t *drive
IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
#endif
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
#endif
idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
return ide_stopped;
@@ -2277,7 +2364,8 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
#endif /* IDETAPE_DEBUG_LOG */
tape->first_frame_position += blocks;
@@ -2384,8 +2472,10 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
idetape_status_reg_t status;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
- printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+ if (tape->debug_level >= 5)
+ printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
#endif /* IDETAPE_DEBUG_LOG */
if (!IDETAPE_RQ_CMD (rq->cmd)) {
@@ -2456,15 +2546,17 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
((rq->cmd == IDETAPE_WRITE_RQ && (tape->cur_frames == tape->max_frames || (tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */))))) ||
(rq->cmd == IDETAPE_READ_RQ && (tape->cur_frames == 0 || (tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed)) && rq->nr_sectors))) {
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "postponing request, cmd %d, cur %d, max %d\n",
- rq->cmd, tape->cur_frames, tape->max_frames);
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
+ rq->cmd, tape->cur_frames, tape->max_frames);
#endif
if (tape->postpone_cnt++ < 500) {
status.b.dsc = 0;
tape->req_buffer_fill = 1;
}
#if ONSTREAM_DEBUG
- else printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+ else if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
#endif
}
if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
@@ -2530,7 +2622,8 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
return ide_stopped;
case IDETAPE_ABORTED_READ_RQ:
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
#endif
rq->cmd = IDETAPE_READ_RQ;
idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
@@ -2643,7 +2736,8 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
idetape_stage_t *cache_stage = tape->cache_stage;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_kmalloc_stage\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
#endif /* IDETAPE_DEBUG_LOG */
if (tape->nr_stages >= tape->max_stages)
@@ -2737,7 +2831,8 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
unsigned long flags;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_add_stage_tail\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
#endif /* IDETAPE_DEBUG_LOG */
spin_lock_irqsave(&tape->spinlock, flags);
stage->next=NULL;
@@ -2851,14 +2946,17 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
idetape_read_position_result_t *result;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
#endif /* IDETAPE_DEBUG_LOG */
if (!tape->pc->error) {
result = (idetape_read_position_result_t *) tape->pc->buffer;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "BOP - %s\n",result->bop ? "Yes":"No");
- printk (KERN_INFO "EOP - %s\n",result->eop ? "Yes":"No");
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
#endif /* IDETAPE_DEBUG_LOG */
if (result->bpu) {
printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
@@ -2866,7 +2964,8 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
idetape_end_request (0,HWGROUP (drive));
} else {
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Block Location - %lu\n", ntohl (result->first_block));
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: Block Location - %lu\n", ntohl (result->first_block));
#endif /* IDETAPE_DEBUG_LOG */
tape->partition = result->partition;
tape->first_frame_position = ntohl (result->first_block);
@@ -2952,7 +3051,7 @@ static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc
pc->callback = &idetape_pc_callback;
}
-static int idetape_wait_ready(ide_drive_t *drive, unsigned long long timeout)
+static int idetape_wait_ready (ide_drive_t *drive, unsigned long long timeout)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
@@ -2975,7 +3074,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long long timeout)
if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
break;
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 10);
+ schedule_timeout(HZ / 10);
}
return -EIO;
}
@@ -2988,7 +3087,8 @@ static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
rc = __idetape_queue_pc_tail(drive, pc);
if (rc) return rc;
if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
- rc = idetape_wait_ready(drive, 60 * 5 * HZ);
+ rc = idetape_wait_ready(drive, 60 * 10 * HZ); /* AJN-4: Changed from 5 to 10 minutes;
+ because retension takes approx. 8:20 with Onstream 30GB tape */
return rc;
}
@@ -3012,17 +3112,20 @@ static void idetape_create_read_position_cmd (idetape_pc_t *pc)
pc->callback = &idetape_read_position_callback;
}
-static int idetape_read_position(ide_drive_t *drive)
+static int idetape_read_position (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
int position;
+#ifdef NO_LONGER_REQUIRED
idetape_flush_tape_buffers(drive);
+#endif
idetape_create_read_position_cmd(&pc);
if (idetape_queue_pc_tail (drive,&pc))
return -1;
position = tape->first_frame_position;
+#ifdef NO_LONGER_REQUIRED
if (tape->onstream) {
if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
(position != tape->last_frame_position + tape->blocks_in_buffer)) {
@@ -3033,6 +3136,7 @@ static int idetape_read_position(ide_drive_t *drive)
}
}
}
+#endif
return position;
}
@@ -3054,7 +3158,7 @@ static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, uns
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_prevent_cmd(ide_drive_t *drive, idetape_pc_t *pc, int prevent)
+static void idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
{
idetape_init_pc(pc);
pc->c[0] = IDETAPE_PREVENT_CMD;
@@ -3130,7 +3234,8 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_posit
if (restore_position) {
position = idetape_read_position(drive);
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
#endif
seek = position > cnt ? position - cnt : 0;
if (idetape_position_tape(drive, seek, 0, 0)) {
@@ -3140,7 +3245,7 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_posit
}
}
-static void idetape_update_stats(ide_drive_t *drive)
+static void idetape_update_stats (ide_drive_t *drive)
{
idetape_pc_t pc;
@@ -3159,7 +3264,8 @@ static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struc
struct request rq;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "idetape_queue_rw_tail: cmd=%d\n",cmd);
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
#endif /* IDETAPE_DEBUG_LOG */
#if IDETAPE_DEBUG_BUGS
if (idetape_pipeline_active (tape)) {
@@ -3192,7 +3298,7 @@ static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struc
* of the write error recovery mechanism for old OnStream
* firmware revisions.
*/
-static void idetape_onstream_read_back_buffer(ide_drive_t *drive)
+static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int frames, i, logical_blk_num;
@@ -3214,7 +3320,8 @@ static void idetape_onstream_read_back_buffer(ide_drive_t *drive)
p = stage->bh->b_data;
idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
#endif
rq = &stage->rq;
ide_init_drive_cmd (rq);
@@ -3237,14 +3344,15 @@ static void idetape_onstream_read_back_buffer(ide_drive_t *drive)
}
idetape_update_stats(drive);
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
#endif
}
/*
* Error recovery algorithm for the OnStream tape.
*/
-static void idetape_onstream_write_error_recovery(ide_drive_t *drive)
+static void idetape_onstream_write_error_recovery (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned int block;
@@ -3263,11 +3371,13 @@ static void idetape_onstream_write_error_recovery(ide_drive_t *drive)
}
idetape_read_position(drive);
#if ONSTREAM_DEBUG
- printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position);
+ if (tape->debug_level >= 1)
+ printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position);
#endif
} else if (tape->onstream_write_error == 2) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name);
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name);
#endif
idetape_flush_tape_buffers(drive);
block = idetape_read_position(drive);
@@ -3297,7 +3407,7 @@ static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
}
}
-static void idetape_create_inquiry_cmd(idetape_pc_t *pc)
+static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
{
idetape_init_pc(pc);
pc->c[0] = IDETAPE_INQUIRY_CMD;
@@ -3350,7 +3460,7 @@ static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
/*
* Verify that we have the correct tape frame
*/
-static int idetape_verify_stage(ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
+static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
{
idetape_tape_t *tape = drive->driver_data;
os_aux_t *aux = stage->aux;
@@ -3404,7 +3514,7 @@ static int idetape_verify_stage(ide_drive_t *drive, idetape_stage_t *stage, int
return 0;
}
if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
- printk(KERN_INFO "ide-tape: %s: skipping frame, wrt_pass_cntr %d (expected %d)\n", tape->name, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr);
+ printk(KERN_INFO "ide-tape: %s: skipping frame, wrt_pass_cntr %d (expected %d)(logical_blk_num %lu)\n", tape->name, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
return 0;
}
if (aux->frame_seq_num != aux->logical_blk_num) {
@@ -3423,7 +3533,7 @@ static int idetape_verify_stage(ide_drive_t *drive, idetape_stage_t *stage, int
return 1;
}
-static void idetape_wait_first_stage(ide_drive_t *drive)
+static void idetape_wait_first_stage (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
@@ -3455,7 +3565,8 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
struct request *rq;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_add_chrdev_write_request\n");
+ if (tape->debug_level >= 3)
+ printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
#endif /* IDETAPE_DEBUG_LOG */
/*
@@ -3577,7 +3688,7 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
bh = tape->bh;
while (i) {
if (bh == NULL) {
- printk(KERN_INFO "bug, bh NULL\n");
+ printk(KERN_INFO "ide-tape: bug, bh NULL\n");
break;
}
min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
@@ -3614,7 +3725,7 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
#endif /* IDETAPE_DEBUG_BUGS */
}
-static void idetape_restart_speed_control(ide_drive_t *drive)
+static void idetape_restart_speed_control (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -3629,7 +3740,7 @@ static void idetape_restart_speed_control(ide_drive_t *drive)
tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
}
-static int idetape_initiate_read(ide_drive_t *drive, int max_stages)
+static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *new_stage;
@@ -3698,7 +3809,7 @@ static int idetape_initiate_read(ide_drive_t *drive, int max_stages)
return 0;
}
-static int idetape_get_logical_blk(ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet)
+static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
@@ -3708,7 +3819,7 @@ static int idetape_get_logical_blk(ide_drive_t *drive, int logical_blk_num, int
* Search and wait for the next logical tape block
*/
while (1) {
- if (cnt++ > 100) {
+ if (cnt++ > 1000) { /* AJN: was 100 */
printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
return 0;
}
@@ -3716,7 +3827,8 @@ static int idetape_get_logical_blk(ide_drive_t *drive, int logical_blk_num, int
if (tape->first_stage == NULL) {
if (tape->onstream) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
#endif
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
position = idetape_read_position(drive);
@@ -3761,7 +3873,8 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
int bytes_read;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
#endif /* IDETAPE_DEBUG_LOG */
/*
@@ -3784,7 +3897,8 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
#endif
return 0;
}
@@ -3796,7 +3910,8 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
idetape_switch_buffers (tape, tape->first_stage);
if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "error detected, bytes_read %d\n", bytes_read);
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
#endif
}
clear_bit (IDETAPE_FILEMARK, &tape->flags);
@@ -3871,7 +3986,8 @@ static int idetape_rewind_tape (ide_drive_t *drive)
idetape_pc_t pc;
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_rewind_tape\n");
+ if (tape->debug_level >= 2)
+ printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
#endif /* IDETAPE_DEBUG_LOG */
idetape_create_rewind_cmd (drive, &pc);
@@ -3899,7 +4015,8 @@ static int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct
idetape_config_t config;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
#endif /* IDETAPE_DEBUG_LOG */
switch (cmd) {
case 0x0340:
@@ -3928,12 +4045,18 @@ static int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct
static int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n");
+#endif
return 0;
}
static void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n");
+#endif
}
/*
@@ -3974,7 +4097,8 @@ static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,sh
if (last_mark_addr == -1)
return -EIO;
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
#endif
idetape_position_tape(drive, last_mark_addr, 0, 0);
cnt++;
@@ -4001,7 +4125,7 @@ static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,sh
*
* Just scans for the filemark sequentially.
*/
-static int idetape_onstream_space_over_filemarks_forward_slow(ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_onstream_space_over_filemarks_forward_slow (ide_drive_t *drive,short mt_op,int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
int cnt = 0;
@@ -4020,7 +4144,8 @@ static int idetape_onstream_space_over_filemarks_forward_slow(ide_drive_t *drive
cnt++;
if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
#endif
return -EIO;
}
@@ -4043,7 +4168,7 @@ static int idetape_onstream_space_over_filemarks_forward_slow(ide_drive_t *drive
/*
* Fast linux specific version of OnStream FSF
*/
-static int idetape_onstream_space_over_filemarks_forward_fast(ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_onstream_space_over_filemarks_forward_fast (ide_drive_t *drive,short mt_op,int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
int cnt = 0, next_mark_addr;
@@ -4062,7 +4187,8 @@ static int idetape_onstream_space_over_filemarks_forward_fast(ide_drive_t *drive
break;
if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
#endif
return -EIO;
}
@@ -4092,10 +4218,11 @@ static int idetape_onstream_space_over_filemarks_forward_fast(ide_drive_t *drive
if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
- }
#if ONSTREAM_DEBUG
- else printk(KERN_INFO "ide-tape: positioning to next mark at %d\n", next_mark_addr);
+ } else if (tape->debug_level >= 2) {
+ printk(KERN_INFO "ide-tape: positioning to next mark at %d\n", next_mark_addr);
#endif
+ }
idetape_position_tape(drive, next_mark_addr, 0, 0);
cnt++;
if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
@@ -4218,6 +4345,7 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
* The tape is optimized to maximize throughput when it is transferring
* an integral number of the "continuous transfer limit", which is
* a parameter of the specific tape (26 KB on my particular tape).
+ * (32 kB for Onstream)
*
* As of version 1.3 of the driver, the character device provides an
* abstract continuous view of the media - any mix of block sizes (even 1
@@ -4226,6 +4354,7 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
* so that an unmatch between the user's block size to the recommended
* size will only result in a (slightly) increased driver overhead, but
* will no longer hit performance.
+ * This is not applicable to Onstream.
*/
static ssize_t idetape_chrdev_read (struct file *file, char *buf,
size_t count, loff_t *ppos)
@@ -4244,7 +4373,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf,
return -EINVAL;
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_chrdev_read, count %d\n", count);
+ if (tape->debug_level >= 3)
+ printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %d\n", count);
#endif /* IDETAPE_DEBUG_LOG */
if (tape->chrdev_direction != idetape_direction_read) {
@@ -4280,7 +4410,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf,
finish:
if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
#endif
idetape_space_over_filemarks (drive, MTFSF, 1);
return 0;
@@ -4293,7 +4424,7 @@ finish:
return actually_read;
}
-static void idetape_update_last_marker(ide_drive_t *drive, int last_mark_addr, int next_mark_addr)
+static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr, int next_mark_addr)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
@@ -4310,8 +4441,10 @@ static void idetape_update_last_marker(ide_drive_t *drive, int last_mark_addr, i
idetape_flush_tape_buffers(drive);
position = idetape_read_position(drive);
#if ONSTREAM_DEBUG
- printk(KERN_INFO "current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
- printk(KERN_INFO "current position (2) tape block %d\n", tape->last_frame_position);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
#endif
idetape_position_tape(drive, last_mark_addr, 0, 0);
if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
@@ -4328,7 +4461,8 @@ static void idetape_update_last_marker(ide_drive_t *drive, int last_mark_addr, i
return;
}
#if ONSTREAM_DEBUG
- printk(KERN_INFO "writing back marker\n");
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: writing back marker\n");
#endif
aux->next_mark_addr = htonl(next_mark_addr);
idetape_position_tape(drive, last_mark_addr, 0, 0);
@@ -4344,7 +4478,7 @@ static void idetape_update_last_marker(ide_drive_t *drive, int last_mark_addr, i
return;
}
-static void __idetape_write_header(ide_drive_t *drive, int block, int cnt)
+static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
@@ -4358,7 +4492,7 @@ static void __idetape_write_header(ide_drive_t *drive, int block, int cnt)
idetape_position_tape(drive, block, 0, 0);
memset(&header, 0, sizeof(header));
strcpy(header.ident_str, "ADR_SEQ");
- header.major_rev = header.minor_rev = 1;
+ header.major_rev = header.minor_rev = 2;
header.par_num = 1;
header.partition.partition_num = OS_DATA_PARTITION;
header.partition.par_desc_ver = OS_PARTITION_VERSION;
@@ -4378,21 +4512,23 @@ static void __idetape_write_header(ide_drive_t *drive, int block, int cnt)
idetape_flush_tape_buffers (drive);
}
-static void idetape_write_header(ide_drive_t *drive, int locate_eod)
+static void idetape_write_header (ide_drive_t *drive, int locate_eod)
{
idetape_tape_t *tape = drive->driver_data;
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: writing tape header\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: writing tape header\n", tape->name);
#endif
if (!tape->onstream || tape->raw)
return;
tape->update_frame_cntr++;
__idetape_write_header(drive, 5, 5);
- __idetape_write_header(drive, 0xbb2, 6);
+ __idetape_write_header(drive, 0xbae, 5);
if (locate_eod) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
#endif
idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
}
@@ -4416,7 +4552,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
return -EINVAL;
}
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_chrdev_write, count %d\n", count);
+ if (tape->debug_level >= 3)
+ printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %d\n", count);
#endif /* IDETAPE_DEBUG_LOG */
if (tape->chrdev_direction != idetape_direction_write) { /* Initialize write operation */
@@ -4439,8 +4576,10 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
tape->logical_blk_num = 0;
tape->wrt_pass_cntr++;
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to 20\n", tape->name);
- printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to 20\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr);
#endif
tape->filemark_cnt = 0;
tape->eod_frame_addr = 20;
@@ -4448,13 +4587,15 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
idetape_write_header(drive, 1);
}
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
#endif
position = idetape_read_position(drive);
if (position != tape->eod_frame_addr)
idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: first_frame_position %d\n", tape->name, tape->first_frame_position);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: first_frame_position %d\n", tape->name, tape->first_frame_position);
#endif
}
@@ -4471,7 +4612,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
return retval;
}
#if ONSTREAM_DEBUG
- printk("ide-tape: first_frame_position %d\n", tape->first_frame_position);
+ if (tape->debug_level >= 2)
+ printk("ide-tape: first_frame_position %d\n", tape->first_frame_position);
#endif
}
if (count==0)
@@ -4512,7 +4654,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
return (actually_written);
}
-static int idetape_write_filemark(ide_drive_t *drive)
+static int idetape_write_filemark (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int last_mark_addr;
@@ -4543,7 +4685,7 @@ static int idetape_write_filemark(ide_drive_t *drive)
return 0;
}
-static void idetape_write_eod(ide_drive_t *drive)
+static void idetape_write_eod (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -4560,7 +4702,7 @@ static void idetape_write_eod(ide_drive_t *drive)
return;
}
-int idetape_seek_logical_blk(ide_drive_t *drive, int logical_blk_num)
+int idetape_seek_logical_blk (ide_drive_t *drive, int logical_blk_num)
{
idetape_tape_t *tape = drive->driver_data;
int estimated_address = logical_blk_num + 20;
@@ -4666,7 +4808,8 @@ static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
int i,retval;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+ if (tape->debug_level >= 1)
+ printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
#endif /* IDETAPE_DEBUG_LOG */
/*
* Commands which need our pipelined read-ahead stages.
@@ -4716,7 +4859,8 @@ static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
case MTEOM:
if (tape->onstream) {
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
#endif
idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
if (!idetape_get_logical_blk(drive, -1, 10, 0))
@@ -4833,7 +4977,8 @@ static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigne
int block_offset = 0, position = tape->first_frame_position;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+ if (tape->debug_level >= 3)
+ printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
#endif /* IDETAPE_DEBUG_LOG */
tape->restart_speed_control_req = 1;
@@ -4890,7 +5035,7 @@ static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigne
}
}
-static int __idetape_analyze_headers(ide_drive_t *drive, int block)
+static int __idetape_analyze_headers (ide_drive_t *drive, int block)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
@@ -4910,7 +5055,8 @@ static int __idetape_analyze_headers(ide_drive_t *drive, int block)
if (stage == NULL)
return 0;
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
#endif
idetape_position_tape(drive, block, 0, 0);
if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
@@ -4925,8 +5071,8 @@ static int __idetape_analyze_headers(ide_drive_t *drive, int block)
__idetape_kfree_stage (stage);
return 0;
}
- if (header->major_rev != 1 || header->minor_rev != 1)
- printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (1.1 supported)\n", header->major_rev, header->minor_rev);
+ if (header->major_rev != 1 || (header->minor_rev != 1 && header->minor_rev != 2))
+ printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (1.1/1.2 supported)\n", header->major_rev, header->minor_rev);
if (header->par_num != 1)
printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num);
tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr);
@@ -4946,13 +5092,14 @@ static int __idetape_analyze_headers(ide_drive_t *drive, int block)
tape->linux_media = 0;
}
#if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
#endif
__idetape_kfree_stage (stage);
return 1;
}
-static int idetape_analyze_headers(ide_drive_t *drive)
+static int idetape_analyze_headers (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int position, block;
@@ -4966,7 +5113,7 @@ static int idetape_analyze_headers(ide_drive_t *drive)
for (block = 5; block < 10; block++)
if (__idetape_analyze_headers(drive, block))
goto ok;
- for (block = 0xbb2; block < 0xbb8; block++)
+ for (block = 0xbae; block < 0xbb3; block++)
if (__idetape_analyze_headers(drive, block))
goto ok;
printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
@@ -4990,7 +5137,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
unsigned int minor=MINOR (inode->i_rdev);
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_chrdev_open\n");
+ printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
#endif /* IDETAPE_DEBUG_LOG */
if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
@@ -5000,6 +5147,10 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
return -EBUSY;
MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-1\n");
+#endif
if (!tape->onstream) {
idetape_read_position(drive);
if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
@@ -5016,15 +5167,27 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
if (idetape_wait_ready(drive, 60 * HZ)) {
clear_bit(IDETAPE_BUSY, &tape->flags);
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-1\n");
+#endif
printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
return -EBUSY;
}
idetape_read_position(drive);
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-2\n");
+#endif
clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
if (tape->chrdev_direction == idetape_direction_none) {
MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-2\n");
+#endif
idetape_create_prevent_cmd(drive, &pc, 1);
if (!idetape_queue_pc_tail (drive,&pc)) {
if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
@@ -5049,7 +5212,8 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
unsigned int minor=MINOR (inode->i_rdev);
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Reached idetape_chrdev_release\n");
+ if (tape->debug_level >= 3)
+ printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
#endif /* IDETAPE_DEBUG_LOG */
if (tape->chrdev_direction == idetape_direction_write) {
@@ -5085,6 +5249,10 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
tape->door_locked = DOOR_UNLOCKED;
}
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_release\n");
+#endif
}
clear_bit (IDETAPE_BUSY, &tape->flags);
return 0;
@@ -5112,14 +5280,14 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
*((unsigned short *) &gcw) = id->config;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Dumping ATAPI Identify Device tape parameters\n");
- printk (KERN_INFO "Protocol Type: ");
+ printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+ printk (KERN_INFO "ide-tape: Protocol Type: ");
switch (gcw.protocol) {
case 0: case 1: printk (KERN_INFO "ATA\n");break;
case 2: printk (KERN_INFO "ATAPI\n");break;
case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
}
- printk (KERN_INFO "Device Type: %x - ",gcw.device_type);
+ printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);
switch (gcw.device_type) {
case 0: printk (KERN_INFO "Direct-access Device\n");break;
case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
@@ -5130,32 +5298,32 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
default: printk (KERN_INFO "Reserved\n");
}
- printk (KERN_INFO "Removable: %s",gcw.removable ? "Yes\n":"No\n");
- printk (KERN_INFO "Command Packet DRQ Type: ");
+ printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");
+ printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
switch (gcw.drq_type) {
case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
case 3: printk (KERN_INFO "Reserved\n");break;
}
- printk (KERN_INFO "Command Packet Size: ");
+ printk (KERN_INFO "ide-tape: Command Packet Size: ");
switch (gcw.packet_size) {
case 0: printk (KERN_INFO "12 bytes\n");break;
case 1: printk (KERN_INFO "16 bytes\n");break;
default: printk (KERN_INFO "Reserved\n");break;
}
- printk (KERN_INFO "Model: %.40s\n",id->model);
- printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
- printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
- printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512);
- printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
- printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
- printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
- printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
- printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
- printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
- printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
- printk (KERN_INFO "Single Word DMA supported modes: ");
+ printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+ printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+ printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+ printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+ printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+ printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+ printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+ printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+ printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+ printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+ printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+ printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
for (i=0,mask=1;i<8;i++,mask=mask << 1) {
if (id->dma_1word & mask)
printk (KERN_INFO "%d ",i);
@@ -5163,7 +5331,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
printk (KERN_INFO "(active) ");
}
printk (KERN_INFO "\n");
- printk (KERN_INFO "Multi Word DMA supported modes: ");
+ printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
for (i=0,mask=1;i<8;i++,mask=mask << 1) {
if (id->dma_mword & mask)
printk (KERN_INFO "%d ",i);
@@ -5172,33 +5340,33 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
}
printk (KERN_INFO "\n");
if (id->field_valid & 0x0002) {
- printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
- printk (KERN_INFO "Minimum Multi-word DMA cycle per word: ");
+ printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+ printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
if (id->eide_dma_min == 0)
printk (KERN_INFO "Not supported\n");
else
printk (KERN_INFO "%d ns\n",id->eide_dma_min);
- printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: ");
+ printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
if (id->eide_dma_time == 0)
printk (KERN_INFO "Not supported\n");
else
printk (KERN_INFO "%d ns\n",id->eide_dma_time);
- printk (KERN_INFO "Minimum PIO cycle without IORDY: ");
+ printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
if (id->eide_pio == 0)
printk (KERN_INFO "Not supported\n");
else
printk (KERN_INFO "%d ns\n",id->eide_pio);
- printk (KERN_INFO "Minimum PIO cycle with IORDY: ");
+ printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
if (id->eide_pio_iordy == 0)
printk (KERN_INFO "Not supported\n");
else
printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
} else
- printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+ printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
#endif /* IDETAPE_DEBUG_LOG */
/* Check that we can support this device */
@@ -5221,7 +5389,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
/*
* Notify vendor ID to the OnStream tape drive
*/
-static void idetape_onstream_set_vendor(ide_drive_t *drive, char *vendor)
+static void idetape_onstream_set_vendor (ide_drive_t *drive, char *vendor)
{
idetape_pc_t pc;
idetape_mode_parameter_header_t *header;
@@ -5248,7 +5416,7 @@ static void idetape_onstream_set_vendor(ide_drive_t *drive, char *vendor)
* Various unused OnStream commands
*/
#if ONSTREAM_DEBUG
-static void idetape_onstream_set_retries(ide_drive_t *drive, int retries)
+static void idetape_onstream_set_retries (ide_drive_t *drive, int retries)
{
idetape_pc_t pc;
@@ -5269,7 +5437,7 @@ static void idetape_onstream_set_retries(ide_drive_t *drive, int retries)
/*
* Configure 32.5KB block size.
*/
-static void idetape_onstream_configure_block_size(ide_drive_t *drive)
+static void idetape_onstream_configure_block_size (ide_drive_t *drive)
{
idetape_pc_t pc;
idetape_mode_parameter_header_t *header;
@@ -5285,10 +5453,10 @@ static void idetape_onstream_configure_block_size(ide_drive_t *drive)
bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "32KB play back: %s\n", bs->play32 ? "Yes" : "No");
- printk(KERN_INFO "32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No");
- printk(KERN_INFO "32KB record: %s\n", bs->record32 ? "Yes" : "No");
- printk(KERN_INFO "32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No");
+ printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No");
+ printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No");
+ printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No");
+ printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No");
#endif
/*
@@ -5315,7 +5483,7 @@ static void idetape_onstream_configure_block_size(ide_drive_t *drive)
/*
* Use INQUIRY to get the firmware revision
*/
-static void idetape_get_inquiry_results(ide_drive_t *drive)
+static void idetape_get_inquiry_results (ide_drive_t *drive)
{
char *r;
idetape_tape_t *tape = drive->driver_data;
@@ -5345,13 +5513,13 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
/*
* Configure the OnStream ATAPI tape drive for default operation
*/
-static void idetape_configure_onstream(ide_drive_t *drive)
+static void idetape_configure_onstream (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
if (tape->firmware_revision_num < 105) {
- printk("ide-tape: %s: Old OnStream firmware revision detected (%s)\n", tape->name, tape->firmware_revision);
- printk("ide-tape: %s: An upgrade to version 1.05 or above is recommended\n", tape->name);
+ printk(KERN_INFO "ide-tape: %s: Old OnStream firmware revision detected (%s)\n", tape->name, tape->firmware_revision);
+ printk(KERN_INFO "ide-tape: %s: An upgrade to version 1.05 or above is recommended\n", tape->name);
}
/*
@@ -5410,37 +5578,37 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
tape->tape_block_size = 32768;
#if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
- printk (KERN_INFO "Mode Parameter Header:\n");
- printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
- printk (KERN_INFO "Medium Type - %d\n",header->medium_type);
- printk (KERN_INFO "Device Specific Parameter - %d\n",header->dsp);
- printk (KERN_INFO "Block Descriptor Length - %d\n",header->bdl);
+ printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+ printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
+ printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+ printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+ printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+ printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
- printk (KERN_INFO "Capabilities and Mechanical Status Page:\n");
- printk (KERN_INFO "Page code - %d\n",capabilities->page_code);
- printk (KERN_INFO "Page length - %d\n",capabilities->page_length);
- printk (KERN_INFO "Read only - %s\n",capabilities->ro ? "Yes":"No");
- printk (KERN_INFO "Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
- printk (KERN_INFO "Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
- printk (KERN_INFO "Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
- printk (KERN_INFO "Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
- printk (KERN_INFO "The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
- printk (KERN_INFO "The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
- printk (KERN_INFO "Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
- printk (KERN_INFO "Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
- printk (KERN_INFO "Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
- printk (KERN_INFO "Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
- printk (KERN_INFO "Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
- printk (KERN_INFO "Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
- printk (KERN_INFO "Maximum supported speed in KBps - %d\n",capabilities->max_speed);
- printk (KERN_INFO "Continuous transfer limits in blocks - %d\n",capabilities->ctl);
- printk (KERN_INFO "Current speed in KBps - %d\n",capabilities->speed);
- printk (KERN_INFO "Buffer size - %d\n",capabilities->buffer_size*512);
+ printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+ printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+ printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+ printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+ printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+ printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+ printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);
+ printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
#endif /* IDETAPE_DEBUG_LOG */
}
-static void idetape_add_settings(ide_drive_t *drive)
+static void idetape_add_settings (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -5465,6 +5633,7 @@ static void idetape_add_settings(ide_drive_t *drive)
ide_add_setting(drive, "max_frames", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->max_frames, NULL);
ide_add_setting(drive, "insert_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_speed, NULL);
ide_add_setting(drive, "speed_control",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->speed_control, NULL);
+ ide_add_setting(drive, "debug_level",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL);
ide_add_setting(drive, "tape_still_time",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->tape_still_time, NULL);
ide_add_setting(drive, "max_insert_speed",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->max_insert_speed, NULL);
ide_add_setting(drive, "insert_size", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_size, NULL);
@@ -5686,6 +5855,9 @@ int idetape_init (void)
int minor, failed = 0, supported = 0;
MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
if (!idetape_chrdev_present)
for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
idetape_chrdevs[minor].drive = NULL;
@@ -5693,11 +5865,18 @@ int idetape_init (void)
if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
ide_register_module (&idetape_module);
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ if (tape->debug_level >= 6)
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
return 0;
}
if (!idetape_chrdev_present && register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
return -EBUSY;
}
do {
@@ -5734,6 +5913,9 @@ int idetape_init (void)
idetape_chrdev_present = 1;
ide_register_module (&idetape_module);
MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
return 0;
}
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 5bdb1d477..873f57cc9 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.21 November 9, 1999
+ * linux/drivers/block/ide.c Version 6.30 Dec 28, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -108,6 +108,7 @@
* Specifically Promise's PDC20262 chipset.
* Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old
* hat that clarified original low level driver design.
+ * Version 6.30 Added SMP support; fixed multmode issues. -ml
*
* Some additional driver compile-time options are in ./include/linux/ide.h
*
@@ -116,8 +117,8 @@
*
*/
-#define REVISION "Revision: 6.21"
-#define VERSION "Id: ide.c 6.21 1999/11/10"
+#define REVISION "Revision: 6.30"
+#define VERSION "Id: ide.c 6.30 1999/12/28"
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -169,6 +170,10 @@ static int idebus_parameter; /* holds the "idebus=" parameter */
static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
static int initializing; /* set while initializing built-in drivers */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+static int ide_scan_direction = 0; /* HELLO, comment me!! */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
#if defined(__mc68000__) || defined(CONFIG_APUS)
/*
* ide_lock is used by the Atari code to obtain access to the IDE interrupt,
@@ -542,22 +547,28 @@ unsigned long current_capacity (ide_drive_t *drive)
return 0;
}
+extern struct block_device_operations ide_fops[];
/*
- * ide_geninit() is called exactly *once* for each major, from genhd.c,
- * at the beginning of the initial partition check for the drives.
+ * ide_geninit() is called exactly *once* for each interface.
*/
-void ide_geninit (struct gendisk *gd)
+void ide_geninit (ide_hwif_t *hwif)
{
unsigned int unit;
- ide_hwif_t *hwif = gd->real_devices;
+ struct gendisk *gd = hwif->gd;
- for (unit = 0; unit < gd->nr_real; ++unit) {
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
- drive->part[0].nr_sects = current_capacity(drive);
- if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) ||
- drive->driver == NULL || !drive->part[0].nr_sects)
- drive->part[0].start_sect = -1; /* skip partition check */
+ if (!drive->present)
+ continue;
+ if (drive->media!=ide_disk && drive->media!=ide_floppy)
+ continue;
+ register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+ (drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+ 1<<PARTN_BITS, ide_fops,
+ current_capacity(drive));
}
}
@@ -669,7 +680,7 @@ static void pre_reset (ide_drive_t *drive)
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
-static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
@@ -1213,7 +1224,7 @@ repeat:
* the driver. This makes the driver much more friendlier to shared IRQs
* than previous designs, while remaining 100% (?) SMP safe and capable.
*/
-static void ide_do_request (ide_hwgroup_t *hwgroup)
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
{
struct blk_dev_struct *bdev;
ide_drive_t *drive;
@@ -1272,14 +1283,25 @@ static void ide_do_request (ide_hwgroup_t *hwgroup)
drive->service_start = jiffies;
bdev = &blk_dev[hwif->major];
- if( bdev->request_queue.plugged ) /* FIXME: paranoia */
+ if ( bdev->request_queue.plugged ) /* FIXME: paranoia */
printk("%s: Huh? nuking plugged queue\n", drive->name);
bdev->request_queue.current_request = hwgroup->rq = drive->queue.current_request;
+ /*
+ * Some systems have trouble with IDE IRQs arriving while
+ * the driver is still setting things up. So, here we disable
+ * the IRQ used by this interface while the request is being started.
+ * This may look bad at first, but pretty much the same thing
+ * happens anyway when any interrupt comes in, IDE or otherwise
+ * -- the kernel masks the IRQ while it is being handled.
+ */
+ if (hwif->irq != masked_irq)
+ disable_irq_nosync(hwif->irq);
spin_unlock(&io_request_lock);
- if (!hwif->serialized) /* play it safe with buggy hardware */
- ide__sti();
+ ide__sti(); /* allow other IRQs while we start this request */
startstop = start_request(drive);
spin_lock_irq(&io_request_lock);
+ if (hwif->irq != masked_irq)
+ enable_irq(hwif->irq);
if (startstop == ide_stopped)
hwgroup->busy = 0;
}
@@ -1297,69 +1319,69 @@ request_queue_t *ide_get_queue (kdev_t dev)
void do_ide0_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[0].hwgroup);
+ ide_do_request (ide_hwifs[0].hwgroup, 0);
}
#if MAX_HWIFS > 1
void do_ide1_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[1].hwgroup);
+ ide_do_request (ide_hwifs[1].hwgroup, 0);
}
#endif /* MAX_HWIFS > 1 */
#if MAX_HWIFS > 2
void do_ide2_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[2].hwgroup);
+ ide_do_request (ide_hwifs[2].hwgroup, 0);
}
#endif /* MAX_HWIFS > 2 */
#if MAX_HWIFS > 3
void do_ide3_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[3].hwgroup);
+ ide_do_request (ide_hwifs[3].hwgroup, 0);
}
#endif /* MAX_HWIFS > 3 */
#if MAX_HWIFS > 4
void do_ide4_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[4].hwgroup);
+ ide_do_request (ide_hwifs[4].hwgroup, 0);
}
#endif /* MAX_HWIFS > 4 */
#if MAX_HWIFS > 5
void do_ide5_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[5].hwgroup);
+ ide_do_request (ide_hwifs[5].hwgroup, 0);
}
#endif /* MAX_HWIFS > 5 */
#if MAX_HWIFS > 6
void do_ide6_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[6].hwgroup);
+ ide_do_request (ide_hwifs[6].hwgroup, 0);
}
#endif /* MAX_HWIFS > 6 */
#if MAX_HWIFS > 7
void do_ide7_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[7].hwgroup);
+ ide_do_request (ide_hwifs[7].hwgroup, 0);
}
#endif /* MAX_HWIFS > 7 */
#if MAX_HWIFS > 8
void do_ide8_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[8].hwgroup);
+ ide_do_request (ide_hwifs[8].hwgroup, 0);
}
#endif /* MAX_HWIFS > 8 */
#if MAX_HWIFS > 9
void do_ide9_request (request_queue_t *q)
{
- ide_do_request (ide_hwifs[9].hwgroup);
+ ide_do_request (ide_hwifs[9].hwgroup, 0);
}
#endif /* MAX_HWIFS > 9 */
@@ -1445,7 +1467,7 @@ void ide_timer_expiry (unsigned long data)
hwgroup->busy = 0;
}
}
- ide_do_request(hwgroup);
+ ide_do_request(hwgroup, 0);
spin_unlock_irqrestore(&io_request_lock, flags);
}
@@ -1593,7 +1615,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
if (startstop == ide_stopped) {
if (hwgroup->handler == NULL) { /* paranoia */
hwgroup->busy = 0;
- ide_do_request(hwgroup);
+ ide_do_request(hwgroup, hwif->irq);
} else {
printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
}
@@ -1608,6 +1630,9 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
ide_drive_t *get_info_ptr (kdev_t i_rdev)
{
int major = MAJOR(i_rdev);
+#if 0
+ int minor = MINOR(i_rdev) & PARTN_MASK;
+#endif
unsigned int h;
for (h = 0; h < MAX_HWIFS; ++h) {
@@ -1616,7 +1641,11 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
unsigned unit = DEVICE_NR(i_rdev);
if (unit < MAX_DRIVES) {
ide_drive_t *drive = &hwif->drives[unit];
+#if 0
+ if ((drive->present) && (drive->part[minor].nr_sects))
+#else
if (drive->present)
+#endif
return drive;
}
break;
@@ -1698,7 +1727,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
rq->next = cur_rq->next;
cur_rq->next = rq;
}
- ide_do_request(hwgroup);
+ ide_do_request(hwgroup, 0);
spin_unlock_irqrestore(&io_request_lock, flags);
if (action == ide_wait) {
down(&sem); /* wait for it to be serviced */
@@ -1751,11 +1780,10 @@ int ide_revalidate_disk (kdev_t i_rdev)
drive->part[p].nr_sects = 0;
};
- drive->part[0].nr_sects = current_capacity(drive);
- if ((drive->media != ide_disk && drive->media != ide_floppy) ||
- drive->driver == NULL || !drive->part[0].nr_sects)
- drive->part[0].start_sect = -1;
- resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
+ grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
+ (drive->media != ide_disk &&
+ drive->media != ide_floppy) ? 1 : 1<<PARTN_BITS,
+ current_capacity(drive));
drive->busy = 0;
wake_up(&drive->wqueue);
@@ -1846,7 +1874,6 @@ static int ide_release (struct inode * inode, struct file * file)
ide_drive_t *drive;
if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
- fsync_dev(inode->i_rdev);
drive->usage--;
if (drive->driver != NULL)
DRIVER(drive)->release(inode, file, drive);
@@ -2678,6 +2705,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
* for chipsets that are ATA-66 capable, but
* the ablity to bit test for detection is
* currently unknown.
+ * "ide=reverse" : Formerly called to pci sub-system, but now local.
*
* "splitfifo=betweenChan"
* : FIFO Configuration of VIA 82c586(<nothing>,"A"or"B").
@@ -2728,6 +2756,14 @@ int __init ide_setup (char *s)
}
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ if (!strcmp(s, "ide=reverse")) {
+ ide_scan_direction = 1;
+ printk("ide: Enabled support for IDE inverse scan order.\n");
+ return 0;
+ }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
init_ide_data ();
/*
@@ -3061,7 +3097,7 @@ static void __init probe_for_hwifs (void)
if (pci_present())
{
#ifdef CONFIG_BLK_DEV_IDEPCI
- ide_scan_pcibus();
+ ide_scan_pcibus(ide_scan_direction);
#else
#ifdef CONFIG_BLK_DEV_RZ1000
{
@@ -3367,7 +3403,6 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup);
EXPORT_SYMBOL(drive_is_flashcard);
EXPORT_SYMBOL(ide_timer_expiry);
EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_geninit);
EXPORT_SYMBOL(ide_fops);
EXPORT_SYMBOL(ide_get_queue);
EXPORT_SYMBOL(do_ide0_request);
@@ -3449,6 +3484,7 @@ EXPORT_SYMBOL(current_capacity);
int __init ide_init (void)
{
static char banner_printed = 0;
+ int i;
if (!banner_printed) {
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
@@ -3461,6 +3497,12 @@ int __init ide_init (void)
ide_init_builtin_drivers();
initializing = 0;
+ for (i = 0; i < MAX_HWIFS; ++i) {
+ ide_hwif_t *hwif = &ide_hwifs[i];
+ if (hwif->present)
+ ide_geninit(hwif);
+ }
+
return 0;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 37c6949ee..fc6024fdc 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -643,7 +643,7 @@ static int lo_open(struct inode *inode, struct file *file)
static int lo_release(struct inode *inode, struct file *file)
{
struct loop_device *lo;
- int dev, err;
+ int dev;
if (!inode)
return 0;
@@ -654,7 +654,6 @@ static int lo_release(struct inode *inode, struct file *file)
dev = MINOR(inode->i_rdev);
if (dev >= max_loop)
return 0;
- err = fsync_dev(inode->i_rdev);
lo = &loop_dev[dev];
if (lo->lo_refcnt <= 0)
printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
@@ -665,7 +664,7 @@ static int lo_release(struct inode *inode, struct file *file)
xfer_funcs[type]->unlock(lo);
MOD_DEC_USE_COUNT;
}
- return err;
+ return 0;
}
static struct block_device_operations lo_fops = {
@@ -760,6 +759,8 @@ int __init loop_init(void)
memset(loop_blksizes, 0, max_loop * sizeof(int));
blk_size[MAJOR_NR] = loop_sizes;
blksize_size[MAJOR_NR] = loop_blksizes;
+ for (i=0; i < max_loop; i++)
+ register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &lo_fops, 0);
return 0;
}
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 7c5fd982a..b5b170069 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -77,16 +77,12 @@ static struct md_thread *md_sync_thread = NULL;
int md_size[MAX_MD_DEV]={0, };
-static void md_geninit (struct gendisk *);
-
static struct gendisk md_gendisk=
{
MD_MAJOR,
"md",
0,
1,
- MAX_MD_DEV,
- md_geninit,
md_hd_struct,
md_size,
MAX_MD_DEV,
@@ -675,8 +671,6 @@ static int md_open (struct inode *inode, struct file *file)
static int md_release (struct inode *inode, struct file *file)
{
int minor=MINOR(inode->i_rdev);
-
- sync_dev (inode->i_rdev);
md_dev[minor].busy--;
return 0;
}
@@ -911,22 +905,20 @@ static int md_status_read_proc(char *page, char **start, off_t off,
}
#endif
-static void md_geninit (struct gendisk *gdisk)
+static void md_geninit (void)
{
int i;
+ blksize_size[MD_MAJOR] = md_blocksizes;
+ max_readahead[MD_MAJOR] = md_maxreadahead;
for(i=0;i<MAX_MD_DEV;i++)
{
md_blocksizes[i] = 1024;
md_maxreadahead[i] = MD_DEFAULT_DISK_READAHEAD;
- md_gendisk.part[i].start_sect=-1; /* avoid partition check */
- md_gendisk.part[i].nr_sects=0;
md_dev[i].pers=NULL;
+ register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0);
}
- blksize_size[MD_MAJOR] = md_blocksizes;
- max_readahead[MD_MAJOR] = md_maxreadahead;
-
#ifdef CONFIG_PROC_FS
create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL);
#endif
@@ -1267,6 +1259,7 @@ int __init md_init (void)
#ifdef CONFIG_MD_RAID5
raid5_init ();
#endif
+ md_geninit();
return (0);
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 4cf81b9b0..0efcce8ed 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -435,8 +435,6 @@ static int nbd_release(struct inode *inode, struct file *file)
dev = MINOR(inode->i_rdev);
if (dev >= MAX_NBD)
return -ENODEV;
- fsync_dev(inode->i_rdev);
- invalidate_buffers(inode->i_rdev);
lo = &nbd_dev[dev];
if (lo->refcnt <= 0)
printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt);
@@ -491,6 +489,8 @@ int nbd_init(void)
nbd_blksize_bits[i] = 10;
nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
nbd_sizes[i] = nbd_bytesizes[i] >> nbd_blksize_bits[i];
+ register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
+ nbd_bytesizes[i]>>9);
}
return 0;
}
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 902e40a65..577d1354c 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -263,7 +263,6 @@ void pd_setup(char * str, int * ints);
#ifdef MODULE
void cleanup_module( void );
#endif
-static void pd_geninit(struct gendisk *ignored);
static int pd_open(struct inode *inode, struct file *file);
static void do_pd_request(request_queue_t * q);
static int pd_ioctl(struct inode *inode,struct file *file,
@@ -345,8 +344,6 @@ static struct gendisk pd_gendisk = {
PD_NAME, /* Major name */
PD_BITS, /* Bits to shift to get real from partition */
PD_PARTNS, /* Number of partitions per real */
- PD_UNITS, /* maximum number of real */
- pd_geninit, /* init function */
pd_hd, /* hd struct */
pd_sizes, /* block sizes */
0, /* number */
@@ -401,26 +398,25 @@ int pd_init (void)
pd_gendisk.major = major;
pd_gendisk.major_name = name;
pd_gendisk.next = gendisk_head;
- gendisk_head = &pd_gendisk;
+ gendisk_head = &pd_gendisk;
- for(i=0;i<PD_DEVS;i++) pd_blocksizes[i] = 1024;
- blksize_size[MAJOR_NR] = pd_blocksizes;
+ for(i=0;i<PD_DEVS;i++) pd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = pd_blocksizes;
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name,name,PD_VERSION,major,cluster,nice);
-
- return 0;
-}
-
-static void pd_geninit (struct gendisk *ignored)
-
-{ pd_init_units();
+ printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
+ name,name,PD_VERSION,major,cluster,nice);
+ pd_init_units();
+ pd_valid = 0;
pd_gendisk.nr_real = pd_detect();
+ pd_valid = 1;
#ifdef MODULE
- if (!pd_gendisk.nr_real) cleanup_module();
+ if (!pd_gendisk.nr_real) {
+ cleanup_module();
+ return -1;
+ }
#endif
-
+ return 0;
}
static int pd_open (struct inode *inode, struct file *file)
@@ -502,8 +498,6 @@ static int pd_release (struct inode *inode, struct file *file)
{ kdev_t devp;
int unit;
- struct super_block *sb;
-
devp = inode->i_rdev;
unit = DEVICE_NR(devp);
@@ -512,15 +506,8 @@ static int pd_release (struct inode *inode, struct file *file)
PD.access--;
- if (!PD.access) {
- fsync_dev(devp);
-
- sb = get_super(devp);
- if (sb) invalidate_inodes(sb);
-
- invalidate_buffers(devp);
- if (PD.removable) pd_doorlock(unit,IDE_DOORUNLOCK);
- }
+ if (!PD.access && PD.removable)
+ pd_doorlock(unit,IDE_DOORUNLOCK);
MOD_DEC_USE_COUNT;
@@ -573,8 +560,8 @@ static int pd_revalidate(kdev_t dev)
pd_hd[minor].nr_sects = 0;
}
- pd_identify(unit);
- resetup_one_dev(&pd_gendisk,unit);
+ if (pd_identify(unit))
+ grok_partitions(&pd_gendisk,unit,1<<PD_BITS,PD.capacity);
pd_valid = 1;
wake_up(&pd_wait_open);
@@ -597,20 +584,7 @@ int init_module(void)
paride_init();
}
#endif
-
- err = pd_init();
- if (err) return err;
-
- pd_geninit(&pd_gendisk);
-
- if (!pd_gendisk.nr_real) return -1;
-
- pd_valid = 0;
- for (unit=0;unit<PD_UNITS;unit++)
- if (PD.present) resetup_one_dev(&pd_gendisk,unit);
- pd_valid = 1;
-
- return 0;
+ return pd_init();
}
void cleanup_module(void)
@@ -822,21 +796,19 @@ static int pd_identify( int unit )
if (PD.capacity) pd_init_dev_parms(unit);
if (!PD.standby) pd_standby_off(unit);
-
- pd_hd[unit<<PD_BITS].nr_sects = PD.capacity;
- pd_hd[unit<<PD_BITS].start_sect = 0;
return 1;
}
static int pd_probe_drive( int unit )
-
-{ if (PD.drive == -1) {
- for (PD.drive=0;PD.drive<=1;PD.drive++)
- if (pd_identify(unit)) return 1;
- return 0;
- }
- else return pd_identify(unit);
+{
+ if (PD.drive == -1) {
+ for (PD.drive=0;PD.drive<=1;PD.drive++)
+ if (pd_identify(unit))
+ return 1;
+ return 0;
+ }
+ return pd_identify(unit);
}
static int pd_detect( void )
@@ -863,15 +835,18 @@ static int pd_detect( void )
k = unit+1;
} else pi_release(PI);
}
+ for (unit=0;unit<PD_UNITS;unit++)
+ register_disk(&pd_gendisk,MKDEV(MAJOR_NR,unit<<PD_BITS),
+ PD_PARTNS,&pd_fops,
+ PD.present?PD.capacity:0);
/* We lie about the number of drives found, as the generic partition
scanner assumes that the drives are numbered sequentially from 0.
This can result in some bogus error messages if non-sequential
drive numbers are used.
*/
-
- if (k) return k;
-
+ if (k)
+ return k;
printk("%s: no valid drive found\n",name);
return 0;
}
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index baed43a07..d658a0369 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -360,6 +360,8 @@ int pf_init (void) /* preliminary initialisation */
for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
blksize_size[MAJOR_NR] = pf_blocksizes;
+ for (i=0;i<PF_UNITS;i++)
+ register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &pf_fops, 0);
return 0;
}
@@ -447,8 +449,6 @@ static int pf_release (struct inode *inode, struct file *file)
{ kdev_t devp;
int unit;
- struct super_block *sb;
-
devp = inode->i_rdev;
unit = DEVICE_NR(devp);
@@ -457,15 +457,8 @@ static int pf_release (struct inode *inode, struct file *file)
PF.access--;
- if (!PF.access) {
- fsync_dev(devp);
-
- sb = get_super(devp);
- if (sb) invalidate_inodes(sb);
-
- invalidate_buffers(devp);
- if (PF.removable) pf_lock(unit,0);
- }
+ if (!PF.access && PF.removable)
+ pf_lock(unit,0);
MOD_DEC_USE_COUNT;
diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c
index dfd8830a2..c5a0c4924 100644
--- a/drivers/block/pdc202xx.c
+++ b/drivers/block/pdc202xx.c
@@ -227,7 +227,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
unsigned short EP;
byte CLKSPD = IN_BYTE(high_16 + 0x11);
int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+ byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0;
/*
@@ -661,8 +661,6 @@ void __init ide_init_pdc202xx (ide_hwif_t *hwif)
if (hwif->dma_base) {
hwif->dmaproc = &pdc202xx_dmaproc;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/block/piix.c b/drivers/block/piix.c
index cb4cd8b46..b8ffb5a4b 100644
--- a/drivers/block/piix.c
+++ b/drivers/block/piix.c
@@ -200,7 +200,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
int u_speed;
byte maslave = hwif->channel ? 0x42 : 0x40;
- byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+ byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
(dev->device == PCI_DEVICE_ID_INTEL_82801AA_1)) ? 1 : 0;
int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) ? 1 : 0;
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index bd4c5245a..9f68ebbfc 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -68,7 +68,7 @@ static void reset_ctrl(void);
int ps2esdi_init(void);
-static void ps2esdi_geninit(struct gendisk *ignored);
+static void ps2esdi_geninit(void);
static void do_ps2esdi_request(request_queue_t * q);
@@ -160,8 +160,6 @@ static struct gendisk ps2esdi_gendisk =
"ed", /* Major name */
6, /* Bits to shift to get real from partition */
1 << 6, /* Number of partitions per real disk */
- MAX_HD, /* maximum number of real disks */
- ps2esdi_geninit, /* init function */
ps2esdi, /* hd struct */
ps2esdi_sizes, /* block sizes */
0, /* number */
@@ -186,8 +184,8 @@ int __init ps2esdi_init(void)
/* some minor housekeeping - setup the global gendisk structure */
ps2esdi_gendisk.next = gendisk_head;
gendisk_head = &ps2esdi_gendisk;
+ ps2esdi_geninit();
return 0;
-
} /* ps2esdi_init */
#ifdef MODULE
@@ -291,7 +289,7 @@ static int ps2esdi_getinfo(char *buf, int slot, void *d)
}
/* ps2 esdi specific initialization - called thru the gendisk chain */
-static void __init ps2esdi_geninit(struct gendisk *ignored)
+static void __init ps2esdi_geninit(void)
{
/*
The first part contains the initialization code
@@ -414,21 +412,21 @@ static void __init ps2esdi_geninit(struct gendisk *ignored)
ps2esdi_gendisk.nr_real = ps2esdi_drives;
- for (i = 0; i < ps2esdi_drives; i++) {
- ps2esdi[i << 6].nr_sects =
- ps2esdi_info[i].head *
- ps2esdi_info[i].sect *
- ps2esdi_info[i].cyl;
- ps2esdi_valid[i] = 1;
- }
for (i = 0; i < (MAX_HD << 6); i++)
ps2esdi_blocksizes[i] = 1024;
request_dma(dma_arb_level, "ed");
request_region(io_base, 4, "ed");
blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
-} /* ps2esdi_geninit */
+ for (i = 0; i < ps2esdi_drives; i++) {
+ register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
+ &ps2esdi_fops,
+ ps2esdi_info[i].head * ps2esdi_info[i].sect *
+ ps2esdi_info[i].cyl);
+ ps2esdi_valid[i] = 1;
+ }
+}
static void __init ps2esdi_get_device_cfg(void)
{
@@ -1105,7 +1103,6 @@ static int ps2esdi_release(struct inode *inode, struct file *file)
int dev = DEVICE_NR(inode->i_rdev);
if (dev < ps2esdi_drives) {
- sync_dev(inode->i_rdev);
access_count[dev]--;
}
return 0;
@@ -1190,9 +1187,8 @@ static int ps2esdi_reread_partitions(kdev_t dev)
ps2esdi_gendisk.part[start + partition].nr_sects = 0;
}
- ps2esdi_gendisk.part[start].nr_sects = ps2esdi_info[target].head *
- ps2esdi_info[target].cyl * ps2esdi_info[target].sect;
- resetup_one_dev(&ps2esdi_gendisk, target);
+ grok_partitions(&ps2esdi_gendisk, target, 1<<6,
+ ps2esdi_info[target].head * ps2esdi_info[target].cyl * ps2esdi_info[target].sect);
ps2esdi_valid[target] = 1;
wake_up(&ps2esdi_wait_open);
diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c
index 2e95d34f8..37b2035cd 100644
--- a/drivers/block/raid0.c
+++ b/drivers/block/raid0.c
@@ -182,6 +182,12 @@ static int raid0_map (struct md_dev *mddev, kdev_t *rdev,
block=*rsector >> 1;
hash=data->hash_table+(block/data->smallest->size);
+ if (hash - data->hash_table > data->nr_zones)
+ {
+ printk(KERN_DEBUG "raid0_map: invalid block %ul\n", block);
+ return -1;
+ }
+
/* Sanity check */
if ((chunk_size*2)<(*rsector % (chunk_size*2))+size)
{
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 7d582e9e3..f3803b4b3 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -429,6 +429,15 @@ int __init rd_init (void)
blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */
+ for (i = 0; i < NUM_RAMDISKS; i++)
+ register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* We ought to separate initrd operations here */
+ register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1);
+#endif
+
+ /* rd_size is given in kB */
printk("RAMDISK driver initialized: "
"%d RAM disks of %dK size %d blocksize\n",
NUM_RAMDISKS, rd_size, rd_blocksize);
diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c
index 08bdb9248..d255bbdf8 100644
--- a/drivers/block/sis5513.c
+++ b/drivers/block/sis5513.c
@@ -222,7 +222,7 @@ byte sis_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
/*
- * ((id->word93 & 0x2000) && (HWIF(drive)->udma_four))
+ * ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four))
*/
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
@@ -235,7 +235,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
byte speed = 0x00, unmask = 0xE0, four_two = 0x00;
int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+ byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
if (host_dev) {
switch(host_dev->device) {
@@ -472,6 +472,7 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
host_dev = host;
printk(SiSHostChipInfo[i].name);
+ printk("\n");
if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) {
if (latency != 0x10)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 7466b5197..3190c10b9 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -924,8 +924,6 @@ static int floppy_release(struct inode *inode, struct file *filp)
if (devnum >= floppy_count)
return -ENODEV;
- block_fsync (filp, filp->f_dentry);
-
fs = &floppy_states[devnum];
sw = fs->swim3;
if (fs->ref_count > 0 && --fs->ref_count == 0) {
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 353e0a8cc..6a74f9a0b 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -449,8 +449,6 @@ static int floppy_release(struct inode *inode, struct file *filp)
if (devnum >= floppy_count)
return -ENODEV;
- block_fsync (filp, filp->f_dentry);
-
fs = &floppy_states[devnum];
if (fs->ref_count > 0) fs->ref_count--;
return 0;
diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c
index 12a121152..09c4a86a7 100644
--- a/drivers/block/via82cxxx.c
+++ b/drivers/block/via82cxxx.c
@@ -546,8 +546,6 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
hwif->tuneproc = &via82cxxx_tune_drive;
if (hwif->dma_base) {
hwif->dmaproc = &via82cxxx_dmaproc;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 363c0ae71..b4c52d6a2 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -135,12 +135,6 @@ static struct gendisk xd_gendisk = {
"xd", /* Major name */
6, /* Bits to shift to get real from partition */
1 << 6, /* Number of partitions per real */
- XD_MAXDRIVES, /* maximum number of real */
-#ifdef MODULE
- NULL, /* called from init_module */
-#else
- xd_geninit, /* init function */
-#endif
xd_struct, /* hd struct */
xd_sizes, /* block sizes */
0, /* number */
@@ -181,6 +175,7 @@ int __init xd_init (void)
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
xd_gendisk.next = gendisk_head;
gendisk_head = &xd_gendisk;
+ xd_geninit();
return 0;
}
@@ -210,16 +205,21 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address)
/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
/* and set up the "raw" device entries in the table */
-static void __init xd_geninit (struct gendisk *ignored)
+static void __init xd_geninit (void)
{
u_char i,controller;
unsigned int address;
+ for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = xd_blocksizes;
+
if (xd_detect(&controller,&address)) {
- printk("Detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address);
+ printk("Detected a%s controller (type %d) at address %06x\n",
+ xd_sigs[controller].name,controller,address);
if (check_region(xd_iobase,4)) {
- printk("xd: Ports at 0x%x are not available\n",xd_iobase);
+ printk("xd: Ports at 0x%x are not available\n",
+ xd_iobase);
return;
}
request_region(xd_iobase,4,"xd");
@@ -227,9 +227,12 @@ static void __init xd_geninit (struct gendisk *ignored)
xd_sigs[controller].init_controller(address);
xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
- printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
+ printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
+ xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
for (i = 0; i < xd_drives; i++)
- printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,xd_info[i].cylinders,xd_info[i].heads,xd_info[i].sectors);
+ printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,
+ xd_info[i].cylinders,xd_info[i].heads,
+ xd_info[i].sectors);
}
if (xd_drives) {
@@ -244,14 +247,14 @@ static void __init xd_geninit (struct gendisk *ignored)
}
for (i = 0; i < xd_drives; i++) {
- xd_struct[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
xd_valid[i] = 1;
+ register_disk(&xd_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, &xd_fops,
+ xd_info[i].heads * xd_info[i].cylinders *
+ xd_info[i].sectors);
}
xd_gendisk.nr_real = xd_drives;
- for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
- blksize_size[MAJOR_NR] = xd_blocksizes;
}
/* xd_open: open a device */
@@ -367,17 +370,12 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
/* xd_release: release the device */
static int xd_release (struct inode *inode, struct file *file)
{
- int target;
-
- target= DEVICE_NR(inode->i_rdev);
+ int target = DEVICE_NR(inode->i_rdev);
if (target < xd_drives) {
- sync_dev(inode->i_rdev);
xd_access[target]--;
-
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif /* MODULE */
-
}
return 0;
}
@@ -411,8 +409,8 @@ static int xd_reread_partitions(kdev_t dev)
xd_gendisk.part[minor].nr_sects = 0;
};
- xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
- resetup_one_dev(&xd_gendisk,target);
+ grok_partitions(&xd_gendisk, target, 1<<6,
+ xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors);
xd_valid[target] = 1;
wake_up(&xd_wait_open);
@@ -1150,27 +1148,26 @@ static void xd_done (void)
int init_module(void)
{
int i,count = 0;
- int error = xd_init();
- if (!error)
- {
- printk(KERN_INFO "XD: Loaded as a module.\n");
- for (i = 4; i > 0; i--)
- if(((xd[i] = xd[i-1]) >= 0) && !count)
- count = i;
- if((xd[0] = count))
- xd_setup(NULL, xd);
- xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
- if (!xd_drives) {
- /* no drives detected - unload module */
- unregister_blkdev(MAJOR_NR, "xd");
- xd_done();
- return (-1);
- }
- for (i = 0; i < xd_drives; i++)
- resetup_one_dev(&xd_gendisk, i);
+ int error;
+
+ for (i = 4; i > 0; i--)
+ if(((xd[i] = xd[i-1]) >= 0) && !count)
+ count = i;
+ if((xd[0] = count))
+ xd_setup(NULL, xd);
+
+ if (error = xd_init())
+ return error;
+
+ printk(KERN_INFO "XD: Loaded as a module.\n");
+ if (!xd_drives) {
+ /* no drives detected - unload module */
+ unregister_blkdev(MAJOR_NR, "xd");
+ xd_done();
+ return (-1);
}
- return error;
+ return 0;
}
void cleanup_module(void)
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index c121e8e9f..b3b9cf4bf 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -109,7 +109,7 @@ void xd_manual_geo_init (char *command,int *integers);
#endif /* MODULE */
static u_char xd_detect (u_char *controller, unsigned int *address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
-static void xd_geninit (struct gendisk *);
+static void xd_geninit (void);
static int xd_open (struct inode *inode,struct file *file);
static void do_xd_request (request_queue_t * q);
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 224db90e8..dfd0b0199 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -320,8 +320,6 @@ z2_release( struct inode *inode, struct file *filp )
if ( current_device == -1 )
return 0;
- sync_dev( inode->i_rdev );
-
/*
* FIXME: unmap memory
*/
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index c9bc3f999..ef9cbd398 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1593,8 +1593,6 @@ static int aztcd_release(struct inode * inode, struct file * file)
MOD_DEC_USE_COUNT;
if (!--azt_open_count) {
azt_invalidate_buffers();
- sync_dev(inode->i_rdev); /*??? isn't it a read only dev?*/
- invalidate_buffers(inode -> i_rdev);
aztUnlockDoor();
if (azt_auto_eject)
aztSendCmd(ACMD_EJECT);
@@ -1798,6 +1796,7 @@ int __init aztcd_init(void)
blksize_size[MAJOR_NR] = aztcd_blocksizes;
#endif
read_ahead[MAJOR_NR] = 4;
+ register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &azt_fops, 0);
if ((azt_port==0x1f0)||(azt_port==0x170))
request_region(azt_port, 8, "aztcd"); /*IDE-interface*/
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index e7585203d..f7d15edad 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -353,6 +353,8 @@ int register_cdrom(struct cdrom_device_info *cdi)
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
cdi->next = topCdromPtr;
topCdromPtr = cdi;
+ /*FIXME:as soon as we'll switch to real thing, pass device number here*/
+ register_disk(NULL, cdi->dev, 1, &cdrom_fops, 0);
return 0;
}
#undef ENSURE
@@ -380,6 +382,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
prev->next = cdi->next;
else
topCdromPtr = cdi->next;
+/* unregister_disk(); */
cdi->ops->n_minors--;
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
return 0;
@@ -640,11 +643,6 @@ int cdrom_release(struct inode *ip, struct file *fp)
!(fp && fp->f_flags & O_NONBLOCK);
cdo->release(cdi);
if (cdi->use_count == 0) { /* last process that closes dev*/
- struct super_block *sb;
- sync_dev(dev);
- sb = get_super(dev);
- if (sb) invalidate_inodes(sb);
- invalidate_buffers(dev);
if (opened_for_data &&
cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
cdo->tray_move(cdi, 1);
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index 73c6c950c..6047df0c7 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -418,8 +418,6 @@ printk ( "GSCD: release\n" );
#endif
gscd_bn = -1;
- sync_dev(inode->i_rdev);
- invalidate_buffers(inode -> i_rdev);
MOD_DEC_USE_COUNT;
return 0;
@@ -1084,6 +1082,7 @@ int result;
gscdPresent = 1;
request_region(gscd_port, 4, "gscd");
+ register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &gscd_fops, 0);
printk (KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n" );
return 0;
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index f8ebde15d..b0bdc833a 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -1935,8 +1935,6 @@ static int opt_release(struct inode *ip, struct file *fp)
if (!--open_count) {
toc_uptodate = 0;
opt_invalidate_buffers();
- sync_dev(ip -> i_rdev);
- invalidate_buffers(ip -> i_rdev);
status = exec_cmd(COMUNLOCK); /* Unlock door */
if (status < 0) {
DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
@@ -2074,6 +2072,7 @@ int __init optcd_init(void)
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 4;
request_region(optcd_port, 4, "optcd");
+ register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);
printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
return 0;
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 7ea184b5f..f13deeac8 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -1413,8 +1413,6 @@ static int sjcd_release( struct inode *inode, struct file *file ){
#endif
if( --sjcd_open_count == 0 ){
sjcd_invalidate_buffers();
- sync_dev( inode->i_rdev );
- invalidate_buffers( inode->i_rdev );
s = sjcd_tray_unlock();
if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
#if defined( SJCD_DIAGNOSTIC )
@@ -1480,6 +1478,7 @@ int __init sjcd_init( void ){
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[ MAJOR_NR ] = 4;
+ register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &sjcd_fops, 0);
if( check_region( sjcd_base, 4 ) ){
printk( "SJCD: Init failed, I/O port (%X) is already in use\n",
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index 14e25f90a..a9b82571e 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -798,9 +798,6 @@ do_cdu535_request(request_queue_t * q)
Byte status[2];
Byte cmd[2];
- if (!sony_inuse) {
- cdu_open(NULL, NULL);
- }
while (1) {
/*
* The beginning here is stolen from the hard disk driver. I hope
@@ -1396,7 +1393,6 @@ cdu_open(struct inode *inode,
{
Byte status[2], cmd_buff[2];
-
if (sony_inuse)
return -EBUSY;
if (check_drive_status() != 0)
@@ -1451,7 +1447,6 @@ cdu_release(struct inode *inode,
sony_usage--;
}
if (sony_usage == 0) {
- sync_dev(inode->i_rdev);
check_drive_status();
if (sony_audio_status != CDROM_AUDIO_PLAY) {
@@ -1639,6 +1634,7 @@ sony535_init(void)
return -EIO;
}
request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
+ register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &cdu_fops, 0);
return 0;
}
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 7d2d0c8e7..140cc583d 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -22,33 +22,35 @@ if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
+ tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
tristate ' Comtrol Rocketport support' CONFIG_ROCKETPORT
- tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
- if [ "$CONFIG_DIGIEPCA" = "n" ]; then
- tristate ' Digiboard PC/Xx Support' CONFIG_DIGI
- fi
tristate ' Cyclades async mux support' CONFIG_CYCLADES
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
fi
- bool ' Stallion multiport serial support' CONFIG_STALDRV
- if [ "$CONFIG_STALDRV" = "y" ]; then
- tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
- tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
+ tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+ if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+ tristate ' Digiboard PC/Xx Support' CONFIG_DIGI
+ fi
+ tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL
+ tristate 'Moxa Intellio support' CONFIG_MOXA_INTELLIO
+ tristate 'Moxa SmartIO support' CONFIG_MOXA_SMARTIO
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
fi
+ dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m
+ dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m
tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8
- tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
tristate ' Specialix IO8+ card support' CONFIG_SPECIALIX
if [ "$CONFIG_SPECIALIX" != "n" ]; then
bool ' Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
fi
tristate ' Specialix SX (and SI) card support' CONFIG_SX
- tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
+ bool ' Stallion multiport serial support' CONFIG_STALDRV
+ if [ "$CONFIG_STALDRV" = "y" ]; then
+ tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
+ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
fi
- dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m
- dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m
fi
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
@@ -216,7 +218,7 @@ if [ "$CONFIG_DRM" = "y" ]; then
dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m
fi
-if [ "$CONFIG_PCMCIA" != "n" ]; then
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
source drivers/char/pcmcia/Config.in
fi
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 42611313f..a25eda6fd 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -105,6 +105,22 @@ else
endif
endif
+ifeq ($(CONFIG_MOXA_SMARTIO),y)
+L_OBJS += mxser.o
+else
+ ifeq ($(CONFIG_MOXA_SMARTIO),m)
+ M_OBJS += mxser.o
+ endif
+endif
+
+ifeq ($(CONFIG_MOXA_INTELLIO),y)
+L_OBJS += moxa.o
+else
+ ifeq ($(CONFIG_MOXA_INTELLIO),m)
+ M_OBJS += moxa.o
+ endif
+endif
+
ifeq ($(CONFIG_DIGI),y)
O_OBJS += pcxx.o
else
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 784360daf..cfc1fdadd 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -219,7 +219,7 @@ int __init acq_init(void)
misc_register(&acq_miscdev);
request_region(WDT_STOP, 1, "Acquire WDT");
request_region(WDT_START, 1, "Acquire WDT");
- unregister_reboot_notifier(&acq_notifier);
+ register_reboot_notifier(&acq_notifier);
return 0;
}
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 379a7b929..3f75d721a 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -386,7 +386,7 @@ static int init_bttv_i2c(struct bttv *btv)
bttv_bit_setscl(btv,1);
bttv_bit_setsda(btv,1);
-
+
return i2c_bit_add_bus(&btv->i2c_adap);
}
@@ -428,15 +428,15 @@ static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
}
/* read EEPROM */
-static void readee(struct bttv *btv, unsigned char *eedata)
+static void readee(struct bttv *btv, unsigned char *eedata, int addr)
{
int i;
- if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) {
+ if (I2CWrite(btv, addr, 0, -1, 0)<0) {
printk(KERN_WARNING "bttv: readee error\n");
return;
}
- btv->i2c_client.addr = 0xa0 >> 1;
+ btv->i2c_client.addr = addr >> 1;
for (i=0; i<256; i+=16) {
if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) {
printk(KERN_WARNING "bttv: readee error\n");
@@ -486,7 +486,7 @@ hauppauge_tuner[] =
static void
hauppauge_eeprom(struct bttv *btv)
{
- readee(btv, eeprom_data);
+ readee(btv, eeprom_data, 0xa0);
if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))
{
btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
@@ -515,7 +515,10 @@ hauppauge_msp_reset(struct bttv *btv)
* driver, but using BTTV functions */
static void init_PXC200(struct bttv *btv)
{
- int tmp;
+ static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x00 };
+ int i,tmp;
/* Initialise GPIO-connevted stuff */
btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
@@ -537,39 +540,37 @@ static void init_PXC200(struct bttv *btv)
* argument so the numbers are different */
printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
-
- tmp=I2CWrite(btv,0x1E,0x08,0,1);
- printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x09,0,1);
- printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x0a,0,1);
- printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x0b,0,1);
- printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x0c,0,1);
- printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x0d,0,1);
- printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x01,0,1);
- printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x02,0,1);
- printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x03,0,1);
- printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x04,0,1);
- printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x05,0,1);
- printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x06,0,1);
- printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
- tmp=I2CWrite(btv,0x1E,0x00,0,1);
- printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-
+
+ for (i = 0; i < sizeof(vals)/sizeof(int); i++) {
+ tmp=I2CWrite(btv,0x1E,vals[i],0,1);
+ printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",
+ tmp,I2CRead(btv,0x1F,NULL));
+ }
printk(KERN_INFO "PXC200 Initialised.\n");
}
/* ----------------------------------------------------------------------- */
+static struct VENDOR {
+ int id;
+ char *name;
+} vendors[] = {
+ { 0x0070, "Hauppauge" },
+ { 0x144f, "Askey" },
+ { -1, NULL }
+};
+
+static struct CARD {
+ int id;
+ int vid;
+ int cardnr;
+ char *name;
+} cards[] = {
+ { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV Theater" },
+ { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" },
+ { -1, -1, -1, NULL }
+};
+
struct tvcard
{
char *name;
@@ -677,8 +678,8 @@ static struct tvcard tvcards[] =
1,1,1,1,0 },
/* 0x18 */
- { "Magic TView CPH061 (bt878)",
- 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0},0,
+ { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
+ 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
1,1,1,1,0 },
{ "Terratec/Vobis TV-Boostar",
3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
@@ -709,15 +710,58 @@ static struct tvcard tvcards[] =
{ "Intel Create and Share PCI",
4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
1,1,1,1,0 },
- { "Askey/Typhoon/Anubis Magic TView",
- 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
- 1,1,1,1,0 },
{ "Terratec TerraTValue",
- 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
+ 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
1,1,1,1,0 },
};
#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
+static void
+dump_eeprom(struct bttv *btv, int addr)
+{
+ int i,id1,id2,n1,n2;
+
+ printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
+ readee(btv, eeprom_data,addr);
+ for (i = 0; i < 256;) {
+ printk(KERN_DEBUG " %02x:",i);
+ do {
+ printk(" %02x",eeprom_data[i++]);
+ } while (i % 16);
+ printk("\n");
+ }
+ id1 = (eeprom_data[252] << 8) | (eeprom_data[253]);
+ id2 = (eeprom_data[254] << 8) | (eeprom_data[255]);
+ if (id1 != 0 && id1 != 0xffff &&
+ id2 != 0 && id2 != 0xffff) {
+ n1 = -1;
+ n2 = -1;
+ for (i = 0; vendors[i].id != -1; i++)
+ if (vendors[i].id == id2)
+ n2 = i;
+ for (i = 0; cards[i].id != -1; i++)
+ if (cards[i].id == id1 &&
+ cards[i].vid == id2)
+ n1 = i;
+ if (n1 != -1 && n2 != -1) {
+ printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n",
+ cards[n1].name,id1,vendors[n2].name,id2);
+ printk(KERN_INFO " => card=%d (%s)\n",
+ cards[n1].cardnr,tvcards[cards[n1].cardnr].name);
+#if 1
+ /* not yet, but that's the plan for autodetect... */
+ btv->type = cards[n1].cardnr;
+#endif
+ } else {
+ printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n",
+ (n1 != -1) ? cards[n1].name : "unknown", id1,
+ (n2 != -1) ? vendors[n2].name : "unknown", id2);
+ printk(KERN_INFO " please mail card type, id + vendor to ");
+ printk(" kraxel@goldbach.in-berlin.de\n");
+ }
+ }
+}
+
/* ----------------------------------------------------------------------- */
static void audio(struct bttv *btv, int mode, int no_irq_context)
@@ -2883,6 +2927,13 @@ static void idcard(int i)
}
}
+#if 1
+ /* DEBUG: dump eeprom content if available */
+ if (I2CRead(btv, 0xa0, "eeprom")>=0) {
+ dump_eeprom(btv,0xa0);
+ }
+#endif
+
/* print which board we have found */
printk(KERN_INFO "bttv%d: model: ",btv->nr);
@@ -2917,7 +2968,8 @@ static void idcard(int i)
if (btv->type == BTTV_HAUPPAUGE878 ||
btv->type == BTTV_CONFERENCETV ||
btv->type == BTTV_PIXVIEWPLAYTV ||
- btv->type == BTTV_AVERMEDIA98) {
+ btv->type == BTTV_AVERMEDIA98 ||
+ btv->type == BTTV_MAGICTVIEW061) {
btv->pll.pll_ifreq=28636363;
btv->pll.pll_crystal=BT848_IFORM_XT0;
}
@@ -2952,8 +3004,8 @@ static void idcard(int i)
request_module("tda9855");
}
- if (tvcards[btv->type].tea63xx &&
- I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0) {
+ if (tvcards[btv->type].tea63xx /* &&
+ I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0 */) {
if (autoload)
request_module("tea6300");
}
@@ -3553,7 +3605,11 @@ int init_bttv_cards(struct video_init *unused)
#endif
{
int i;
-
+
+ printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
+ (BTTV_VERSION_CODE >> 16) & 0xff,
+ (BTTV_VERSION_CODE >> 8) & 0xff,
+ BTTV_VERSION_CODE & 0xff);
handle_chipset();
if (find_bt848()<=0)
return -EIO;
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index b4b0caaa0..309e93e95 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -21,7 +21,7 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE 0x00070b
+#define BTTV_VERSION_CODE 0x00070d
#include <linux/types.h>
#include <linux/wait.h>
@@ -248,32 +248,6 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
#define BTTV_TERRATV 0x1c
#define BTTV_PXC200 0x1d
-#if 0
-#define BTTV_UNKNOWN 0x00
-#define BTTV_MIRO 0x01
-#define BTTV_HAUPPAUGE 0x02
-#define BTTV_STB 0x03
-#define BTTV_INTEL 0x04
-#define BTTV_DIAMOND 0x05
-#define BTTV_AVERMEDIA 0x06
-#define BTTV_MATRIX_VISION 0x07
-#define BTTV_FLYVIDEO 0x08
-#define BTTV_TURBOTV 0x09
-#define BTTV_HAUPPAUGE878 0x0a
-#define BTTV_MIROPRO 0x0b
-#define BTTV_TVBOOSTAR 0x0c
-#define BTTV_WINCAM 0x0d
-#define BTTV_MAXI 0x0e
-#define BTTV_VHX 0x10
-#define BTTV_PXC200 0x11
-#define BTTV_AVERMEDIA98 0x12
-#define BTTV_FLYVIDEO98 0x13
-
-#define BTTV_PIXVIEWPLAYTV 0x17
-#define BTTV_WINVIEW_601 0x18
-#define BTTV_CONFERENCETV 0x1c
-#endif
-
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 655f11aff..d11de7b35 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,7 +1,7 @@
#undef BLOCKMOVE
#define Z_WAKE
static char rcsid[] =
-"$Revision: 2.3.2.2 $$Date: 1999/10/01 11:27:43 $";
+"$Revision: 2.3.2.4 $$Date: 2000/01/17 09:19:40 $";
/*
* linux/drivers/char/cyclades.c
@@ -9,8 +9,9 @@ static char rcsid[] =
* This file contains the driver for the Cyclades Cyclom-Y multiport
* serial boards.
*
- * Initially written by Randolph Bentson (bentson@grieg.seaslug.org).
- * Maintained by Ivan Passos (ivan@cyclades.com).
+ * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
+ * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
+ * Currently maintained by Ivan Passos <ivan@cyclades.com>.
*
* For Technical support and installation problems, please send e-mail
* to support@cyclades.com.
@@ -30,10 +31,21 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.3.2.4 2000/01/17 09:19:40 ivan
+ * Fixed SMP locking in Cyclom-Y interrupt handler.
+ *
+ * Revision 2.3.2.3 1999/12/28 12:11:39 ivan
+ * Added a new cyclades_card field called nports to allow the driver to
+ * know the exact number of ports found by the Z firmware after its load;
+ * RX buffer contention prevention logic on interrupt op mode revisited
+ * (Cyclades-Z only);
+ * Revisited printk's for Z debug;
+ * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
+ *
* Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
+ * Fixed bug in cyz_poll that would make all ports but port 0
* unable to transmit/receive data (Cyclades-Z only);
- * Implemented logic to prevent the RX buffer from being stuck with
+ * Implemented logic to prevent the RX buffer from being stuck with data
* due to a driver / firmware race condition in interrupt op mode
* (Cyclades-Z only);
* Fixed bug in block_til_ready logic that would lead to a system crash;
@@ -598,25 +610,6 @@ static char rcsid[] =
#define cy_min(a,b) (((a)<(b))?(a):(b))
-#if 0
-/********
- * For the next two macros, it is assumed that the buffer size is a
- * power of 2
- ********/
-
-#define CHARS_IN_BUF(buf_ctrl) \
- ((cy_readl(&buf_ctrl->rx_put) - \
- cy_readl(&buf_ctrl->rx_get) + \
- cy_readl(&buf_ctrl->rx_bufsize)) & \
- (cy_readl(&buf_ctrl->rx_bufsize) - 1))
-
-#define SPACE_IN_BUF(buf_ctrl) \
- ((cy_readl(&buf_ctrl->tx_get) - \
- cy_readl(&buf_ctrl->tx_put) + \
- cy_readl(&buf_ctrl->tx_bufsize) - 1) & \
- (cy_readl(&buf_ctrl->tx_bufsize) - 1))
-#endif
-
/*
* Include section
*/
@@ -997,10 +990,12 @@ do_softint(void *private_)
}
#ifdef CONFIG_CYZ_INTR
if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
- cyz_rx_full_timer[info->line].expires = jiffies + 1;
- cyz_rx_full_timer[info->line].function = cyz_rx_restart;
- cyz_rx_full_timer[info->line].data = (unsigned long)info;
- add_timer(&cyz_rx_full_timer[info->line]);
+ if (cyz_rx_full_timer[info->line].function == NULL) {
+ cyz_rx_full_timer[info->line].expires = jiffies + 1;
+ cyz_rx_full_timer[info->line].function = cyz_rx_restart;
+ cyz_rx_full_timer[info->line].data = (unsigned long)info;
+ add_timer(&cyz_rx_full_timer[info->line]);
+ }
}
#endif
if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) {
@@ -1172,7 +1167,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->last_active = jiffies;
save_car = cy_readb(base_addr+(CyCAR<<index));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
- spin_unlock(&cinfo->card_lock);
/* if there is nowhere to put the data, discard it */
if(info->tty == 0){
@@ -1301,7 +1295,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
queue_task(&tty->flip.tqueue, &tq_timer);
}
/* end of service */
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyRIR<<index), (save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
spin_unlock(&cinfo->card_lock);
@@ -1323,23 +1316,18 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
i = channel + chip * 4 + cinfo->first_line;
save_car = cy_readb(base_addr+(CyCAR<<index));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
- spin_unlock(&cinfo->card_lock);
/* validate the port# (as configured and open) */
if( (i < 0) || (NR_PORTS <= i) ){
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
goto txend;
}
info = &cy_port[i];
info->last_active = jiffies;
if(info->tty == 0){
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
goto txdone;
}
@@ -1371,27 +1359,21 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while (char_count-- > 0){
if (!info->xmit_cnt){
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
goto txdone;
}
if (info->xmit_buf == 0){
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
goto txdone;
}
if (info->tty->stopped || info->tty->hw_stopped){
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
goto txdone;
}
/* Because the Embedded Transmit Commands have
@@ -1433,7 +1415,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
txend:
/* end of service */
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyTIR<<index),
(save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
@@ -1454,7 +1435,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mdm_change = cy_readb(base_addr+(CyMISR<<index));
mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
- spin_unlock(&cinfo->card_lock);
if(info->tty == 0){/* no place for data, ignore it*/
;
@@ -1489,11 +1469,9 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* cy_start isn't used
because... !!! */
info->tty->hw_stopped = 0;
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) |
CyTxMpty);
- spin_unlock(&cinfo->card_lock);
cy_sched_event(info,
Cy_EVENT_WRITE_WAKEUP);
}
@@ -1502,11 +1480,9 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* cy_stop isn't used
because ... !!! */
info->tty->hw_stopped = 1;
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxMpty);
- spin_unlock(&cinfo->card_lock);
}
}
}
@@ -1516,7 +1492,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
/* end of service */
- spin_lock(&cinfo->card_lock);
cy_writeb((u_long)base_addr+(CyMIR<<index),
(save_xir & 0x3f));
cy_writeb((u_long)base_addr+(CyCAR<<index), save_car);
@@ -1538,7 +1513,6 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/******** Start of block of Cyclades-Z specific code *********/
/***********************************************************/
-
static int
cyz_fetch_msg( struct cyclades_card *cinfo,
uclong *channel, ucchar *cmd, uclong *param)
@@ -1592,7 +1566,7 @@ cyz_issue_cmd( struct cyclades_card *cinfo,
(cinfo->ctl_addr))->pci_doorbell);
while( (cy_readl(pci_doorbell) & 0xff) != 0){
if (index++ == 1000){
- return(-1);
+ return((int)(cy_readl(pci_doorbell) & 0xff));
}
udelay(50L);
}
@@ -1604,7 +1578,8 @@ cyz_issue_cmd( struct cyclades_card *cinfo,
} /* cyz_issue_cmd */
static void
-cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
+cyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl,
+ volatile struct BUF_CTRL *buf_ctrl)
{
struct cyclades_card *cinfo = &cy_card[info->card];
struct tty_struct *tty = info->tty;
@@ -1614,14 +1589,12 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
#else
char data;
#endif
- volatile uclong rx_put, rx_get, rx_bufsize;
-
-/* Removed due to compilation problems in Alpha systems */
-// if ((char_count = CHARS_IN_BUF(buf_ctrl))){
+ volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
- rx_get = cy_readl(&buf_ctrl->rx_get);
+ rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
rx_put = cy_readl(&buf_ctrl->rx_put);
rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+ rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
if (rx_put >= rx_get)
char_count = rx_put - rx_get;
else
@@ -1640,7 +1613,7 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
#endif
if(tty == 0){
/* flush received characters */
- rx_get = (rx_get + char_count) & (rx_bufsize - 1);
+ new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1);
info->rflush_count++;
}else{
#ifdef BLOCKMOVE
@@ -1648,19 +1621,18 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
for performance, but because of buffer boundaries, there
may be several steps to the operation */
while(0 < (small_count =
- cy_min((rx_bufsize - rx_get),
+ cy_min((rx_bufsize - new_rx_get),
cy_min((TTY_FLIPBUF_SIZE - tty->flip.count), char_count))
)) {
memcpy_fromio(tty->flip.char_buf_ptr,
(char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->rx_bufaddr)
- + rx_get),
+ + rx_bufaddr + new_rx_get),
small_count);
tty->flip.char_buf_ptr += small_count;
memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count);
tty->flip.flag_buf_ptr += small_count;
- rx_get = (rx_get + small_count) & (rx_bufsize - 1);
+ new_rx_get = (new_rx_get + small_count) & (rx_bufsize - 1);
char_count -= small_count;
info->icount.rx += small_count;
info->idle_stats.recv_bytes += small_count;
@@ -1669,14 +1641,10 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
#else
while(char_count--){
if (tty->flip.count >= TTY_FLIPBUF_SIZE){
-#ifdef CONFIG_CYZ_INTR
- cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
-#endif
break;
}
- data = cy_readb(cinfo->base_addr +
- cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
- rx_get = (rx_get + 1) & (rx_bufsize - 1);
+ data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get);
+ new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1);
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = data;
@@ -1684,16 +1652,29 @@ cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
info->icount.rx++;
}
#endif
+#ifdef CONFIG_CYZ_INTR
+ /* Recalculate the number of chars in the RX buffer and issue
+ a cmd in case it's higher than the RX high water mark */
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
+ if(char_count >= cy_readl(&buf_ctrl->rx_threshold)) {
+ cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
+ }
+#endif
info->idle_stats.recv_idle = jiffies;
queue_task(&tty->flip.tqueue, &tq_timer);
}
/* Update rx_get */
- cy_writel(&buf_ctrl->rx_get, rx_get);
+ cy_writel(&buf_ctrl->rx_get, new_rx_get);
}
}
static void
-cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
+cyz_handle_tx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl,
+ volatile struct BUF_CTRL *buf_ctrl)
{
struct cyclades_card *cinfo = &cy_card[info->card];
struct tty_struct *tty = info->tty;
@@ -1702,14 +1683,15 @@ cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
#ifdef BLOCKMOVE
int small_count;
#endif
- volatile uclong tx_put, tx_get, tx_bufsize;
+ volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
-/* Removed due to compilation problems in Alpha systems */
-// if ((char_count = SPACE_IN_BUF(buf_ctrl))){
+ if (info->xmit_cnt <= 0) /* Nothing to transmit */
+ return;
tx_get = cy_readl(&buf_ctrl->tx_get);
tx_put = cy_readl(&buf_ctrl->tx_put);
tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
if (tx_put >= tx_get)
char_count = tx_get - tx_put - 1 + tx_bufsize;
else
@@ -1724,8 +1706,7 @@ cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
if(info->x_char) { /* send special char */
data = info->x_char;
- cy_writeb((cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
+ cy_writeb((cinfo->base_addr + tx_bufaddr + tx_put), data);
tx_put = (tx_put + 1) & (tx_bufsize - 1);
info->x_char = 0;
char_count--;
@@ -1739,8 +1720,7 @@ cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
cy_min(info->xmit_cnt, char_count))))){
- memcpy_toio((char *)(cinfo->base_addr
- + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
+ memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
&info->xmit_buf[info->xmit_tail],
small_count);
@@ -1759,8 +1739,7 @@ cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl)
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
- cy_writeb(cinfo->base_addr +
- cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, data);
+ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
tx_put = (tx_put + 1) & (tx_bufsize - 1);
char_count--;
info->icount.tx++;
@@ -1801,6 +1780,11 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
fw_ver = cy_readl(&board_ctrl->fw_version);
hw_ver = cy_readl(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0);
+#ifdef CONFIG_CYZ_INTR
+ if (!cinfo->nports)
+ cinfo->nports = (int) cy_readl(&board_ctrl->n_channel);
+#endif
+
while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
delta_count = 0;
@@ -1873,7 +1857,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r",
info->card, channel);
#endif
- cyz_handle_rx(info, buf_ctrl);
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
break;
case C_CM_TXBEMPTY:
case C_CM_TXLOWWM:
@@ -1883,7 +1867,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r",
info->card, channel);
#endif
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
break;
#endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL:
@@ -1932,12 +1916,16 @@ cyz_rx_restart(unsigned long arg)
int retval;
int card = info->card;
uclong channel = (info->line) - (cy_card[card].first_line);
+ unsigned long flags;
- cyz_rx_full_timer[info->card].expires = jiffies + HZ;
+ CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
if (retval != 0){
- printk("cyc:cyz_rx_restart retval was %x\n", retval);
+ printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+ info->line, retval);
}
+ cyz_rx_full_timer[info->line].function = NULL;
+ CY_UNLOCK(info, flags);
}
#else /* CONFIG_CYZ_INTR */
@@ -1962,27 +1950,28 @@ cyz_poll(unsigned long arg)
if (!IS_CYC_Z(*cinfo)) continue;
if (!ISZLOADED(*cinfo)) continue;
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+ board_ctrl = &(zfw_ctrl->board_ctrl);
+
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
+ cinfo->nports = (int) cy_readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
continue;
}
- firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
- zfw_ctrl = (struct ZFW_CTRL *)
- (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
- board_ctrl = &(zfw_ctrl->board_ctrl);
-
cyz_handle_cmd(cinfo);
- for (port = 0; port < cy_readl(&board_ctrl->n_channel); port++){
+ for (port = 0 ; port < cinfo->nports ; port++) {
info = &cy_port[ port + cinfo->first_line ];
tty = info->tty;
ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
- cyz_handle_rx(info, buf_ctrl);
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
}
/* poll every 'cyz_polling_cycle' period */
cyz_timerlist.expires = jiffies + cyz_polling_cycle;
@@ -2141,13 +2130,15 @@ startup(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
if (retval != 0){
- printk("cyc:startup(1) retval was %x\n", retval);
+ printk("cyc:startup(1) retval on ttyC%d was %x\n",
+ info->line, retval);
}
/* Flush RX buffers before raising DTR and RTS */
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, 0L);
if (retval != 0){
- printk("cyc:startup(2) retval was %x\n", retval);
+ printk("cyc:startup(2) retval on ttyC%d was %x\n",
+ info->line, retval);
}
/* set timeout !!! */
@@ -2157,7 +2148,8 @@ startup(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:startup(3) retval was %x\n", retval);
+ printk("cyc:startup(3) retval on ttyC%d was %x\n",
+ info->line, retval);
}
#ifdef CY_DEBUG_DTR
printk("cyc:startup raising Z DTR\n");
@@ -2219,7 +2211,8 @@ start_xmit( struct cyclades_port *info )
CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
if (retval != 0){
- printk("cyc:start_xmit retval was %x\n", retval);
+ printk("cyc:start_xmit retval on ttyC%d was %x\n",
+ info->line, retval);
}
CY_UNLOCK(info, flags);
#else /* CONFIG_CYZ_INTR */
@@ -2329,7 +2322,8 @@ shutdown(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:shutdown retval was %x\n", retval);
+ printk("cyc:shutdown retval on ttyC%d was %x\n",
+ info->line, retval);
}
#ifdef CY_DEBUG_DTR
printk("cyc:shutdown dropping Z DTR\n");
@@ -2513,16 +2507,21 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
ch_ctrl = zfw_ctrl->ch_ctrl;
while (1) {
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR);
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:block_til_ready retval was %x\n", retval);
- }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD)){
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].rs_control) |
+ (C_RS_RTS | C_RS_DTR));
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:block_til_ready retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising Z DTR\n");
+ printk("cyc:block_til_ready raising Z DTR\n");
#endif
+ }
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)
@@ -2894,7 +2893,8 @@ cy_close(struct tty_struct *tty, struct file *filp)
retval = cyz_issue_cmd(&cy_card[info->card], channel,
C_CM_IOCTLW, 0L);
if (retval != 0){
- printk("cyc:cy_close retval was %x\n", retval);
+ printk("cyc:cy_close retval on ttyC%d was %x\n",
+ info->line, retval);
}
CY_UNLOCK(info, flags);
interruptible_sleep_on(&info->shutdown_wait);
@@ -3501,8 +3501,8 @@ set_line_char(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
if (retval != 0){
- printk("cyc:set_line_char retval at %d was %x\n",
- __LINE__, retval);
+ printk("cyc:set_line_char retval on ttyC%d was %x\n",
+ info->line, retval);
}
/* CD sensitivity */
@@ -3528,8 +3528,8 @@ set_line_char(struct cyclades_port * info)
retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:set_line_char retval at %d was %x\n",
- __LINE__, retval);
+ printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
+ info->line, retval);
}
if (info->tty){
@@ -3905,8 +3905,8 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM,0L);
if (retval != 0){
- printk("cyc:set_modem_info retval at %d was %x\n",
- __LINE__, retval);
+ printk("cyc:set_modem_info retval on ttyC%d was %x\n",
+ info->line, retval);
}
CY_UNLOCK(info, flags);
}
@@ -3957,16 +3957,16 @@ cy_break(struct tty_struct *tty, int break_state)
(info->line) - (cy_card[info->card].first_line),
C_CM_SET_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (set) retval at %d was %x\n",
- __LINE__, retval);
+ printk("cyc:cy_break (set) retval on ttyC%d was %x\n",
+ info->line, retval);
}
} else {
retval = cyz_issue_cmd(&cy_card[info->card],
(info->line) - (cy_card[info->card].first_line),
C_CM_CLR_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (clr) retval at %d was %x\n",
- __LINE__, retval);
+ printk("cyc:cy_break (clr) retval on ttyC%d was %x\n",
+ info->line, retval);
}
}
}
@@ -4579,7 +4579,8 @@ cy_flush_buffer(struct tty_struct *tty)
CY_LOCK(info, flags);
retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
if (retval != 0) {
- printk("cyc: flush_buffer retval was %x\n", retval);
+ printk("cyc: flush_buffer retval on ttyC%d was %x\n",
+ info->line, retval);
}
CY_UNLOCK(info, flags);
}
@@ -5474,6 +5475,8 @@ cy_init(void)
cy_card[board].ctl_addr)->mail_box_0);
nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
cinfo->intr_enabled = 0;
+ cinfo->nports = 0; /* Will be correctly set later, after
+ Z FW is loaded */
spin_lock_init(&cinfo->card_lock);
for (port = cinfo->first_line ;
port < cinfo->first_line + nports;
@@ -5510,9 +5513,6 @@ cy_init(void)
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef CY_DEBUG_COUNT
-// printk("cyc:cy_init(1) setting Z count to 0\n");
-#endif
info->blocked_open = 0;
info->default_threshold = 0;
info->default_timeout = 0;
@@ -5535,13 +5535,17 @@ cy_init(void)
info->jiffies[1] = 0;
info->jiffies[2] = 0;
info->rflush_count = 0;
+#ifdef CONFIG_CYZ_INTR
+ cyz_rx_full_timer[port].function = NULL;
+#endif
}
continue;
}else{ /* Cyclom-Y of some kind*/
index = cinfo->bus_index;
spin_lock_init(&cinfo->card_lock);
+ cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
for (port = cinfo->first_line ;
- port < cinfo->first_line + 4*cinfo->num_chips ;
+ port < cinfo->first_line + cinfo->nports ;
port++)
{
info = &cy_port[port];
@@ -5586,9 +5590,6 @@ cy_init(void)
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef CY_DEBUG_COUNT
-// printk("cyc:cy_init(2) setting Y count to 0\n");
-#endif
info->blocked_open = 0;
info->default_threshold = 0;
info->default_timeout = 0;
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index ea97ee151..90d95f7ba 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -61,7 +61,9 @@
#define KBD_DEFLOCK 0
#endif
+void (*kbd_ledfunc)(unsigned int led) = NULL;
EXPORT_SYMBOL(handle_scancode);
+EXPORT_SYMBOL(kbd_ledfunc);
extern void ctrl_alt_del(void);
@@ -920,6 +922,7 @@ static void kbd_bh(void)
if (leds != ledstate) {
ledstate = leds;
kbd_leds(leds);
+ if (kbd_ledfunc) kbd_ledfunc(leds);
}
}
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
new file mode 100644
index 000000000..44f01bb77
--- /dev/null
+++ b/drivers/char/moxa.c
@@ -0,0 +1,3320 @@
+/*****************************************************************************/
+/*
+ * moxa.c -- MOXA Intellio family multiport serial driver.
+ *
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ *
+ * This code is loosely based on the Linux serial driver, written by
+ * Linus Torvalds, Theodore T'so and others.
+ *
+ * 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.
+ */
+
+/*
+ * MOXA Intellio Series Driver
+ * for : LINUX
+ * date : 1999/1/7
+ * version : 5.1
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#define MOXA_VERSION "5.1k"
+
+#define MOXAMAJOR 172
+#define MOXACUMAJOR 173
+
+#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
+#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
+
+#define MAX_BOARDS 4 /* Don't change this value */
+#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
+#define MAX_PORTS 128 /* Don't change this value */
+
+/*
+ * Define the Moxa PCI vendor and device IDs.
+ */
+#define MOXA_BUS_TYPE_ISA 0
+#define MOXA_BUS_TYPE_PCI 1
+
+#ifndef PCI_VENDOR_ID_MOXA
+#define PCI_VENDOR_ID_MOXA 0x1393
+#endif
+#ifndef PCI_DEVICE_ID_CP204J
+#define PCI_DEVICE_ID_CP204J 0x2040
+#endif
+#ifndef PCI_DEVICE_ID_C218
+#define PCI_DEVICE_ID_C218 0x2180
+#endif
+#ifndef PCI_DEVICE_ID_C320
+#define PCI_DEVICE_ID_C320 0x3200
+#endif
+
+enum {
+ MOXA_BOARD_C218_PCI = 1,
+ MOXA_BOARD_C218_ISA,
+ MOXA_BOARD_C320_PCI,
+ MOXA_BOARD_C320_ISA,
+ MOXA_BOARD_CP204J,
+};
+
+static char *moxa_brdname[] =
+{
+ "C218 Turbo PCI series",
+ "C218 Turbo ISA series",
+ "C320 Turbo PCI series",
+ "C320 Turbo ISA series",
+ "CP-204J series",
+};
+
+typedef struct {
+ unsigned short vendor_id;
+ unsigned short device_id;
+ unsigned short board_type;
+} moxa_pciinfo;
+
+static moxa_pciinfo moxa_pcibrds[] =
+{
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, MOXA_BOARD_C218_PCI},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, MOXA_BOARD_C320_PCI},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, MOXA_BOARD_CP204J},
+};
+
+typedef struct _moxa_isa_board_conf {
+ int boardType;
+ int numPorts;
+ unsigned long baseAddr;
+} moxa_isa_board_conf;
+
+static moxa_isa_board_conf moxa_isa_boards[] =
+{
+/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */
+};
+
+typedef struct _moxa_pci_devinfo {
+ ushort busNum;
+ ushort devNum;
+} moxa_pci_devinfo;
+
+typedef struct _moxa_board_conf {
+ int boardType;
+ int numPorts;
+ unsigned long baseAddr;
+ int busType;
+ moxa_pci_devinfo pciInfo;
+} moxa_board_conf;
+
+static moxa_board_conf moxa_boards[MAX_BOARDS];
+static unsigned long moxaBaseAddr[MAX_BOARDS];
+
+struct moxa_str {
+ int type;
+ int port;
+ int close_delay;
+ unsigned short closing_wait;
+ int count;
+ int blocked_open;
+ int event;
+ int asyncflags;
+ long session;
+ long pgrp;
+ unsigned long statusflags;
+ struct tty_struct *tty;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ struct tq_struct tqueue;
+};
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MAX_PORTS];
+
+/* statusflags */
+#define TXSTOPPED 0x1
+#define LOWWAIT 0x2
+#define EMPTYWAIT 0x4
+#define THROTTLE 0x8
+
+/* event */
+#define MOXA_EVENT_HANGUP 1
+
+#define SERIAL_DO_RESTART
+
+
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+#define WAKEUP_CHARS 256
+
+#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start)
+
+static int verbose = 0;
+static int ttymajor = MOXAMAJOR;
+static int calloutmajor = MOXACUMAJOR;
+#ifdef MODULE
+/* Variables for insmod */
+static int baseaddr[] = {0, 0, 0, 0};
+static int type[] = {0, 0, 0, 0};
+static int numports[] = {0, 0, 0, 0};
+
+MODULE_AUTHOR("William Chen");
+MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
+MODULE_PARM(type, "1-4i");
+MODULE_PARM(baseaddr, "1-4i");
+MODULE_PARM(numports, "1-4i");
+MODULE_PARM(ttymajor, "i");
+MODULE_PARM(calloutmajor, "i");
+MODULE_PARM(verbose, "i");
+
+#endif //MODULE
+
+static struct tty_driver moxaDriver;
+static struct tty_driver moxaCallout;
+static struct tty_struct *moxaTable[MAX_PORTS + 1];
+static struct termios *moxaTermios[MAX_PORTS + 1];
+static struct termios *moxaTermiosLocked[MAX_PORTS + 1];
+static struct moxa_str moxaChannels[MAX_PORTS];
+static int moxaRefcount;
+static unsigned char *moxaXmitBuff;
+static int moxaTimer_on;
+static struct timer_list moxaTimer;
+static int moxaEmptyTimer_on[MAX_PORTS];
+static struct timer_list moxaEmptyTimer[MAX_PORTS];
+static struct semaphore moxaBuffSem;
+
+int moxa_init(void);
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+/*
+ * static functions:
+ */
+static int moxa_get_PCI_conf(struct pci_dev *, int, moxa_board_conf *);
+static void do_moxa_softint(void *);
+static int moxa_open(struct tty_struct *, struct file *);
+static void moxa_close(struct tty_struct *, struct file *);
+static int moxa_write(struct tty_struct *, int, const unsigned char *, int);
+static int moxa_write_room(struct tty_struct *);
+static void moxa_flush_buffer(struct tty_struct *);
+static int moxa_chars_in_buffer(struct tty_struct *);
+static void moxa_flush_chars(struct tty_struct *);
+static void moxa_put_char(struct tty_struct *, unsigned char);
+static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
+static void moxa_throttle(struct tty_struct *);
+static void moxa_unthrottle(struct tty_struct *);
+static void moxa_set_termios(struct tty_struct *, struct termios *);
+static void moxa_stop(struct tty_struct *);
+static void moxa_start(struct tty_struct *);
+static void moxa_hangup(struct tty_struct *);
+static void moxa_poll(unsigned long);
+static void set_tty_param(struct tty_struct *);
+static int block_till_ready(struct tty_struct *, struct file *,
+ struct moxa_str *);
+static void setup_empty_event(struct tty_struct *);
+static void check_xmit_empty(unsigned long);
+static void shut_down(struct moxa_str *);
+static void receive_data(struct moxa_str *);
+/*
+ * moxa board interface functions:
+ */
+static void MoxaDriverInit(void);
+static int MoxaDriverIoctl(unsigned int, unsigned long, int);
+static int MoxaDriverPoll(void);
+static int MoxaPortsOfCard(int);
+static int MoxaPortIsValid(int);
+static void MoxaPortEnable(int);
+static void MoxaPortDisable(int);
+static long MoxaPortGetMaxBaud(int);
+static long MoxaPortSetBaud(int, long);
+static int MoxaPortSetTermio(int, struct termios *);
+static int MoxaPortGetLineOut(int, int *, int *);
+static void MoxaPortLineCtrl(int, int, int);
+static void MoxaPortFlowCtrl(int, int, int, int, int, int);
+static int MoxaPortLineStatus(int);
+static int MoxaPortDCDChange(int);
+static int MoxaPortDCDON(int);
+static void MoxaPortFlushData(int, int);
+static int MoxaPortWriteData(int, unsigned char *, int);
+static int MoxaPortReadData(int, unsigned char *, int);
+static int MoxaPortTxQueue(int);
+static int MoxaPortRxQueue(int);
+static int MoxaPortTxFree(int);
+static void MoxaPortTxDisable(int);
+static void MoxaPortTxEnable(int);
+static int MoxaPortResetBrkCnt(int);
+static void MoxaPortSendBreak(int, int);
+static int moxa_get_serial_info(struct moxa_str *, struct serial_struct *);
+static int moxa_set_serial_info(struct moxa_str *, struct serial_struct *);
+static void MoxaSetFifo(int port, int enable);
+
+#ifdef MODULE
+int init_module(void)
+{
+ int ret;
+
+ if (verbose)
+ printk("Loading module moxa ...\n");
+ ret = moxa_init();
+ if (verbose)
+ printk("Done\n");
+ return (ret);
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+ if (verbose)
+ printk("Unloading module moxa ...\n");
+
+ if (moxaTimer_on)
+ del_timer(&moxaTimer);
+
+ for (i = 0; i < MAX_PORTS; i++)
+ if (moxaEmptyTimer_on[i])
+ del_timer(&moxaEmptyTimer[i]);
+
+ if (tty_unregister_driver(&moxaCallout))
+ printk("Couldn't unregister MOXA Intellio family callout driver\n");
+ if (tty_unregister_driver(&moxaDriver))
+ printk("Couldn't unregister MOXA Intellio family serial driver\n");
+ if (verbose)
+ printk("Done\n");
+
+}
+#endif
+
+int moxa_init(void)
+{
+ int i, n, numBoards;
+ struct moxa_str *ch;
+ int ret1, ret2;
+
+ printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION);
+
+ init_MUTEX(&moxaBuffSem);
+ memset(&moxaDriver, 0, sizeof(struct tty_driver));
+ memset(&moxaCallout, 0, sizeof(struct tty_driver));
+ moxaDriver.magic = TTY_DRIVER_MAGIC;
+ moxaDriver.name = "ttya";
+ moxaDriver.major = ttymajor;
+ moxaDriver.minor_start = 0;
+ moxaDriver.num = MAX_PORTS + 1;
+ moxaDriver.type = TTY_DRIVER_TYPE_SERIAL;
+ moxaDriver.subtype = SERIAL_TYPE_NORMAL;
+ moxaDriver.init_termios = tty_std_termios;
+ moxaDriver.init_termios.c_iflag = 0;
+ moxaDriver.init_termios.c_oflag = 0;
+ moxaDriver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ moxaDriver.init_termios.c_lflag = 0;
+ moxaDriver.flags = TTY_DRIVER_REAL_RAW;
+ moxaDriver.refcount = &moxaRefcount;
+ moxaDriver.table = moxaTable;
+ moxaDriver.termios = moxaTermios;
+ moxaDriver.termios_locked = moxaTermiosLocked;
+
+ moxaDriver.open = moxa_open;
+ moxaDriver.close = moxa_close;
+ moxaDriver.write = moxa_write;
+ moxaDriver.write_room = moxa_write_room;
+ moxaDriver.flush_buffer = moxa_flush_buffer;
+ moxaDriver.chars_in_buffer = moxa_chars_in_buffer;
+ moxaDriver.flush_chars = moxa_flush_chars;
+ moxaDriver.put_char = moxa_put_char;
+ moxaDriver.ioctl = moxa_ioctl;
+ moxaDriver.throttle = moxa_throttle;
+ moxaDriver.unthrottle = moxa_unthrottle;
+ moxaDriver.set_termios = moxa_set_termios;
+ moxaDriver.stop = moxa_stop;
+ moxaDriver.start = moxa_start;
+ moxaDriver.hangup = moxa_hangup;
+
+ moxaCallout = moxaDriver;
+ moxaCallout.name = "ttyA";
+ moxaCallout.major = calloutmajor;
+ moxaCallout.subtype = SERIAL_TYPE_CALLOUT;
+
+ moxaXmitBuff = 0;
+
+ for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) {
+ ch->type = PORT_16550A;
+ ch->port = i;
+ ch->tqueue.routine = do_moxa_softint;
+ ch->tqueue.data = ch;
+ ch->tty = 0;
+ ch->close_delay = 5 * HZ / 10;
+ ch->closing_wait = 30 * HZ;
+ ch->count = 0;
+ ch->blocked_open = 0;
+ ch->callout_termios = moxaCallout.init_termios;
+ ch->normal_termios = moxaDriver.init_termios;
+ init_waitqueue_head(&ch->open_wait);
+ init_waitqueue_head(&ch->close_wait);
+ }
+
+ for (i = 0; i < MAX_BOARDS; i++) {
+ moxa_boards[i].boardType = 0;
+ moxa_boards[i].numPorts = 0;
+ moxa_boards[i].baseAddr = 0;
+ moxa_boards[i].busType = 0;
+ moxa_boards[i].pciInfo.busNum = 0;
+ moxa_boards[i].pciInfo.devNum = 0;
+ }
+ MoxaDriverInit();
+ printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+
+ ret1 = 0;
+ ret2 = 0;
+ if ((ret1 = tty_register_driver(&moxaDriver))) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+ } else if ((ret2 = tty_register_driver(&moxaCallout))) {
+ tty_unregister_driver(&moxaDriver);
+ printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n");
+ }
+ if (ret1 || ret2) {
+ return -1;
+ }
+ for (i = 0; i < MAX_PORTS; i++) {
+ init_timer(&moxaEmptyTimer[i]);
+ moxaEmptyTimer[i].function = check_xmit_empty;
+ moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i];
+ moxaEmptyTimer_on[i] = 0;
+ }
+
+ init_timer(&moxaTimer);
+ moxaTimer.function = moxa_poll;
+ moxaTimer.expires = jiffies + (HZ / 50);
+ moxaTimer_on = 1;
+ add_timer(&moxaTimer);
+
+ /* Find the boards defined in source code */
+ numBoards = 0;
+ for (i = 0; i < MAX_BOARDS; i++) {
+ if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) ||
+ (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) {
+ moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType;
+ if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
+ moxa_boards[numBoards].numPorts = 8;
+ else
+ moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
+ moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
+ moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
+ if (verbose)
+ printk("Board %2d: %s board(baseAddr=%lx)\n",
+ numBoards + 1,
+ moxa_brdname[moxa_boards[numBoards].boardType - 1],
+ moxa_boards[numBoards].baseAddr);
+ numBoards++;
+ }
+ }
+ /* Find the boards defined form module args. */
+#ifdef MODULE
+ for (i = 0; i < MAX_BOARDS; i++) {
+ if ((type[i] == MOXA_BOARD_C218_ISA) ||
+ (type[i] == MOXA_BOARD_C320_ISA)) {
+ if (verbose)
+ printk("Board %2d: %s board(baseAddr=%lx)\n",
+ numBoards + 1,
+ moxa_brdname[type[i] - 1],
+ (unsigned long) baseaddr[i]);
+ if (numBoards >= MAX_BOARDS) {
+ if (verbose)
+ printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
+ continue;
+ }
+ moxa_boards[numBoards].boardType = type[i];
+ if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
+ moxa_boards[numBoards].numPorts = 8;
+ else
+ moxa_boards[numBoards].numPorts = numports[i];
+ moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
+ moxa_boards[numBoards].baseAddr = baseaddr[i];
+ numBoards++;
+ }
+ }
+#endif
+ /* Find PCI boards here */
+#ifdef CONFIG_PCI
+ if (pci_present()) {
+ struct pci_dev *p = NULL;
+ n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo);
+ i = 0;
+ while (i < n) {
+ while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL)
+ {
+ if (numBoards >= MAX_BOARDS) {
+ if (verbose)
+ printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
+ } else {
+ moxa_get_PCI_conf(p, moxa_pcibrds[i].board_type,
+ &moxa_boards[numBoards]);
+ numBoards++;
+ }
+ }
+ i++;
+ }
+ }
+#endif
+ for (i = 0; i < numBoards; i++) {
+ moxaBaseAddr[i] = (unsigned long) ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000);
+ }
+
+ return (0);
+}
+
+static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
+{
+ unsigned int val;
+
+ board->baseAddr = p->resource[2].start;
+ board->boardType = board_type;
+ switch (board_type) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ board->numPorts = 8;
+ break;
+
+ case MOXA_BOARD_CP204J:
+ board->numPorts = 4;
+ break;
+ default:
+ board->numPorts = 0;
+ break;
+ }
+ board->busType = MOXA_BUS_TYPE_PCI;
+ board->pciInfo.busNum = p->bus->number;
+ board->pciInfo.devNum = p->devfn >> 3;
+
+ return (0);
+}
+
+static void do_moxa_softint(void *private_)
+{
+ struct moxa_str *ch = (struct moxa_str *) private_;
+ struct tty_struct *tty;
+
+ if (!ch || !(tty = ch->tty))
+ return;
+ if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) {
+ tty_hangup(tty);
+ wake_up_interruptible(&ch->open_wait);
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+ }
+}
+
+static int moxa_open(struct tty_struct *tty, struct file *filp)
+{
+ struct moxa_str *ch;
+ int port;
+ int retval;
+ unsigned long page;
+
+ port = PORTNO(tty);
+ if (port == MAX_PORTS) {
+ MOD_INC_USE_COUNT;
+ return (0);
+ }
+ if (!MoxaPortIsValid(port)) {
+ tty->driver_data = NULL;
+ return (-ENODEV);
+ }
+ down(&moxaBuffSem);
+ if (!moxaXmitBuff) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ up(&moxaBuffSem);
+ return (-ENOMEM);
+ }
+ if (moxaXmitBuff)
+ free_page(page);
+ else
+ moxaXmitBuff = (unsigned char *) page;
+ }
+ up(&moxaBuffSem);
+
+ MOD_INC_USE_COUNT;
+ ch = &moxaChannels[port];
+ ch->count++;
+ tty->driver_data = ch;
+ ch->tty = tty;
+ if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = ch->normal_termios;
+ else
+ *tty->termios = ch->callout_termios;
+ }
+ ch->session = current->session;
+ ch->pgrp = current->pgrp;
+ if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
+ ch->statusflags = 0;
+ set_tty_param(tty);
+ MoxaPortLineCtrl(ch->port, 1, 1);
+ MoxaPortEnable(ch->port);
+ ch->asyncflags |= ASYNC_INITIALIZED;
+ }
+ retval = block_till_ready(tty, filp, ch);
+
+ moxa_unthrottle(tty);
+
+ if (ch->type == PORT_16550A) {
+ MoxaSetFifo(ch->port, 1);
+ } else {
+ MoxaSetFifo(ch->port, 0);
+ }
+
+ return (retval);
+}
+
+static void moxa_close(struct tty_struct *tty, struct file *filp)
+{
+ struct moxa_str *ch;
+ int port;
+
+ port = PORTNO(tty);
+ if (port == MAX_PORTS) {
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ if (!MoxaPortIsValid(port)) {
+#ifdef SERIAL_DEBUG_CLOSE
+ printk("Invalid portno in moxa_close\n");
+#endif
+ tty->driver_data = NULL;
+ return;
+ }
+ if (tty->driver_data == NULL) {
+ return;
+ }
+ if (tty_hung_up_p(filp)) {
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ ch = (struct moxa_str *) tty->driver_data;
+
+ if ((tty->count == 1) && (ch->count != 1)) {
+ printk("moxa_close: bad serial port count; tty->count is 1, "
+ "ch->count is %d\n", ch->count);
+ ch->count = 1;
+ }
+ if (--ch->count < 0) {
+ printk("moxa_close: bad serial port count, minor=%d\n",
+ MINOR(tty->device));
+ ch->count = 0;
+ }
+ if (ch->count) {
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ ch->asyncflags |= ASYNC_CLOSING;
+
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ ch->normal_termios = *tty->termios;
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ ch->callout_termios = *tty->termios;
+ if (ch->asyncflags & ASYNC_INITIALIZED) {
+ setup_empty_event(tty);
+ tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
+ moxaEmptyTimer_on[ch->port] = 0;
+ del_timer(&moxaEmptyTimer[ch->port]);
+ }
+ shut_down(ch);
+ MoxaPortFlushData(port, 2);
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ ch->event = 0;
+ ch->tty = 0;
+ if (ch->blocked_open) {
+ if (ch->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(ch->close_delay);
+ }
+ wake_up_interruptible(&ch->open_wait);
+ }
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+ ASYNC_CLOSING);
+ wake_up_interruptible(&ch->close_wait);
+ MOD_DEC_USE_COUNT;
+}
+
+static int moxa_write(struct tty_struct *tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct moxa_str *ch;
+ int len, port;
+ unsigned long flags;
+ unsigned char *temp;
+
+ ch = (struct moxa_str *) tty->driver_data;
+ if (ch == NULL)
+ return (0);
+ port = ch->port;
+ save_flags(flags);
+ cli();
+ if (from_user) {
+ copy_from_user(moxaXmitBuff, buf, count);
+ temp = moxaXmitBuff;
+ } else
+ temp = (unsigned char *) buf;
+ len = MoxaPortWriteData(port, temp, count);
+ restore_flags(flags);
+ /*********************************************
+ if ( !(ch->statusflags & LOWWAIT) &&
+ ((len != count) || (MoxaPortTxFree(port) <= 100)) )
+ ************************************************/
+ ch->statusflags |= LOWWAIT;
+ return (len);
+}
+
+static int moxa_write_room(struct tty_struct *tty)
+{
+ struct moxa_str *ch;
+
+ if (tty->stopped)
+ return (0);
+ ch = (struct moxa_str *) tty->driver_data;
+ if (ch == NULL)
+ return (0);
+ return (MoxaPortTxFree(ch->port));
+}
+
+static void moxa_flush_buffer(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ if (ch == NULL)
+ return;
+ MoxaPortFlushData(ch->port, 1);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+static int moxa_chars_in_buffer(struct tty_struct *tty)
+{
+ int chars;
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ /*
+ * Sigh...I have to check if driver_data is NULL here, because
+ * if an open() fails, the TTY subsystem eventually calls
+ * tty_wait_until_sent(), which calls the driver's chars_in_buffer()
+ * routine. And since the open() failed, we return 0 here. TDJ
+ */
+ if (ch == NULL)
+ return (0);
+ chars = MoxaPortTxQueue(ch->port);
+ if (chars) {
+ /*
+ * Make it possible to wakeup anything waiting for output
+ * in tty_ioctl.c, etc.
+ */
+ if (!(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty);
+ }
+ return (chars);
+}
+
+static void moxa_flush_chars(struct tty_struct *tty)
+{
+ /*
+ * Don't think I need this, because this is called to empty the TX
+ * buffer for the 16450, 16550, etc.
+ */
+}
+
+static void moxa_put_char(struct tty_struct *tty, unsigned char c)
+{
+ struct moxa_str *ch;
+ int port;
+ unsigned long flags;
+
+ ch = (struct moxa_str *) tty->driver_data;
+ if (ch == NULL)
+ return;
+ port = ch->port;
+ save_flags(flags);
+ cli();
+ moxaXmitBuff[0] = c;
+ MoxaPortWriteData(port, moxaXmitBuff, 1);
+ restore_flags(flags);
+ /************************************************
+ if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
+ *************************************************/
+ ch->statusflags |= LOWWAIT;
+}
+
+static int moxa_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ register int port;
+ int retval, dtr, rts;
+ unsigned long flag;
+
+ port = PORTNO(tty);
+ if ((port != MAX_PORTS) && (!ch))
+ return (-EINVAL);
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return (retval);
+ setup_empty_event(tty);
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ MoxaPortSendBreak(ch->port, 0);
+ return (0);
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return (retval);
+ setup_empty_event(tty);
+ tty_wait_until_sent(tty, 0);
+ MoxaPortSendBreak(ch->port, arg);
+ return (0);
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ case TIOCSSOFTCAR:
+ if(get_user(retval, (unsigned long *) arg))
+ return -EFAULT;
+ arg = retval;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ if (C_CLOCAL(tty))
+ ch->asyncflags &= ~ASYNC_CHECK_CD;
+ else
+ ch->asyncflags |= ASYNC_CHECK_CD;
+ return (0);
+ case TIOCMGET:
+ flag = 0;
+ MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ if (dtr)
+ flag |= TIOCM_DTR;
+ if (rts)
+ flag |= TIOCM_RTS;
+ dtr = MoxaPortLineStatus(ch->port);
+ if (dtr & 1)
+ flag |= TIOCM_CTS;
+ if (dtr & 2)
+ flag |= TIOCM_DSR;
+ if (dtr & 4)
+ flag |= TIOCM_CD;
+ return put_user(flag, (unsigned int *) arg);
+ case TIOCMBIS:
+ if(get_user(retval, (unsigned int *) arg))
+ return -EFAULT;
+ MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ if (retval & TIOCM_RTS)
+ rts = 1;
+ if (retval & TIOCM_DTR)
+ dtr = 1;
+ MoxaPortLineCtrl(ch->port, dtr, rts);
+ return (0);
+ case TIOCMBIC:
+ if(get_user(retval, (unsigned int *) arg))
+ return -EFAULT;
+ MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ if (retval & TIOCM_RTS)
+ rts = 0;
+ if (retval & TIOCM_DTR)
+ dtr = 0;
+ MoxaPortLineCtrl(ch->port, dtr, rts);
+ return (0);
+ case TIOCMSET:
+ if(get_user(retval, (unsigned long *) arg))
+ return -EFAULT;
+ dtr = rts = 0;
+ if (retval & TIOCM_RTS)
+ rts = 1;
+ if (retval & TIOCM_DTR)
+ dtr = 1;
+ MoxaPortLineCtrl(ch->port, dtr, rts);
+ return (0);
+ case TIOCGSERIAL:
+ return (moxa_get_serial_info(ch, (struct serial_struct *) arg));
+
+ case TIOCSSERIAL:
+ return (moxa_set_serial_info(ch, (struct serial_struct *) arg));
+ default:
+ retval = MoxaDriverIoctl(cmd, arg, port);
+ }
+ return (retval);
+}
+
+static void moxa_throttle(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ ch->statusflags |= THROTTLE;
+}
+
+static void moxa_unthrottle(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ ch->statusflags &= ~THROTTLE;
+}
+
+static void moxa_set_termios(struct tty_struct *tty,
+ struct termios *old_termios)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ if (ch == NULL)
+ return;
+ set_tty_param(tty);
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&ch->open_wait);
+}
+
+static void moxa_stop(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ if (ch == NULL)
+ return;
+ MoxaPortTxDisable(ch->port);
+ ch->statusflags |= TXSTOPPED;
+}
+
+
+static void moxa_start(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ if (ch == NULL)
+ return;
+
+ if (!(ch->statusflags & TXSTOPPED))
+ return;
+
+ MoxaPortTxEnable(ch->port);
+ ch->statusflags &= ~TXSTOPPED;
+}
+
+static void moxa_hangup(struct tty_struct *tty)
+{
+ struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+
+ moxa_flush_buffer(tty);
+ shut_down(ch);
+ ch->event = 0;
+ ch->count = 0;
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+ ch->tty = 0;
+ wake_up_interruptible(&ch->open_wait);
+}
+
+static void moxa_poll(unsigned long ignored)
+{
+ register int card;
+ struct moxa_str *ch;
+ struct tty_struct *tp;
+ int i, ports;
+
+ moxaTimer_on = 0;
+ del_timer(&moxaTimer);
+
+ if (MoxaDriverPoll() < 0) {
+ moxaTimer.function = moxa_poll;
+ moxaTimer.expires = jiffies + (HZ / 50);
+ moxaTimer_on = 1;
+ add_timer(&moxaTimer);
+ return;
+ }
+ for (card = 0; card < MAX_BOARDS; card++) {
+ if ((ports = MoxaPortsOfCard(card)) <= 0)
+ continue;
+ ch = &moxaChannels[card * MAX_PORTS_PER_BOARD];
+ for (i = 0; i < ports; i++, ch++) {
+ if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
+ continue;
+ if (!(ch->statusflags & THROTTLE) &&
+ (MoxaPortRxQueue(ch->port) > 0))
+ receive_data(ch);
+ if ((tp = ch->tty) == 0)
+ continue;
+ if (ch->statusflags & LOWWAIT) {
+ if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
+ if (!tp->stopped) {
+ ch->statusflags &= ~LOWWAIT;
+ if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tp->ldisc.write_wakeup)
+ (tp->ldisc.write_wakeup) (tp);
+ wake_up_interruptible(&tp->write_wait);
+ }
+ }
+ }
+ if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
+ tty_insert_flip_char(tp, 0, TTY_BREAK);
+ tty_schedule_flip(tp);
+ }
+ if (MoxaPortDCDChange(ch->port)) {
+ if (ch->asyncflags & ASYNC_CHECK_CD) {
+ if (MoxaPortDCDON(ch->port))
+ wake_up_interruptible(&ch->open_wait);
+ else {
+ set_bit(MOXA_EVENT_HANGUP, &ch->event);
+ queue_task(&ch->tqueue, &tq_scheduler);
+ }
+ }
+ }
+ }
+ }
+
+ moxaTimer.function = moxa_poll;
+ moxaTimer.expires = jiffies + (HZ / 50);
+ moxaTimer_on = 1;
+ add_timer(&moxaTimer);
+}
+
+/******************************************************************************/
+
+static void set_tty_param(struct tty_struct *tty)
+{
+ register struct termios *ts;
+ struct moxa_str *ch;
+ int rts, cts, txflow, rxflow, xany;
+
+ ch = (struct moxa_str *) tty->driver_data;
+ ts = tty->termios;
+ if (ts->c_cflag & CLOCAL)
+ ch->asyncflags &= ~ASYNC_CHECK_CD;
+ else
+ ch->asyncflags |= ASYNC_CHECK_CD;
+ rts = cts = txflow = rxflow = xany = 0;
+ if (ts->c_cflag & CRTSCTS)
+ rts = cts = 1;
+ if (ts->c_iflag & IXON)
+ txflow = 1;
+ if (ts->c_iflag & IXOFF)
+ rxflow = 1;
+ if (ts->c_iflag & IXANY)
+ xany = 1;
+ MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
+ MoxaPortSetTermio(ch->port, ts);
+}
+
+static int block_till_ready(struct tty_struct *tty, struct file *filp,
+ struct moxa_str *ch)
+{
+ DECLARE_WAITQUEUE(wait,current);
+ unsigned long flags;
+ int retval;
+ int do_clocal = C_CLOCAL(tty);
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {
+ if (ch->asyncflags & ASYNC_CLOSING)
+ interruptible_sleep_on(&ch->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ return (-EAGAIN);
+ else
+ return (-ERESTARTSYS);
+#else
+ return (-EAGAIN);
+#endif
+ }
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ return (-EBUSY);
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
+ (ch->session != current->session))
+ return (-EBUSY);
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
+ (ch->pgrp != current->pgrp))
+ return (-EBUSY);
+ ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
+ return (0);
+ }
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ return (-EBUSY);
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ return (0);
+ }
+ /*
+ * Block waiting for the carrier detect and the line to become free
+ */
+ retval = 0;
+ add_wait_queue(&ch->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ ch->line, ch->count);
+#endif
+ save_flags(flags);
+ cli();
+ if (!tty_hung_up_p(filp))
+ ch->count--;
+ restore_flags(flags);
+ ch->blocked_open++;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) ||
+ !(ch->asyncflags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
+ MoxaPortDCDON(ch->port)))
+ break;
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&ch->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ ch->count++;
+ ch->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ ch->line, ch->count);
+#endif
+ if (retval)
+ return (retval);
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ return (0);
+}
+
+static void setup_empty_event(struct tty_struct *tty)
+{
+ struct moxa_str *ch = tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ ch->statusflags |= EMPTYWAIT;
+ moxaEmptyTimer_on[ch->port] = 0;
+ del_timer(&moxaEmptyTimer[ch->port]);
+ moxaEmptyTimer[ch->port].expires = jiffies + HZ;
+ moxaEmptyTimer_on[ch->port] = 1;
+ add_timer(&moxaEmptyTimer[ch->port]);
+ restore_flags(flags);
+}
+
+static void check_xmit_empty(unsigned long data)
+{
+ struct moxa_str *ch;
+
+ ch = (struct moxa_str *) data;
+ moxaEmptyTimer_on[ch->port] = 0;
+ del_timer(&moxaEmptyTimer[ch->port]);
+ if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
+ if (MoxaPortTxQueue(ch->port) == 0) {
+ ch->statusflags &= ~EMPTYWAIT;
+ if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ ch->tty->ldisc.write_wakeup)
+ (ch->tty->ldisc.write_wakeup) (ch->tty);
+ wake_up_interruptible(&ch->tty->write_wait);
+ return;
+ }
+ moxaEmptyTimer[ch->port].expires = jiffies + HZ;
+ moxaEmptyTimer_on[ch->port] = 1;
+ add_timer(&moxaEmptyTimer[ch->port]);
+ } else
+ ch->statusflags &= ~EMPTYWAIT;
+}
+
+static void shut_down(struct moxa_str *ch)
+{
+ struct tty_struct *tp;
+
+ if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ return;
+
+ tp = ch->tty;
+
+ MoxaPortDisable(ch->port);
+
+ /*
+ * If we're a modem control device and HUPCL is on, drop RTS & DTR.
+ */
+ if (tp->termios->c_cflag & HUPCL)
+ MoxaPortLineCtrl(ch->port, 0, 0);
+
+ ch->asyncflags &= ~ASYNC_INITIALIZED;
+}
+
+static void receive_data(struct moxa_str *ch)
+{
+ struct tty_struct *tp;
+ struct termios *ts;
+ int i, count, rc, space;
+ unsigned char *charptr, *flagptr;
+ unsigned long flags;
+
+ ts = 0;
+ tp = ch->tty;
+ if (tp)
+ ts = tp->termios;
+ /**************************************************
+ if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
+ *****************************************************/
+ if (!tp || !ts) {
+ MoxaPortFlushData(ch->port, 0);
+ return;
+ }
+ space = TTY_FLIPBUF_SIZE - tp->flip.count;
+ if (space <= 0)
+ return;
+ charptr = tp->flip.char_buf_ptr;
+ flagptr = tp->flip.flag_buf_ptr;
+ rc = tp->flip.count;
+ save_flags(flags);
+ cli();
+ count = MoxaPortReadData(ch->port, charptr, space);
+ restore_flags(flags);
+ for (i = 0; i < count; i++)
+ *flagptr++ = 0;
+ charptr += count;
+ rc += count;
+ tp->flip.count = rc;
+ tp->flip.char_buf_ptr = charptr;
+ tp->flip.flag_buf_ptr = flagptr;
+ tty_schedule_flip(ch->tty);
+}
+
+#define Magic_code 0x404
+
+/*
+ * System Configuration
+ */
+/*
+ * for C218 BIOS initialization
+ */
+#define C218_ConfBase 0x800
+#define C218_status (C218_ConfBase + 0) /* BIOS running status */
+#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
+#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
+#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
+#define C218check_sum (C218_ConfBase + 8) /* BYTE */
+#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
+#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
+#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
+#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
+#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
+
+#define C218_LoadBuf 0x0F00
+#define C218_KeyCode 0x218
+#define CP204J_KeyCode 0x204
+
+/*
+ * for C320 BIOS initialization
+ */
+#define C320_ConfBase 0x800
+#define C320_LoadBuf 0x0f00
+#define STS_init 0x05 /* for C320_status */
+
+#define C320_status C320_ConfBase + 0 /* BIOS running status */
+#define C320_diag C320_ConfBase + 2 /* diagnostic status */
+#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
+#define C320DLoad_len C320_ConfBase + 6 /* WORD */
+#define C320check_sum C320_ConfBase + 8 /* WORD */
+#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
+#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
+#define C320UART_no C320_ConfBase + 0x0e /* WORD */
+
+#define C320_KeyCode 0x320
+
+#define FixPage_addr 0x0000 /* starting addr of static page */
+#define DynPage_addr 0x2000 /* starting addr of dynamic page */
+#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
+#define Control_reg 0x1ff0 /* select page and reset control */
+#define HW_reset 0x80
+
+/*
+ * Function Codes
+ */
+#define FC_CardReset 0x80
+#define FC_ChannelReset 1 /* C320 firmware not supported */
+#define FC_EnableCH 2
+#define FC_DisableCH 3
+#define FC_SetParam 4
+#define FC_SetMode 5
+#define FC_SetRate 6
+#define FC_LineControl 7
+#define FC_LineStatus 8
+#define FC_XmitControl 9
+#define FC_FlushQueue 10
+#define FC_SendBreak 11
+#define FC_StopBreak 12
+#define FC_LoopbackON 13
+#define FC_LoopbackOFF 14
+#define FC_ClrIrqTable 15
+#define FC_SendXon 16
+#define FC_SetTermIrq 17 /* C320 firmware not supported */
+#define FC_SetCntIrq 18 /* C320 firmware not supported */
+#define FC_SetBreakIrq 19
+#define FC_SetLineIrq 20
+#define FC_SetFlowCtl 21
+#define FC_GenIrq 22
+#define FC_InCD180 23
+#define FC_OutCD180 24
+#define FC_InUARTreg 23
+#define FC_OutUARTreg 24
+#define FC_SetXonXoff 25
+#define FC_OutCD180CCR 26
+#define FC_ExtIQueue 27
+#define FC_ExtOQueue 28
+#define FC_ClrLineIrq 29
+#define FC_HWFlowCtl 30
+#define FC_GetClockRate 35
+#define FC_SetBaud 36
+#define FC_SetDataMode 41
+#define FC_GetCCSR 43
+#define FC_GetDataError 45
+#define FC_RxControl 50
+#define FC_ImmSend 51
+#define FC_SetXonState 52
+#define FC_SetXoffState 53
+#define FC_SetRxFIFOTrig 54
+#define FC_SetTxFIFOCnt 55
+#define FC_UnixRate 56
+#define FC_UnixResetTimer 57
+
+#define RxFIFOTrig1 0
+#define RxFIFOTrig4 1
+#define RxFIFOTrig8 2
+#define RxFIFOTrig14 3
+
+/*
+ * Dual-Ported RAM
+ */
+#define DRAM_global 0
+#define INT_data (DRAM_global + 0)
+#define Config_base (DRAM_global + 0x108)
+
+#define IRQindex (INT_data + 0)
+#define IRQpending (INT_data + 4)
+#define IRQtable (INT_data + 8)
+
+/*
+ * Interrupt Status
+ */
+#define IntrRx 0x01 /* receiver data O.K. */
+#define IntrTx 0x02 /* transmit buffer empty */
+#define IntrFunc 0x04 /* function complete */
+#define IntrBreak 0x08 /* received break */
+#define IntrLine 0x10 /* line status change
+ for transmitter */
+#define IntrIntr 0x20 /* received INTR code */
+#define IntrQuit 0x40 /* received QUIT code */
+#define IntrEOF 0x80 /* received EOF code */
+
+#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
+#define IntrTxTrigger 0x200 /* tx data count below trigger value */
+
+#define Magic_no (Config_base + 0)
+#define Card_model_no (Config_base + 2)
+#define Total_ports (Config_base + 4)
+#define Module_cnt (Config_base + 8)
+#define Module_no (Config_base + 10)
+#define Timer_10ms (Config_base + 14)
+#define Disable_IRQ (Config_base + 20)
+#define TMS320_PORT1 (Config_base + 22)
+#define TMS320_PORT2 (Config_base + 24)
+#define TMS320_CLOCK (Config_base + 26)
+
+/*
+ * DATA BUFFER in DRAM
+ */
+#define Extern_table 0x400 /* Base address of the external table
+ (24 words * 64) total 3K bytes
+ (24 words * 128) total 6K bytes */
+#define Extern_size 0x60 /* 96 bytes */
+#define RXrptr 0x00 /* read pointer for RX buffer */
+#define RXwptr 0x02 /* write pointer for RX buffer */
+#define TXrptr 0x04 /* read pointer for TX buffer */
+#define TXwptr 0x06 /* write pointer for TX buffer */
+#define HostStat 0x08 /* IRQ flag and general flag */
+#define FlagStat 0x0A
+#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
+ /* x x x x | | | | */
+ /* | | | + CTS flow */
+ /* | | +--- RTS flow */
+ /* | +------ TX Xon/Xoff */
+ /* +--------- RX Xon/Xoff */
+#define Break_cnt 0x0E /* received break count */
+#define CD180TXirq 0x10 /* if non-0: enable TX irq */
+#define RX_mask 0x12
+#define TX_mask 0x14
+#define Ofs_rxb 0x16
+#define Ofs_txb 0x18
+#define Page_rxb 0x1A
+#define Page_txb 0x1C
+#define EndPage_rxb 0x1E
+#define EndPage_txb 0x20
+#define Data_error 0x22
+#define RxTrigger 0x28
+#define TxTrigger 0x2a
+
+#define rRXwptr 0x34
+#define Low_water 0x36
+
+#define FuncCode 0x40
+#define FuncArg 0x42
+#define FuncArg1 0x44
+
+#define C218rx_size 0x2000 /* 8K bytes */
+#define C218tx_size 0x8000 /* 32K bytes */
+
+#define C218rx_mask (C218rx_size - 1)
+#define C218tx_mask (C218tx_size - 1)
+
+#define C320p8rx_size 0x2000
+#define C320p8tx_size 0x8000
+#define C320p8rx_mask (C320p8rx_size - 1)
+#define C320p8tx_mask (C320p8tx_size - 1)
+
+#define C320p16rx_size 0x2000
+#define C320p16tx_size 0x4000
+#define C320p16rx_mask (C320p16rx_size - 1)
+#define C320p16tx_mask (C320p16tx_size - 1)
+
+#define C320p24rx_size 0x2000
+#define C320p24tx_size 0x2000
+#define C320p24rx_mask (C320p24rx_size - 1)
+#define C320p24tx_mask (C320p24tx_size - 1)
+
+#define C320p32rx_size 0x1000
+#define C320p32tx_size 0x1000
+#define C320p32rx_mask (C320p32rx_size - 1)
+#define C320p32tx_mask (C320p32tx_size - 1)
+
+#define Page_size 0x2000
+#define Page_mask (Page_size - 1)
+#define C218rx_spage 3
+#define C218tx_spage 4
+#define C218rx_pageno 1
+#define C218tx_pageno 4
+#define C218buf_pageno 5
+
+#define C320p8rx_spage 3
+#define C320p8tx_spage 4
+#define C320p8rx_pgno 1
+#define C320p8tx_pgno 4
+#define C320p8buf_pgno 5
+
+#define C320p16rx_spage 3
+#define C320p16tx_spage 4
+#define C320p16rx_pgno 1
+#define C320p16tx_pgno 2
+#define C320p16buf_pgno 3
+
+#define C320p24rx_spage 3
+#define C320p24tx_spage 4
+#define C320p24rx_pgno 1
+#define C320p24tx_pgno 1
+#define C320p24buf_pgno 2
+
+#define C320p32rx_spage 3
+#define C320p32tx_ofs C320p32rx_size
+#define C320p32tx_spage 3
+#define C320p32buf_pgno 1
+
+/*
+ * Host Status
+ */
+#define WakeupRx 0x01
+#define WakeupTx 0x02
+#define WakeupBreak 0x08
+#define WakeupLine 0x10
+#define WakeupIntr 0x20
+#define WakeupQuit 0x40
+#define WakeupEOF 0x80 /* used in VTIME control */
+#define WakeupRxTrigger 0x100
+#define WakeupTxTrigger 0x200
+/*
+ * Flag status
+ */
+#define Rx_over 0x01
+#define Xoff_state 0x02
+#define Tx_flowOff 0x04
+#define Tx_enable 0x08
+#define CTS_state 0x10
+#define DSR_state 0x20
+#define DCD_state 0x80
+/*
+ * FlowControl
+ */
+#define CTS_FlowCtl 1
+#define RTS_FlowCtl 2
+#define Tx_FlowCtl 4
+#define Rx_FlowCtl 8
+#define IXM_IXANY 0x10
+
+#define LowWater 128
+
+#define DTR_ON 1
+#define RTS_ON 2
+#define CTS_ON 1
+#define DSR_ON 2
+#define DCD_ON 8
+
+/* mode definition */
+#define MX_CS8 0x03
+#define MX_CS7 0x02
+#define MX_CS6 0x01
+#define MX_CS5 0x00
+
+#define MX_STOP1 0x00
+#define MX_STOP15 0x04
+#define MX_STOP2 0x08
+
+#define MX_PARNONE 0x00
+#define MX_PAREVEN 0x40
+#define MX_PARODD 0xC0
+
+/*
+ * Query
+ */
+#define QueryPort MAX_PORTS
+
+
+
+struct mon_str {
+ int tick;
+ int rxcnt[MAX_PORTS];
+ int txcnt[MAX_PORTS];
+};
+typedef struct mon_str mon_st;
+
+#define DCD_changed 0x01
+#define DCD_oldstate 0x80
+
+static unsigned char moxaBuff[10240];
+static unsigned long moxaIntNdx[MAX_BOARDS];
+static unsigned long moxaIntPend[MAX_BOARDS];
+static unsigned long moxaIntTable[MAX_BOARDS];
+static char moxaChkPort[MAX_PORTS];
+static char moxaLineCtrl[MAX_PORTS];
+static unsigned long moxaTableAddr[MAX_PORTS];
+static long moxaCurBaud[MAX_PORTS];
+static char moxaDCDState[MAX_PORTS];
+static char moxaLowChkFlag[MAX_PORTS];
+static int moxaLowWaterChk;
+static int moxaCard;
+static mon_st moxaLog;
+static int moxaFuncTout;
+static ushort moxaBreakCnt[MAX_PORTS];
+
+static void moxadelay(int);
+static void moxafunc(unsigned long, int, ushort);
+static void wait_finish(unsigned long);
+static void low_water_check(unsigned long);
+static int moxaloadbios(int, unsigned char *, int);
+static int moxafindcard(int);
+static int moxaload320b(int, unsigned char *, int);
+static int moxaloadcode(int, unsigned char *, int);
+static int moxaloadc218(int, unsigned long, int);
+static int moxaloadc320(int, unsigned long, int, int *);
+
+/*****************************************************************************
+ * Driver level functions: *
+ * 1. MoxaDriverInit(void); *
+ * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); *
+ * 3. MoxaDriverPoll(void); *
+ *****************************************************************************/
+void MoxaDriverInit(void)
+{
+ int i;
+
+ moxaFuncTout = HZ / 2; /* 500 mini-seconds */
+ moxaCard = 0;
+ moxaLog.tick = 0;
+ moxaLowWaterChk = 0;
+ for (i = 0; i < MAX_PORTS; i++) {
+ moxaChkPort[i] = 0;
+ moxaLowChkFlag[i] = 0;
+ moxaLineCtrl[i] = 0;
+ moxaLog.rxcnt[i] = 0;
+ moxaLog.txcnt[i] = 0;
+ }
+}
+
+#define MOXA 0x400
+#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
+#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
+#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */
+#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */
+#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */
+#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */
+#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_IOQUEUE (MOXA + 27)
+#define MOXA_FLUSH_QUEUE (MOXA + 28)
+#define MOXA_GET_CONF (MOXA + 35) /* configuration */
+#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
+#define MOXA_GETMSTATUS (MOXA + 65)
+
+
+struct moxaq_str {
+ int inq;
+ int outq;
+};
+
+struct dl_str {
+ char *buf;
+ int len;
+ int cardno;
+};
+
+static struct moxaq_str temp_queue[MAX_PORTS];
+static struct dl_str dltmp;
+
+void MoxaPortFlushData(int port, int mode)
+{
+ unsigned long ofsAddr;
+ if ((mode < 0) || (mode > 2))
+ return;
+ ofsAddr = moxaTableAddr[port];
+ moxafunc(ofsAddr, FC_FlushQueue, mode);
+ if (mode != 1) {
+ moxaLowChkFlag[port] = 0;
+ low_water_check(ofsAddr);
+ }
+}
+
+int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
+{
+ int i;
+ int status;
+ int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
+
+ if (port == QueryPort) {
+ if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) &&
+ (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) &&
+ (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) &&
+ (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
+ (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
+ return (-EINVAL);
+ }
+ switch (cmd) {
+ case MOXA_GET_CONF:
+ if(copy_to_user((void *)arg, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf)))
+ return -EFAULT;
+ return (0);
+ case MOXA_INIT_DRIVER:
+ if ((int) arg == 0x404)
+ MoxaDriverInit();
+ return (0);
+ case MOXA_GETDATACOUNT:
+ moxaLog.tick = jiffies;
+ if(copy_to_user((void *)arg, &moxaLog, sizeof(mon_st)))
+ return -EFAULT;
+ return (0);
+ case MOXA_FLUSH_QUEUE:
+ MoxaPortFlushData(port, arg);
+ return (0);
+ case MOXA_GET_IOQUEUE:
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (moxaChkPort[i]) {
+ temp_queue[i].inq = MoxaPortRxQueue(i);
+ temp_queue[i].outq = MoxaPortTxQueue(i);
+ }
+ }
+ if(copy_to_user((void *)arg, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS))
+ return -EFAULT;
+ return (0);
+ case MOXA_LOAD_BIOS:
+ if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+ return -EFAULT;
+ i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
+ return (i);
+ case MOXA_FIND_BOARD:
+ if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+ return -EFAULT;
+ return moxafindcard(dltmp.cardno);
+ case MOXA_LOAD_C320B:
+ if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+ return -EFAULT;
+ moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
+ return (0);
+ case MOXA_LOAD_CODE:
+ if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+ return -EFAULT;
+ i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
+ if (i == -1)
+ return (-EFAULT);
+ return (i);
+ case MOXA_GET_OQUEUE:
+ i = MoxaPortTxQueue(port);
+ return put_user(i, (unsigned long *) arg);
+ case MOXA_GET_IQUEUE:
+ i = MoxaPortRxQueue(port);
+ return put_user(i, (unsigned long *) arg);
+ case MOXA_GET_MAJOR:
+ if(copy_to_user((void *)arg, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case MOXA_GET_CUMAJOR:
+ if(copy_to_user((void *)arg, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case MOXA_GETMSTATUS:
+ for (i = 0; i < MAX_PORTS; i++) {
+ GMStatus[i].ri = 0;
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ if (!moxaChkPort[i]) {
+ continue;
+ } else {
+ status = MoxaPortLineStatus(moxaChannels[i].port);
+ if (status & 1)
+ GMStatus[i].cts = 1;
+ if (status & 2)
+ GMStatus[i].dsr = 1;
+ if (status & 4)
+ GMStatus[i].dcd = 1;
+ }
+
+ if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios)
+ GMStatus[i].cflag = moxaChannels[i].normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag;
+ }
+ if(copy_to_user((void *)arg, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS))
+ return -EFAULT;
+ return 0;
+
+ }
+ return (-ENOIOCTLCMD);
+}
+
+int MoxaDriverPoll(void)
+{
+ register ushort temp;
+ register int card;
+ unsigned long ip, ofsAddr;
+ int port, p, ports;
+
+ if (moxaCard == 0)
+ return (-1);
+ for (card = 0; card < MAX_BOARDS; card++) {
+ if ((ports = moxa_boards[card].numPorts) == 0)
+ continue;
+ if (readb(moxaIntPend[card]) == 0xff) {
+ ip = moxaIntTable[card] + readb(moxaIntNdx[card]);
+ p = card * MAX_PORTS_PER_BOARD;
+ ports <<= 1;
+ for (port = 0; port < ports; port += 2, p++) {
+ if ((temp = readw(ip + port)) != 0) {
+ writew(0, ip + port);
+ ofsAddr = moxaTableAddr[p];
+ if (temp & IntrTx)
+ writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
+ if (temp & IntrBreak) {
+ moxaBreakCnt[p]++;
+ }
+ if (temp & IntrLine) {
+ if (readb(ofsAddr + FlagStat) & DCD_state) {
+ if ((moxaDCDState[p] & DCD_oldstate) == 0)
+ moxaDCDState[p] = (DCD_oldstate |
+ DCD_changed);
+ } else {
+ if (moxaDCDState[p] & DCD_oldstate)
+ moxaDCDState[p] = DCD_changed;
+ }
+ }
+ }
+ }
+ writeb(0, moxaIntPend[card]);
+ }
+ if (moxaLowWaterChk) {
+ p = card * MAX_PORTS_PER_BOARD;
+ for (port = 0; port < ports; port++, p++) {
+ if (moxaLowChkFlag[p]) {
+ moxaLowChkFlag[p] = 0;
+ ofsAddr = moxaTableAddr[p];
+ low_water_check(ofsAddr);
+ }
+ }
+ }
+ }
+ moxaLowWaterChk = 0;
+ return (0);
+}
+
+/*****************************************************************************
+ * Card level function: *
+ * 1. MoxaPortsOfCard(int cardno); *
+ *****************************************************************************/
+int MoxaPortsOfCard(int cardno)
+{
+
+ if (moxa_boards[cardno].boardType == 0)
+ return (0);
+ return (moxa_boards[cardno].numPorts);
+}
+
+/*****************************************************************************
+ * Port level functions: *
+ * 1. MoxaPortIsValid(int port); *
+ * 2. MoxaPortEnable(int port); *
+ * 3. MoxaPortDisable(int port); *
+ * 4. MoxaPortGetMaxBaud(int port); *
+ * 5. MoxaPortGetCurBaud(int port); *
+ * 6. MoxaPortSetBaud(int port, long baud); *
+ * 7. MoxaPortSetMode(int port, int databit, int stopbit, int parity); *
+ * 8. MoxaPortSetTermio(int port, unsigned char *termio); *
+ * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); *
+ * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); *
+ * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); *
+ * 12. MoxaPortLineStatus(int port); *
+ * 13. MoxaPortDCDChange(int port); *
+ * 14. MoxaPortDCDON(int port); *
+ * 15. MoxaPortFlushData(int port, int mode); *
+ * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
+ * 17. MoxaPortReadData(int port, unsigned char * buffer, int length); *
+ * 18. MoxaPortTxBufSize(int port); *
+ * 19. MoxaPortRxBufSize(int port); *
+ * 20. MoxaPortTxQueue(int port); *
+ * 21. MoxaPortTxFree(int port); *
+ * 22. MoxaPortRxQueue(int port); *
+ * 23. MoxaPortRxFree(int port); *
+ * 24. MoxaPortTxDisable(int port); *
+ * 25. MoxaPortTxEnable(int port); *
+ * 26. MoxaPortGetBrkCnt(int port); *
+ * 27. MoxaPortResetBrkCnt(int port); *
+ * 28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); *
+ * 29. MoxaPortIsTxHold(int port); *
+ * 30. MoxaPortSendBreak(int port, int ticks); *
+ *****************************************************************************/
+/*
+ * Moxa Port Number Description:
+ *
+ * MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
+ * the port number using in MOXA driver functions will be 0 to 31 for
+ * first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
+ * to 127 for fourth. For example, if you setup three MOXA boards,
+ * first board is C218, second board is C320-16 and third board is
+ * C320-32. The port number of first board (C218 - 8 ports) is from
+ * 0 to 7. The port number of second board (C320 - 16 ports) is form
+ * 32 to 47. The port number of third board (C320 - 32 ports) is from
+ * 64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
+ * 127 will be invalid.
+ *
+ *
+ * Moxa Functions Description:
+ *
+ * Function 1: Driver initialization routine, this routine must be
+ * called when initialized driver.
+ * Syntax:
+ * void MoxaDriverInit();
+ *
+ *
+ * Function 2: Moxa driver private IOCTL command processing.
+ * Syntax:
+ * int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
+ *
+ * unsigned int cmd : IOCTL command
+ * unsigned long arg : IOCTL argument
+ * int port : port number (0 - 127)
+ *
+ * return: 0 (OK)
+ * -EINVAL
+ * -ENOIOCTLCMD
+ *
+ *
+ * Function 3: Moxa driver polling process routine.
+ * Syntax:
+ * int MoxaDriverPoll(void);
+ *
+ * return: 0 ; polling O.K.
+ * -1 : no any Moxa card.
+ *
+ *
+ * Function 4: Get the ports of this card.
+ * Syntax:
+ * int MoxaPortsOfCard(int cardno);
+ *
+ * int cardno : card number (0 - 3)
+ *
+ * return: 0 : this card is invalid
+ * 8/16/24/32
+ *
+ *
+ * Function 5: Check this port is valid or invalid
+ * Syntax:
+ * int MoxaPortIsValid(int port);
+ * int port : port number (0 - 127, ref port description)
+ *
+ * return: 0 : this port is invalid
+ * 1 : this port is valid
+ *
+ *
+ * Function 6: Enable this port to start Tx/Rx data.
+ * Syntax:
+ * void MoxaPortEnable(int port);
+ * int port : port number (0 - 127)
+ *
+ *
+ * Function 7: Disable this port
+ * Syntax:
+ * void MoxaPortDisable(int port);
+ * int port : port number (0 - 127)
+ *
+ *
+ * Function 8: Get the maximun available baud rate of this port.
+ * Syntax:
+ * long MoxaPortGetMaxBaud(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 : this port is invalid
+ * 38400/57600/115200 bps
+ *
+ *
+ * Function 9: Get the current baud rate of this port.
+ * Syntax:
+ * long MoxaPortGetCurBaud(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 : this port is invalid
+ * 50 - 115200 bps
+ *
+ *
+ * Function 10: Setting baud rate of this port.
+ * Syntax:
+ * long MoxaPortSetBaud(int port, long baud);
+ * int port : port number (0 - 127)
+ * long baud : baud rate (50 - 115200)
+ *
+ * return: 0 : this port is invalid or baud < 50
+ * 50 - 115200 : the real baud rate set to the port, if
+ * the argument baud is large than maximun
+ * available baud rate, the real setting
+ * baud rate will be the maximun baud rate.
+ *
+ *
+ * Function 11: Setting the data-bits/stop-bits/parity of this port
+ * Syntax:
+ * int MoxaPortSetMode(int port, int databits, int stopbits, int parity);
+ * int port : port number (0 - 127)
+ * int databits : data bits (8/7/6/5)
+ * int stopbits : stop bits (2/1/0, 0 show 1.5 stop bits)
+ int parity : parity (0:None,1:Odd,2:Even,3:Mark,4:Space)
+ *
+ * return: -1 : invalid parameter
+ * 0 : setting O.K.
+ *
+ *
+ * Function 12: Configure the port.
+ * Syntax:
+ * int MoxaPortSetTermio(int port, struct termios *termio);
+ * int port : port number (0 - 127)
+ * struct termios * termio : termio structure pointer
+ *
+ * return: -1 : this port is invalid or termio == NULL
+ * 0 : setting O.K.
+ *
+ *
+ * Function 13: Get the DTR/RTS state of this port.
+ * Syntax:
+ * int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
+ * int port : port number (0 - 127)
+ * int * dtrState : pointer to INT to receive the current DTR
+ * state. (if NULL, this function will not
+ * write to this address)
+ * int * rtsState : pointer to INT to receive the current RTS
+ * state. (if NULL, this function will not
+ * write to this address)
+ *
+ * return: -1 : this port is invalid
+ * 0 : O.K.
+ *
+ *
+ * Function 14: Setting the DTR/RTS output state of this port.
+ * Syntax:
+ * void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
+ * int port : port number (0 - 127)
+ * int dtrState : DTR output state (0: off, 1: on)
+ * int rtsState : RTS output state (0: off, 1: on)
+ *
+ *
+ * Function 15: Setting the flow control of this port.
+ * Syntax:
+ * void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
+ * int txFlow,int xany);
+ * int port : port number (0 - 127)
+ * int rtsFlow : H/W RTS flow control (0: no, 1: yes)
+ * int ctsFlow : H/W CTS flow control (0: no, 1: yes)
+ * int rxFlow : S/W Rx XON/XOFF flow control (0: no, 1: yes)
+ * int txFlow : S/W Tx XON/XOFF flow control (0: no, 1: yes)
+ * int xany : S/W XANY flow control (0: no, 1: yes)
+ *
+ *
+ * Function 16: Get ths line status of this port
+ * Syntax:
+ * int MoxaPortLineStatus(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: Bit 0 - CTS state (0: off, 1: on)
+ * Bit 1 - DSR state (0: off, 1: on)
+ * Bit 2 - DCD state (0: off, 1: on)
+ *
+ *
+ * Function 17: Check the DCD state has changed since the last read
+ * of this function.
+ * Syntax:
+ * int MoxaPortDCDChange(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 : no changed
+ * 1 : DCD has changed
+ *
+ *
+ * Function 18: Check ths current DCD state is ON or not.
+ * Syntax:
+ * int MoxaPortDCDON(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 : DCD off
+ * 1 : DCD on
+ *
+ *
+ * Function 19: Flush the Rx/Tx buffer data of this port.
+ * Syntax:
+ * void MoxaPortFlushData(int port, int mode);
+ * int port : port number (0 - 127)
+ * int mode
+ * 0 : flush the Rx buffer
+ * 1 : flush the Tx buffer
+ * 2 : flush the Rx and Tx buffer
+ *
+ *
+ * Function 20: Write data.
+ * Syntax:
+ * int MoxaPortWriteData(int port, unsigned char * buffer, int length);
+ * int port : port number (0 - 127)
+ * unsigned char * buffer : pointer to write data buffer.
+ * int length : write data length
+ *
+ * return: 0 - length : real write data length
+ *
+ *
+ * Function 21: Read data.
+ * Syntax:
+ * int MoxaPortReadData(int port, unsigned char * buffer, int length);
+ * int port : port number (0 - 127)
+ * unsigned char * buffer : pointer to read data buffer.
+ * int length : read data buffer length
+ *
+ * return: 0 - length : real read data length
+ *
+ *
+ * Function 22: Get the Tx buffer size of this port
+ * Syntax:
+ * int MoxaPortTxBufSize(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Tx buffer size
+ *
+ *
+ * Function 23: Get the Rx buffer size of this port
+ * Syntax:
+ * int MoxaPortRxBufSize(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Rx buffer size
+ *
+ *
+ * Function 24: Get the Tx buffer current queued data bytes
+ * Syntax:
+ * int MoxaPortTxQueue(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Tx buffer current queued data bytes
+ *
+ *
+ * Function 25: Get the Tx buffer current free space
+ * Syntax:
+ * int MoxaPortTxFree(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Tx buffer current free space
+ *
+ *
+ * Function 26: Get the Rx buffer current queued data bytes
+ * Syntax:
+ * int MoxaPortRxQueue(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Rx buffer current queued data bytes
+ *
+ *
+ * Function 27: Get the Rx buffer current free space
+ * Syntax:
+ * int MoxaPortRxFree(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: .. : Rx buffer current free space
+ *
+ *
+ * Function 28: Disable port data transmission.
+ * Syntax:
+ * void MoxaPortTxDisable(int port);
+ * int port : port number (0 - 127)
+ *
+ *
+ * Function 29: Enable port data transmission.
+ * Syntax:
+ * void MoxaPortTxEnable(int port);
+ * int port : port number (0 - 127)
+ *
+ *
+ * Function 30: Get the received BREAK signal count.
+ * Syntax:
+ * int MoxaPortGetBrkCnt(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 - .. : BREAK signal count
+ *
+ *
+ * Function 31: Get the received BREAK signal count and reset it.
+ * Syntax:
+ * int MoxaPortResetBrkCnt(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 - .. : BREAK signal count
+ *
+ *
+ * Function 32: Set the S/W flow control new XON/XOFF value, default
+ * XON is 0x11 & XOFF is 0x13.
+ * Syntax:
+ * void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue);
+ * int port : port number (0 - 127)
+ * int xonValue : new XON value (0 - 255)
+ * int xoffValue : new XOFF value (0 - 255)
+ *
+ *
+ * Function 33: Check this port's transmission is hold by remote site
+ * because the flow control.
+ * Syntax:
+ * int MoxaPortIsTxHold(int port);
+ * int port : port number (0 - 127)
+ *
+ * return: 0 : normal
+ * 1 : hold by remote site
+ *
+ *
+ * Function 34: Send out a BREAK signal.
+ * Syntax:
+ * void MoxaPortSendBreak(int port, int ms100);
+ * int port : port number (0 - 127)
+ * int ms100 : break signal time interval.
+ * unit: 100 mini-second. if ms100 == 0, it will
+ * send out a about 250 ms BREAK signal.
+ *
+ */
+int MoxaPortIsValid(int port)
+{
+
+ if (moxaCard == 0)
+ return (0);
+ if (moxaChkPort[port] == 0)
+ return (0);
+ return (1);
+}
+
+void MoxaPortEnable(int port)
+{
+ unsigned long ofsAddr;
+ int MoxaPortLineStatus(int);
+ short lowwater = 512;
+
+ ofsAddr = moxaTableAddr[port];
+ writew(lowwater, ofsAddr + Low_water);
+ moxaBreakCnt[port] = 0;
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ moxafunc(ofsAddr, FC_SetBreakIrq, 0);
+ } else {
+ writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
+ }
+
+ moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
+ moxafunc(ofsAddr, FC_FlushQueue, 2);
+
+ moxafunc(ofsAddr, FC_EnableCH, Magic_code);
+ MoxaPortLineStatus(port);
+}
+
+void MoxaPortDisable(int port)
+{
+ unsigned long ofsAddr;
+
+ ofsAddr = moxaTableAddr[port];
+ moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
+ moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
+ writew(0, ofsAddr + HostStat);
+ moxafunc(ofsAddr, FC_DisableCH, Magic_code);
+}
+
+long MoxaPortGetMaxBaud(int port)
+{
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI))
+ return (460800L);
+ else
+ return (921600L);
+}
+
+
+long MoxaPortSetBaud(int port, long baud)
+{
+ unsigned long ofsAddr;
+ long max, clock;
+ unsigned int val;
+
+ if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
+ return (0);
+ ofsAddr = moxaTableAddr[port];
+ if (baud > max)
+ baud = max;
+ if (max == 38400L)
+ clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */
+ else if (max == 57600L)
+ clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */
+ else
+ clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */
+ val = clock / baud;
+ moxafunc(ofsAddr, FC_SetBaud, val);
+ baud = clock / val;
+ moxaCurBaud[port] = baud;
+ return (baud);
+}
+
+int MoxaPortSetTermio(int port, struct termios *termio)
+{
+ unsigned long ofsAddr;
+ tcflag_t cflag;
+ long baud;
+ tcflag_t mode = 0;
+
+ if (moxaChkPort[port] == 0 || termio == 0)
+ return (-1);
+ ofsAddr = moxaTableAddr[port];
+ cflag = termio->c_cflag; /* termio->c_cflag */
+
+ mode = termio->c_cflag & CSIZE;
+ if (mode == CS5)
+ mode = MX_CS5;
+ else if (mode == CS6)
+ mode = MX_CS6;
+ else if (mode == CS7)
+ mode = MX_CS7;
+ else if (mode == CS8)
+ mode = MX_CS8;
+
+ if (termio->c_cflag & CSTOPB) {
+ if (mode == MX_CS5)
+ mode |= MX_STOP15;
+ else
+ mode |= MX_STOP2;
+ } else
+ mode |= MX_STOP1;
+
+ if (termio->c_cflag & PARENB) {
+ if (termio->c_cflag & PARODD)
+ mode |= MX_PARODD;
+ else
+ mode |= MX_PAREVEN;
+ } else
+ mode |= MX_PARNONE;
+
+ moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+
+ cflag &= (CBAUD | CBAUDEX);
+#ifndef B921600
+#define B921600 (B460800+1)
+#endif
+ switch (cflag) {
+ case B921600:
+ baud = 921600L;
+ break;
+ case B460800:
+ baud = 460800L;
+ break;
+ case B230400:
+ baud = 230400L;
+ break;
+ case B115200:
+ baud = 115200L;
+ break;
+ case B57600:
+ baud = 57600L;
+ break;
+ case B38400:
+ baud = 38400L;
+ break;
+ case B19200:
+ baud = 19200L;
+ break;
+ case B9600:
+ baud = 9600L;
+ break;
+ case B4800:
+ baud = 4800L;
+ break;
+ case B2400:
+ baud = 2400L;
+ break;
+ case B1800:
+ baud = 1800L;
+ break;
+ case B1200:
+ baud = 1200L;
+ break;
+ case B600:
+ baud = 600L;
+ break;
+ case B300:
+ baud = 300L;
+ break;
+ case B200:
+ baud = 200L;
+ break;
+ case B150:
+ baud = 150L;
+ break;
+ case B134:
+ baud = 134L;
+ break;
+ case B110:
+ baud = 110L;
+ break;
+ case B75:
+ baud = 75L;
+ break;
+ case B50:
+ baud = 50L;
+ break;
+ default:
+ baud = 0;
+ }
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ if (baud == 921600L)
+ return (-1);
+ }
+ MoxaPortSetBaud(port, baud);
+
+ if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
+ writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
+ writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
+ writeb(FC_SetXonXoff, ofsAddr + FuncCode);
+ wait_finish(ofsAddr);
+
+ }
+ return (0);
+}
+
+int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
+{
+
+ if (!MoxaPortIsValid(port))
+ return (-1);
+ if (dtrState) {
+ if (moxaLineCtrl[port] & DTR_ON)
+ *dtrState = 1;
+ else
+ *dtrState = 0;
+ }
+ if (rtsState) {
+ if (moxaLineCtrl[port] & RTS_ON)
+ *rtsState = 1;
+ else
+ *rtsState = 0;
+ }
+ return (0);
+}
+
+void MoxaPortLineCtrl(int port, int dtr, int rts)
+{
+ unsigned long ofsAddr;
+ int mode;
+
+ ofsAddr = moxaTableAddr[port];
+ mode = 0;
+ if (dtr)
+ mode |= DTR_ON;
+ if (rts)
+ mode |= RTS_ON;
+ moxaLineCtrl[port] = mode;
+ moxafunc(ofsAddr, FC_LineControl, mode);
+}
+
+void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
+{
+ unsigned long ofsAddr;
+ int mode;
+
+ ofsAddr = moxaTableAddr[port];
+ mode = 0;
+ if (rts)
+ mode |= RTS_FlowCtl;
+ if (cts)
+ mode |= CTS_FlowCtl;
+ if (txflow)
+ mode |= Tx_FlowCtl;
+ if (rxflow)
+ mode |= Rx_FlowCtl;
+ if (txany)
+ mode |= IXM_IXANY;
+ moxafunc(ofsAddr, FC_SetFlowCtl, mode);
+}
+
+int MoxaPortLineStatus(int port)
+{
+ unsigned long ofsAddr;
+ int val;
+
+ ofsAddr = moxaTableAddr[port];
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ moxafunc(ofsAddr, FC_LineStatus, 0);
+ val = readw(ofsAddr + FuncArg);
+ } else {
+ val = readw(ofsAddr + FlagStat) >> 4;
+ }
+ val &= 0x0B;
+ if (val & 8) {
+ val |= 4;
+ if ((moxaDCDState[port] & DCD_oldstate) == 0)
+ moxaDCDState[port] = (DCD_oldstate | DCD_changed);
+ } else {
+ if (moxaDCDState[port] & DCD_oldstate)
+ moxaDCDState[port] = DCD_changed;
+ }
+ val &= 7;
+ return (val);
+}
+
+int MoxaPortDCDChange(int port)
+{
+ int n;
+
+ if (moxaChkPort[port] == 0)
+ return (0);
+ n = moxaDCDState[port];
+ moxaDCDState[port] &= ~DCD_changed;
+ n &= DCD_changed;
+ return (n);
+}
+
+int MoxaPortDCDON(int port)
+{
+ int n;
+
+ if (moxaChkPort[port] == 0)
+ return (0);
+ if (moxaDCDState[port] & DCD_oldstate)
+ n = 1;
+ else
+ n = 0;
+ return (n);
+}
+
+
+/*
+ int MoxaDumpMem(int port, unsigned char * buffer, int len)
+ {
+ int i;
+ unsigned long baseAddr,ofsAddr,ofs;
+
+ baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+ ofs = baseAddr + DynPage_addr + pageofs;
+ if (len > 0x2000L)
+ len = 0x2000L;
+ for (i = 0; i < len; i++)
+ buffer[i] = readb(ofs+i);
+ }
+ */
+
+
+int MoxaPortWriteData(int port, unsigned char * buffer, int len)
+{
+ int c, total, i;
+ ushort tail;
+ int cnt;
+ ushort head, tx_mask, spage, epage;
+ ushort pageno, pageofs, bufhead;
+ unsigned long baseAddr, ofsAddr, ofs;
+
+ ofsAddr = moxaTableAddr[port];
+ baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+ tx_mask = readw(ofsAddr + TX_mask);
+ spage = readw(ofsAddr + Page_txb);
+ epage = readw(ofsAddr + EndPage_txb);
+ tail = readw(ofsAddr + TXwptr);
+ head = readw(ofsAddr + TXrptr);
+ c = (head > tail) ? (head - tail - 1)
+ : (head - tail + tx_mask);
+ if (c > len)
+ c = len;
+ moxaLog.txcnt[port] += c;
+ total = c;
+ if (spage == epage) {
+ bufhead = readw(ofsAddr + Ofs_txb);
+ writew(spage, baseAddr + Control_reg);
+ while (c > 0) {
+ if (head > tail)
+ len = head - tail - 1;
+ else
+ len = tx_mask + 1 - tail;
+ len = (c > len) ? len : c;
+ ofs = baseAddr + DynPage_addr + bufhead + tail;
+ for (i = 0; i < len; i++)
+ writeb(*buffer++, ofs + i);
+ tail = (tail + len) & tx_mask;
+ c -= len;
+ }
+ writew(tail, ofsAddr + TXwptr);
+ } else {
+ len = c;
+ pageno = spage + (tail >> 13);
+ pageofs = tail & Page_mask;
+ do {
+ cnt = Page_size - pageofs;
+ if (cnt > c)
+ cnt = c;
+ c -= cnt;
+ writeb(pageno, baseAddr + Control_reg);
+ ofs = baseAddr + DynPage_addr + pageofs;
+ for (i = 0; i < cnt; i++)
+ writeb(*buffer++, ofs + i);
+ if (c == 0) {
+ writew((tail + len) & tx_mask, ofsAddr + TXwptr);
+ break;
+ }
+ if (++pageno == epage)
+ pageno = spage;
+ pageofs = 0;
+ } while (1);
+ }
+ writeb(1, ofsAddr + CD180TXirq); /* start to send */
+ return (total);
+}
+
+int MoxaPortReadData(int port, unsigned char * buffer, int space)
+{
+ register ushort head, pageofs;
+ int i, count, cnt, len, total, remain;
+ ushort tail, rx_mask, spage, epage;
+ ushort pageno, bufhead;
+ unsigned long baseAddr, ofsAddr, ofs;
+
+ ofsAddr = moxaTableAddr[port];
+ baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+ head = readw(ofsAddr + RXrptr);
+ tail = readw(ofsAddr + RXwptr);
+ rx_mask = readw(ofsAddr + RX_mask);
+ spage = readw(ofsAddr + Page_rxb);
+ epage = readw(ofsAddr + EndPage_rxb);
+ count = (tail >= head) ? (tail - head)
+ : (tail - head + rx_mask + 1);
+ if (count == 0)
+ return (0);
+
+ total = (space > count) ? count : space;
+ remain = count - total;
+ moxaLog.rxcnt[port] += total;
+ count = total;
+ if (spage == epage) {
+ bufhead = readw(ofsAddr + Ofs_rxb);
+ writew(spage, baseAddr + Control_reg);
+ while (count > 0) {
+ if (tail >= head)
+ len = tail - head;
+ else
+ len = rx_mask + 1 - head;
+ len = (count > len) ? len : count;
+ ofs = baseAddr + DynPage_addr + bufhead + head;
+ for (i = 0; i < len; i++)
+ *buffer++ = readb(ofs + i);
+ head = (head + len) & rx_mask;
+ count -= len;
+ }
+ writew(head, ofsAddr + RXrptr);
+ } else {
+ len = count;
+ pageno = spage + (head >> 13);
+ pageofs = head & Page_mask;
+ do {
+ cnt = Page_size - pageofs;
+ if (cnt > count)
+ cnt = count;
+ count -= cnt;
+ writew(pageno, baseAddr + Control_reg);
+ ofs = baseAddr + DynPage_addr + pageofs;
+ for (i = 0; i < cnt; i++)
+ *buffer++ = readb(ofs + i);
+ if (count == 0) {
+ writew((head + len) & rx_mask, ofsAddr + RXrptr);
+ break;
+ }
+ if (++pageno == epage)
+ pageno = spage;
+ pageofs = 0;
+ } while (1);
+ }
+ if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
+ moxaLowWaterChk = 1;
+ moxaLowChkFlag[port] = 1;
+ }
+ return (total);
+}
+
+
+int MoxaPortTxQueue(int port)
+{
+ unsigned long ofsAddr;
+ ushort rptr, wptr, mask;
+ int len;
+
+ ofsAddr = moxaTableAddr[port];
+ rptr = readw(ofsAddr + TXrptr);
+ wptr = readw(ofsAddr + TXwptr);
+ mask = readw(ofsAddr + TX_mask);
+ len = (wptr - rptr) & mask;
+ return (len);
+}
+
+int MoxaPortTxFree(int port)
+{
+ unsigned long ofsAddr;
+ ushort rptr, wptr, mask;
+ int len;
+
+ ofsAddr = moxaTableAddr[port];
+ rptr = readw(ofsAddr + TXrptr);
+ wptr = readw(ofsAddr + TXwptr);
+ mask = readw(ofsAddr + TX_mask);
+ len = mask - ((wptr - rptr) & mask);
+ return (len);
+}
+
+int MoxaPortRxQueue(int port)
+{
+ unsigned long ofsAddr;
+ ushort rptr, wptr, mask;
+ int len;
+
+ ofsAddr = moxaTableAddr[port];
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = (wptr - rptr) & mask;
+ return (len);
+}
+
+
+void MoxaPortTxDisable(int port)
+{
+ unsigned long ofsAddr;
+
+ ofsAddr = moxaTableAddr[port];
+ moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
+}
+
+void MoxaPortTxEnable(int port)
+{
+ unsigned long ofsAddr;
+
+ ofsAddr = moxaTableAddr[port];
+ moxafunc(ofsAddr, FC_SetXonState, Magic_code);
+}
+
+
+int MoxaPortResetBrkCnt(int port)
+{
+ ushort cnt;
+ cnt = moxaBreakCnt[port];
+ moxaBreakCnt[port] = 0;
+ return (cnt);
+}
+
+
+void MoxaPortSendBreak(int port, int ms100)
+{
+ unsigned long ofsAddr;
+
+ ofsAddr = moxaTableAddr[port];
+ if (ms100) {
+ moxafunc(ofsAddr, FC_SendBreak, Magic_code);
+ moxadelay(ms100 * (HZ / 10));
+ } else {
+ moxafunc(ofsAddr, FC_SendBreak, Magic_code);
+ moxadelay(HZ / 4); /* 250 ms */
+ }
+ moxafunc(ofsAddr, FC_StopBreak, Magic_code);
+}
+
+static int moxa_get_serial_info(struct moxa_str *info,
+ struct serial_struct *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return (-EFAULT);
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->port;
+ tmp.port = 0;
+ tmp.irq = 0;
+ tmp.flags = info->asyncflags;
+ tmp.baud_base = 921600;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = 0;
+ tmp.hub6 = 0;
+ if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return (0);
+}
+
+
+static int moxa_set_serial_info(struct moxa_str *info,
+ struct serial_struct *new_info)
+{
+ struct serial_struct new_serial;
+
+ if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+
+ if ((new_serial.irq != 0) ||
+ (new_serial.port != 0) ||
+// (new_serial.type != info->type) ||
+ (new_serial.custom_divisor != 0) ||
+ (new_serial.baud_base != 921600))
+ return (-EPERM);
+
+ if (!suser()) {
+ if (((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (info->asyncflags & ~ASYNC_USR_MASK)))
+ return (-EPERM);
+ } else {
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ }
+
+ new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
+ new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
+
+ if (new_serial.type == PORT_16550A) {
+ MoxaSetFifo(info->port, 1);
+ } else {
+ MoxaSetFifo(info->port, 0);
+ }
+
+ info->type = new_serial.type;
+ return (0);
+}
+
+
+
+/*****************************************************************************
+ * Static local functions: *
+ *****************************************************************************/
+/*
+ * moxadelay - delays a specified number ticks
+ */
+static void moxadelay(int tick)
+{
+ unsigned long st, et;
+
+ st = jiffies;
+ et = st + tick;
+ while (jiffies < et);
+}
+
+static void moxafunc(unsigned long ofsAddr, int cmd, ushort arg)
+{
+
+ writew(arg, ofsAddr + FuncArg);
+ writew(cmd, ofsAddr + FuncCode);
+ wait_finish(ofsAddr);
+}
+
+static void wait_finish(unsigned long ofsAddr)
+{
+ unsigned long i, j;
+
+ i = jiffies;
+ while (readw(ofsAddr + FuncCode) != 0) {
+ j = jiffies;
+ if ((j - i) > moxaFuncTout) {
+ return;
+ }
+ }
+}
+
+static void low_water_check(unsigned long ofsAddr)
+{
+ int len;
+ ushort rptr, wptr, mask;
+
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = (wptr - rptr) & mask;
+ if (len <= Low_water)
+ moxafunc(ofsAddr, FC_SendXon, 0);
+ }
+}
+
+static int moxaloadbios(int cardno, unsigned char *tmp, int len)
+{
+ unsigned long baseAddr;
+ int i;
+
+ if(copy_from_user(moxaBuff, tmp, len))
+ return -EFAULT;
+ baseAddr = moxaBaseAddr[cardno];
+ writeb(HW_reset, baseAddr + Control_reg); /* reset */
+ moxadelay(1); /* delay 10 ms */
+ for (i = 0; i < 4096; i++)
+ writeb(0, baseAddr + i); /* clear fix page */
+ for (i = 0; i < len; i++)
+ writeb(moxaBuff[i], baseAddr + i); /* download BIOS */
+ writeb(0, baseAddr + Control_reg); /* restart */
+ return (0);
+}
+
+static int moxafindcard(int cardno)
+{
+ unsigned long baseAddr;
+ ushort tmp;
+
+ baseAddr = moxaBaseAddr[cardno];
+ switch (moxa_boards[cardno].boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) {
+ return (-1);
+ }
+ break;
+ case MOXA_BOARD_CP204J:
+ if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) {
+ return (-1);
+ }
+ break;
+ default:
+ if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) {
+ return (-1);
+ }
+ if ((tmp = readw(baseAddr + C320_status)) != STS_init) {
+ return (-2);
+ }
+ }
+ return (0);
+}
+
+static int moxaload320b(int cardno, unsigned char * tmp, int len)
+{
+ unsigned long baseAddr;
+ int i;
+
+ if(copy_from_user(moxaBuff, tmp, len))
+ return -EFAULT;
+ baseAddr = moxaBaseAddr[cardno];
+ writew(len - 7168 - 2, baseAddr + C320bapi_len);
+ writeb(1, baseAddr + Control_reg); /* Select Page 1 */
+ for (i = 0; i < 7168; i++)
+ writeb(moxaBuff[i], baseAddr + DynPage_addr + i);
+ writeb(2, baseAddr + Control_reg); /* Select Page 2 */
+ for (i = 0; i < (len - 7168); i++)
+ writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i);
+ return (0);
+}
+
+static int moxaloadcode(int cardno, unsigned char * tmp, int len)
+{
+ unsigned long baseAddr, ofsAddr;
+ int retval, port, i;
+
+ if(copy_from_user(moxaBuff, tmp, len))
+ return -EFAULT;
+ baseAddr = moxaBaseAddr[cardno];
+ switch (moxa_boards[cardno].boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ case MOXA_BOARD_CP204J:
+ retval = moxaloadc218(cardno, baseAddr, len);
+ if (retval)
+ return (retval);
+ port = cardno * MAX_PORTS_PER_BOARD;
+ for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
+ moxaChkPort[port] = 1;
+ moxaCurBaud[port] = 9600L;
+ moxaDCDState[port] = 0;
+ moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
+ ofsAddr = moxaTableAddr[port];
+ writew(C218rx_mask, ofsAddr + RX_mask);
+ writew(C218tx_mask, ofsAddr + TX_mask);
+ writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
+
+ writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
+
+ }
+ break;
+ default:
+ retval = moxaloadc320(cardno, baseAddr, len,
+ &moxa_boards[cardno].numPorts);
+ if (retval)
+ return (retval);
+ port = cardno * MAX_PORTS_PER_BOARD;
+ for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
+ moxaChkPort[port] = 1;
+ moxaCurBaud[port] = 9600L;
+ moxaDCDState[port] = 0;
+ moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
+ ofsAddr = moxaTableAddr[port];
+ if (moxa_boards[cardno].numPorts == 8) {
+ writew(C320p8rx_mask, ofsAddr + RX_mask);
+ writew(C320p8tx_mask, ofsAddr + TX_mask);
+ writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
+
+ } else if (moxa_boards[cardno].numPorts == 16) {
+ writew(C320p16rx_mask, ofsAddr + RX_mask);
+ writew(C320p16tx_mask, ofsAddr + TX_mask);
+ writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
+
+ } else if (moxa_boards[cardno].numPorts == 24) {
+ writew(C320p24rx_mask, ofsAddr + RX_mask);
+ writew(C320p24tx_mask, ofsAddr + TX_mask);
+ writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ } else if (moxa_boards[cardno].numPorts == 32) {
+ writew(C320p32rx_mask, ofsAddr + RX_mask);
+ writew(C320p32tx_mask, ofsAddr + TX_mask);
+ writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
+ writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
+ writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
+ writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ }
+ }
+ break;
+ }
+ return (0);
+}
+
+static int moxaloadc218(int cardno, unsigned long baseAddr, int len)
+{
+ char retry;
+ int i, j, len1, len2;
+ ushort usum, *ptr, keycode;
+
+ if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J)
+ keycode = CP204J_KeyCode;
+ else
+ keycode = C218_KeyCode;
+ usum = 0;
+ len1 = len >> 1;
+ ptr = (ushort *) moxaBuff;
+ for (i = 0; i < len1; i++)
+ usum += *(ptr + i);
+ retry = 0;
+ do {
+ len1 = len >> 1;
+ j = 0;
+ while (len1) {
+ len2 = (len1 > 2048) ? 2048 : len1;
+ len1 -= len2;
+ for (i = 0; i < len2 << 1; i++)
+ writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i);
+ j += i;
+
+ writew(len2, baseAddr + C218DLoad_len);
+ writew(0, baseAddr + C218_key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + C218_key) == keycode)
+ break;
+ moxadelay(1); /* delay 10 ms */
+ }
+ if (readw(baseAddr + C218_key) != keycode) {
+ return (-1);
+ }
+ }
+ writew(0, baseAddr + C218DLoad_len);
+ writew(usum, baseAddr + C218check_sum);
+ writew(0, baseAddr + C218_key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + C218_key) == keycode)
+ break;
+ moxadelay(1); /* delay 10 ms */
+ }
+ retry++;
+ } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
+ if (readb(baseAddr + C218chksum_ok) != 1) {
+ return (-1);
+ }
+ writew(0, baseAddr + C218_key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ moxadelay(1); /* delay 10 ms */
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code) {
+ return (-1);
+ }
+ writew(1, baseAddr + Disable_IRQ);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ moxadelay(1); /* delay 10 ms */
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code) {
+ return (-1);
+ }
+ moxaCard = 1;
+ moxaIntNdx[cardno] = baseAddr + IRQindex;
+ moxaIntPend[cardno] = baseAddr + IRQpending;
+ moxaIntTable[cardno] = baseAddr + IRQtable;
+ return (0);
+}
+
+static int moxaloadc320(int cardno, unsigned long baseAddr, int len, int *numPorts)
+{
+ ushort usum;
+ int i, j, wlen, len2, retry;
+ ushort *uptr;
+
+ usum = 0;
+ wlen = len >> 1;
+ uptr = (ushort *) moxaBuff;
+ for (i = 0; i < wlen; i++)
+ usum += uptr[i];
+ retry = 0;
+ j = 0;
+ do {
+ while (wlen) {
+ if (wlen > 2048)
+ len2 = 2048;
+ else
+ len2 = wlen;
+ wlen -= len2;
+ len2 <<= 1;
+ for (i = 0; i < len2; i++)
+ writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i);
+ len2 >>= 1;
+ j += i;
+ writew(len2, baseAddr + C320DLoad_len);
+ writew(0, baseAddr + C320_key);
+ for (i = 0; i < 10; i++) {
+ if (readw(baseAddr + C320_key) == C320_KeyCode)
+ break;
+ moxadelay(1);
+ }
+ if (readw(baseAddr + C320_key) != C320_KeyCode)
+ return (-1);
+ }
+ writew(0, baseAddr + C320DLoad_len);
+ writew(usum, baseAddr + C320check_sum);
+ writew(0, baseAddr + C320_key);
+ for (i = 0; i < 10; i++) {
+ if (readw(baseAddr + C320_key) == C320_KeyCode)
+ break;
+ moxadelay(1);
+ }
+ retry++;
+ } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
+ if (readb(baseAddr + C320chksum_ok) != 1)
+ return (-1);
+ writew(0, baseAddr + C320_key);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ moxadelay(1);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return (-100);
+
+ if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
+ } else {
+ writew(0x3200, baseAddr + TMS320_PORT1);
+ writew(0x3400, baseAddr + TMS320_PORT2);
+ writew(19999, baseAddr + TMS320_CLOCK);
+ }
+ writew(1, baseAddr + Disable_IRQ);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 500; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ moxadelay(1);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return (-102);
+
+ j = readw(baseAddr + Module_cnt);
+ if (j <= 0)
+ return (-101);
+ *numPorts = j * 8;
+ writew(j, baseAddr + Module_no);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ moxadelay(1);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return (-102);
+ moxaCard = 1;
+ moxaIntNdx[cardno] = baseAddr + IRQindex;
+ moxaIntPend[cardno] = baseAddr + IRQpending;
+ moxaIntTable[cardno] = baseAddr + IRQtable;
+ return (0);
+}
+
+long MoxaPortGetCurBaud(int port)
+{
+
+ if (moxaChkPort[port] == 0)
+ return (0);
+ return (moxaCurBaud[port]);
+}
+
+static void MoxaSetFifo(int port, int enable)
+{
+ unsigned long ofsAddr = moxaTableAddr[port];
+
+ if (!enable) {
+ moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
+ moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
+ } else {
+ moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
+ moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
+ }
+}
+
+#if 0
+int MoxaPortSetMode(int port, int databits, int stopbits, int parity)
+{
+ unsigned long ofsAddr;
+ int val;
+
+ val = 0;
+ switch (databits) {
+ case 5:
+ val |= 0;
+ break;
+ case 6:
+ val |= 1;
+ break;
+ case 7:
+ val |= 2;
+ break;
+ case 8:
+ val |= 3;
+ break;
+ default:
+ return (-1);
+ }
+ switch (stopbits) {
+ case 0:
+ val |= 0;
+ break; /* stop bits 1.5 */
+ case 1:
+ val |= 0;
+ break;
+ case 2:
+ val |= 4;
+ break;
+ default:
+ return (-1);
+ }
+ switch (parity) {
+ case 0:
+ val |= 0x00;
+ break; /* None */
+ case 1:
+ val |= 0x08;
+ break; /* Odd */
+ case 2:
+ val |= 0x18;
+ break; /* Even */
+ case 3:
+ val |= 0x28;
+ break; /* Mark */
+ case 4:
+ val |= 0x38;
+ break; /* Space */
+ default:
+ return (-1);
+ }
+ ofsAddr = moxaTableAddr[port];
+ moxafunc(ofsAddr, FC_SetMode, val);
+ return (0);
+}
+
+int MoxaPortTxBufSize(int port)
+{
+ unsigned long ofsAddr;
+ int size;
+
+ ofsAddr = moxaTableAddr[port];
+ size = readw(ofsAddr + TX_mask);
+ return (size);
+}
+
+int MoxaPortRxBufSize(int port)
+{
+ unsigned long ofsAddr;
+ int size;
+
+ ofsAddr = moxaTableAddr[port];
+ size = readw(ofsAddr + RX_mask);
+ return (size);
+}
+
+int MoxaPortRxFree(int port)
+{
+ unsigned long ofsAddr;
+ ushort rptr, wptr, mask;
+ int len;
+
+ ofsAddr = moxaTableAddr[port];
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = mask - ((wptr - rptr) & mask);
+ return (len);
+}
+int MoxaPortGetBrkCnt(int port)
+{
+ return (moxaBreakCnt[port]);
+}
+
+void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue)
+{
+ unsigned long ofsAddr;
+
+ ofsAddr = moxaTableAddr[port];
+ writew(xonValue, ofsAddr + FuncArg);
+ writew(xoffValue, ofsAddr + FuncArg1);
+ writew(FC_SetXonXoff, ofsAddr + FuncCode);
+ wait_finish(ofsAddr);
+}
+
+int MoxaPortIsTxHold(int port)
+{
+ unsigned long ofsAddr;
+ int val;
+
+ ofsAddr = moxaTableAddr[port];
+ if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
+ (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ moxafunc(ofsAddr, FC_GetCCSR, 0);
+ val = readw(ofsAddr + FuncArg);
+ if (val & 0x04)
+ return (1);
+ } else {
+ if (readw(ofsAddr + FlagStat) & Tx_flowOff)
+ return (1);
+ }
+ return (0);
+}
+#endif
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index 48709907c..7541cc054 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -6,7 +6,8 @@
* what works and what doesn't:
*
* AM-Mono
- * probably doesn't (untested)
+ * Support for Hauppauge cards added (decoding handled by tuner) added by
+ * Frederic Crozat <fcrozat@mail.dotcom.fr>
*
* FM-Mono
* should work. The stereo modes are backward compatible to FM-mono,
@@ -19,7 +20,7 @@
* should work, no autodetect (i.e. default is mono, but you can
* switch to stereo -- untested)
*
- * NICAM (B/G, used in UK, Scandinavia and Spain)
+ * NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
* should work, with autodetect. Support for NICAM was added by
* Pekka Pietikainen <pp@netppl.fi>
*
@@ -49,15 +50,13 @@
#include <asm/pgtable.h>
#include <linux/smp_lock.h>
#endif
-
/* kernel_thread */
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include "audiochip.h"
-
-#define WAIT_QUEUE wait_queue_head_t
+#define WAIT_QUEUE wait_queue_head_t
/* sound mixer stuff */
#include <linux/config.h>
@@ -278,7 +277,7 @@ static struct MSP_INIT_DATA_DEM {
/* NICAM/AM -- L (6.5/5.85) */
{ { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 },
MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0140, 0x0120, 0x7000},
+ 0x00c6, 0x0140, 0x0120, 0x7c03},
};
struct CARRIER_DETECT {
@@ -302,7 +301,7 @@ static struct CARRIER_DETECT carrier_detect_55[] = {
static struct CARRIER_DETECT carrier_detect_65[] = {
/* PAL SAT / SECAM */
- { MSP_CARRIER(5.85), "5.85 PAL D/K NICAM" },
+ { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" },
{ MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" },
{ MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" },
{ MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" },
@@ -409,7 +408,7 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
if (msp->nicam) {
/* nicam prescale */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x3000);
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
}
}
@@ -475,10 +474,22 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode)
case VIDEO_SOUND_STEREO:
src = 0x0020 | nicam;
#if 0
+ /* spatial effect */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000);
#endif
break;
case VIDEO_SOUND_MONO:
+ if (msp->mode == MSP_MODE_AM_NICAM) {
+ printk("msp3400: switching to AM mono\n");
+ /* AM mono decoding is handled by tuner, not MSP chip */
+ /* so let's redirect sound from tuner via SCART */
+ /* volume prescale for SCART */
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
+ /* SCART switching control register*/
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900);
+ src = 0x0200;
+ break;
+ }
case VIDEO_SOUND_LANG1:
src = 0x0000 | nicam;
break;
@@ -551,7 +562,7 @@ autodetect_stereo(struct i2c_client *client)
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
if (val > 32768)
val -= 65536;
- dprintk("msp3400: stereo detect register: %d\n",val);
+ dprintk("msp34xx: stereo detect register: %d\n",val);
if (val > 4096) {
newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO;
@@ -566,7 +577,7 @@ autodetect_stereo(struct i2c_client *client)
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
- dprintk("msp3400: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
+ dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
if (val & 1) {
/* nicam synced */
@@ -592,30 +603,33 @@ autodetect_stereo(struct i2c_client *client)
}
newnicam=1;
} else {
- newnicam=0;
-#if 0 /* fixme: quick & dirty for testing */
- if (msp->main == MSP_CARRIER(6.5)) {
- /* This is a french mono channel => AM */
- printk("msp3400: switching to AM mono\n");
- msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
- msp->second = msp->main;
- msp3400c_setmode(msp, MSP_MODE_AM_DETECT);
- msp3400c_setcarrier(client, msp->second, msp->main);
- }
-#endif
+ newnicam = 0;
newstereo = VIDEO_SOUND_MONO;
}
break;
+ case MSP_MODE_BTSC:
+ val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
+ dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+ val,
+ (val & 0x0002) ? "no" : "yes",
+ (val & 0x0004) ? "no" : "yes",
+ (val & 0x0040) ? "stereo" : "mono",
+ (val & 0x0080) ? ", nicam 2nd mono" : "",
+ (val & 0x0100) ? ", bilingual/SAP" : "");
+ newstereo = VIDEO_SOUND_MONO;
+ if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO;
+ if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1;
+ break;
}
if (newstereo != msp->stereo) {
update = 1;
- dprintk("msp3400: watch: stereo %d => %d\n",
+ dprintk("msp34xx: watch: stereo %d => %d\n",
msp->stereo,newstereo);
msp->stereo = newstereo;
}
if (newnicam != msp->nicam_on) {
update = 1;
- dprintk("msp3400: watch: nicam %d => %d\n",
+ dprintk("msp34xx: watch: nicam %d => %d\n",
msp->nicam_on,newnicam);
msp->nicam_on = newnicam;
}
@@ -706,8 +720,15 @@ static int msp3400c_thread(void *data)
msp->active = 0;
continue;
}
-
+
+ /* some time for the tuner to sync */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ if (signal_pending(current))
+ goto done;
+
restart:
+ msp->restart = 0;
msp3400c_setvolume(client, 0, 0);
msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
val1 = val2 = 0;
@@ -717,6 +738,14 @@ static int msp3400c_thread(void *data)
/* carrier detect pass #1 -- main carrier */
cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+
+ if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
+ /* autodetect doesn't work well with AM ... */
+ max1 = 3;
+ count = 0;
+ dprintk("msp3400: AM sound override\n");
+ }
+
for (this = 0; this < count; this++) {
msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -724,23 +753,15 @@ static int msp3400c_thread(void *data)
schedule_timeout(HZ/25);
if (signal_pending(current))
goto done;
- if (msp->restart) {
+ if (msp->restart)
msp->restart = 0;
- goto restart;
- }
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
if (val1 < val)
val1 = val, max1 = this;
dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
}
-
- if (amsound) {
- /* autodetect does'nt work well with AM ... */
- max1 = 3;
- dprintk("msp3400: AM sound override\n");
- }
-
+
/* carrier detect pass #2 -- second (stereo) carrier */
switch (max1) {
case 1: /* 5.5 */
@@ -755,6 +776,11 @@ static int msp3400c_thread(void *data)
cd = NULL; count = 0;
break;
}
+
+ if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
+ /* autodetect doesn't work well with AM ... */
+ cd = NULL; count = 0; max2 = 0;
+ }
for (this = 0; this < count; this++) {
msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -762,10 +788,8 @@ static int msp3400c_thread(void *data)
schedule_timeout(HZ/25);
if (signal_pending(current))
goto done;
- if (msp->restart) {
- msp->restart = 0;
+ if (msp->restart)
goto restart;
- }
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
if (val2 < val)
@@ -811,12 +835,13 @@ static int msp3400c_thread(void *data)
msp->nicam_on = 0;
msp3400c_setstereo(client, VIDEO_SOUND_MONO);
msp->watch_stereo = 1;
- } else if (max2 == 0 && msp->nicam &&
+ } else if (max2 == 0 &&
msp->norm == VIDEO_MODE_SECAM) {
- /* L NICAM */
+ /* L NICAM or AM-mono */
msp->second = carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_AM_NICAM);
- msp->nicam_on = 1;
+ msp->nicam_on = 0;
+ msp3400c_setstereo(client, VIDEO_SOUND_MONO);
msp3400c_setcarrier(client, msp->second, msp->main);
msp->watch_stereo = 1;
} else if (max2 == 0 && msp->nicam) {
@@ -942,24 +967,19 @@ static int msp3410d_thread(void *data)
msp->active = 1;
if (msp->watch_stereo) {
-#if 1 /* dump status register */
- val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
- printk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
- val,
- (val & 0x0002) ? "no" : "yes",
- (val & 0x0004) ? "no" : "yes",
- (val & 0x0040) ? "stereo" : "mono",
- (val & 0x0080) ? ", nicam 2nd mono" : "",
- (val & 0x0100) ? ", bilingual/SAP" : "");
- msp->watch_stereo = 0;
-#else
- watch_stereo(msp);
-#endif
+ watch_stereo(client);
msp->active = 0;
continue;
}
+ /* some time for the tuner to sync */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ if (signal_pending(current))
+ goto done;
+
restart:
+ msp->restart = 0;
del_timer(&msp->wake_stereo);
msp->watch_stereo = 0;
@@ -977,6 +997,9 @@ static int msp3410d_thread(void *data)
std = 0x0020;
break;
case VIDEO_MODE_SECAM:
+ mode = 0x0003;
+ std = 1;
+ break;
default:
mode = 0x0003;
std = 1;
@@ -1005,10 +1028,8 @@ static int msp3410d_thread(void *data)
schedule_timeout(HZ/10);
if (signal_pending(current))
goto done;
- if (msp->restart) {
- msp->restart = 0;
+ if (msp->restart)
goto restart;
- }
/* check results */
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
@@ -1027,11 +1048,21 @@ static int msp3410d_thread(void *data)
msp->main = modelist[i].main;
msp->second = modelist[i].second;
+ if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
+ /* autodetection has failed, let backup */
+ dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n",
+ modelist[8].name ? modelist[8].name : "unknown",val);
+ val = 0x0009;
+ msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
+ }
+
/* set prescale / stereo */
switch (val) {
- case 0x0009:
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x7c03); /* AM */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */
+ case 0x0009:
+ msp->mode = MSP_MODE_AM_NICAM;
+ msp->stereo = VIDEO_SOUND_MONO;
+ msp3400c_setstereo(client,VIDEO_SOUND_MONO);
+ msp->watch_stereo = 1;
break;
case 0x0020: /* BTSC */
/* just turn on stereo */
@@ -1479,12 +1510,8 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
va->bass = msp->bass;
va->treble = msp->treble;
- if (msp->simple) {
- /* fixme */
- } else {
- autodetect_stereo(client);
- va->mode = msp->stereo;
- }
+ autodetect_stereo(client);
+ va->mode = msp->stereo;
break;
}
case VIDIOCSAUDIO:
@@ -1501,9 +1528,7 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
msp3400c_setbass(client,msp->bass);
msp3400c_settreble(client,msp->treble);
- if (msp->simple) {
- /* fixme */
- } else if (va->mode != 0) {
+ if (va->mode != 0) {
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
msp->stereo = va->mode;
@@ -1584,17 +1609,11 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
msp3400c_settreble(client,msp->treble);
break;
- case AUDC_GET_STEREO:
- if (msp->simple) {
- *sarg = 0; /* fixme */
- } else {
- autodetect_stereo(client);
- *sarg = msp->stereo;
- }
+ case AUDC_GET_STEREO:
+ autodetect_stereo(client);
+ *sarg = msp->stereo;
break;
case AUDC_SET_STEREO:
- if (msp->simple)
- break; /* fixme */
if (*sarg) {
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
@@ -1642,4 +1661,3 @@ void cleanup_module(void)
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
new file mode 100644
index 000000000..176ebe8d8
--- /dev/null
+++ b/drivers/char/mxser.c
@@ -0,0 +1,2451 @@
+/*****************************************************************************/
+/*
+ * mxser.c -- MOXA Smartio family multiport serial driver.
+ *
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ *
+ * This code is loosely based on the Linux serial driver, written by
+ * Linus Torvalds, Theodore T'so and others.
+ *
+ * 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.
+ */
+
+/*
+ * MOXA Smartio Family Serial Driver
+ *
+ * Copyright (C) 1999,2000 Moxa Technologies Co., LTD.
+ *
+ * for : LINUX 2.0.X, 2.2.X
+ * date : 1999/07/22
+ * version : 1.1
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#define MXSER_VERSION "1.1kern"
+
+#define MXSERMAJOR 174
+#define MXSERCUMAJOR 175
+
+
+#define MXSER_EVENT_TXLOW 1
+#define MXSER_EVENT_HANGUP 2
+
+
+#define SERIAL_DO_RESTART
+
+#define MXSER_BOARDS 4 /* Max. boards */
+#define MXSER_PORTS 32 /* Max. ports */
+#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
+#define MXSER_ISR_PASS_LIMIT 256
+
+#define MXSER_ERR_IOADDR -1
+#define MXSER_ERR_IRQ -2
+#define MXSER_ERR_IRQ_CONFLIT -3
+#define MXSER_ERR_VECTOR -4
+
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+#define WAKEUP_CHARS 256
+
+#define UART_MCR_AFE 0x20
+#define UART_LSR_SPECIAL 0x1E
+
+#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start)
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Define the Moxa PCI vendor and device IDs.
+ */
+
+#ifndef PCI_VENDOR_ID_MOXA
+#define PCI_VENDOR_ID_MOXA 0x1393
+#endif
+#ifndef PCI_DEVICE_ID_C168
+#define PCI_DEVICE_ID_C168 0x1680
+#endif
+#ifndef PCI_DEVICE_ID_C104
+#define PCI_DEVICE_ID_C104 0x1040
+#endif
+
+#define C168_ASIC_ID 1
+#define C104_ASIC_ID 2
+#define CI104J_ASIC_ID 5
+
+enum {
+ MXSER_BOARD_C168_ISA = 1,
+ MXSER_BOARD_C104_ISA,
+ MXSER_BOARD_CI104J,
+ MXSER_BOARD_C168_PCI,
+ MXSER_BOARD_C104_PCI,
+};
+
+static char *mxser_brdname[] =
+{
+ "C168 series",
+ "C104 series",
+ "CI-104J series",
+ "C168H/PCI series",
+ "C104H/PCI series",
+};
+
+static int mxser_numports[] =
+{
+ 8,
+ 4,
+ 4,
+ 8,
+ 4,
+};
+
+/*
+ * MOXA ioctls
+ */
+#define MOXA 0x400
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_CONF (MOXA + 35)
+#define MOXA_DIAGNOSE (MOXA + 50)
+#define MOXA_CHKPORTENABLE (MOXA + 60)
+#define MOXA_HighSpeedOn (MOXA + 61)
+#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
+#define MOXA_GETMSTATUS (MOXA + 65)
+
+typedef struct {
+ unsigned short vendor_id;
+ unsigned short device_id;
+ unsigned short board_type;
+} mxser_pciinfo;
+
+static mxser_pciinfo mxser_pcibrds[] =
+{
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, MXSER_BOARD_C168_PCI},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, MXSER_BOARD_C104_PCI},
+};
+
+typedef struct _moxa_pci_info {
+ unsigned short busNum;
+ unsigned short devNum;
+} moxa_pci_info;
+
+static int ioaddr[MXSER_BOARDS] = {0, 0, 0, 0};
+static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+static int verbose = 0;
+
+/* Variables for insmod */
+
+MODULE_AUTHOR("William Chen");
+MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver");
+MODULE_PARM(ioaddr, "1-4i");
+MODULE_PARM(ttymajor, "i");
+MODULE_PARM(calloutmajor, "i");
+MODULE_PARM(verbose, "i");
+
+struct mxser_hwconf {
+ int board_type;
+ int ports;
+ int irq;
+ int vector;
+ int vector_mask;
+ int uart_type;
+ int ioaddr[MXSER_PORTS_PER_BOARD];
+ int baud_base[MXSER_PORTS_PER_BOARD];
+ moxa_pci_info pciInfo;
+};
+
+struct mxser_struct {
+ int port;
+ int base; /* port base address */
+ int irq; /* port using irq no. */
+ int vector; /* port irq vector */
+ int vectormask; /* port vector mask */
+ int rx_trigger; /* Rx fifo trigger level */
+ int baud_base; /* max. speed */
+ int flags; /* defined in tty.h */
+ int type; /* UART type */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+ unsigned long event;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ wait_queue_head_t delta_msr_wait;
+ struct async_icount icount; /* kernel counters for the 4 input interrupts */
+};
+
+struct mxser_log {
+ int tick;
+ int rxcnt[MXSER_PORTS];
+ int txcnt[MXSER_PORTS];
+};
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MXSER_PORTS];
+
+static int mxserBoardCAP[MXSER_BOARDS] =
+{
+ 0, 0, 0, 0
+ /* 0x180, 0x280, 0x200, 0x320 */
+};
+
+
+static struct tty_driver mxvar_sdriver, mxvar_cdriver;
+static int mxvar_refcount;
+static struct mxser_struct mxvar_table[MXSER_PORTS];
+static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
+static struct termios *mxvar_termios[MXSER_PORTS + 1];
+static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
+static struct mxser_log mxvar_log;
+static int mxvar_diagflag;
+/*
+ * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need
+ * to lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *mxvar_tmp_buf = 0;
+static struct semaphore mxvar_tmp_buf_sem;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int mxvar_baud_table[] =
+{
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 0};
+
+struct mxser_hwconf mxsercfg[MXSER_BOARDS];
+
+/*
+ * static functions:
+ */
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
+int mxser_init(void);
+static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
+static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
+static void mxser_do_softint(void *);
+static int mxser_open(struct tty_struct *, struct file *);
+static void mxser_close(struct tty_struct *, struct file *);
+static int mxser_write(struct tty_struct *, int, const unsigned char *, int);
+static int mxser_write_room(struct tty_struct *);
+static void mxser_flush_buffer(struct tty_struct *);
+static int mxser_chars_in_buffer(struct tty_struct *);
+static void mxser_flush_chars(struct tty_struct *);
+static void mxser_put_char(struct tty_struct *, unsigned char);
+static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
+static int mxser_ioctl_special(unsigned int, unsigned long);
+static void mxser_throttle(struct tty_struct *);
+static void mxser_unthrottle(struct tty_struct *);
+static void mxser_set_termios(struct tty_struct *, struct termios *);
+static void mxser_stop(struct tty_struct *);
+static void mxser_start(struct tty_struct *);
+static void mxser_hangup(struct tty_struct *);
+static void mxser_interrupt(int, void *, struct pt_regs *);
+static inline void mxser_receive_chars(struct mxser_struct *, int *);
+static inline void mxser_transmit_chars(struct mxser_struct *);
+static inline void mxser_check_modem_status(struct mxser_struct *, int);
+static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
+static int mxser_startup(struct mxser_struct *);
+static void mxser_shutdown(struct mxser_struct *);
+static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
+static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);
+static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
+static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
+static void mxser_send_break(struct mxser_struct *, int);
+static int mxser_get_modem_info(struct mxser_struct *, unsigned int *);
+static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);
+
+/*
+ * The MOXA C168/C104 serial driver boot-time initialization code!
+ */
+
+
+#ifdef MODULE
+int init_module(void)
+{
+ int ret;
+
+ if (verbose)
+ printk("Loading module mxser ...\n");
+ ret = mxser_init();
+ if (verbose)
+ printk("Done.\n");
+ return (ret);
+}
+
+void cleanup_module(void)
+{
+ int i, err = 0;
+
+
+ if (verbose)
+ printk("Unloading module mxser ...\n");
+ if ((err |= tty_unregister_driver(&mxvar_cdriver)))
+ printk("Couldn't unregister MOXA Smartio family callout driver\n");
+ if ((err |= tty_unregister_driver(&mxvar_sdriver)))
+ printk("Couldn't unregister MOXA Smartio family serial driver\n");
+
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (mxsercfg[i].board_type == -1)
+ continue;
+ else {
+ free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+ }
+ }
+
+ if (verbose)
+ printk("Done.\n");
+
+}
+#endif
+
+
+int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
+{
+ struct mxser_struct *info;
+ unsigned long flags;
+ int retval;
+ int i, n;
+
+ init_MUTEX(&mxvar_tmp_buf_sem);
+
+ n = board * MXSER_PORTS_PER_BOARD;
+ info = &mxvar_table[n];
+ for (i = 0; i < hwconf->ports; i++, n++, info++) {
+ if (verbose) {
+ printk(" ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]);
+ if (hwconf->baud_base[i] == 115200)
+ printk(" max. baud rate up to 115200 bps.\n");
+ else
+ printk(" max. baud rate up to 921600 bps.\n");
+ }
+ info->port = n;
+ info->base = hwconf->ioaddr[i];
+ info->irq = hwconf->irq;
+ info->vector = hwconf->vector;
+ info->vectormask = hwconf->vector_mask;
+ info->rx_trigger = 14;
+ info->baud_base = hwconf->baud_base[i];
+ info->flags = ASYNC_SHARE_IRQ;
+ info->type = hwconf->uart_type;
+ if ((info->type == PORT_16450) || (info->type == PORT_8250))
+ info->xmit_fifo_size = 1;
+ else
+ info->xmit_fifo_size = 16;
+ info->custom_divisor = hwconf->baud_base[i] * 16;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = 30 * HZ;
+ info->tqueue.routine = mxser_do_softint;
+ info->tqueue.data = info;
+ info->callout_termios = mxvar_cdriver.init_termios;
+ info->normal_termios = mxvar_sdriver.init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ }
+
+ /*
+ * Allocate the IRQ if necessary
+ */
+ save_flags(flags);
+
+ n = board * MXSER_PORTS_PER_BOARD;
+ info = &mxvar_table[n];
+
+ cli();
+ retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+ "mxser", info);
+ if (retval) {
+ restore_flags(flags);
+ printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
+ printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+ return (retval);
+ }
+ restore_flags(flags);
+
+ return 0;
+}
+
+
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
+{
+ mxsercfg[board] = *hwconf;
+}
+
+static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
+{
+ int i;
+ unsigned int val, ioaddress;
+
+ hwconf->board_type = board_type;
+ hwconf->ports = mxser_numports[board_type - 1];
+ pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_2, &val);
+ if (val == 0xffffffff)
+ return (MXSER_ERR_IOADDR);
+ else
+ ioaddress = val & 0xffffffc;
+ for (i = 0; i < hwconf->ports; i++)
+ hwconf->ioaddr[i] = ioaddress + 8 * i;
+
+ pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_3, &val);
+ if (val == 0xffffffff)
+ return (MXSER_ERR_VECTOR);
+ else
+ ioaddress = val & 0xffffffc;
+ hwconf->vector = ioaddress;
+
+ pcibios_read_config_dword(busnum, devnum, PCI_INTERRUPT_LINE, &val);
+ if (val == 0xffffffff)
+ return (MXSER_ERR_IRQ);
+ else
+ hwconf->irq = val & 0xff;
+
+ hwconf->uart_type = PORT_16550A;
+ hwconf->vector_mask = 0;
+ for (i = 0; i < hwconf->ports; i++) {
+ hwconf->vector_mask |= (1 << i);
+ hwconf->baud_base[i] = 921600;
+ }
+ return (0);
+}
+
+int mxser_init(void)
+{
+ int i, m, retval, b;
+ int n, index;
+ int ret1, ret2;
+ unsigned char busnum, devnum;
+ struct mxser_hwconf hwconf;
+
+ printk("MOXA Smartio family driver version %s\n", MXSER_VERSION);
+
+ /* Initialize the tty_driver structure */
+
+ memset(&mxvar_sdriver, 0, sizeof(struct tty_driver));
+ mxvar_sdriver.magic = TTY_DRIVER_MAGIC;
+ mxvar_sdriver.name = "ttyM";
+ mxvar_sdriver.major = ttymajor;
+ mxvar_sdriver.minor_start = 0;
+ mxvar_sdriver.num = MXSER_PORTS + 1;
+ mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL;
+ mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL;
+ mxvar_sdriver.init_termios = tty_std_termios;
+ mxvar_sdriver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW;
+ mxvar_sdriver.refcount = &mxvar_refcount;
+ mxvar_sdriver.table = mxvar_tty;
+ mxvar_sdriver.termios = mxvar_termios;
+ mxvar_sdriver.termios_locked = mxvar_termios_locked;
+
+ mxvar_sdriver.open = mxser_open;
+ mxvar_sdriver.close = mxser_close;
+ mxvar_sdriver.write = mxser_write;
+ mxvar_sdriver.put_char = mxser_put_char;
+ mxvar_sdriver.flush_chars = mxser_flush_chars;
+ mxvar_sdriver.write_room = mxser_write_room;
+ mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer;
+ mxvar_sdriver.flush_buffer = mxser_flush_buffer;
+ mxvar_sdriver.ioctl = mxser_ioctl;
+ mxvar_sdriver.throttle = mxser_throttle;
+ mxvar_sdriver.unthrottle = mxser_unthrottle;
+ mxvar_sdriver.set_termios = mxser_set_termios;
+ mxvar_sdriver.stop = mxser_stop;
+ mxvar_sdriver.start = mxser_start;
+ mxvar_sdriver.hangup = mxser_hangup;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ mxvar_cdriver = mxvar_sdriver;
+ mxvar_cdriver.name = "cum";
+ mxvar_cdriver.major = calloutmajor;
+ mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT;
+
+ printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+
+ mxvar_diagflag = 0;
+ memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
+ memset(&mxvar_log, 0, sizeof(struct mxser_log));
+
+
+ m = 0;
+ /* Start finding ISA boards here */
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ int cap;
+ if (!(cap = mxserBoardCAP[b]))
+ continue;
+
+ retval = mxser_get_ISA_conf(cap, &hwconf);
+
+ if (retval != 0)
+ printk("Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1],
+ ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk("Invalid interrupt vector,board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk("Invalid I/O address,board not configured\n");
+
+ continue;
+ }
+ hwconf.pciInfo.busNum = 0;
+ hwconf.pciInfo.devNum = 0;
+
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+
+ mxser_getcfg(m, &hwconf);
+
+ m++;
+ }
+
+ /* Start finding ISA boards from module arg */
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ int cap;
+ if (!(cap = ioaddr[b]))
+ continue;
+
+ retval = mxser_get_ISA_conf(cap, &hwconf);
+
+ if (retval != 0)
+ printk("Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1],
+ ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk("Invalid interrupt vector,board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk("Invalid I/O address,board not configured\n");
+
+ continue;
+ }
+ hwconf.pciInfo.busNum = 0;
+ hwconf.pciInfo.devNum = 0;
+
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+
+ mxser_getcfg(m, &hwconf);
+
+ m++;
+ }
+
+ /* start finding PCI board here */
+
+#ifdef CONFIG_PCI
+ if (pci_present())
+ {
+ n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo);
+ index = 0;
+ b = 0;
+ while (b < n) {
+ if (pcibios_find_device(mxser_pcibrds[b].vendor_id,
+ mxser_pcibrds[b].device_id,
+ index,
+ &busnum,
+ &devnum) != 0) {
+ b++;
+ index = 0;
+ continue;
+ }
+ hwconf.pciInfo.busNum = busnum;
+ hwconf.pciInfo.devNum = devnum;
+ printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], busnum, devnum >> 3);
+ index++;
+ if (m >= MXSER_BOARDS) {
+ printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
+ } else {
+ retval = mxser_get_PCI_conf(busnum, devnum,
+ mxser_pcibrds[b].board_type, &hwconf);
+ if (retval < 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk("Invalid interrupt vector,board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk("Invalid I/O address,board not configured\n");
+ continue;
+
+ }
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+ mxser_getcfg(m, &hwconf);
+ m++;
+
+ }
+
+ }
+ }
+#endif
+
+ for (i = m; i < MXSER_BOARDS; i++) {
+ mxsercfg[i].board_type = -1;
+ }
+
+
+ ret1 = 0;
+ ret2 = 0;
+ if (!(ret1 = tty_register_driver(&mxvar_sdriver))) {
+ if (!(ret2 = tty_register_driver(&mxvar_cdriver))) {
+ return 0;
+ } else {
+ tty_unregister_driver(&mxvar_sdriver);
+ printk("Couldn't install MOXA Smartio family callout driver !\n");
+ }
+ } else
+ printk("Couldn't install MOXA Smartio family driver !\n");
+
+
+ if (ret1 || ret2) {
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (mxsercfg[i].board_type == -1)
+ continue;
+ else {
+ free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+ }
+ }
+ return -1;
+ }
+ return (0);
+}
+
+static void mxser_do_softint(void *private_)
+{
+ struct mxser_struct *info = (struct mxser_struct *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+ if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+ if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
+ tty_hangup(tty);
+ }
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_struct *info;
+ int retval, line;
+ unsigned long page;
+
+ line = PORTNO(tty);
+ if (line == MXSER_PORTS)
+ return (0);
+ if ((line < 0) || (line > MXSER_PORTS))
+ return (-ENODEV);
+ info = mxvar_table + line;
+ if (!info->base)
+ return (-ENODEV);
+
+ info->count++;
+ tty->driver_data = info;
+ info->tty = tty;
+
+ if (!mxvar_tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return (-ENOMEM);
+ if (mxvar_tmp_buf)
+ free_page(page);
+ else
+ mxvar_tmp_buf = (unsigned char *) page;
+ }
+ /*
+ * Start up serial port
+ */
+ retval = mxser_startup(info);
+ if (retval)
+ return (retval);
+
+ retval = mxser_block_til_ready(tty, filp, info);
+ if (retval)
+ return (retval);
+
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ mxser_change_speed(info, 0);
+ }
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+ MOD_INC_USE_COUNT;
+
+ return (0);
+}
+
+/*
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+ unsigned long timeout;
+
+ if (PORTNO(tty) == MXSER_PORTS)
+ return;
+ if (!info)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("mxser_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk("mxser_close: bad serial port count for ttys%d: %d\n",
+ info->port, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ restore_flags(flags);
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->IER &= ~UART_IER_RLSI;
+ /* by William
+ info->read_status_mask &= ~UART_LSR_DR;
+ */
+ if (info->flags & ASYNC_INITIALIZED) {
+ outb(info->IER, info->base + UART_IER);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ timeout = jiffies + HZ;
+ while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(5);
+ if (jiffies > timeout)
+ break;
+ }
+ }
+ mxser_shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ restore_flags(flags);
+
+ MOD_DEC_USE_COUNT;
+}
+
+static int mxser_write(struct tty_struct *tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ if (!tty || !info->xmit_buf || !mxvar_tmp_buf)
+ return (0);
+
+ if (from_user)
+ down(&mxvar_tmp_buf_sem);
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ copy_from_user(mxvar_tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ if (from_user)
+ up(&mxvar_tmp_buf_sem);
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+ !(info->IER & UART_IER_THRI)) {
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ restore_flags(flags);
+ return (total);
+}
+
+static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ if (!tty || !info->xmit_buf)
+ return;
+
+ save_flags(flags);
+ cli();
+ if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ restore_flags(flags);
+ return;
+ }
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
+ /********************************************** why ??? ***********
+ if ( !tty->stopped && !tty->hw_stopped &&
+ !(info->IER & UART_IER_THRI) ) {
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ *****************************************************************/
+ restore_flags(flags);
+}
+
+static void mxser_flush_chars(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+
+ save_flags(flags);
+ cli();
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ restore_flags(flags);
+}
+
+static int mxser_write_room(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ int ret;
+
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return (ret);
+}
+
+static int mxser_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+ return (info->xmit_cnt);
+}
+
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+}
+
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned long flags;
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ int retval;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct *p_cuser; /* user space */
+ unsigned long templ;
+
+ if (PORTNO(tty) == MXSER_PORTS)
+ return (mxser_ioctl_special(cmd, arg));
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) &&
+ (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return (-EIO);
+ }
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return (retval);
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ mxser_send_break(info, HZ / 4); /* 1/4 second */
+ return (0);
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return (retval);
+ tty_wait_until_sent(tty, 0);
+ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+ return (0);
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ case TIOCSSOFTCAR:
+ if(get_user(templ, (unsigned long *) arg))
+ return -EFAULT;
+ arg = templ;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return (0);
+ case TIOCMGET:
+ return (mxser_get_modem_info(info, (unsigned int *) arg));
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return (mxser_set_modem_info(info, cmd, (unsigned int *) arg));
+ case TIOCGSERIAL:
+ return (mxser_get_serial_info(info, (struct serial_struct *) arg));
+ case TIOCSSERIAL:
+ return (mxser_set_serial_info(info, (struct serial_struct *) arg));
+ case TIOCSERGETLSR: /* Get line status register */
+ return (mxser_get_lsr_info(info, (unsigned int *) arg));
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ save_flags(flags);
+ cli();
+ cprev = info->icount; /* note the counters on entry */
+ restore_flags(flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return (-ERESTARTSYS);
+ save_flags(flags);
+ cli();
+ cnow = info->icount; /* atomic copy */
+ restore_flags(flags);
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return (-EIO); /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return (0);
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ save_flags(flags);
+ cli();
+ cnow = info->icount;
+ restore_flags(flags);
+ p_cuser = (struct serial_icounter_struct *) arg;
+ if(put_user(cnow.cts, &p_cuser->cts))
+ return -EFAULT;
+ if(put_user(cnow.dsr, &p_cuser->dsr))
+ return -EFAULT;
+ if(put_user(cnow.rng, &p_cuser->rng))
+ return -EFAULT;
+ return put_user(cnow.dcd, &p_cuser->dcd);
+ case MOXA_HighSpeedOn:
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg);
+ default:
+ return (-ENOIOCTLCMD);
+ }
+ return (0);
+}
+
+static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
+{
+ int i, result, status;
+
+ switch (cmd) {
+ case MOXA_GET_CONF:
+ if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
+ return -EFAULT;
+ return 0;
+ case MOXA_GET_MAJOR:
+ if(copy_to_user((int *) arg, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_GET_CUMAJOR:
+ if(copy_to_user((int *) arg, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_CHKPORTENABLE:
+ result = 0;
+ for (i = 0; i < MXSER_PORTS; i++) {
+ if (mxvar_table[i].base)
+ result |= (1 << i);
+ }
+ return put_user(result, (unsigned long *) arg);
+ case MOXA_GETDATACOUNT:
+ if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log)))
+ return -EFAULT;
+ return (0);
+ case MOXA_GETMSTATUS:
+ for (i = 0; i < MXSER_PORTS; i++) {
+ GMStatus[i].ri = 0;
+ if (!mxvar_table[i].base) {
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ continue;
+ }
+ if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios)
+ GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;
+
+ status = inb(mxvar_table[i].base + UART_MSR);
+ if (status & 0x80 /*UART_MSR_DCD */ )
+ GMStatus[i].dcd = 1;
+ else
+ GMStatus[i].dcd = 0;
+
+ if (status & 0x20 /*UART_MSR_DSR */ )
+ GMStatus[i].dsr = 1;
+ else
+ GMStatus[i].dsr = 0;
+
+
+ if (status & 0x10 /*UART_MSR_CTS */ )
+ GMStatus[i].cts = 1;
+ else
+ GMStatus[i].cts = 0;
+ }
+ if(copy_to_user((struct mxser_mstatus *) arg, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ return -EFAULT;
+ return 0;
+ default:
+ return (-ENOIOCTLCMD);
+ }
+ return (0);
+}
+
+/*
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ */
+static void mxser_throttle(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ if (I_IXOFF(tty)) {
+ info->x_char = STOP_CHAR(tty);
+ save_flags(flags);
+ cli();
+ outb(info->IER, 0);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER); /* force Tx interrupt */
+ restore_flags(flags);
+ }
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR &= ~UART_MCR_RTS;
+ save_flags(flags);
+ cli();
+ outb(info->MCR, info->base + UART_MCR);
+ restore_flags(flags);
+ }
+}
+
+static void mxser_unthrottle(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ info->x_char = START_CHAR(tty);
+ save_flags(flags);
+ cli();
+ outb(info->IER, 0);
+ info->IER |= UART_IER_THRI; /* force Tx interrupt */
+ outb(info->IER, info->base + UART_IER);
+ restore_flags(flags);
+ }
+ }
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR |= UART_MCR_RTS;
+ save_flags(flags);
+ cli();
+ outb(info->MCR, info->base + UART_MCR);
+ restore_flags(flags);
+ }
+}
+
+static void mxser_set_termios(struct tty_struct *tty,
+ struct termios *old_termios)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+/* 8-2-99 by William
+ if ( (tty->termios->c_cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag)) )
+ return;
+
+ mxser_change_speed(info, old_termios);
+
+ if ( (old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS) ) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
+ }
+ */
+ if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+ (RELEVANT_IFLAG(tty->termios->c_iflag) !=
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+
+ mxser_change_speed(info, old_termios);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
+ }
+ }
+/* Handle sw stopped */
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
+ tty->stopped = 0;
+ mxser_start(tty);
+ }
+}
+
+/*
+ * mxser_stop() and mxser_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ */
+static void mxser_stop(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ restore_flags(flags);
+}
+
+static void mxser_start(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (info->xmit_cnt && info->xmit_buf &&
+ !(info->IER & UART_IER_THRI)) {
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+void mxser_hangup(struct tty_struct *tty)
+{
+ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+
+ mxser_flush_buffer(tty);
+ mxser_shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int status, i;
+ struct mxser_struct *info;
+ struct mxser_struct *port;
+ int max, irqbits, bits, msr;
+ int pass_counter = 0;
+
+ port = 0;
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
+ port = dev_id;
+ break;
+ }
+ }
+
+ if (i == MXSER_BOARDS)
+ return;
+ if (port == 0)
+ return;
+ max = mxser_numports[mxsercfg[i].board_type - 1];
+
+ while (1) {
+ irqbits = inb(port->vector) & port->vectormask;
+ if (irqbits == port->vectormask)
+ break;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == port->vectormask)
+ break;
+ if (bits & irqbits)
+ continue;
+ info = port + i;
+ if (!info->tty ||
+ (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
+ continue;
+ status = inb(info->base + UART_LSR) & info->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(info, &status);
+ msr = inb(info->base + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, msr);
+ if (status & UART_LSR_THRE) {
+/* 8-2-99 by William
+ if ( info->x_char || (info->xmit_cnt > 0) )
+ */
+ mxser_transmit_chars(info);
+ }
+ }
+ if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
+#if 0
+ printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
+#endif
+ break; /* Prevent infinite loops */
+ }
+ }
+}
+
+static inline void mxser_receive_chars(struct mxser_struct *info,
+ int *status)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch;
+ int ignored = 0;
+ int cnt = 0;
+
+ do {
+ ch = inb(info->base + UART_RX);
+ if (*status & info->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ } else {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ break;
+ tty->flip.count++;
+ if (*status & UART_LSR_SPECIAL) {
+ if (*status & UART_LSR_BI) {
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (*status & UART_LSR_PE) {
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ } else if (*status & UART_LSR_FE) {
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ } else if (*status & UART_LSR_OE) {
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ } else
+ *tty->flip.flag_buf_ptr++ = 0;
+ } else
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = ch;
+ cnt++;
+ }
+ *status = inb(info->base + UART_LSR) & info->read_status_mask;
+ } while (*status & UART_LSR_DR);
+ mxvar_log.rxcnt[info->port] += cnt;
+ queue_task(&tty->flip.tqueue, &tq_timer);
+
+}
+
+static inline void mxser_transmit_chars(struct mxser_struct *info)
+{
+ int count, cnt;
+
+ if (info->x_char) {
+ outb(info->x_char, info->base + UART_TX);
+ info->x_char = 0;
+ mxvar_log.txcnt[info->port]++;
+ return;
+ }
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ info->tty->hw_stopped) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ return;
+ }
+ cnt = info->xmit_cnt;
+ count = info->xmit_fifo_size;
+ do {
+ outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ if (--info->xmit_cnt <= 0)
+ break;
+ } while (--count > 0);
+ mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
+
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ queue_task(&info->tqueue, &tq_scheduler);
+ }
+ if (info->xmit_cnt <= 0) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+}
+
+static inline void mxser_check_modem_status(struct mxser_struct *info,
+ int status)
+{
+
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ info->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ info->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ info->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ info->icount.cts++;
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&info->open_wait);
+ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_CALLOUT_NOHUP)))
+ set_bit(MXSER_EVENT_HANGUP, &info->event);
+ queue_task(&info->tqueue, &tq_scheduler);
+
+ }
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ queue_task(&info->tqueue, &tq_scheduler);
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ }
+ }
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct mxser_struct *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ return (-EAGAIN);
+ else
+ return (-ERESTARTSYS);
+#else
+ return (-EAGAIN);
+#endif
+ }
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return (-EBUSY);
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return (-EBUSY);
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return (-EBUSY);
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return (0);
+ }
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return (-EBUSY);
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return (0);
+ }
+ if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * mxser_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+ save_flags(flags);
+ cli();
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ restore_flags(flags);
+ info->blocked_open++;
+ while (1) {
+ save_flags(flags);
+ cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
+ outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS,
+ info->base + UART_MCR);
+ restore_flags(flags);
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(info->flags & ASYNC_CLOSING) &&
+ (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+ if (retval)
+ return (retval);
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return (0);
+}
+
+static int mxser_startup(struct mxser_struct *info)
+{
+ unsigned long flags;
+ unsigned long page;
+
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return (-ENOMEM);
+
+ save_flags(flags);
+ cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ restore_flags(flags);
+ return (0);
+ }
+ if (!info->base || !info->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ restore_flags(flags);
+ return (0);
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in mxser_change_speed())
+ */
+ if (info->xmit_fifo_size == 16)
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
+
+ /*
+ * At this point there's no way the LSR could still be 0xFF;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (inb(info->base + UART_LSR) == 0xff) {
+ restore_flags(flags);
+ if (suser()) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ return (0);
+ } else
+ return (-ENODEV);
+ }
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) inb(info->base + UART_LSR);
+ (void) inb(info->base + UART_RX);
+ (void) inb(info->base + UART_IIR);
+ (void) inb(info->base + UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+ outb(info->MCR, info->base + UART_MCR);
+
+ /*
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+ outb(info->IER, info->base + UART_IER); /* enable interrupts */
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) inb(info->base + UART_LSR);
+ (void) inb(info->base + UART_RX);
+ (void) inb(info->base + UART_IIR);
+ (void) inb(info->base + UART_MSR);
+
+ if (info->tty)
+ test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * and set the speed of the serial port
+ */
+ mxser_change_speed(info, 0);
+
+ info->flags |= ASYNC_INITIALIZED;
+ restore_flags(flags);
+ return (0);
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_struct *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags);
+ cli(); /* Disable interrupts */
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+ info->IER = 0;
+ outb(0x00, info->base + UART_IER); /* disable all intrs */
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(info->MCR, info->base + UART_MCR);
+
+ /* clear Rx/Tx FIFO's */
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ /* read data port to reset things */
+ (void) inb(info->base + UART_RX);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_struct *info,
+ struct termios *old_termios)
+{
+ int quot = 0;
+ unsigned cflag, cval, fcr;
+ int i;
+ int ret = 0;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+ cflag = info->tty->termios->c_cflag;
+ if (!(info->base))
+ return ret;
+
+#ifndef B921600
+#define B921600 (B460800 +1)
+#endif
+ switch (cflag & (CBAUD | CBAUDEX)) {
+ case B921600:
+ i = 20;
+ break;
+ case B460800:
+ i = 19;
+ break;
+ case B230400:
+ i = 18;
+ break;
+ case B115200:
+ i = 17;
+ break;
+ case B57600:
+ i = 16;
+ break;
+ case B38400:
+ i = 15;
+ break;
+ case B19200:
+ i = 14;
+ break;
+ case B9600:
+ i = 13;
+ break;
+ case B4800:
+ i = 12;
+ break;
+ case B2400:
+ i = 11;
+ break;
+ case B1800:
+ i = 10;
+ break;
+ case B1200:
+ i = 9;
+ break;
+ case B600:
+ i = 8;
+ break;
+ case B300:
+ i = 7;
+ break;
+ case B200:
+ i = 6;
+ break;
+ case B150:
+ i = 5;
+ break;
+ case B134:
+ i = 4;
+ break;
+ case B110:
+ i = 3;
+ break;
+ case B75:
+ i = 2;
+ break;
+ case B50:
+ i = 1;
+ break;
+ default:
+ i = 0;
+ break;
+ }
+
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i = 16; /* 57600 bps */
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i = 17; /* 115200 bps */
+
+#ifdef ASYNC_SPD_SHI
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ i = 18;
+#endif
+
+#ifdef ASYNC_SPD_WARP
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ i = 19;
+#endif
+ }
+ if (mxvar_baud_table[i] == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (mxvar_baud_table[i]) {
+ quot = info->baud_base / mxvar_baud_table[i];
+ if (!quot && old_termios) {
+ /* re-calculate */
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ switch (info->tty->termios->c_cflag & (CBAUD | CBAUDEX)) {
+ case B921600:
+ i = 20;
+ break;
+ case B460800:
+ i = 19;
+ break;
+ case B230400:
+ i = 18;
+ break;
+ case B115200:
+ i = 17;
+ break;
+ case B57600:
+ i = 16;
+ break;
+ case B38400:
+ i = 15;
+ break;
+ case B19200:
+ i = 14;
+ break;
+ case B9600:
+ i = 13;
+ break;
+ case B4800:
+ i = 12;
+ break;
+ case B2400:
+ i = 11;
+ break;
+ case B1800:
+ i = 10;
+ break;
+ case B1200:
+ i = 9;
+ break;
+ case B600:
+ i = 8;
+ break;
+ case B300:
+ i = 7;
+ break;
+ case B200:
+ i = 6;
+ break;
+ case B150:
+ i = 5;
+ break;
+ case B134:
+ i = 4;
+ break;
+ case B110:
+ i = 3;
+ break;
+ case B75:
+ i = 2;
+ break;
+ case B50:
+ i = 1;
+ break;
+ default:
+ i = 0;
+ break;
+ }
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i = 16; /* 57600 bps */
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i = 17; /* 115200 bps */
+#ifdef ASYNC_SPD_SHI
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ i = 18;
+#endif
+#ifdef ASYNC_SPD_WARP
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ i = 19;
+#endif
+ }
+ if (mxvar_baud_table[i] == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (mxvar_baud_table[i]) {
+ quot = info->baud_base / mxvar_baud_table[i];
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
+ } else if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
+
+ if (quot) {
+ info->MCR |= UART_MCR_DTR;
+ save_flags(flags);
+ cli();
+ outb(info->MCR, info->base + UART_MCR);
+ restore_flags(flags);
+ } else {
+ info->MCR &= ~UART_MCR_DTR;
+ save_flags(flags);
+ cli();
+ outb(info->MCR, info->base + UART_MCR);
+ restore_flags(flags);
+ return ret;
+ }
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ case CS8:
+ cval = 0x03;
+ break;
+ default:
+ cval = 0x00;
+ break; /* too keep GCC shut... */
+ }
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+ if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+ fcr = 0;
+ } else {
+ fcr = UART_FCR_ENABLE_FIFO;
+ switch (info->rx_trigger) {
+ case 1:
+ fcr |= UART_FCR_TRIGGER_1;
+ break;
+ case 4:
+ fcr |= UART_FCR_TRIGGER_4;
+ break;
+ case 8:
+ fcr |= UART_FCR_TRIGGER_8;
+ break;
+ default:
+ fcr |= UART_FCR_TRIGGER_14;
+ }
+ }
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ info->MCR &= ~UART_MCR_AFE;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ if (info->type == PORT_16550A)
+ info->MCR |= UART_MCR_AFE;
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ }
+ outb(info->MCR, info->base + UART_MCR);
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ outb(info->IER, info->base + UART_IER);
+
+ /*
+ * Set up parity check flag
+ */
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ info->ignore_status_mask = 0;
+#if 0
+ /* This should be safe, but for some broken bits of hardware... */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ }
+#endif
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ info->read_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+ info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+ }
+ }
+ save_flags(flags);
+ cli();
+ outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */
+ outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */
+ outb(cval, info->base + UART_LCR); /* reset DLAB */
+ outb(fcr, info->base + UART_FCR); /* set fcr */
+ restore_flags(flags);
+
+ return ret;
+}
+
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_struct *info,
+ struct serial_struct *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return (-EFAULT);
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->port;
+ tmp.port = info->base;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0;
+ copy_to_user(retinfo, &tmp, sizeof(*retinfo));
+ return (0);
+}
+
+static int mxser_set_serial_info(struct mxser_struct *info,
+ struct serial_struct *new_info)
+{
+ struct serial_struct new_serial;
+ unsigned int flags;
+ int retval = 0;
+
+ if (!new_info || !info->base)
+ return (-EFAULT);
+ copy_from_user(&new_serial, new_info, sizeof(new_serial));
+
+ if ((new_serial.irq != info->irq) ||
+ (new_serial.port != info->base) ||
+ (new_serial.type != info->type) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return (-EPERM);
+
+ flags = info->flags & ASYNC_SPD_MASK;
+
+ if (!suser()) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (info->flags & ~ASYNC_USR_MASK)))
+ return (-EPERM);
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ } else {
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ }
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (flags != (info->flags & ASYNC_SPD_MASK)) {
+ mxser_change_speed(info, 0);
+ }
+ } else
+ retval = mxser_startup(info);
+ return (retval);
+}
+
+/*
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value)
+{
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ status = inb(info->base + UART_LSR);
+ restore_flags(flags);
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ put_user(result, value);
+ return (0);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_struct *info, int duration)
+{
+ unsigned long flags;
+ if (!info->base)
+ return;
+ current->state = TASK_INTERRUPTIBLE;
+ save_flags(flags);
+ cli();
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+ schedule_timeout(duration);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+ restore_flags(flags);
+}
+
+static int mxser_get_modem_info(struct mxser_struct *info,
+ unsigned int *value)
+{
+ unsigned char control, status;
+ unsigned int result;
+ unsigned long flags;
+
+ control = info->MCR;
+ save_flags(flags);
+ cli();
+ status = inb(info->base + UART_MSR);
+ if (status & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, status);
+ restore_flags(flags);
+ result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+ put_user(result, value);
+ return (0);
+}
+
+static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg;
+ unsigned long flags;
+
+ if(get_user(arg, value))
+ return -EFAULT;
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
+ break;
+ case TIOCMSET:
+ info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) |
+ ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) |
+ ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+ break;
+ default:
+ return (-EINVAL);
+ }
+ save_flags(flags);
+ cli();
+ outb(info->MCR, info->base + UART_MCR);
+ restore_flags(flags);
+ return (0);
+}
+
+static int mxser_read_register(int, unsigned short *);
+static int mxser_program_mode(int);
+static void mxser_normal_mode(int);
+
+static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
+{
+ int id, i, bits;
+ unsigned short regs[16], irq;
+ unsigned char scratch, scratch2;
+
+ id = mxser_read_register(cap, regs);
+ if (id == C168_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_C168_ISA;
+ else if (id == C104_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_C104_ISA;
+ else if (id == CI104J_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_CI104J;
+ else
+ return (0);
+ irq = regs[9] & 0x0F;
+ irq = irq | (irq << 4);
+ irq = irq | (irq << 8);
+ if ((irq != regs[9]) || ((id == 1) && (irq != regs[10]))) {
+ return (MXSER_ERR_IRQ_CONFLIT);
+ }
+ if (!irq) {
+ return (MXSER_ERR_IRQ);
+ }
+ for (i = 0; i < 8; i++)
+ hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
+ hwconf->irq = (int) (irq & 0x0F);
+ if ((regs[12] & 0x80) == 0) {
+ return (MXSER_ERR_VECTOR);
+ }
+ hwconf->vector = (int) regs[11]; /* interrupt vector */
+ if (id == 1)
+ hwconf->vector_mask = 0x00FF;
+ else
+ hwconf->vector_mask = 0x000F;
+ for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
+ if (regs[12] & bits)
+ hwconf->baud_base[i] = 921600;
+ else
+ hwconf->baud_base[i] = 115200;
+ }
+ scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
+ outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
+ outb(0, cap + UART_EFR); /* EFR is the same as FCR */
+ outb(scratch2, cap + UART_LCR);
+ outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
+ scratch = inb(cap + UART_IIR);
+ if (scratch & 0xC0)
+ hwconf->uart_type = PORT_16550A;
+ else
+ hwconf->uart_type = PORT_16450;
+ if (id == 1)
+ hwconf->ports = 8;
+ else
+ hwconf->ports = 4;
+ return (hwconf->ports);
+}
+
+#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
+#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
+#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
+#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
+#define EN_CCMD 0x000 /* Chip's command register */
+#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
+#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
+#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
+#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
+#define EN0_DCFG 0x00E /* Data configuration reg WR */
+#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
+#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
+#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
+static int mxser_read_register(int port, unsigned short *regs)
+{
+ int i, k, value, id;
+ unsigned int j;
+
+ id = mxser_program_mode(port);
+ if (id < 0)
+ return (id);
+ for (i = 0; i < 14; i++) {
+ k = (i & 0x3F) | 0x180;
+ for (j = 0x100; j > 0; j >>= 1) {
+ outb(CHIP_CS, port);
+ if (k & j) {
+ outb(CHIP_CS | CHIP_DO, port);
+ outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
+ } else {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
+ }
+ }
+ (void) inb(port);
+ value = 0;
+ for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port);
+ if (inb(port) & CHIP_DI)
+ value |= j;
+ }
+ regs[i] = value;
+ outb(0, port);
+ }
+ mxser_normal_mode(port);
+ return (id);
+}
+
+static int mxser_program_mode(int port)
+{
+ int id, i, j, n;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb(0, port);
+ outb(0, port);
+ outb(0, port);
+ (void) inb(port);
+ (void) inb(port);
+ outb(0, port);
+ (void) inb(port);
+ restore_flags(flags);
+ id = inb(port + 1) & 0x1F;
+ if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID))
+ return (-1);
+ for (i = 0, j = 0; i < 4; i++) {
+ n = inb(port + 2);
+ if (n == 'M') {
+ j = 1;
+ } else if ((j == 1) && (n == 1)) {
+ j = 2;
+ break;
+ } else
+ j = 0;
+ }
+ if (j != 2)
+ id = -2;
+ return (id);
+}
+
+static void mxser_normal_mode(int port)
+{
+ int i, n;
+
+ outb(0xA5, port + 1);
+ outb(0x80, port + 3);
+ outb(12, port + 0); /* 9600 bps */
+ outb(0, port + 1);
+ outb(0x03, port + 3); /* 8 data bits */
+ outb(0x13, port + 4); /* loop back mode */
+ for (i = 0; i < 16; i++) {
+ n = inb(port + 5);
+ if ((n & 0x61) == 0x60)
+ break;
+ if ((n & 1) == 1)
+ (void) inb(port);
+ }
+ outb(0x00, port + 4);
+}
diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in
index 7a32e5d55..766fdd1d0 100644
--- a/drivers/char/pcmcia/Config.in
+++ b/drivers/char/pcmcia/Config.in
@@ -2,10 +2,7 @@
# PCMCIA character device configuration
#
-mainmenu_option next_comment
-comment 'PCMCIA character device support'
-
-if [ "$CONFIG_SERIAL" = "n" -o "$CONFIG_PCMCIA" = "n" ]; then
+if [ "$CONFIG_SERIAL" = "n" ]; then
define_bool CONFIG_PCMCIA_SERIAL n
else
if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then
@@ -15,14 +12,19 @@ else
fi
fi
-dep_tristate ' PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL
-if [ "$CONFIG_CARDBUS" = "y" ]; then
- dep_tristate ' CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL
-fi
+if [ "$CONFIG_PCMCIA_SERIAL" != "n" ]; then
+ mainmenu_option next_comment
+ comment 'PCMCIA character device support'
-if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \
- "$CONFIG_PCMCIA_SERIAL_CB" = "y" ]; then
- define_bool CONFIG_PCMCIA_CHRDEV y
-fi
+ dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL
+ if [ "$CONFIG_CARDBUS" = "y" ]; then
+ dep_tristate 'CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL
+ fi
-endmenu
+ if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \
+ "$CONFIG_PCMCIA_SERIAL_CB" = "y" ]; then
+ define_bool CONFIG_PCMCIA_CHRDEV y
+ fi
+
+ endmenu
+fi
diff --git a/drivers/char/pcmcia/serial_cb.c b/drivers/char/pcmcia/serial_cb.c
index 8a2dede85..b0d8b02a8 100644
--- a/drivers/char/pcmcia/serial_cb.c
+++ b/drivers/char/pcmcia/serial_cb.c
@@ -2,7 +2,7 @@
A driver for CardBus serial devices
- serial_cb.c 1.14 1999/11/11 02:18:08
+ serial_cb.c 1.15 1999/11/24 02:52:06
Copyright 1998, 1999 by Donald Becker and David Hinds
@@ -39,7 +39,7 @@ 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 =
-"serial_cb.c 1.14 1999/11/11 02:18:08 (David Hinds)";
+"serial_cb.c 1.15 1999/11/24 02:52:06 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -56,8 +56,9 @@ static void device_setup(u_char bus, u_char devfn, u_int ioaddr)
pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &a);
pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_ID, &b);
- if ((a == 0x13a2) && (b == 0x8007)) {
- /* Ositech Jack of Spades */
+ if (((a == 0x13a2) && (b == 0x8007)) ||
+ ((a == 0x1420) && (b == 0x8003))) {
+ /* Ositech, Psion 83c175-based cards */
DEBUG(0, " 83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80));
outl(0x4C00, ioaddr + 0x80);
outl(0x4C80, ioaddr + 0x80);
diff --git a/drivers/char/pcmcia/serial_cs.c b/drivers/char/pcmcia/serial_cs.c
index 38345b1b5..a59a877bb 100644
--- a/drivers/char/pcmcia/serial_cs.c
+++ b/drivers/char/pcmcia/serial_cs.c
@@ -2,7 +2,7 @@
A driver for PCMCIA serial devices
- serial_cs.c 1.114 1999/11/11 00:54:46
+ serial_cs.c 1.117 1999/12/11 03:59:18
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -58,7 +58,7 @@ 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 =
-"serial_cs.c 1.114 1999/11/11 00:54:46 (David Hinds)";
+"serial_cs.c 1.117 1999/12/11 03:59:18 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -100,6 +100,7 @@ static multi_id_t multi_id[] = {
#define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t))
typedef struct serial_info_t {
+ dev_link_t link;
int ndev;
int multi;
int slave;
@@ -138,6 +139,7 @@ static void cs_error(client_handle_t handle, int func, int ret)
static dev_link_t *serial_attach(void)
{
+ serial_info_t *info;
client_reg_t client_reg;
dev_link_t *link;
int i, ret;
@@ -145,8 +147,11 @@ static dev_link_t *serial_attach(void)
DEBUG(0, "serial_attach()\n");
/* Create new serial device */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+
link->release.function = &serial_release;
link->release.data = (u_long)link;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -165,8 +170,6 @@ static dev_link_t *serial_attach(void)
link->conf.Status = CCSR_AUDIO_ENA;
}
link->conf.IntType = INT_MEMORY_AND_IO;
- link->priv = kmalloc(sizeof(struct serial_info_t), GFP_KERNEL);
- memset(link->priv, 0, sizeof(struct serial_info_t));
/* Register with Card Services */
link->next = dev_list;
@@ -201,6 +204,7 @@ static dev_link_t *serial_attach(void)
static void serial_detach(dev_link_t *link)
{
+ serial_info_t *info = link->priv;
dev_link_t **linkp;
long flags;
int ret;
@@ -232,8 +236,7 @@ static void serial_detach(dev_link_t *link)
/* Unlink device structure, free bits */
*linkp = link->next;
- kfree_s(link->priv, sizeof(serial_info_t));
- kfree_s(link, sizeof(struct dev_link_t));
+ kfree(info);
} /* serial_detach */
@@ -326,7 +329,8 @@ static int simple_config(dev_link_t *link)
if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
link->conf.Vpp1 = link->conf.Vpp2 =
cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
- if ((cf->io.nwin > 0) && ((cf->io.win[0].base & 0xf) == 8)) {
+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[0].base != 0)) {
link->conf.ConfigIndex = cf->index;
link->io.BasePort1 = cf->io.win[0].base;
link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
@@ -347,6 +351,7 @@ static int simple_config(dev_link_t *link)
link->conf.ConfigIndex = cf->index;
for (j = 0; j < 5; j++) {
link->io.BasePort1 = base[j];
+ link->io.IOAddrLines = base[j] ? 16 : 3;
i = CardServices(RequestIO, link->handle,
&link->io);
if (i == CS_SUCCESS) goto found_port;
@@ -470,18 +475,14 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
void serial_config(dev_link_t *link)
{
- client_handle_t handle;
- serial_info_t *info;
+ client_handle_t handle = link->handle;
+ serial_info_t *info = link->priv;
tuple_t tuple;
u_short buf[128];
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
int i, last_ret, last_fn;
- sti();
- handle = link->handle;
- info = link->priv;
-
DEBUG(0, "serial_config(0x%p)\n", link);
tuple.TupleData = (cisdata_t *)buf;
@@ -572,8 +573,6 @@ void serial_release(u_long arg)
serial_info_t *info = link->priv;
int i;
- sti();
-
DEBUG(0, "serial_release(0x%p)\n", link);
for (i = 0; i < info->ndev; i++) {
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 10d059278..39cceb5f5 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -34,6 +34,8 @@
* 971222 Changed open/close for temperature handling
* Michael Meskes <meskes@debian.org>.
* 980112 Used minor numbers from include/linux/miscdevice.h
+ * 990403 Clear reset status after reading control status register in
+ * pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
* 990605 Made changes to code to support Firmware 1.22a, added
* fairly useless proc entry.
* 990610 removed said useless proc code for the merge <alan>
@@ -183,8 +185,10 @@ void pcwd_showprevstate(void)
if (revision == PCWD_REVISION_A)
initial_status = card_status = inb(current_readport);
- else
+ else {
initial_status = card_status = inb(current_readport + 1);
+ outb_p(0x00, current_readport + 1); /* clear reset status */
+ }
if (revision == PCWD_REVISION_A) {
if (card_status & WD_WDRST)
diff --git a/drivers/char/radio-cadet.c b/drivers/char/radio-cadet.c
index a979e7424..685a08a0d 100644
--- a/drivers/char/radio-cadet.c
+++ b/drivers/char/radio-cadet.c
@@ -39,6 +39,7 @@ struct timer_list tunertimer,rdstimer,readtimer;
static __u8 rdsin=0,rdsout=0,rdsstat=0;
static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
+static int cadet_probe(void);
/*
* Signal Strength Threshold Values
diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c
index a34c85d1f..b63f35436 100644
--- a/drivers/char/stradis.c
+++ b/drivers/char/stradis.c
@@ -2249,7 +2249,7 @@ int init_stradis_cards(struct video_init *unused)
saa_num = 0;
while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) {
- if (!dev->subsystem_vendor_id)
+ if (!dev->subsystem_vendor)
printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
else
printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num);
diff --git a/drivers/char/tda8425.c b/drivers/char/tda8425.c
index 87d79b00e..73df0b4ac 100644
--- a/drivers/char/tda8425.c
+++ b/drivers/char/tda8425.c
@@ -104,7 +104,7 @@ static void tda8425_set(struct i2c_client *client)
tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0);
}
-static void tda8425_init(struct i2c_client *client)
+static void do_tda8425_init(struct i2c_client *client)
{
struct tda8425 *tda = client->data;
@@ -152,7 +152,7 @@ static int tda8425_attach(struct i2c_adapter *adap, int addr,
if (!tda)
return -ENOMEM;
memset(tda,0,sizeof *tda);
- tda8425_init(client);
+ do_tda8425_init(client);
MOD_INC_USE_COUNT;
strcpy(client->name,"TDA8425");
printk(KERN_INFO "tda8425: init\n");
@@ -173,7 +173,7 @@ static int tda8425_detach(struct i2c_client *client)
{
struct tda8425 *tda = client->data;
- tda8425_init(client);
+ do_tda8425_init(client);
i2c_detach_client(client);
kfree(tda);
diff --git a/drivers/char/tda9855.c b/drivers/char/tda9855.c
index ed676087f..dfdee66dc 100644
--- a/drivers/char/tda9855.c
+++ b/drivers/char/tda9855.c
@@ -194,7 +194,7 @@ static int tda9855_set(struct i2c_client *client)
return 0;
}
-static void tda9855_init(struct i2c_client *client)
+static void do_tda9855_init(struct i2c_client *client)
{
struct tda9855 *t = client->data;
@@ -235,7 +235,7 @@ static int tda9855_attach(struct i2c_adapter *adap, int addr,
if (!t)
return -ENOMEM;
memset(t,0,sizeof *t);
- tda9855_init(client);
+ do_tda9855_init(client);
MOD_INC_USE_COUNT;
strcpy(client->name,"TDA9855");
printk(KERN_INFO "tda9855: init\n");
@@ -255,7 +255,7 @@ static int tda9855_detach(struct i2c_client *client)
{
struct tda9855 *t = client->data;
- tda9855_init(client);
+ do_tda9855_init(client);
i2c_detach_client(client);
kfree(t);
@@ -298,8 +298,7 @@ static int tda9855_command(struct i2c_client *client,
va->mode = ((TDA9855_STP | TDA9855_SAPP) &
tda9855_read(client)) >> 4;
- if (0 == va->mode)
- va->mode = VIDEO_SOUND_MONO;
+ va->mode |= VIDEO_SOUND_MONO;
break;
}
case VIDIOCSAUDIO:
@@ -327,7 +326,7 @@ static int tda9855_command(struct i2c_client *client,
case VIDEO_SOUND_STEREO:
t->c2= TDA9855_STEREO | (t->c2 & 0x3f);
break;
- case VIDEO_SOUND_LANG2:
+ case VIDEO_SOUND_LANG1:
t->c2= TDA9855_SAP | (t->c2 & 0x3f);
break;
}
@@ -445,7 +444,7 @@ int tda9855_init(void)
#ifdef MODULE
void cleanup_module(void)
{
- i2c_add_driver(&driver);
+ i2c_del_driver(&driver);
}
#endif
diff --git a/drivers/char/tea6300.c b/drivers/char/tea6300.c
index 5449ae0a5..f5949c94f 100644
--- a/drivers/char/tea6300.c
+++ b/drivers/char/tea6300.c
@@ -111,7 +111,7 @@ static void tea6300_set(struct i2c_client *client)
tea6300_write(client, TEA6300_TR, tea->treble>>12);
}
-static void tea6300_init(struct i2c_client *client)
+static void do_tea6300_init(struct i2c_client *client)
{
struct tea6300 *tea = client->data;
@@ -173,7 +173,7 @@ static int tea6300_attach(struct i2c_adapter *adap, int addr,
if (!tea)
return -ENOMEM;
memset(tea,0,sizeof *tea);
- tea6300_init(client);
+ do_tea6300_init(client);
MOD_INC_USE_COUNT;
strcpy(client->name,"TEA6300T");
@@ -194,7 +194,7 @@ static int tea6300_detach(struct i2c_client *client)
{
struct tea6300 *tea = client->data;
- tea6300_init(client);
+ do_tea6300_init(client);
i2c_detach_client(client);
kfree(tea);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f78171281..c726f745c 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -344,7 +344,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
-static long long tty_lseek(struct file * file, long long offset, int orig)
+static loff_t tty_lseek(struct file * file, loff_t offset, int orig)
{
return -ESPIPE;
}
@@ -2216,6 +2216,12 @@ void __init tty_init(void)
rs_8xx_init();
#endif /* CONFIG_8xx */
pty_init();
+#ifdef CONFIG_MOXA_SMARTIO
+ mxser_init();
+#endif
+#ifdef CONFIG_MOXA_INTELLIO
+ moxa_init();
+#endif
#ifdef CONFIG_VT
vcs_init();
#endif
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index a25013fea..5fc98155b 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -59,7 +59,7 @@ vcs_size(struct inode *inode)
return size;
}
-static long long vcs_lseek(struct file *file, long long offset, int orig)
+static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size = vcs_size(file->f_dentry->d_inode);
diff --git a/drivers/fc4/Makefile b/drivers/fc4/Makefile
index 540167bbf..7b88ecc14 100644
--- a/drivers/fc4/Makefile
+++ b/drivers/fc4/Makefile
@@ -7,8 +7,6 @@ L_TARGET := fc4.a
M_OBJS :=
MOD_LIST_NAME := FC4_MODULES
-include ../../.config
-
ifeq ($(CONFIG_FC4),y)
FC4 = fc.o
ifeq ($(CONFIG_MODULES),y)
diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c
index 78d3a6c53..a0cab3015 100644
--- a/drivers/i2o/i2o_block.c
+++ b/drivers/i2o/i2o_block.c
@@ -685,7 +685,6 @@ static int i2ob_release(struct inode *inode, struct file *file)
minor = MINOR(inode->i_rdev);
if (minor >= (MAX_I2OB<<4))
return -ENODEV;
- sync_dev(inode->i_rdev);
dev = &i2ob_dev[(minor&0xF0)];
if (dev->refcnt <= 0)
printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
@@ -739,7 +738,9 @@ static int i2ob_open(struct inode *inode, struct file *file)
if (minor >= MAX_I2OB<<4)
return -ENODEV;
dev=&i2ob_dev[(minor&0xF0)];
-
+ if(dev->i2odev == NULL)
+ return -ENODEV;
+
if(dev->refcnt++==0)
{
u32 msg[6];
@@ -822,7 +823,6 @@ static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, i
i2ob_query_device(dev, 0x0000, 6, &status, 4);
i2ob_sizes[unit] = (int)(size>>10);
i2ob_hardsizes[unit] = blocksize;
- i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit];
limit=4096; /* 8 deep scatter gather */
@@ -870,7 +870,7 @@ static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, i
printk(".\n");
printk("%s: Maximum sectors/read set to %d.\n",
d->dev_name, i2ob_max_sectors[unit]);
- resetup_one_dev(&i2ob_gendisk, unit>>4);
+ grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9));
return 0;
}
@@ -1014,14 +1014,6 @@ static struct block_device_operations i2ob_fops =
check_media_change: i2ob_media_change,
revalidate: i2ob_revalidate,
};
-
-/*
- * Partitioning
- */
-
-static void i2ob_geninit(struct gendisk *gd)
-{
-}
static struct gendisk i2ob_gendisk =
{
@@ -1029,8 +1021,6 @@ static struct gendisk i2ob_gendisk =
"i2ohd",
4,
1<<4,
- MAX_I2OB,
- i2ob_geninit,
i2ob,
i2ob_sizes,
0,
@@ -1129,6 +1119,9 @@ int i2o_block_init(void)
* Finally see what is actually plugged in to our controllers
*/
+ for (i = 0; i < MAX_I2OB; i++)
+ register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4,
+ &i2ob_fops, 0);
i2ob_probe();
register_reboot_notifier(&i2ob_reboot_notifier);
diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c
index 96d9c17e1..4133db0cb 100644
--- a/drivers/i2o/i2o_config.c
+++ b/drivers/i2o/i2o_config.c
@@ -1,26 +1,28 @@
/*
- * I2O Configuration Interface Driver
+ * I2O Configuration Interface Driver
*
- * (C) Copyright 1999 Red Hat Software
+ * (C) Copyright 1999 Red Hat Software
*
- * Written by Alan Cox, Building Number Three Ltd
+ * Written by Alan Cox, Building Number Three Ltd
*
- * Modified 04/20/1999 by Deepak Saxena
- * - Added basic ioctl() support
- * Modified 06/07/1999 by Deepak Saxena
- * - Added software download ioctl (still testing)
- * Modified 09/10/1999 by Auvo Häkkinen
- * - Changes to i2o_cfg_reply(), ioctl_parms()
- * - Added ioct_validate()
- * Modified 09/30/1999 by Taneli Vähäkangas
- * - Fixed ioctl_swdl()
- * Modified 10/04/1999 by Taneli Vähäkangas
- * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 04/20/1999 by Deepak Saxena
+ * - Added basic ioctl() support
+ * Modified 06/07/1999 by Deepak Saxena
+ * - Added software download ioctl (still testing)
+ * Modified 09/10/1999 by Auvo Häkkinen
+ * - Changes to i2o_cfg_reply(), ioctl_parms()
+ * - Added ioct_validate()
+ * Modified 09/30/1999 by Taneli Vähäkangas
+ * - Fixed ioctl_swdl()
+ * Modified 10/04/1999 by Taneli Vähäkangas
+ * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 11/18/199 by Deepak Saxena
+ * - Added event managmenet support
*
- * 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 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.
*/
#include <linux/module.h>
@@ -37,13 +39,29 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-static int i2o_cfg_token = 0;
static int i2o_cfg_context = -1;
static void *page_buf;
static void *i2o_buffer;
static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
struct wait_queue *i2o_wait_queue;
+#define MODINC(x,y) (x = x++ % y)
+
+struct i2o_cfg_info
+{
+ struct file* fp;
+ struct fasync_struct *fasync;
+ struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
+ u16 q_in; // Queue head index
+ u16 q_out; // Queue tail index
+ u16 q_len; // Queue length
+ u16 q_lost; // Number of lost events
+ u32 q_id; // Event queue ID...used as tx_context
+ struct i2o_cfg_info *next;
+};
+static struct i2o_cfg_info *open_files = NULL;
+static int i2o_cfg_info_id = 0;
+
static int ioctl_getiops(unsigned long);
static int ioctl_gethrt(unsigned long);
static int ioctl_getlct(unsigned long);
@@ -53,6 +71,9 @@ static int ioctl_swdl(unsigned long);
static int ioctl_swul(unsigned long);
static int ioctl_swdel(unsigned long);
static int ioctl_validate(unsigned long);
+static int ioctl_evt_reg(unsigned long, struct file *);
+static int ioctl_evt_get(unsigned long, struct file *);
+static int cfg_fasync(int, struct file*, int);
/*
* This is the callback for any message we have posted. The message itself
@@ -62,13 +83,78 @@ static int ioctl_validate(unsigned long);
*/
static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m)
{
- u32 *msg = (u32 *)m;
+ u32 *msg = (u32 *)m;
+
+ if (msg[0] & (1<<13))
+ printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
- if (msg[4] >> 24) // RegStatus != SUCCESS
- i2o_cfg_token = -(msg[4] & 0xFFFF); // DetailedStatus
- else
- i2o_cfg_token = I2O_POST_WAIT_OK;
-
+ if (msg[4] >> 24) // RegStatus != SUCCESS
+ i2o_report_status(KERN_INFO,"i2o_config",msg);
+
+ if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+ {
+ struct i2o_cfg_info *inf;
+
+ for(inf = open_files; inf; inf = inf->next)
+ if(inf->q_id == msg[3])
+ break;
+
+ //
+ // If this is the case, it means that we're getting
+ // events for a file descriptor that's been close()'d
+ // w/o the user unregistering for events first.
+ // The code currently assumes that the user will
+ // take care of unregistering for events before closing
+ // a file.
+ //
+ // TODO:
+ // Should we track event registartion and deregister
+ // for events when a file is close()'d so this doesn't
+ // happen? That would get rid of the search through
+ // the linked list since file->private_data could point
+ // directly to the i2o_config_info data structure...but
+ // it would mean having all sorts of tables to track
+ // what each file is registered for...I think the
+ // current method is simpler. - DS
+ //
+ if(!inf)
+ return;
+
+ inf->event_q[inf->q_in].id.iop = c->unit;
+ inf->event_q[inf->q_in].id.tid = m->target_tid;
+ inf->event_q[inf->q_in].id.evt_mask = msg[4];
+
+ //
+ // Data size = msg size - reply header
+ //
+ inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
+ if(inf->event_q[inf->q_in].data_size)
+ memcpy(inf->event_q[inf->q_in].evt_data,
+ (unsigned char *)(msg + 5),
+ inf->event_q[inf->q_in].data_size);
+
+ spin_lock(&i2o_config_lock);
+ MODINC(inf->q_in, I2O_EVT_Q_LEN);
+ if(inf->q_len == I2O_EVT_Q_LEN)
+ {
+ MODINC(inf->q_out, I2O_EVT_Q_LEN);
+ inf->q_lost++;
+ }
+ else
+ {
+ // Keep I2OEVTGET on another CPU from touching this
+ inf->q_len++;
+ }
+ spin_unlock(&i2o_config_lock);
+
+
+// printk(KERN_INFO "File %p w/id %d has %d events\n",
+// inf->fp, inf->q_id, inf->q_len);
+
+ if(inf->fasync)
+ kill_fasync(inf->fasync, SIGIO, POLL_IN);
+ }
+
return;
}
@@ -107,14 +193,11 @@ static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr)
/*
* IOCTL Handler
*/
-static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
unsigned long arg)
{
int ret;
- /* Only 1 token, so lock... */
- spin_lock(&i2o_config_lock);
-
switch(cmd)
{
case I2OGETIOPS:
@@ -157,11 +240,18 @@ static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = ioctl_html(arg);
break;
+ case I2OEVTREG:
+ ret = ioctl_evt_reg(arg, fp);
+ break;
+
+ case I2OEVTGET:
+ ret = ioctl_evt_get(arg, fp);
+ break;
+
default:
ret = -EINVAL;
}
- spin_unlock(&i2o_config_lock);
return ret;
}
@@ -320,7 +410,7 @@ static int ioctl_parms(unsigned long arg, unsigned int type)
}
len = i2o_issue_params(i2o_cmd, c, kcmd.tid,
- ops, kcmd.oplen, res, sizeof(res));
+ ops, kcmd.oplen, res, 65536);
i2o_unlock_controller(c);
kfree(ops);
@@ -392,7 +482,7 @@ int ioctl_html(unsigned long arg)
}
}
- res = kmalloc(4096, GFP_KERNEL);
+ res = kmalloc(65536, GFP_KERNEL);
if(!res)
{
i2o_unlock_controller(c);
@@ -403,21 +493,22 @@ int ioctl_html(unsigned long arg)
msg[2] = i2o_cfg_context;
msg[3] = 0;
msg[4] = kcmd.page;
- msg[5] = 0xD0000000|4096;
+ msg[5] = 0xD0000000|65536;
msg[6] = virt_to_bus(res);
if(!kcmd.qlen) /* Check for post data */
msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5;
else
{
msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
- msg[5] = 0x50000000|4096;
+ msg[5] = 0x50000000|65536;
msg[7] = 0xD4000000|(kcmd.qlen);
msg[8] = virt_to_phys(query);
}
token = i2o_post_wait(c, msg, 9*4, 10);
- if(token != I2O_POST_WAIT_OK)
+ if(token)
{
+ printk(KERN_DEBUG "token = %#10x\n", token);
i2o_unlock_controller(c);
kfree(res);
if(kcmd.qlen) kfree(query);
@@ -426,7 +517,7 @@ int ioctl_html(unsigned long arg)
}
i2o_unlock_controller(c);
- len = strnlen(res, 8192);
+ len = strnlen(res, 65536);
put_user(len, kcmd.reslen);
if(len > reslen)
ret = -ENOMEM;
@@ -500,7 +591,7 @@ int ioctl_swdl(unsigned long arg)
{
// it fails if you try and send frags out of order
// and for some yet unknown reasons too
- printk("i2o_config: swdl failed, DetailedStatus = %d\n", status);
+ printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
return -ETIMEDOUT;
}
@@ -562,7 +653,7 @@ int ioctl_swul(unsigned long arg)
if (status != I2O_POST_WAIT_OK)
{
kfree(buffer);
- printk("i2o_config: swul failed, DetailedStatus = %d\n", status);
+ printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
return -ETIMEDOUT;
}
@@ -603,7 +694,7 @@ int ioctl_swdel(unsigned long arg)
if (token != I2O_POST_WAIT_OK)
{
- printk("i2o_config: swdel failed, DetailedStatus = %d\n", token);
+ printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token);
return -ETIMEDOUT;
}
@@ -631,7 +722,7 @@ int ioctl_validate(unsigned long arg)
if (token != I2O_POST_WAIT_OK)
{
- printk("Can't validate configuration, ErrorStatus = %d\n",
+ printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n",
token);
return -ETIMEDOUT;
}
@@ -639,22 +730,154 @@ int ioctl_validate(unsigned long arg)
return 0;
}
+static int ioctl_evt_reg(unsigned long arg, struct file *fp)
+{
+ u32 msg[5];
+ struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg;
+ struct i2o_evt_id kdesc;
+ struct i2o_controller *iop;
+ struct i2o_device *d;
+
+ if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
+ return -EFAULT;
+
+ /* IOP exists? */
+ iop = i2o_find_controller(kdesc.iop);
+ if(!iop)
+ return -ENXIO;
+ i2o_unlock_controller(iop);
+
+ /* Device exists? */
+ for(d = iop->devices; d; d = d->next)
+ if(d->lct_data->tid == kdesc.tid)
+ break;
+
+ if(!d)
+ return -ENODEV;
+
+ msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+ msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid;
+ msg[2] = (u32)i2o_cfg_context;
+ msg[3] = (u32)fp->private_data;
+ msg[4] = kdesc.evt_mask;
+
+ i2o_post_this(iop, msg, 20);
+
+ return 0;
+}
+
+static int ioctl_evt_get(unsigned long arg, struct file *fp)
+{
+ u32 id = (u32)fp->private_data;
+ struct i2o_cfg_info *p = NULL;
+ struct i2o_evt_get *uget = (struct i2o_evt_get*)arg;
+ struct i2o_evt_get kget;
+ unsigned int flags;
+
+ // access_ok doesn't check for NULL?!?!
+ if(!arg)
+ return -EFAULT;
+
+ if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get)))
+ return -EFAULT;
+
+ for(p = open_files; p; p = p->next)
+ if(p->q_id == id)
+ break;
+
+ if(!p->q_len)
+ {
+ return -ENOENT;
+ return 0;
+ }
+
+ memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
+ MODINC(p->q_out, I2O_EVT_Q_LEN);
+ spin_lock_irqsave(&i2o_config_lock, flags);
+ p->q_len--;
+ kget.pending = p->q_len;
+ kget.lost = p->q_lost;
+ spin_unlock_irqrestore(&i2o_config_lock, flags);
+
+ __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get));
+
+ return 0;
+}
static int cfg_open(struct inode *inode, struct file *file)
{
- /*
- * Should support multiple management users
- */
+ struct i2o_cfg_info *tmp =
+ (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL);
+ unsigned int flags;
+
+ if(!tmp)
+ return -ENOMEM;
+
+ file->private_data = (void*)(i2o_cfg_info_id++);
+ tmp->fp = file;
+ tmp->fasync = NULL;
+ tmp->q_id = (u32)file->private_data;
+ tmp->q_len = 0;
+ tmp->q_in = 0;
+ tmp->q_out = 0;
+ tmp->q_lost = 0;
+ tmp->next = open_files;
+
+ spin_lock_irqsave(&i2o_config_lock, flags);
+ open_files = tmp;
+ spin_unlock_irqrestore(&i2o_config_lock, flags);
+
MOD_INC_USE_COUNT;
return 0;
}
static int cfg_release(struct inode *inode, struct file *file)
{
+ u32 id = (u32)file->private_data;
+ struct i2o_cfg_info *p1, *p2;
+ unsigned int flags;
+
+ p1 = p2 = NULL;
+
+ spin_lock_irqsave(&i2o_config_lock, flags);
+ for(p1 = open_files; p1; )
+ {
+ if(p1->q_id == id)
+ {
+
+ if(p1->fasync)
+ cfg_fasync(-1, file, 0);
+ if(p2)
+ p2->next = p1->next;
+ else
+ open_files = p1->next;
+
+ kfree(p1);
+ break;
+ }
+ p2 = p1;
+ p1 = p1->next;
+ }
+ spin_unlock_irqrestore(&i2o_config_lock, flags);
+
MOD_DEC_USE_COUNT;
return 0;
}
+static int cfg_fasync(int fd, struct file *fp, int on)
+{
+ u32 id = (u32)fp->private_data;
+ struct i2o_cfg_info *p;
+
+ for(p = open_files; p; p = p->next)
+ if(p->q_id == id)
+ break;
+
+ if(!p)
+ return -EBADF;
+
+ return fasync_helper(fd, fp, on, &p->fasync);
+}
static struct file_operations config_fops =
{
@@ -667,7 +890,9 @@ static struct file_operations config_fops =
NULL, /* No mmap */
cfg_open,
NULL, /* No flush */
- cfg_release
+ cfg_release,
+ NULL,
+ cfg_fasync
};
static struct miscdevice i2o_miscdev = {
@@ -682,7 +907,8 @@ int init_module(void)
int __init i2o_config_init(void)
#endif
{
- printk(KERN_INFO "i2o configuration manager v 0.03\n");
+ printk(KERN_INFO "I2O configuration manager v 0.04.\n");
+ printk(KERN_INFO " (C) Copyright 1999 Red Hat Software");
if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
{
diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c
index ff3e2405f..6428af9fc 100644
--- a/drivers/i2o/i2o_core.c
+++ b/drivers/i2o/i2o_core.c
@@ -18,7 +18,6 @@
* Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
* Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
- *
*/
#include <linux/config.h>
@@ -35,7 +34,6 @@
#include <linux/bitops.h>
#include <linux/wait.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <asm/io.h>
@@ -53,19 +51,22 @@
static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
+struct i2o_controller *i2o_controller_chain;
int i2o_num_controllers = 0;
static int core_context = 0;
-extern int i2o_online_controller(struct i2o_controller *c);
+static int i2o_activate_controller(struct i2o_controller *iop);
+static int i2o_online_controller(struct i2o_controller *c);
static int i2o_init_outbound_q(struct i2o_controller *c);
static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
struct i2o_message *);
static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
-static void i2o_dump_message(u32 *msg);
+void i2o_dump_message(u32 *msg);
static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
+static int i2o_reset_controller(struct i2o_controller *);
static int i2o_lct_get(struct i2o_controller *);
static int i2o_hrt_get(struct i2o_controller *);
@@ -176,9 +177,7 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
{
if (msg[4] >> 24)
{
- /* 0x40000000 is used as an error report supress bit */
- if(msg[2]&0x40000000)
- i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
+ i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
status = -(msg[4] & 0xFFFF);
}
else
@@ -233,7 +232,6 @@ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
d->next=c->devices;
c->devices=d;
*d->dev_name = 0;
- d->owner = NULL;
for(i = 0; i < I2O_MAX_MANAGERS; i++)
d->managers[i] = NULL;
@@ -307,12 +305,7 @@ int i2o_install_controller(struct i2o_controller *c)
c->next=i2o_controller_chain;
i2o_controller_chain=c;
c->unit = i;
- c->page_frame = NULL;
- c->hrt = NULL;
- c->lct = NULL;
- c->status_block = NULL;
-// printk(KERN_INFO "lct @ %p hrt @ %p status @ %p",
-// c->lct, c->hrt, c->status_block);
+
sprintf(c->name, "i2o/iop%d", i);
i2o_num_controllers++;
spin_unlock(&i2o_configuration_lock);
@@ -328,15 +321,13 @@ int i2o_delete_controller(struct i2o_controller *c)
{
struct i2o_controller **p;
int users;
-
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Deleting controller iop%d\n", c->unit);
-#endif
+ char name[16];
spin_lock(&i2o_configuration_lock);
if((users=atomic_read(&c->users)))
{
- printk(KERN_INFO "I2O: %d users for controller iop%d\n", users, c->unit);
+ printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users);
+ c->bus_disable(c);
spin_unlock(&i2o_configuration_lock);
return -EBUSY;
}
@@ -345,6 +336,7 @@ int i2o_delete_controller(struct i2o_controller *c)
if(__i2o_delete_device(c->devices)<0)
{
/* Shouldnt happen */
+ c->bus_disable(c);
spin_unlock(&i2o_configuration_lock);
return -EBUSY;
}
@@ -356,8 +348,8 @@ int i2o_delete_controller(struct i2o_controller *c)
{
if(*p==c)
{
- /* Ask the IOP to switch to HOLD state */
- i2o_clear_controller(c);
+ /* Ask the IOP to switch into RESET state */
+ i2o_reset_controller(c);
/* Release IRQ */
c->destructor(c);
@@ -365,8 +357,6 @@ int i2o_delete_controller(struct i2o_controller *c)
*p=c->next;
spin_unlock(&i2o_configuration_lock);
-// printk(KERN_INFO "hrt %p lct %p page_frame %p status_block %p\n",
-// c->hrt, c->lct, c->page_frame, c->status_block);
if(c->page_frame)
kfree(c->page_frame);
if(c->hrt)
@@ -376,14 +366,13 @@ int i2o_delete_controller(struct i2o_controller *c)
if(c->status_block)
kfree(c->status_block);
- kfree(c);
-
i2o_controllers[c->unit]=NULL;
-
+ memcpy(name, c->name, strlen(c->name)+1);
+ kfree(c);
i2o_num_controllers--;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "iop deleted\n");
-#endif
+
+ dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name));
+
return 0;
}
p=&((*p)->next);
@@ -540,17 +529,20 @@ void i2o_run_queue(struct i2o_controller *c)
u32 mv;
#ifdef DEBUG_IRQ
- printk(KERN_INFO "iop%d interrupt\n", c->unit);
+ printk(KERN_INFO "%s: interrupt\n", c->name);
#endif
+ /* Sometimes we get here, but a message can't be read. Why? */
+ if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+ mv=I2O_REPLY_READ32(c);
- while((mv=I2O_REPLY_READ32(c))!=0xFFFFFFFF)
+ while (mv!=0xFFFFFFFF)
{
struct i2o_handler *i;
m=(struct i2o_message *)bus_to_virt(mv);
/*
* Temporary Debugging
*/
- if(((m->function_addr>>24)&0xFF)==0x15)
+ if(m->function==0x15)
printk("UTFR!\n");
#ifdef DEBUG_IRQ
@@ -562,12 +554,13 @@ void i2o_run_queue(struct i2o_controller *c)
i->reply(i,c,m);
else
{
- printk("Spurious reply to handler %d\n",
+ printk("i2o: Spurious reply to handler %d\n",
m->initiator_context&(MAX_I2O_MODULES-1));
i2o_dump_message((u32*)m);
}
i2o_flush_reply(c,mv);
mb();
+ mv=I2O_REPLY_READ32(c);
}
}
@@ -699,7 +692,6 @@ void i2o_report_controller_unit(struct i2o_controller *c, int unit)
}
if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0)
{
-
buf[16]=0;
printk(" Device: %s", buf);
}
@@ -707,7 +699,7 @@ void i2o_report_controller_unit(struct i2o_controller *c, int unit)
if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
{
buf[16]=0;
- printk(KERN_INFO "Description: %s\n", buf);
+ printk("Description: %s", buf);
}
#endif
if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0)
@@ -831,25 +823,17 @@ static int i2o_parse_lct(struct i2o_controller *c)
char str[22];
i2o_lct *lct = c->lct;
- max = lct->table_size;
+ if (lct == NULL) {
+ printk(KERN_ERR "%s: LCT is empty???\n",c->name);
+ return -1;
+ }
+ max = lct->table_size;
max -= 3;
max /= 9;
- if(max==0)
- {
- printk(KERN_ERR "%s: LCT is empty????\n",c->name);
- return -1;
- }
-
printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
- if(max > 128)
- {
- printk(KERN_INFO "%s: LCT was truncated.\n",c->name);
- max=128;
- }
-
if(lct->iop_flags&(1<<0))
printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
@@ -870,7 +854,7 @@ static int i2o_parse_lct(struct i2o_controller *c)
d->flags = 0;
tid = d->lct_data->tid;
- printk(KERN_INFO "Task ID %d.\n", tid);
+ printk(KERN_INFO "Target ID %d.\n", tid);
i2o_report_controller_unit(c, tid);
@@ -880,10 +864,10 @@ static int i2o_parse_lct(struct i2o_controller *c)
sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
printk("%s", str);
-
- printk(" Subclass: 0x%04X Flags: ",
+
+ printk(" Subclass: 0x%04X Flags: ",
d->lct_data->sub_class);
-
+
if(d->lct_data->device_flags&(1<<0))
printk("C"); // ConfigDialog requested
if(d->lct_data->device_flags&(1<<1))
@@ -899,37 +883,44 @@ static int i2o_parse_lct(struct i2o_controller *c)
}
-/* Quiesce IOP */
+/*
+ * Quiesce IOP. Causes IOP to make external operation quiescend.
+ * Internal operation of the IOP continues normally.
+ */
int i2o_quiesce_controller(struct i2o_controller *c)
{
u32 msg[4];
int ret;
- if ((c->status_block->iop_state != ADAPTER_STATE_READY) &
- (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
+ /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+
+ if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
+ (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
{
- dprintk((KERN_INFO "%s: Not in READY or OPERATIONAL state\n",
- c->name));
- dprintk((KERN_INFO "%s: state = %d\n",
- c->name, c->status_block->iop_state));
- return -EINVAL;
+ return 0;
}
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3]=0;
/* Long timeout needed for quiesce if lots of devices */
if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
- printk(KERN_INFO "%s: Unable to quiesce.\n", c->name);
+ printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n",
+ c->name, ret);
else
dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
+ i2o_status_get(c); // Reread the Status Block
+
return ret;
}
-/* Enable IOP */
+/*
+ * Enable IOP. Allows the IOP to resume external operations.
+ */
int i2o_enable_controller(struct i2o_controller *c)
{
u32 msg[4];
@@ -937,44 +928,80 @@ int i2o_enable_controller(struct i2o_controller *c)
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
/* How long of a timeout do we need? */
if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
- printk(KERN_ERR "%s: Could not enable, %d\n", c->name, ret);
+ printk(KERN_ERR "%s: Could not enable (status=%#10x).\n",
+ c->name, ret);
+ else
+ dprintk((KERN_INFO "%s: Enabled.\n", c->name));
+
+ i2o_status_get(c);
return ret;
}
-/* Reset an IOP, but keep message queues alive */
+/*
+ * Clear an IOP to HOLD state, ie. terminate external operations, clear all
+ * input queues and prepare for a system restart. IOP's internal operation
+ * continues normally and the outbound queue is alive.
+ * IOP is not expected to rebuild its LCT.
+ */
int i2o_clear_controller(struct i2o_controller *c)
{
+ struct i2o_controller *iop;
u32 msg[4];
int ret;
+ /* Quiesce all IOPs first */
+
+ for (iop = i2o_controller_chain; iop; iop = iop->next)
+ i2o_quiesce_controller(iop);
+
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3]=0;
if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
- printk(KERN_INFO "%s: Unable to clear, %#10x\n",
+ printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n",
c->name, ret);
+ else
+ dprintk((KERN_INFO "%s: Cleared.\n",c->name));
- i2o_status_get(c); // Reread the Status Block
+ i2o_status_get(c);
+
+ /* Enable other IOPs */
+
+ for (iop = i2o_controller_chain; iop; iop = iop->next)
+ if (iop != c)
+ i2o_enable_controller(iop);
return ret;
}
-/* Reset the IOP to sane state */
+/*
+ * Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ * Terminate all external operations, clear IOP's inbound and outbound
+ * queues, terminate all DDMs, and reload the IOP's operating environment
+ * and all local DDMs. IOP rebuilds its LCT.
+ */
static int i2o_reset_controller(struct i2o_controller *c)
{
+ struct i2o_controller *iop;
u32 m;
u8 *status;
u32 *msg;
long time;
+ /* Quiesce all IOPs first */
+
+ for (iop = i2o_controller_chain; iop; iop = iop->next)
+ i2o_quiesce_controller(iop);
+
m=i2o_wait_message(c, "AdapterReset");
if(m==0xFFFFFFFF)
return -ETIMEDOUT;
@@ -1013,16 +1040,14 @@ static int i2o_reset_controller(struct i2o_controller *c)
barrier();
}
- if (status[0]==0x02)
- printk(KERN_WARNING "%s: Reset rejected.\n",c->name);
- else
+ if (status[0]==0x01)
{
/*
* Once the reset is sent, the IOP goes into the INIT state
- * which is inditerminate. We need to wait until the IOP
+ * which is indeterminate. We need to wait until the IOP
* has rebooted before we can let the system talk to
* it. We read the inbound Free_List until a message is
- * available. If we can't read one in the given ammount of
+ * available. If we can't read one in the given amount of
* time, we assume the IOP could not reboot properly.
*/
@@ -1043,9 +1068,26 @@ static int i2o_reset_controller(struct i2o_controller *c)
}
i2o_flush_reply(c,m);
- printk(KERN_INFO "%s: Reset completed.\n", c->name);
+
+ dprintk((KERN_INFO "%s: Reset completed.\n", c->name));
}
+ /* If IopReset was rejected or didn't perform reset, try IopClear */
+
+ i2o_status_get(c);
+ if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET)
+ {
+ printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name);
+ i2o_clear_controller(c);
+
+ }
+
+ /* Enable other IOPs */
+
+ for (iop = i2o_controller_chain; iop; iop = iop->next)
+ if (iop != c)
+ i2o_enable_controller(iop);
+
kfree(status);
return 0;
}
@@ -1157,13 +1199,14 @@ int i2o_hrt_get(struct i2o_controller *c)
msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3]= 0;
msg[4]= (0xD0000000 | size); /* Simple transaction */
msg[5]= virt_to_phys(c->hrt); /* Dump it here */
if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
- printk(KERN_ERR "%s: Unable to get HRT,"
- " Status = %d.\n",c->name, ret);
+ printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n",
+ c->name, ret);
return ret;
}
@@ -1193,6 +1236,8 @@ static int i2o_systab_send(struct i2o_controller *iop)
iop->status->current_io_base;
iop->status->current_io_size;
#endif
+
+/* FIXME */
privmem[0]=iop->priv_mem; /* Private memory space base address */
privmem[1]=iop->priv_mem_size;
privio[0]=iop->priv_io; /* Private I/O address */
@@ -1200,7 +1245,8 @@ static int i2o_systab_send(struct i2o_controller *iop)
msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
- /* [2] and [3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3] = 0;
msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
msg[5] = 0; /* Segment 0 */
@@ -1217,8 +1263,10 @@ static int i2o_systab_send(struct i2o_controller *iop)
msg[11] = virt_to_phys(privio);
if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
- printk(KERN_INFO "%s: Unable to set SysTab, %d\n",
- iop->name, ret);
+ printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n",
+ iop->name, ret);
+ else
+ dprintk((KERN_INFO "%s: SysTab set.\n", iop->name));
return ret;
@@ -1229,292 +1277,114 @@ static int i2o_systab_send(struct i2o_controller *iop)
*/
static void __init i2o_sys_init()
{
- struct i2o_controller *iop, *niop;
- int ret;
- u32 m;
+ struct i2o_controller *iop, *niop = NULL;
printk(KERN_INFO "Activating I2O controllers\n");
printk(KERN_INFO "This may take a few minutes if there are many devices\n");
- /* Get the status for each IOP */
- for(iop = i2o_controller_chain; iop; iop = niop)
- {
- niop = iop->next;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Getting initial status for iop%d\n", iop->unit);
-#endif
- if(i2o_status_get(iop)<0)
- {
- printk("Unable to obtain status of IOP, attempting a reset.\n");
- i2o_reset_controller(iop);
- if(i2o_status_get(iop)<0)
- {
- printk("IOP not responding.\n");
- i2o_delete_controller(iop);
- continue;
- }
- }
-
- if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED)
- {
- printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
- iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
+ /* In INIT state, Activate IOPs */
- if(iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
- iop->status_block->iop_state == ADAPTER_STATE_READY ||
- iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
- iop->status_block->iop_state == ADAPTER_STATE_FAILED)
- {
- int msg[256];
-
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "iop%d already running...trying to reboot\n",
- iop->unit);
-#endif
- i2o_init_outbound_q(iop);
- I2O_REPLY_WRITE32(iop,virt_to_phys(msg));
- i2o_quiesce_controller(iop);
- i2o_reset_controller(iop);
- if(i2o_status_get(iop) ||
- iop->status_block->iop_state != ADAPTER_STATE_RESET)
- {
- printk(KERN_CRIT "Failed to initialize iop%d\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- }
- }
-
- /*
- * Now init the outbound queue for each one.
- */
- for(iop = i2o_controller_chain; iop; iop = niop)
- {
- int i;
-
+ for (iop = i2o_controller_chain; iop; iop = niop) {
niop = iop->next;
-
- if((ret=i2o_init_outbound_q(iop)))
- {
- printk(KERN_ERR
- "IOP%d initialization failed: Could not initialize outbound q\n",
- iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- iop->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
-
- if(iop->page_frame==NULL)
- {
- printk(KERN_CRIT "iop%d init failed: no memory for message page.\n",
- iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
-
- m=virt_to_phys(iop->page_frame);
-
- for(i=0; i< NMBR_MSG_FRAMES; i++)
- {
- I2O_REPLY_WRITE32(iop,m);
- mb();
- m+=MSG_FRAME_SIZE;
- mb();
- }
+ i2o_activate_controller(iop);
}
- /*
- * OK..parse the HRT
- */
- for(iop = i2o_controller_chain; iop; iop = niop)
- {
- niop = iop->next;
- if(i2o_hrt_get(iop))
- {
- printk(KERN_CRIT "iop%d: Could not get HRT!\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- if(i2o_parse_hrt(iop))
- {
- printk(KERN_CRIT "iop%d: Could not parse HRT!\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- }
+ /* Active IOPs in HOLD state */
+
+rebuild_sys_tab:
+ if (i2o_controller_chain == NULL)
+ return;
/*
- * Build and send the system table
- *
* If build_sys_table fails, we kill everything and bail
* as we can't init the IOPs w/o a system table
*/
- if(i2o_build_sys_table())
- {
- printk(KERN_CRIT "I2O: Error building system table. Aborting!\n");
+ if (i2o_build_sys_table() < 0) {
i2o_sys_shutdown();
return;
}
- for(iop = i2o_controller_chain; iop; iop = niop)
-#ifdef DRIVERDEBUG
- {
- niop = iop->next;
- printk(KERN_INFO "Sending system table to iop%d\n", iop->unit);
-#endif
- if(i2o_systab_send(iop))
- {
- printk(KERN_CRIT "iop%d: Error sending system table\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
-#ifdef DRIVERDEBUG
- }
-#endif
-
- /*
- * Enable
- */
- for(iop = i2o_controller_chain; iop; iop = niop)
- {
- niop = iop->next;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Enabling iop%d\n", iop->unit);
-#endif
- if(i2o_enable_controller(iop))
- {
- printk(KERN_ERR "Could not enable iop%d\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- }
-
- /*
- * OK..one last thing and we're ready to go!
- */
- for(iop = i2o_controller_chain; iop; iop = niop)
- {
+ /* If IOP don't get online, we need to rebuild the System table */
+ for (iop = i2o_controller_chain; iop; iop = niop) {
niop = iop->next;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Getting LCT for iop%d\n", iop->unit);
-#endif
- if(i2o_lct_get(iop))
- {
- printk(KERN_ERR "Could not get LCT from iop%d\n", iop->unit);
- i2o_delete_controller(iop);
- continue;
- }
- else
- i2o_parse_lct(iop);
+ if (i2o_online_controller(iop) < 0)
+ goto rebuild_sys_tab;
}
+
+ /* Active IOPs now in OPERATIONAL state */
}
/*
* Shutdown I2O system
- *
- * 1. Quiesce all controllers
- * 2. Delete all controllers
*/
static void i2o_sys_shutdown(void)
{
struct i2o_controller *iop, *niop;
- for (iop = i2o_controller_chain; iop ; iop=iop->next) {
- i2o_quiesce_controller(iop);
- i2o_status_get(iop); // Update IOP status block
- }
+ /* Delete all IOPs from the controller chain */
+ /* that will reset all IOPs too */
for (iop = i2o_controller_chain; iop; iop = niop) {
niop = iop->next;
- if (i2o_delete_controller(iop))
- iop->bus_disable(iop);
+ i2o_delete_controller(iop);
}
}
/*
- * Bring an I2O controller into HOLD state. See the 1.5
- * spec. Basically we go
- *
- * Wait for the message queue to initialise.
- * If it didnt -> controller is dead
- *
- * Send a get status using the message queue
- * Poll for a reply block 88 bytes long
- *
- * Send an initialise outbound queue
- * Poll for a reply
- *
- * Post our blank messages to the queue FIFO
- *
- * Send GetHRT, Parse it
+ * Bring an I2O controller into HOLD state. See the spec.
*/
-int i2o_activate_controller(struct i2o_controller *c)
+int i2o_activate_controller(struct i2o_controller *iop)
{
- return 0;
-#ifdef I2O_HOTPLUG_SUPPORT
- u32 m;
- int i;
- int ret;
-
- printk(KERN_INFO "%s: Configuring I2O controller at 0x%08X.\n",
- c->name, (u32)c->mem_phys);
-
- if((ret=i2o_status_get(c)))
- return ret;
+ /* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */
+ /* In READY state, Get status */
+
+ if (i2o_status_get(iop) < 0) {
+ printk("Unable to obtain status of IOP, attempting a reset.\n");
+ i2o_reset_controller(iop);
+ if (i2o_status_get(iop) < 0) {
+ printk("IOP not responding.\n");
+ i2o_delete_controller(iop);
+ return -1;
+ }
+ }
- /* not likely to be seen */
- if(c->status_block->iop_state == ADAPTER_STATE_FAULTED)
- {
- printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
- c->unit);
+ if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
+ printk(KERN_CRIT "%s: hardware fault\n", iop->name);
+ i2o_delete_controller(iop);
return -1;
}
- /*
- * If the board is running, reset it - we have no idea
- * what kind of a mess the previous owner left it in.
- * We need to feed the IOP a single outbound message
- * so that it can reply back to the ExecSysQuiesce.
- */
- if(c->status_block->iop_state == ADAPTER_STATE_HOLD ||
- c->status_block->iop_state == ADAPTER_STATE_READY ||
- c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
- c->status_block->iop_state == ADAPTER_STATE_FAILED)
+// if (iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
+ if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
+ iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+ iop->status_block->iop_state == ADAPTER_STATE_FAILED)
{
- int msg[256];
- printk(KERN_INFO "i2o/iop%d already running, reseting\n", c->unit);
+ dprintk((KERN_INFO "%s: already running...trying to reset\n",
+ iop->name));
+ i2o_reset_controller(iop);
- if(i2o_init_outbound_q(c));
- I2O_REPLY_WRITE32(c,virt_to_phys(msg));
-
- if((ret=i2o_reset_controller(c)))
- return ret;
-
- if((ret=i2o_status_get(c)))
- return ret;
+ if (i2o_status_get(iop) < 0 ||
+ iop->status_block->iop_state != ADAPTER_STATE_RESET)
+ {
+ printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name);
+ i2o_delete_controller(iop);
+ return -1;
+ }
}
- if ((ret=i2o_init_outbound_q(c))){
- return ret;
+ if (i2o_init_outbound_q(iop) < 0) {
+ i2o_delete_controller(iop);
+ return -1;
}
- /* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
-
- /*
- * The outbound queue is initialised and loaded,
- *
- * Now we need the Hardware Resource Table. We must ask for
- * this next we can't issue random messages yet.
- */
-
- if ((ret=i2o_hrt_get(c)))
- return ret;
+ /* In HOLD state */
+
+ if (i2o_hrt_get(iop) < 0) {
+ i2o_delete_controller(iop);
+ return -1;
+ }
- return i2o_online_controller(c);
-#endif
+ return 0;
}
/*
@@ -1533,7 +1403,6 @@ int i2o_init_outbound_q(struct i2o_controller *c)
return -ETIMEDOUT;
msg=(u32 *)(c->mem_offset+m);
-
status = kmalloc(4,GFP_KERNEL);
if (status==NULL) {
printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
@@ -1568,6 +1437,8 @@ int i2o_init_outbound_q(struct i2o_controller *c)
barrier();
}
+ /* Alloc space for IOP's outbound queue message frames */
+
c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
if(c->page_frame==NULL) {
printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
@@ -1577,6 +1448,8 @@ int i2o_init_outbound_q(struct i2o_controller *c)
}
m=virt_to_phys(c->page_frame);
+ /* Post frames */
+
for(i=0; i< NMBR_MSG_FRAMES; i++) {
I2O_REPLY_WRITE32(c,m);
mb();
@@ -1608,15 +1481,16 @@ int i2o_lct_get(struct i2o_controller *c)
msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3] = 0;
msg[4] = 0xFFFFFFFF; /* All devices */
msg[5] = 0x00000000; /* Report now */
msg[6] = 0xD0000000|size;
msg[7] = virt_to_bus(c->lct);
if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
- printk(KERN_ERR "%s: Unable to get LCT,"
- " Status = %d.\n", c->name,ret);
+ printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n",
+ c->name, ret);
return ret;
}
@@ -1627,83 +1501,39 @@ int i2o_lct_get(struct i2o_controller *c)
}
} while (c->lct == NULL);
+ if ((ret=i2o_parse_lct(c)) < 0)
+ return ret;
+
return 0;
}
/*
- * Bring a controller online. Needs completing for multiple controllers
+ * Bring a controller online into OPERATIONAL state.
*/
-int i2o_online_controller(struct i2o_controller *c)
+int i2o_online_controller(struct i2o_controller *iop)
{
- return 0;
-#ifdef I2O_HOTPLUG_SUPPORT
- u32 msg[10];
- u32 privmem[2];
- u32 privio[2];
- int ret;
+ if (i2o_systab_send(iop) < 0) {
+ i2o_delete_controller(iop);
+ return -1;
+ }
- /*
- * Build and send the system table
- *
- * If build_sys_table fails, we kill everything and bail
- * as we can't init the IOPs w/o a system table
- */
-
- if (i2o_build_sys_table()) {
- i2o_sys_shutdown();
- return;
- }
-
- privmem[0]=c->priv_mem; /* Private memory space base address */
- privmem[1]=c->priv_mem_size;
- privio[0]=c->priv_io; /* Private I/O address */
- privio[1]=c->priv_io_size;
-
- __raw_writel(TEN_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
- __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg$
- __raw_writel(0, &msg[2]); /* Context not needed */
- __raw_writel(0, &msg[3]);
- __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
- __raw_writel(0, &msg[5]); /* Segment 1 */
-
- /*
- * Scatter Gather List
- */
-
- __raw_writel(0x54000000|sys_tbl_len, &msg[6]); /* One table for now */
- __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
- __raw_writel(0xD4000000|48, &msg[8]); /* One table for now */
- __raw_writel(virt_to_phys(privmem), &msg[9]);
-
- ret = (i2o_post_wait(c, msg, sizeof(msg), 120);
- if (ret)
- return ret;
-
- /*
- * Finally we go online
- */
- ret = i2o_enable_controller(c);
- if(ret)
- return ret;
+ /* In READY state */
- /*
- * Grab the LCT, see what is attached
- */
- ret=i2o_lct_get(c);
- if(ret)
- {
- /* Maybe we should do also do something else */
- return ret;
- }
+ if (i2o_enable_controller(iop) < 0) {
+ i2o_delete_controller(iop);
+ return -1;
+ }
- ret=i2o_parse_lct(c);
- if(ret)
- return ret;
+ /* In OPERATIONAL state */
- return 0;
-#endif
+ if (i2o_lct_get(iop) < 0){
+ i2o_delete_controller(iop);
+ return -1;
+ }
+
+ return 0;
}
static int i2o_build_sys_table(void)
@@ -1923,7 +1753,8 @@ int i2o_event_ack(struct i2o_controller *c, int tid, int context,
msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ msg[2] = context;
+ msg[3] = 0;
msg[4] = evt_indicator;
memcpy(msg+5, evt_data, evt_data_len);
@@ -1947,9 +1778,10 @@ static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int o
else
msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
- /* msg[2] and msg[3] filled in i2o_post_wait */
+ /* msg[2] filled in i2o_post_wait */
+ msg[3] = 0;
msg[4] = type;
-
+
return i2o_post_wait(c, msg, sizeof(msg), 2);
}
@@ -1970,6 +1802,8 @@ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid,
msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
msg[1] = cmd << 24 | HOST_TID << 12 | tid;
+ /* msg[2] filled in i2o_post_wait */
+ msg[3] = 0;
msg[4] = 0;
msg[5] = 0x54000000 | oplen; /* OperationBlock */
msg[6] = virt_to_bus(opblk);
@@ -2515,7 +2349,7 @@ void i2o_report_status(const char *severity, const char *module, u32 *msg)
}
/* Used to dump a message to syslog during debugging */
-static void i2o_dump_message(u32 *msg)
+void i2o_dump_message(u32 *msg)
{
#ifdef DRIVERDEBUG
int i;
@@ -2531,10 +2365,7 @@ static void i2o_dump_message(u32 *msg)
EXPORT_SYMBOL(i2o_install_handler);
EXPORT_SYMBOL(i2o_remove_handler);
-EXPORT_SYMBOL(i2o_install_device);
-EXPORT_SYMBOL(i2o_delete_device);
-EXPORT_SYMBOL(i2o_quiesce_controller);
-EXPORT_SYMBOL(i2o_clear_controller);
+
EXPORT_SYMBOL(i2o_install_controller);
EXPORT_SYMBOL(i2o_delete_controller);
EXPORT_SYMBOL(i2o_unlock_controller);
@@ -2547,9 +2378,7 @@ EXPORT_SYMBOL(i2o_event_ack);
EXPORT_SYMBOL(i2o_claim_device);
EXPORT_SYMBOL(i2o_release_device);
EXPORT_SYMBOL(i2o_run_queue);
-EXPORT_SYMBOL(i2o_report_controller_unit);
EXPORT_SYMBOL(i2o_activate_controller);
-EXPORT_SYMBOL(i2o_online_controller);
EXPORT_SYMBOL(i2o_get_class_name);
EXPORT_SYMBOL(i2o_status_get);
@@ -2558,7 +2387,6 @@ EXPORT_SYMBOL(i2o_set_scalar);
EXPORT_SYMBOL(i2o_query_table);
EXPORT_SYMBOL(i2o_clear_table);
EXPORT_SYMBOL(i2o_row_add_table);
-EXPORT_SYMBOL(i2o_row_delete_table);
EXPORT_SYMBOL(i2o_post_this);
EXPORT_SYMBOL(i2o_post_wait);
@@ -2632,7 +2460,7 @@ int __init i2o_init(void)
#endif
if(i2o_num_controllers)
- i2o_init();
+ i2o_sys_init();
i2o_config_init();
#ifdef CONFIG_I2O_BLOCK
diff --git a/drivers/i2o/i2o_lan.c b/drivers/i2o/i2o_lan.c
index 08fcc2c2c..d6aa43398 100644
--- a/drivers/i2o/i2o_lan.c
+++ b/drivers/i2o/i2o_lan.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/i2o/i2o_lan.c
*
- * I2O LAN CLASS OSM December 2nd 1999
+ * I2O LAN CLASS OSM January 7th 1999
*
* (C) Copyright 1999 University of Helsinki,
* Department of Computer Science
@@ -18,7 +18,8 @@
* Deepak Saxena <deepak@plexity.net>
*
* Tested: in FDDI environment (using SysKonnect's DDM)
- * in Ethernet environment (using Intel 82558 DDM proto)
+ * in Gigabit Eth environment (using SysKonnect's DDM)
+ * in Fast Ethernet environment (using Intel 82558 DDM)
*
* TODO: check error checking / timeouts
* code / test for other LAN classes
@@ -68,11 +69,12 @@ struct i2o_lan_local {
unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
u32 bucket_count; /* nbr of buckets sent to DDM */
u32 tx_count; /* packets in one TX message frame */
- u32 tx_max; /* DDM's Tx queue len */
+ u32 tx_max_out; /* DDM's Tx queue len */
u32 tx_out; /* outstanding TXes */
u32 sgl_max; /* max SGLs in one message frame */
u32 m; /* IOP address of msg frame */
+ struct tq_struct i2o_batch_send_task;
struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */
int i2o_fbl_tail;
@@ -98,6 +100,9 @@ static struct tq_struct i2o_post_buckets_task = {
0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
};
+/*
+ * i2o_lan_reply(): The only callback function to handle incoming messages.
+ */
static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
struct i2o_message *m)
{
@@ -133,7 +138,7 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
}
// Something VERY wrong if this is happening
- printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name);
+ printk( KERN_WARNING "%s: rejected bucket post.\n", dev->name);
}
// Shutting down, we are getting unused buckets back
@@ -165,7 +170,7 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
break;
}
- case LAN_RESET:
+ case LAN_RESET: /* default reply without payload */
case LAN_SUSPEND:
break;
@@ -175,12 +180,14 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
break;
default:
- printk(KERN_ERR "%s: Sorry, no handler for the reply.\n", dev->name);
+ printk(KERN_ERR "%s: No handler for the reply.\n", dev->name);
i2o_report_status(KERN_INFO, dev->name, msg);
}
}
-
+/*
+ * i2o_lan_event_reply(): Handle events.
+ */
static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -277,6 +284,9 @@ static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
/* Do we need to do something here too? */
}
+/*
+ * i2o_lan_release_buckets(): Handle unused buckets.
+ */
static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -292,6 +302,9 @@ static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
}
}
+/*
+ * i2o_lan_receive_post_reply(): Process incoming packets.
+ */
static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -332,15 +345,17 @@ static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
bucket++; // to next Packet Descriptor Block
}
- if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN)
- printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n",
- dev->name, msg[5]);
+#ifdef DRIVERDEBUG
+ if (msg[5] == 0)
+ printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n",
+ dev->name, priv->bucket_count);
+#endif
if (priv->bucket_count <= bucketpost - bucketthresh) {
-// i2o_lan_receive_post(dev);
i2o_post_buckets_task.data = (void *)dev;
queue_task(&i2o_post_buckets_task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
+ /* Note: the task is queued only once */
}
return 0;
@@ -415,6 +430,7 @@ static int i2o_lan_reset(struct net_device *dev)
struct i2o_controller *iop = i2o_dev->controller;
u32 msg[5];
+ dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name);
msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
@@ -453,7 +469,7 @@ static int i2o_lan_suspend(struct net_device *dev)
}
/*
- * Set DDM into batch mode.
+ * i2o_set_batch_mode(): Set DDM into batch mode.
*/
static void i2o_set_batch_mode(struct net_device *dev)
{
@@ -498,9 +514,10 @@ static int i2o_lan_open(struct net_device *dev)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_device *i2o_dev = priv->i2o_dev;
+#if 0
struct i2o_controller *iop = i2o_dev->controller;
- u32 evt_mask = 0xFFC00007; // All generic events, all lan evenst
-
+ u32 evt_mask = 0xFFC00007; // All generic events, all lan events
+#endif
if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
return -EAGAIN;
@@ -543,8 +560,8 @@ static int i2o_lan_close(struct net_device *dev)
if (i2o_event_register(iop, i2o_dev->lct_data->tid,
priv->unit << 16 | lan_context, 0) < 0)
printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
- dev->name);
-#endif
+#endif dev->name);
+
dev->tbusy = 1;
dev->start = 0;
i2o_lan_suspend(dev);
@@ -586,10 +603,6 @@ static void i2o_lan_batch_send(struct net_device *dev)
}
}
-struct tq_struct i2o_post_send_task = {
- 0, 0, (void (*)(void *))i2o_lan_batch_send, (void *) 0
-};
-
/*
* i2o_lan_packet_send(): Send a packet as is, including the MAC header.
*
@@ -598,8 +611,8 @@ struct tq_struct i2o_post_send_task = {
*/
static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
{
- struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
- struct i2o_device *i2o_dev = priv->i2o_dev;
+ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+ struct i2o_device *i2o_dev = priv->i2o_dev;
struct i2o_controller *iop = i2o_dev->controller;
u32 m, *msg;
u32 *sgl_elem;
@@ -616,7 +629,7 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
priv->tx_count++;
priv->tx_out++;
- if (priv->tx_count == 1) {
+ if (priv->tx_count == 1) {
dprintk("%s: New message frame\n", dev->name);
m = I2O_POST_READ32(iop);
@@ -635,42 +648,40 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
__raw_writel((u32)skb, msg+5); // TransactionContext
__raw_writel(virt_to_bus(skb->data), msg+6);
- i2o_post_send_task.data = (void *)dev;
- queue_task(&i2o_post_send_task, &tq_scheduler);
-
- if (priv->tx_out < priv->tx_max)
- clear_bit(0, (void *)&dev->tbusy);
-
- return 0;
- }
-
- /* Else add new SGL element to the previous message frame */
-
- dprintk("%s: Adding packet %d to msg frame\n", dev->name, priv->tx_count);
+ queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
- msg = (u32 *)(iop->mem_offset + priv->m);
- sgl_elem = &msg[priv->tx_count * 3 + 1];
+ } else { /* Add new SGL element to the previous message frame */
- __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
- __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
- __raw_writel(0xD5000000 | skb->len, sgl_elem);
- __raw_writel((u32)skb, sgl_elem+1);
- __raw_writel(virt_to_bus(skb->data), sgl_elem+2);
-
- if (priv->tx_count == priv->sgl_max) { /* frame full, send now */
-// i2o_lan_batch_send(dev);
- i2o_post_message(iop, priv->m);
- dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);
- priv->tx_count = 0;
+ dprintk("%s: Adding packet %d to msg frame\n",
+ dev->name, priv->tx_count);
+
+ msg = (u32 *)(iop->mem_offset + priv->m);
+ sgl_elem = &msg[priv->tx_count * 3 + 1];
+
+ __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
+ __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
+ __raw_writel(0xD5000000 | skb->len, sgl_elem);
+ __raw_writel((u32)skb, sgl_elem+1);
+ __raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+
+ if (priv->tx_count == priv->sgl_max) { /* frame full, send now */
+ i2o_post_message(iop, priv->m);
+ dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);
+ priv->tx_count = 0;
+ }
}
+
+ /* If HDMs TxMaxPktOut reached, stay busy (don't clean tbusy) */
- if (priv->tx_out < priv->tx_max)
+ if (priv->tx_out < priv->tx_max_out)
clear_bit(0, (void *)&dev->tbusy);
-
+
return 0;
}
-
+/*
+ * i2o_lan_get_stats(): Fill in the statistics.
+ */
static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -882,12 +893,27 @@ static void i2o_lan_set_multicast_list(struct net_device *dev)
queue_task(task, &tq_scheduler);
}
+/*
+ * i2o_lan_change_mtu(): Change maximum transfer unit size.
+ */
+static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > 9000))
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/*
+ * i2o_lan_register_device(): Register LAN class device to kernel.
+ */
struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
{
struct net_device *dev = NULL;
struct i2o_lan_local *priv = NULL;
u8 hw_addr[8];
- u32 tx_max = 0;
+ u32 tx_max_out = 0;
unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
void (*unregister_dev)(struct net_device *dev);
@@ -981,7 +1007,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
memcpy(dev->dev_addr, hw_addr, 6);
if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
- 0x0007, 2, &tx_max, sizeof(tx_max)) < 0)
+ 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0)
{
printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
unit--;
@@ -989,17 +1015,23 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
kfree(dev);
return NULL;
}
- dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max);
- priv->tx_max = tx_max;
+ dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
+ priv->tx_max_out = tx_max_out;
priv->tx_out = 0;
priv->tx_count = 0;
priv->lock = SPIN_LOCK_UNLOCKED;
+ priv->i2o_batch_send_task.next = NULL;
+ priv->i2o_batch_send_task.sync = 0;
+ priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
+ priv->i2o_batch_send_task.data = (void *)dev;
+
dev->open = i2o_lan_open;
dev->stop = i2o_lan_close;
dev->hard_start_xmit = i2o_lan_packet_send;
dev->get_stats = i2o_lan_get_stats;
dev->set_multicast_list = i2o_lan_set_multicast_list;
+ dev->change_mtu = i2o_lan_change_mtu;
return dev;
}
diff --git a/drivers/i2o/i2o_lan.h b/drivers/i2o/i2o_lan.h
index 7cd22e9ac..d4e5aa44b 100644
--- a/drivers/i2o/i2o_lan.h
+++ b/drivers/i2o/i2o_lan.h
@@ -18,7 +18,7 @@
/* Tunable parameters first */
#define I2O_BUCKET_COUNT 256
-#define I2O_BUCKET_THRESH 8
+#define I2O_BUCKET_THRESH 18 /* 9 buckets in one message */
/* LAN types */
#define I2O_LAN_ETHERNET 0x0030
diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c
index 2d1c06ddc..ed89973eb 100644
--- a/drivers/i2o/i2o_proc.c
+++ b/drivers/i2o/i2o_proc.c
@@ -29,7 +29,7 @@
/*
* TODO List
*
- * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
+ * - Add support for any version 2.0 spec changes once 2.0 IRTOS
* is available to test with
* - Clean up code to use official structure definitions
*/
@@ -64,8 +64,6 @@ typedef struct _i2o_proc_entry_t
write_proc_t *write_proc; /* write func */
} i2o_proc_entry;
-static int proc_context = 0;
-
static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
@@ -101,8 +99,6 @@ static void i2o_proc_remove_controller(struct i2o_controller *,
struct proc_dir_entry * );
static int create_i2o_procfs(void);
static int destroy_i2o_procfs(void);
-static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *,
- struct i2o_message *);
static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
void *);
@@ -134,17 +130,6 @@ static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
static struct proc_dir_entry *i2o_proc_dir_root;
/*
- * Message handler
- */
-static struct i2o_handler i2o_proc_handler =
-{
- (void *)i2o_proc_reply,
- "I2O procfs Layer",
- 0,
- 0xffffffff // All classes
-};
-
-/*
* IOP specific entries...write field just in case someone
* ever wants one.
*/
@@ -255,9 +240,6 @@ static i2o_proc_entry lan_fddi_entries[] =
{NULL, 0, NULL, NULL}
};
-
-static u32 i2o_proc_token = 0;
-
static char *chtostr(u8 *chars, int n)
{
char tmp[256];
@@ -295,12 +277,6 @@ static char* bus_strings[] =
static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
-void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl,
- struct i2o_message *pmsg)
-{
- i2o_proc_token = I2O_POST_WAIT_OK;
-}
-
int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
int *eof, void *data)
{
@@ -681,7 +657,7 @@ int i2o_proc_read_status(char *buf, char **start, off_t offset, int len,
c->status_block->expected_lct_size);
len += sprintf(buf+len,"IOP Capabilities\n");
- len += sprintf(buf+len," Context Field Size Support : ");
+ len += sprintf(buf+len," Context Field Size Support : ");
switch (c->status_block->iop_capabilities & 0x0000003) {
case 0:
len += sprintf(buf+len,"Supports only 32-bit context fields\n");
@@ -700,7 +676,7 @@ int i2o_proc_read_status(char *buf, char **start, off_t offset, int len,
default:
len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
}
- len += sprintf(buf+len," Current Context Field Size : ");
+ len += sprintf(buf+len," Current Context Field Size : ");
switch (c->status_block->iop_capabilities & 0x0000000C) {
case 0:
len += sprintf(buf+len,"not configured\n");
@@ -718,11 +694,11 @@ int i2o_proc_read_status(char *buf, char **start, off_t offset, int len,
default:
len += sprintf(buf+len,"\n");
}
- len += sprintf(buf+len," Inbound Peer Support : %s\n",
+ len += sprintf(buf+len," Inbound Peer Support : %s\n",
(c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
- len += sprintf(buf+len," Outbound Peer Support : %s\n",
+ len += sprintf(buf+len," Outbound Peer Support : %s\n",
(c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
- len += sprintf(buf+len," Peer to Peer Support : %s\n",
+ len += sprintf(buf+len," Peer to Peer Support : %s\n",
(c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
len += sprintf(buf+len, "Desired private memory size : %d kB\n",
@@ -790,17 +766,17 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10);
hwcap = work32[3];
- len += sprintf(buf+len, "Capabilities :\n");
- if(hwcap&0x00000001)
- len += sprintf(buf+len, " Self-booting\n");
- if(hwcap&0x00000002)
- len += sprintf(buf+len, " Upgradable IRTOS\n");
- if(hwcap&0x00000004)
- len += sprintf(buf+len, " Supports downloading DDMs\n");
- if(hwcap&0x00000008)
- len += sprintf(buf+len, " Supports installing DDMs\n");
- if(hwcap&0x00000010)
- len += sprintf(buf+len, " Battery-backed RAM\n");
+ len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap);
+ len += sprintf(buf+len, " [%s] Self booting\n",
+ (hwcap&0x00000001) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Upgradable IRTOS\n",
+ (hwcap&0x00000002) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Supports downloading DDMs\n",
+ (hwcap&0x00000004) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Supports installing DDMs\n",
+ (hwcap&0x00000008) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Battery-backed RAM\n",
+ (hwcap&0x00000010) ? "+" : "-");
spin_unlock(&i2o_proc_lock);
@@ -1695,23 +1671,23 @@ int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len,
break;
}
- len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable);
- if (result.event_enable & 0x01)
- len += sprintf(buf+len, "\tOperational state change. \n");
- if (result.event_enable & 0x02)
- len += sprintf(buf+len, "\tLow catastrophic. \n");
- if (result.event_enable & 0x04)
- len += sprintf(buf+len, "\tLow reading. \n");
- if (result.event_enable & 0x08)
- len += sprintf(buf+len, "\tLow warning. \n");
- if (result.event_enable & 0x10)
- len += sprintf(buf+len, "\tChange back to normal from out of range state. \n");
- if (result.event_enable & 0x20)
- len += sprintf(buf+len, "\tHigh warning. \n");
- if (result.event_enable & 0x40)
- len += sprintf(buf+len, "\tHigh reading. \n");
- if (result.event_enable & 0x80)
- len += sprintf(buf+len, "\tHigh catastrophic. \n");
+ len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable);
+ len += sprintf(buf+len, " [%s] Operational state change. \n",
+ (result.event_enable & 0x01) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] Low catastrophic. \n",
+ (result.event_enable & 0x02) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] Low reading. \n",
+ (result.event_enable & 0x04) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] Low warning. \n",
+ (result.event_enable & 0x08) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n",
+ (result.event_enable & 0x10) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] High warning. \n",
+ (result.event_enable & 0x20) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] High reading. \n",
+ (result.event_enable & 0x40) ? "+" : "-" );
+ len += sprintf(buf+len, " [%s] High catastrophic. \n",
+ (result.event_enable & 0x80) ? "+" : "-" );
spin_unlock(&i2o_proc_lock);
return len;
@@ -2187,38 +2163,37 @@ int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len,
work8[16],work8[17],work8[18],work8[19],
work8[20],work8[21],work8[22],work8[23]);
- len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]);
- len += sprintf(buf+len, " Unicast packets %ssupported\n",
- (work32[7]&0x00000001)?"":"not ");
- len += sprintf(buf+len, " Promiscuous mode %ssupported\n",
- (work32[7]&0x00000002)?"":"not");
- len += sprintf(buf+len, " Promiscuous multicast mode %ssupported\n",
- (work32[7]&0x00000004)?"":"not ");
- len += sprintf(buf+len," Broadcast reception disabling %ssupported\n",
- (work32[7]&0x00000100)?"":"not ");
- len += sprintf(buf+len," Multicast reception disabling %ssupported\n",
- (work32[7]&0x00000200)?"":"not ");
- len += sprintf(buf+len," Functional address disabling %ssupported\n",
- (work32[7]&0x00000400)?"":"not ");
- len += sprintf(buf+len, " MAC reporting %ssupported\n",
- (work32[7]&0x00000800)?"":"not ");
-
- len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]);
- len += sprintf(buf+len, " Unicast packets %s\n",
- (work32[6]&0x00000001)?"rejected":"enabled");
- len += sprintf(buf+len, " Promiscuous mode %s\n",
- (work32[6]&0x00000002)?"enabled":"disabled");
- len += sprintf(buf+len, " Promiscuous multicast mode %s\n",
- (work32[6]&0x00000004)?"enabled":"disabled");
- len += sprintf(buf+len, " Broadcast packets %s\n",
- (work32[6]&0x00000100)?"rejected":"enabled");
- len += sprintf(buf+len, " Multicast packets %s\n",
- (work32[6]&0x00000200)?"rejected":"enabled");
- len += sprintf(buf+len, " Functional address %s\n",
- (work32[6]&0x00000400)?"ignored":"enabled");
+ len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]);
+ len += sprintf(buf+len," [%s] Unicast packets supported\n",
+ (work32[7]&0x00000001)?"+":"-");
+ len += sprintf(buf+len," [%s] Promiscuous mode supported\n",
+ (work32[7]&0x00000002)?"+":"-");
+ len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n",
+ (work32[7]&0x00000004)?"+":"-");
+ len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n",
+ (work32[7]&0x00000100)?"+":"-");
+ len += sprintf(buf+len," [%s] Multicast reception disabling supported\n",
+ (work32[7]&0x00000200)?"+":"-");
+ len += sprintf(buf+len," [%s] Functional address disabling supported\n",
+ (work32[7]&0x00000400)?"+":"-");
+ len += sprintf(buf+len," [%s] MAC reporting supported\n",
+ (work32[7]&0x00000800)?"+":"-");
+
+ len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]);
+ len += sprintf(buf+len," [%s] Unicast packets disable\n",
+ (work32[6]&0x00000001)?"+":"-");
+ len += sprintf(buf+len," [%s] Promiscuous mode enable\n",
+ (work32[6]&0x00000002)?"+":"-");
+ len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n",
+ (work32[6]&0x00000004)?"+":"-");
+ len += sprintf(buf+len," [%s] Broadcast packets disable\n",
+ (work32[6]&0x00000100)?"+":"-");
+ len += sprintf(buf+len," [%s] Multicast packets disable\n",
+ (work32[6]&0x00000200)?"+":"-");
+ len += sprintf(buf+len," [%s] Functional address disable\n",
+ (work32[6]&0x00000400)?"+":"-");
- if (work32[7]&0x00000800)
- {
+ if (work32[7]&0x00000800) {
len += sprintf(buf+len, " MAC reporting mode : ");
if (work32[6]&0x00000800)
len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
@@ -2321,28 +2296,10 @@ int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
len += sprintf(buf+len, ", toggle");
len += sprintf(buf+len, "\n");
- if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
- len += sprintf(buf+len, "Rising load delay : %d ms\n",
- work32[1]/10);
- len += sprintf(buf+len, "Rising load threshold : %d ms\n",
- work32[2]/10);
- len += sprintf(buf+len, "Falling load delay : %d ms\n",
- work32[3]/10);
- len += sprintf(buf+len, "Falling load threshold : %d ms\n",
- work32[4]/10);
- }
-
- len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
- len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
-
- if(d->i2oversion == 0x00) {
- len += sprintf(buf+len,
- "Transmission completion reporting delay : %d ms\n",
- work32[7]);
- } else {
- len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
- len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
- }
+ len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
+ len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
+ len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
+ len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
spin_unlock(&i2o_proc_lock);
return len;
@@ -2374,37 +2331,35 @@ int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
(work32[1]&0x2)?"by host":"by DDM");
len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]);
- len += sprintf(buf+len, "Tx modes :\n");
- if (work32[3]&0x00000004)
- len += sprintf(buf+len, " HW CRC supressed\n");
- else
- len += sprintf(buf+len, " HW CRC\n");
- if (work32[3]&0x00000100)
- len += sprintf(buf+len, " HW IPv4 checksumming\n");
- if (work32[3]&0x00000200)
- len += sprintf(buf+len, " HW TCP checksumming\n");
- if (work32[3]&0x00000400)
- len += sprintf(buf+len, " HW UDP checksumming\n");
- if (work32[3]&0x00000800)
- len += sprintf(buf+len, " HW RSVP checksumming\n");
- if (work32[3]&0x00001000)
- len += sprintf(buf+len, " HW ICMP checksumming\n");
- if (work32[3]&0x00002000)
- len += sprintf(buf+len, " Loopback packet not delivered\n");
-
- len += sprintf(buf+len, "Rx modes :\n");
- if (work32[4]&0x00000004)
- len += sprintf(buf+len, " FCS in payload\n");
- if (work32[4]&0x00000100)
- len += sprintf(buf+len, " HW IPv4 checksum validation\n");
- if (work32[4]&0x00000200)
- len += sprintf(buf+len, " HW TCP checksum validation\n");
- if (work32[4]&0x00000400)
- len += sprintf(buf+len, " HW UDP checksum validation\n");
- if (work32[4]&0x00000800)
- len += sprintf(buf+len, " HW RSVP checksum validation\n");
- if (work32[4]&0x00001000)
- len += sprintf(buf+len, " HW ICMP checksum validation\n");
+ len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]);
+ len += sprintf(buf+len, " [%s] HW CRC supression\n",
+ (work32[3]&0x00000004) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW IPv4 checksum\n",
+ (work32[3]&0x00000100) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW TCP checksum\n",
+ (work32[3]&0x00000200) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW UDP checksum\n",
+ (work32[3]&0x00000400) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW RSVP checksum\n",
+ (work32[3]&0x00000800) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW ICMP checksum\n",
+ (work32[3]&0x00001000) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Loopback supression enable\n",
+ (work32[3]&0x00002000) ? "+" : "-");
+
+ len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]);
+ len += sprintf(buf+len, " [%s] FCS in payload\n",
+ (work32[4]&0x00000004) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n",
+ (work32[4]&0x00000100) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW TCP checksum validation\n",
+ (work32[4]&0x00000200) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW UDP checksum validation\n",
+ (work32[4]&0x00000400) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n",
+ (work32[4]&0x00000800) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n",
+ (work32[4]&0x00001000) ? "+" : "-");
spin_unlock(&i2o_proc_lock);
return len;
@@ -2471,16 +2426,8 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
len += sprintf(buf+len, "Unspecified\n");
}
- if (d->i2oversion == 0x00) /* Reserved in 1.53 and 2.0 */
- {
- len += sprintf(buf+len, "Bad packets handled by : %s\n",
- (result.reserved == 0xFF)?"host":"DDM");
- }
- else
- {
- len += sprintf(buf+len, "Duplex mode target : ");
- switch (result.duplex_mode_target)
- {
+ len += sprintf(buf+len, "Duplex mode target : ");
+ switch (result.duplex_mode_target){
case 0:
len += sprintf(buf+len, "Half duplex\n");
break;
@@ -2489,14 +2436,13 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
break;
default:
len += sprintf(buf+len, "\n");
- }
-
- len += sprintf(buf+len, "Connector type target : %s\n",
- i2o_get_connector_type(result.connector_type_target));
- len += sprintf(buf+len, "Connection type target : %s\n",
- i2o_get_connection_type(result.connection_type_target));
}
+ len += sprintf(buf+len, "Connector type target : %s\n",
+ i2o_get_connector_type(result.connector_type_target));
+ len += sprintf(buf+len, "Connection type target : %s\n",
+ i2o_get_connection_type(result.connection_type_target));
+
spin_unlock(&i2o_proc_lock);
return len;
}
@@ -2568,46 +2514,34 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
return len;
}
- len += sprintf(buf, "Max SG Elements per packet : %d\n", work32[0]);
- len += sprintf(buf+len, "Max SG Elements per chain : %d\n", work32[1]);
- len += sprintf(buf+len, "Max outstanding packets : %d\n", work32[2]);
- len += sprintf(buf+len, "Max packets per request : %d\n", work32[3]);
-
- len += sprintf(buf+len, "Tx modes :\n");
- if(work32[4]&0x00000002)
- len += sprintf(buf+len, " No DA in SGL\n");
- if(work32[4]&0x00000004)
- len += sprintf(buf+len, " CRC suppression\n");
- if(work32[4]&0x00000008)
- len += sprintf(buf+len, " Loop suppression\n");
- if(work32[4]&0x00000010)
- len += sprintf(buf+len, " MAC insertion\n");
- if(work32[4]&0x00000020)
- len += sprintf(buf+len, " RIF insertion\n");
- if(work32[4]&0x00000100)
- len += sprintf(buf+len, " IPv4 checksum\n");
- if(work32[4]&0x00000200)
- len += sprintf(buf+len, " TCP checksum\n");
- if(work32[4]&0x00000400)
- len += sprintf(buf+len, " UDP checksum\n");
- if(work32[4]&0x00000800)
- len += sprintf(buf+len, " RSVP checksum\n");
- if(work32[4]&0x00001000)
- len += sprintf(buf+len, " ICMP checksum\n");
- if (d->i2oversion == 0x00)
- {
- if(work32[4]&0x00008000)
- len += sprintf(buf+len, " Loopback enabled\n");
- if(work32[4]&0x00010000)
- len += sprintf(buf+len, " Loopback suppression enabled\n");
- }
- else
- {
- if(work32[4]&0x00010000)
- len += sprintf(buf+len, " Loopback enabled\n");
- if(work32[4]&0x00020000)
- len += sprintf(buf+len, " Loopback suppression enabled\n");
- }
+ len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]);
+ len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]);
+ len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]);
+ len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]);
+
+ len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]);
+ len += sprintf(buf+len, " [%s] No DA in SGL\n",
+ (work32[4]&0x00000002) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] CRC suppression\n",
+ (work32[4]&0x00000004) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] MAC insertion\n",
+ (work32[4]&0x00000010) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] RIF insertion\n",
+ (work32[4]&0x00000020) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] IPv4 checksum generation\n",
+ (work32[4]&0x00000100) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] TCP checksum generation\n",
+ (work32[4]&0x00000200) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] UDP checksum generation\n",
+ (work32[4]&0x00000400) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] RSVP checksum generation\n",
+ (work32[4]&0x00000800) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] ICMP checksum generation\n",
+ (work32[4]&0x00001000) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Loopback enabled\n",
+ (work32[4]&0x00010000) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] Loopback suppression enabled\n",
+ (work32[4]&0x00020000) ? "+" : "-");
spin_unlock(&i2o_proc_lock);
return len;
@@ -2632,15 +2566,25 @@ int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len,
return len;
}
- len += sprintf(buf,"Max size of chain element : %d\n", work32[0]);
- len += sprintf(buf+len, "Max number of buckets : %d\n", work32[1]);
-
- if (d->i2oversion > 0x00) { /* not in 1.5 */
- len += sprintf(buf+len, "RxModes : %d\n", work32[2]);
- len += sprintf(buf+len, "RxMaxBucketsReply : %d\n", work32[3]);
- len += sprintf(buf+len, "RxMaxPacketsPerBuckets : %d\n", work32[4]);
- len += sprintf(buf+len, "RxMaxPostBuckets : %d\n", work32[5]);
- }
+ len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]);
+ len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]);
+ len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]);
+ len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]);
+ len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]);
+
+ len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]);
+ len += sprintf(buf+len, " [%s] FCS reception\n",
+ (work32[2]&0x00000004) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] IPv4 checksum validation \n",
+ (work32[2]&0x00000100) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] TCP checksum validation \n",
+ (work32[2]&0x00000200) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] UDP checksum validation \n",
+ (work32[2]&0x00000400) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] RSVP checksum validation \n",
+ (work32[2]&0x00000800) ? "+" : "-");
+ len += sprintf(buf+len, " [%s] ICMP checksum validation \n",
+ (work32[2]&0x00001000) ? "+" : "-");
spin_unlock(&i2o_proc_lock);
return len;
@@ -3344,14 +3288,6 @@ int __init i2o_proc_init(void)
if(create_i2o_procfs())
return -EBUSY;
- if (i2o_install_handler(&i2o_proc_handler) < 0)
- {
- printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n");
- return 0;
- }
-
- proc_context = i2o_proc_handler.context;
-
return 0;
}
@@ -3364,6 +3300,5 @@ MODULE_DESCRIPTION("I2O procfs Handler");
void cleanup_module(void)
{
destroy_i2o_procfs();
- i2o_remove_handler(&i2o_proc_handler);
}
#endif
diff --git a/drivers/ieee1394/.cvsignore b/drivers/ieee1394/.cvsignore
new file mode 100644
index 000000000..6d007a06f
--- /dev/null
+++ b/drivers/ieee1394/.cvsignore
@@ -0,0 +1,4 @@
+.depend
+.*.flags
+aic7xxx_asm
+aic7xxx_seq.h
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
new file mode 100644
index 000000000..899add490
--- /dev/null
+++ b/drivers/ieee1394/Config.in
@@ -0,0 +1,24 @@
+# -*- shell-script -*-
+
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'IEEE 1394 (FireWire) support'
+
+ tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI
+
+ if [ "$CONFIG_IEEE1394" != "n" ]; then
+
+ dep_tristate 'Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394
+ if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
+ bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ fi
+
+ dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394
+
+ dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
+
+ dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+
+ fi
+ endmenu
+fi
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
new file mode 100644
index 000000000..f2ce58897
--- /dev/null
+++ b/drivers/ieee1394/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile for the Linux IEEE 1394 implementation
+#
+# 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 (not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+MOD_LIST_NAME := IEEE1394_MODULES
+
+L_TARGET := ieee1394.a
+L_OBJS :=
+LX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+MI_OBJS :=
+MIX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+
+ifeq ($(CONFIG_IEEE1394),y)
+L_OBJS += ieee1394.o hosts.o highlevel.o csr.o
+O_TARGET = ieee1394.o
+O_OBJS += ieee1394_core.o ieee1394_transactions.o
+OX_OBJS += ieee1394_syms.o
+else
+ ifeq ($(CONFIG_IEEE1394),m)
+ M_OBJS += ieee1394.o
+ O_TARGET = ieee1394.o
+ O_OBJS += ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o csr.o
+ OX_OBJS += ieee1394_syms.o
+ endif
+endif
+
+ifeq ($(CONFIG_IEEE1394_PCILYNX),y)
+L_OBJS += pcilynx.o
+else
+ ifeq ($(CONFIG_IEEE1394_PCILYNX),m)
+ M_OBJS += pcilynx.o
+ endif
+endif
+
+ifeq ($(CONFIG_IEEE1394_AIC5800),y)
+L_OBJS += aic5800.o
+else
+ ifeq ($(CONFIG_IEEE1394_AIC5800),m)
+ M_OBJS += aic5800.o
+ endif
+endif
+
+ifeq ($(CONFIG_IEEE1394_OHCI1394),y)
+L_OBJS += ohci1394.o
+else
+ ifeq ($(CONFIG_IEEE1394_OHCI1394),m)
+ M_OBJS += ohci1394.o
+ endif
+endif
+
+
+ifeq ($(CONFIG_IEEE1394_RAWIO),y)
+L_OBJS += raw1394.o
+else
+ ifeq ($(CONFIG_IEEE1394_RAWIO),m)
+ M_OBJS += raw1394.o
+ endif
+endif
+
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/ieee1394/aic5800.c b/drivers/ieee1394/aic5800.c
new file mode 100644
index 000000000..73c1928cd
--- /dev/null
+++ b/drivers/ieee1394/aic5800.c
@@ -0,0 +1,897 @@
+/*
+ * aic5800.c - Adaptec AIC-5800 PCI-IEEE1394 chip driver
+ * Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "ieee1394.h"
+#include "aic5800.h"
+
+
+
+/// print general (card independent) information
+#define PRINT_G(level, fmt, args...) printk(level "aic5800: " fmt "\n" , ## args)
+/// print card specific information
+#define PRINT(level, card, fmt, args...) printk(level "aic5800-%d: " fmt "\n" , card , ## args)
+
+/// card array
+static struct aic5800 cards[MAX_AIC5800_CARDS];
+/// holds the number of installed aic5800 cards
+static int num_of_cards = 0;
+
+static int add_card(struct pci_dev *dev);
+static void remove_card(struct aic5800 *aic);
+static int init_driver(void);
+
+
+/*****************************************************************
+ * Auxiliary functions needed to read the EEPROM
+ * Daniel Minitti
+ *****************************************************************/
+#define SEEPDOUT 0x1
+#define SEEPDIN 0x02
+#define SEEPSK 0x04
+#define SEEPCS 0x08
+#define SEEPCYC 0x10
+#define SEEPBUSY 0x20
+
+#define CLOCK_PULSE() {\
+ int cnt=200;\
+ while(cnt-->0 && reg_read(aic, misc_SEEPCTL) & SEEPBUSY);\
+ if (reg_read(aic, misc_SEEPCTL) & SEEPBUSY) printk("BUSY ");\
+ }
+
+static inline unsigned short read_seeprom_word(struct aic5800 *aic,
+ int offset)
+{
+ int i;
+ unsigned char temp;
+ unsigned char read_cmd[3] = {1,1,0};
+ unsigned short rd;
+
+ // send chip select for one clock cycle.
+ reg_write(aic, misc_SEEPCTL, SEEPSK|SEEPCS);
+ CLOCK_PULSE();
+
+ // write start bit (1) & READ op-code (10b)
+ for (i=0; i<sizeof(read_cmd); i++) {
+ temp = SEEPCS | SEEPCYC | read_cmd[i];
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ temp = temp ^ SEEPSK;
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ }
+ // write 8 bit address (MSB --> LSB)
+ for (i=7; i>=0; i--) {
+ temp = offset;
+ temp = (temp >> i) & 1;
+ temp = SEEPCS | SEEPCYC | temp;
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ temp = temp ^ SEEPSK;
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ }
+ // read 16 bit (MSB --> LSB)
+ rd = 0;
+ for (i=0; i<=16; i++) {
+ temp = SEEPCS | SEEPCYC;
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ temp = temp ^ SEEPSK;
+ rd = (rd << 1) | (unsigned short)((reg_read(aic, misc_SEEPCTL)
+& SEEPDIN)>>1);
+ reg_write(aic, misc_SEEPCTL, temp);
+ CLOCK_PULSE();
+ }
+
+ // reset chip select for the next command cycle
+ reg_write(aic, misc_SEEPCTL, SEEPCYC);
+ CLOCK_PULSE();
+ reg_write(aic, misc_SEEPCTL, SEEPCYC | SEEPSK);
+ CLOCK_PULSE();
+ reg_write(aic, misc_SEEPCTL, SEEPCYC);
+ CLOCK_PULSE();
+
+ reg_write(aic, misc_SEEPCTL, 0);
+ CLOCK_PULSE();
+
+ return rd;
+}
+
+#undef DEBUG_SEEPROM
+
+/** Read 64-bit GUID (Global Unique ID) from SEEPROM
+ *
+ * It works well on AHA-8945.
+ * On AHA-8920 it works well only on first time, It returns ffff... on
+ * the other times.
+ *****************************************************************/
+static unsigned long long read_guid(struct aic5800 *aic)
+{
+ int i;
+ unsigned long long guid;
+
+#ifdef DEBUG_SEEPROM
+ printk("\n");
+ printk("SEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));
+#endif
+
+ /* read GUID */
+ guid = 0;
+ for (i=0x10; i<0x14; i++)
+ guid = (guid << 16) | read_seeprom_word(aic,i);
+
+#ifdef DEBUG_SEEPROM
+ for (i=0; i<3; i++)
+ printk("%x ", (unsigned int) read_seeprom_word(aic,i));
+ printk("\nGUID = ");
+ for (i=3; i>=0; i--)
+ printk("%x ", (unsigned int)(guid>>(16*i))&0xffff);
+
+ printk("\nSEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));
+#endif
+ return guid;
+}
+
+#undef CLOCK_PULSE()
+
+static int aic_detect(struct hpsb_host_template *tmpl)
+{
+ struct hpsb_host *host;
+ int i;
+
+ init_driver();
+
+ for (i = 0; i < num_of_cards; i++) {
+ host = hpsb_get_host(tmpl, 0);
+ if (host == NULL) {
+ /* simply don't init more after out of mem */
+ return i;
+ }
+ host->hostdata = &cards[i];
+ cards[i].host = host;
+ }
+
+ return num_of_cards;
+}
+
+static int aic_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
+{
+ struct aic5800 *aic = host->hostdata;
+ int retval = 0;
+ unsigned long flags;
+ struct hpsb_packet *packet, *lastpacket;
+
+ switch (cmd) {
+ case RESET_BUS:
+ reg_write(aic, misc_PhyControl, 0x00004140 );
+ break;
+
+ case GET_CYCLE_COUNTER:
+ arg = reg_read(aic, misc_CycleTimer);
+ break;
+
+ case SET_CYCLE_COUNTER:
+ reg_write(aic, misc_CycleTimer, arg);
+ break;
+
+ case SET_BUS_ID:
+ reg_clear_bits(aic, misc_NodeID, 0xFFC0);
+ reg_set_bits(aic, misc_NodeID, (arg<<6));
+ break;
+
+ case ACT_CYCLE_MASTER:
+ if (arg) {
+ /* enable cycleMaster */
+ reg_set_bits(aic, misc_Control, 0x20000);
+ } else {
+ /* disable cycleMaster */
+ reg_clear_bits(aic, misc_Control, 0x20000);
+ };
+ break;
+
+ case CANCEL_REQUESTS:
+ spin_lock_irqsave(&aic->async_queue_lock, flags);
+ /* stop any chip activity */
+ reg_write( aic, AT_ChannelControl, 0x80000000);
+ packet = aic->async_queue;
+ aic->async_queue = NULL;
+ spin_unlock_irqrestore(&aic->async_queue_lock, flags);
+
+ while (packet != NULL) {
+ lastpacket = packet;
+ packet = packet->xnext;
+ hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
+ }
+
+ break;
+
+ case MODIFY_USAGE:
+ if (arg) {
+ MOD_INC_USE_COUNT;
+ } else {
+ MOD_DEC_USE_COUNT;
+ }
+ break;
+
+#if 0
+ case DEBUG_DUMPINFO:
+ PRINT(KERN_INFO, aic->id, AIC5800_DRIVER_NAME);
+ PRINT(KERN_INFO, aic->id, " Register MMIO base: 0x%p\n",
+ aic->registers);
+ PRINT(KERN_INFO, aic->id, " NodeID: 0x%x\n",
+ reg_read(aic, misc_NodeID) );
+ PRINT(KERN_INFO,aic->id, " #Intr: %lu BusResets: %lu\n",
+ aic->NumInterrupts, aic->NumBusResets);
+ PRINT(KERN_INFO, aic->id, " TxPackets: %lu RxPackets: %lu\n",
+ aic->TxPackets, aic->RxPackets);
+ PRINT(KERN_INFO,aic->id, " TxRdy: %lu ATErr: %lu HdrErr: %lu TcodeErr: %lu SendRej: %lu\n",
+ aic->TxRdy, aic->ATError, aic->HdrErr,
+ aic->TCodeErr, aic->SendRej);
+ break;
+#endif
+
+ default:
+ PRINT(KERN_ERR, aic->id, "unknown devctl command %d", cmd);
+ retval = -1;
+ }
+
+ return retval;
+
+}
+
+/** Initialize the host adapter chip and corresponding data
+ structures. We reset the chip, enable transmitter, receiver,
+ the physical DMA units, cycle timer, cycle source, reception
+ of selfid packets and initialize several other registers. */
+static int aic_initialize(struct hpsb_host *host)
+{
+ int i;
+ struct aic5800 *aic = host->hostdata;
+
+ /* Reset data structures */
+ aic->async_queue = NULL;
+ spin_lock_init(&aic->async_queue_lock);
+
+ /* Reset the chip */
+ reg_write( aic, misc_Reset, 0x37);
+ udelay(10); // FIXME
+ reg_write( aic, misc_Reset, 0);
+
+ /* Enable Transmitter/Receiver, enable physDMA,
+ * enable CycleTimer, cycleSource */
+ reg_write( aic, misc_Control, 0x82050003);
+
+ /* Enable reception of SelfID packets */
+ reg_set_bits(aic, misc_PacketControl, 0x20);
+
+ reg_write(aic, AT_InterruptSelect, 0x00F0001);
+ reg_write(aic, AT_BranchSelect, 0x0100010);
+ reg_write(aic, AT_WaitSelect, 0x00F0001);
+ reg_write(aic, misc_ATRetries, reg_read(aic, misc_ATRetries) | 0x7);
+
+ /* initialize AR DMA */
+
+ /* unset run bit */
+ reg_write( aic, AR_ChannelControl, 0x80000000);
+
+ /* here we should have 0 iterations because of the code
+ in the DmaAR handler. However, to be sure we do it */
+ i = 0;
+ while (reg_read(aic, AR_ChannelStatus) & 0x400) {
+ i++;
+ if (i>100000) {
+ PRINT(KERN_ERR, aic->id,
+ "Huh! Can't set AR_ChannelControl... card can not receive!");
+ break;
+ }
+ }
+
+ (aic->AR_program)->control = ( DMA_CMD_INPUTLAST | DMA_KEY_STREAM0
+ | DMA_INTR_ALWAYS | DMA_BRANCH_ALWAYS)
+ + AIC5800_ARFIFO_SIZE;
+ (aic->AR_program)->address = virt_to_bus(aic->rcv_page);
+ (aic->AR_program)->branchAddress = virt_to_bus(aic->AR_program);
+ (aic->AR_program)->status = AIC5800_ARFIFO_SIZE;
+
+ (aic->AR_program+1)->control = DMA_CMD_STOP;
+ (aic->AR_program+1)->address = 0;
+ (aic->AR_program+1)->branchAddress = 0;
+ (aic->AR_program+1)->status = 0;
+
+ reg_write( aic, AR_CommandPtr, (u32) virt_to_bus(aic->AR_program));
+ reg_write( aic, AR_ChannelControl, 0x80008000);
+
+ /* Enable Interrupts */
+ reg_write(aic, misc_InterruptClear, 0xFFFFFFFF);
+ reg_write(aic, misc_InterruptMask, 0xFFFFFFFF);
+ /*reg_write(aic, misc_InterruptMask, 0x00F1F03F);*/
+
+ return 1;
+}
+
+static void aic_release(struct hpsb_host *host)
+{
+ struct aic5800 *aic;
+
+ if (host != NULL) {
+ aic = host->hostdata;
+ remove_card(aic);
+ }
+}
+
+/* This must be called with the async_queue_lock held. */
+static void send_next_async(struct aic5800 *aic)
+{
+ int i;
+ struct hpsb_packet *packet = aic->async_queue;
+
+ /* stop the channel program if it's still running */
+ reg_write( aic, AT_ChannelControl, 0x80000000);
+
+ /* re-format packet header for AIC-5800 chip */
+ packet->header[1] = (packet->header[1] & 0xFFFF) |
+ (packet->header[0] & 0xFFFF0000);
+ packet->header[0] = (packet->header[0] & 0xFFFF);
+
+#ifndef __BIG_ENDIAN
+ /* Packet must be byte-swapped in non-big-endian environments,
+ * see AIC-5800 specification...
+ */
+ { u32 i;
+ for ( i = 0 ; i < packet->header_size/sizeof(u32) ; i++ )
+ packet->header[i] = cpu_to_be32( packet->header[i] );
+ for ( i = 0 ; i < packet->data_size/sizeof(u32) ; i++ )
+ packet->data[i] = cpu_to_be32( packet->data[i] );
+ }
+
+#endif
+
+ /* typically we use only a few iterations here */
+ i = 0;
+ while (reg_read(aic, AT_ChannelStatus) & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, aic->id,
+ "runaway loop 1 in send_next_async() - bailing out...");
+ break;
+ };
+ };
+
+ /* set data buffer address and packet length */
+ memset(aic->AT_program, 0, MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd));
+
+ if (packet->data_size) {
+ aic->AT_program[0].control = ( DMA_CMD_OUTPUTMORE | DMA_KEY_STREAM0 ) +
+ packet -> header_size;
+ aic->AT_program[0].address = virt_to_bus( packet->header );
+ aic->AT_program[1].control = ( DMA_CMD_OUTPUTLAST | DMA_KEY_STREAM0
+ | DMA_INTR_ALWAYS )
+ + packet -> data_size;
+ aic->AT_program[1].address = virt_to_bus( packet->data );
+
+ aic->AT_program[2].control = DMA_CMD_STOP;
+
+ } else {
+ aic->AT_program[0].control = ( DMA_CMD_OUTPUTLAST | DMA_INTR_ALWAYS |
+ DMA_KEY_STREAM0 ) +
+ packet -> header_size;
+ aic->AT_program[0].address = virt_to_bus( packet->header );
+
+ aic->AT_program[1].control = DMA_CMD_STOP;
+ };
+
+ /* set program start address */
+ reg_write(aic, AT_CommandPtr, (unsigned int) virt_to_bus(aic->AT_program));
+
+ /* typically we use only a few iterations here */
+ i = 0;
+ while (reg_read(aic, AT_CommandPtr) != (unsigned int)
+ virt_to_bus(aic->AT_program)) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, aic->id,
+ "runaway loop 2 in send_next_async() - bailing out...");
+ break;
+ };
+ };
+
+ /* run program */
+ reg_write( aic, AT_ChannelControl, 0x80008000);
+}
+
+
+static int aic_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
+{
+ struct aic5800 *aic = host->hostdata;
+ struct hpsb_packet *p;
+ unsigned long flags;
+
+ if (packet->data_size >= 4096) {
+ PRINT(KERN_ERR, aic->id, "transmit packet data too big (%d)",
+ packet->data_size);
+ return 0;
+ }
+
+ packet->xnext = NULL;
+
+ spin_lock_irqsave(&aic->async_queue_lock, flags);
+
+ if (aic->async_queue == NULL) {
+ aic->async_queue = packet;
+ send_next_async(aic);
+ } else {
+ p = aic->async_queue;
+ while (p->xnext != NULL) {
+ p = p->xnext;
+ }
+
+ p->xnext = packet;
+ }
+
+ spin_unlock_irqrestore(&aic->async_queue_lock, flags);
+
+ return 1;
+}
+
+static int get_phy_reg(struct aic5800 *aic, int addr)
+{
+ int retval;
+ int i = 0;
+
+ /* sanity check */
+ if (addr > 15) {
+ PRINT(KERN_ERR, aic->id, __FUNCTION__
+ ": PHY register address %d out of range", addr);
+ return -1;
+ }
+
+ /* request data from PHY */
+ reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr));
+
+ /* read data from PhyControl register */
+ /* note that we have to wait until the register is updated */
+ do {
+ retval = reg_read(aic, misc_PhyControl);
+
+ if (i > 10000) {
+ PRINT(KERN_ERR, aic->id, __FUNCTION__
+ ": runaway loop, aborting");
+ retval = -1;
+ break;
+ }
+ i++;
+ } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr));
+
+ /* we don't want a PhyInt interrupt */
+ reg_write(aic, misc_InterruptClear, INT_PhyInt);
+
+ if (retval != -1) {
+ return ((retval & 0xff0000)>>16);
+ } else {
+ return -1;
+ }
+}
+
+static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid)
+{
+ quadlet_t lsid;
+ char phyreg[7];
+ int i;
+
+ for (i = 1; i < 7; i++) {
+ phyreg[i] = get_phy_reg(aic, i);
+ }
+
+ /* Standard PHY register map */
+ lsid = 0x80400000 | (phyid << 24);
+ lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
+ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
+ lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */
+ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
+
+ for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */
+ if (phyreg[3 + i] & 0x4) {
+ lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
+ << (6 - i*2);
+ } else {
+ lsid |= 1 << (6 - i*2);
+ }
+ }
+
+ return lsid;
+};
+
+/* moved out to make interrupt routine more readable */
+inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host,
+ int phyid, int isroot, size_t size)
+{
+ quadlet_t *q = aic->rcv_page;
+ quadlet_t lsid;
+
+ /* we need our own self-id packet */
+ lsid = generate_own_selfid(aic, phyid);
+
+ /* unconnected state? only begin and end marker in rcv_page */
+ if (size==8) {
+ hpsb_selfid_received(host, lsid);
+ }
+
+ /* process buffer... AIC's FIFO often contains some strangenesses */
+ while (size > 0) {
+ if (q[0] == 0xe0) {
+ /* marker */
+ q += 1;
+ size -= 4;
+ continue;
+ };
+ if (q[0] == 0x1) {
+ /* marker */
+ q += 1;
+ size -= 4;
+ break;
+ };
+
+ if (q[0] == ~q[1]) {
+ /* correct self-id */
+
+ if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
+ /* its our turn now! */
+ //PRINT(KERN_INFO,
+ // aic->id, "selfid packet 0x%x included", lsid);
+
+ hpsb_selfid_received(host, lsid);
+ }
+
+ //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]);
+ hpsb_selfid_received(host, q[0]);
+ q += 2;
+ size -= 8;
+ continue;
+ };
+ }
+
+ /* if we are root, our self-id packet is last */
+ if (isroot && phyid != 0) {
+ hpsb_selfid_received(host, lsid);
+ }
+
+ hpsb_selfid_complete(host, phyid, isroot);
+}
+
+static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct aic5800 *aic = (struct aic5800 *)dev_id;
+ struct hpsb_host *host = aic->host;
+ quadlet_t *q = aic->rcv_page;
+
+ int phyid = -1, isroot = 0;
+
+ u32 interruptEvent = reg_read(aic, misc_InterruptEvents);
+ reg_write(aic, misc_InterruptClear, interruptEvent);
+
+ //printk("InterruptEvent 0x%x\n", interruptEvent);
+ if ( (interruptEvent & 0x3f) == 0x3f ) {
+ PRINT(KERN_INFO, aic->id, "Dma Engine Error");
+ };
+
+ if ( interruptEvent & INT_DmaAT ) {
+ if (aic->AT_program[0].status & 0xFFFF)
+ PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes",
+ aic->AT_program[0].status & 0xFFFF);
+ };
+
+ if ( interruptEvent & INT_PhyInt) {
+ PRINT(KERN_INFO, aic->id, "PhyInt");
+ };
+
+ if ( interruptEvent & INT_DmaAR ) {
+ int rcv_bytes;
+ int i;
+
+ /* we calculate the number of received bytes from the
+ residual count field */
+ rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF);
+
+ //PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes);
+
+ if ((aic->AR_program->status & 0x84000000)
+ && (aic->AR_program->status & 0xFFFF) >= 8 ) {
+
+#ifndef __BIG_ENDIAN
+ /* we have to do byte-swapping on non-bigendian architectures */
+ for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) {
+ *q = be32_to_cpu(*q);
+ q++;
+ };
+ q = aic->rcv_page;
+#endif
+
+ if (*q == 0xe0) {
+ phyid = reg_read(aic, misc_NodeID);
+ isroot = phyid & 0x800000;
+ phyid = phyid & 0x3F;
+ handle_selfid(aic, host, phyid, isroot, rcv_bytes);
+ } else {
+ hpsb_packet_received(host, aic->rcv_page, rcv_bytes);
+ };
+ } else {
+ PRINT(KERN_ERR, aic->id,
+ "AR DMA program status value 0x%x is incorrect!",
+ aic->AR_program->status);
+ };
+ }
+ if ( interruptEvent & INT_BusReset ) {
+ PRINT(KERN_INFO, aic->id, "bus reset occured");
+ if (!host->in_bus_reset) {
+ hpsb_bus_reset(host);
+ }
+ reg_set_bits(aic, misc_Control, 0x1);
+ aic->NumBusResets++;
+ };
+
+ if (interruptEvent & INT_RcvData ) {
+ aic->RxPackets++;
+ };
+
+ if (interruptEvent & INT_TxRdy) {
+ /* async packet sent - transmitter ready */
+ u32 ack;
+ struct hpsb_packet *packet;
+
+ if (aic->async_queue) {
+
+ spin_lock(&aic->async_queue_lock);
+
+
+ ack = reg_read(aic, AT_ChannelStatus) & 0xF;
+
+ packet = aic->async_queue;
+ aic->async_queue = packet->xnext;
+
+ if (aic->async_queue != NULL) {
+ send_next_async(aic);
+ }
+ spin_unlock(&aic->async_queue_lock);
+ PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack);
+ hpsb_packet_sent(host, packet, ack);
+ } // else
+ //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)");
+
+ aic->TxRdy++;
+ };
+ if (interruptEvent & INT_ATError ) {
+ PRINT(KERN_INFO,aic->id,"ATError");
+ aic->ATError++;
+ };
+ if (interruptEvent & INT_SendRej ) {
+ aic->SendRej++;
+ };
+ if (interruptEvent & INT_HdrErr ) {
+ aic->HdrErr++;
+ };
+ if (interruptEvent & INT_TCodeErr ) {
+ PRINT(KERN_INFO,aic->id,"TCodeErr");
+ aic->TCodeErr++;
+ };
+
+ aic->NumInterrupts++;
+
+}
+
+inline static void * quadquadalign(void *buf)
+{
+ if ((unsigned int) buf % 0x10 != 0) {
+ return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0);
+ } else {
+ return buf;
+ };
+}
+
+static int add_card(struct pci_dev *dev)
+{
+#define FAIL(fmt, args...) \
+ PRINT_G(KERN_ERR, fmt , ## args); \
+ num_of_cards--; \
+ remove_card(aic); \
+ return 1;
+
+ struct aic5800 *aic; /* shortcut to currently handled device */
+ unsigned long page;
+
+ if (num_of_cards == MAX_AIC5800_CARDS) {
+ PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
+ "Adjust MAX_AIC5800_CARDS in aic5800.h.",
+ MAX_AIC5800_CARDS);
+ return 1;
+ }
+
+ aic = &cards[num_of_cards++];
+
+ aic->id = num_of_cards-1;
+ aic->dev = dev;
+
+ if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ,
+ AIC5800_DRIVER_NAME, aic)) {
+ PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq);
+ } else {
+ FAIL("failed to allocate shared interrupt %d", dev->irq);
+ }
+
+ page = get_free_page(GFP_KERNEL);
+ if (page != 0) {
+ aic->rcv_page = phys_to_virt(page);
+ } else {
+ FAIL("failed to allocate receive buffer");
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+ aic->registers = ioremap_nocache(dev->base_address[0],
+ AIC5800_REGSPACE_SIZE);
+#else
+ aic->registers = ioremap_nocache(dev->resource[0].start,
+ AIC5800_REGSPACE_SIZE);
+#endif
+
+ if (aic->registers == NULL) {
+ FAIL("failed to remap registers - card not accessible");
+ }
+
+ PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p",
+ aic->registers);
+
+ aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL);
+
+ if (!aic->pbuf) {
+ FAIL("failed to allocate program buffer");
+ }
+
+ aic->AT_program = quadquadalign(aic->pbuf);
+ aic->AT_program[2].control = DMA_CMD_STOP;
+
+ aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE *
+ sizeof(struct dma_cmd);
+
+ return 0;
+#undef FAIL
+}
+
+static void remove_card(struct aic5800 *aic)
+{
+ /* Disable interrupts of this controller */
+ reg_write(aic, misc_InterruptMask, 0);
+ /* Free AR buffer */
+ free_page(virt_to_phys(aic->rcv_page));
+ /* Free channel program buffer */
+ kfree(aic->pbuf);
+ /* Free interrupt request */
+ free_irq(aic->dev->irq, aic);
+ /* Unmap register space */
+ iounmap(aic->registers);
+}
+
+static int init_driver()
+{
+ struct pci_dev *dev = NULL;
+ int success = 0;
+
+ if (num_of_cards) {
+ PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
+ return 0;
+ }
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_5800, dev))
+ != NULL) {
+ if (add_card(dev) == 0) {
+ success = 1;
+ }
+ }
+
+ if (success == 0) {
+ PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+/** Prepare our local CSR ROM. This is done by using the software-stored
+ ROM and inserting the GUID read from the EEPROM */
+static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr)
+{
+ struct aic5800 *aic = host -> hostdata;
+ u64 guid;
+
+ /* Read the GUID from the card's EEPROM and put it into the right
+ place in the CONFIG ROM. */
+ guid = read_guid(aic);
+ aic5800_csr_rom[15] = (u32) (guid >> 32);
+ aic5800_csr_rom[16] = (u32) (guid & 0xFFFF);
+
+ *ptr = aic5800_csr_rom;
+
+ return sizeof(aic5800_csr_rom);
+}
+
+struct hpsb_host_template *get_aic_template(void)
+{
+ static struct hpsb_host_template tmpl;
+ static int initialized = 0;
+
+ if (!initialized) {
+ /* Initialize by field names so that a template structure
+ * reorganization does not influence this code. */
+ tmpl.name = "aic5800";
+
+ tmpl.detect_hosts = aic_detect;
+ tmpl.initialize_host = aic_initialize;
+ tmpl.release_host = aic_release;
+ tmpl.get_rom = get_aic_rom;
+ tmpl.transmit_packet = aic_transmit;
+ tmpl.devctl = aic_devctl;
+
+ initialized = 1;
+ }
+
+ return &tmpl;
+}
+
+#ifdef MODULE
+
+/* EXPORT_NO_SYMBOLS; */
+
+MODULE_AUTHOR("Emanuel Pirker <epirker@edu.uni-klu.ac.at>");
+MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver");
+MODULE_SUPPORTED_DEVICE("aic5800");
+
+void cleanup_module(void)
+{
+ hpsb_unregister_lowlevel(get_aic_template());
+ PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module");
+}
+
+int init_module(void)
+{
+ if (hpsb_register_lowlevel(get_aic_template())) {
+ PRINT_G(KERN_ERR, "registering failed");
+ return -ENXIO;
+ } else {
+ return 0;
+ }
+}
+
+#endif /* MODULE */
diff --git a/drivers/ieee1394/aic5800.h b/drivers/ieee1394/aic5800.h
new file mode 100644
index 000000000..70686c72c
--- /dev/null
+++ b/drivers/ieee1394/aic5800.h
@@ -0,0 +1,292 @@
+/*
+** aic5800.h - Adaptec AIC-5800 PCI-IEEE1394 chip driver header file
+** Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+*/
+
+#ifndef AIC5800_H
+#define AIC5800_H
+
+#define AIC5800_DRIVER_NAME "aic5800"
+
+#define MAX_AIC5800_CARDS 4
+#define AIC5800_REGSPACE_SIZE 512
+#define AIC5800_PBUF_SIZE 512
+
+#define MAX_AT_PROGRAM_SIZE 10
+#define AIC5800_ARFIFO_SIZE 128
+
+struct dma_cmd {
+ u32 control;
+ u32 address;
+ u32 branchAddress;
+ u32 status;
+};
+
+struct aic5800 {
+ int id; /* sequential card number */
+
+ struct pci_dev *dev;
+
+ /* remapped memory spaces */
+ void *registers;
+
+ struct hpsb_host *host;
+
+ int phyid, isroot;
+
+ void *rcv_page;
+ void *pbuf;
+
+ struct dma_cmd *AT_program;
+ u32 *AT_status;
+ struct dma_cmd *AR_program;
+ u32 *AR_status;
+ int AR_active;
+
+ struct hpsb_packet *async_queue;
+ spinlock_t async_queue_lock;
+
+ unsigned long NumInterrupts, NumBusResets;
+ unsigned long TxPackets, RxPackets;
+ unsigned long TxErrors, RxErrors;
+ unsigned long TxRdy, ATError, HdrErr, TCodeErr, SendRej;
+
+};
+
+
+/*
+ * Register read and write helper functions.
+ */
+inline static void reg_write(const struct aic5800 *aic, int offset, u32 data)
+{
+ writel(data, aic->registers + offset);
+}
+
+inline static u32 reg_read(const struct aic5800 *aic, int offset)
+{
+ return readl(aic->registers + offset);
+}
+
+inline static void reg_set_bits(const struct aic5800 *aic, int offset,
+ u32 mask)
+{
+ reg_write(aic, offset, (reg_read(aic, offset) | mask));
+}
+
+inline static void reg_clear_bits(const struct aic5800 *aic, int offset,
+ u32 mask)
+{
+ reg_write(aic, offset, (reg_read(aic, offset) & ~mask));
+}
+
+
+/* AIC-5800 Registers */
+
+#define AT_ChannelControl 0x0
+#define AT_ChannelStatus 0x4
+#define AT_CommandPtr 0xC
+#define AT_InterruptSelect 0x10
+#define AT_BranchSelect 0x14
+#define AT_WaitSelect 0x18
+
+/* Asynchronous receive */
+#define AR_ChannelControl 0x20
+#define AR_ChannelStatus 0x24
+#define AR_CommandPtr 0x2C
+
+/* ITA */
+#define ITA_ChannelControl 0x40
+#define ITA_ChannelStatus 0x44
+#define ITA_CommandPtr 0x4C
+
+/* ITB */
+#define ITB_ChannelControl 0x60
+#define ITB_ChannelStatus 0x64
+#define ITB_CommandPtr 0x6C
+
+/* IRA */
+#define IRA_ChannelControl 0x80
+#define IRA_ChannelStatus 0x84
+#define IRA_CommandPtr 0x8C
+
+/* IRB */
+#define IRB_ChannelControl 0xA0
+#define IRB_ChannelStatus 0xA4
+#define IRB_CommandPtr 0xAC
+
+/* miscellaneous */
+#define misc_Version 0x100
+#define misc_Control 0x104
+#define misc_NodeID 0x108
+#define misc_Reset 0x10C
+#define misc_PacketControl 0x110
+#define misc_Diagnostic 0x114
+#define misc_PhyControl 0x118
+#define misc_ATRetries 0x11C
+#define misc_SSNinterface 0x120
+#define misc_CycleTimer 0x124
+
+/* ITA */
+#define ITA_EventCycle 0x130
+#define ITA_Configuration 0x134
+#define ITA_Bandwidth 0x138
+
+/* ITB */
+#define ITB_EventCycle 0x140
+#define ITB_Configuration 0x144
+#define ITB_Bandwidth 0x148
+
+/* IRA */
+#define IRA_EventCycle 0x150
+#define IRA_Configuration 0x154
+
+/* IRB */
+#define IRB_EventCycle 0x160
+#define IRB_Configuration 0x164
+
+/* RSU */
+#define RSU_Enable 0x170
+#define RSU_Interrupt 0x174
+#define RSU_TablePtr 0x178
+#define RSU_InterruptSet 0x17C
+
+/* misc */
+#define misc_InterruptEvents 0x180
+#define misc_InterruptMask 0x184
+#define misc_InterruptClear 0x188
+#define misc_CardBusEvent 0x1E0
+#define misc_CardBusMask 0x1E4
+#define misc_CardBusState 0x1E8
+#define misc_CardBusForce 0x1EC
+#define misc_SEEPCTL 0x1F0
+
+/* Interrupts */
+#define INT_DmaAT 1
+#define INT_DmaAR (1<<1)
+#define INT_DmaITA (1<<2)
+#define INT_DmaITB (1<<3)
+#define INT_DmaIRA (1<<4)
+#define INT_DmaIRB (1<<5)
+#define INT_PERResponse (1<<7)
+#define INT_CycleEventITA (1<<8)
+#define INT_CycleEventITB (1<<9)
+#define INT_CycleEventIRA (1<<10)
+#define INT_CycleEventIRB (1<<11)
+#define INT_BusReset (1<<12)
+#define INT_CmdReset (1<<13)
+#define INT_PhyInt (1<<14)
+#define INT_RcvData (1<<15)
+#define INT_TxRdy (1<<16)
+#define INT_CycleStart (1<<17)
+#define INT_CycleSeconds (1<<18)
+#define INT_CycleLost (1<<19)
+#define INT_ATError (1<<20)
+#define INT_SendRej (1<<21)
+#define INT_HdrErr (1<<22)
+#define INT_TCodeErr (1<<23)
+#define INT_PRQUxferErr (1<<24)
+#define INT_PWQUxferErr (1<<25)
+#define INT_RSUxferErr (1<<26)
+#define INT_RSDone (1<<27)
+#define INT_PSOutOfRetries (1<<28)
+#define INT_cycleTooLong (1<<29)
+
+/* DB DMA constants */
+#define DMA_CMD_OUTPUTMORE 0
+#define DMA_CMD_OUTPUTLAST 0x10000000
+#define DMA_CMD_INPUTMORE 0x20000000
+#define DMA_CMD_INPUTLAST 0x30000000
+#define DMA_CMD_STOREQUAD 0x40000000
+#define DMA_CMD_LOADQUAD 0x50000000
+#define DMA_CMD_NOP 0x60000000
+#define DMA_CMD_STOP 0x70000000
+
+#define DMA_KEY_STREAM0 0
+#define DMA_KEY_STREAM1 (1<<24)
+#define DMA_KEY_STREAM2 (2<<24)
+#define DMA_KEY_STREAM3 (3<<24)
+#define DMA_KEY_REGS (5<<24)
+#define DMA_KEY_SYSTEM (6<<24)
+#define DMA_KEY_DEVICE (7<<24)
+
+#define DMA_INTR_NEVER 0
+#define DMA_INTR_TRUE (1<<20)
+#define DMA_INTR_FALSE (2<<20)
+#define DMA_INTR_ALWAYS (3<<20)
+#define DMA_WAIT_NEVER 0
+#define DMA_WAIT_TRUE (1<<16)
+#define DMA_WAIT_FALSE (2<<16)
+#define DMA_WAIT_ALWAYS (3<<16)
+#define DMA_BRANCH_NEVER 0
+#define DMA_BRANCH_TRUE (1<<18)
+#define DMA_BRANCH_FALSE (2<<18)
+#define DMA_BRANCH_ALWAYS (3<<18)
+
+#define DMA_SPEED_100 0
+#define DMA_SPEED_200 (1<<16)
+#define DMA_SPEED_400 (2<<16)
+
+/* PHY access */
+#define LINK_PHY_READ (1<<15)
+#define LINK_PHY_WRITE (1<<14)
+#define LINK_PHY_ADDR(addr) (addr<<8)
+#define LINK_PHY_WDATA(data) (data)
+#define LINK_PHY_RADDR(addr) (addr<<24)
+
+quadlet_t aic5800_csr_rom[] = {
+ /* bus info block */
+ 0x041ffb82, // length of bus info block, CRC
+ 0x31333934, // 1394 designator
+ 0xf005a000, // various capabilites
+ 0x0000d189, // node_vendor_id, chip_id_hi
+ 0x401010fc, // chip_id_lo
+ /* root directory */
+ 0x00040e54, // length of root directory, CRC
+ 0x030000d1, // module_vendor_id
+ 0x0c008000, // various capabilities
+ 0x8d000006, // offset of node unique id leaf
+ 0xd1000001, // offset of unit directory
+ /* unit directory */
+ 0x0003e60d, // length of unit directory, CRC
+ 0x12000000, // unit_spec_id
+ 0x13000000, // unit_sw_version
+ 0xd4000004, // offset of unit dependent directory
+ /* node unique id leaf */
+ 0x00026ba7, // length of leaf, CRC
+ 0x0000d189, // node_vendor_id, chip_id_hi
+ 0x401010fc, // chip_id_lo
+ /* unit dependent directory */
+ 0x0002ae47, // length of directory, CRC
+ 0x81000002, // offset of vendor name leaf
+ 0x82000006, // offset of model name leaf
+ /* vendor name leaf */
+ 0x000486a3, // length of leaf, CRC
+ 0x00000000,
+ 0x00000000,
+ 0x41444150, // ADAP
+ 0x54454300, // TEC
+ /* model name leaf */
+ 0x0004f420, // length of leaf, CRC
+ 0x00000000,
+ 0x00000000,
+ 0x4148412d, // AHA-
+ 0x38393430 // 8940
+};
+
+#endif
+
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
new file mode 100644
index 000000000..4ffe0fadd
--- /dev/null
+++ b/drivers/ieee1394/csr.c
@@ -0,0 +1,435 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * CSR implementation, iso/bus manager implementation.
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/string.h>
+
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394.h"
+#include "highlevel.h"
+
+
+static u16 csr_crc16(unsigned *data, int length)
+{
+ int check=0, i;
+ int shift, sum, next=0;
+
+ for (i = length; i; i--) {
+ for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
+ sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+ next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
+ }
+ check = next & 0xffff;
+ data++;
+ }
+
+ return check;
+}
+
+static void host_reset(struct hpsb_host *host)
+{
+ host->csr.state &= 0x300;
+
+ host->csr.bus_manager_id = 0x3f;
+ host->csr.bandwidth_available = 4915;
+ host->csr.channels_available_hi = ~0;
+ host->csr.channels_available_lo = ~0;
+
+ host->csr.node_ids = host->node_id << 16;
+
+ if (!host->is_root) {
+ /* clear cmstr bit */
+ host->csr.state &= ~0x100;
+ }
+
+ host->csr.topology_map[1]++;
+ host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count;
+ host->csr.topology_map[0] = (host->selfid_count + 2) << 16
+ | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2);
+
+ /* FIXME - generate speed map */
+ host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1,
+ 0x3f1);
+}
+
+
+static void add_host(struct hpsb_host *host)
+{
+ host->csr.lock = SPIN_LOCK_UNLOCKED;
+
+ host->csr.rom_size = host->template->get_rom(host, &host->csr.rom);
+
+ host->csr.state = 0;
+ host->csr.node_ids = 0;
+ host->csr.split_timeout_hi = 0;
+ host->csr.split_timeout_lo = 800 << 19;
+ host->csr.cycle_time = 0;
+ host->csr.bus_time = 0;
+ host->csr.bus_manager_id = 0x3f;
+ host->csr.bandwidth_available = 4915;
+ host->csr.channels_available_hi = ~0;
+ host->csr.channels_available_lo = ~0;
+}
+
+
+/* Read topology / speed maps and configuration ROM */
+static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
+ unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+ const char *src;
+
+ if (csraddr < CSR_TOPOLOGY_MAP) {
+ if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
+ return RCODE_ADDRESS_ERROR;
+ }
+ src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM;
+ } else if (csraddr < CSR_SPEED_MAP) {
+ src = ((char *)host->csr.topology_map) + csraddr
+ - CSR_TOPOLOGY_MAP;
+ } else {
+ src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
+ }
+
+ memcpy(buffer, src, length);
+ return RCODE_COMPLETE;
+}
+
+/* Read FCP register space */
+static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
+ unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+ const char *src;
+
+ if (csraddr + length > CSR_FCP_END) {
+ return RCODE_ADDRESS_ERROR;
+ }
+ src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
+
+ memcpy(buffer, src, length);
+ return RCODE_COMPLETE;
+}
+
+/* Write FCP register space */
+static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr,
+ unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+ char *dest;
+
+ if (csraddr + length > CSR_FCP_END) {
+ return RCODE_ADDRESS_ERROR;
+ }
+ dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
+
+ memcpy(dest, data, length);
+ return RCODE_COMPLETE;
+}
+
+
+#define out if (--length == 0) break
+
+static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
+ unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+ int oldcycle;
+
+ if ((csraddr | length) & 0x3) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ length /= 4;
+
+ switch (csraddr) {
+ case CSR_STATE_CLEAR:
+ *(buf++) = host->csr.state;
+ out;
+ case CSR_STATE_SET:
+ *(buf++) = host->csr.state;
+ out;
+ case CSR_NODE_IDS:
+ *(buf++) = host->csr.node_ids;
+ out;
+
+ case CSR_RESET_START:
+ return RCODE_TYPE_ERROR;
+
+ /* address gap - handled by default below */
+
+ case CSR_SPLIT_TIMEOUT_HI:
+ *(buf++) = host->csr.split_timeout_hi;
+ out;
+ case CSR_SPLIT_TIMEOUT_LO:
+ *(buf++) = host->csr.split_timeout_lo;
+ out;
+
+ /* address gap */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_CYCLE_TIME:
+ oldcycle = host->csr.cycle_time;
+ host->csr.cycle_time =
+ host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+
+ if (oldcycle > host->csr.cycle_time) {
+ /* cycle time wrapped around */
+ host->csr.bus_time += 1 << 7;
+ }
+ *(buf++) = host->csr.cycle_time;
+ out;
+ case CSR_BUS_TIME:
+ oldcycle = host->csr.cycle_time;
+ host->csr.cycle_time =
+ host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+
+ if (oldcycle > host->csr.cycle_time) {
+ /* cycle time wrapped around */
+ host->csr.bus_time += (1 << 7);
+ }
+ *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25);
+ out;
+
+ /* address gap */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_BUSY_TIMEOUT:
+ /* not yet implemented */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_BUS_MANAGER_ID:
+ *(buf++) = host->csr.bus_manager_id;
+ out;
+ case CSR_BANDWIDTH_AVAILABLE:
+ *(buf++) = host->csr.bandwidth_available;
+ out;
+ case CSR_CHANNELS_AVAILABLE_HI:
+ *(buf++) = host->csr.channels_available_hi;
+ out;
+ case CSR_CHANNELS_AVAILABLE_LO:
+ *(buf++) = host->csr.channels_available_lo;
+ out;
+
+ /* address gap to end - fall through to default */
+ default:
+ return RCODE_ADDRESS_ERROR;
+ }
+
+ return RCODE_COMPLETE;
+}
+
+static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
+ unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+
+ if ((csraddr | length) & 0x3) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ length /= 4;
+
+ switch (csraddr) {
+ case CSR_STATE_CLEAR:
+ /* FIXME FIXME FIXME */
+ printk("doh, someone wants to mess with state clear\n");
+ out;
+ case CSR_STATE_SET:
+ printk("doh, someone wants to mess with state set\n");
+ out;
+
+ case CSR_NODE_IDS:
+ host->csr.node_ids &= NODE_MASK << 16;
+ host->csr.node_ids |= *(data++) & (BUS_MASK << 16);
+ host->node_id = host->csr.node_ids >> 16;
+ host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
+ out;
+
+ case CSR_RESET_START:
+ /* FIXME - perform command reset */
+ out;
+
+ /* address gap */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_SPLIT_TIMEOUT_HI:
+ host->csr.split_timeout_hi = *(data++) & 0x00000007;
+ out;
+ case CSR_SPLIT_TIMEOUT_LO:
+ host->csr.split_timeout_lo = *(data++) & 0xfff80000;
+ out;
+
+ /* address gap */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_CYCLE_TIME:
+ /* should only be set by cycle start packet, automatically */
+ host->csr.cycle_time = *data;
+ host->template->devctl(host, SET_CYCLE_COUNTER, *(data++));
+ out;
+ case CSR_BUS_TIME:
+ host->csr.bus_time = *(data++) & 0xffffff80;
+ out;
+
+ /* address gap */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_BUSY_TIMEOUT:
+ /* not yet implemented */
+ return RCODE_ADDRESS_ERROR;
+
+ case CSR_BUS_MANAGER_ID:
+ case CSR_BANDWIDTH_AVAILABLE:
+ case CSR_CHANNELS_AVAILABLE_HI:
+ case CSR_CHANNELS_AVAILABLE_LO:
+ /* these are not writable, only lockable */
+ return RCODE_TYPE_ERROR;
+
+ /* address gap to end - fall through */
+ default:
+ return RCODE_ADDRESS_ERROR;
+ }
+
+ return RCODE_COMPLETE;
+}
+
+#undef out
+
+
+/* helper function for lock_regs */
+inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg)
+{
+ if (*old == arg) {
+ *old = data;
+ }
+}
+
+static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
+ quadlet_t data, quadlet_t arg, int extcode)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+ unsigned long flags;
+
+ if (csraddr & 0x3) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ if ((csraddr >= CSR_BUS_MANAGER_ID)
+ && (csraddr <= CSR_CHANNELS_AVAILABLE_LO)) {
+ if (extcode == EXTCODE_COMPARE_SWAP) {
+ spin_lock_irqsave(&host->csr.lock, flags);
+
+ switch (csraddr) {
+ case CSR_BUS_MANAGER_ID:
+ *store = host->csr.bus_manager_id;
+ compare_swap(&host->csr.bus_manager_id,
+ data, arg);
+ break;
+
+ case CSR_BANDWIDTH_AVAILABLE:
+ *store = host->csr.bandwidth_available;
+ compare_swap(&host->csr.bandwidth_available,
+ data, arg);
+ break;
+
+ case CSR_CHANNELS_AVAILABLE_HI:
+ *store = host->csr.channels_available_hi;
+ compare_swap(&host->csr.channels_available_hi,
+ data, arg);
+ break;
+
+ case CSR_CHANNELS_AVAILABLE_LO:
+ *store = host->csr.channels_available_lo;
+ compare_swap(&host->csr.channels_available_lo,
+ data, arg);
+ break;
+ }
+
+ spin_unlock_irqrestore(&host->csr.lock, flags);
+ return RCODE_COMPLETE;
+ } else {
+ return RCODE_TYPE_ERROR;
+ }
+ }
+
+ /* no locking for anything else yet */
+ switch (csraddr) {
+ case CSR_STATE_CLEAR:
+ case CSR_STATE_SET:
+ case CSR_RESET_START:
+ case CSR_NODE_IDS:
+ case CSR_SPLIT_TIMEOUT_HI:
+ case CSR_SPLIT_TIMEOUT_LO:
+ case CSR_CYCLE_TIME:
+ case CSR_BUS_TIME:
+ return RCODE_TYPE_ERROR;
+
+ case CSR_BUSY_TIMEOUT:
+ /* not yet implemented - fall through */
+ default:
+ return RCODE_ADDRESS_ERROR;
+ }
+}
+
+
+struct hpsb_highlevel_ops csr_ops = {
+ add_host,
+ NULL,
+ host_reset,
+ NULL
+};
+
+
+struct hpsb_address_ops map_ops = {
+ read_maps,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct hpsb_address_ops fcp_ops = {
+ read_fcp,
+ write_fcp,
+ NULL,
+ NULL
+};
+
+struct hpsb_address_ops reg_ops = {
+ read_regs,
+ write_regs,
+ lock_regs,
+ NULL
+};
+
+
+void init_csr(void)
+{
+ struct hpsb_highlevel *hl;
+
+ hl = hpsb_register_highlevel("standard registers", &csr_ops);
+ if (hl == NULL) {
+ HPSB_ERR("out of memory during ieee1394 initialization");
+ return;
+ }
+
+ hpsb_register_addrspace(hl, &reg_ops, CSR_REGISTER_BASE,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM);
+ hpsb_register_addrspace(hl, &map_ops,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
+ hpsb_register_addrspace(hl, &fcp_ops,
+ CSR_REGISTER_BASE + CSR_FCP_COMMAND,
+ CSR_REGISTER_BASE + CSR_FCP_END);
+ hpsb_register_addrspace(hl, &map_ops,
+ CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
+ CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
+ hpsb_register_addrspace(hl, &map_ops,
+ CSR_REGISTER_BASE + CSR_SPEED_MAP,
+ CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
+}
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
new file mode 100644
index 000000000..70bacdd10
--- /dev/null
+++ b/drivers/ieee1394/csr.h
@@ -0,0 +1,55 @@
+
+#ifndef _IEEE1394_CSR_H
+#define _IEEE1394_CSR_H
+
+#define CSR_REGISTER_BASE 0xfffff0000000ULL
+
+/* register offsets relative to CSR_REGISTER_BASE */
+#define CSR_STATE_CLEAR 0x0
+#define CSR_STATE_SET 0x4
+#define CSR_NODE_IDS 0x8
+#define CSR_RESET_START 0xc
+#define CSR_SPLIT_TIMEOUT_HI 0x18
+#define CSR_SPLIT_TIMEOUT_LO 0x1c
+#define CSR_CYCLE_TIME 0x200
+#define CSR_BUS_TIME 0x204
+#define CSR_BUSY_TIMEOUT 0x210
+#define CSR_BUS_MANAGER_ID 0x21c
+#define CSR_BANDWIDTH_AVAILABLE 0x220
+#define CSR_CHANNELS_AVAILABLE_HI 0x224
+#define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_CONFIG_ROM 0x400
+#define CSR_CONFIG_ROM_END 0x800
+#define CSR_FCP_COMMAND 0xB00
+#define CSR_FCP_RESPONSE 0xD00
+#define CSR_FCP_END 0xF00
+#define CSR_TOPOLOGY_MAP 0x1000
+#define CSR_TOPOLOGY_MAP_END 0x1400
+#define CSR_SPEED_MAP 0x2000
+#define CSR_SPEED_MAP_END 0x3000
+
+
+struct csr_control {
+ spinlock_t lock;
+
+ quadlet_t state;
+ quadlet_t node_ids;
+ quadlet_t split_timeout_hi, split_timeout_lo;
+ quadlet_t cycle_time;
+ quadlet_t bus_time;
+ quadlet_t bus_manager_id;
+ quadlet_t bandwidth_available;
+ quadlet_t channels_available_hi, channels_available_lo;
+
+ const quadlet_t *rom;
+ size_t rom_size;
+
+ quadlet_t topology_map[256];
+ quadlet_t speed_map[1024];
+ quadlet_t fcp_data[1024];
+};
+
+
+void init_csr(void);
+
+#endif /* _IEEE1394_CSR_H */
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
new file mode 100644
index 000000000..3b4ac40f5
--- /dev/null
+++ b/drivers/ieee1394/highlevel.c
@@ -0,0 +1,402 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"
+
+
+LIST_HEAD(hl_drivers);
+rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED;
+
+LIST_HEAD(addr_space);
+rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
+
+/* addr_space list will have zero and max already included as bounds */
+static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
+static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
+
+struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
+ struct hpsb_highlevel_ops *ops)
+{
+ struct hpsb_highlevel *hl;
+
+ hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel),
+ GFP_KERNEL);
+ if (hl == NULL) {
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&hl->hl_list);
+ INIT_LIST_HEAD(&hl->addr_list);
+ hl->name = name;
+ hl->op = ops;
+
+ write_lock_irq(&hl_drivers_lock);
+ hl_all_hosts(hl, 1);
+ list_add_tail(&hl->hl_list, &hl_drivers);
+ write_unlock_irq(&hl_drivers_lock);
+
+ return hl;
+}
+
+void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
+{
+ struct list_head *entry;
+ struct hpsb_address_serve *as;
+
+ if (hl == NULL) {
+ return;
+ }
+
+ write_lock_irq(&addr_space_lock);
+ entry = hl->addr_list.next;
+
+ while (entry != &hl->addr_list) {
+ as = list_entry(entry, struct hpsb_address_serve, addr_list);
+ list_del(&as->as_list);
+ entry = entry->next;
+ kfree(as);
+ }
+ write_unlock_irq(&addr_space_lock);
+
+ write_lock_irq(&hl_drivers_lock);
+ list_del(&hl->hl_list);
+ hl_all_hosts(hl, 0);
+ write_unlock_irq(&hl_drivers_lock);
+
+ kfree(hl);
+}
+
+int hpsb_register_addrspace(struct hpsb_highlevel *hl,
+ struct hpsb_address_ops *ops, u64 start, u64 end)
+{
+ struct hpsb_address_serve *as;
+ struct list_head *entry;
+ int retval = 0;
+
+ if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
+ HPSB_ERR(__FUNCTION__ " called with invalid addresses");
+ return 0;
+ }
+
+ as = (struct hpsb_address_serve *)
+ kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
+ if (as == NULL) {
+ return 0;
+ }
+
+ INIT_LIST_HEAD(&as->as_list);
+ INIT_LIST_HEAD(&as->addr_list);
+ as->op = ops;
+ as->start = start;
+ as->end = end;
+
+ write_lock_irq(&addr_space_lock);
+ entry = addr_space.next;
+
+ while (list_entry(entry, struct hpsb_address_serve, as_list)->end
+ <= start) {
+ if (list_entry(entry->next, struct hpsb_address_serve, as_list)
+ ->start >= end) {
+ list_add(&as->as_list, entry);
+ list_add_tail(&as->addr_list, &hl->addr_list);
+ retval = 1;
+ break;
+ }
+ entry = entry->next;
+ }
+ write_unlock_irq(&addr_space_lock);
+
+ if (retval == 0) {
+ kfree(as);
+ }
+
+ return retval;
+}
+
+
+void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ unsigned int channel)
+{
+ if (channel > 63) {
+ HPSB_ERR(__FUNCTION__ " called with invalid channel");
+ return;
+ }
+
+ if (host->iso_listen_count[channel]++ == 0) {
+ host->template->devctl(host, ISO_LISTEN_CHANNEL, channel);
+ }
+}
+
+void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ unsigned int channel)
+{
+ if (channel > 63) {
+ HPSB_ERR(__FUNCTION__ " called with invalid channel");
+ return;
+ }
+
+ if (--host->iso_listen_count[channel] == 0) {
+ host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
+ }
+}
+
+
+#define DEFINE_MULTIPLEXER(Function) \
+void highlevel_##Function(struct hpsb_host *host) \
+{ \
+ struct list_head *entry; \
+ void (*funcptr)(struct hpsb_host*); \
+ read_lock(&hl_drivers_lock); \
+ entry = hl_drivers.next; \
+ while (entry != &hl_drivers) { \
+ funcptr = list_entry(entry, struct hpsb_highlevel, hl_list) \
+ ->op->Function; \
+ if (funcptr) funcptr(host); \
+ entry = entry->next; \
+ } \
+ read_unlock(&hl_drivers_lock); \
+}
+
+DEFINE_MULTIPLEXER(add_host)
+DEFINE_MULTIPLEXER(remove_host)
+DEFINE_MULTIPLEXER(host_reset)
+#undef DEFINE_MULTIPLEXER
+
+void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+ unsigned int length)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+ int channel = (data[0] >> 8) & 0x3f;
+
+ read_lock(&hl_drivers_lock);
+ entry = hl_drivers.next;
+
+ while (entry != &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+ if (hl->op->iso_receive) {
+ hl->op->iso_receive(host, channel, data, length);
+ }
+ entry = entry->next;
+ }
+ read_unlock(&hl_drivers_lock);
+}
+
+
+int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
+ unsigned int length)
+{
+ struct hpsb_address_serve *as;
+ struct list_head *entry;
+ unsigned int partlength;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ if ((addr | length) & 0x3) {
+ /* Addresses or lengths not a multiple of a quadlet pose a big
+ * problem on little endian machines because we always do this
+ * in arch endian and swapping would mess it all up. So we
+ * simply don't allow this at all. */
+ return RCODE_TYPE_ERROR;
+ }
+
+ read_lock(&addr_space_lock);
+
+ entry = addr_space.next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+
+ while (as->start <= addr) {
+ if (as->end > addr) {
+ partlength = MIN((unsigned int)(as->end - addr),
+ length);
+
+ if (as->op->read != NULL) {
+ rcode = as->op->read(host, buffer, addr,
+ partlength);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+ length -= partlength;
+ addr += partlength;
+
+ if ((rcode != RCODE_COMPLETE) || !length) {
+ break;
+ }
+ }
+
+ entry = entry->next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+ }
+
+ read_unlock(&addr_space_lock);
+
+ if (length && (rcode == RCODE_COMPLETE)) {
+ rcode = RCODE_ADDRESS_ERROR;
+ }
+
+ return rcode;
+}
+
+int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
+ unsigned int length)
+{
+ struct hpsb_address_serve *as;
+ struct list_head *entry;
+ unsigned int partlength;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ if ((addr | length) & 0x3) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ read_lock(&addr_space_lock);
+
+ entry = addr_space.next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+
+ while (as->start <= addr) {
+ if (as->end > addr) {
+ partlength = MIN((unsigned int)(as->end - addr),
+ length);
+
+ if (as->op->write != NULL) {
+ rcode = as->op->write(host, data, addr,
+ partlength);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+ length -= partlength;
+ addr += partlength;
+
+ if ((rcode != RCODE_COMPLETE) || !length) {
+ break;
+ }
+ }
+
+ entry = entry->next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+ }
+
+ read_unlock(&addr_space_lock);
+
+ if (length && (rcode == RCODE_COMPLETE)) {
+ rcode = RCODE_ADDRESS_ERROR;
+ }
+
+ return rcode;
+}
+
+
+int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
+ quadlet_t data, quadlet_t arg, int ext_tcode)
+{
+ struct hpsb_address_serve *as;
+ struct list_head *entry;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ read_lock(&addr_space_lock);
+
+ entry = addr_space.next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+
+ while (as->start <= addr) {
+ if (as->end > addr) {
+ if (as->op->lock != NULL) {
+ rcode = as->op->lock(host, store, addr, data,
+ arg, ext_tcode);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+ break;
+ }
+
+ entry = entry->next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+ }
+
+ read_unlock(&addr_space_lock);
+
+ return rcode;
+}
+
+int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
+ octlet_t data, octlet_t arg, int ext_tcode)
+{
+ struct hpsb_address_serve *as;
+ struct list_head *entry;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ read_lock(&addr_space_lock);
+
+ entry = addr_space.next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+
+ while (as->start <= addr) {
+ if (as->end > addr) {
+ if (as->op->lock64 != NULL) {
+ rcode = as->op->lock64(host, store, addr, data,
+ arg, ext_tcode);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+ break;
+ }
+
+ entry = entry->next;
+ as = list_entry(entry, struct hpsb_address_serve, as_list);
+ }
+
+ read_unlock(&addr_space_lock);
+
+ return rcode;
+}
+
+
+
+#ifndef MODULE
+
+void register_builtin_highlevels(void)
+{
+#ifdef CONFIG_IEEE1394_RAWIO
+ {
+ int init_raw1394(void);
+ init_raw1394();
+ }
+#endif
+}
+
+#endif /* !MODULE */
+
+
+void init_hpsb_highlevel(void)
+{
+ INIT_LIST_HEAD(&dummy_zero_addr.as_list);
+ INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
+ INIT_LIST_HEAD(&dummy_max_addr.as_list);
+ INIT_LIST_HEAD(&dummy_max_addr.addr_list);
+
+ dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
+
+ dummy_zero_addr.start = dummy_zero_addr.end = 0;
+ dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
+
+ list_add_tail(&dummy_zero_addr.as_list, &addr_space);
+ list_add_tail(&dummy_max_addr.as_list, &addr_space);
+
+#ifndef MODULE
+ register_builtin_highlevels();
+#endif
+}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
new file mode 100644
index 000000000..9bf406742
--- /dev/null
+++ b/drivers/ieee1394/highlevel.h
@@ -0,0 +1,133 @@
+
+#ifndef IEEE1394_HIGHLEVEL_H
+#define IEEE1394_HIGHLEVEL_H
+
+
+struct hpsb_highlevel {
+ struct list_head hl_list;
+
+ /* List of hpsb_address_serve. */
+ struct list_head addr_list;
+
+ const char *name;
+ struct hpsb_highlevel_ops *op;
+};
+
+
+struct hpsb_address_serve {
+ struct list_head as_list; /* global list */
+
+ struct list_head addr_list; /* hpsb_highlevel list */
+
+ struct hpsb_address_ops *op;
+
+ /* first address handled and first address behind, quadlet aligned */
+ u64 start, end;
+};
+
+
+/*
+ * The above structs are internal to highlevel driver handling. Only the
+ * following structures are of interest to actual highlevel drivers.
+ */
+
+struct hpsb_highlevel_ops {
+ /* Any of the following pointers can legally be NULL, except for
+ * iso_receive which can only be NULL when you don't request
+ * channels. */
+
+ /* New host initialized. Will also be called during
+ * hpsb_register_highlevel for all hosts already installed. */
+ void (*add_host) (struct hpsb_host *host);
+
+ /* Host about to be removed. Will also be called during
+ * hpsb_unregister_highlevel once for each host. */
+ void (*remove_host) (struct hpsb_host *host);
+
+ /* Host experienced bus reset with possible configuration changes. Note
+ * that this one may occur during interrupt/bottom half handling. You
+ * can not expect to be able to do stock hpsb_reads. */
+ void (*host_reset) (struct hpsb_host *host);
+
+ /* An isochronous packet was received. Channel contains the channel
+ * number for your convenience, it is also contained in the included
+ * packet header (first quadlet, CRCs are missing). You may get called
+ * for channel/host combinations you did not request. */
+ void (*iso_receive) (struct hpsb_host *host, int channel,
+ quadlet_t *data, unsigned int length);
+};
+
+struct hpsb_address_ops {
+ /*
+ * Null function pointers will make the respective operation complete
+ * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
+ * registers (just leave everything but read NULL).
+ *
+ * All functions shall return appropriate IEEE 1394 rcodes.
+ */
+
+ /* These functions have to implement block reads for themselves. */
+ int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr,
+ unsigned int length);
+ int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr,
+ unsigned int length);
+
+ /* Lock transactions: write results of ext_tcode operation into
+ * *store. */
+ int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr,
+ quadlet_t data, quadlet_t arg, int ext_tcode);
+ int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr,
+ octlet_t data, octlet_t arg, int ext_tcode);
+};
+
+
+void init_hpsb_highlevel(void);
+
+void highlevel_add_host(struct hpsb_host *host);
+void highlevel_remove_host(struct hpsb_host *host);
+void highlevel_host_reset(struct hpsb_host *host);
+
+int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
+ unsigned int length);
+int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
+ unsigned int length);
+int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
+ quadlet_t data, quadlet_t arg, int ext_tcode);
+int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
+ octlet_t data, octlet_t arg, int ext_tcode);
+
+void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+ unsigned int length);
+
+
+/*
+ * Register highlevel driver. The name pointer has to stay valid at all times
+ * because the string is not copied.
+ */
+struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
+ struct hpsb_highlevel_ops *ops);
+void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
+
+/*
+ * Register handlers for host address spaces. Start and end are 48 bit pointers
+ * and have to be quadlet aligned (end points to the first address behind the
+ * handled addresses. This function can be called multiple times for a single
+ * hpsb_highlevel to implement sparse register sets. The requested region must
+ * not overlap any previously allocated region, otherwise registering will fail.
+ *
+ * It returns true for successful allocation. There is no unregister function,
+ * all address spaces are deallocated together with the hpsb_highlevel.
+ */
+int hpsb_register_addrspace(struct hpsb_highlevel *hl,
+ struct hpsb_address_ops *ops, u64 start, u64 end);
+
+/*
+ * Enable or disable receving a certain isochronous channel through the
+ * iso_receive op.
+ */
+void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ unsigned int channel);
+void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ unsigned int channel);
+
+#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
new file mode 100644
index 000000000..1ac6a9595
--- /dev/null
+++ b/drivers/ieee1394/hosts.c
@@ -0,0 +1,344 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Low level (host adapter) management.
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ * Copyright (C) 1999 Emanuel Pirker
+ */
+
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"
+
+
+static struct hpsb_host_template *templates = NULL;
+spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * The following function is exported for module usage. It will
+ * be called from high-level drivers such as the raw driver.
+ */
+int hpsb_get_host_list(struct hpsb_host *list[], int list_size)
+{
+ struct hpsb_host *host, **ptr;
+ struct hpsb_host_template *tmpl;
+ int count=0;
+
+ ptr = list;
+
+ for (tmpl = templates ; tmpl != NULL; tmpl = tmpl->next) {
+ for (host = tmpl->hosts; (host != NULL) && (count < list_size);
+ host = host->next) {
+ *ptr = host;
+ ptr++;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/*
+ * This function calls the add_host/remove_host hooks for every host currently
+ * registered. Init == TRUE means add_host.
+ */
+void hl_all_hosts(struct hpsb_highlevel *hl, int init)
+{
+ struct hpsb_host_template *tmpl;
+ struct hpsb_host *host;
+
+ spin_lock(&templates_lock);
+
+ for (tmpl = templates; tmpl != NULL; tmpl = tmpl->next) {
+ for (host = tmpl->hosts; host != NULL; host = host->next) {
+ if (host->initialized) {
+ if (init) {
+ if (hl->op->add_host) {
+ hl->op->add_host(host);
+ }
+ } else {
+ if (hl->op->remove_host) {
+ hl->op->remove_host(host);
+ }
+ }
+ }
+ }
+ }
+
+ spin_unlock(&templates_lock);
+}
+
+int hpsb_inc_host_usage(struct hpsb_host *host)
+{
+ struct hpsb_host_template *tmpl;
+ struct hpsb_host *h;
+ int retval = 0;
+
+ spin_lock(&templates_lock);
+
+ for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) {
+ for (h = tmpl->hosts; h != NULL; h = h->next) {
+ if (h == host) {
+ tmpl->devctl(h, MODIFY_USAGE, 1);
+ retval = 1;
+ break;
+ }
+ }
+ }
+
+ spin_unlock(&templates_lock);
+
+ return retval;
+}
+
+void hpsb_dec_host_usage(struct hpsb_host *host)
+{
+ host->template->devctl(host, MODIFY_USAGE, 0);
+}
+
+/*
+ * The following function is exported for module usage. It will be called from
+ * the detect function of a adapter driver.
+ */
+struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
+ size_t hd_size)
+{
+ struct hpsb_host *h;
+
+ h = vmalloc(sizeof(struct hpsb_host) + hd_size);
+ if (h == NULL) {
+ return NULL;
+ }
+
+ memset(h, 0, sizeof(struct hpsb_host) + hd_size);
+ h->tlabel_count = 64;
+ INIT_LIST_HEAD(&h->pending_packets);
+ spin_lock_init(&h->pending_pkt_lock);
+ spin_lock_init(&h->tlabel_lock);
+ init_waitqueue_head(&h->tlabel_wait);
+
+ h->timeout_tq.routine = (void (*)(void*))abort_timedouts;
+ h->timeout_tq.data = h;
+
+ h->topology_map = h->csr.topology_map + 3;
+ h->speed_map = h->csr.speed_map + 2;
+
+ h->template = tmpl;
+ if (hd_size) {
+ h->hostdata = &h->embedded_hostdata[0];
+ }
+
+ if (tmpl->hosts == NULL) {
+ tmpl->hosts = h;
+ } else {
+ struct hpsb_host *last = tmpl->hosts;
+
+ while (last->next != NULL) {
+ last = last->next;
+ }
+ last->next = h;
+ }
+
+ return h;
+}
+
+static void free_all_hosts(struct hpsb_host_template *tmpl)
+{
+ struct hpsb_host *next, *host = tmpl->hosts;
+
+ while (host) {
+ next = host->next;
+ vfree(host);
+ host = next;
+ }
+}
+
+
+static void init_hosts(struct hpsb_host_template *tmpl)
+{
+ int count;
+ struct hpsb_host *host;
+
+ count = tmpl->detect_hosts(tmpl);
+
+ for (host = tmpl->hosts; host != NULL; host = host->next) {
+ if (tmpl->initialize_host(host)) {
+ host->initialized = 1;
+
+ highlevel_add_host(host);
+ reset_host_bus(host);
+
+ //kernel_thread(hpsb_host_thread, host,
+ // CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ }
+ }
+
+ tmpl->number_of_hosts = count;
+ HPSB_INFO("detected %d %s adapter%c", count, tmpl->name,
+ (count != 1 ? 's' : ' '));
+}
+
+static void shutdown_hosts(struct hpsb_host_template *tmpl)
+{
+ struct hpsb_host *host;
+
+ for (host = tmpl->hosts; host != NULL; host = host->next) {
+ if (host->initialized) {
+ host->initialized = 0;
+ abort_requests(host);
+
+ highlevel_remove_host(host);
+
+ tmpl->release_host(host);
+ while (test_bit(0, &host->timeout_tq.sync)) {
+ schedule();
+ }
+ }
+ }
+ free_all_hosts(tmpl);
+ tmpl->release_host(NULL);
+
+ tmpl->number_of_hosts = 0;
+}
+
+
+static int add_template(struct hpsb_host_template *new)
+{
+ new->next = NULL;
+ new->hosts = NULL;
+ new->number_of_hosts = 0;
+
+ spin_lock(&templates_lock);
+ if (templates == NULL) {
+ templates = new;
+ } else {
+ struct hpsb_host_template *last = templates;
+ while (last->next != NULL) {
+ last = last->next;
+ }
+ last->next = new;
+ }
+ spin_unlock(&templates_lock);
+
+ return 0;
+}
+
+static int remove_template(struct hpsb_host_template *tmpl)
+{
+ int retval = 0;
+
+ if (tmpl->number_of_hosts) {
+ HPSB_ERR("attempted to remove busy host template "
+ "of %s at address 0x%p", tmpl->name, tmpl);
+ return 1;
+ }
+
+ spin_lock(&templates_lock);
+ if (templates == tmpl) {
+ templates = tmpl->next;
+ } else {
+ struct hpsb_host_template *t;
+
+ t = templates;
+ while (t->next != tmpl && t->next != NULL) {
+ t = t->next;
+ }
+
+ if (t->next == NULL) {
+ HPSB_ERR("attempted to remove unregistered host template "
+ "of %s at address 0x%p", tmpl->name, tmpl);
+ retval = -1;
+ } else {
+ t->next = tmpl->next;
+ }
+ }
+ spin_unlock(&templates_lock);
+
+ inc_hpsb_generation();
+ return retval;
+}
+
+
+/*
+ * The following two functions are exported symbols for module usage.
+ */
+int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
+{
+ add_template(tmpl);
+ HPSB_INFO("registered %s driver, initializing now", tmpl->name);
+ init_hosts(tmpl);
+
+ return 0;
+}
+
+void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl)
+{
+ shutdown_hosts(tmpl);
+
+ if (remove_template(tmpl)) {
+ HPSB_PANIC("remove_template failed on %s", tmpl->name);
+ }
+}
+
+
+
+#ifndef MODULE
+
+/*
+ * This is the init function for builtin lowlevel drivers. To add new drivers
+ * put their setup code (get and register template) here. Module only
+ * drivers don't need to touch this.
+ */
+
+#define SETUP_TEMPLATE(name, visname) \
+do { \
+ extern struct hpsb_host_template *get_ ## name ## _template(void); \
+ t = get_ ## name ## _template(); \
+ \
+ if (t != NULL) { \
+ if(!hpsb_register_lowlevel(t)) { \
+ count++; \
+ } \
+ } else { \
+ HPSB_WARN(visname " driver returned no host template"); \
+ } \
+} while (0)
+
+void __init register_builtin_lowlevels()
+{
+ struct hpsb_host_template *t;
+ int count = 0;
+
+ /* Touch t to avoid warning if no drivers are configured to
+ * be built directly into the kernel. */
+ t = NULL;
+
+#ifdef CONFIG_IEEE1394_PCILYNX
+ SETUP_TEMPLATE(lynx, "Lynx");
+#endif
+
+#ifdef CONFIG_IEEE1394_AIC5800
+ SETUP_TEMPLATE(aic, "AIC-5800");
+#endif
+
+#ifdef CONFIG_IEEE1394_OHCI1394
+ SETUP_TEMPLATE(ohci, "OHCI-1394");
+#endif
+
+ HPSB_INFO("%d host adapter%s initialized", count,
+ (count != 1 ? "s" : ""));
+}
+
+#undef SETUP_TEMPLATE
+
+#endif /* !MODULE */
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
new file mode 100644
index 000000000..d516e7f8c
--- /dev/null
+++ b/drivers/ieee1394/hosts.h
@@ -0,0 +1,192 @@
+
+#ifndef _IEEE1394_HOSTS_H
+#define _IEEE1394_HOSTS_H
+
+#include <linux/wait.h>
+#include <linux/tqueue.h>
+
+#include "ieee1394_types.h"
+#include "csr.h"
+
+
+struct hpsb_packet;
+
+struct hpsb_host {
+/* private fields (hosts, do not use them) */
+ struct hpsb_host *next;
+
+ struct list_head pending_packets;
+ spinlock_t pending_pkt_lock;
+ struct tq_struct timeout_tq;
+
+ /* A bitmask where a set bit means that this tlabel is in use.
+ * FIXME - should be handled per node instead of per bus. */
+ u32 tlabel_pool[2];
+ int tlabel_count;
+ spinlock_t tlabel_lock;
+ wait_queue_head_t tlabel_wait;
+
+ int reset_retries;
+ quadlet_t *topology_map, *speed_map;
+ struct csr_control csr;
+
+ unsigned char iso_listen_count[64];
+
+/* readonly fields for hosts */
+ struct hpsb_host_template *template;
+
+ int node_count; /* number of identified nodes on this bus */
+ int selfid_count; /* total number of SelfIDs received */
+
+ nodeid_t node_id; /* node ID of this host */
+ nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
+ nodeid_t busmgr_id; /* ID of this bus' bus manager */
+
+ unsigned initialized:1; /* initialized and usable */
+ unsigned in_bus_reset:1; /* in bus reset / SelfID stage */
+ unsigned attempt_root:1; /* attempt to become root during next reset */
+
+ /* this nodes' duties on the bus */
+ unsigned is_root:1;
+ unsigned is_cycmst:1;
+ unsigned is_irm:1;
+ unsigned is_busmgr:1;
+
+/* fields readable and writeable by the hosts */
+
+ void *hostdata;
+ int embedded_hostdata[0];
+};
+
+
+
+enum devctl_cmd {
+ /* Host is requested to reset its bus and cancel all outstanding async
+ * requests. If arg == 1, it shall also attempt to become root on the
+ * bus. Return void. */
+ RESET_BUS,
+
+ /* Arg is void, return value is the hardware cycle counter value. */
+ GET_CYCLE_COUNTER,
+
+ /* Set the hardware cycle counter to the value in arg, return void.
+ * FIXME - setting is probably not required. */
+ SET_CYCLE_COUNTER,
+
+ /* Configure hardware for new bus ID in arg, return void. */
+ SET_BUS_ID,
+
+ /* If arg true, start sending cycle start packets, stop if arg == 0.
+ * Return void. */
+ ACT_CYCLE_MASTER,
+
+ /* Cancel all outstanding async requests without resetting the bus.
+ * Return void. */
+ CANCEL_REQUESTS,
+
+ /* Decrease module usage count if arg == 0, increase otherwise. Return
+ * void. */
+ MODIFY_USAGE,
+
+ /* Start or stop receiving isochronous channel in arg. Return void.
+ * This acts as an optimization hint, hosts are not required not to
+ * listen on unrequested channels. */
+ ISO_LISTEN_CHANNEL,
+ ISO_UNLISTEN_CHANNEL
+};
+
+struct hpsb_host_template {
+ struct hpsb_host_template *next;
+
+ struct hpsb_host *hosts;
+ int number_of_hosts;
+
+ /* fields above will be ignored and overwritten after registering */
+
+ /* This should be the name of the driver (single word) and must not be
+ * NULL. */
+ const char *name;
+
+ /* This function shall detect all available adapters of this type and
+ * call hpsb_get_host for each one. The initialize_host function will
+ * be called to actually set up these adapters. The number of detected
+ * adapters or zero if there are none must be returned.
+ */
+ int (*detect_hosts) (struct hpsb_host_template *template);
+
+ /* After detecting and registering hosts, this function will be called
+ * for every registered host. It shall set up the host to be fully
+ * functional for bus operations and return 0 for failure.
+ */
+ int (*initialize_host) (struct hpsb_host *host);
+
+ /* To unload modules, this function is provided. It shall free all
+ * resources this host is using (if host is not NULL) or free all
+ * resources globally allocated by the driver (if host is NULL).
+ */
+ void (*release_host) (struct hpsb_host *host);
+
+ /* This function must store a pointer to the configuration ROM into the
+ * location referenced to by pointer and return the size of the ROM. It
+ * may not fail. If any allocation is required, it must be done
+ * earlier.
+ */
+ size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
+
+ /* This function shall implement packet transmission based on
+ * packet->type. It shall CRC both parts of the packet (unless
+ * packet->type == raw) and do byte-swapping as necessary or instruct
+ * the hardware to do so. It can return immediately after the packet
+ * was queued for sending. After sending, hpsb_sent_packet() has to be
+ * called. Return 0 for failure.
+ * NOTE: The function must be callable in interrupt context.
+ */
+ int (*transmit_packet) (struct hpsb_host *host,
+ struct hpsb_packet *packet);
+
+ /* This function requests miscellanous services from the driver, see
+ * above for command codes and expected actions. Return -1 for unknown
+ * command, though that should never happen.
+ */
+ int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg);
+};
+
+
+
+/* mid level internal use */
+void register_builtin_lowlevels(void);
+
+/* high level internal use */
+struct hpsb_highlevel;
+void hl_all_hosts(struct hpsb_highlevel *hl, int init);
+
+/*
+ * These functions are for lowlevel (host) driver use.
+ */
+int hpsb_register_lowlevel(struct hpsb_host_template *tmpl);
+void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl);
+
+/*
+ * Get a initialized host structure with hostdata_size bytes allocated in
+ * embedded_hostdata for free usage. Returns NULL for failure.
+ */
+struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
+ size_t hostdata_size);
+
+/*
+ * Write pointers to all available hpsb_hosts into list.
+ * Return number of host adapters (i.e. elements in list).
+ *
+ * DEPRECATED - register with highlevel instead.
+ */
+int hpsb_get_host_list(struct hpsb_host *list[], int max_list_size);
+
+/*
+ * Increase / decrease host usage counter. Increase function will return true
+ * only if successful (host still existed). Decrease function expects host to
+ * exist.
+ */
+int hpsb_inc_host_usage(struct hpsb_host *host);
+void hpsb_dec_host_usage(struct hpsb_host *host);
+
+#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
new file mode 100644
index 000000000..dfca3aef3
--- /dev/null
+++ b/drivers/ieee1394/ieee1394.h
@@ -0,0 +1,66 @@
+/*
+ * Generic IEEE 1394 definitions
+ */
+
+#ifndef _IEEE1394_IEEE1394_H
+#define _IEEE1394_IEEE1394_H
+
+#define TCODE_WRITEQ 0x0
+#define TCODE_WRITEB 0x1
+#define TCODE_WRITE_RESPONSE 0x2
+#define TCODE_READQ 0x4
+#define TCODE_READB 0x5
+#define TCODE_READQ_RESPONSE 0x6
+#define TCODE_READB_RESPONSE 0x7
+#define TCODE_CYCLE_START 0x8
+#define TCODE_LOCK_REQUEST 0x9
+#define TCODE_ISO_DATA 0xa
+#define TCODE_LOCK_RESPONSE 0xb
+
+#define RCODE_COMPLETE 0x0
+#define RCODE_CONFLICT_ERROR 0x4
+#define RCODE_DATA_ERROR 0x5
+#define RCODE_TYPE_ERROR 0x6
+#define RCODE_ADDRESS_ERROR 0x7
+
+#define EXTCODE_MASK_SWAP 0x1
+#define EXTCODE_COMPARE_SWAP 0x2
+#define EXTCODE_FETCH_ADD 0x3
+#define EXTCODE_LITTLE_ADD 0x4
+#define EXTCODE_BOUNDED_ADD 0x5
+#define EXTCODE_WRAP_ADD 0x6
+
+#define ACK_COMPLETE 0x1
+#define ACK_PENDING 0x2
+#define ACK_BUSY_X 0x4
+#define ACK_BUSY_A 0x5
+#define ACK_BUSY_B 0x6
+#define ACK_DATA_ERROR 0xd
+#define ACK_TYPE_ERROR 0xe
+
+/* Non-standard "ACK codes" for internal use */
+#define ACKX_NONE -1
+#define ACKX_SEND_ERROR -2
+#define ACKX_ABORTED -3
+#define ACKX_TIMEOUT -4
+
+
+#define SPEED_100 0x0
+#define SPEED_200 0x1
+#define SPEED_400 0x2
+
+#define SELFID_PWRCL_NO_POWER 0x0
+#define SELFID_PWRCL_PROVIDE_15W 0x1
+#define SELFID_PWRCL_PROVIDE_30W 0x2
+#define SELFID_PWRCL_PROVIDE_45W 0x3
+#define SELFID_PWRCL_USE_1W 0x4
+#define SELFID_PWRCL_USE_3W 0x5
+#define SELFID_PWRCL_USE_6W 0x6
+#define SELFID_PWRCL_USE_10W 0x7
+
+#define SELFID_PORT_CHILD 0x3
+#define SELFID_PORT_PARENT 0x2
+#define SELFID_PORT_NCONN 0x1
+#define SELFID_PORT_NONE 0x0
+
+#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
new file mode 100644
index 000000000..eccbe8933
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -0,0 +1,698 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Core support: hpsb_packet management, packet handling and forwarding to
+ * csr or lowlevel code
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/semaphore.h>
+
+#include "ieee1394_types.h"
+#include "ieee1394.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"
+#include "ieee1394_transactions.h"
+#include "csr.h"
+
+
+atomic_t hpsb_generation = ATOMIC_INIT(0);
+
+
+static void dump_packet(const char *text, quadlet_t *data, int size)
+{
+ int i;
+
+ size /= 4;
+ size = (size > 4 ? 4 : size);
+
+ printk(KERN_DEBUG "ieee1394: %s", text);
+ for (i = 0; i < size; i++) {
+ printk(" %8.8x", data[i]);
+ }
+ printk("\n");
+}
+
+
+struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
+{
+ struct hpsb_packet *packet = NULL;
+ void *header = NULL, *data = NULL;
+ int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+
+ packet = kmalloc(sizeof(struct hpsb_packet), kmflags);
+ header = kmalloc(5 * 4, kmflags);
+ if (header == NULL || packet == NULL) {
+ kfree(header);
+ kfree(packet);
+ return NULL;
+ }
+
+ memset(packet, 0, sizeof(struct hpsb_packet));
+ packet->header = header;
+
+ if (data_size) {
+ data = kmalloc(data_size + 4, kmflags);
+ if (data == NULL) {
+ kfree(header);
+ kfree(packet);
+ return NULL;
+ }
+
+ packet->data = data;
+ packet->data_size = data_size - 4;
+ }
+
+ INIT_LIST_HEAD(&packet->list);
+ sema_init(&packet->state_change, 0);
+ packet->state = unused;
+ packet->generation = get_hpsb_generation();
+
+#ifdef __BIG_ENDIAN
+ /* set default */
+ packet->data_be = 1;
+#endif
+
+ return packet;
+}
+
+void free_hpsb_packet(struct hpsb_packet *packet)
+{
+ if (packet == NULL) {
+ return;
+ }
+
+ kfree(packet->data);
+ kfree(packet->header);
+ kfree(packet);
+}
+
+
+void reset_host_bus(struct hpsb_host *host)
+{
+ if (!host->initialized) {
+ return;
+ }
+
+ hpsb_bus_reset(host);
+ host->template->devctl(host, RESET_BUS, 0);
+}
+
+
+void hpsb_bus_reset(struct hpsb_host *host)
+{
+ if (!host->in_bus_reset) {
+ abort_requests(host);
+ host->in_bus_reset = 1;
+ host->irm_id = -1;
+ host->busmgr_id = -1;
+ host->node_count = 0;
+ host->selfid_count = 0;
+ } else {
+ HPSB_NOTICE(__FUNCTION__
+ " called while bus reset already in progress");
+ }
+}
+
+
+/*
+ * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in
+ * case verification failed.
+ */
+static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
+{
+ int nodeid = -1;
+ int rest_of_selfids = num_of_selfids;
+ quadlet_t *sidp = host->topology_map;
+ quadlet_t sid = *sidp;
+ int esid_seq = 23;
+ int i;
+
+ while (rest_of_selfids--) {
+ sid = *(sidp++);
+
+ if (!(sid & 0x00800000) /* !extended */) {
+ nodeid++;
+ esid_seq = 0;
+
+ if (((sid >> 24) & NODE_MASK) != nodeid) {
+ HPSB_INFO("SelfIDs failed monotony check with "
+ "%d", (sid >> 24) & NODE_MASK);
+ return 0;
+ }
+
+ /* "if is contender and link active" */
+ if ((sid & (1<<11)) && (sid & (1<<22))) {
+ host->irm_id = LOCAL_BUS | ((sid >> 24)
+ & NODE_MASK);
+ }
+ } else {
+ if ((((sid >> 24) & NODE_MASK) != nodeid)
+ || (((sid >> 20) & 0x7) != esid_seq)) {
+ HPSB_INFO("SelfIDs failed monotony check with "
+ "%d/%d", (sid >> 24) & NODE_MASK,
+ (sid >> 20) & 0x7);
+ return 0;
+ }
+ esid_seq++;
+ }
+ }
+
+ sidp--;
+ while (sid & 0x00800000 /* extended */) {
+ /* check that no ports go to a parent */
+ for (i = 2; i < 18; i += 2) {
+ if ((sid & (0x3 << i)) == (0x2 << i)) {
+ HPSB_INFO("SelfIDs failed root check on "
+ "extended SelfID");
+ return 0;
+ }
+ }
+ sid = *(sidp--);
+ }
+
+ for (i = 2; i < 8; i += 2) {
+ if ((sid & (0x3 << i)) == (0x2 << i)) {
+ HPSB_INFO("SelfIDs failed root check");
+ return 0;
+ }
+ }
+
+ return nodeid + 1;
+}
+
+void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
+{
+ if (host->in_bus_reset) {
+ printk("including selfid 0x%x\n", sid);
+ host->topology_map[host->selfid_count++] = sid;
+ } else {
+ /* FIXME - info on which host */
+ HPSB_NOTICE("spurious selfid packet (0x%8.8x) received", sid);
+ }
+}
+
+void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
+{
+
+
+ host->node_id = 0xffc0 | phyid;
+ host->in_bus_reset = 0;
+ host->is_root = isroot;
+
+ host->node_count = check_selfids(host, host->selfid_count);
+ if (!host->node_count) {
+ if (host->reset_retries++ < 20) {
+ /* selfid stage did not complete without error */
+ HPSB_NOTICE("error in SelfID stage - resetting");
+ reset_host_bus(host);
+ return;
+ } else {
+ HPSB_NOTICE("stopping out-of-control reset loop");
+ HPSB_NOTICE("warning - topology map will therefore not "
+ "be valid");
+ }
+ }
+
+ /* irm_id is kept up to date by check_selfids() */
+ host->is_irm = (host->irm_id == host->node_id);
+
+ host->reset_retries = 0;
+ inc_hpsb_generation();
+ highlevel_host_reset(host);
+}
+
+
+void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
+ int ackcode)
+{
+ unsigned long flags;
+
+ packet->ack_code = ackcode;
+
+ if (packet->no_waiter) {
+ /* must not have a tlabel allocated */
+ free_hpsb_packet(packet);
+ return;
+ }
+
+ if (ackcode != ACK_PENDING || !packet->expect_response) {
+ packet->state = complete;
+ up(&packet->state_change);
+ up(&packet->state_change);
+ run_task_queue(&packet->complete_tq);
+ return;
+ }
+
+ packet->state = pending;
+ packet->sendtime = jiffies;
+
+ spin_lock_irqsave(&host->pending_pkt_lock, flags);
+ list_add_tail(&packet->list, &host->pending_packets);
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+
+ up(&packet->state_change);
+ queue_task(&host->timeout_tq, &tq_timer);
+}
+
+int hpsb_send_packet(struct hpsb_packet *packet)
+{
+ struct hpsb_host *host = packet->host;
+
+ if (!host->initialized || host->in_bus_reset
+ || (packet->generation != get_hpsb_generation())) {
+ return 0;
+ }
+
+ packet->state = queued;
+
+ dump_packet("send packet:", packet->header, packet->header_size);
+
+ return host->template->transmit_packet(host, packet);
+}
+
+static void send_packet_nocare(struct hpsb_packet *packet)
+{
+ if (!hpsb_send_packet(packet)) {
+ free_hpsb_packet(packet);
+ }
+}
+
+
+void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data,
+ size_t size)
+{
+ struct hpsb_packet *packet = NULL;
+ struct list_head *lh;
+ int tcode_match = 0;
+ int tlabel;
+ unsigned long flags;
+
+ tlabel = (data[0] >> 10) & 0x3f;
+
+ spin_lock_irqsave(&host->pending_pkt_lock, flags);
+
+ lh = host->pending_packets.next;
+ while (lh != &host->pending_packets) {
+ packet = list_entry(lh, struct hpsb_packet, list);
+ if ((packet->tlabel == tlabel)
+ && (packet->node_id == (data[1] >> 16))){
+ break;
+ }
+ lh = lh->next;
+ }
+
+ if (lh == &host->pending_packets) {
+ HPSB_INFO("unsolicited response packet received - np");
+ dump_packet("contents:", data, 16);
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+ return;
+ }
+
+ switch (packet->tcode) {
+ case TCODE_WRITEQ:
+ case TCODE_WRITEB:
+ if (tcode == TCODE_WRITE_RESPONSE) tcode_match = 1;
+ break;
+ case TCODE_READQ:
+ if (tcode == TCODE_READQ_RESPONSE) tcode_match = 1;
+ break;
+ case TCODE_READB:
+ if (tcode == TCODE_READB_RESPONSE) tcode_match = 1;
+ break;
+ case TCODE_LOCK_REQUEST:
+ if (tcode == TCODE_LOCK_RESPONSE) tcode_match = 1;
+ break;
+ }
+
+ if (!tcode_match || (packet->tlabel != tlabel)
+ || (packet->node_id != (data[1] >> 16))) {
+ HPSB_INFO("unsolicited response packet received");
+ dump_packet("contents:", data, 16);
+
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+ return;
+ }
+
+ list_del(&packet->list);
+
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+
+ /* FIXME - update size fields? */
+ switch (tcode) {
+ case TCODE_WRITE_RESPONSE:
+ memcpy(packet->header, data, 12);
+ break;
+ case TCODE_READQ_RESPONSE:
+ memcpy(packet->header, data, 16);
+ break;
+ case TCODE_READB_RESPONSE:
+ memcpy(packet->header, data, 16);
+ memcpy(packet->data, data + 4, size - 16);
+ break;
+ case TCODE_LOCK_RESPONSE:
+ memcpy(packet->header, data, 16);
+ memcpy(packet->data, data + 4, (size - 16) > 8 ? 8 : size - 16);
+ break;
+ }
+
+ packet->state = complete;
+ up(&packet->state_change);
+ run_task_queue(&packet->complete_tq);
+}
+
+
+struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
+ size_t dsize)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(dsize);
+ if (p == NULL) {
+ /* FIXME - send data_error response */
+ return NULL;
+ }
+
+ p->type = async;
+ p->state = unused;
+ p->host = host;
+ p->node_id = data[1] >> 16;
+ p->tlabel = (data[0] >> 10) & 0x3f;
+ p->no_waiter = 1;
+
+ return p;
+}
+
+#define PREP_REPLY_PACKET(length) \
+ packet = create_reply_packet(host, data, length); \
+ if (packet == NULL) break
+
+inline void swap_quadlets_on_le(quadlet_t *q)
+{
+#ifdef __LITTLE_ENDIAN
+ quadlet_t saved = q[0];
+ q[0] = q[1];
+ q[1] = saved;
+#endif
+}
+
+
+void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
+ size_t size)
+{
+ struct hpsb_packet *packet;
+ int length, rcode, extcode;
+ u64 addr;
+
+ /* big FIXME - no error checking is done for an out of bounds length */
+
+ switch (tcode) {
+ case TCODE_WRITEQ:
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_write(host, data+3, addr, 4);
+
+ if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+ /* not a broadcast write, reply */
+ PREP_REPLY_PACKET(0);
+ fill_async_write_resp(packet, rcode);
+ send_packet_nocare(packet);
+ }
+ break;
+
+ case TCODE_WRITEB:
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_write(host, data+4, addr, data[3]>>16);
+
+ if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+ /* not a broadcast write, reply */
+ PREP_REPLY_PACKET(0);
+ fill_async_write_resp(packet, rcode);
+ send_packet_nocare(packet);
+ }
+ break;
+
+ case TCODE_READQ:
+ PREP_REPLY_PACKET(0);
+
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_read(host, data, addr, 4);
+ fill_async_readquad_resp(packet, rcode, *data);
+ send_packet_nocare(packet);
+ break;
+
+ case TCODE_READB:
+ length = data[3] >> 16;
+ PREP_REPLY_PACKET(length);
+
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_read(host, packet->data, addr, length);
+ fill_async_readblock_resp(packet, rcode, length);
+ send_packet_nocare(packet);
+ break;
+
+ case TCODE_LOCK_REQUEST:
+ length = data[3] >> 16;
+ extcode = data[3] & 0xffff;
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+
+ PREP_REPLY_PACKET(8);
+
+ if ((extcode == 0) || (extcode >= 7)) {
+ /* let switch default handle error */
+ length = 0;
+ }
+
+ switch (length) {
+ case 4:
+ rcode = highlevel_lock(host, packet->data, addr,
+ data[4], 0, extcode);
+ fill_async_lock_resp(packet, rcode, extcode, 4);
+ break;
+ case 8:
+ if ((extcode != EXTCODE_FETCH_ADD)
+ && (extcode != EXTCODE_LITTLE_ADD)) {
+ rcode = highlevel_lock(host, packet->data, addr,
+ data[5], data[4],
+ extcode);
+ fill_async_lock_resp(packet, rcode, extcode, 4);
+ } else {
+ swap_quadlets_on_le(data + 4);
+ rcode = highlevel_lock64(host,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 4), 0ULL,
+ extcode);
+ swap_quadlets_on_le(packet->data);
+ fill_async_lock_resp(packet, rcode, extcode, 8);
+ }
+ break;
+ case 16:
+ swap_quadlets_on_le(data + 4);
+ swap_quadlets_on_le(data + 6);
+ rcode = highlevel_lock64(host, (octlet_t *)packet->data,
+ addr, *(octlet_t *)(data + 6),
+ *(octlet_t *)(data + 4),
+ extcode);
+ swap_quadlets_on_le(packet->data);
+ fill_async_lock_resp(packet, rcode, extcode, 8);
+ break;
+ default:
+ fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
+ extcode, 0);
+ }
+
+ send_packet_nocare(packet);
+ break;
+ }
+
+}
+#undef PREP_REPLY_PACKET
+
+
+void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size)
+{
+ int tcode;
+
+ if (host->in_bus_reset) {
+ HPSB_INFO("received packet during reset; ignoring");
+ return;
+ }
+
+ dump_packet("received packet:", data, size);
+
+ tcode = (data[0] >> 4) & 0xf;
+
+ switch (tcode) {
+ case TCODE_WRITE_RESPONSE:
+ case TCODE_READQ_RESPONSE:
+ case TCODE_READB_RESPONSE:
+ case TCODE_LOCK_RESPONSE:
+ handle_packet_response(host, tcode, data, size);
+ break;
+
+ case TCODE_WRITEQ:
+ case TCODE_WRITEB:
+ case TCODE_READQ:
+ case TCODE_READB:
+ case TCODE_LOCK_REQUEST:
+ handle_incoming_packet(host, tcode, data, size);
+ break;
+
+
+ case TCODE_ISO_DATA:
+ highlevel_iso_receive(host, data, size);
+ break;
+
+ case TCODE_CYCLE_START:
+ /* simply ignore this packet if it is passed on */
+ break;
+
+ default:
+ HPSB_NOTICE("received packet with bogus transaction code %d",
+ tcode);
+ break;
+ }
+}
+
+
+void abort_requests(struct hpsb_host *host)
+{
+ unsigned long flags;
+ struct hpsb_packet *packet;
+ struct list_head *lh;
+ LIST_HEAD(llist);
+
+ host->template->devctl(host, CANCEL_REQUESTS, 0);
+
+ spin_lock_irqsave(&host->pending_pkt_lock, flags);
+ list_splice(&host->pending_packets, &llist);
+ INIT_LIST_HEAD(&host->pending_packets);
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+
+ lh = llist.next;
+
+ while (lh != &llist) {
+ packet = list_entry(lh, struct hpsb_packet, list);
+ lh = lh->next;
+ packet->state = complete;
+ packet->ack_code = ACKX_ABORTED;
+ up(&packet->state_change);
+ run_task_queue(&packet->complete_tq);
+ }
+}
+
+void abort_timedouts(struct hpsb_host *host)
+{
+ unsigned long flags;
+ struct hpsb_packet *packet;
+ unsigned long expire;
+ struct list_head *lh;
+ LIST_HEAD(expiredlist);
+
+ spin_lock_irqsave(&host->csr.lock, flags);
+ expire = (host->csr.split_timeout_hi * 8000
+ + (host->csr.split_timeout_lo >> 19))
+ * HZ / 8000;
+ /* Avoid shortening of timeout due to rounding errors: */
+ expire++;
+ spin_unlock_irqrestore(&host->csr.lock, flags);
+
+
+ spin_lock_irqsave(&host->pending_pkt_lock, flags);
+ lh = host->pending_packets.next;
+
+ while (lh != &host->pending_packets) {
+ packet = list_entry(lh, struct hpsb_packet, list);
+ lh = lh->next;
+ if (time_before(packet->sendtime + expire, jiffies)) {
+ list_del(&packet->list);
+ list_add(&packet->list, &expiredlist);
+ }
+ }
+
+ if (!list_empty(&host->pending_packets)) {
+ queue_task(&host->timeout_tq, &tq_timer);
+ }
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+
+ lh = expiredlist.next;
+ while (lh != &expiredlist) {
+ packet = list_entry(lh, struct hpsb_packet, list);
+ lh = lh->next;
+ packet->state = complete;
+ packet->ack_code = ACKX_TIMEOUT;
+ up(&packet->state_change);
+ run_task_queue(&packet->complete_tq);
+ }
+}
+
+
+#if 0
+int hpsb_host_thread(void *hostPointer)
+{
+ struct hpsb_host *host = (struct hpsb_host *)hostPointer;
+
+ /* I don't understand why, but I just want to be on the safe side. */
+ lock_kernel();
+
+ HPSB_INFO(__FUNCTION__ " starting for one %s adapter",
+ host->template->name);
+
+ exit_mm(current);
+ exit_files(current);
+ exit_fs(current);
+
+ strcpy(current->comm, "ieee1394 thread");
+
+ /* ... but then again, I think the following is safe. */
+ unlock_kernel();
+
+ for (;;) {
+ siginfo_t info;
+ unsigned long signr;
+
+ if (signal_pending(current)) {
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ break;
+ }
+
+ abort_timedouts(host);
+ }
+
+ HPSB_INFO(__FUNCTION__ " exiting");
+ return 0;
+}
+#endif
+
+
+#ifndef MODULE
+
+void __init ieee1394_init(void)
+{
+ register_builtin_lowlevels();
+ init_hpsb_highlevel();
+ init_csr();
+}
+
+#else
+
+int init_module(void)
+{
+ init_hpsb_highlevel();
+ init_csr();
+ return 0;
+}
+
+#endif
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
new file mode 100644
index 000000000..171a2fa9f
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -0,0 +1,152 @@
+
+#ifndef _IEEE1394_CORE_H
+#define _IEEE1394_CORE_H
+
+#include <linux/tqueue.h>
+#include <asm/semaphore.h>
+#include "hosts.h"
+
+
+struct hpsb_packet {
+ /* This struct is basically read-only for hosts with the exception of
+ * the data buffer contents and xnext - see below. */
+ struct list_head list;
+
+ /* This can be used for host driver internal linking. */
+ struct hpsb_packet *xnext;
+
+ nodeid_t node_id;
+
+ /* Async and Iso types should be clear, raw means send-as-is, do not
+ * CRC! Byte swapping shall still be done in this case. */
+ enum { async, iso, raw } __attribute__((packed)) type;
+
+ /* Okay, this is core internal and a no care for hosts.
+ * queued = queued for sending
+ * pending = sent, waiting for response
+ * complete = processing completed, successful or not
+ * incoming = incoming packet
+ */
+ enum {
+ unused, queued, pending, complete, incoming
+ } __attribute__((packed)) state;
+
+ /* These are core internal. */
+ char tlabel;
+ char ack_code;
+ char tcode;
+
+ unsigned expect_response:1;
+ unsigned no_waiter:1;
+
+ /* Data big endianness flag - may vary from request to request. The
+ * header is always in machine byte order. */
+ unsigned data_be:1;
+
+ /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
+ unsigned speed_code:2;
+
+ /* --- 16 bytes (one cacheline) --- */
+
+ /* *header and *data are guaranteed to be 32-bit DMAable and may be
+ * overwritten to allow in-place byte swapping. Neither of these is
+ * CRCed (the sizes also don't include CRC), but contain space for at
+ * least one additional quadlet to allow in-place CRCing. The memory is
+ * also guaranteed to have physical mapping (virt_to_bus() is meaningful
+ * on these pointers).
+ * NOTE: The 32-bit DMA guarantee is currently not enforced.
+ * That's a Linux 2.3 issue.
+ */
+ quadlet_t *header;
+ quadlet_t *data;
+ size_t header_size;
+ size_t data_size;
+
+ /* --- 32 bytes --- */
+
+ struct hpsb_host *host;
+ unsigned int generation;
+
+ /* Very core internal, don't care. */
+ struct semaphore state_change;
+
+ task_queue complete_tq;
+
+ /* Store jiffies for implementing bus timeouts. */
+ unsigned long sendtime;
+};
+
+
+void reset_host_bus(struct hpsb_host *host);
+void abort_timedouts(struct hpsb_host *host);
+void abort_requests(struct hpsb_host *host);
+
+struct hpsb_packet *alloc_hpsb_packet(size_t data_size);
+void free_hpsb_packet(struct hpsb_packet *packet);
+
+
+/*
+ * Generation counter for the complete 1394 subsystem. Generation gets
+ * incremented on every change in the subsystem (e.g. bus reset).
+ *
+ * Use the functions, not the variable.
+ */
+#include <asm/atomic.h>
+extern atomic_t hpsb_generation;
+
+inline static unsigned int get_hpsb_generation(void)
+{
+ return atomic_read(&hpsb_generation);
+}
+
+inline static void inc_hpsb_generation(void)
+{
+ atomic_inc(&hpsb_generation);
+}
+
+
+/*
+ * Queue packet for transmitting, return 0 for failure.
+ */
+int hpsb_send_packet(struct hpsb_packet *packet);
+
+
+/*
+ * The following functions are exported for host driver module usage. All of
+ * them are safe to use in interrupt contexts, although some are quite
+ * complicated so you may want to run them in bottom halves instead of calling
+ * them directly.
+ */
+
+/* Notify a bus reset to the core. */
+void hpsb_bus_reset(struct hpsb_host *host);
+
+/*
+ * Hand over received selfid packet to the core. Complement check (second
+ * quadlet is complement of first) is expected to be done and succesful.
+ */
+void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
+
+/*
+ * Notify completion of SelfID stage to the core and report new physical ID
+ * and whether host is root now.
+ */
+void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
+
+/*
+ * Notify core of sending a packet. Ackcode is the ack code returned for async
+ * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
+ * for other cases (internal errors that don't justify a panic). Safe to call
+ * from within a transmit packet routine.
+ */
+void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode);
+
+/*
+ * Hand over received packet to the core. The contents of data are expected to
+ * be the full packet but with the CRCs left out (data block follows header
+ * immediately) and in machine byte order. *data can be safely overwritten
+ * after this call.
+ */
+void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size);
+
+#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c
new file mode 100644
index 000000000..e4d92fa0f
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_syms.c
@@ -0,0 +1,59 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Exported symbols for module usage.
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "ieee1394_transactions.h"
+/* #include "events.h" */
+#include "highlevel.h"
+
+EXPORT_SYMBOL(hpsb_register_lowlevel);
+EXPORT_SYMBOL(hpsb_unregister_lowlevel);
+EXPORT_SYMBOL(hpsb_get_host);
+EXPORT_SYMBOL(hpsb_get_host_list);
+EXPORT_SYMBOL(hpsb_inc_host_usage);
+EXPORT_SYMBOL(hpsb_dec_host_usage);
+
+EXPORT_SYMBOL(alloc_hpsb_packet);
+EXPORT_SYMBOL(free_hpsb_packet);
+EXPORT_SYMBOL(hpsb_send_packet);
+EXPORT_SYMBOL(hpsb_bus_reset);
+EXPORT_SYMBOL(hpsb_selfid_received);
+EXPORT_SYMBOL(hpsb_selfid_complete);
+EXPORT_SYMBOL(hpsb_packet_sent);
+EXPORT_SYMBOL(hpsb_packet_received);
+EXPORT_SYMBOL(hpsb_generation);
+
+EXPORT_SYMBOL(get_tlabel);
+EXPORT_SYMBOL(free_tlabel);
+EXPORT_SYMBOL(hpsb_make_readqpacket);
+EXPORT_SYMBOL(hpsb_make_readbpacket);
+EXPORT_SYMBOL(hpsb_make_writeqpacket);
+EXPORT_SYMBOL(hpsb_make_writebpacket);
+EXPORT_SYMBOL(hpsb_read);
+EXPORT_SYMBOL(hpsb_write);
+EXPORT_SYMBOL(hpsb_lock);
+
+EXPORT_SYMBOL(hpsb_register_highlevel);
+EXPORT_SYMBOL(hpsb_unregister_highlevel);
+EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_listen_channel);
+EXPORT_SYMBOL(hpsb_unlisten_channel);
+EXPORT_SYMBOL(highlevel_read);
+EXPORT_SYMBOL(highlevel_write);
+EXPORT_SYMBOL(highlevel_lock);
+EXPORT_SYMBOL(highlevel_lock64);
+
+/*
+EXPORT_SYMBOL(hpsb_dispatch_event);
+EXPORT_SYMBOL(hpsb_reg_event_handler);
+*/
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
new file mode 100644
index 000000000..c50bce62a
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -0,0 +1,514 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Transaction support.
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/sched.h>
+#include <asm/errno.h>
+#include <asm/bitops.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"
+
+
+#define PREP_ASYNC_HEAD_ADDRESS(tc) \
+ packet->tcode = tc; \
+ packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
+ | (1 << 8) | (tc << 4); \
+ packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
+ packet->header[2] = addr & 0xffffffff
+
+#define PREP_ASYNC_HEAD_RCODE(tc) \
+ packet->tcode = tc; \
+ packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
+ | (1 << 8) | (tc << 4); \
+ packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
+ packet->header[2] = 0
+
+
+void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
+{
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
+ packet->header_size = 12;
+ packet->data_size = 0;
+ packet->expect_response = 1;
+}
+
+void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
+ quadlet_t data)
+{
+ PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
+ packet->header[3] = data;
+ packet->header_size = 16;
+ packet->data_size = 0;
+}
+
+void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length)
+{
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
+ packet->header[3] = length << 16;
+ packet->header_size = 16;
+ packet->data_size = 0;
+ packet->expect_response = 1;
+}
+
+void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
+ int length)
+{
+ if (rcode != RCODE_COMPLETE) {
+ length = 0;
+ }
+
+ PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
+ packet->header[3] = length << 16;
+ packet->header_size = 16;
+ packet->data_size = length;
+}
+
+void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
+{
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
+ packet->header[3] = data;
+ packet->header_size = 16;
+ packet->data_size = 0;
+ packet->expect_response = 1;
+}
+
+void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length)
+{
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
+ packet->header[3] = length << 16;
+ packet->header_size = 16;
+ packet->data_size = length;
+ packet->expect_response = 1;
+}
+
+void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
+{
+ PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
+ packet->header[2] = 0;
+ packet->header_size = 12;
+ packet->data_size = 0;
+}
+
+void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
+ int length)
+{
+ PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
+ packet->header[3] = (length << 16) | extcode;
+ packet->header_size = 16;
+ packet->data_size = length;
+ packet->expect_response = 1;
+}
+
+void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
+ int length)
+{
+ if (rcode != RCODE_COMPLETE) {
+ length = 0;
+ }
+
+ PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
+ packet->header[3] = (length << 16) | extcode;
+ packet->header_size = 16;
+ packet->data_size = length;
+}
+
+void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
+ int tag, int sync)
+{
+ packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
+ | (TCODE_ISO_DATA << 4) | sync;
+
+ packet->header_size = 4;
+ packet->data_size = length;
+ packet->tcode = TCODE_ISO_DATA;
+}
+
+
+int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
+{
+ unsigned long flags;
+ int tlabel;
+
+ while (1) {
+ spin_lock_irqsave(&host->tlabel_lock, flags);
+
+ if (host->tlabel_count) {
+ host->tlabel_count--;
+
+ if (host->tlabel_pool[0] != ~0) {
+ tlabel = ffz(host->tlabel_pool[0]);
+ host->tlabel_pool[0] |= 1 << tlabel;
+ } else {
+ tlabel = ffz(host->tlabel_pool[1]);
+ host->tlabel_pool[1] |= 1 << tlabel;
+ tlabel += 32;
+ }
+
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+ return tlabel;
+ }
+
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+
+ if (wait) {
+ sleep_on(&host->tlabel_wait);
+ } else {
+ return -1;
+ }
+ }
+}
+
+void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->tlabel_lock, flags);
+
+ if (tlabel < 32) {
+ host->tlabel_pool[0] &= ~(1 << tlabel);
+ } else {
+ host->tlabel_pool[1] &= ~(1 << (tlabel-32));
+ }
+
+ host->tlabel_count++;
+
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+
+ wake_up(&host->tlabel_wait);
+}
+
+
+
+int hpsb_packet_success(struct hpsb_packet *packet)
+{
+ switch (packet->ack_code) {
+ case ACK_PENDING:
+ switch ((packet->header[1] >> 12) & 0xf) {
+ case RCODE_COMPLETE:
+ return 0;
+ case RCODE_CONFLICT_ERROR:
+ return -EAGAIN;
+ case RCODE_DATA_ERROR:
+ return -EREMOTEIO;
+ case RCODE_TYPE_ERROR:
+ return -EACCES;
+ case RCODE_ADDRESS_ERROR:
+ return -EINVAL;
+ default:
+ HPSB_ERR("received reserved rcode %d from node %d",
+ (packet->header[1] >> 12) & 0xf,
+ packet->node_id);
+ return -EAGAIN;
+ }
+ HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__);
+
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+ case ACK_BUSY_B:
+ return -EBUSY;
+
+ case ACK_TYPE_ERROR:
+ return -EACCES;
+
+ case ACK_COMPLETE:
+ if (packet->tcode == TCODE_WRITEQ
+ || packet->tcode == TCODE_WRITEB) {
+ return 0;
+ } else {
+ HPSB_ERR("impossible ack_complete from node %d "
+ "(tcode %d)", packet->node_id, packet->tcode);
+ return -EAGAIN;
+ }
+
+
+ case ACK_DATA_ERROR:
+ if (packet->tcode == TCODE_WRITEB
+ || packet->tcode == TCODE_LOCK_REQUEST) {
+ return -EAGAIN;
+ } else {
+ HPSB_ERR("impossible ack_data_error from node %d "
+ "(tcode %d)", packet->node_id, packet->tcode);
+ return -EAGAIN;
+ }
+
+ case ACKX_NONE:
+ case ACKX_SEND_ERROR:
+ case ACKX_ABORTED:
+ case ACKX_TIMEOUT:
+ /* error while sending */
+ return -EAGAIN;
+
+ default:
+ HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
+ packet->ack_code, packet->node_id, packet->tcode);
+ return -EAGAIN;
+ }
+
+ HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__);
+}
+
+
+int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length)
+{
+ if (host->node_id != node) return -1;
+ return highlevel_read(host, buffer, addr, length);
+}
+
+struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(0);
+ if (!p) return NULL;
+
+ p->host = host;
+ p->tlabel = get_tlabel(host, node, 1);
+ p->node_id = node;
+ fill_async_readquad(p, addr);
+
+ return p;
+}
+
+struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr, size_t length)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(length);
+ if (!p) return NULL;
+
+ p->host = host;
+ p->tlabel = get_tlabel(host, node, 1);
+ p->node_id = node;
+ fill_async_readblock(p, addr, length);
+
+ return p;
+}
+
+struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host,
+ nodeid_t node, u64 addr,
+ quadlet_t data)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(0);
+ if (!p) return NULL;
+
+ p->host = host;
+ p->tlabel = get_tlabel(host, node, 1);
+ p->node_id = node;
+ fill_async_writequad(p, addr, data);
+
+ return p;
+}
+
+struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
+ nodeid_t node, u64 addr,
+ size_t length)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(length);
+ if (!p) return NULL;
+
+ p->host = host;
+ p->tlabel = get_tlabel(host, node, 1);
+ p->node_id = node;
+ fill_async_writeblock(p, addr, length);
+
+ return p;
+}
+
+
+/*
+ * FIXME - these functions should probably read from / write to user space to
+ * avoid in kernel buffers for user space callers
+ */
+
+int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length)
+{
+ struct hpsb_packet *packet;
+ int retval = 0;
+
+ if (length == 0) {
+ return -EINVAL;
+ }
+
+ if (host->node_id == node) {
+ switch(highlevel_read(host, buffer, addr, length)) {
+ case RCODE_COMPLETE:
+ return 0;
+ case RCODE_TYPE_ERROR:
+ return -EACCES;
+ case RCODE_ADDRESS_ERROR:
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (length & 0x3) {
+ /* FIXME: Lengths not multiple of 4 are not implemented. Mainly
+ * there is the problem with little endian machines because we
+ * always swap to little endian on receive. If we read 5 bytes
+ * 12345 we receive them as 12345000 and swap them to 43210005.
+ * How should we copy that to the caller? Require *buffer to be
+ * a full quadlet multiple in length? */
+ return -EACCES;
+ }
+
+ if (length == 4) {
+ packet = hpsb_make_readqpacket(host, node, addr);
+ } else {
+ packet = hpsb_make_readbpacket(host, node, addr, length);
+ }
+
+ if (!packet) {
+ return -ENOMEM;
+ }
+
+ hpsb_send_packet(packet);
+ down(&packet->state_change);
+ down(&packet->state_change);
+ retval = hpsb_packet_success(packet);
+
+ if (retval == 0) {
+ if (length == 4) {
+ *buffer = packet->header[3];
+ } else {
+ memcpy(buffer, packet->data, length);
+ }
+ }
+
+ free_tlabel(host, node, packet->tlabel);
+ free_hpsb_packet(packet);
+
+ return retval;
+}
+
+
+int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length)
+{
+ struct hpsb_packet *packet;
+ int retval = 0;
+
+ if (length == 0) {
+ return -EINVAL;
+ }
+
+ if (host->node_id == node) {
+ switch(highlevel_write(host, buffer, addr, length)) {
+ case RCODE_COMPLETE:
+ return 0;
+ case RCODE_TYPE_ERROR:
+ return -EACCES;
+ case RCODE_ADDRESS_ERROR:
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (length & 0x3) {
+ /* FIXME: Lengths not multiple of 4 are not implemented. See function
+ * hpsb_read for explanation, same reason, different direction. */
+ return -EACCES;
+ }
+
+ if (length == 4) {
+ packet = hpsb_make_writeqpacket(host, node, addr, *buffer);
+ } else {
+ packet = hpsb_make_writebpacket(host, node, addr, length);
+ }
+
+ if (!packet) {
+ return -ENOMEM;
+ }
+
+ if (length != 4) {
+ memcpy(packet->data, buffer, length);
+ }
+
+ hpsb_send_packet(packet);
+ down(&packet->state_change);
+ down(&packet->state_change);
+ retval = hpsb_packet_success(packet);
+
+ free_tlabel(host, node, packet->tlabel);
+ free_hpsb_packet(packet);
+
+ return retval;
+}
+
+
+/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
+ quadlet_t *data, quadlet_t arg)
+{
+ struct hpsb_packet *packet;
+ int retval = 0, length;
+
+ if (host->node_id == node) {
+ switch(highlevel_lock(host, data, addr, *data, arg, extcode)) {
+ case RCODE_COMPLETE:
+ return 0;
+ case RCODE_TYPE_ERROR:
+ return -EACCES;
+ case RCODE_ADDRESS_ERROR:
+ default:
+ return -EINVAL;
+ }
+ }
+
+ packet = alloc_hpsb_packet(8);
+ if (!packet) {
+ return -ENOMEM;
+ }
+
+ packet->host = host;
+ packet->tlabel = get_tlabel(host, node, 1);
+ packet->node_id = node;
+
+ switch (extcode) {
+ case EXTCODE_MASK_SWAP:
+ case EXTCODE_COMPARE_SWAP:
+ case EXTCODE_BOUNDED_ADD:
+ case EXTCODE_WRAP_ADD:
+ length = 8;
+ packet->data[0] = arg;
+ packet->data[1] = *data;
+ break;
+ case EXTCODE_FETCH_ADD:
+ case EXTCODE_LITTLE_ADD:
+ length = 4;
+ packet->data[0] = *data;
+ break;
+ default:
+ return -EINVAL;
+ }
+ fill_async_lock(packet, addr, extcode, length);
+
+ hpsb_send_packet(packet);
+ down(&packet->state_change);
+ down(&packet->state_change);
+ retval = hpsb_packet_success(packet);
+
+ if (retval == 0) {
+ *data = packet->data[0];
+ }
+
+ free_tlabel(host, node, packet->tlabel);
+ free_hpsb_packet(packet);
+
+ return retval;
+}
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
new file mode 100644
index 000000000..136d4f7d9
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -0,0 +1,69 @@
+#ifndef _IEEE1394_TRANSACTIONS_H
+#define _IEEE1394_TRANSACTIONS_H
+
+#include "ieee1394_core.h"
+
+
+/*
+ * Utility functions to fill out packet headers.
+ */
+void fill_async_readquad(struct hpsb_packet *packet, u64 addr);
+void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
+ quadlet_t data);
+void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length);
+void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
+ int length);
+void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data);
+void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length);
+void fill_async_write_resp(struct hpsb_packet *packet, int rcode);
+void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
+ int length);
+void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
+ int length);
+void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
+ int tag, int sync);
+
+/*
+ * Get and free transaction labels.
+ */
+int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait);
+void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel);
+
+struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr);
+struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr, size_t length);
+struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host,
+ nodeid_t node, u64 addr,
+ quadlet_t data);
+struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
+ nodeid_t node, u64 addr,
+ size_t length);
+
+/*
+ * hpsb_packet_success - Make sense of the ack and reply codes and
+ * return more convenient error codes:
+ * 0 success
+ * -EBUSY node is busy, try again
+ * -EAGAIN error which can probably resolved by retry
+ * -EREMOTEIO node suffers from an internal error
+ * -EACCES this transaction is not allowed on requested address
+ * -EINVAL invalid address at node
+ */
+int hpsb_packet_success(struct hpsb_packet *packet);
+
+
+/*
+ * The generic read, write and lock functions. All recognize the local node ID
+ * and act accordingly. Read and write automatically use quadlet commands if
+ * length == 4 and and block commands otherwise (however, they do not yet
+ * support lengths that are not a multiple of 4).
+ */
+int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length);
+int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length);
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
+ quadlet_t *data, quadlet_t arg);
+
+#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
new file mode 100644
index 000000000..d619182dd
--- /dev/null
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -0,0 +1,86 @@
+
+#ifndef _IEEE1394_TYPES_H
+#define _IEEE1394_TYPES_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/list.h>
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
+#define DECLARE_WAITQUEUE(name, task) struct wait_queue name = { task, NULL }
+
+typedef struct wait_queue *wait_queue_head_t;
+
+inline static void init_waitqueue_head(wait_queue_head_t *wh)
+{
+ *wh = NULL;
+}
+
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
+#include <asm/spinlock.h>
+#else
+#include <linux/spinlock.h>
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+typedef __u32 quadlet_t;
+typedef __u64 octlet_t;
+typedef __u16 nodeid_t;
+
+#define BUS_MASK 0xffc0
+#define NODE_MASK 0x003f
+#define LOCAL_BUS 0xffc0
+#define ALL_NODES 0x003f
+
+#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args)
+
+#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
+#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
+#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
+#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
+
+#define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args)
+
+#define HPSB_TRACE() HPSB_PRINT(KERN_INFO, "TRACE - %s, %s(), line %d", __FILE__, __FUNCTION__, __LINE__)
+
+
+#ifdef __BIG_ENDIAN
+
+static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
+{
+ void *tmp = dest;
+
+ count /= 4;
+
+ while (count--) {
+ *dest++ = swab32p(src++);
+ }
+
+ return tmp;
+}
+
+#else
+
+static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
+{
+ return memcpy(dest, src, count);
+}
+
+#endif /* __BIG_ENDIAN */
+
+#endif /* _IEEE1394_TYPES_H */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
new file mode 100644
index 000000000..f39a8de86
--- /dev/null
+++ b/drivers/ieee1394/ohci1394.c
@@ -0,0 +1,1403 @@
+/*
+ * ti_ohci1394.c - Texas Instruments Ohci1394 driver
+ * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ * Gord Peters <GordPeters@smarttech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "ohci1394.h"
+
+#undef CONFIG_PROC_FS
+
+/* print general (card independent) information */
+#define PRINT_G(level, fmt, args...) \
+printk(level "ohci1394: " fmt "\n" , ## args)
+
+/* print card specific information */
+#define PRINT(level, card, fmt, args...) \
+printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
+
+int supported_chips[][2] = {
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
+ { -1, -1 }
+};
+
+static struct ti_ohci cards[MAX_OHCI1394_CARDS];
+static int num_of_cards = 0;
+
+static int add_card(struct pci_dev *dev);
+static void remove_card(struct ti_ohci *ohci);
+static int init_driver(void);
+
+/***********************************
+ * IEEE-1394 functionality section *
+ ***********************************/
+
+
+#if 0 /* not needed at this time */
+static int get_phy_reg(struct ti_ohci *ohci, int addr)
+{
+ int timeout=10000;
+ static quadlet_t r;
+
+ if ((addr < 1) || (addr > 15)) {
+ PRINT(KERN_ERR, ohci->id, __FUNCTION__
+ ": PHY register address %d out of range", addr);
+ return -EFAULT;
+ }
+
+ spin_lock(&ohci->phy_reg_lock);
+
+ /* initiate read request */
+ reg_write(ohci, OHCI1394_PhyControl,
+ ((addr<<8)&0x00000f00) | 0x00008000);
+
+ /* wait */
+ while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
+ timeout--;
+
+
+ if (!timeout) {
+ PRINT(KERN_ERR, ohci->id, "get_phy_reg timeout !!!\n");
+ spin_unlock(&ohci->phy_reg_lock);
+ return -EFAULT;
+ }
+ r = reg_read(ohci, OHCI1394_PhyControl);
+
+ spin_unlock(&ohci->phy_reg_lock);
+
+ return (r&0x00ff0000)>>16;
+}
+
+static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) {
+ int timeout=10000;
+ u32 r;
+
+ if ((addr < 1) || (addr > 15)) {
+ PRINT(KERN_ERR, ohci->id, __FUNCTION__
+ ": PHY register address %d out of range", addr);
+ return -EFAULT;
+ }
+
+ r = ((addr<<8)&0x00000f00) | 0x00004000 | ((u32)data & 0x000000ff);
+
+ spin_lock(&ohci->phy_reg_lock);
+
+ reg_write(ohci, OHCI1394_PhyControl, r);
+
+ /* wait */
+ while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
+ timeout--;
+
+ spin_unlock(&ohci->phy_reg_lock);
+
+ if (!timeout) {
+ PRINT(KERN_ERR, ohci->id, "set_phy_reg timeout !!!\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+#endif /* unneeded functions */
+
+inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
+ int phyid, int isroot)
+{
+ quadlet_t *q = ohci->self_id_buffer;
+ quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
+ size_t size;
+ quadlet_t lsid;
+
+ /* Self-id handling seems much easier than for the aic5800 chip.
+ All the self-id packets, including this device own self-id,
+ should be correctly arranged in the self_id_buffer at this
+ stage */
+
+ /* Check status of self-id reception */
+ if ((self_id_count&0x80000000) ||
+ ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) {
+ PRINT(KERN_ERR, ohci->id,
+ "Error in reception of self-id packets");
+ return -1;
+ }
+
+ size = ((self_id_count&0x0000EFFC)>>2) - 1;
+ q++;
+
+ while (size > 0) {
+ if (q[0] == ~q[1]) {
+ printk("-%d- selfid packet 0x%x rcvd\n",
+ ohci->id, q[0]);
+ hpsb_selfid_received(host, q[0]);
+ if (((q[0]&0x3f000000)>>24)==phyid) {
+ lsid=q[0];
+ printk("This node self-id is 0x%08x\n",lsid);
+ }
+ } else {
+ printk("-%d- inconsistent selfid 0x%x/0x%x\n", ohci->id,
+ q[0], q[1]);
+ }
+ q += 2;
+ size -= 2;
+ }
+
+ printk(" calling self-id complete\n");
+
+ hpsb_selfid_complete(host, phyid, isroot);
+ return 0;
+}
+
+static int ohci_detect(struct hpsb_host_template *tmpl)
+{
+ struct hpsb_host *host;
+ int i;
+
+ init_driver();
+
+ for (i = 0; i < num_of_cards; i++) {
+ host = hpsb_get_host(tmpl, 0);
+ if (host == NULL) {
+ /* simply don't init more after out of mem */
+ return i;
+ }
+ host->hostdata = &cards[i];
+ cards[i].host = host;
+ }
+
+ return num_of_cards;
+}
+
+static int ohci_soft_reset(struct ti_ohci *ohci) {
+ int timeout=10000;
+
+ reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
+
+ while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout)
+ timeout--;
+ if (!timeout) {
+ PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!");
+ return -EFAULT;
+ }
+ else PRINT(KERN_INFO, ohci->id, "soft reset finished");
+ return 0;
+}
+
+static int ohci_initialize(struct hpsb_host *host)
+{
+ struct ti_ohci *ohci=host->hostdata;
+ int retval, i;
+
+ spin_lock_init(&ohci->phy_reg_lock);
+
+ /* Soft reset */
+ if ((retval=ohci_soft_reset(ohci))<0) return retval;
+
+ /* Set the bus number */
+ reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
+
+ /* Set Link Power Status (LPS) */
+ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+
+ /* Enable posted writes */
+ reg_write(ohci, OHCI1394_HCControlSet, 0x00040000);
+
+ /* Clear link control register */
+ reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
+
+ /* Enable cycle timer and cycle master */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);
+
+ /* Clear interrupt registers */
+ reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+
+ /* Set up self-id dma buffer */
+ reg_write(ohci, OHCI1394_SelfIDBuffer,
+ virt_to_bus(ohci->self_id_buffer));
+
+ /* enable self-id dma */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);
+
+ /* Set the configuration ROM mapping register */
+ reg_write(ohci, OHCI1394_ConfigROMmap,
+ virt_to_bus(ohci->csr_config_rom));
+
+#if 1 /* Why is this step necessary ? */
+ /* Write the config ROM header */
+ reg_write(ohci, OHCI1394_ConfigROMhdr,0x04040000);
+
+ /* Set bus options */
+ reg_write(ohci, OHCI1394_BusOptions, 0xf064A002);
+#endif
+
+#if 1
+ /* Accept phy packets into AR request context */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
+#endif
+
+ /* Enable link */
+ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
+
+ /* Initialize IR dma */
+
+ /* make sure the context isn't running, dead, or active */
+ if (!(reg_read(ohci, OHCI1394_IrRcvContextControlSet) & 0x00008F00)) {
+
+ /* initialize IR program */
+ for (i= 0; i < IR_NUM_DESC; i++) {
+
+ /* end of descriptor list? */
+ if ((i + 1) < IR_NUM_DESC) {
+ ohci->IR_recv_prg[i]->control=
+ (0x283C << 16) | IR_RECV_BUF_SIZE;
+ ohci->IR_recv_prg[i]->branchAddress=
+ (virt_to_bus(ohci->IR_recv_prg[i + 1])
+ & 0xfffffff0) | 0x1;
+ } else {
+ ohci->IR_recv_prg[i]->control=
+ (0x283C << 16) | IR_RECV_BUF_SIZE;
+ ohci->IR_recv_prg[i]->branchAddress=
+ (virt_to_bus(ohci->IR_recv_prg[0])
+ & 0xfffffff0) | 0x1;
+ }
+
+ ohci->IR_recv_prg[i]->address=
+ virt_to_bus(ohci->IR_recv_buf[i]);
+ ohci->IR_recv_prg[i]->status= IR_RECV_BUF_SIZE;
+ }
+
+ /* Tell the controller where the first IR program is */
+ reg_write(ohci, OHCI1394_IrRcvCommandPtr,
+ virt_to_bus(ohci->IR_recv_prg[0]) | 0x1 );
+
+ /* Set bufferFill, isochHeader, multichannel for IR context */
+ reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+
+ /* Set the context match register to match on all tags */
+ reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
+
+ /* Clear the multi channel mask high and low registers */
+ reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+
+ /* Set up isoRecvIntMask to generate interrupts for context 0
+ (thanks to Michael Greger for seeing that I forgot this) */
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
+
+ /* Run IR context */
+ reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0x00008000);
+ }
+
+ /* Initialize AR dma */
+ ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE;
+ ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf);
+ ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
+ PRINT(KERN_INFO, ohci->id, "AR control: %x",
+ ohci->AR_resp_prg->control);
+ PRINT(KERN_INFO, ohci->id, "AR status: %x %d",
+ ohci->AR_resp_prg->status & 0xffff,
+ ohci->AR_resp_prg->status & 0xffff);
+
+ /* Tell the controller where the AR program is */
+ reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
+ virt_to_bus(ohci->AR_resp_prg)|0x00000001);
+
+#if 1
+ /* Accept phy packets into AR request context */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
+#endif
+
+ /* Run AR context */
+ reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+
+#ifndef __BIG_ENDIAN
+ reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
+#else
+ reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+#endif
+
+ /* Enable interrupts */
+ reg_write(ohci, OHCI1394_IntMaskSet,
+ OHCI1394_masterIntEnable |
+ OHCI1394_phyRegRcvd |
+ OHCI1394_busReset |
+ OHCI1394_selfIDComplete |
+ OHCI1394_RSPkt |
+ OHCI1394_RQPkt |
+ OHCI1394_ARRS |
+ OHCI1394_ARRQ |
+ OHCI1394_respTxComplete |
+ OHCI1394_reqTxComplete |
+ OHCI1394_isochRx
+ );
+
+ return 1;
+}
+
+static void ohci_remove(struct hpsb_host *host)
+{
+ struct ti_ohci *ohci;
+
+ if (host != NULL) {
+ ohci = host->hostdata;
+ remove_card(ohci);
+ }
+}
+
+
+/* This must be called with the async_queue_lock held. */
+static void send_next_async(struct ti_ohci *ohci)
+{
+ int i=0;
+ struct hpsb_packet *packet = ohci->async_queue;
+ struct dma_cmd prg;
+ quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
+
+ //HPSB_TRACE();
+
+ /* stop the channel program if it's still running */
+ reg_write(ohci, OHCI1394_AsReqTrContextControlClear, 0x8000);
+
+ /* Wait until it effectively stops */
+ while (reg_read(ohci, OHCI1394_AsReqTrContextControlSet)
+ & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id,
+ "runaway loop in DmaAT. bailing out...");
+ break;
+ }
+ };
+
+ if (packet->type == async)
+ {
+
+ /* re-format packet header according to ohci specification */
+ packet->header[1] = (packet->header[1] & 0xFFFF) |
+ (packet->header[0] & 0xFFFF0000);
+ packet->header[0] = DMA_SPEED_200 |
+ (packet->header[0] & 0xFFFF);
+
+ if (packet->data_size) { /* block transmit */
+ prg.control = OUTPUT_MORE_IMMEDIATE | 0x10;
+ prg.address = 0;
+ prg.branchAddress = 0;
+ prg.status = 0;
+ memcpy(ohci->AT_req_prg, &prg, 16);
+ memcpy(ohci->AT_req_prg + 1, packet->header, 16);
+ prg.control = OUTPUT_LAST | packet->data_size;
+ prg.address = virt_to_bus(packet->data);
+ memcpy(ohci->AT_req_prg + 2, &prg, 16);
+
+ reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
+ virt_to_bus(ohci->AT_req_prg)|0x3);
+ }
+ else { /* quadlet transmit */
+ prg.control = OUTPUT_LAST_IMMEDIATE |
+ packet->header_size;
+ prg.address = 0;
+ prg.branchAddress = 0;
+ prg.status = 0;
+ memcpy(ohci->AT_req_prg, &prg, 16);
+ memcpy(ohci->AT_req_prg + 1, packet->header, 16);
+
+ PRINT(KERN_INFO, ohci->id,
+ "dma_cmd: %08x %08x %08x %08x",
+ *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
+ PRINT(KERN_INFO, ohci->id,
+ "header: %08x %08x %08x %08x",
+ *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
+
+ reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
+ virt_to_bus(ohci->AT_req_prg)|0x2);
+ }
+
+ }
+ else if (packet->type == raw)
+ {
+ prg.control = OUTPUT_LAST | packet->data_size;
+ prg.address = virt_to_bus(packet->data);
+ prg.branchAddress = 0;
+ prg.status = 0;
+ memcpy(ohci->AT_req_prg, &prg, 16);
+
+ PRINT(KERN_INFO, ohci->id,
+ "dma_cmd: %08x %08x %08x %08x",
+ *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
+
+ reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
+ virt_to_bus(ohci->AT_req_prg)|0x2);
+ }
+
+ /* run program */
+ reg_write(ohci, OHCI1394_AsReqTrContextControlSet, 0x00008000);
+}
+
+static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
+{
+ struct ti_ohci *ohci = host->hostdata;
+ struct hpsb_packet *p;
+ unsigned long flags;
+
+ if (packet->data_size >= 4096) {
+ PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
+ packet->data_size);
+ return 0;
+ }
+
+ //HPSB_TRACE();
+ packet->xnext = NULL;
+
+ spin_lock_irqsave(&ohci->async_queue_lock, flags);
+
+ if (ohci->async_queue == NULL) {
+ ohci->async_queue = packet;
+ send_next_async(ohci);
+ } else {
+ p = ohci->async_queue;
+ while (p->xnext != NULL) {
+ p = p->xnext;
+ }
+
+ p->xnext = packet;
+ }
+
+ spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
+
+ return 1;
+}
+
+static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
+{
+ struct ti_ohci *ohci = host->hostdata;
+ int retval = 0;
+ unsigned long flags;
+ struct hpsb_packet *packet, *lastpacket;
+ u32 r;
+
+ switch (cmd) {
+ case RESET_BUS:
+ PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
+ (host->attempt_root ? " and attempting to become root"
+ : ""));
+ r = (host->attempt_root) ? 0x000041ff : 0x0000417f;
+ reg_write(ohci, OHCI1394_PhyControl, r);
+ break;
+
+ case GET_CYCLE_COUNTER:
+ retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ break;
+
+ case SET_CYCLE_COUNTER:
+ reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
+ break;
+
+ case SET_BUS_ID:
+ PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err");
+ break;
+
+ case ACT_CYCLE_MASTER:
+#if 0
+ if (arg) {
+ /* enable cycleTimer, cycleMaster, cycleSource */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000);
+ } else {
+ /* disable cycleTimer, cycleMaster, cycleSource */
+ reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000);
+ };
+#endif
+ break;
+
+ case CANCEL_REQUESTS:
+ spin_lock_irqsave(&ohci->async_queue_lock, flags);
+ /* stop any chip activity */
+ reg_write(ohci, OHCI1394_HCControlClear, 0x00020000);
+ packet = ohci->async_queue;
+ ohci->async_queue = NULL;
+ spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
+
+ while (packet != NULL) {
+ lastpacket = packet;
+ packet = packet->xnext;
+ hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
+ }
+
+ break;
+
+ case MODIFY_USAGE:
+ if (arg) {
+ MOD_INC_USE_COUNT;
+ } else {
+ MOD_DEC_USE_COUNT;
+ }
+ break;
+
+ case ISO_LISTEN_CHANNEL:
+
+ spin_lock_irqsave(&ohci->IR_channel_lock, flags);
+
+ if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) {
+ PRINT(KERN_INFO, ohci->id,
+ "listening enabled on channel %d", arg);
+
+ if (arg > 31) {
+ u32 setMask= 0x00000001;
+ arg-= 32;
+ while(arg--) setMask= setMask << 1;
+ reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet,
+ setMask);
+ } else {
+ u32 setMask= 0x00000001;
+ while(arg--) setMask= setMask << 1;
+ reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet,
+ setMask);
+ }
+
+ }
+
+ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
+ break;
+
+ case ISO_UNLISTEN_CHANNEL:
+
+ spin_lock_irqsave(&ohci->IR_channel_lock, flags);
+
+ if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) {
+ PRINT(KERN_INFO, ohci->id,
+ "listening disabled on iso channel %d", arg);
+
+ if (arg > 31) {
+ u32 clearMask= 0x00000001;
+ arg-= 32;
+ while(arg--) clearMask= clearMask << 1;
+ reg_write(ohci,
+ OHCI1394_IRMultiChanMaskHiClear,
+ clearMask);
+ } else {
+ u32 clearMask= 0x00000001;
+ while(arg--) clearMask= clearMask << 1;
+ reg_write(ohci,
+ OHCI1394_IRMultiChanMaskLoClear,
+ clearMask);
+ }
+
+ }
+
+ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
+ break;
+
+ default:
+ PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n",
+ cmd);
+ break;
+ }
+ return retval;
+}
+
+/***************************************
+ * IEEE-1394 functionality section END *
+ ***************************************/
+
+
+/********************************************************
+ * Global stuff (interrupt handler, init/shutdown code) *
+ ********************************************************/
+
+static void ohci_irq_handler(int irq, void *dev_id,
+ struct pt_regs *regs_are_unused)
+{
+ //int i;
+ static quadlet_t event,node_id;
+ struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
+ struct hpsb_host *host = ohci->host;
+ int phyid = -1, isroot = 0;
+
+ event=reg_read(ohci, OHCI1394_IntEventSet);
+
+ /* Clear the interrupt register */
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+
+ /* PRINT(KERN_INFO, ohci->id, "int event %08X mask %08X",
+ event,reg_read(ohci, OHCI1394_IntMaskSet)); */
+
+ if (event & OHCI1394_busReset) {
+ PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
+ if (!host->in_bus_reset) {
+ hpsb_bus_reset(host);
+ }
+ ohci->NumBusResets++;
+ }
+ if (event & OHCI1394_reqTxComplete) {
+ PRINT(KERN_INFO, ohci->id, "reqTxComplete int received");
+ }
+ if (event & OHCI1394_RQPkt) {
+ PRINT(KERN_INFO, ohci->id, "RQPkt int received");
+ }
+ if (event & OHCI1394_RQPkt) {
+ PRINT(KERN_INFO, ohci->id, "ControlContext: %08X",
+ reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
+ }
+ if (event & OHCI1394_RSPkt) {
+ int rcv_bytes;
+ int i=0;
+
+ /* we calculate the number of received bytes from the
+ residual count field */
+ rcv_bytes = AR_RESP_BUF_SIZE -
+ (ohci->AR_resp_prg->status & 0xFFFF);
+
+ PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read",
+ ohci->AR_resp_prg->status,
+ ohci->AR_resp_prg->status & 0xffff,
+ rcv_bytes);
+
+ ohci->AR_resp_active = 0;
+
+ if ((ohci->AR_resp_prg->status & 0x84000000)
+ && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) {
+ hpsb_packet_received(host, ohci->AR_resp_buf,
+ rcv_bytes);
+ } else {
+ //HPSB_TRACE();
+ PRINT(KERN_ERR, ohci->id,
+ "AR resp DMA program status value 0x%x is incorrect!",
+ ohci->AR_resp_prg->status);
+ }
+
+
+ /* --------------- FIXME ---------------------------------
+ this is a complete hack... we stop the dma prg
+ and start it again so as to reset the dma buffer address
+ Very slow, very bad design... to change ASAP */
+
+ /* stop the channel program if it's still running */
+ reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
+
+ /* Wait until it effectively stops */
+ while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet)
+ & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id,
+ "runaway loop in DmaAT. bailing out...");
+ break;
+ }
+ }
+
+ reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
+ virt_to_bus(ohci->AR_resp_prg)|0x00000001);
+ ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
+ reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000);
+
+ /* ---------------- end of FIXME --------------------------*/
+ }
+ if (event & OHCI1394_isochRx) {
+ quadlet_t isoRecvIntEvent;
+
+ /* ASSUMPTION: We assume there is only one context for now. */
+
+ spin_lock(&ohci->IR_recv_lock);
+
+ /* Clear the isoRecvIntEvent register (very important!) */
+ isoRecvIntEvent= reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
+ reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
+ isoRecvIntEvent);
+
+ ohci->IR_buf_used++;
+ ohci->IR_buf_next_ind=
+ (ohci->IR_buf_next_ind + 1) % IR_NUM_DESC;
+
+ /* is buffer processing too slow? (all buffers used) */
+ if (ohci->IR_buf_next_ind == ohci->IR_buf_last_ind) {
+ int i= 0;
+
+ /* stop the context */
+ reg_write(ohci,
+ OHCI1394_IrRcvContextControlClear, 0x8000);
+
+ while (reg_read(ohci, OHCI1394_IrRcvContextControlSet)
+ & 0x400) {
+ i++;
+
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
+ break;
+ }
+
+ }
+
+ spin_unlock(&ohci->IR_recv_lock);
+ PRINT(KERN_ERR, ohci->id,
+ "iso receive processing too slow... stopped");
+ return;
+ }
+
+ /* reset status field of next descriptor */
+ ohci->IR_recv_prg[ohci->IR_buf_next_ind]->status=
+ IR_RECV_BUF_SIZE;
+
+ spin_unlock(&ohci->IR_recv_lock);
+
+ /* queue bottom half in immediate queue */
+ queue_task(&ohci->IR_pdl_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ if (event & OHCI1394_selfIDComplete) {
+ if (host->in_bus_reset) {
+ node_id = reg_read(ohci, OHCI1394_NodeID);
+ if (node_id & 0x8000000) { /* NodeID valid */
+ phyid = node_id & 0x0000003f;
+ isroot = (node_id & 0x40000000) != 0;
+
+ PRINT(KERN_INFO, ohci->id,
+ "SelfID process finished (phyid %d, %s)",
+ phyid, (isroot ? "root" : "not root"));
+
+ handle_selfid(ohci, host, phyid, isroot);
+ }
+ else
+ PRINT(KERN_ERR, ohci->id,
+ "SelfID process finished but NodeID"
+ " not valid: %08X",node_id);
+ }
+ else PRINT(KERN_INFO, ohci->id,
+ "phy reg received without reset\n");
+ }
+ if (event & OHCI1394_phyRegRcvd) {
+#if 0
+ if (host->in_bus_reset) {
+ PRINT(KERN_INFO, ohci->id, "PhyControl: %08X",
+ reg_read(ohci, OHCI1394_PhyControl));
+ } else printk("-%d- phy reg received without reset\n",
+ ohci->id);
+#endif
+ }
+ if (event & OHCI1394_reqTxComplete) {
+ /* async packet sent - transmitter ready */
+ u32 ack;
+ struct hpsb_packet *packet;
+
+ if (ohci->async_queue) {
+
+ spin_lock(&ohci->async_queue_lock);
+
+ ack=reg_read(ohci, OHCI1394_AsReqTrContextControlSet)
+ & 0xF;
+
+ packet = ohci->async_queue;
+ ohci->async_queue = packet->xnext;
+
+ if (ohci->async_queue != NULL) {
+ send_next_async(ohci);
+ }
+ spin_unlock(&ohci->async_queue_lock);
+ PRINT(KERN_INFO,ohci->id,
+ "packet sent with ack code %d",ack);
+ hpsb_packet_sent(host, packet, ack);
+ } else
+ PRINT(KERN_INFO,ohci->id,
+ "packet sent without async_queue (self-id?)");
+
+ ohci->TxRdy++;
+ }
+
+ ohci->NumInterrupts++;
+}
+
+/* This is the bottom half that processes iso receive descriptor buffers. */
+static void ohci_ir_proc_desc(void *data)
+{
+ quadlet_t *buf_ptr;
+ struct ti_ohci *ohci= (struct ti_ohci*)data;
+ int bytes_left, data_length;
+ unsigned int idx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->IR_recv_lock, flags);
+
+ while(ohci->IR_buf_used > 0)
+ {
+ idx= ohci->IR_buf_last_ind;
+
+ /* check to see if a fatal error occurred */
+ if ((ohci->IR_recv_prg[idx]->status >> 16) & 0x800) {
+ int i= 0;
+
+ /* stop the context */
+ reg_write(ohci, OHCI1394_IrRcvContextControlClear,
+ 0x8000);
+
+ while (reg_read(ohci, OHCI1394_IrRcvContextControlSet)
+ & 0x400) {
+ i++;
+
+ if (i > 5000) {
+ PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
+ break;
+ }
+
+ }
+
+ spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+ PRINT(KERN_ERR, ohci->id,
+ "fatal iso receive error -- status is %d",
+ ohci->IR_recv_prg[idx]->status & 0x1F);
+ return;
+ }
+
+ spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+
+ buf_ptr= bus_to_virt(ohci->IR_recv_prg[idx]->address);
+ bytes_left= IR_RECV_BUF_SIZE;
+
+ /* are we processing a split packet from last buffer */
+ if (ohci->IR_sp_bytes_left) {
+
+ if (!ohci->IR_spb_bytes_used) {
+ /* packet is in process of being dropped */
+ if (ohci->IR_sp_bytes_left > bytes_left) {
+ ohci->IR_sp_bytes_left-= bytes_left;
+ bytes_left= 0;
+ } else {
+ buf_ptr= bus_to_virt((unsigned long)
+ &((quadlet_t*)ohci->IR_recv_prg
+ [idx]->address)
+ [ohci->IR_sp_bytes_left / 4]);
+ bytes_left-= ohci->IR_sp_bytes_left;
+ ohci->IR_sp_bytes_left= 0;
+ }
+
+ } else {
+ /* packet is being assembled */
+ if (ohci->IR_sp_bytes_left > bytes_left) {
+ memcpy(&ohci->IR_spb
+ [ohci->IR_spb_bytes_used / 4],
+ buf_ptr, bytes_left);
+ ohci->IR_spb_bytes_used+= bytes_left;
+ ohci->IR_sp_bytes_left-= bytes_left;
+ bytes_left= 0;
+ } else {
+ memcpy(&ohci->IR_spb
+ [ohci->IR_spb_bytes_used / 4],
+ buf_ptr,
+ ohci->IR_sp_bytes_left);
+ ohci->IR_spb_bytes_used+=
+ ohci->IR_sp_bytes_left;
+ hpsb_packet_received(ohci->host,
+ ohci->IR_spb,
+ ohci->IR_spb_bytes_used);
+ buf_ptr=
+ bus_to_virt((unsigned long)
+ &((quadlet_t*)ohci->IR_recv_prg
+ [idx]->address)
+ [ohci->IR_sp_bytes_left / 4]);
+ bytes_left-= ohci->IR_sp_bytes_left;
+ ohci->IR_sp_bytes_left= 0;
+ ohci->IR_spb_bytes_used= 0;
+ }
+
+ }
+
+ }
+
+ while(bytes_left > 0) {
+ data_length= (int)((buf_ptr[0] >> 16) & 0xffff);
+
+ if (data_length % 4)
+ data_length+= 4 - (data_length % 4);
+
+ /* is this a split packet? */
+ if ( (bytes_left - (data_length + 8)) < 0 ) {
+
+ if ( (data_length + 8) <=
+ IR_SPLIT_PACKET_BUF_SIZE ) {
+ memcpy(ohci->IR_spb, buf_ptr,
+ bytes_left);
+ ohci->IR_spb_bytes_used= bytes_left;
+ } else {
+ PRINT(KERN_ERR, ohci->id, "Packet too large for split packet buffer... dropping it");
+ PRINT(KERN_DEBUG, ohci->id, "Header: %8.8x\n", buf_ptr[0]);
+ ohci->IR_spb_bytes_used= 0;
+ }
+
+ ohci->IR_sp_bytes_left=
+ (data_length + 8) - bytes_left;
+ } else {
+ hpsb_packet_received(ohci->host, buf_ptr,
+ (data_length + 8));
+ buf_ptr= bus_to_virt((unsigned long)
+ &((quadlet_t*)ohci->IR_recv_prg
+ [idx]->address)
+ [(IR_RECV_BUF_SIZE - bytes_left
+ + data_length + 8) / 4]);
+ }
+
+ bytes_left-= (data_length + 8);
+ }
+
+ spin_lock_irqsave(&ohci->IR_recv_lock, flags);
+ ohci->IR_buf_last_ind= (idx + 1) % IR_NUM_DESC;
+ ohci->IR_buf_used--;
+ }
+
+ spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+}
+
+static int add_card(struct pci_dev *dev)
+{
+#define FAIL(fmt, args...) \
+ PRINT_G(KERN_ERR, fmt , ## args); \
+ num_of_cards--; \
+ remove_card(ohci); \
+ return 1;
+
+ struct ti_ohci *ohci; /* shortcut to currently handled device */
+ int i;
+
+ if (num_of_cards == MAX_OHCI1394_CARDS) {
+ PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
+ "Adjust MAX_OHCI1394_CARDS in ti_ohci1394.h.",
+ MAX_OHCI1394_CARDS);
+ return 1;
+ }
+
+ ohci = &cards[num_of_cards++];
+
+ ohci->id = num_of_cards-1;
+ ohci->dev = dev;
+
+ ohci->state = 0;
+
+ if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
+ OHCI1394_DRIVER_NAME, ohci)) {
+ PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq);
+ } else {
+ FAIL("failed to allocate shared interrupt %d", dev->irq);
+ }
+
+ /* csr_config rom allocation */
+ ohci->csr_config_rom = kmalloc(1024, GFP_KERNEL);
+ if (ohci->csr_config_rom == NULL) {
+ FAIL("failed to allocate buffer config rom");
+ }
+ memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom));
+
+ /* self-id dma buffer allocation */
+ ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
+ if (ohci->self_id_buffer == NULL) {
+ FAIL("failed to allocate DMA buffer for self-id packets");
+ }
+
+ /* AR dma buffer allocation */
+ ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
+ if (ohci->AR_resp_buf != NULL) {
+ memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE);
+ } else {
+ FAIL("failed to allocate AR response DMA buffer");
+ }
+
+ /* AR dma program allocation */
+ ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE,
+ GFP_KERNEL);
+ if (ohci->AR_resp_prg != NULL) {
+ memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE);
+ } else {
+ FAIL("failed to allocate AR response DMA program");
+ }
+
+ /* AT dma program allocation */
+ ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE,
+ GFP_KERNEL);
+ if (ohci->AT_req_prg != NULL) {
+ memset(ohci->AT_req_prg, 0, AT_REQ_PRG_SIZE);
+ } else {
+ FAIL("failed to allocate AT request DMA program");
+ }
+
+ /* IR dma buffer and program allocation */
+ ohci->IR_recv_buf=
+ kmalloc(IR_NUM_DESC * sizeof(quadlet_t*),
+ GFP_KERNEL);
+
+ if (ohci->IR_recv_buf == NULL) {
+ FAIL("failed to allocate IR receive DMA buffer");
+ }
+
+ ohci->IR_recv_prg=
+ kmalloc(IR_NUM_DESC * sizeof(struct dma_cmd*),
+ GFP_KERNEL);
+
+ if (ohci->IR_recv_prg == NULL) {
+ FAIL("failed to allocate IR receive DMA program");
+ }
+
+ ohci->IR_spb= kmalloc(IR_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
+
+ if (ohci->IR_spb == NULL) {
+ FAIL("failed to allocate IR split packet buffer");
+ }
+
+ for (i= 0; i < IR_NUM_DESC; i++) {
+ ohci->IR_recv_buf[i]= kmalloc(IR_RECV_BUF_SIZE, GFP_KERNEL);
+
+ if (ohci->IR_recv_buf[i] != NULL) {
+ memset(ohci->IR_recv_buf[i], 0, IR_RECV_BUF_SIZE);
+ } else {
+ FAIL("failed to allocate IR DMA buffer");
+ }
+
+ ohci->IR_recv_prg[i]= kmalloc(sizeof(struct dma_cmd),
+ GFP_KERNEL);
+
+ if (ohci->IR_recv_prg[i] != NULL) {
+ memset(ohci->IR_recv_prg[i], 0,
+ sizeof(struct dma_cmd));
+ } else {
+ FAIL("failed to allocate IR DMA buffer");
+ }
+
+ }
+
+ ohci->IR_buf_used= 0;
+ ohci->IR_buf_last_ind= 0;
+ ohci->IR_buf_next_ind= 0;
+ spin_lock_init(&ohci->IR_recv_lock);
+ spin_lock_init(&ohci->IR_channel_lock);
+ ohci->IR_channel_usage= 0x0000000000000000;
+
+ /* initialize iso receive task */
+ ohci->IR_pdl_task.routine= ohci_ir_proc_desc;
+ ohci->IR_pdl_task.data= (void*)ohci;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+ ohci->registers = ioremap_nocache(dev->base_address[0],
+ OHCI1394_REGISTER_SIZE);
+#else
+ ohci->registers = ioremap_nocache(dev->resource[0].start,
+ OHCI1394_REGISTER_SIZE);
+#endif
+
+ if (ohci->registers == NULL) {
+ FAIL("failed to remap registers - card not accessible");
+ }
+
+ PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p",
+ ohci->registers);
+
+ return 0;
+#undef FAIL
+}
+
+#ifdef CONFIG_PROC_FS
+
+#define SR(fmt, reg0, reg1, reg2)\
+p += sprintf(p,fmt,reg_read(ohci, reg0),\
+ reg_read(ohci, reg1),reg_read(ohci, reg2));
+
+int ohci_get_info(char *buf, char **start, off_t fpos,
+ int length, int dummy)
+{
+ struct ti_ohci *ohci=&cards[0];
+ struct hpsb_host *host=ohci->host;
+ char *p=buf;
+ //unsigned char phyreg;
+ //int i, nports;
+ int i;
+
+ p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
+ p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n",
+ (reg_read(ohci, OHCI1394_NodeID) & 0xFFC0) >> 6,
+ reg_read(ohci, OHCI1394_NodeID)&0x3f);
+#if 0
+ p += sprintf(p," hardware version %d.%d GUID_ROM is %s\n\n",
+ (reg_read(ohci, OHCI1394_Version) & 0xFF0000) >>16,
+ reg_read(ohci, OHCI1394_Version) & 0xFF,
+ (reg_read(ohci, OHCI1394_Version) & 0x01000000)
+ ? "set" : "clear");
+#endif
+ p += sprintf(p,"\n### Host data ###\n");
+ p += sprintf(p,"node_count: %8d ",host->node_count);
+ p += sprintf(p,"node_id : %08X\n",host->node_id);
+ p += sprintf(p,"irm_id : %08X ",host->irm_id);
+ p += sprintf(p,"busmgr_id : %08X\n",host->busmgr_id);
+ p += sprintf(p,"%s %s %s\n",
+ host->initialized ? "initialized" : "",
+ host->in_bus_reset ? "in_bus_reset" : "",
+ host->attempt_root ? "attempt_root" : "");
+ p += sprintf(p,"%s %s %s %s\n",
+ host->is_root ? "root" : "",
+ host->is_cycmst ? "cycle_master" : "",
+ host->is_irm ? "iso_res_mgr" : "",
+ host->is_busmgr ? "bus_mgr" : "");
+
+ p += sprintf(p,"\n### ohci data ###\n");
+ p += sprintf(p,"AR_resp_buf : %p AR_resp_prg: %p\n",
+ ohci->AR_resp_buf, ohci->AR_resp_prg);
+
+ for (i= 0; i < IR_NUM_DESC; i++) {
+ p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n",
+ i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
+ }
+
+ /* ----- Register Dump ----- */
+ p += sprintf(p,"\n### HC Register dump ###\n");
+ SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n",
+ OHCI1394_Version, OHCI1394_GUID_ROM, OHCI1394_ATRetries);
+ SR("CSRReadData : %08x CSRCompData : %08x CSRControl : %08x\n",
+ OHCI1394_CSRReadData, OHCI1394_CSRCompareData, OHCI1394_CSRControl);
+ SR("ConfigROMhdr: %08x BusID : %08x BusOptions : %08x\n",
+ OHCI1394_ConfigROMhdr, OHCI1394_BusID, OHCI1394_BusOptions);
+ SR("GUIDHi : %08x GUIDLo : %08x ConfigROMmap: %08x\n",
+ OHCI1394_GUIDHi, OHCI1394_GUIDLo, OHCI1394_ConfigROMmap);
+ SR("PtdWrAddrLo : %08x PtdWrAddrHi : %08x VendorID : %08x\n",
+ OHCI1394_PostedWriteAddressLo, OHCI1394_PostedWriteAddressHi,
+ OHCI1394_VendorID);
+ SR("HCControl : %08x SelfIDBuffer: %08x SelfIDCount : %08x\n",
+ OHCI1394_HCControlSet, OHCI1394_SelfIDBuffer, OHCI1394_SelfIDCount);
+ SR("IRMuChMaskHi: %08x IRMuChMaskLo: %08x IntEvent : %08x\n",
+ OHCI1394_IRMultiChanMaskHiSet, OHCI1394_IRMultiChanMaskLoSet,
+ OHCI1394_IntEventSet);
+ SR("IntMask : %08x IsoXmIntEvnt: %08x IsoXmIntMask: %08x\n",
+ OHCI1394_IntMaskSet, OHCI1394_IsoXmitIntEventSet,
+ OHCI1394_IsoXmitIntMaskSet);
+ SR("IsoRcvIntEvt: %08x IsoRcvIntMsk: %08x FairnessCtrl: %08x\n",
+ OHCI1394_IsoRecvIntEventSet, OHCI1394_IsoRecvIntMaskSet,
+ OHCI1394_FairnessControl);
+ SR("LinkControl : %08x NodeID : %08x PhyControl : %08x\n",
+ OHCI1394_LinkControlSet, OHCI1394_NodeID, OHCI1394_PhyControl);
+ SR("IsoCyclTimer: %08x AsRqFilterHi: %08x AsRqFilterLo: %08x\n",
+ OHCI1394_IsochronousCycleTimer,
+ OHCI1394_AsReqFilterHiSet, OHCI1394_AsReqFilterLoSet);
+ SR("PhyReqFiltHi: %08x PhyReqFiltLo: %08x PhyUpperBnd : %08x\n",
+ OHCI1394_PhyReqFilterHiSet, OHCI1394_PhyReqFilterLoSet,
+ OHCI1394_PhyUpperBound);
+ SR("AsRqTrCxtCtl: %08x AsRqTrCmdPtr: %08x AsRsTrCtxCtl: %08x\n",
+ OHCI1394_AsReqTrContextControlSet, OHCI1394_AsReqTrCommandPtr,
+ OHCI1394_AsRspTrContextControlSet);
+ SR("AsRsTrCmdPtr: %08x AsRqRvCtxCtl: %08x AsRqRvCmdPtr: %08x\n",
+ OHCI1394_AsRspTrCommandPtr, OHCI1394_AsReqRcvContextControlSet,
+ OHCI1394_AsReqRcvCommandPtr);
+ SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n",
+ OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr,
+ OHCI1394_IntEventSet);
+
+#if 0
+ p += sprintf(p,"\n### Phy Register dump ###\n");
+ phyreg=get_phy_reg(ohci,1);
+ p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d IBR: %d Gap_count: %d\n",
+ 1,phyreg,(phyreg&0x80) != 0, (phyreg&0x40) !=0, phyreg&0x3f);
+ phyreg=get_phy_reg(ohci,2);
+ nports=phyreg&0x1f;
+ p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d E : %d Ports : %2d\n",
+ 2,phyreg,
+ (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
+ for (i=0;i<nports;i++) {
+ phyreg=get_phy_reg(ohci,3+i);
+ p += sprintf(p,"offset: %d val: 0x%02x -> [port %d] TPA: %d TPB: %d | %s %s\n",
+ 3+i,phyreg,
+ i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4,
+ (phyreg&0x08) ? "child" : "parent",
+ (phyreg&0x04) ? "connected" : "disconnected");
+ }
+ phyreg=get_phy_reg(ohci,3+i);
+ p += sprintf(p,"offset: %d val: 0x%02x -> ENV: %s Reg_count: %d\n",
+ 3+i,phyreg,
+ (((phyreg&0xC0)>>6)==0) ? "backplane" :
+ (((phyreg&0xC0)>>6)==1) ? "cable" : "reserved",
+ phyreg&0x3f);
+#endif
+
+ p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
+ p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
+
+ return p - buf;
+}
+
+struct proc_dir_entry ohci_proc_entry =
+{
+ 0, /* Inode number - dynamic */
+ 8, /* Length of the file name */
+ "ohci1394", /* The file name */
+ S_IFREG | S_IRUGO, /* File mode */
+ 1, /* Number of links */
+ 0, 0, /* The uid and gid for the file */
+ 0, /* The size of the file reported by ls. */
+ NULL, /* functions which can be done on the inode */
+ ohci_get_info, /* The read function for this file */
+ NULL
+};
+#endif
+
+static void remove_card(struct ti_ohci *ohci)
+{
+ if (ohci->registers)
+ iounmap(ohci->registers);
+ if (ohci->AR_resp_buf)
+ kfree(ohci->AR_resp_buf);
+ if (ohci->AR_resp_prg)
+ kfree(ohci->AR_resp_prg);
+ if (ohci->AT_req_prg)
+ kfree(ohci->AT_req_prg);
+ if (ohci->IR_recv_buf) {
+ int i;
+ for (i= 0; i < IR_NUM_DESC; i++) {
+ kfree(ohci->IR_recv_buf[i]);
+ }
+ kfree(ohci->IR_recv_buf);
+ }
+ if (ohci->IR_recv_prg) {
+ int i;
+ for (i= 0; i < IR_NUM_DESC; i++) {
+ kfree(ohci->IR_recv_prg[i]);
+ }
+ kfree(ohci->IR_recv_prg);
+ }
+ kfree(ohci->IR_spb);
+ if (ohci->self_id_buffer)
+ kfree(ohci->self_id_buffer);
+ if (ohci->csr_config_rom)
+ kfree(ohci->csr_config_rom);
+
+ free_irq(ohci->dev->irq, ohci);
+
+ ohci->state = 0;
+}
+
+static int init_driver()
+{
+ struct pci_dev *dev = NULL;
+ int success = 0;
+ int i;
+
+ if (num_of_cards) {
+ PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
+ return 0;
+ }
+
+ PRINT_G(KERN_INFO, "looking for Ohci1394 cards");
+
+ for (i = 0; supported_chips[i][0] != -1; i++) {
+ while ((dev = pci_find_device(supported_chips[i][0],
+ supported_chips[i][1], dev))
+ != NULL) {
+ if (add_card(dev) == 0) {
+ success = 1;
+ }
+ }
+ }
+
+ if (success == 0) {
+ PRINT_G(KERN_WARNING, "no operable Ohci1394 cards found");
+ return -ENXIO;
+ }
+
+#ifdef CONFIG_PROC_FS
+ if (proc_register(&proc_root, &ohci_proc_entry)) {
+ PRINT_G(KERN_ERR, "unable to register proc file\n");
+ return -EIO;
+ }
+#endif
+ return 0;
+}
+
+static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr)
+{
+ struct ti_ohci *ohci=host->hostdata;
+
+#if 0
+ PRINT(KERN_INFO, ohci->id, "request csr_rom address: %08X",
+ (u32)ohci->csr_config_rom);
+#endif
+
+ *ptr = ohci->csr_config_rom;
+ return sizeof(ohci_csr_rom);
+}
+
+struct hpsb_host_template *get_ohci_template(void)
+{
+ static struct hpsb_host_template tmpl;
+ static int initialized = 0;
+
+ if (!initialized) {
+ /* Initialize by field names so that a template structure
+ * reorganization does not influence this code. */
+ tmpl.name = "ohci1394";
+
+ tmpl.detect_hosts = ohci_detect;
+ tmpl.initialize_host = ohci_initialize;
+ tmpl.release_host = ohci_remove;
+ tmpl.get_rom = get_ohci_rom;
+ tmpl.transmit_packet = ohci_transmit;
+ tmpl.devctl = ohci_devctl;
+
+ initialized = 1;
+ }
+
+ return &tmpl;
+}
+
+
+#ifdef MODULE
+
+/* EXPORT_NO_SYMBOLS; */
+
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("driver for PCI Ohci IEEE-1394 controller");
+MODULE_SUPPORTED_DEVICE("ohci1394");
+
+void cleanup_module(void)
+{
+ hpsb_unregister_lowlevel(get_ohci_template());
+#ifdef CONFIG_PROC_FS
+ proc_unregister(&proc_root, ohci_proc_entry.low_ino);
+#endif
+ PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
+}
+
+int init_module(void)
+{
+
+ if (hpsb_register_lowlevel(get_ohci_template())) {
+ PRINT_G(KERN_ERR, "registering failed\n");
+ return -ENXIO;
+ } else {
+ return 0;
+ }
+}
+
+#endif /* MODULE */
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
new file mode 100644
index 000000000..c6d7f469a
--- /dev/null
+++ b/drivers/ieee1394/ohci1394.h
@@ -0,0 +1,290 @@
+
+#ifndef _OHCI1394_H
+#define _OHCI1394_H
+
+#include "ieee1394_types.h"
+
+#define OHCI1394_DRIVER_NAME "ohci1394"
+
+#ifndef PCI_DEVICE_ID_TI_OHCI1394
+#define PCI_DEVICE_ID_TI_OHCI1394 0x8009
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_2
+#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019
+#endif
+
+#ifndef PCI_DEVICE_ID_VIA_OHCI1394
+#define PCI_DEVICE_ID_VIA_OHCI1394 0x3044
+#endif
+
+#define MAX_OHCI1394_CARDS 4
+
+#define AR_RESP_BUF_SIZE 4096
+#define AR_RESP_PRG_SIZE 256
+#define AT_REQ_PRG_SIZE 256
+
+#define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */
+#define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */
+#define IR_NUM_DESC 16 /* number of ISO recv descriptors */
+
+struct dma_cmd {
+ u32 control;
+ u32 address;
+ u32 branchAddress;
+ u32 status;
+};
+
+struct ti_ohci {
+ int id; /* sequential card number */
+
+ struct pci_dev *dev;
+
+ u32 state;
+
+ /* remapped memory spaces */
+ void *registers;
+
+ quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
+ quadlet_t *csr_config_rom; /* buffer for csr config rom */
+
+ /* asynchronous receive */
+ struct dma_cmd *AR_resp_prg;
+ quadlet_t *AR_resp_buf;
+
+ /* asynchronous transmit */
+ struct dma_cmd *AT_req_prg;
+
+ /* isochronous receive */
+ struct dma_cmd **IR_recv_prg;
+ quadlet_t **IR_recv_buf;
+ unsigned int IR_buf_used;
+ unsigned int IR_buf_last_ind;
+ unsigned int IR_buf_next_ind;
+ spinlock_t IR_recv_lock;
+
+ /* iso recv split packet handling */
+ quadlet_t *IR_spb;
+ unsigned int IR_sp_bytes_left;
+ unsigned int IR_spb_bytes_used;
+
+ /* iso receive channel usage */
+ spinlock_t IR_channel_lock;
+ u64 IR_channel_usage;
+
+ /* iso receive task */
+ struct tq_struct IR_pdl_task;
+
+ /* IEEE-1394 part follows */
+ struct hpsb_host *host;
+
+ int phyid, isroot;
+
+ spinlock_t phy_reg_lock;
+
+ struct hpsb_packet *async_queue;
+ spinlock_t async_queue_lock;
+
+ int AR_resp_active;
+ int NumBusResets;
+ int TxRdy;
+ int NumInterrupts;
+};
+
+
+/*
+ * Register read and write helper functions.
+ */
+inline static void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
+{
+ writel(data, ohci->registers + offset);
+}
+
+inline static u32 reg_read(const struct ti_ohci *ohci, int offset)
+{
+ return readl(ohci->registers + offset);
+}
+
+/* This structure is not properly initialized ... it is taken from
+ the lynx_csr_rom written by Andreas ... Some fields in the root
+ directory and the module dependent info needs to be modified
+ I do not have the proper doc */
+quadlet_t ohci_csr_rom[] = {
+ /* bus info block */
+ 0x04040000, /* info/CRC length, CRC */
+ 0x31333934, /* 1394 magic number */
+ 0xf064a000, /* misc. settings - FIXME */
+ 0x08002856, /* vendor ID, chip ID high */
+ 0x0000083E, /* chip ID low */
+ /* root directory - FIXME */
+ 0x00090000, /* CRC length, CRC */
+ 0x03080028, /* vendor ID (Texas Instr.) */
+ 0x81000009, /* offset to textual ID */
+ 0x0c000200, /* node capabilities */
+ 0x8d00000e, /* offset to unique ID */
+ 0xc7000010, /* offset to module independent info */
+ 0x04000000, /* module hardware version */
+ 0x81000026, /* offset to textual ID */
+ 0x09000000, /* node hardware version */
+ 0x81000026, /* offset to textual ID */
+ /* module vendor ID textual */
+ 0x00080000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54455841, /* "Texas Instruments" */
+ 0x5320494e,
+ 0x53545255,
+ 0x4d454e54,
+ 0x53000000,
+ /* node unique ID leaf */
+ 0x00020000, /* CRC length, CRC */
+ 0x08002856, /* vendor ID, chip ID high */
+ 0x0000083E, /* chip ID low */
+ /* module dependent info - FIXME */
+ 0x00060000, /* CRC length, CRC */
+ 0xb8000006, /* ??? offset to module textual ID */
+ 0x81000004, /* ??? textual descriptor */
+ 0x00000000, /* SRAM size */
+ 0x00000000, /* AUXRAM size */
+ 0x00000000, /* AUX device */
+ /* module textual ID */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54534231, /* "TSB12LV22" */
+ 0x324c5632,
+ 0x32000000,
+ /* part number */
+ 0x00060000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x39383036, /* "9806000-0001" */
+ 0x3030342d,
+ 0x30303431,
+ 0x20000001,
+ /* module hardware version textual */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x5453424b, /* "TSBKOHCI403" */
+ 0x4f484349,
+ 0x34303300,
+ /* node hardware version textual */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54534234, /* "TSB41LV03" */
+ 0x314c5630,
+ 0x33000000
+};
+
+
+/* 2 KiloBytes of register space */
+#define OHCI1394_REGISTER_SIZE 0x800
+
+/* register map */
+#define OHCI1394_Version 0x000
+#define OHCI1394_GUID_ROM 0x004
+#define OHCI1394_ATRetries 0x008
+#define OHCI1394_CSRReadData 0x00C
+#define OHCI1394_CSRCompareData 0x010
+#define OHCI1394_CSRControl 0x014
+#define OHCI1394_ConfigROMhdr 0x018
+#define OHCI1394_BusID 0x01C
+#define OHCI1394_BusOptions 0x020
+#define OHCI1394_GUIDHi 0x024
+#define OHCI1394_GUIDLo 0x028
+#define OHCI1394_ConfigROMmap 0x034
+#define OHCI1394_PostedWriteAddressLo 0x038
+#define OHCI1394_PostedWriteAddressHi 0x03C
+#define OHCI1394_VendorID 0x040
+#define OHCI1394_HCControlSet 0x050
+#define OHCI1394_HCControlClear 0x054
+#define OHCI1394_SelfIDBuffer 0x064
+#define OHCI1394_SelfIDCount 0x068
+#define OHCI1394_IRMultiChanMaskHiSet 0x070
+#define OHCI1394_IRMultiChanMaskHiClear 0x074
+#define OHCI1394_IRMultiChanMaskLoSet 0x078
+#define OHCI1394_IRMultiChanMaskLoClear 0x07C
+#define OHCI1394_IntEventSet 0x080
+#define OHCI1394_IntEventClear 0x084
+#define OHCI1394_IntMaskSet 0x088
+#define OHCI1394_IntMaskClear 0x08C
+#define OHCI1394_IsoXmitIntEventSet 0x090
+#define OHCI1394_IsoXmitIntEventClear 0x094
+#define OHCI1394_IsoXmitIntMaskSet 0x098
+#define OHCI1394_IsoXmitIntMaskClear 0x09C
+#define OHCI1394_IsoRecvIntEventSet 0x0A0
+#define OHCI1394_IsoRecvIntEventClear 0x0A4
+#define OHCI1394_IsoRecvIntMaskSet 0x0A8
+#define OHCI1394_IsoRecvIntMaskClear 0x0AC
+#define OHCI1394_FairnessControl 0x0DC
+#define OHCI1394_LinkControlSet 0x0E0
+#define OHCI1394_LinkControlClear 0x0E4
+#define OHCI1394_NodeID 0x0E8
+#define OHCI1394_PhyControl 0x0EC
+#define OHCI1394_IsochronousCycleTimer 0x0F0
+#define OHCI1394_AsReqFilterHiSet 0x100
+#define OHCI1394_AsReqFilterHiClear 0x104
+#define OHCI1394_AsReqFilterLoSet 0x108
+#define OHCI1394_AsReqFilterLoClear 0x10C
+#define OHCI1394_PhyReqFilterHiSet 0x110
+#define OHCI1394_PhyReqFilterHiClear 0x114
+#define OHCI1394_PhyReqFilterLoSet 0x118
+#define OHCI1394_PhyReqFilterLoClear 0x11C
+#define OHCI1394_PhyUpperBound 0x120
+#define OHCI1394_AsReqTrContextControlSet 0x180
+#define OHCI1394_AsReqTrContextControlClear 0x184
+#define OHCI1394_AsReqTrCommandPtr 0x18C
+#define OHCI1394_AsRspTrContextControlSet 0x1A0
+#define OHCI1394_AsRspTrContextControlClear 0x1A4
+#define OHCI1394_AsRspTrCommandPtr 0x1AC
+#define OHCI1394_AsReqRcvContextControlSet 0x1C0
+#define OHCI1394_AsReqRcvContextControlClear 0x1C4
+#define OHCI1394_AsReqRcvCommandPtr 0x1CC
+#define OHCI1394_AsRspRcvContextControlSet 0x1E0
+#define OHCI1394_AsRspRcvContextControlClear 0x1E4
+#define OHCI1394_AsRspRcvCommandPtr 0x1EC
+
+/* Isochronous receive registers */
+/* Add (32 * n) for context n */
+#define OHCI1394_IrRcvContextControlSet 0x400
+#define OHCI1394_IrRcvContextControlClear 0x404
+#define OHCI1394_IrRcvCommandPtr 0x40C
+#define OHCI1394_IrRcvContextMatch 0x410
+
+/* Interrupts Mask/Events */
+
+#define OHCI1394_reqTxComplete 0x00000001
+#define OHCI1394_respTxComplete 0x00000002
+#define OHCI1394_ARRQ 0x00000004
+#define OHCI1394_ARRS 0x00000008
+#define OHCI1394_RQPkt 0x00000010
+#define OHCI1394_RSPkt 0x00000020
+#define OHCI1394_isochTx 0x00000040
+#define OHCI1394_isochRx 0x00000080
+#define OHCI1394_postedWriteErr 0x00001000
+#define OHCI1394_lockRespErr 0x00002000
+#define OHCI1394_selfIDComplete 0x00010000
+#define OHCI1394_busReset 0x00020000
+#define OHCI1394_phy 0x00080000
+#define OHCI1394_cycleSynch 0x00100000
+#define OHCI1394_cycle64Seconds 0x00200000
+#define OHCI1394_cycleLost 0x00400000
+#define OHCI1394_cycleInconsistent 0x00800000
+#define OHCI1394_unrecoverableError 0x01000000
+#define OHCI1394_cycleTooLong 0x02000000
+#define OHCI1394_phyRegRcvd 0x04000000
+#define OHCI1394_masterIntEnable 0x80000000
+
+#define OUTPUT_MORE 0x00000000
+#define OUTPUT_MORE_IMMEDIATE 0x02000000
+#define OUTPUT_LAST 0x103c0000
+#define OUTPUT_LAST_IMMEDIATE 0x123c0000
+
+#define DMA_SPEED_100 0x0
+#define DMA_SPEED_200 0x1
+#define DMA_SPEED_400 0x2
+
+#endif
+
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
new file mode 100644
index 000000000..ae87337f2
--- /dev/null
+++ b/drivers/ieee1394/pcilynx.c
@@ -0,0 +1,1469 @@
+/*
+ * ti_pcilynx.c - Texas Instruments PCILynx driver
+ * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
+ * Stephan Linz <linz@mazet.de>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Lynx DMA usage:
+ *
+ * 0 is used for Lynx local bus transfers
+ * 1 is async/selfid receive
+ * 2 is iso receive
+ * 3 is async transmit
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "pcilynx.h"
+
+
+#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START
+#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work.
+#endif
+
+/* print general (card independent) information */
+#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
+/* print card specific information */
+#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+
+
+static struct ti_lynx cards[MAX_PCILYNX_CARDS];
+static int num_of_cards = 0;
+
+
+/*
+ * PCL handling functions.
+ */
+
+static pcl_t alloc_pcl(struct ti_lynx *lynx)
+{
+ u8 m;
+ int i, j;
+
+ spin_lock(&lynx->lock);
+ /* FIXME - use ffz() to make this readable */
+ for (i = 0; i < LOCALRAM_SIZE; i++) {
+ m = lynx->pcl_bmap[i];
+ for (j = 0; j < 8; j++) {
+ if (m & 1<<j) {
+ continue;
+ }
+ m |= 1<<j;
+ lynx->pcl_bmap[i] = m;
+ spin_unlock(&lynx->lock);
+ return 8 * i + j;
+ }
+ }
+ spin_unlock(&lynx->lock);
+
+ return -1;
+}
+
+static void free_pcl(struct ti_lynx *lynx, pcl_t pclid)
+{
+ int off, bit;
+
+ off = pclid / 8;
+ bit = pclid % 8;
+
+ if (pclid < 0) {
+ return;
+ }
+
+ spin_lock(&lynx->lock);
+ if (lynx->pcl_bmap[off] & 1<<bit) {
+ lynx->pcl_bmap[off] &= ~(1<<bit);
+ } else {
+ PRINT(KERN_ERR, lynx->id,
+ "attempted to free unallocated PCL %d", pclid);
+ }
+ spin_unlock(&lynx->lock);
+}
+
+/* functions useful for debugging */
+static void pretty_print_pcl(const struct ti_pcl *pcl)
+{
+ int i;
+
+ printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",
+ pcl->next, pcl->user_data, pcl->pcl_status,
+ pcl->remaining_transfer_count, pcl->next_data_buffer);
+
+ printk("PCL");
+ for (i=0; i<13; i++) {
+ printk(" c%x:%08x d%x:%08x",
+ i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);
+ if (!(i & 0x3) && (i != 12)) printk("\nPCL");
+ }
+ printk("\n");
+}
+
+static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
+{
+ struct ti_pcl pcl;
+
+ get_pcl(lynx, pclid, &pcl);
+ pretty_print_pcl(&pcl);
+}
+
+
+static int add_card(struct pci_dev *dev);
+static void remove_card(struct ti_lynx *lynx);
+static int init_driver(void);
+
+
+
+
+/***********************************
+ * IEEE-1394 functionality section *
+ ***********************************/
+
+
+static int get_phy_reg(struct ti_lynx *lynx, int addr)
+{
+ int retval;
+ int i = 0;
+
+ unsigned long flags;
+
+ if (addr > 15) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": PHY register address %d out of range", addr);
+ return -1;
+ }
+
+ spin_lock_irqsave(&lynx->phy_reg_lock, flags);
+
+ do {
+ reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));
+ retval = reg_read(lynx, LINK_PHY);
+
+ if (i > 10000) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": runaway loop, aborting");
+ retval = -1;
+ break;
+ }
+ i++;
+ } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));
+
+ reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);
+ spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
+
+ if (retval != -1) {
+ return retval & 0xff;
+ } else {
+ return -1;
+ }
+}
+
+static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
+{
+ unsigned long flags;
+
+ if (addr > 15) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": PHY register address %d out of range", addr);
+ return -1;
+ }
+
+ if (val > 0xff) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": PHY register value %d out of range", val);
+ return -1;
+ }
+
+ spin_lock_irqsave(&lynx->phy_reg_lock, flags);
+
+ reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)
+ | LINK_PHY_WDATA(val));
+
+ spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
+
+ return 0;
+}
+
+static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
+{
+ int reg;
+
+ if (page > 7) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": PHY page %d out of range", page);
+ return -1;
+ }
+
+ reg = get_phy_reg(lynx, 7);
+ if (reg != -1) {
+ reg &= 0x1f;
+ reg |= (page << 5);
+ set_phy_reg(lynx, 7, reg);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+#if 0 /* not needed at this time */
+static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
+{
+ int reg;
+
+ if (port > 15) {
+ PRINT(KERN_ERR, lynx->id, __FUNCTION__
+ ": PHY port %d out of range", port);
+ return -1;
+ }
+
+ reg = get_phy_reg(lynx, 7);
+ if (reg != -1) {
+ reg &= 0xf0;
+ reg |= port;
+ set_phy_reg(lynx, 7, reg);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+#endif
+
+static u32 get_phy_vendorid(struct ti_lynx *lynx)
+{
+ u32 pvid = 0;
+ sel_phy_reg_page(lynx, 1);
+ pvid |= (get_phy_reg(lynx, 10) << 16);
+ pvid |= (get_phy_reg(lynx, 11) << 8);
+ pvid |= get_phy_reg(lynx, 12);
+ PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);
+ return pvid;
+}
+
+static u32 get_phy_productid(struct ti_lynx *lynx)
+{
+ u32 id = 0;
+ sel_phy_reg_page(lynx, 1);
+ id |= (get_phy_reg(lynx, 13) << 16);
+ id |= (get_phy_reg(lynx, 14) << 8);
+ id |= get_phy_reg(lynx, 15);
+ PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);
+ return id;
+}
+
+static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
+ struct hpsb_host *host)
+{
+ quadlet_t lsid;
+ char phyreg[7];
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ phyreg[i] = get_phy_reg(lynx, i);
+ }
+
+ /* FIXME? We assume a TSB21LV03A phy here. This code doesn't support
+ more than 3 ports on the PHY anyway. */
+
+ lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
+ lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
+ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
+ /* lsid |= (phyreg[6] & 0x01) << 11; *//* contender (phy dependent) */
+ lsid |= 1 << 11; /* set contender (hack) */
+ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
+
+ //for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */
+ for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */
+ if (phyreg[3 + i] & 0x4) {
+ lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
+ << (6 - i*2);
+ } else {
+ lsid |= 1 << (6 - i*2);
+ }
+ }
+
+ printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid);
+ return lsid;
+}
+
+static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t size)
+{
+ quadlet_t *q = lynx->rcv_page;
+ int phyid, isroot;
+ quadlet_t lsid = 0;
+
+ if (!lynx->phyic.reg_1394a) {
+ lsid = generate_own_selfid(lynx, host);
+ }
+
+ phyid = get_phy_reg(lynx, 0);
+ isroot = (phyid & 2) != 0;
+ phyid >>= 2;
+ PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",
+ phyid, (isroot ? "root" : "not root"));
+ reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);
+
+ if (!lynx->phyic.reg_1394a && !size) {
+ hpsb_selfid_received(host, lsid);
+ }
+
+ while (size > 0) {
+ if (!lynx->phyic.reg_1394a
+ && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
+ hpsb_selfid_received(host, lsid);
+ }
+
+ if (q[0] == ~q[1]) {
+ printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]);
+ hpsb_selfid_received(host, q[0]);
+ } else {
+ printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id,
+ q[0], q[1]);
+ }
+ q += 2;
+ size -= 8;
+ }
+
+ if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {
+ hpsb_selfid_received(host, lsid);
+ }
+
+ hpsb_selfid_complete(host, phyid, isroot);
+}
+
+
+
+/* This must be called with the async_queue_lock held. */
+static void send_next_async(struct ti_lynx *lynx)
+{
+ struct ti_pcl pcl;
+ struct hpsb_packet *packet = lynx->async_queue;
+
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+ pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14
+ | packet->header_size;
+#else
+ pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14
+ | packet->header_size | PCL_BIGENDIAN;
+#endif
+ pcl.buffer[0].pointer = virt_to_bus(packet->header);
+ pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
+ pcl.buffer[1].pointer = virt_to_bus(packet->data);
+
+ if (!packet->data_be) {
+ pcl.buffer[1].control |= PCL_BIGENDIAN;
+ }
+
+ put_pcl(lynx, lynx->async_pcl, &pcl);
+ run_pcl(lynx, lynx->async_pcl_start, 3);
+}
+
+
+static int lynx_detect(struct hpsb_host_template *tmpl)
+{
+ struct hpsb_host *host;
+ int i;
+
+ init_driver();
+
+ for (i = 0; i < num_of_cards; i++) {
+ host = hpsb_get_host(tmpl, 0);
+ if (host == NULL) {
+ /* simply don't init more after out of mem */
+ return i;
+ }
+ host->hostdata = &cards[i];
+ cards[i].host = host;
+ }
+
+ return num_of_cards;
+}
+
+static int lynx_initialize(struct hpsb_host *host)
+{
+ struct ti_lynx *lynx = host->hostdata;
+ struct ti_pcl pcl;
+ int i;
+ u32 *pcli;
+
+ lynx->async_queue = NULL;
+ spin_lock_init(&lynx->async_queue_lock);
+ spin_lock_init(&lynx->phy_reg_lock);
+
+ pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
+ put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
+
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+ pcl.buffer[0].control = PCL_CMD_RCV | 2048;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2048;
+#else
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048;
+ pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048;
+#endif
+ pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page);
+ pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048;
+ put_pcl(lynx, lynx->rcv_pcl, &pcl);
+
+ pcl.next = pcl_bus(lynx, lynx->async_pcl);
+ pcl.async_error_next = pcl_bus(lynx, lynx->async_pcl);
+ put_pcl(lynx, lynx->async_pcl_start, &pcl);
+
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048;
+#ifndef __BIG_ENDIAN
+ pcl.buffer[0].control |= PCL_BIGENDIAN;
+#endif
+
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ int page = i / ISORCV_PER_PAGE;
+ int sec = i % ISORCV_PER_PAGE;
+
+ pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page])
+ + sec * MAX_ISORCV_SIZE;
+ put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
+ }
+
+ pcli = (u32 *)&pcl;
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
+ }
+ put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
+
+ /* 85 bytes for each FIFO - FIXME - optimize or make configurable */
+ reg_write(lynx, FIFO_SIZES, 0x00555555);
+ /* 20 byte threshold before triggering PCI transfer */
+ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
+ /* 69 byte threshold on both send FIFOs before transmitting */
+ reg_write(lynx, FIFO_XMIT_THRESHOLD, 0x4545);
+
+ reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
+ reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
+ | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
+ | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
+ | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
+ | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
+ | LINK_INT_ATF_UNDERFLOW);
+
+ reg_write(lynx, DMA1_WORD0_CMP_VALUE, 0);
+ reg_write(lynx, DMA1_WORD0_CMP_ENABLE, 0xa<<4);
+ reg_write(lynx, DMA1_WORD1_CMP_VALUE, 0);
+ reg_write(lynx, DMA1_WORD1_CMP_ENABLE, DMA_WORD1_CMP_MATCH_NODE_BCAST
+ | DMA_WORD1_CMP_MATCH_BROADCAST | DMA_WORD1_CMP_MATCH_LOCAL
+ | DMA_WORD1_CMP_MATCH_BUS_BCAST | DMA_WORD1_CMP_ENABLE_SELF_ID
+ | DMA_WORD1_CMP_ENABLE_MASTER);
+
+ run_pcl(lynx, lynx->rcv_pcl_start, 1);
+
+ reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
+ reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
+
+ run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
+
+ reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
+ | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
+ | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
+ | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX
+ | LINK_CONTROL_CYCSOURCE | LINK_CONTROL_CYCTIMEREN);
+
+ /* attempt to enable contender bit -FIXME- would this work elsewhere? */
+ reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+ reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
+
+ return 1;
+}
+
+static void lynx_release(struct hpsb_host *host)
+{
+ struct ti_lynx *lynx;
+
+ if (host != NULL) {
+ lynx = host->hostdata;
+ remove_card(lynx);
+ } else {
+ unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+ }
+}
+
+
+/*
+ * FIXME - does not support iso/raw transmits yet and will choke on them.
+ */
+static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
+{
+ struct ti_lynx *lynx = host->hostdata;
+ struct hpsb_packet *p;
+ unsigned long flags;
+
+ if (packet->data_size >= 4096) {
+ PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%d)",
+ packet->data_size);
+ return 0;
+ }
+
+ packet->xnext = NULL;
+
+ spin_lock_irqsave(&lynx->async_queue_lock, flags);
+
+ if (lynx->async_queue == NULL) {
+ lynx->async_queue = packet;
+ send_next_async(lynx);
+ } else {
+ p = lynx->async_queue;
+ while (p->xnext != NULL) {
+ p = p->xnext;
+ }
+
+ p->xnext = packet;
+ }
+
+ spin_unlock_irqrestore(&lynx->async_queue_lock, flags);
+
+ return 1;
+}
+
+static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
+{
+ struct ti_lynx *lynx = host->hostdata;
+ int retval = 0;
+ struct hpsb_packet *packet, *lastpacket;
+ unsigned long flags;
+
+ switch (cmd) {
+ case RESET_BUS:
+ if (arg) {
+ arg = 3 << 6;
+ } else {
+ arg = 1 << 6;
+ }
+
+ PRINT(KERN_INFO, lynx->id, "resetting bus on request%s",
+ (host->attempt_root ? " and attempting to become root"
+ : ""));
+
+ spin_lock_irqsave(&lynx->phy_reg_lock, flags);
+ reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(1)
+ | LINK_PHY_WDATA(arg));
+ spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
+ break;
+
+ case GET_CYCLE_COUNTER:
+ retval = reg_read(lynx, CYCLE_TIMER);
+ break;
+
+ case SET_CYCLE_COUNTER:
+ reg_write(lynx, CYCLE_TIMER, arg);
+ break;
+
+ case SET_BUS_ID:
+ reg_write(lynx, LINK_ID,
+ (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));
+ break;
+
+ case ACT_CYCLE_MASTER:
+ if (arg) {
+ reg_set_bits(lynx, LINK_CONTROL,
+ LINK_CONTROL_CYCMASTER);
+ } else {
+ reg_clear_bits(lynx, LINK_CONTROL,
+ LINK_CONTROL_CYCMASTER);
+ }
+ break;
+
+ case CANCEL_REQUESTS:
+ spin_lock_irqsave(&lynx->async_queue_lock, flags);
+
+ reg_write(lynx, DMA3_CHAN_CTRL, 0);
+ packet = lynx->async_queue;
+ lynx->async_queue = NULL;
+
+ spin_unlock_irqrestore(&lynx->async_queue_lock, flags);
+
+ while (packet != NULL) {
+ lastpacket = packet;
+ packet = packet->xnext;
+ hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
+ }
+
+ break;
+
+ case MODIFY_USAGE:
+ if (arg) {
+ MOD_INC_USE_COUNT;
+ } else {
+ MOD_DEC_USE_COUNT;
+ }
+ break;
+
+ case ISO_LISTEN_CHANNEL:
+ spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
+
+ if (lynx->iso_rcv.chan_count++ == 0) {
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
+ DMA_WORD1_CMP_ENABLE_MASTER);
+ }
+
+ spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
+ break;
+
+ case ISO_UNLISTEN_CHANNEL:
+ spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
+
+ if (--lynx->iso_rcv.chan_count == 0) {
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
+ 0);
+ }
+
+ spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
+ break;
+
+ default:
+ PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+/***************************************
+ * IEEE-1394 functionality section END *
+ ***************************************/
+
+
+/* VFS functions for local bus / aux device access. Access to those
+ * is implemented as a character device instead of block devices
+ * because buffers are not wanted for this. Therefore llseek (from
+ * VFS) can be used for these char devices with obvious effects.
+ */
+static int mem_open(struct inode*, struct file*);
+static int mem_release(struct inode*, struct file*);
+static unsigned int aux_poll(struct file*, struct poll_table_struct*);
+static ssize_t mem_read (struct file*, char*, size_t, loff_t*);
+static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
+
+
+static struct file_operations aux_ops = {
+ /* FIXME: should have custom llseek with bounds checking*/
+ read: mem_read,
+ write: mem_write,
+ poll: aux_poll,
+ open: mem_open,
+ release: mem_release
+};
+
+
+static void aux_setup_pcls(struct ti_lynx *lynx)
+{
+ struct ti_pcl pcl;
+ unsigned long membufbus = virt_to_bus(lynx->mem_dma_buffer);
+ int i;
+
+ /* This pcl is used to start any aux transfers, the pointer to next
+ points to itself to avoid a dummy pcl (the PCL engine only executes
+ the next pcl on startup. The real chain is done by branch */
+ pcl.next = pcl_bus(lynx, lynx->mem_pcl.start);
+ pcl.buffer[0].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_SET;
+ pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.max);
+ pcl.buffer[1].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_CLEAR;
+ pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd);
+ put_pcl(lynx, lynx->mem_pcl.start, &pcl);
+
+ /* let maxpcl transfer exactly 32kB */
+ pcl.next = PCL_NEXT_INVALID;
+ for (i=0; i<8; i++) {
+ pcl.buffer[i].control = 4000;
+ pcl.buffer[i].pointer = membufbus + i * 4000;
+ }
+ pcl.buffer[0].control |= PCL_CMD_LBUS_TO_PCI /*| PCL_GEN_INTR*/;
+ pcl.buffer[8].control = 768 | PCL_LAST_BUFF;
+ pcl.buffer[8].pointer = membufbus + 8 * 4000;
+ put_pcl(lynx, lynx->mem_pcl.max, &pcl);
+
+
+ /* magic stuff - self and modpcl modifying pcl */
+ pcl.next = pcl_bus(lynx, lynx->mem_pcl.mod);
+ pcl.user_data = 4000;
+ pcl.buffer[0].control = PCL_CMD_LOAD;
+ pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd)
+ + pcloffs(user_data);
+ pcl.buffer[1].control = PCL_CMD_STOREQ;
+ pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.mod)
+ + pcloffs(buffer[1].control);
+ pcl.buffer[2].control = PCL_CMD_LOAD;
+ pcl.buffer[2].pointer = membufbus;
+ pcl.buffer[3].control = PCL_CMD_STOREQ;
+ pcl.buffer[3].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd)
+ + pcloffs(buffer[1].pointer);
+ pcl.buffer[4].control = PCL_CMD_STOREQ;
+ pcl.buffer[4].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd)
+ + pcloffs(buffer[6].pointer);
+ pcl.buffer[5].control = PCL_CMD_LOAD;
+ pcl.buffer[5].pointer = membufbus + 4;
+ pcl.buffer[6].control = PCL_CMD_STOREQ | PCL_LAST_CMD;
+ put_pcl(lynx, lynx->mem_pcl.cmd, &pcl);
+
+ /* modified by cmdpcl when actual transfer occurs */
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.buffer[0].control = PCL_CMD_LBUS_TO_PCI; /* null transfer */
+ for (i=1; i<13; i++) {
+ pcl.buffer[i].control = 4000;
+ pcl.buffer[i].pointer = membufbus + (i-1) * 4000;
+ }
+ put_pcl(lynx, lynx->mem_pcl.mod, &pcl);
+}
+
+static int mem_open(struct inode *inode, struct file *file)
+{
+ int cid = MINOR(inode->i_rdev);
+ enum { rom, aux, ram } type;
+ struct memdata *md;
+
+ MOD_INC_USE_COUNT;
+
+ if (cid < PCILYNX_MINOR_AUX_START) {
+ /* just for completeness */
+ MOD_DEC_USE_COUNT;
+ return -ENXIO;
+ } else if (cid < PCILYNX_MINOR_ROM_START) {
+ cid -= PCILYNX_MINOR_AUX_START;
+ if (cid >= num_of_cards || !cards[cid].aux_port) {
+ MOD_DEC_USE_COUNT;
+ return -ENXIO;
+ }
+ type = aux;
+ } else if (cid < PCILYNX_MINOR_RAM_START) {
+ cid -= PCILYNX_MINOR_ROM_START;
+ if (cid >= num_of_cards || !cards[cid].local_rom) {
+ MOD_DEC_USE_COUNT;
+ return -ENXIO;
+ }
+ type = rom;
+ } else {
+ /* WARNING: Know what you are doing when opening RAM.
+ * It is currently used inside the driver! */
+ cid -= PCILYNX_MINOR_RAM_START;
+ if (cid >= num_of_cards || !cards[cid].local_ram) {
+ MOD_DEC_USE_COUNT;
+ return -ENXIO;
+ }
+ type = ram;
+ }
+
+ md = (struct memdata *)vmalloc(sizeof(struct memdata));
+ if (md == NULL) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+
+ md->lynx = &cards[cid];
+ md->cid = cid;
+
+ switch (type) {
+ case rom:
+ md->type = rom;
+ break;
+ case ram:
+ md->type = ram;
+ break;
+ case aux:
+ md->aux_intr_last_seen = atomic_read(&cards[cid].aux_intr_seen);
+ md->type = aux;
+ break;
+ }
+
+ file->private_data = md;
+
+ return 0;
+}
+
+static int mem_release(struct inode *inode, struct file *file)
+{
+ struct memdata *md = (struct memdata *)file->private_data;
+
+ vfree(md);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table *pt)
+{
+ struct memdata *md = (struct memdata *)file->private_data;
+ int cid = md->cid;
+ unsigned int mask;
+ int intr_seen;
+
+ /* reading and writing is always allowed */
+ mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
+
+ if (md->type == aux) {
+ poll_wait(file, &cards[cid].aux_intr_wait, pt);
+ intr_seen = atomic_read(&cards[cid].aux_intr_seen);
+
+ if (md->aux_intr_last_seen != intr_seen) {
+ mask |= POLLPRI;
+ /* md->aux_intr_last_seen = intr_seen; */
+ md->aux_intr_last_seen++; /* don't miss interrupts */
+ /* FIXME - make ioctl for configuring this */
+ }
+ }
+
+ return mask;
+}
+
+
+/*
+ * do not DMA if count is too small because this will have a serious impact
+ * on performance - the value 2400 was found by experiment and may not work
+ * everywhere as good as here - use mem_mindma option for modules to change
+ */
+short mem_mindma = 2400;
+MODULE_PARM(mem_mindma, "h");
+
+static ssize_t mem_read(struct file *file, char *buffer, size_t count,
+ loff_t *offset)
+{
+ struct memdata *md = (struct memdata *)file->private_data;
+ size_t bcount;
+ size_t alignfix;
+ int off = (int)*offset; /* avoid useless 64bit-arithmetic */
+ void *membase;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ if ((off + count) > PCILYNX_MAX_MEMORY+1) {
+ count = PCILYNX_MAX_MEMORY+1 - off;
+ }
+ if (count <= 0) {
+ return 0;
+ }
+
+
+ down(&md->lynx->mem_dma_mutex);
+
+ switch (md->type) {
+ case rom:
+ reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | off);
+ membase = md->lynx->local_rom;
+ break;
+ case ram:
+ reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | off);
+ membase = md->lynx->local_ram;
+ break;
+ case aux:
+ reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | off);
+ membase = md->lynx->aux_port;
+ break;
+ default:
+ panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__,
+ md->lynx->id, md->type);
+ }
+
+ if (count < mem_mindma) {
+ memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count);
+ copy_to_user(buffer, md->lynx->mem_dma_buffer, count);
+ bcount = 0;
+ goto done;
+ }
+
+ bcount = count;
+ alignfix = 4 - (off % 4);
+ if (alignfix != 4) {
+ if (bcount < alignfix) {
+ alignfix = bcount;
+ }
+ memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, alignfix);
+ copy_to_user(buffer, md->lynx->mem_dma_buffer, alignfix);
+ if (bcount == alignfix) {
+ goto done;
+ }
+ bcount -= alignfix;
+ buffer += alignfix;
+ off += alignfix;
+ }
+
+ if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) {
+ PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!");
+ }
+
+ add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
+
+ if (bcount > 32768) {
+ current->state = TASK_INTERRUPTIBLE;
+
+ reg_write(md->lynx, DMA0_READY, 1); /* select maxpcl */
+ run_pcl(md->lynx, md->lynx->mem_pcl.start, 0);
+
+ while (reg_read(md->lynx, DMA0_CHAN_CTRL)
+ & DMA_CHAN_CTRL_BUSY) {
+ if (signal_pending(current)) {
+ reg_write(md->lynx, DMA0_CHAN_CTRL, 0);
+ goto rmwait_done;
+ }
+ schedule();
+ }
+
+ copy_to_user(buffer, md->lynx->mem_dma_buffer, 32768);
+ buffer += 32768;
+ bcount -= 32768;
+ }
+
+ *(u32 *)(md->lynx->mem_dma_buffer) =
+ pcl_bus(md->lynx, md->lynx->mem_pcl.mod)
+ + pcloffs(buffer[bcount/4000+1].control);
+ *(u32 *)(md->lynx->mem_dma_buffer+4) = PCL_LAST_BUFF | (bcount % 4000);
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ reg_write(md->lynx, DMA0_READY, 0);
+ run_pcl(md->lynx, md->lynx->mem_pcl.start, 0);
+
+ while (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) {
+ if (signal_pending(current)) {
+ reg_write(md->lynx, DMA0_CHAN_CTRL, 0);
+ goto rmwait_done;
+ }
+ schedule();
+ }
+
+ copy_to_user(buffer, md->lynx->mem_dma_buffer, bcount);
+ bcount = 0;
+
+ if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) {
+ PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!");
+ }
+
+ rmwait_done:
+ reg_write(md->lynx, DMA0_CHAN_CTRL, 0);
+ remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
+ done:
+ up(&md->lynx->mem_dma_mutex);
+
+ count -= bcount;
+ *offset += count;
+ return (count ? count : -EINTR);
+}
+
+
+static ssize_t mem_write(struct file *file, const char *buffer, size_t count,
+ loff_t *offset)
+{
+ struct memdata *md = (struct memdata *)file->private_data;
+
+ if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) {
+ count = PCILYNX_MAX_MEMORY+1 - *offset;
+ }
+ if (count == 0 || *offset > PCILYNX_MAX_MEMORY) {
+ return -ENOSPC;
+ }
+
+ /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */
+ switch (md->type) {
+ case aux:
+ copy_from_user(md->lynx->aux_port+(*offset), buffer, count);
+ break;
+ case ram:
+ copy_from_user(md->lynx->local_ram+(*offset), buffer, count);
+ break;
+ case rom:
+ /* the ROM may be writeable */
+ copy_from_user(md->lynx->local_rom+(*offset), buffer, count);
+ break;
+ }
+
+ file->f_pos += count;
+ return count;
+}
+
+
+
+/********************************************************
+ * Global stuff (interrupt handler, init/shutdown code) *
+ ********************************************************/
+
+
+static void lynx_irq_handler(int irq, void *dev_id,
+ struct pt_regs *regs_are_unused)
+{
+ struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
+ struct hpsb_host *host = lynx->host;
+ u32 intmask = reg_read(lynx, PCI_INT_STATUS);
+ u32 linkint = reg_read(lynx, LINK_INT_STATUS);
+
+ reg_write(lynx, PCI_INT_STATUS, intmask);
+ reg_write(lynx, LINK_INT_STATUS, linkint);
+ //printk("-%d- one interrupt: 0x%08x / 0x%08x\n", lynx->id, intmask, linkint);
+
+ if (intmask & PCI_INT_AUX_INT) {
+ atomic_inc(&lynx->aux_intr_seen);
+ wake_up_interruptible(&lynx->aux_intr_wait);
+ }
+
+ if (intmask & PCI_INT_DMA0_HLT) {
+ wake_up_interruptible(&lynx->mem_dma_intr_wait);
+ }
+
+
+ if (intmask & PCI_INT_1394) {
+ if (linkint & LINK_INT_PHY_TIMEOUT) {
+ PRINT(KERN_INFO, lynx->id, "PHY timeout occured");
+ }
+ if (linkint & LINK_INT_PHY_BUSRESET) {
+ PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
+ if (!host->in_bus_reset) {
+ hpsb_bus_reset(host);
+ }
+ }
+ if (linkint & LINK_INT_PHY_REG_RCVD) {
+ if (!host->in_bus_reset) {
+ printk("-%d- phy reg received without reset\n",
+ lynx->id);
+ }
+ }
+ if (linkint & LINK_INT_ISO_STUCK) {
+ PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");
+ }
+ if (linkint & LINK_INT_ASYNC_STUCK) {
+ PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");
+ }
+ if (linkint & LINK_INT_SENT_REJECT) {
+ PRINT(KERN_INFO, lynx->id, "sent reject");
+ }
+ if (linkint & LINK_INT_TX_INVALID_TC) {
+ PRINT(KERN_INFO, lynx->id, "invalid transaction code");
+ }
+ if (linkint & LINK_INT_GRF_OVERFLOW) {
+ PRINT(KERN_INFO, lynx->id, "GRF overflow");
+ }
+ if (linkint & LINK_INT_ITF_UNDERFLOW) {
+ PRINT(KERN_INFO, lynx->id, "ITF underflow");
+ }
+ if (linkint & LINK_INT_ATF_UNDERFLOW) {
+ PRINT(KERN_INFO, lynx->id, "ATF underflow");
+ }
+ }
+
+ if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
+ PRINT(KERN_INFO, lynx->id, "iso receive");
+
+ spin_lock(&lynx->iso_rcv.lock);
+
+ lynx->iso_rcv.stat[lynx->iso_rcv.next] =
+ reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));
+
+ lynx->iso_rcv.used++;
+ lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;
+
+ if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
+ || !lynx->iso_rcv.chan_count) {
+ printk("stopped\n");
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
+ }
+
+ run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,
+ CHANNEL_ISO_RCV);
+
+ spin_unlock(&lynx->iso_rcv.lock);
+
+ queue_task(&lynx->iso_rcv.tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+ if (intmask & PCI_INT_DMA3_HLT) {
+ /* async send DMA completed */
+ u32 ack;
+ struct hpsb_packet *packet;
+
+ spin_lock(&lynx->async_queue_lock);
+
+ ack = reg_read(lynx, DMA3_CHAN_STAT);
+ packet = lynx->async_queue;
+ lynx->async_queue = packet->xnext;
+
+ if (lynx->async_queue != NULL) {
+ send_next_async(lynx);
+ }
+
+ spin_unlock(&lynx->async_queue_lock);
+
+ if (ack & DMA_CHAN_STAT_SPECIALACK) {
+ printk("-%d- special ack %d\n", lynx->id,
+ (ack >> 15) & 0xf);
+ ack = ACKX_SEND_ERROR;
+ } else {
+ ack = (ack >> 15) & 0xf;
+ }
+
+ hpsb_packet_sent(host, packet, ack);
+ }
+
+ if (intmask & (PCI_INT_DMA1_HLT | PCI_INT_DMA1_PCL)) {
+ /* general receive DMA completed */
+ int stat = reg_read(lynx, DMA1_CHAN_STAT);
+
+ printk("-%d- received packet size %d\n", lynx->id,
+ stat & 0x1fff);
+
+ if (stat & DMA_CHAN_STAT_SELFID) {
+ handle_selfid(lynx, host, stat & 0x1fff);
+ reg_set_bits(lynx, LINK_CONTROL,
+ LINK_CONTROL_RCV_CMP_VALID
+ | LINK_CONTROL_TX_ASYNC_EN
+ | LINK_CONTROL_RX_ASYNC_EN);
+ } else {
+ hpsb_packet_received(host, lynx->rcv_page,
+ stat & 0x1fff);
+ }
+
+ run_pcl(lynx, lynx->rcv_pcl_start, 1);
+ }
+}
+
+static void iso_rcv_bh(struct ti_lynx *lynx)
+{
+ unsigned int idx;
+ quadlet_t *data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
+
+ while (lynx->iso_rcv.used) {
+ idx = lynx->iso_rcv.last;
+ spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
+
+ data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]
+ + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;
+
+ if (lynx->iso_rcv.stat[idx]
+ & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {
+ PRINT(KERN_INFO, lynx->id,
+ "iso receive error on %d to 0x%p", idx, data);
+ } else {
+ hpsb_packet_received(lynx->host, data,
+ lynx->iso_rcv.stat[idx] & 0x1fff);
+ }
+
+ spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
+ lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;
+ lynx->iso_rcv.used--;
+ }
+
+ if (lynx->iso_rcv.chan_count) {
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
+ DMA_WORD1_CMP_ENABLE_MASTER);
+ }
+ spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
+}
+
+
+static int add_card(struct pci_dev *dev)
+{
+#define FAIL(fmt, args...) \
+ PRINT_G(KERN_ERR, fmt , ## args); \
+ num_of_cards--; \
+ remove_card(lynx); \
+ return 1
+
+ struct ti_lynx *lynx; /* shortcut to currently handled device */
+ unsigned long page;
+ unsigned int i;
+
+ if (num_of_cards == MAX_PCILYNX_CARDS) {
+ PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
+ "Adjust MAX_PCILYNX_CARDS in ti_pcilynx.h.",
+ MAX_PCILYNX_CARDS);
+ return 1;
+ }
+
+ lynx = &cards[num_of_cards++];
+
+ lynx->id = num_of_cards-1;
+ lynx->dev = dev;
+
+ pci_set_master(dev);
+
+ if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
+ PCILYNX_DRIVER_NAME, lynx)) {
+ PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq);
+ lynx->state = have_intr;
+ } else {
+ FAIL("failed to allocate shared interrupt %d", dev->irq);
+ }
+
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ lynx->pcl_mem = kmalloc(8 * sizeof(lynx->pcl_bmap)
+ * sizeof(struct ti_pcl), GFP_KERNEL);
+
+ if (lynx->pcl_mem != NULL) {
+ lynx->state = have_pcl_mem;
+ PRINT(KERN_INFO, lynx->id,
+ "allocated PCL memory %d Bytes @ 0x%p",
+ 8 * sizeof(lynx->pcl_bmap) * sizeof(struct ti_pcl),
+ lynx->pcl_mem);
+ } else {
+ FAIL("failed to allocate PCL memory area");
+ }
+#endif
+
+ lynx->mem_dma_buffer = kmalloc(32768, GFP_KERNEL);
+ if (lynx->mem_dma_buffer != NULL) {
+ lynx->state = have_aux_buf;
+ } else {
+ FAIL("failed to allocate DMA buffer for aux");
+ }
+
+ page = get_free_page(GFP_KERNEL);
+ if (page != 0) {
+ lynx->rcv_page = (void *)page;
+ lynx->state = have_1394_buffers;
+ } else {
+ FAIL("failed to allocate receive buffer");
+ }
+
+ for (i = 0; i < ISORCV_PAGES; i++) {
+ page = get_free_page(GFP_KERNEL);
+ if (page != 0) {
+ lynx->iso_rcv.page[i] = (void *)page;
+ } else {
+ FAIL("failed to allocate iso receive buffers");
+ }
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+ lynx->registers = ioremap_nocache(dev->base_address[0],
+ PCILYNX_MAX_REGISTER);
+ lynx->local_ram = ioremap(dev->base_address[1], PCILYNX_MAX_MEMORY);
+ lynx->aux_port = ioremap(dev->base_address[2], PCILYNX_MAX_MEMORY);
+#else
+ lynx->registers = ioremap_nocache(dev->resource[0].start,
+ PCILYNX_MAX_REGISTER);
+ lynx->local_ram = ioremap(dev->resource[1].start, PCILYNX_MAX_MEMORY);
+ lynx->aux_port = ioremap(dev->resource[2].start, PCILYNX_MAX_MEMORY);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,15)
+ lynx->local_rom = ioremap(dev->rom_address, PCILYNX_MAX_MEMORY);
+#else
+ lynx->local_rom = ioremap(dev->resource[PCI_ROM_RESOURCE].start,
+ PCILYNX_MAX_MEMORY);
+#endif
+ lynx->state = have_iomappings;
+
+ if (lynx->registers == NULL) {
+ FAIL("failed to remap registers - card not accessible");
+ }
+
+#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ if (lynx->local_ram == NULL) {
+ FAIL("failed to remap local RAM which is required for "
+ "operation");
+ }
+#endif
+
+ /* alloc_pcl return values are not checked, it is expected that the
+ * provided PCL space is sufficient for the initial allocations */
+ if (lynx->aux_port != NULL) {
+ lynx->mem_pcl.start = alloc_pcl(lynx);
+ lynx->mem_pcl.cmd = alloc_pcl(lynx);
+ lynx->mem_pcl.mod = alloc_pcl(lynx);
+ lynx->mem_pcl.max = alloc_pcl(lynx);
+ aux_setup_pcls(lynx);
+
+ sema_init(&lynx->mem_dma_mutex, 1);
+ }
+ lynx->rcv_pcl = alloc_pcl(lynx);
+ lynx->rcv_pcl_start = alloc_pcl(lynx);
+ lynx->async_pcl = alloc_pcl(lynx);
+ lynx->async_pcl_start = alloc_pcl(lynx);
+
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
+ }
+ lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
+
+ /* all allocations successful - simple init stuff follows */
+
+ lynx->lock = SPIN_LOCK_UNLOCKED;
+
+ reg_write(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT | PCI_INT_DMA_ALL);
+
+ init_waitqueue_head(&lynx->mem_dma_intr_wait);
+ init_waitqueue_head(&lynx->aux_intr_wait);
+
+ lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh;
+ lynx->iso_rcv.tq.data = lynx;
+ lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED;
+
+ PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "
+ "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,
+ lynx->local_ram, lynx->aux_port);
+
+ /* now, looking for PHY register set */
+ if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
+ lynx->phyic.reg_1394a = 1;
+ PRINT(KERN_INFO, lynx->id,
+ "found 1394a conform PHY (using extended register set)");
+ lynx->phyic.vendor = get_phy_vendorid(lynx);
+ lynx->phyic.product = get_phy_productid(lynx);
+ } else {
+ lynx->phyic.reg_1394a = 0;
+ PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
+ }
+
+ return 0;
+#undef FAIL
+}
+
+static void remove_card(struct ti_lynx *lynx)
+{
+ int i;
+
+ switch (lynx->state) {
+ case have_iomappings:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ iounmap(lynx->registers);
+ iounmap(lynx->local_rom);
+ iounmap(lynx->local_ram);
+ iounmap(lynx->aux_port);
+ case have_1394_buffers:
+ for (i = 0; i < ISORCV_PAGES; i++) {
+ if (lynx->iso_rcv.page[i]) {
+ free_page((unsigned long)lynx->iso_rcv.page[i]);
+ }
+ }
+ free_page((unsigned long)lynx->rcv_page);
+ case have_aux_buf:
+ kfree(lynx->mem_dma_buffer);
+ case have_pcl_mem:
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ kfree(lynx->pcl_mem);
+#endif
+ case have_intr:
+ free_irq(lynx->dev->irq, lynx);
+ case clear:
+ /* do nothing - already freed */
+ }
+
+ lynx->state = clear;
+}
+
+static int init_driver()
+{
+ struct pci_dev *dev = NULL;
+ int success = 0;
+
+ if (num_of_cards) {
+ PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
+ return 0;
+ }
+
+ PRINT_G(KERN_INFO, "looking for PCILynx cards");
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_TI,
+ PCI_DEVICE_ID_TI_PCILYNX, dev))
+ != NULL) {
+ if (add_card(dev) == 0) {
+ success = 1;
+ }
+ }
+
+ if (success == 0) {
+ PRINT_G(KERN_WARNING, "no operable PCILynx cards found");
+ return -ENXIO;
+ }
+
+ if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed\n",
+ PCILYNX_MAJOR);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+{
+ *ptr = lynx_csr_rom;
+ return sizeof(lynx_csr_rom);
+}
+
+struct hpsb_host_template *get_lynx_template(void)
+{
+ static struct hpsb_host_template tmpl = {
+ name: "pcilynx",
+ detect_hosts: lynx_detect,
+ initialize_host: lynx_initialize,
+ release_host: lynx_release,
+ get_rom: get_lynx_rom,
+ transmit_packet: lynx_transmit,
+ devctl: lynx_devctl
+ };
+
+ return &tmpl;
+}
+
+
+#ifdef MODULE
+
+/* EXPORT_NO_SYMBOLS; */
+
+MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
+MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");
+MODULE_SUPPORTED_DEVICE("pcilynx");
+
+void cleanup_module(void)
+{
+ hpsb_unregister_lowlevel(get_lynx_template());
+ PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n");
+}
+
+int init_module(void)
+{
+ if (hpsb_register_lowlevel(get_lynx_template())) {
+ PRINT_G(KERN_ERR, "registering failed\n");
+ return -ENXIO;
+ } else {
+ return 0;
+ }
+}
+
+#endif /* MODULE */
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
new file mode 100644
index 000000000..27cbd0c78
--- /dev/null
+++ b/drivers/ieee1394/pcilynx.h
@@ -0,0 +1,528 @@
+#include <linux/config.h>
+
+#define PCILYNX_DRIVER_NAME "pcilynx"
+#define PCILYNX_MAJOR 177
+
+#define PCILYNX_MINOR_AUX_START 0
+#define PCILYNX_MINOR_ROM_START 16
+#define PCILYNX_MINOR_RAM_START 32
+
+#define PCILYNX_MAX_REGISTER 0xfff
+#define PCILYNX_MAX_MEMORY 0xffff
+
+#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
+#define MAX_PCILYNX_CARDS 4
+#define LOCALRAM_SIZE 64
+
+#define NUM_ISORCV_PCL 4
+#define MAX_ISORCV_SIZE 2048
+#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE)
+#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
+
+/* only iso rcv uses these definitions so far */
+#define CHANNEL_LOCALBUS 0
+#define CHANNEL_ASYNC_RCV 1
+#define CHANNEL_ISO_RCV 2
+#define CHANNEL_ASYNC_SEND 3
+
+typedef int pcl_t;
+
+struct ti_lynx {
+ int id; /* sequential card number */
+
+ spinlock_t lock;
+
+ struct pci_dev *dev;
+
+ struct {
+ unsigned reg_1394a:1;
+ u32 vendor;
+ u32 product;
+ } phyic;
+
+ enum { clear, have_intr, have_aux_buf, have_pcl_mem,
+ have_1394_buffers, have_iomappings } state;
+
+ /* remapped memory spaces */
+ void *registers;
+ void *local_rom;
+ void *local_ram;
+ void *aux_port;
+
+
+ atomic_t aux_intr_seen;
+ wait_queue_head_t aux_intr_wait;
+
+ void *mem_dma_buffer;
+ struct semaphore mem_dma_mutex;
+ wait_queue_head_t mem_dma_intr_wait;
+
+ /*
+ * use local RAM of LOCALRAM_SIZE (in kB) for PCLs, which allows for
+ * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
+ * the following is an allocation bitmap
+ */
+ u8 pcl_bmap[LOCALRAM_SIZE];
+
+#ifndef CONFIG_IEEE1394_LYNXRAM
+ /* point to PCLs memory area if needed */
+ void *pcl_mem;
+#endif
+
+ /* PCLs for local mem / aux transfers */
+ struct {
+ pcl_t start, cmd, mod, max;
+ } mem_pcl;
+
+ /* IEEE-1394 part follows */
+ struct hpsb_host *host;
+
+ int phyid, isroot;
+
+ spinlock_t phy_reg_lock;
+
+ pcl_t rcv_pcl_start, rcv_pcl;
+ void *rcv_page;
+ int rcv_active;
+
+ pcl_t async_pcl_start, async_pcl;
+ struct hpsb_packet *async_queue;
+ spinlock_t async_queue_lock;
+
+ struct {
+ pcl_t pcl[NUM_ISORCV_PCL];
+ u32 stat[NUM_ISORCV_PCL];
+ void *page[ISORCV_PAGES];
+ pcl_t pcl_start;
+ int chan_count;
+ int next, last, used, running;
+ struct tq_struct tq;
+ spinlock_t lock;
+ } iso_rcv;
+};
+
+/* the per-file data structure for mem space access */
+struct memdata {
+ struct ti_lynx *lynx;
+ int cid;
+ int aux_intr_last_seen;
+ enum { rom, aux, ram } type;
+};
+
+
+
+/*
+ * Register read and write helper functions.
+ */
+inline static void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
+{
+ writel(data, lynx->registers + offset);
+}
+
+inline static u32 reg_read(const struct ti_lynx *lynx, int offset)
+{
+ return readl(lynx->registers + offset);
+}
+
+inline static void reg_set_bits(const struct ti_lynx *lynx, int offset,
+ u32 mask)
+{
+ reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
+}
+
+inline static void reg_clear_bits(const struct ti_lynx *lynx, int offset,
+ u32 mask)
+{
+ reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
+}
+
+
+
+/* chip register definitions follow */
+
+#define MISC_CONTROL 0x40
+#define MISC_CONTROL_SWRESET (1<<0)
+
+#define PCI_INT_STATUS 0x48
+#define PCI_INT_ENABLE 0x4c
+/* status and enable have identical bit numbers */
+#define PCI_INT_INT_PEND (1<<31)
+#define PCI_INT_FORCED_INT (1<<30)
+#define PCI_INT_SLV_ADR_PERR (1<<28)
+#define PCI_INT_SLV_DAT_PERR (1<<27)
+#define PCI_INT_MST_DAT_PERR (1<<26)
+#define PCI_INT_MST_DEV_TIMEOUT (1<<25)
+#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23)
+#define PCI_INT_AUX_TIMEOUT (1<<18)
+#define PCI_INT_AUX_INT (1<<17)
+#define PCI_INT_1394 (1<<16)
+#define PCI_INT_DMA4_PCL (1<<9)
+#define PCI_INT_DMA4_HLT (1<<8)
+#define PCI_INT_DMA3_PCL (1<<7)
+#define PCI_INT_DMA3_HLT (1<<6)
+#define PCI_INT_DMA2_PCL (1<<5)
+#define PCI_INT_DMA2_HLT (1<<4)
+#define PCI_INT_DMA1_PCL (1<<3)
+#define PCI_INT_DMA1_HLT (1<<2)
+#define PCI_INT_DMA0_PCL (1<<1)
+#define PCI_INT_DMA0_HLT (1<<0)
+/* all DMA interrupts combined: */
+#define PCI_INT_DMA_ALL 0x3ff
+
+#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
+#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
+
+#define LBUS_ADDR 0xb4
+#define LBUS_ADDR_SEL_RAM (0x0<<16)
+#define LBUS_ADDR_SEL_ROM (0x1<<16)
+#define LBUS_ADDR_SEL_AUX (0x2<<16)
+#define LBUS_ADDR_SEL_ZV (0x3<<16)
+
+#define GPIO_CTRL_A 0xb8
+#define GPIO_CTRL_B 0xbc
+#define GPIO_DATA_BASE 0xc0
+
+#define DMA_BREG(base, chan) (base + chan * 0x20)
+#define DMA_SREG(base, chan) (base + chan * 0x10)
+
+#define DMA0_PREV_PCL 0x100
+#define DMA1_PREV_PCL 0x120
+#define DMA2_PREV_PCL 0x140
+#define DMA3_PREV_PCL 0x160
+#define DMA4_PREV_PCL 0x180
+#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
+
+#define DMA0_CURRENT_PCL 0x104
+#define DMA1_CURRENT_PCL 0x124
+#define DMA2_CURRENT_PCL 0x144
+#define DMA3_CURRENT_PCL 0x164
+#define DMA4_CURRENT_PCL 0x184
+#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
+
+#define DMA0_CHAN_STAT 0x10c
+#define DMA1_CHAN_STAT 0x12c
+#define DMA2_CHAN_STAT 0x14c
+#define DMA3_CHAN_STAT 0x16c
+#define DMA4_CHAN_STAT 0x18c
+#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
+/* CHAN_STATUS registers share bits */
+#define DMA_CHAN_STAT_SELFID (1<<31)
+#define DMA_CHAN_STAT_ISOPKT (1<<30)
+#define DMA_CHAN_STAT_PCIERR (1<<29)
+#define DMA_CHAN_STAT_PKTERR (1<<28)
+#define DMA_CHAN_STAT_PKTCMPL (1<<27)
+#define DMA_CHAN_STAT_SPECIALACK (1<<14)
+
+
+#define DMA0_CHAN_CTRL 0x110
+#define DMA1_CHAN_CTRL 0x130
+#define DMA2_CHAN_CTRL 0x150
+#define DMA3_CHAN_CTRL 0x170
+#define DMA4_CHAN_CTRL 0x190
+#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
+/* CHAN_CTRL registers share bits */
+#define DMA_CHAN_CTRL_ENABLE (1<<31)
+#define DMA_CHAN_CTRL_BUSY (1<<30)
+#define DMA_CHAN_CTRL_LINK (1<<29)
+
+#define DMA0_READY 0x114
+#define DMA1_READY 0x134
+#define DMA2_READY 0x154
+#define DMA3_READY 0x174
+#define DMA4_READY 0x194
+#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
+
+#define DMA_GLOBAL_REGISTER 0x908
+
+#define FIFO_SIZES 0xa00
+
+#define FIFO_CONTROL 0xa10
+#define GRF_FLUSH (1<<4)
+#define ITF_FLUSH (1<<3)
+#define ATF_FLUSH (1<<2)
+
+#define FIFO_XMIT_THRESHOLD 0xa14
+
+#define DMA0_WORD0_CMP_VALUE 0xb00
+#define DMA1_WORD0_CMP_VALUE 0xb10
+#define DMA2_WORD0_CMP_VALUE 0xb20
+#define DMA3_WORD0_CMP_VALUE 0xb30
+#define DMA4_WORD0_CMP_VALUE 0xb40
+#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
+
+#define DMA0_WORD0_CMP_ENABLE 0xb04
+#define DMA1_WORD0_CMP_ENABLE 0xb14
+#define DMA2_WORD0_CMP_ENABLE 0xb24
+#define DMA3_WORD0_CMP_ENABLE 0xb34
+#define DMA4_WORD0_CMP_ENABLE 0xb44
+#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
+
+#define DMA0_WORD1_CMP_VALUE 0xb08
+#define DMA1_WORD1_CMP_VALUE 0xb18
+#define DMA2_WORD1_CMP_VALUE 0xb28
+#define DMA3_WORD1_CMP_VALUE 0xb38
+#define DMA4_WORD1_CMP_VALUE 0xb48
+#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
+
+#define DMA0_WORD1_CMP_ENABLE 0xb0c
+#define DMA1_WORD1_CMP_ENABLE 0xb1c
+#define DMA2_WORD1_CMP_ENABLE 0xb2c
+#define DMA3_WORD1_CMP_ENABLE 0xb3c
+#define DMA4_WORD1_CMP_ENABLE 0xb4c
+#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
+/* word 1 compare enable flags */
+#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
+#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
+#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
+#define DMA_WORD1_CMP_MATCH_NODE_BCAST (1<<12)
+#define DMA_WORD1_CMP_MATCH_LOCAL (1<<11)
+#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
+#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
+
+#define LINK_ID 0xf00
+#define LINK_ID_BUS(id) (id<<22)
+#define LINK_ID_NODE(id) (id<<16)
+
+#define LINK_CONTROL 0xf04
+#define LINK_CONTROL_BUSY (1<<29)
+#define LINK_CONTROL_TX_ISO_EN (1<<26)
+#define LINK_CONTROL_RX_ISO_EN (1<<25)
+#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
+#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
+#define LINK_CONTROL_RESET_TX (1<<21)
+#define LINK_CONTROL_RESET_RX (1<<20)
+#define LINK_CONTROL_CYCMASTER (1<<11)
+#define LINK_CONTROL_CYCSOURCE (1<<10)
+#define LINK_CONTROL_CYCTIMEREN (1<<9)
+#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
+#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
+
+#define CYCLE_TIMER 0xf08
+
+#define LINK_PHY 0xf0c
+#define LINK_PHY_READ (1<<31)
+#define LINK_PHY_WRITE (1<<30)
+#define LINK_PHY_ADDR(addr) (addr<<24)
+#define LINK_PHY_WDATA(data) (data<<16)
+#define LINK_PHY_RADDR(addr) (addr<<8)
+
+
+#define LINK_INT_STATUS 0xf14
+#define LINK_INT_ENABLE 0xf18
+/* status and enable have identical bit numbers */
+#define LINK_INT_LINK_INT (1<<31)
+#define LINK_INT_PHY_TIMEOUT (1<<30)
+#define LINK_INT_PHY_REG_RCVD (1<<29)
+#define LINK_INT_PHY_BUSRESET (1<<28)
+#define LINK_INT_TX_RDY (1<<26)
+#define LINK_INT_RX_DATA_RDY (1<<25)
+#define LINK_INT_ISO_STUCK (1<<20)
+#define LINK_INT_ASYNC_STUCK (1<<19)
+#define LINK_INT_SENT_REJECT (1<<17)
+#define LINK_INT_HDR_ERR (1<<16)
+#define LINK_INT_TX_INVALID_TC (1<<15)
+#define LINK_INT_CYC_SECOND (1<<11)
+#define LINK_INT_CYC_START (1<<10)
+#define LINK_INT_CYC_DONE (1<<9)
+#define LINK_INT_CYC_PENDING (1<<8)
+#define LINK_INT_CYC_LOST (1<<7)
+#define LINK_INT_CYC_ARB_FAILED (1<<6)
+#define LINK_INT_GRF_OVERFLOW (1<<5)
+#define LINK_INT_ITF_UNDERFLOW (1<<4)
+#define LINK_INT_ATF_UNDERFLOW (1<<3)
+#define LINK_INT_ISOARB_FAILED (1<<0)
+
+/* PHY specifics */
+#define PHY_VENDORID_TI 0x800028
+#define PHY_PRODUCTID_TSB41LV03 0x000000
+
+
+/* this is the physical layout of a PCL, its size is 128 bytes */
+struct ti_pcl {
+ u32 next;
+ u32 async_error_next;
+ u32 user_data;
+ u32 pcl_status;
+ u32 remaining_transfer_count;
+ u32 next_data_buffer;
+ struct {
+ u32 control;
+ u32 pointer;
+ } buffer[13];
+};
+
+#include <linux/stddef.h>
+#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
+
+
+#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+
+inline static void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
+ const struct ti_pcl *pcl)
+{
+ int i;
+ u32 *in = (u32 *)pcl;
+ u32 *out = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
+
+ for (i = 0; i < 32; i++, out++, in++) {
+ writel(cpu_to_le32(*in), out);
+ }
+}
+
+inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
+ struct ti_pcl *pcl)
+{
+ int i;
+ u32 *out = (u32 *)pcl;
+ u32 *in = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
+
+ for (i = 0; i < 32; i++, out++, in++) {
+ *out = le32_to_cpu(readl(in));
+ }
+}
+
+inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
+{
+ return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl);
+}
+
+#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
+
+inline static void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
+ const struct ti_pcl *pcl)
+{
+ memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
+ (u32 *)pcl, sizeof(struct ti_pcl));
+}
+
+inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
+ struct ti_pcl *pcl)
+{
+ memcpy_le32((u32 *)pcl,
+ (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
+ sizeof(struct ti_pcl));
+}
+
+inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
+{
+ return virt_to_bus(lynx->pcl_mem) + pclid * sizeof(struct ti_pcl);
+}
+
+#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
+
+
+inline static void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
+ int dmachan)
+{
+ reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
+ pcl_bus(lynx, pclid) + idx * 4);
+ reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
+ DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
+}
+
+inline static void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
+{
+ run_sub_pcl(lynx, pclid, 0, dmachan);
+}
+
+#define PCL_NEXT_INVALID (1<<0)
+
+/* transfer commands */
+#define PCL_CMD_RCV (0x1<<24)
+#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
+#define PCL_CMD_XMT (0x2<<24)
+#define PCL_CMD_UNFXMT (0xc<<24)
+#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
+#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
+
+/* aux commands */
+#define PCL_CMD_NOP (0x0<<24)
+#define PCL_CMD_LOAD (0x3<<24)
+#define PCL_CMD_STOREQ (0x4<<24)
+#define PCL_CMD_STORED (0xb<<24)
+#define PCL_CMD_STORE0 (0x5<<24)
+#define PCL_CMD_STORE1 (0x6<<24)
+#define PCL_CMD_COMPARE (0xe<<24)
+#define PCL_CMD_SWAP_COMPARE (0xf<<24)
+#define PCL_CMD_ADD (0xd<<24)
+#define PCL_CMD_BRANCH (0x7<<24)
+
+/* BRANCH condition codes */
+#define PCL_COND_DMARDY_SET (0x1<<20)
+#define PCL_COND_DMARDY_CLEAR (0x2<<20)
+
+#define PCL_GEN_INTR (1<<19)
+#define PCL_LAST_BUFF (1<<18)
+#define PCL_LAST_CMD (PCL_LAST_BUFF)
+#define PCL_WAITSTAT (1<<17)
+#define PCL_BIGENDIAN (1<<16)
+
+
+quadlet_t lynx_csr_rom[] = {
+ /* bus info block */
+ 0x04040000, /* info/CRC length, CRC */
+ 0x31333934, /* 1394 magic number */
+ 0xf064a000, /* misc. settings */
+ 0x08002850, /* vendor ID, chip ID high */
+ 0x0000ffff, /* chip ID low */
+ /* root directory */
+ 0x00090000, /* CRC length, CRC */
+ 0x03080028, /* vendor ID (Texas Instr.) */
+ 0x81000009, /* offset to textual ID */
+ 0x0c000200, /* node capabilities */
+ 0x8d00000e, /* offset to unique ID */
+ 0xc7000010, /* offset to module independent info */
+ 0x04000000, /* module hardware version */
+ 0x81000026, /* offset to textual ID */
+ 0x09000000, /* node hardware version */
+ 0x81000026, /* offset to textual ID */
+ /* module vendor ID textual */
+ 0x00080000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54455841, /* "Texas Instruments" */
+ 0x5320494e,
+ 0x53545255,
+ 0x4d454e54,
+ 0x53000000,
+ /* node unique ID leaf */
+ 0x00020000, /* CRC length, CRC */
+ 0x08002850, /* vendor ID, chip ID high */
+ 0x0000ffff, /* chip ID low */
+ /* module dependent info */
+ 0x00060000, /* CRC length, CRC */
+ 0xb8000006, /* offset to module textual ID */
+ 0x81000004, /* ??? textual descriptor */
+ 0x39010000, /* SRAM size */
+ 0x3a010000, /* AUXRAM size */
+ 0x3b000000, /* AUX device */
+ /* module textual ID */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54534231, /* "TSB12LV21" */
+ 0x324c5632,
+ 0x31000000,
+ /* part number */
+ 0x00060000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x39383036, /* "9806000-0001" */
+ 0x3030342d,
+ 0x30303431,
+ 0x20000001,
+ /* module hardware version textual */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x5453424b, /* "TSBKPCITST" */
+ 0x50434954,
+ 0x53540000,
+ /* node hardware version textual */
+ 0x00050000, /* CRC length, CRC */
+ 0x00000000,
+ 0x00000000,
+ 0x54534232, /* "TSB21LV03" */
+ 0x313c5630,
+ 0x33000000
+};
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
new file mode 100644
index 000000000..596f95219
--- /dev/null
+++ b/drivers/ieee1394/raw1394.c
@@ -0,0 +1,823 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Raw interface to the bus
+ *
+ * Copyright (C) 1999 Andreas E. Bombe
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "ieee1394_core.h"
+#include "hosts.h"
+#include "highlevel.h"
+#include "ieee1394_transactions.h"
+#include "raw1394.h"
+
+
+LIST_HEAD(host_info_list);
+static int host_count = 0;
+spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+
+static struct hpsb_highlevel *hl_handle = NULL;
+
+static void queue_complete_cb(struct pending_request *req);
+
+static struct pending_request *__alloc_pending_request(int flags)
+{
+ struct pending_request *req;
+
+ req = (struct pending_request *)kmalloc(sizeof(struct pending_request),
+ flags);
+ if (req != NULL) {
+ memset(req, 0, sizeof(struct pending_request));
+ INIT_LIST_HEAD(&req->list);
+ req->tq.routine = (void(*)(void*))queue_complete_cb;
+ }
+
+ return req;
+}
+
+inline static struct pending_request *alloc_pending_request(void)
+{
+ return __alloc_pending_request(SLAB_KERNEL);
+}
+
+static void free_pending_request(struct pending_request *req)
+{
+ if (req->ibs) {
+ if (atomic_dec_and_test(&req->ibs->refcount)) {
+ kfree(req->ibs);
+ }
+ } else if (req->free_data) {
+ kfree(req->data);
+ }
+ free_hpsb_packet(req->packet);
+ kfree(req);
+}
+
+static void queue_complete_req(struct pending_request *req)
+{
+ unsigned long flags;
+ struct file_info *fi = req->file_info;
+
+ spin_lock_irqsave(&fi->reqlists_lock, flags);
+ list_del(&req->list);
+ list_add_tail(&req->list, &fi->req_complete);
+ spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+
+ up(&fi->complete_sem);
+ wake_up_interruptible(&fi->poll_wait_complete);
+}
+
+static void queue_complete_cb(struct pending_request *req)
+{
+ struct hpsb_packet *packet = req->packet;
+ int rcode = (packet->header[1] >> 12) & 0xf;
+
+ switch (packet->ack_code) {
+ case ACKX_NONE:
+ case ACKX_SEND_ERROR:
+ req->req.error = RAW1394_ERROR_SEND_ERROR;
+ break;
+ case ACKX_ABORTED:
+ req->req.error = RAW1394_ERROR_ABORTED;
+ break;
+ case ACKX_TIMEOUT:
+ req->req.error = RAW1394_ERROR_TIMEOUT;
+ break;
+ default:
+ req->req.error = (packet->ack_code << 16) | rcode;
+ break;
+ }
+
+ if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
+ req->req.length = 0;
+ }
+
+ free_tlabel(packet->host, packet->node_id, packet->tlabel);
+ queue_complete_req(req);
+}
+
+
+static void add_host(struct hpsb_host *host)
+{
+ struct host_info *hi;
+
+ hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
+ if (hi != NULL) {
+ INIT_LIST_HEAD(&hi->list);
+ hi->host = host;
+ INIT_LIST_HEAD(&hi->file_info_list);
+
+ spin_lock_irq(&host_info_lock);
+ list_add_tail(&hi->list, &host_info_list);
+ host_count++;
+ spin_unlock_irq(&host_info_lock);
+ }
+}
+
+
+static struct host_info *find_host_info(struct hpsb_host *host)
+{
+ struct list_head *lh;
+ struct host_info *hi;
+
+ lh = host_info_list.next;
+ while (lh != &host_info_list) {
+ hi = list_entry(lh, struct host_info, list);
+ if (hi->host == host) {
+ return hi;
+ }
+ lh = lh->next;
+ }
+
+ return NULL;
+}
+
+static void remove_host(struct hpsb_host *host)
+{
+ struct host_info *hi;
+
+ spin_lock_irq(&host_info_lock);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ list_del(&hi->list);
+ host_count--;
+ }
+ spin_unlock_irq(&host_info_lock);
+
+ if (hi == NULL) {
+ printk(KERN_ERR "raw1394: attempt to remove unknown host "
+ "0x%p\n", host);
+ return;
+ }
+
+ kfree(hi);
+}
+
+static void host_reset(struct hpsb_host *host)
+{
+ unsigned long flags;
+ struct list_head *lh;
+ struct host_info *hi;
+ struct file_info *fi;
+ struct pending_request *req;
+
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ lh = hi->file_info_list.next;
+
+ while (lh != &hi->file_info_list) {
+ fi = list_entry(lh, struct file_info, list);
+ req = __alloc_pending_request(SLAB_ATOMIC);
+
+ if (req != NULL) {
+ req->file_info = fi;
+ req->req.type = RAW1394_REQ_BUS_RESET;
+ req->req.generation = get_hpsb_generation();
+ req->req.misc = (host->node_id << 16)
+ | host->node_count;
+ queue_complete_req(req);
+ }
+
+ lh = lh->next;
+ }
+ }
+ spin_unlock_irqrestore(&host_info_lock, flags);
+}
+
+static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
+ unsigned int length)
+{
+ unsigned long flags;
+ struct list_head *lh;
+ struct host_info *hi;
+ struct file_info *fi;
+ struct pending_request *req;
+ struct iso_block_store *ibs = NULL;
+ LIST_HEAD(reqs);
+
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ for (lh = hi->file_info_list.next; lh != &hi->file_info_list;
+ lh = lh->next) {
+ fi = list_entry(lh, struct file_info, list);
+
+ if (!(fi->listen_channels & (1ULL << channel))) {
+ continue;
+ }
+
+ if (!ibs) {
+ ibs = kmalloc(sizeof(struct iso_block_store)
+ + length, SLAB_ATOMIC);
+ if (!ibs) break;
+
+ atomic_set(&ibs->refcount, 0);
+ memcpy(ibs->data, data, length);
+ }
+
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) {
+ kfree(ibs);
+ break;
+ }
+
+ atomic_inc(&ibs->refcount);
+
+ req->file_info = fi;
+ req->ibs = ibs;
+ req->data = ibs->data;
+ req->req.type = RAW1394_REQ_ISO_RECEIVE;
+ req->req.generation = get_hpsb_generation();
+ req->req.misc = 0;
+ req->req.recvb = fi->iso_buffer;
+ req->req.length = MIN(length, fi->iso_buffer_length);
+
+ list_add_tail(&req->list, &reqs);
+ }
+ }
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ lh = reqs.next;
+ while (lh != &reqs) {
+ req = list_entry(lh, struct pending_request, list);
+ lh = lh->next;
+ queue_complete_req(req);
+ }
+}
+
+
+static int dev_read(struct file *file, char *buffer, size_t count,
+ loff_t *offset_is_ignored)
+{
+ struct file_info *fi = (struct file_info *)file->private_data;
+ struct list_head *lh;
+ struct pending_request *req;
+
+ if (count != sizeof(struct raw1394_request)) {
+ return -EINVAL;
+ }
+
+ if (!access_ok(VERIFY_WRITE, buffer, count)) {
+ return -EFAULT;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (down_trylock(&fi->complete_sem)) {
+ return -EAGAIN;
+ }
+ } else {
+ if (down_interruptible(&fi->complete_sem)) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ spin_lock_irq(&fi->reqlists_lock);
+ lh = fi->req_complete.next;
+ list_del(lh);
+ spin_unlock_irq(&fi->reqlists_lock);
+
+ req = list_entry(lh, struct pending_request, list);
+
+ if (req->req.length) {
+ if (copy_to_user(req->req.recvb, req->data, req->req.length)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ }
+ }
+ __copy_to_user(buffer, &req->req, sizeof(req->req));
+
+ free_pending_request(req);
+ return sizeof(struct raw1394_request);
+}
+
+
+static int state_opened(struct file_info *fi, struct pending_request *req)
+{
+ if (req->req.type == RAW1394_REQ_INITIALIZE) {
+ if (req->req.misc == RAW1394_KERNELAPI_VERSION) {
+ fi->state = initialized;
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.generation = get_hpsb_generation();
+ } else {
+ req->req.error = RAW1394_ERROR_COMPAT;
+ req->req.misc = RAW1394_KERNELAPI_VERSION;
+ }
+ } else {
+ req->req.error = RAW1394_ERROR_STATE_ORDER;
+ }
+
+ req->req.length = 0;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+}
+
+static int state_initialized(struct file_info *fi, struct pending_request *req)
+{
+ struct list_head *lh;
+ struct host_info *hi;
+ struct raw1394_khost_list *khl;
+
+ if (req->req.generation != get_hpsb_generation()) {
+ req->req.error = RAW1394_ERROR_GENERATION;
+ req->req.generation = get_hpsb_generation();
+ req->req.length = 0;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+ }
+
+ switch (req->req.type) {
+ case RAW1394_REQ_LIST_CARDS:
+ spin_lock_irq(&host_info_lock);
+ khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count,
+ SLAB_ATOMIC);
+
+ if (khl != NULL) {
+ req->req.misc = host_count;
+ req->data = (quadlet_t *)khl;
+
+ lh = host_info_list.next;
+ while (lh != &host_info_list) {
+ hi = list_entry(lh, struct host_info, list);
+
+ khl->nodes = hi->host->node_count;
+ strcpy(khl->name, hi->host->template->name);
+
+ khl++;
+ lh = lh->next;
+ }
+ }
+ spin_unlock_irq(&host_info_lock);
+
+ if (khl != NULL) {
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.length = MIN(req->req.length,
+ sizeof(struct raw1394_khost_list)
+ * req->req.misc);
+ req->free_data = 1;
+ } else {
+ return -ENOMEM;
+ }
+ break;
+
+ case RAW1394_REQ_SET_CARD:
+ lh = NULL;
+
+ spin_lock_irq(&host_info_lock);
+ if (req->req.misc < host_count) {
+ lh = host_info_list.next;
+ while (req->req.misc--) {
+ lh = lh->next;
+ }
+ hi = list_entry(lh, struct host_info, list);
+ hpsb_inc_host_usage(hi->host);
+ list_add_tail(&fi->list, &hi->file_info_list);
+ fi->host = hi->host;
+ fi->state = connected;
+ }
+ spin_unlock_irq(&host_info_lock);
+
+ if (lh != NULL) {
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.misc = (fi->host->node_id << 16)
+ | fi->host->node_count;
+ } else {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ }
+
+ req->req.length = 0;
+ break;
+
+ default:
+ req->req.error = RAW1394_ERROR_STATE_ORDER;
+ req->req.length = 0;
+ break;
+ }
+
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+}
+
+static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
+{
+ int channel = req->req.misc;
+
+ spin_lock(&host_info_lock);
+ if ((channel > 63) || (channel < -64)) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ } else if (channel >= 0) {
+ /* allocate channel req.misc */
+ if (fi->listen_channels & (1ULL << channel)) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->listen_channels |= 1ULL << channel;
+ hpsb_listen_channel(hl_handle, fi->host, channel);
+ fi->iso_buffer = req->req.recvb;
+ fi->iso_buffer_length = req->req.length;
+ }
+ } else {
+ /* deallocate channel (one's complement neg) req.misc */
+ channel = ~channel;
+
+ if (fi->listen_channels & (1ULL << channel)) {
+ hpsb_unlisten_channel(hl_handle, fi->host, channel);
+ fi->listen_channels &= ~(1ULL << channel);
+ } else {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ }
+ }
+
+ req->req.length = 0;
+ queue_complete_req(req);
+ spin_unlock(&host_info_lock);
+}
+
+static int handle_local_request(struct file_info *fi,
+ struct pending_request *req)
+{
+ u64 addr = req->req.address & 0xffffffffffffULL;
+
+ req->data = kmalloc(req->req.length, SLAB_KERNEL);
+ if (!req->data) return -ENOMEM;
+ req->free_data = 1;
+
+ switch (req->req.type) {
+ case RAW1394_REQ_ASYNC_READ:
+ req->req.error = highlevel_read(fi->host, req->data, addr,
+ req->req.length);
+ break;
+
+ case RAW1394_REQ_ASYNC_WRITE:
+ if (copy_from_user(req->data, req->req.sendb,
+ req->req.length)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ break;
+ }
+
+ req->req.error = highlevel_write(fi->host, req->data, addr,
+ req->req.length);
+ req->req.length = 0;
+ break;
+
+ case RAW1394_REQ_LOCK:
+ if ((req->req.misc != EXTCODE_FETCH_ADD)
+ && (req->req.misc != EXTCODE_LITTLE_ADD)) {
+ if (req->req.length != 4) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ break;
+ }
+ } else {
+ if (req->req.length != 8) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ break;
+ }
+ }
+
+ if (copy_from_user(req->data, req->req.sendb,
+ req->req.length)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ break;
+ }
+
+ if (req->req.length == 8) {
+ req->req.error = highlevel_lock(fi->host, req->data,
+ addr, req->data[0],
+ req->data[1],
+ req->req.misc);
+ req->req.length = 4;
+ } else {
+ req->req.error = highlevel_lock(fi->host, req->data,
+ addr, req->data[0], 0,
+ req->req.misc);
+ }
+ break;
+
+ case RAW1394_REQ_LOCK64:
+ default:
+ req->req.error = RAW1394_ERROR_STATE_ORDER;
+ }
+
+ if (req->req.error) req->req.length = 0;
+ req->req.error |= 0x00100000;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+}
+
+static int handle_remote_request(struct file_info *fi,
+ struct pending_request *req, int node)
+{
+ struct hpsb_packet *packet = NULL;
+ u64 addr = req->req.address & 0xffffffffffffULL;
+
+ switch (req->req.type) {
+ case RAW1394_REQ_ASYNC_READ:
+ if (req->req.length == 4) {
+ packet = hpsb_make_readqpacket(fi->host, node, addr);
+ if (!packet) return -ENOMEM;
+
+ req->data = &packet->header[3];
+ } else if ((req->req.length % 4) == 0) {
+ packet = hpsb_make_readbpacket(fi->host, node, addr,
+ req->req.length);
+ if (!packet) return -ENOMEM;
+
+ req->data = packet->data;
+ } else {
+ req->req.error = RAW1394_ERROR_UNTIDY_LEN;
+ }
+ break;
+
+ case RAW1394_REQ_ASYNC_WRITE:
+ if (req->req.length == 4) {
+ packet = hpsb_make_writeqpacket(fi->host, node, addr,
+ 0);
+ if (!packet) return -ENOMEM;
+
+ if (copy_from_user(&packet->header[3], req->req.sendb,
+ 4)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ }
+ } else if ((req->req.length % 4) == 0) {
+ packet = hpsb_make_writebpacket(fi->host, node, addr,
+ req->req.length);
+ if (!packet) return -ENOMEM;
+
+ if (copy_from_user(packet->data, req->req.sendb,
+ req->req.length)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ }
+ } else {
+ req->req.error = RAW1394_ERROR_UNTIDY_LEN;
+ }
+ req->req.length = 0;
+ break;
+
+ case RAW1394_REQ_LOCK:
+ case RAW1394_REQ_LOCK64:
+ default:
+ req->req.error = RAW1394_ERROR_STATE_ORDER;
+ }
+
+ req->packet = packet;
+
+ if (req->req.error) {
+ req->req.length = 0;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+ }
+
+ req->tq.data = req;
+ queue_task(&req->tq, &packet->complete_tq);
+
+ spin_lock_irq(&fi->reqlists_lock);
+ list_add_tail(&req->list, &fi->req_pending);
+ spin_unlock_irq(&fi->reqlists_lock);
+
+ if (!hpsb_send_packet(packet)) {
+ req->req.error = RAW1394_ERROR_SEND_ERROR;
+ req->req.length = 0;
+ queue_complete_req(req);
+ }
+ return sizeof(struct raw1394_request);
+}
+
+static int state_connected(struct file_info *fi, struct pending_request *req)
+{
+ int node = req->req.address >> 48;
+
+ req->req.error = RAW1394_ERROR_NONE;
+
+ if (req->req.generation != get_hpsb_generation()) {
+ req->req.error = RAW1394_ERROR_GENERATION;
+ req->req.generation = get_hpsb_generation();
+ req->req.length = 0;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+ }
+
+ if (req->req.type == RAW1394_REQ_ISO_LISTEN) {
+ handle_iso_listen(fi, req);
+ return sizeof(struct raw1394_request);
+ }
+
+ if (req->req.length == 0) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ queue_complete_req(req);
+ return sizeof(struct raw1394_request);
+ }
+
+ if (fi->host->node_id == node) {
+ return handle_local_request(fi, req);
+ }
+
+ return handle_remote_request(fi, req, node);
+}
+
+
+static int dev_write(struct file *file, const char *buffer, size_t count,
+ loff_t *offset_is_ignored)
+{
+ struct file_info *fi = (struct file_info *)file->private_data;
+ struct pending_request *req;
+ int retval = 0;
+
+ if (count != sizeof(struct raw1394_request)) {
+ return -EINVAL;
+ }
+
+ req = alloc_pending_request();
+ if (req == NULL) {
+ return -ENOMEM;
+ }
+ req->file_info = fi;
+
+ if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
+ free_pending_request(req);
+ return -EFAULT;
+ }
+
+ switch (fi->state) {
+ case opened:
+ retval = state_opened(fi, req);
+ break;
+
+ case initialized:
+ retval = state_initialized(fi, req);
+ break;
+
+ case connected:
+ retval = state_connected(fi, req);
+ break;
+ }
+
+ if (retval < 0) {
+ free_pending_request(req);
+ }
+
+ return retval;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *pt)
+{
+ struct file_info *fi = file->private_data;
+ unsigned int mask = POLLOUT | POLLWRNORM;
+
+ poll_wait(file, &fi->poll_wait_complete, pt);
+
+ spin_lock_irq(&fi->reqlists_lock);
+ if (!list_empty(&fi->req_complete)) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irq(&fi->reqlists_lock);
+
+ return mask;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+ struct file_info *fi;
+
+ if (MINOR(inode->i_rdev)) {
+ return -ENXIO;
+ }
+
+ fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
+ if (fi == NULL) {
+ return -ENOMEM;
+ }
+
+ memset(fi, 0, sizeof(struct file_info));
+
+ INIT_LIST_HEAD(&fi->list);
+ fi->state = opened;
+ INIT_LIST_HEAD(&fi->req_pending);
+ INIT_LIST_HEAD(&fi->req_complete);
+ sema_init(&fi->complete_sem, 0);
+ spin_lock_init(&fi->reqlists_lock);
+ init_waitqueue_head(&fi->poll_wait_complete);
+
+ file->private_data = fi;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int dev_release(struct inode *inode, struct file *file)
+{
+ struct file_info *fi = file->private_data;
+ struct list_head *lh;
+ struct pending_request *req;
+ int done = 0, i;
+
+ for (i = 0; i < 64; i++) {
+ if (fi->listen_channels & (1ULL << i)) {
+ hpsb_unlisten_channel(hl_handle, fi->host, i);
+ }
+ }
+
+ spin_lock(&host_info_lock);
+ fi->listen_channels = 0;
+ spin_unlock(&host_info_lock);
+
+ while (!done) {
+ spin_lock_irq(&fi->reqlists_lock);
+
+ while (!list_empty(&fi->req_complete)) {
+ lh = fi->req_complete.next;
+ list_del(lh);
+
+ req = list_entry(lh, struct pending_request, list);
+
+ free_pending_request(req);
+ }
+
+ if (list_empty(&fi->req_pending)) {
+ done = 1;
+ }
+
+ spin_unlock_irq(&fi->reqlists_lock);
+
+ if (!done) {
+ down_interruptible(&fi->complete_sem);
+ }
+ }
+
+ if (fi->state == connected) {
+ spin_lock_irq(&host_info_lock);
+ list_del(&fi->list);
+ spin_unlock_irq(&host_info_lock);
+
+ hpsb_dec_host_usage(fi->host);
+ }
+
+ kfree(fi);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static struct hpsb_highlevel_ops hl_ops = {
+ add_host,
+ remove_host,
+ host_reset,
+ iso_receive
+};
+
+static struct file_operations file_ops = {
+ read: dev_read,
+ write: dev_write,
+ poll: dev_poll,
+ open: dev_open,
+ release: dev_release,
+};
+
+int init_raw1394(void)
+{
+ hl_handle = hpsb_register_highlevel(RAW1394_DEVICE_NAME, &hl_ops);
+ if (hl_handle == NULL) {
+ HPSB_ERR("raw1394 failed to register with ieee1394 highlevel");
+ return -ENOMEM;
+ }
+
+ if (register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME,
+ &file_ops)) {
+ HPSB_ERR("raw1394 failed to allocate device major");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+void cleanup_raw1394(void)
+{
+ unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+ hpsb_unregister_highlevel(hl_handle);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return init_raw1394();
+}
+
+void cleanup_module(void)
+{
+ return cleanup_raw1394();
+}
+
+#endif
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
new file mode 100644
index 000000000..b1b0e4b90
--- /dev/null
+++ b/drivers/ieee1394/raw1394.h
@@ -0,0 +1,110 @@
+
+#ifndef IEEE1394_RAW1394_H
+#define IEEE1394_RAW1394_H
+
+#define RAW1394_DEVICE_MAJOR 171
+#define RAW1394_DEVICE_NAME "raw1394"
+
+#define RAW1394_KERNELAPI_VERSION 1
+
+/* state: opened */
+#define RAW1394_REQ_INITIALIZE 1
+
+/* state: initialized */
+#define RAW1394_REQ_LIST_CARDS 2
+#define RAW1394_REQ_SET_CARD 3
+
+/* state: connected */
+#define RAW1394_REQ_ASYNC_READ 100
+#define RAW1394_REQ_ASYNC_WRITE 101
+#define RAW1394_REQ_LOCK 102
+#define RAW1394_REQ_LOCK64 103
+
+#define RAW1394_REQ_ISO_LISTEN 200
+
+/* kernel to user */
+#define RAW1394_REQ_BUS_RESET 10000
+#define RAW1394_REQ_ISO_RECEIVE 10001
+
+/* error codes */
+#define RAW1394_ERROR_NONE 0
+#define RAW1394_ERROR_COMPAT (-1001)
+#define RAW1394_ERROR_STATE_ORDER (-1002)
+#define RAW1394_ERROR_GENERATION (-1003)
+#define RAW1394_ERROR_INVALID_ARG (-1004)
+#define RAW1394_ERROR_MEMFAULT (-1005)
+#define RAW1394_ERROR_ALREADY (-1006)
+
+#define RAW1394_ERROR_EXCESSIVE (-1020)
+#define RAW1394_ERROR_UNTIDY_LEN (-1021)
+
+#define RAW1394_ERROR_SEND_ERROR (-1100)
+#define RAW1394_ERROR_ABORTED (-1101)
+#define RAW1394_ERROR_TIMEOUT (-1102)
+
+
+struct raw1394_request {
+ int type;
+ int error;
+ int misc;
+
+ unsigned int generation;
+ octlet_t address;
+
+ unsigned long tag;
+
+ size_t length;
+ quadlet_t *sendb;
+ quadlet_t *recvb;
+};
+
+struct raw1394_khost_list {
+ int nodes;
+ char name[32];
+};
+
+#ifdef __KERNEL__
+
+struct iso_block_store {
+ atomic_t refcount;
+ quadlet_t data[0];
+};
+
+struct file_info {
+ struct list_head list;
+
+ enum { opened, initialized, connected } state;
+
+ struct hpsb_host *host;
+
+ struct list_head req_pending;
+ struct list_head req_complete;
+ struct semaphore complete_sem;
+ spinlock_t reqlists_lock;
+ wait_queue_head_t poll_wait_complete;
+
+ u64 listen_channels;
+ quadlet_t *iso_buffer;
+ size_t iso_buffer_length;
+};
+
+struct pending_request {
+ struct list_head list;
+ struct file_info *file_info;
+ struct hpsb_packet *packet;
+ struct tq_struct tq;
+ struct iso_block_store *ibs;
+ quadlet_t *data;
+ int free_data;
+ struct raw1394_request req;
+};
+
+struct host_info {
+ struct list_head list;
+ struct hpsb_host *host;
+ struct list_head file_info_list;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* IEEE1394_RAW1394_H */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index fbd4503bd..595d69b22 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -251,6 +251,7 @@ int el3_probe(struct net_device *dev)
if (el3_debug > 2) {
printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
+ EL3WINDOW(0);
for (i = 0; i < 3; i++) {
phys_addr[i] = htons(read_eeprom(ioaddr, i));
}
@@ -374,6 +375,7 @@ int el3_probe(struct net_device *dev)
((struct el3_private *)dev->priv)->mca_slot = mca_slot;
((struct el3_private *)dev->priv)->next_dev = el3_root_dev;
+ ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
el3_root_dev = dev;
if (el3_debug > 0)
@@ -434,9 +436,6 @@ el3_open(struct net_device *dev)
outw(RxReset, ioaddr + EL3_CMD);
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
- /* Set the spinlock before grabbing IRQ! */
- ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-
if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) {
return -EAGAIN;
}
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index ddb6d8bf8..f1449299b 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -16,7 +16,7 @@
*/
static const char *version =
- "3c527.c:v0.05 1999/09/06 Alan Cox (alan@redhat.com)\n";
+ "3c527.c:v0.07 2000/01/18 Alan Cox (alan@redhat.com)\n";
/*
* Things you need
@@ -447,10 +447,22 @@ static void mc32_ring_poll(struct net_device *dev)
/*
- * Send exec commands
+ * Send exec commands. This requires a bit of explaining.
+ *
+ * You feed the card a command, you wait, it interrupts you get a
+ * reply. All well and good. The complication arises because you use
+ * commands for filter list changes which come in at bh level from things
+ * like IPV6 group stuff.
+ *
+ * We have a simple state machine
+ *
+ * 0 - nothing issued
+ * 1 - command issued, wait reply
+ * 2 - reply waiting - reader then goes to state 0
+ * 3 - command issued, trash reply. In which case the irq
+ * takes it back to state 0
*/
-
/*
* Send command from interrupt state
*/
@@ -463,7 +475,7 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int
if(lp->exec_pending)
return -1;
- lp->exec_pending=1;
+ lp->exec_pending=3;
lp->exec_box->mbox=0;
lp->exec_box->mbox=cmd;
memcpy((void *)lp->exec_box->data, data, len);
@@ -492,6 +504,9 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
* Wait for a command
*/
+ save_flags(flags);
+ cli();
+
while(lp->exec_pending)
sleep_on(&lp->event);
@@ -500,6 +515,9 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
*/
lp->exec_pending=1;
+
+ restore_flags(flags);
+
lp->exec_box->mbox=0;
lp->exec_box->mbox=cmd;
memcpy((void *)lp->exec_box->data, data, len);
@@ -826,6 +844,10 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
wmb();
np->length = skb->len;
+
+ if(np->length < 60)
+ np->length = 60;
+
np->data = virt_to_bus(skb->data);
np->status = 0;
np->control = (1<<7)|(1<<6); /* EOP EOL */
@@ -1015,8 +1037,11 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
status>>=3;
if(status&1)
{
- /* 0=no 1=yes 2=reply clearing */
- lp->exec_pending=2;
+ /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */
+ if(lp->exec_pending!=3)
+ lp->exec_pending=2;
+ else
+ lp->exec_pending=0;
wake_up(&lp->event);
}
if(status&2)
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 01a8fae37..0a5d04a00 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -34,6 +34,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE
tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC
tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
+ tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
tristate ' Ariadne support' CONFIG_ARIADNE
@@ -264,6 +265,6 @@ fi
source drivers/net/wan/Config.in
-if [ "$CONFIG_PCMCIA" != "n" ]; then
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
source drivers/net/pcmcia/Config.in
fi
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e8bf8a3c8..03864c4ba 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -251,6 +251,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_NCR885E) += ncr885e.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
#
# HIPPI adapters
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 8582587c1..0151d4d52 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -40,12 +40,16 @@
8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
v1.12 10/27/97 Module support -djb
v1.14 2/3/98 Module support modified, made PCI support optional -djb
+ v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed
+ before unregister_netdev() which caused NULL pointer
+ reference later in the chain (in rtnetlink_fill_ifinfo())
+ -- Mika Kuoppala <miku@iki.fi>
Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
the 2.1 version of the old driver - Alan Cox
*/
-static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -349,11 +353,11 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
struct net_device *dev = &dev_lance[this_dev];
if (dev->priv != NULL) {
- kfree(dev->priv);
- dev->priv = NULL;
+ unregister_netdev(dev);
free_dma(dev->dma);
release_region(dev->base_addr, LANCE_TOTAL_SIZE);
- unregister_netdev(dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
}
}
}
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
new file mode 100644
index 000000000..282d436fd
--- /dev/null
+++ b/drivers/net/oaknet.c
@@ -0,0 +1,544 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: oaknet.c
+ *
+ * Description:
+ * Driver for the National Semiconductor DP83902AV Ethernet controller
+ * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
+ * various other 8390 drivers written by Donald Becker and Paul Gortmaker.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/board.h>
+#include <asm/io.h>
+
+#include "8390.h"
+
+
+/* Preprocessor Defines */
+
+#if !defined(TRUE) || TRUE != 1
+#define TRUE 1
+#endif
+
+#if !defined(FALSE) || FALSE != 0
+#define FALSE 0
+#endif
+
+#define OAKNET_CMD 0x00
+#define OAKNET_DATA 0x10 /* NS-defined port window offset. */
+#define OAKNET_RESET 0x1f /* A read resets, a write clears. */
+
+#define OAKNET_START_PG 0x20 /* First page of TX buffer */
+#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */
+
+#define OAKNET_BASE (dev->base_addr)
+
+#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */
+
+
+/* Global Variables */
+
+#if defined(MODULE)
+static struct net_device *oaknet_devs;
+#endif
+
+
+/* Function Prototypes */
+
+static int oaknet_open(struct net_device *dev);
+static int oaknet_close(struct net_device *dev);
+
+static void oaknet_reset_8390(struct net_device *dev);
+static void oaknet_get_8390_hdr(struct net_device *dev,
+ struct e8390_pkt_hdr *hdr, int ring_page);
+static void oaknet_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void oaknet_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, int start_page);
+
+static void oaknet_dma_error(struct net_device *dev, const char *name);
+
+
+/*
+ * int oaknet_init()
+ *
+ * Description:
+ * This routine performs all the necessary platform-specific initiali-
+ * zation and set-up for the IBM "Oak" evaluation board's National
+ * Semiconductor DP83902AV "ST-NIC" Ethernet controller.
+ *
+ * Input(s):
+ * N/A
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * 0 if OK, otherwise system error number on error.
+ *
+ */
+int
+oaknet_init(void)
+{
+ register int i;
+ int reg0, regd;
+ struct net_device *dev = NULL;
+ unsigned long ioaddr = OAKNET_IO_BASE;
+ const char *name = "National DP83902AV";
+ bd_t *bip = (bd_t *)__res;
+
+ /* Quick register check to see if the device is really there. */
+
+ if ((reg0 = inb_p(ioaddr)) == 0xFF)
+ return (ENODEV);
+
+ /*
+ * That worked. Now a more thorough check, using the multicast
+ * address registers, that the device is definitely out there
+ * and semi-functional.
+ */
+
+ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
+ regd = inb_p(ioaddr + 0x0D);
+ outb_p(0xFF, ioaddr + 0x0D);
+ outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
+ inb_p(ioaddr + EN0_COUNTER0);
+
+ /* It's no good. Fix things back up and leave. */
+
+ if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+ outb_p(reg0, ioaddr);
+ outb_p(regd, ioaddr + 0x0D);
+ dev->base_addr = 0;
+
+ return (ENODEV);
+ }
+
+ /*
+ * We're dependent on the 8390 generic driver module, make
+ * sure its symbols are loaded.
+ */
+
+ if (load_8390_module("oaknet.c"))
+ return (-ENOSYS);
+
+ /*
+ * We're not using the old-style probing API, so we have to allocate
+ * our own device structure.
+ */
+
+ dev = init_etherdev(0, 0);
+#if defined(MODULE)
+ oaknet_devs = dev;
+#endif
+
+ /*
+ * This controller is on an embedded board, so the base address
+ * and interrupt assignments are pre-assigned and unchageable.
+ */
+
+ dev->base_addr = OAKNET_IO_BASE;
+ dev->irq = OAKNET_INT;
+
+ /* Allocate 8390-specific device-private area and fields. */
+
+ if (ethdev_init(dev)) {
+ printk(" unable to get memory for dev->priv.\n");
+ return (-ENOMEM);
+ }
+
+ /*
+ * Just to be safe, reset the card as we cannot really* be sure
+ * what state it was last left in.
+ */
+
+ oaknet_reset_8390(dev);
+
+ /*
+ * Disable all chip interrupts for now and ACK all pending
+ * interrupts.
+ */
+
+ outb_p(0x0, ioaddr + EN0_IMR);
+ outb_p(0xFF, ioaddr + EN0_ISR);
+
+ /* Attempt to get the interrupt line */
+
+ if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
+ printk("%s: unable to request interrupt %d.\n",
+ dev->name, dev->irq);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return (EAGAIN);
+ }
+
+ request_region(dev->base_addr, OAKNET_IO_SIZE, name);
+
+ /* Tell the world about what and where we've found. */
+
+ printk("%s: %s at", dev->name, name);
+ for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+ dev->dev_addr[i] = bip->bi_enetaddr[i];
+ printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
+ }
+ printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
+
+ /* Set up some required driver fields and then we're done. */
+
+ ei_status.name = name;
+ ei_status.word16 = FALSE;
+ ei_status.tx_start_page = OAKNET_START_PG;
+ ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
+ ei_status.stop_page = OAKNET_STOP_PG;
+
+ ei_status.reset_8390 = &oaknet_reset_8390;
+ ei_status.block_input = &oaknet_block_input;
+ ei_status.block_output = &oaknet_block_output;
+ ei_status.get_8390_hdr = &oaknet_get_8390_hdr;
+
+ dev->open = oaknet_open;
+ dev->stop = oaknet_close;
+
+ NS8390_init(dev, FALSE);
+
+ return (0);
+}
+
+/*
+ * static int oaknet_open()
+ *
+ * Description:
+ * This routine is a modest wrapper around ei_open, the 8390-generic,
+ * driver open routine. This just increments the module usage count
+ * and passes along the status from ei_open.
+ *
+ * Input(s):
+ * *dev - Pointer to the device structure for this driver.
+ *
+ * Output(s):
+ * *dev - Pointer to the device structure for this driver, potentially
+ * modified by ei_open.
+ *
+ * Returns:
+ * 0 if OK, otherwise < 0 on error.
+ *
+ */
+static int
+oaknet_open(struct net_device *dev)
+{
+ int status = ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return (status);
+}
+
+/*
+ * static int oaknet_close()
+ *
+ * Description:
+ * This routine is a modest wrapper around ei_close, the 8390-generic,
+ * driver close routine. This just decrements the module usage count
+ * and passes along the status from ei_close.
+ *
+ * Input(s):
+ * *dev - Pointer to the device structure for this driver.
+ *
+ * Output(s):
+ * *dev - Pointer to the device structure for this driver, potentially
+ * modified by ei_close.
+ *
+ * Returns:
+ * 0 if OK, otherwise < 0 on error.
+ *
+ */
+static int
+oaknet_close(struct net_device *dev)
+{
+ int status = ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return (status);
+}
+
+/*
+ * static void oaknet_reset_8390()
+ *
+ * Description:
+ * This routine resets the DP83902 chip.
+ *
+ * Input(s):
+ * *dev -
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+static void
+oaknet_reset_8390(struct net_device *dev)
+{
+ int base = OAKNET_BASE;
+ unsigned long start = jiffies;
+
+ outb(inb(base + OAKNET_RESET), base + OAKNET_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check shouldn't be necessary eventually */
+
+ while ((inb_p(base + EN0_ISR) & ENISR_RESET) == 0) {
+ if (jiffies - start > OAKNET_WAIT) {
+ printk("%s: reset didn't complete\n", dev->name);
+ break;
+ }
+ }
+
+ outb_p(ENISR_RESET, base + EN0_ISR); /* ACK reset interrupt */
+
+ return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page)
+{
+ int base = OAKNET_BASE;
+
+ /*
+ * This should NOT happen. If it does, it is the LAST thing you'll
+ * see.
+ */
+
+ if (ei_status.dmaing) {
+ oaknet_dma_error(dev, "oaknet_get_8390_hdr");
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
+ outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
+ outb_p(0, base + EN0_RCNTHI);
+ outb_p(0, base + EN0_RSARLO); /* On page boundary */
+ outb_p(ring_page, base + EN0_RSARHI);
+ outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+
+ if (ei_status.word16)
+ insw(base + OAKNET_DATA, hdr,
+ sizeof(struct e8390_pkt_hdr) >> 1);
+ else
+ insb(base + OAKNET_DATA, hdr,
+ sizeof(struct e8390_pkt_hdr));
+
+ outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
+ ei_status.dmaing &= ~0x01;
+
+ return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+ int ring_offset)
+{
+ int base = OAKNET_BASE;
+ char *buf = skb->data;
+
+ /*
+ * This should NOT happen. If it does, it is the LAST thing you'll
+ * see.
+ */
+
+ if (ei_status.dmaing) {
+ oaknet_dma_error(dev, "oaknet_block_input");
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
+ outb_p(count & 0xff, base + EN0_RCNTLO);
+ outb_p(count >> 8, base + EN0_RCNTHI);
+ outb_p(ring_offset & 0xff, base + EN0_RSARLO);
+ outb_p(ring_offset >> 8, base + EN0_RSARHI);
+ outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+ if (ei_status.word16) {
+ insw(base + OAKNET_DATA, buf, count >> 1);
+ if (count & 0x01) {
+ buf[count-1] = inb(base + OAKNET_DATA);
+ }
+ } else {
+ insb(base + OAKNET_DATA, buf, count);
+ }
+ outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
+ ei_status.dmaing &= ~0x01;
+
+ return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, int start_page)
+{
+ int base = OAKNET_BASE;
+ int bug;
+ unsigned long start;
+ unsigned char lobyte;
+
+ /* Round the count up for word writes. */
+
+ if (ei_status.word16 && (count & 0x1))
+ count++;
+
+ /*
+ * This should NOT happen. If it does, it is the LAST thing you'll
+ * see.
+ */
+
+ if (ei_status.dmaing) {
+ oaknet_dma_error(dev, "oaknet_block_output");
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+
+ /* Make sure we are in page 0. */
+
+ outb_p(E8390_PAGE0 + E8390_START + E8390_NODMA, base + OAKNET_CMD);
+
+ /*
+ * The 83902 documentation states that the processor needs to
+ * do a "dummy read" before doing the remote write to work
+ * around a chip bug they don't feel like fixing.
+ */
+
+ bug = 0;
+ while (1) {
+ unsigned int rdhi;
+ unsigned int rdlo;
+
+ /* Now the normal output. */
+ outb_p(ENISR_RDC, base + EN0_ISR);
+ outb_p(count & 0xff, base + EN0_RCNTLO);
+ outb_p(count >> 8, base + EN0_RCNTHI);
+ outb_p(0x00, base + EN0_RSARLO);
+ outb_p(start_page, base + EN0_RSARHI);
+
+ if (bug++)
+ break;
+
+ /* Perform the dummy read */
+ rdhi = inb_p(base + EN0_CRDAHI);
+ rdlo = inb_p(base + EN0_CRDALO);
+ outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+
+ while (1) {
+ unsigned int nrdhi;
+ unsigned int nrdlo;
+ nrdhi = inb_p(base + EN0_CRDAHI);
+ nrdlo = inb_p(base + EN0_CRDALO);
+ if ((rdhi != nrdhi) || (rdlo != nrdlo))
+ break;
+ }
+ }
+
+ outb_p(E8390_RWRITE+E8390_START, base + OAKNET_CMD);
+ if (ei_status.word16) {
+ outsw(OAKNET_BASE + OAKNET_DATA, buf, count >> 1);
+ } else {
+ outsb(OAKNET_BASE + OAKNET_DATA, buf, count);
+ }
+
+ start = jiffies;
+
+ while (((lobyte = inb_p(base + EN0_ISR)) & ENISR_RDC) == 0) {
+ if (jiffies - start > OAKNET_WAIT) {
+ unsigned char hicnt, locnt;
+ hicnt = inb_p(base + EN0_CRDAHI);
+ locnt = inb_p(base + EN0_CRDALO);
+ printk("%s: timeout waiting for Tx RDC, stat = 0x%x\n",
+ dev->name, lobyte);
+ printk("\tstart address 0x%x, current address 0x%x, count %d\n",
+ (start_page << 8), (hicnt << 8) | locnt, count);
+ oaknet_reset_8390(dev);
+ NS8390_init(dev, TRUE);
+ break;
+ }
+ }
+
+ outb_p(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+
+ return;
+}
+
+static void
+oaknet_dma_error(struct net_device *dev, const char *name)
+{
+ printk(KERN_EMERG "%s: DMAing conflict in %s."
+ "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
+ dev->name, name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+
+ return;
+}
+
+#if defined(MODULE)
+/*
+ * Oak Ethernet module load interface.
+ */
+int
+init_module(void)
+{
+ int status;
+
+ if (oaknet_devs != NULL)
+ return (-EBUSY);
+
+ status = oaknet_init()
+
+ lock_8390_module();
+
+ return (status);
+}
+
+/*
+ * Oak Ethernet module unload interface.
+ */
+void
+cleanup_module(void)
+{
+ if (oaknet_devs == NULL)
+ return;
+
+ if (oaknet_devs->priv != NULL) {
+ int ioaddr = oaknet_devs->base_addr;
+ void *priv = oaknet_devs->priv;
+ free_irq(oaknet_devs->irq, oaknet_devs);
+ release_region(ioaddr, OAKNET_IO_SIZE);
+ unregister_netdev(oaknet_dev);
+ kfree(priv);
+ }
+
+ oaknet_devs = NULL;
+
+ unlock_8390_module();
+
+ return;
+}
+#endif /* MODULE */
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 0e9110a8b..4e4fc4157 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -119,7 +119,7 @@ static int irq_list[4] = { -1 };
#define TX_TIMEOUT ((800*HZ)/1000)
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 64;
+static int max_interrupt_work = 32;
/* Force full duplex modes? */
static int full_duplex = 0;
@@ -207,6 +207,8 @@ enum Window4 { /* Window 4: Xcvr/media bits. */
#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
struct el3_private {
+ dev_link_t link;
+ struct net_device dev;
dev_node_t node;
struct net_device_stats stats;
u16 advertising, partner; /* NWay media advertisement */
@@ -253,13 +255,11 @@ static void media_check(u_long arg);
static int el3_open(struct net_device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void update_stats(ioaddr_t addr, struct net_device *dev);
+static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev, int worklimit);
static int el3_close(struct net_device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
+static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
static dev_info_t dev_info = "3c574_cs";
@@ -307,6 +307,7 @@ static int tc574_init(struct net_device *dev)
static dev_link_t *tc574_attach(void)
{
+ struct el3_private *lp;
client_reg_t client_reg;
dev_link_t *link;
struct net_device *dev;
@@ -316,8 +317,12 @@ static dev_link_t *tc574_attach(void)
flush_stale_links();
/* Create the PC card device object. */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp) return NULL;
+ memset(lp, 0, sizeof(*lp));
+ link = &lp->link; dev = &lp->dev;
+ link->priv = dev->priv = link->irq.Instance = lp;
+
link->release.function = &tc574_release;
link->release.data = (u_long)link;
link->io.NumPorts1 = 32;
@@ -336,33 +341,18 @@ static dev_link_t *tc574_attach(void)
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
- /* Create the network device object. */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
-
- /* Make up a Odie-specific data structure. */
- dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct el3_private));
-
/* The EL3-specific entries in the device structure. */
dev->hard_start_xmit = &el3_start_xmit;
dev->get_stats = &el3_get_stats;
-#ifdef HAVE_PRIVATE_IOCTL
- dev->do_ioctl = &private_ioctl;
-#endif
+ dev->do_ioctl = &el3_ioctl;
dev->set_multicast_list = &set_rx_mode;
ether_setup(dev);
- dev->name = ((struct el3_private *)dev->priv)->node.dev_name;
+ dev->name = lp->node.dev_name;
dev->init = &tc574_init;
dev->open = &el3_open;
dev->stop = &el3_close;
dev->tbusy = 1;
- link->priv = dev;
-#if CS_RELEASE_CODE > 0x2911
- link->irq.Instance = dev;
-#endif
-
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
@@ -396,6 +386,7 @@ static dev_link_t *tc574_attach(void)
static void tc574_detach(dev_link_t *link)
{
+ struct el3_private *lp = link->priv;
dev_link_t **linkp;
long flags;
@@ -428,15 +419,9 @@ static void tc574_detach(dev_link_t *link)
/* Unlink device structure, free bits */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&lp->dev);
+ kfree(lp);
} /* tc574_detach */
@@ -451,9 +436,9 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void tc574_config(dev_link_t *link)
{
- client_handle_t handle;
- struct net_device *dev;
- struct el3_private *lp;
+ client_handle_t handle = link->handle;
+ struct el3_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
tuple_t tuple;
cisparse_t parse;
u_short buf[32];
@@ -462,8 +447,6 @@ static void tc574_config(dev_link_t *link)
u16 *phys_addr;
char *cardname;
- handle = link->handle;
- dev = link->priv;
phys_addr = (u16 *)dev->dev_addr;
DEBUG(0, "3c574_config(0x%p)\n", link);
@@ -528,7 +511,6 @@ static void tc574_config(dev_link_t *link)
link->state &= ~DEV_CONFIG_PENDING;
ioaddr = dev->base_addr;
- lp = (struct el3_private *)dev->priv;
link->dev = &lp->node;
/* The 3c574 normally uses an EEPROM for configuration info, including
@@ -641,7 +623,8 @@ failed:
static void tc574_release(u_long arg)
{
dev_link_t *link = (dev_link_t *)arg;
- struct net_device *dev = link->priv;
+ struct el3_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(0, "3c574_release(0x%p)\n", link);
@@ -675,7 +658,8 @@ static int tc574_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ struct el3_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(1, "3c574_event(0x%06x)\n", event);
@@ -922,10 +906,8 @@ static void tc574_reset(struct net_device *dev)
static int el3_open(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -935,14 +917,14 @@ static int el3_open(struct net_device *dev)
tc574_reset(dev);
lp->media.function = &media_check;
- lp->media.data = (u_long)dev;
+ lp->media.data = (u_long)lp;
lp->media.expires = jiffies + HZ;
add_timer(&lp->media);
DEBUG(2, "%s: opened, status %4.4x.\n",
dev->name, inw(dev->base_addr + EL3_STATUS));
- return 0; /* Always succeed */
+ return 0;
}
static void el3_tx_timeout(struct net_device *dev)
@@ -1054,14 +1036,13 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The EL3 interrupt handler. */
static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = (struct net_device *)dev_id;
- struct el3_private *lp;
+ struct el3_private *lp = dev_id;
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr, status;
int work_budget = max_interrupt_work;
- if ((dev == NULL) || !dev->start)
+ if ((lp == NULL) || !dev->start)
return;
- lp = (struct el3_private *)dev->priv;
ioaddr = dev->base_addr;
#ifdef PCMCIA_DEBUG
@@ -1098,7 +1079,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts. */
if (status & StatsFull)
- update_stats(ioaddr, dev);
+ update_stats(dev);
if (status & RxEarly) {
work_budget = el3_rx(dev, work_budget);
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
@@ -1151,8 +1132,8 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
static void media_check(u_long arg)
{
- struct net_device *dev = (struct net_device *)(arg);
- struct el3_private *lp = (struct el3_private *)dev->priv;
+ struct el3_private *lp = (struct el3_private *)arg;
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr = dev->base_addr;
u_long flags;
u_short /* cable, */ media, partner;
@@ -1165,7 +1146,7 @@ static void media_check(u_long arg)
(inb(ioaddr + Timer) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, dev, NULL);
+ el3_interrupt(dev->irq, lp, NULL);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
@@ -1228,7 +1209,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
struct el3_private *lp = (struct el3_private *)dev->priv;
if (dev->start)
- update_stats(dev->base_addr, dev);
+ update_stats(dev);
return &lp->stats;
}
@@ -1236,9 +1217,10 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
Suprisingly this need not be run single-threaded, but it effectively is.
The counters clear when read, so the adds must merely be atomic.
*/
-static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
+static void update_stats(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
u8 upper_cnt;
DEBUG(2, "%s: updating the statistics.\n", dev->name);
@@ -1252,16 +1234,16 @@ static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
lp->stats.tx_carrier_errors += inb(ioaddr + 0);
lp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- lp->stats.collisions += inb(ioaddr + 3);
- lp->stats.tx_window_errors += inb(ioaddr + 4);
- lp->stats.rx_fifo_errors += inb(ioaddr + 5);
- lp->stats.tx_packets += inb(ioaddr + 6);
- upper_cnt = inb(ioaddr + 9);
- lp->stats.tx_packets += (upper_cnt&0x30) << 4;
- /* Rx packets */ inb(ioaddr + 7);
- /* Tx deferrals */ inb(ioaddr + 8);
- lp->stats.rx_bytes += inw(ioaddr + 10);
- lp->stats.tx_bytes += inw(ioaddr + 12);
+ lp->stats.collisions += inb(ioaddr + 3);
+ lp->stats.tx_window_errors += inb(ioaddr + 4);
+ lp->stats.rx_fifo_errors += inb(ioaddr + 5);
+ lp->stats.tx_packets += inb(ioaddr + 6);
+ upper_cnt = inb(ioaddr + 9);
+ lp->stats.tx_packets += (upper_cnt&0x30) << 4;
+ /* Rx packets */ inb(ioaddr + 7);
+ /* Tx deferrals */ inb(ioaddr + 8);
+ lp->stats.rx_bytes += inw(ioaddr + 10);
+ lp->stats.tx_bytes += inw(ioaddr + 12);
/* With Vortex and later we must also clear the BadSSD counter. */
EL3WINDOW(4);
@@ -1284,12 +1266,12 @@ static int el3_rx(struct net_device *dev, int worklimit)
short error = rx_status & 0x3800;
lp->stats.rx_errors++;
switch (error) {
- case 0x0000: lp->stats.rx_over_errors++; break;
- case 0x0800: lp->stats.rx_length_errors++; break;
- case 0x1000: lp->stats.rx_frame_errors++; break;
- case 0x1800: lp->stats.rx_length_errors++; break;
- case 0x2000: lp->stats.rx_frame_errors++; break;
- case 0x2800: lp->stats.rx_crc_errors++; break;
+ case 0x0000: lp->stats.rx_over_errors++; break;
+ case 0x0800: lp->stats.rx_length_errors++; break;
+ case 0x1000: lp->stats.rx_frame_errors++; break;
+ case 0x1800: lp->stats.rx_length_errors++; break;
+ case 0x2000: lp->stats.rx_frame_errors++; break;
+ case 0x2800: lp->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
@@ -1343,14 +1325,13 @@ static int el3_rx(struct net_device *dev, int worklimit)
return worklimit;
}
-#ifdef HAVE_PRIVATE_IOCTL
/* Provide ioctl() calls to examine the MII xcvr state. */
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct el3_private *vp = (struct el3_private *)dev->priv;
+ struct el3_private *lp = (struct el3_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
- int phy = vp->phys[0] & 0x1f;
+ int phy = lp->phys[0] & 0x1f;
DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
dev->name, rq->ifr_ifrn.ifrn_name, cmd,
@@ -1378,7 +1359,7 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
int saved_window;
long flags;
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
save_flags(flags);
cli();
@@ -1393,7 +1374,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP;
}
}
-#endif /* HAVE_PRIVATE_IOCTL */
/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
documented. Until it is we revert to receiving all multicast frames when
@@ -1419,12 +1399,8 @@ static void set_rx_mode(struct net_device *dev)
static int el3_close(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
-
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
+ struct el3_private *lp = dev->priv;
+ dev_link_t *link = &lp->link;
DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
@@ -1439,12 +1415,12 @@ static int el3_close(struct net_device *dev)
/* Note: Switching to window 0 may disable the IRQ. */
EL3WINDOW(0);
- update_stats(ioaddr, dev);
+ update_stats(dev);
}
link->open--;
dev->start = 0;
- del_timer(&((struct el3_private *)dev->priv)->media);
+ del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c
index d5b3e95a0..82f534f0c 100644
--- a/drivers/net/pcmcia/3c575_cb.c
+++ b/drivers/net/pcmcia/3c575_cb.c
@@ -24,7 +24,7 @@ static const int rx_copybreak = 200;
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
static const int mtu = 1500;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 32;
/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
#define vortex_debug debug
@@ -40,7 +40,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
/* A few values that may be tweaked. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
+#define TX_TIMEOUT ((400*HZ)/1000)
/* Keep the ring sizes a power of two for efficiency. */
#define TX_RING_SIZE 16
@@ -442,13 +442,15 @@ struct vortex_private {
full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
hw_csums:1, /* Has hardware checksums. */
tx_full:1,
- open:1;
+ open:1,
+ reap:1;
u16 status_enable;
u16 intr_enable;
u16 available_media; /* From Wn3_Options. */
u16 capabilities, info1, info2; /* Various, from EEPROM. */
u16 advertising; /* NWay media advertisement */
unsigned char phys[2]; /* MII device addresses. */
+ u16 deferred;
};
/* The action to take with a media selection timer tick.
@@ -520,6 +522,22 @@ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
#include <pcmcia/driver_ops.h>
+static void vortex_reap(void)
+{
+ struct net_device **devp, **next;
+ printk(KERN_DEBUG "vortex_reap()\n");
+ for (devp = &root_vortex_dev; *devp; devp = next) {
+ struct vortex_private *vp = (*devp)->priv;
+ next = &vp->next_module;
+ if (vp->open || !vp->reap) continue;
+ unregister_netdev(*devp);
+ if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
+ kfree(*devp);
+ kfree(vp->priv_addr);
+ *devp = *next; next = devp;
+ }
+}
+
static dev_node_t *vortex_attach(dev_locator_t *loc)
{
u16 dev_id, vendor_id;
@@ -528,6 +546,7 @@ static dev_node_t *vortex_attach(dev_locator_t *loc)
struct net_device *dev;
int chip_idx;
+ vortex_reap();
if (loc->bus != LOC_PCI) return NULL;
bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
@@ -567,23 +586,16 @@ static dev_node_t *vortex_attach(dev_locator_t *loc)
static void vortex_detach(dev_node_t *node)
{
- struct net_device **devp, **next;
- printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
- for (devp = &root_vortex_dev; *devp; devp = next) {
- next = &((struct vortex_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ struct net_device *dev, *next;
+ printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name);
+ for (dev = root_vortex_dev; dev; dev = next) {
+ next = ((struct vortex_private *)dev->priv)->next_module;
+ if (strcmp(dev->name, node->dev_name) == 0) break;
}
- if (*devp) {
- struct net_device *dev = *devp;
+ if (dev && dev->priv) {
struct vortex_private *vp = dev->priv;
- if (dev->flags & IFF_UP)
- vortex_close(dev);
- dev->flags &= ~(IFF_UP|IFF_RUNNING);
- unregister_netdev(dev);
- if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
- kfree(dev);
- *devp = *next;
- kfree(vp->priv_addr);
+ if (vp->open) vortex_down(dev);
+ vp->reap = 1;
kfree(node);
MOD_DEC_USE_COUNT;
}
@@ -592,7 +604,7 @@ static void vortex_detach(dev_node_t *node)
static void vortex_suspend(dev_node_t *node)
{
struct net_device *dev, *next;
- printk(KERN_INFO "vortex_suspend(%s)\n", node->dev_name);
+ printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name);
for (dev = root_vortex_dev; dev; dev = next) {
next = ((struct vortex_private *)dev->priv)->next_module;
if (strcmp(dev->name, node->dev_name) == 0) break;
@@ -606,7 +618,7 @@ static void vortex_suspend(dev_node_t *node)
static void vortex_resume(dev_node_t *node)
{
struct net_device *dev, *next;
- printk(KERN_INFO "vortex_resume(%s)\n", node->dev_name);
+ printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name);
for (dev = root_vortex_dev; dev; dev = next) {
next = ((struct vortex_private *)dev->priv)->next_module;
if (strcmp(dev->name, node->dev_name) == 0) break;
@@ -797,9 +809,9 @@ static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
{
void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
vp = (void *)(((long)mem + 15) & ~15);
+ memset(vp, 0, sizeof(*vp));
vp->priv_addr = mem;
}
- memset(vp, 0, sizeof(*vp));
dev->priv = vp;
vp->next_module = root_vortex_dev;
@@ -1133,7 +1145,9 @@ vortex_up(struct net_device *dev)
dev->hard_start_xmit = &boomerang_start_xmit;
vp->cur_tx = vp->dirty_tx = 0;
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
- /* Clear the Tx ring. */
+ /* Clear the Rx, Tx rings. */
+ for (i = 0; i < RX_RING_SIZE; i++)
+ vp->rx_ring[i].status = 0;
for (i = 0; i < TX_RING_SIZE; i++)
vp->tx_skbuff[i] = 0;
outl(0, ioaddr + DownListPtr);
@@ -1172,6 +1186,10 @@ vortex_open(struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int i;
+#ifdef CARDBUS
+ if (vp->reap)
+ return -ENODEV;
+#endif
/* Use the now-standard shared IRQ implementation. */
if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
return -EAGAIN;
@@ -1306,6 +1324,8 @@ static void vortex_timer(unsigned long data)
vp->timer.expires = RUN_AT(next_tick);
add_timer(&vp->timer);
+ if (vp->deferred)
+ outw(FakeIntr, ioaddr + EL3_CMD);
return;
}
@@ -1431,10 +1451,10 @@ vortex_error(struct net_device *dev, int status)
dev->name, fifo_diag);
/* Adapter failure requires Tx/Rx reset and reinit. */
if (vp->full_bus_master_tx) {
+ /* In this case, blow the card away */
+ vortex_down(dev);
wait_for_completion(dev, TotalReset | 0xff);
- /* Re-enable the receiver. */
- outw(RxEnable, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
+ vortex_up(dev);
} else if (fifo_diag & 0x0400)
do_tx_reset = 1;
if (fifo_diag & 0x3000) {
@@ -1597,6 +1617,10 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
status = inw(ioaddr + EL3_STATUS);
+ if (status & IntReq) {
+ status |= vp->deferred;
+ vp->deferred = 0;
+ }
if (status == 0xffff)
goto handler_exit;
@@ -1665,19 +1689,20 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (--work_done < 0) {
- if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
- /* Just ack these and return. */
- outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD);
- } else {
- printk(KERN_WARNING "%s: Too much work in interrupt, status "
- "%4.4x. Temporarily disabling functions (%4.4x).\n",
- dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
- /* Disable all pending interrupts. */
- outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
- outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- /* The timer will reenable interrupts. */
- break;
- }
+ printk(KERN_WARNING "%s: Too much work in interrupt, status "
+ "%4.4x.\n", dev->name, status);
+ /* Disable all pending interrupts. */
+ do {
+ vp->deferred |= status;
+ outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+ ioaddr + EL3_CMD);
+ outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+ } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+ /* The timer will reenable interrupts. */
+ del_timer(&vp->timer);
+ vp->timer.expires = RUN_AT(1);
+ add_timer(&vp->timer);
+ break;
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
@@ -1758,12 +1783,8 @@ static int vortex_rx(struct net_device *dev)
printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
"size %d.\n", dev->name, pkt_len);
}
- outw(RxDiscard, ioaddr + EL3_CMD);
vp->stats.rx_dropped++;
- /* Wait a limited time to skip this packet. */
- for (i = 200; i >= 0; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, RxDiscard);
}
return 0;
@@ -2185,6 +2206,7 @@ void cleanup_module(void)
#ifdef CARDBUS
unregister_driver(&vortex_ops);
+ vortex_reap();
#endif
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 40e5a643f..e95b87104 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -4,7 +4,7 @@
Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
- 3c589_cs.c 1.137 1999/11/08 20:46:17
+ 3c589_cs.c 1.143 1999/12/30 21:28:10
The network driver code is based on Donald Becker's 3c589 code:
@@ -99,13 +99,15 @@ enum RxFilter {
#define TX_TIMEOUT ((400*HZ)/1000)
struct el3_private {
- dev_node_t node;
+ dev_link_t link;
+ struct net_device dev;
+ dev_node_t node;
struct net_device_stats stats;
/* For transceiver monitoring */
- struct timer_list media;
- u_short media_status;
- u_short fast_poll;
- u_long last_irq;
+ struct timer_list media;
+ u_short media_status;
+ u_short fast_poll;
+ u_long last_irq;
};
static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
@@ -115,7 +117,7 @@ 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 =
-"3c589_cs.c 1.137 1999/11/08 20:46:17 (David Hinds)";
+"3c589_cs.c 1.143 1999/12/30 21:28:10 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -149,7 +151,7 @@ static int el3_config(struct net_device *dev, struct ifmap *map);
static int el3_open(struct net_device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void update_stats(ioaddr_t addr, struct net_device *dev);
+static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev);
static int el3_close(struct net_device *dev);
@@ -211,6 +213,7 @@ static int tc589_init(struct net_device *dev)
static dev_link_t *tc589_attach(void)
{
+ struct el3_private *lp;
client_reg_t client_reg;
dev_link_t *link;
struct net_device *dev;
@@ -220,8 +223,12 @@ static dev_link_t *tc589_attach(void)
flush_stale_links();
/* Create new ethernet device */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp) return NULL;
+ memset(lp, 0, sizeof(*lp));
+ link = &lp->link; dev = &lp->dev;
+ link->priv = dev->priv = link->irq.Instance = lp;
+
link->release.function = &tc589_release;
link->release.data = (u_long)link;
link->io.NumPorts1 = 16;
@@ -240,25 +247,17 @@ static dev_link_t *tc589_attach(void)
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
-
- /* Make up a EL3-specific-data structure. */
- dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct el3_private));
-
/* The EL3-specific entries in the device structure. */
dev->hard_start_xmit = &el3_start_xmit;
dev->set_config = &el3_config;
dev->get_stats = &el3_get_stats;
dev->set_multicast_list = &set_multicast_list;
ether_setup(dev);
- dev->name = ((struct el3_private *)dev->priv)->node.dev_name;
+ dev->name = lp->node.dev_name;
dev->init = &tc589_init;
dev->open = &el3_open;
dev->stop = &el3_close;
dev->tbusy = 1;
- link->priv = link->irq.Instance = dev;
/* Register with Card Services */
link->next = dev_list;
@@ -293,6 +292,7 @@ static dev_link_t *tc589_attach(void)
static void tc589_detach(dev_link_t *link)
{
+ struct el3_private *lp = link->priv;
dev_link_t **linkp;
long flags;
@@ -325,15 +325,9 @@ static void tc589_detach(dev_link_t *link)
/* Unlink device structure, free bits */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&lp->dev);
+ kfree(lp);
} /* tc589_detach */
@@ -350,8 +344,9 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void tc589_config(dev_link_t *link)
{
- client_handle_t handle;
- struct net_device *dev;
+ client_handle_t handle = link->handle;
+ struct el3_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
tuple_t tuple;
cisparse_t parse;
u_short buf[32], *phys_addr;
@@ -359,12 +354,9 @@ static void tc589_config(dev_link_t *link)
ioaddr_t ioaddr;
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- handle = link->handle;
- dev = link->priv;
- phys_addr = (u_short *)dev->dev_addr;
-
DEBUG(0, "3c589_config(0x%p)\n", link);
+ phys_addr = (u_short *)dev->dev_addr;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CONFIG;
CS_CHECK(GetFirstTuple, handle, &tuple);
@@ -434,7 +426,7 @@ static void tc589_config(dev_link_t *link)
}
}
- link->dev = &((struct el3_private *)dev->priv)->node;
+ link->dev = &lp->node;
/* The address and resource configuration register aren't loaded from
the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
@@ -507,7 +499,8 @@ static int tc589_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ struct el3_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(1, "3c589_event(0x%06x)\n", event);
@@ -683,10 +676,8 @@ static int el3_config(struct net_device *dev, struct ifmap *map)
static int el3_open(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -696,14 +687,14 @@ static int el3_open(struct net_device *dev)
tc589_reset(dev);
lp->media.function = &media_check;
- lp->media.data = (u_long)dev;
+ lp->media.data = (u_long)lp;
lp->media.expires = jiffies + HZ;
add_timer(&lp->media);
DEBUG(1, "%s: opened, status %4.4x.\n",
dev->name, inw(dev->base_addr + EL3_STATUS));
- return 0; /* Always succeed */
+ return 0;
}
static void el3_tx_timeout(struct net_device *dev)
@@ -746,7 +737,6 @@ static void pop_tx_status(struct net_device *dev)
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct el3_private *lp = (struct el3_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
@@ -765,6 +755,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_NOTICE "%s: transmitter access conflict.\n",
dev->name);
else {
+ struct el3_private *lp = (struct el3_private *)dev->priv;
lp->stats.tx_bytes += skb->len;
/* Put out the doubleword header... */
outw(skb->len, ioaddr + TX_FIFO);
@@ -789,14 +780,13 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The EL3 interrupt handler. */
static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = (struct net_device *)dev_id;
- struct el3_private *lp;
+ struct el3_private *lp = dev_id;
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr, status;
int i = 0;
- if ((dev == NULL) || !dev->start)
+ if ((lp == NULL) || !dev->start)
return;
- lp = (struct el3_private *)dev->priv;
ioaddr = dev->base_addr;
#ifdef PCMCIA_DEBUG
@@ -834,7 +824,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts. */
if (status & StatsFull) /* Empty statistics. */
- update_stats(ioaddr, dev);
+ update_stats(dev);
if (status & RxEarly) { /* Rx early is unused. */
el3_rx(dev);
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
@@ -883,14 +873,14 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void media_check(u_long arg)
{
- struct net_device *dev = (struct net_device *)(arg);
- struct el3_private *lp = (struct el3_private *)dev->priv;
+ struct el3_private *lp = (struct el3_private *)(arg);
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr = dev->base_addr;
u_short media, errs;
u_long flags;
if (dev->start == 0) goto reschedule;
-
+
EL3WINDOW(1);
/* Check for pending interrupt with expired latency timer: with
this, we can limp along even if the interrupt is blocked */
@@ -898,7 +888,7 @@ static void media_check(u_long arg)
(inb(ioaddr + EL3_TIMER) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, dev, NULL);
+ el3_interrupt(dev->irq, lp, NULL);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
@@ -965,14 +955,12 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
unsigned long flags;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (DEV_OK(link)) {
save_flags(flags);
cli();
- update_stats(dev->base_addr, dev);
+ update_stats(dev);
restore_flags(flags);
}
return &lp->stats;
@@ -984,10 +972,11 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
operation, and it's simpler for the rest of the driver to assume that
window 1 is always valid rather than use a special window-state variable.
*/
-static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
+static void update_stats(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
-
+ ioaddr_t ioaddr = dev->base_addr;
+
DEBUG(2, "%s: updating the statistics.\n", dev->name);
/* Turn off statistics updates while reading. */
outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1002,8 +991,8 @@ static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
lp->stats.tx_packets += inb(ioaddr + 6);
/* Rx packets */ inb(ioaddr + 7);
/* Tx deferrals */ inb(ioaddr + 8);
- inw(ioaddr + 10); /* Total Rx and Tx octets. */
- inw(ioaddr + 12);
+ /* Rx octets */ inw(ioaddr + 10);
+ /* Tx octets */ inw(ioaddr + 12);
/* Back to window 1, and turn statistics back on. */
EL3WINDOW(1);
@@ -1025,12 +1014,12 @@ static int el3_rx(struct net_device *dev)
short error = rx_status & 0x3800;
lp->stats.rx_errors++;
switch (error) {
- case 0x0000: lp->stats.rx_over_errors++; break;
- case 0x0800: lp->stats.rx_length_errors++; break;
- case 0x1000: lp->stats.rx_frame_errors++; break;
- case 0x1800: lp->stats.rx_length_errors++; break;
- case 0x2000: lp->stats.rx_frame_errors++; break;
- case 0x2800: lp->stats.rx_crc_errors++; break;
+ case 0x0000: lp->stats.rx_over_errors++; break;
+ case 0x0800: lp->stats.rx_length_errors++; break;
+ case 0x1000: lp->stats.rx_frame_errors++; break;
+ case 0x1800: lp->stats.rx_length_errors++; break;
+ case 0x2000: lp->stats.rx_frame_errors++; break;
+ case 0x2800: lp->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
@@ -1073,10 +1062,10 @@ static int el3_rx(struct net_device *dev)
*/
static void set_multicast_list(struct net_device *dev)
{
+ struct el3_private *lp = dev->priv;
+ dev_link_t *link = &lp->link;
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
+
if (!(DEV_OK(link))) return;
#ifdef PCMCIA_DEBUG
if (pc_debug > 2) {
@@ -1099,13 +1088,9 @@ static void set_multicast_list(struct net_device *dev)
static int el3_close(struct net_device *dev)
{
+ struct el3_private *lp = dev->priv;
+ dev_link_t *link = &lp->link;
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
-
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
@@ -1133,12 +1118,12 @@ static int el3_close(struct net_device *dev)
/* Check if the card still exists */
if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
- update_stats(ioaddr, dev);
+ update_stats(dev);
}
link->open--;
dev->start = 0;
- del_timer(&((struct el3_private *)dev->priv)->media);
+ del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 243b5c896..be83dc205 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -31,6 +31,8 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
fi
fi
+endmenu
+
if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \
"$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \
"$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \
@@ -38,5 +40,3 @@ if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \
"$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then
define_bool CONFIG_PCMCIA_NETCARD y
fi
-
-endmenu
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 82e3ce57a..9dd2c188e 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -69,16 +69,6 @@ MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...)
#endif
-/*
- For debugging this driver you may need more information.
- To enable printing registers or status, set 'fmvj18x_debug=#' option .
- */
-#ifdef FMVJ18X_DEBUG
-static int fmvj18x_debug = FMVJ18X_DEBUG;
-#else
-static int fmvj18x_debug = 2;
-#endif /* FMVJ18X_DEBUG */
-
/* Bit map of interrupts to choose from */
/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
static u_int irq_mask = 0xdeb8;
@@ -138,6 +128,8 @@ typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501 } cardtype_t;
driver specific data structure
*/
typedef struct local_info_t {
+ dev_link_t link;
+ struct net_device dev;
dev_node_t node;
struct net_device_stats stats;
long open_time;
@@ -273,17 +265,21 @@ static void cs_error(client_handle_t handle, int func, int ret)
static dev_link_t *fmvj18x_attach(void)
{
- client_reg_t client_reg;
+ local_info_t *lp;
dev_link_t *link;
struct net_device *dev;
+ client_reg_t client_reg;
int i, ret;
DEBUG(0, "fmvj18x_attach()\n");
flush_stale_links();
- /* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ /* Make up a FMVJ18x specific data structure */
+ lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp) return NULL;
+ memset(lp, 0, sizeof(*lp));
+ link = &lp->link; dev = &lp->dev;
+ link->priv = dev->priv = link->irq.Instance = lp;
link->release.function = &fmvj18x_release;
link->release.data = (u_long)link;
@@ -308,24 +304,17 @@ static dev_link_t *fmvj18x_attach(void)
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
- /* Make up a FMVJ18x specific data structure */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
- dev->priv = kmalloc(sizeof(local_info_t), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(local_info_t));
-
/* The FMVJ18x specific entries in the device structure. */
dev->hard_start_xmit = &fjn_start_xmit;
dev->set_config = &fjn_config;
dev->get_stats = &fjn_get_stats;
dev->set_multicast_list = &set_rx_mode;
ether_setup(dev);
- dev->name = ((local_info_t *)dev->priv)->node.dev_name;
+ dev->name = lp->node.dev_name;
dev->init = &fmvj18x_init;
dev->open = &fjn_open;
dev->stop = &fjn_close;
dev->tbusy = 0xFF;
- link->priv = link->irq.Instance = dev;
/* Register with Card Services */
link->next = dev_list;
@@ -353,6 +342,7 @@ static dev_link_t *fmvj18x_attach(void)
static void fmvj18x_detach(dev_link_t *link)
{
+ local_info_t *lp = link->priv;
dev_link_t **linkp;
long flags;
@@ -386,15 +376,9 @@ static void fmvj18x_detach(dev_link_t *link)
/* Unlink device structure, free pieces */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(dev);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&lp->dev);
+ kfree(lp);
} /* fmvj18x_detach */
@@ -405,10 +389,11 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void fmvj18x_config(dev_link_t *link)
{
- client_handle_t handle;
+ client_handle_t handle = link->handle;
+ local_info_t *lp = link->priv;
+ struct net_device *dev = &lp->dev;
tuple_t tuple;
cisparse_t parse;
- struct net_device *dev;
u_short buf[32];
int i, last_fn, last_ret;
ioaddr_t ioaddr;
@@ -416,9 +401,6 @@ static void fmvj18x_config(dev_link_t *link)
char *card_name = "unknown";
u_char *node_id;
- handle = link->handle;
- dev =link->priv;
-
DEBUG(0, "fmvj18x_config(0x%p)\n", link);
/*
@@ -538,10 +520,10 @@ static void fmvj18x_config(dev_link_t *link)
break;
}
- link->dev = &((local_info_t *)dev->priv)->node;
+ link->dev = &lp->node;
link->state &= ~DEV_CONFIG_PENDING;
- ((struct local_info_t *)dev->priv)->cardtype = cardtype ;
+ lp->cardtype = cardtype;
/* print current configuration */
printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ",
dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
@@ -594,7 +576,8 @@ static int fmvj18x_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ local_info_t *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(1, "fmvj18x_event(0x%06x)\n", event);
@@ -677,12 +660,12 @@ module_exit(exit_fmvj18x_cs);
static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ local_info_t *lp = dev_id;
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr;
- local_info_t *lp;
unsigned short tx_stat, rx_stat;
- if (dev == NULL) {
+ if (lp == NULL) {
printk(KERN_NOTICE "fjn_interrupt(): irq %d for "
"unknown device.\n", irq);
return;
@@ -693,7 +676,6 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
dev->interrupt = 1;
- lp = (struct local_info_t *)dev->priv;
ioaddr = dev->base_addr;
/* avoid multiple interrupts */
@@ -710,12 +692,8 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outb(tx_stat, ioaddr + TX_STATUS);
outb(rx_stat, ioaddr + RX_STATUS);
- if (fmvj18x_debug > 4) {
- printk(KERN_DEBUG "%s: interrupt, rx_status %02x.\n",
- dev->name, rx_stat);
- printk(KERN_DEBUG " tx_status %02x.\n",
- tx_stat);
- }
+ DEBUG(4, "%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
+ DEBUG(4, " tx_status %02x.\n", tx_stat);
if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
/* there is packet(s) in rx buffer */
@@ -738,11 +716,8 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mark_bh(NET_BH); /* Inform upper layers. */
}
}
- if (fmvj18x_debug > 4) {
- printk(KERN_DEBUG "%s: exiting interrupt,\n", dev->name);
- printk(KERN_DEBUG " tx_status %02x, rx_status %02x.\n",
- tx_stat, rx_stat);
- }
+ DEBUG(4, "%s: exiting interrupt,\n", dev->name);
+ DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
dev->interrupt = 0;
outb(D_TX_INTR, ioaddr + TX_INTR);
@@ -802,15 +777,13 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned char *buf = skb->data;
if (length > ETH_FRAME_LEN) {
- if (fmvj18x_debug)
- printk(KERN_NOTICE "%s: Attempting to send a large packet"
- " (%d bytes).\n", dev->name, length);
+ printk(KERN_NOTICE "%s: Attempting to send a large packet"
+ " (%d bytes).\n", dev->name, length);
return 1;
}
- if (fmvj18x_debug > 4)
- printk(KERN_DEBUG "%s: Transmitting a packet of length %lu.\n",
- dev->name, (unsigned long)skb->len);
+ DEBUG(4, "%s: Transmitting a packet of length %lu.\n",
+ dev->name, (unsigned long)skb->len);
lp->stats.tx_bytes += skb->len;
/* Disable both interrupts. */
@@ -864,9 +837,7 @@ static void fjn_reset(struct net_device *dev)
ioaddr_t ioaddr = dev->base_addr;
int i;
- if (fmvj18x_debug > 4) {
- printk(KERN_DEBUG "fjn_reset(%s) called.\n",dev->name);
- }
+ DEBUG(4, "fjn_reset(%s) called.\n",dev->name);
/* Power On chip and select bank 0 */
outb(BANK_0, ioaddr + CONFIG_1);
@@ -885,12 +856,6 @@ static void fjn_reset(struct net_device *dev)
for (i = 0; i < 6; i++)
outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
- if (fmvj18x_debug > 4) {
- printk(KERN_DEBUG "node id: ");
- for (i = 0; i < 6; i++)
- printk("%02X ",inb(ioaddr + NODE_ID + i));
- printk("\n");
- }
/* Switch to bank 1 */
outb(BANK_1, ioaddr + CONFIG_1);
@@ -948,16 +913,14 @@ static void fjn_rx(struct net_device *dev)
ioaddr_t ioaddr = dev->base_addr;
int boguscount = 10; /* 5 -> 10: by agy 19940922 */
- if (fmvj18x_debug > 4)
- printk(KERN_DEBUG "%s: in rx_packet(), rx_status %02x.\n",
- dev->name, inb(ioaddr + RX_STATUS));
+ DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n",
+ dev->name, inb(ioaddr + RX_STATUS));
while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
u_short status = inw(ioaddr + DATAPORT);
- if (fmvj18x_debug > 4)
- printk(KERN_DEBUG "%s: Rxing packet mode %02x status %04x.\n",
- dev->name, inb(ioaddr + RX_MODE), status);
+ DEBUG(4, "%s: Rxing packet mode %02x status %04x.\n",
+ dev->name, inb(ioaddr + RX_MODE), status);
#ifndef final_version
if (status == 0) {
outb(F_SKP_PKT, ioaddr + RX_SKIP);
@@ -997,7 +960,8 @@ static void fjn_rx(struct net_device *dev)
(pkt_len + 1) >> 1);
skb->protocol = eth_type_trans(skb, dev);
- if (fmvj18x_debug > 5) {
+#ifdef PCMCIA_DEBUG
+ if (pc_debug > 5) {
int i;
printk(KERN_DEBUG "%s: Rxed packet of length %d: ",
dev->name, pkt_len);
@@ -1005,6 +969,7 @@ static void fjn_rx(struct net_device *dev)
printk(" %02x", skb->data[i]);
printk(".\n");
}
+#endif
netif_rx(skb);
lp->stats.rx_packets++;
@@ -1027,9 +992,9 @@ static void fjn_rx(struct net_device *dev)
outb(F_SKP_PKT, ioaddr + RX_SKIP);
}
- if (fmvj18x_debug > 5 && i > 0)
- printk(KERN_DEBUG "%s: Exint Rx packet with mode %02x after"
- " %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
+ if (i > 0)
+ DEBUG(5, "%s: Exint Rx packet with mode %02x after "
+ "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
}
*/
@@ -1040,18 +1005,15 @@ static void fjn_rx(struct net_device *dev)
static int fjn_config(struct net_device *dev, struct ifmap *map){
return 0;
-} /* fjn_config */
+}
static int fjn_open(struct net_device *dev)
{
struct local_info_t *lp = (struct local_info_t *)dev->priv;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
- if (fmvj18x_debug > 4)
- printk(KERN_DEBUG "fjn_open('%s').\n", dev->name);
+ DEBUG(4, "fjn_open('%s').\n", dev->name);
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -1076,23 +1038,13 @@ static int fjn_open(struct net_device *dev)
static int fjn_close(struct net_device *dev)
{
- ioaddr_t ioaddr = dev->base_addr;
struct local_info_t *lp = (struct local_info_t *)dev->priv;
- dev_link_t *link;
-
- if (fmvj18x_debug > 4)
- printk(KERN_DEBUG "fjn_open('%s').\n", dev->name);
-
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
-
- if (fmvj18x_debug > 2)
- printk(KERN_DEBUG "%s: shutting down ethercard.\n", dev->name);
+ dev_link_t *link = &lp->link;
+ ioaddr_t ioaddr = dev->base_addr;
- ((struct local_info_t *)dev->priv)->open_time = 0;
+ DEBUG(4, "fjn_close('%s').\n", dev->name);
+ lp->open_time = 0;
dev->tbusy = 1;
dev->start = 0;
@@ -1109,7 +1061,7 @@ static int fjn_close(struct net_device *dev)
/* Set the ethernet adaptor disable IRQ */
if( lp->cardtype != TDK )
- outb(INTR_OFF, ioaddr + LAN_CTRL);
+ outb(INTR_OFF, ioaddr + LAN_CTRL);
link->open--;
dev->start = 0;
diff --git a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/pcmcia/netwave_cs.c
index 6ca0ce297..74928fd27 100644
--- a/drivers/net/pcmcia/netwave_cs.c
+++ b/drivers/net/pcmcia/netwave_cs.c
@@ -302,6 +302,8 @@ struct site_survey {
};
typedef struct netwave_private {
+ dev_link_t link;
+ struct net_device dev;
dev_node_t node;
u_char *ramBase;
int timeoutCounter;
@@ -440,7 +442,7 @@ static dev_link_t *netwave_attach(void)
client_reg_t client_reg;
dev_link_t *link;
struct net_device *dev;
- netwave_private *priv;
+ netwave_private *priv;
int i, ret;
DEBUG(0, "netwave_attach()\n");
@@ -449,8 +451,11 @@ static dev_link_t *netwave_attach(void)
netwave_flush_stale_links();
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) return NULL;
+ memset(priv, 0, sizeof(*priv));
+ link = &priv->link; dev = &priv->dev;
+ link->priv = dev->priv = priv;
link->release.function = &netwave_release;
link->release.data = (u_long)link;
@@ -478,15 +483,7 @@ static dev_link_t *netwave_attach(void)
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
- /* Allocate space for private device-specific data */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
-
- dev->priv = kmalloc(sizeof(netwave_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(netwave_private));
-
/* Set the watchdog timer */
- priv = (netwave_private *) dev->priv;
priv->watchdog.function = &netwave_watchdog;
priv->watchdog.data = (unsigned long) dev;
@@ -502,12 +499,12 @@ static dev_link_t *netwave_attach(void)
dev->do_ioctl = &netwave_ioctl;
ether_setup(dev);
- dev->name = ((struct netwave_private *)dev->priv)->node.dev_name;
+ dev->name = priv->node.dev_name;
dev->init = &netwave_init;
dev->open = &netwave_open;
dev->stop = &netwave_close;
dev->tbusy = 1;
- link->priv = link->irq.Instance = dev;
+ link->irq.Instance = dev;
/* Register with Card Services */
link->next = dev_list;
@@ -541,6 +538,7 @@ static dev_link_t *netwave_attach(void)
*/
static void netwave_detach(dev_link_t *link)
{
+ netwave_private *priv = link->priv;
dev_link_t **linkp;
long flags;
@@ -587,16 +585,9 @@ static void netwave_detach(dev_link_t *link)
/* Unlink device structure, free pieces */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- link->dev = NULL;
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&priv->dev);
+ kfree(priv);
} /* netwave_detach */
@@ -633,8 +624,8 @@ static void netwave_flush_stale_links(void)
*
*/
static int netwave_ioctl(struct net_device *dev, /* ioctl device */
- struct ifreq *rq, /* Data passed */
- int cmd) /* Ioctl number */
+ struct ifreq *rq, /* Data passed */
+ int cmd) /* Ioctl number */
{
unsigned long flags;
int ret = 0;
@@ -839,20 +830,16 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void netwave_pcmcia_config(dev_link_t *link) {
- client_handle_t handle;
+ client_handle_t handle = link->handle;
+ netwave_private *priv = link->priv;
+ struct net_device *dev = &priv->dev;
tuple_t tuple;
cisparse_t parse;
- struct net_device *dev;
int i, j, last_ret, last_fn;
u_char buf[64];
win_req_t req;
memreq_t mem;
u_char *ramBase = NULL;
- /* modwin_t mod;
- short iobase, *phys_addr;
- */
- handle = link->handle;
- dev = link->priv;
DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
@@ -969,7 +956,7 @@ failed:
*/
static void netwave_release(u_long arg) {
dev_link_t *link = (dev_link_t *)arg;
- struct net_device *dev = link->priv;
+ netwave_private *priv = link->priv;
DEBUG(0, "netwave_release(0x%p)\n", link);
@@ -986,7 +973,7 @@ static void netwave_release(u_long arg) {
/* Don't bother checking to see if these succeed or not */
if (link->win) {
- iounmap(((netwave_private *)dev->priv)->ramBase);
+ iounmap(priv->ramBase);
CardServices(ReleaseWindow, link->win);
}
CardServices(ReleaseConfiguration, link->handle);
@@ -1014,7 +1001,8 @@ static void netwave_release(u_long arg) {
static int netwave_event(event_t event, int priority,
event_callback_args_t *args) {
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ netwave_private *priv = link->priv;
+ struct net_device *dev = &priv->dev;
DEBUG(1, "netwave_event(0x%06x)\n", event);
@@ -1027,7 +1015,6 @@ static int netwave_event(event_t event, int priority,
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
dev->tbusy = 1; dev->start = 0;
- /* ((netwave_private *)link->priv)->block = 1; */
link->release.expires = jiffies + 5;
add_timer(&link->release);
}
@@ -1312,24 +1299,18 @@ static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
ioaddr_t iobase;
u_char *ramBase;
struct net_device *dev = (struct net_device *)dev_id;
- struct netwave_private *priv;
+ struct netwave_private *priv = dev->priv;
+ dev_link_t *link = &priv->link;
int i;
- dev_link_t *link;
-
- if ((dev == NULL) | (!dev->start))
- return;
- priv = (netwave_private *)dev->priv;
+ if ((dev == NULL) | (!dev->start))
+ return;
if (dev->interrupt) {
printk("%s: re-entering the interrupt handler.\n", dev->name);
return;
}
dev->interrupt = 1;
-
- /* Find the correct dev_link_t */
- for (link = dev_list; NULL != link; link = link->next)
- if (dev == link->priv) break;
iobase = dev->base_addr;
ramBase = priv->ramBase;
@@ -1592,12 +1573,10 @@ static int netwave_rx(struct net_device *dev) {
}
static int netwave_open(struct net_device *dev) {
- dev_link_t *link;
+ netwave_private *priv = dev->priv;
+ dev_link_t *link = &priv->link;
DEBUG(1, "netwave_open: starting.\n");
-
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -1612,16 +1591,11 @@ static int netwave_open(struct net_device *dev) {
}
static int netwave_close(struct net_device *dev) {
- dev_link_t *link;
- netwave_private *priv = (netwave_private *) dev->priv;
+ netwave_private *priv = (netwave_private *)dev->priv;
+ dev_link_t *link = &priv->link;
DEBUG(1, "netwave_close: finishing.\n");
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
-
/* If watchdog was activated, kill it ! */
del_timer(&priv->watchdog);
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 2dd6a369b..2fb3772a5 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -312,61 +312,63 @@ Type Definitions
---------------------------------------------------------------------------- */
typedef struct _mace_statistics {
- /* MACE_XMTFS */
- int xmtsv;
- int uflo;
- int lcol;
- int more;
- int one;
- int defer;
- int lcar;
- int rtry;
-
- /* MACE_XMTRC */
- int exdef;
- int xmtrc;
-
- /* RFS1--Receive Status (RCVSTS) */
- int oflo;
- int clsn;
- int fram;
- int fcs;
-
- /* RFS2--Runt Packet Count (RNTPC) */
- int rfs_rntpc;
-
- /* RFS3--Receive Collision Count (RCVCC) */
- int rfs_rcvcc;
-
- /* MACE_IR */
- int jab;
- int babl;
- int cerr;
- int rcvcco;
- int rntpco;
- int mpco;
-
- /* MACE_MPC */
- int mpc;
-
- /* MACE_RNTPC */
- int rntpc;
-
- /* MACE_RCVCC */
- int rcvcc;
+ /* MACE_XMTFS */
+ int xmtsv;
+ int uflo;
+ int lcol;
+ int more;
+ int one;
+ int defer;
+ int lcar;
+ int rtry;
+
+ /* MACE_XMTRC */
+ int exdef;
+ int xmtrc;
+
+ /* RFS1--Receive Status (RCVSTS) */
+ int oflo;
+ int clsn;
+ int fram;
+ int fcs;
+
+ /* RFS2--Runt Packet Count (RNTPC) */
+ int rfs_rntpc;
+
+ /* RFS3--Receive Collision Count (RCVCC) */
+ int rfs_rcvcc;
+
+ /* MACE_IR */
+ int jab;
+ int babl;
+ int cerr;
+ int rcvcco;
+ int rntpco;
+ int mpco;
+
+ /* MACE_MPC */
+ int mpc;
+
+ /* MACE_RNTPC */
+ int rntpc;
+
+ /* MACE_RCVCC */
+ int rcvcc;
} mace_statistics;
typedef struct _mace_private {
- dev_node_t node;
- struct net_device_stats linux_stats; /* Linux statistics counters */
- mace_statistics mace_stats; /* MACE chip statistics counters */
-
- /* restore_multicast_list() state variables */
- int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */
- int multicast_num_addrs;
-
- char tx_free_frames; /* Number of free transmit frame buffers */
- char tx_irq_disabled; /* MACE TX interrupt disabled */
+ dev_link_t link;
+ struct net_device dev;
+ dev_node_t node;
+ struct net_device_stats linux_stats; /* Linux statistics counters */
+ mace_statistics mace_stats; /* MACE chip statistics counters */
+
+ /* restore_multicast_list() state variables */
+ int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */
+ int multicast_num_addrs;
+
+ char tx_free_frames; /* Number of free transmit frame buffers */
+ char tx_irq_disabled; /* MACE TX interrupt disabled */
} mace_private;
/* ----------------------------------------------------------------------------
@@ -384,9 +386,7 @@ static dev_info_t dev_info="nmclan_cs";
static dev_link_t *dev_list=NULL;
static char *if_names[]={
- "Auto",
- "10baseT",
- "BNC",
+ "Auto", "10baseT", "BNC",
};
#ifdef PCMCIA_DEBUG
@@ -403,12 +403,8 @@ Parameters
'insmod'.
---------------------------------------------------------------------------- */
-static int if_port=0; /* default=auto */
- /*
- * 0=auto
- * 1=10base-T (twisted pair)
- * 2=10base-2 (BNC)
- */
+/* 0=auto, 1=10baseT, 2 = 10base2, default=auto */
+static int if_port=0;
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xdeb8;
@@ -425,7 +421,7 @@ Function Prototypes
static void nmclan_config(dev_link_t *link);
static void nmclan_release(u_long arg);
static int nmclan_event(event_t event, int priority,
- event_callback_args_t *args);
+ event_callback_args_t *args);
static void nmclan_reset(struct net_device *dev);
static int mace_config(struct net_device *dev, struct ifmap *map);
@@ -473,10 +469,11 @@ nmclan_init
We never need to do anything when a nmclan device is "initialized"
by the net software, because we only register already-found cards.
---------------------------------------------------------------------------- */
+
static int nmclan_init(struct net_device *dev)
{
- return 0;
-} /* nmclan_init */
+ return 0;
+}
/* ----------------------------------------------------------------------------
nmclan_attach
@@ -484,79 +481,78 @@ nmclan_attach
structures for one device. The device is registered with Card
Services.
---------------------------------------------------------------------------- */
+
static dev_link_t *nmclan_attach(void)
{
- client_reg_t client_reg;
- dev_link_t *link;
- struct net_device *dev;
- int i, ret;
-
- DEBUG(0, "nmclan_attach()\n");
- DEBUG(1, "%s\n", rcsid);
- flush_stale_links();
-
- /* Create new ethernet device */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
- link->release.function = &nmclan_release;
- link->release.data = (u_long)link;
- link->io.NumPorts1 = 32;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 5;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
- link->irq.Handler = &mace_interrupt;
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Vcc = 50;
- link->conf.IntType = INT_MEMORY_AND_IO;
- link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
-
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
-
- /* Allocate private data area for this device. */
- dev->priv = kmalloc(sizeof(mace_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(mace_private));
- ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
-
- dev->hard_start_xmit = &mace_start_xmit;
- dev->set_config = &mace_config;
- dev->get_stats = &mace_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- ether_setup(dev);
- dev->name = ((mace_private *)dev->priv)->node.dev_name;
- dev->init = &nmclan_init;
- dev->open = &mace_open;
- dev->stop = &mace_close;
- dev->tbusy = 0xFF;
- link->priv = link->irq.Instance = dev;
-
- /* Register with Card Services */
- link->next = dev_list;
- dev_list = link;
- client_reg.dev_info = &dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &nmclan_event;
- 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);
- nmclan_detach(link);
- return NULL;
- }
+ mace_private *lp;
+ dev_link_t *link;
+ struct net_device *dev;
+ client_reg_t client_reg;
+ int i, ret;
+
+ DEBUG(0, "nmclan_attach()\n");
+ DEBUG(1, "%s\n", rcsid);
+ flush_stale_links();
+
+ /* Create new ethernet device */
+ lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp) return NULL;
+ memset(lp, 0, sizeof(*lp));
+ link = &lp->link; dev = &lp->dev;
+ link->priv = dev->priv = link->irq.Instance = lp;
+
+ link->release.function = &nmclan_release;
+ link->release.data = (u_long)link;
+ link->io.NumPorts1 = 32;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 5;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.Handler = &mace_interrupt;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 1;
+ link->conf.Present = PRESENT_OPTION;
+
+ lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+ dev->hard_start_xmit = &mace_start_xmit;
+ dev->set_config = &mace_config;
+ dev->get_stats = &mace_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ ether_setup(dev);
+ dev->name = lp->node.dev_name;
+ dev->init = &nmclan_init;
+ dev->open = &mace_open;
+ dev->stop = &mace_close;
+ dev->tbusy = 0xFF;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &nmclan_event;
+ 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);
+ nmclan_detach(link);
+ return NULL;
+ }
- return link;
+ return link;
} /* nmclan_attach */
/* ----------------------------------------------------------------------------
@@ -566,40 +562,36 @@ nmclan_detach
structures are freed. Otherwise, the structures will be freed
when the device is released.
---------------------------------------------------------------------------- */
+
static void nmclan_detach(dev_link_t *link)
{
- dev_link_t **linkp;
-
- DEBUG(0, "nmclan_detach(0x%p)\n", link);
-
- /* Locate device structure */
- for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) break;
- if (*linkp == NULL)
- return;
-
- if (link->state & DEV_CONFIG) {
- nmclan_release((u_long)link);
- if (link->state & DEV_STALE_CONFIG) {
- link->state |= DEV_STALE_LINK;
- return;
+ mace_private *lp = link->priv;
+ dev_link_t **linkp;
+
+ DEBUG(0, "nmclan_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ nmclan_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
}
- }
- if (link->handle)
- CardServices(DeregisterClient, link->handle);
-
- /* Unlink device structure, free bits */
- *linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ if (link->dev)
+ unregister_netdev(&lp->dev);
+ kfree(lp);
} /* nmclan_detach */
@@ -731,18 +723,14 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void nmclan_config(dev_link_t *link)
{
- client_handle_t handle;
- struct net_device *dev;
+ client_handle_t handle = link->handle;
+ mace_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[64];
int i, last_ret, last_fn;
ioaddr_t ioaddr;
- u_short *phys_addr;
-
- handle = link->handle;
- dev = link->priv;
- phys_addr = (u_short *)dev->dev_addr;
DEBUG(0, "nmclan_config(0x%p)\n", link);
@@ -770,7 +758,7 @@ static void nmclan_config(dev_link_t *link)
printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
goto failed;
}
-
+
ioaddr = dev->base_addr;
/* Read the ethernet address from the CIS. */
@@ -807,9 +795,9 @@ static void nmclan_config(dev_link_t *link)
else
printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
- link->dev = &((mace_private *)dev->priv)->node;
+ link->dev = &lp->node;
link->state &= ~DEV_CONFIG_PENDING;
-
+
printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
for (i = 0; i < 6; i++)
@@ -821,7 +809,7 @@ cs_failed:
failed:
nmclan_release((u_long)link);
return;
-
+
} /* nmclan_config */
/* ----------------------------------------------------------------------------
@@ -862,10 +850,11 @@ static int nmclan_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ mace_private *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(1, "nmclan_event(0x%06x)\n", event);
-
+
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
@@ -918,20 +907,13 @@ nmclan_reset
---------------------------------------------------------------------------- */
static void nmclan_reset(struct net_device *dev)
{
+ mace_private *lp = dev->priv;
#if RESET_XILINX
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
conf_reg_t reg;
u_long OrigCorValue;
- /* Find our client handle. */
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL) {
- printk(KERN_NOTICE "nmclan_cs: bad device pointer!\n");
- return;
- }
-
/* Save original COR value */
reg.Function = 0;
reg.Action = CS_READ;
@@ -953,13 +935,13 @@ static void nmclan_reset(struct net_device *dev)
reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK);
CardServices(AccessConfigurationRegister, link->handle, &reg);
/* Xilinx is now completely reset along with the MACE chip. */
- ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
+ lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
#endif /* #if RESET_XILINX */
/* Xilinx is now completely reset along with the MACE chip. */
- ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
-
+ lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
/* Reinitialize the MACE chip for operation. */
mace_init(dev->base_addr, dev->dev_addr);
mace_write(dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT);
@@ -981,9 +963,8 @@ static int mace_config(struct net_device *dev, struct ifmap *map)
dev->if_port = map->port;
printk(KERN_INFO "%s: switched to %s port\n", dev->name,
if_names[dev->if_port]);
- }
- else
- return -EINVAL;
+ } else
+ return -EINVAL;
}
return 0;
} /* mace_config */
@@ -995,10 +976,9 @@ mace_open
static int mace_open(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
+ mace_private *lp = dev->priv;
+ dev_link_t *link = &lp->link;
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -1023,15 +1003,11 @@ mace_close
static int mace_close(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
-
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
+ mace_private *lp = dev->priv;
+ dev_link_t *link = &lp->link;
DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
-
+
/* Mask off all interrupts from the MACE chip. */
outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
@@ -1062,7 +1038,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
mace_private *lp = (mace_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
#if TIMEOUT_TX
/* Transmitter timeout. */
@@ -1074,10 +1050,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
#if RESET_ON_TIMEOUT
printk("resetting card\n");
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link)
- CardServices(ResetCard, link->handle);
+ CardServices(ResetCard, link->handle);
#else /* #if RESET_ON_TIMEOUT */
printk("NOT resetting card\n");
#endif /* #if RESET_ON_TIMEOUT */
@@ -1091,7 +1064,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
dev->name, (long)skb->len);
-
+
/* Avoid timer-based retransmission conflicts. */
if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) {
printk(KERN_NOTICE "%s: transmitter access conflict.\n",
@@ -1146,7 +1119,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif /* #if (!TX_INTERRUPTABLE) */
dev_kfree_skb(skb);
-
+
return 0;
} /* mace_start_xmit */
@@ -1156,8 +1129,8 @@ mace_interrupt
---------------------------------------------------------------------------- */
static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = (struct net_device *)dev_id;
- mace_private *lp = (mace_private *)dev->priv;
+ mace_private *lp = (mace_private *)dev_id;
+ struct net_device *dev = &lp->dev;
ioaddr_t ioaddr = dev->base_addr;
int status;
int IntrCnt = MACE_MAX_IR_ITERATIONS;
@@ -1169,7 +1142,6 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (dev->interrupt || lp->tx_irq_disabled) {
- sti();
printk(
(lp->tx_irq_disabled?
KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
@@ -1184,7 +1156,6 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
dev->interrupt = 1;
- sti();
if (dev->start == 0) {
DEBUG(2, "%s: interrupt from dead card\n", dev->name);
@@ -1194,7 +1165,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do {
/* WARNING: MACE_IR is a READ/CLEAR port! */
status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
-
+
DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
if (status & MACE_IR_RCVINT) {
@@ -1346,9 +1317,9 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt)
DEBUG(3, " receiving packet size 0x%X rx_status"
" 0x%X.\n", pkt_len, rx_status);
-
+
skb = dev_alloc_skb(pkt_len+2);
-
+
if (skb != NULL) {
skb->dev = dev;
@@ -1425,7 +1396,7 @@ static void pr_mace_stats(mace_statistics *pstats)
/* MACE_XMTRC */
DEBUG(2, " exdef=%-7d xmtrc=%d\n",
pstats->exdef, pstats->xmtrc);
-
+
/* RFS1--Receive Status (RCVSTS) */
DEBUG(2, " oflo=%-7d clsn=%d\n",
pstats->oflo, pstats->clsn);
@@ -1472,7 +1443,7 @@ update_stats
static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
{
mace_private *lp = (mace_private *)dev->priv;
-
+
lp->mace_stats.rcvcc += mace_read(ioaddr, MACE_RCVCC);
lp->mace_stats.rntpc += mace_read(ioaddr, MACE_RNTPC);
lp->mace_stats.mpc += mace_read(ioaddr, MACE_MPC);
@@ -1711,7 +1682,7 @@ static void restore_multicast_list(struct net_device *dev)
DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name,
((mace_private *)(dev->priv))->multicast_num_addrs);
-
+
if (dev->flags & IFF_PROMISC) {
/* Promiscuous mode: receive all packets */
mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
@@ -1768,10 +1739,10 @@ exit_nmclan_cs
static void __exit exit_nmclan_cs(void)
{
- DEBUG(0, "nmclan_cs: unloading\n");
- unregister_pccard_driver(&dev_info);
- while (dev_list != NULL)
- nmclan_detach(dev_list);
+ DEBUG(0, "nmclan_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ nmclan_detach(dev_list);
}
module_init(init_nmclan_cs);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index cefdf91be..575a91271 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -11,7 +11,7 @@
Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
- pcnet_cs.c 1.106 1999/11/09 21:53:13
+ pcnet_cs.c 1.110 1999/12/06 21:39:18
The network driver code is based on Donald Becker's NE2000 code:
@@ -72,7 +72,7 @@ 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 =
-"pcnet_cs.c 1.106 1999/11/09 21:53:13 (David Hinds)";
+"pcnet_cs.c 1.110 1999/12/06 21:39:18 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -122,26 +122,21 @@ static void pcnet_config(dev_link_t *link);
static void pcnet_release(u_long arg);
static int pcnet_event(event_t event, int priority,
event_callback_args_t *args);
-
static int pcnet_open(struct net_device *dev);
static int pcnet_close(struct net_device *dev);
static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
static void ei_watchdog(u_long arg);
-
static void pcnet_reset_8390(struct net_device *dev);
-
static int set_config(struct net_device *dev, struct ifmap *map);
-
static int setup_shmem_window(dev_link_t *link, int start_pg,
int stop_pg, int cm_offset);
static int setup_dma_config(dev_link_t *link, int start_pg,
int stop_pg);
-static dev_info_t dev_info = "pcnet_cs";
-
static dev_link_t *pcnet_attach(void);
static void pcnet_detach(dev_link_t *);
+static dev_info_t dev_info = "pcnet_cs";
static dev_link_t *dev_list;
/*====================================================================*/
@@ -215,7 +210,8 @@ static hw_info_t hw_info[] = {
{ /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
{ /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
- { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }
+ { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
+ { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 }
};
#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
@@ -226,12 +222,13 @@ static hw_info_t dl_fast_info =
{ /* D-Link EtherFast */ 0x00, 0x00, 0x00, 0x00, IS_DL10019A };
typedef struct pcnet_dev_t {
- struct net_device dev;
+ struct net_device dev; /* so &dev == &pcnet_dev_t */
+ dev_link_t link;
dev_node_t node;
u_long flags;
caddr_t base;
struct timer_list watchdog;
- int stale, link;
+ int stale, state;
u_short fast_poll;
} pcnet_dev_t;
@@ -283,18 +280,22 @@ static int pcnet_init(struct net_device *dev)
static dev_link_t *pcnet_attach(void)
{
- client_reg_t client_reg;
- dev_link_t *link;
pcnet_dev_t *info;
+ dev_link_t *link;
struct net_device *dev;
+ client_reg_t client_reg;
int i, ret;
DEBUG(0, "pcnet_attach()\n");
flush_stale_links();
/* Create new ethernet device */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; dev = &info->dev;
+ link->priv = info;
+
link->release.function = &pcnet_release;
link->release.data = (u_long)link;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -308,9 +309,6 @@ static dev_link_t *pcnet_attach(void)
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
- info = kmalloc(sizeof(struct pcnet_dev_t), GFP_KERNEL);
- memset(info, 0, sizeof(struct pcnet_dev_t));
- dev = &info->dev;
ethdev_init(dev);
dev->name = info->node.dev_name;
dev->init = &pcnet_init;
@@ -318,7 +316,6 @@ static dev_link_t *pcnet_attach(void)
dev->stop = &pcnet_close;
dev->set_config = &set_config;
dev->tbusy = 1;
- link->priv = info;
/* Register with Card Services */
link->next = dev_list;
@@ -353,6 +350,7 @@ static dev_link_t *pcnet_attach(void)
static void pcnet_detach(dev_link_t *link)
{
+ pcnet_dev_t *info = link->priv;
dev_link_t **linkp;
long flags;
@@ -385,15 +383,9 @@ static void pcnet_detach(dev_link_t *link)
/* Unlink device structure, free bits */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree_s(dev->priv, sizeof(struct ei_device));
- kfree_s(dev, sizeof(struct pcnet_dev_t));
- }
- kfree_s(link, sizeof(struct dev_link_t));
+ if (link->dev)
+ unregister_netdev(&info->dev);
+ kfree(info);
} /* pcnet_detach */
@@ -595,20 +587,16 @@ static int try_io_port(dev_link_t *link)
static void pcnet_config(dev_link_t *link)
{
- client_handle_t handle;
+ client_handle_t handle = link->handle;
+ pcnet_dev_t *info = link->priv;
+ struct net_device *dev = &info->dev;
tuple_t tuple;
cisparse_t parse;
- pcnet_dev_t *info;
- struct net_device *dev;
int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
int manfid = 0, prodid = 0, has_shmem = 0;
u_short buf[64];
hw_info_t *hw_info;
- handle = link->handle;
- info = link->priv;
- dev = &info->dev;
-
DEBUG(0, "pcnet_config(0x%p)\n", link);
tuple.Attributes = 0;
@@ -881,12 +869,10 @@ static void set_misc_reg(struct net_device *dev)
static int pcnet_open(struct net_device *dev)
{
pcnet_dev_t *info = (pcnet_dev_t *)dev;
- dev_link_t *link;
+ dev_link_t *link = &info->link;
DEBUG(2, "pcnet_open('%s')\n", dev->name);
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
if (!DEV_OK(link))
return -ENODEV;
@@ -897,7 +883,7 @@ static int pcnet_open(struct net_device *dev)
request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
/* Start by assuming the link is bad */
- info->link = 1;
+ info->state = 1;
info->watchdog.function = &ei_watchdog;
info->watchdog.data = (u_long)info;
info->watchdog.expires = jiffies + HZ;
@@ -910,18 +896,15 @@ static int pcnet_open(struct net_device *dev)
static int pcnet_close(struct net_device *dev)
{
- dev_link_t *link;
+ pcnet_dev_t *info = (pcnet_dev_t *)dev;
+ dev_link_t *link = &info->link;
DEBUG(2, "pcnet_close('%s')\n", dev->name);
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
free_irq(dev->irq, dev);
link->open--; dev->start = 0;
- del_timer(&((pcnet_dev_t *)dev)->watchdog);
+ del_timer(&info->watchdog);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
@@ -1016,12 +999,12 @@ static void ei_watchdog(u_long arg)
if (info->flags & IS_DL10019A) {
int state = inb(dev->base_addr+0x1c) & 0x01;
- if (state != info->link) {
+ if (state != info->state) {
printk(KERN_INFO "%s: %s link beat\n", dev->name,
(state) ? "lost" : "found");
if (!state)
NS8390_init(dev, 1);
- info->link = state;
+ info->state = state;
}
}
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 5c7c5e4df..4a58706f6 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -8,7 +8,7 @@
Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
- smc91c92_cs.c 1.82 1999/11/08 20:46:17
+ smc91c92_cs.c 1.85 2000/01/15 02:03:14
This driver contains code written by Donald Becker
(becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au),
@@ -110,6 +110,8 @@ static dev_info_t dev_info = "smc91c92_cs";
static dev_link_t *dev_list = NULL;
struct smc_private {
+ dev_link_t link;
+ struct net_device dev;
u_short manfid;
u_short cardid;
struct net_device_stats stats;
@@ -336,6 +338,7 @@ static int smc91c92_init(struct net_device *dev)
static dev_link_t *smc91c92_attach(void)
{
client_reg_t client_reg;
+ struct smc_private *smc;
dev_link_t *link;
struct net_device *dev;
int i, ret;
@@ -344,8 +347,11 @@ static dev_link_t *smc91c92_attach(void)
flush_stale_links();
/* Create new ethernet device */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
+ if (!smc) return NULL;
+ memset(smc, 0, sizeof(struct smc_private));
+ link = &smc->link; dev = &smc->dev;
+
link->release.function = &smc91c92_release;
link->release.data = (u_long)link;
link->io.NumPorts1 = 16;
@@ -362,26 +368,19 @@ static dev_link_t *smc91c92_attach(void)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
-
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
-
- /* Make up a SMC91-specific-data structure. */
- dev->priv = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct smc_private));
-
+
/* The SMC91c92-specific entries in the device structure. */
dev->hard_start_xmit = &smc_start_xmit;
dev->get_stats = &smc91c92_get_stats;
dev->set_config = &s9k_config;
dev->set_multicast_list = &set_rx_mode;
ether_setup(dev);
- dev->name = ((struct smc_private *)dev->priv)->node.dev_name;
+ dev->name = smc->node.dev_name;
dev->init = &smc91c92_init;
dev->open = &smc91c92_open;
dev->stop = &smc91c92_close;
dev->tbusy = 1;
- link->priv = link->irq.Instance = dev;
+ dev->priv = link->priv = link->irq.Instance = smc;
/* Register with Card Services */
link->next = dev_list;
@@ -415,6 +414,7 @@ static dev_link_t *smc91c92_attach(void)
static void smc91c92_detach(dev_link_t *link)
{
+ struct smc_private *smc = link->priv;
dev_link_t **linkp;
long flags;
@@ -447,15 +447,9 @@ static void smc91c92_detach(dev_link_t *link)
/* Unlink device structure, free bits */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&smc->dev);
+ kfree(smc);
} /* smc91c92_detach */
@@ -509,30 +503,29 @@ static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
static int mhz_3288_power(dev_link_t *link)
{
- struct net_device *dev = link->priv;
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = link->priv;
u_char tmp;
/* Read the ISR twice... */
- readb(lp->base+MEGAHERTZ_ISR);
+ readb(smc->base+MEGAHERTZ_ISR);
udelay(5);
- readb(lp->base+MEGAHERTZ_ISR);
+ readb(smc->base+MEGAHERTZ_ISR);
/* Pause 200ms... */
mdelay(200);
/* Now read and write the COR... */
- tmp = readb(lp->base + link->conf.ConfigBase + CISREG_COR);
+ tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
udelay(5);
- writeb(tmp, lp->base + link->conf.ConfigBase + CISREG_COR);
+ writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);
return 0;
}
static int mhz_mfc_config(dev_link_t *link)
{
- struct net_device *dev = link->priv;
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[255];
@@ -545,6 +538,7 @@ static int mhz_mfc_config(dev_link_t *link)
link->conf.Status = CCSR_AUDIO_ENA;
link->irq.Attributes =
IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+ link->io.IOAddrLines = 16;
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts2 = 8;
@@ -581,15 +575,15 @@ static int mhz_mfc_config(dev_link_t *link)
i = CardServices(RequestWindow, &link->win, &req);
if (i != CS_SUCCESS)
return i;
- lp->base = ioremap(req.Base, 0x1000);
+ smc->base = ioremap(req.Base, 0x1000);
mem.CardOffset = mem.Page = 0;
- if (lp->manfid == MANFID_MOTOROLA)
+ if (smc->manfid == MANFID_MOTOROLA)
mem.CardOffset = link->conf.ConfigBase;
i = CardServices(MapMemPage, link->win, &mem);
if ((i == CS_SUCCESS)
- && (lp->manfid == MANFID_MEGAHERTZ)
- && (lp->cardid == PRODID_MEGAHERTZ_EM3288))
+ && (smc->manfid == MANFID_MEGAHERTZ)
+ && (smc->cardid == PRODID_MEGAHERTZ_EM3288))
mhz_3288_power(link);
return i;
@@ -598,7 +592,8 @@ static int mhz_mfc_config(dev_link_t *link)
static int mhz_setup(dev_link_t *link)
{
client_handle_t handle = link->handle;
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[255], *station_addr;
@@ -645,27 +640,28 @@ static int mhz_setup(dev_link_t *link)
static void mot_config(dev_link_t *link)
{
- struct net_device *dev = link->priv;
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr;
ioaddr_t iouart = link->io.BasePort2;
/* Set UART base address and force map with COR bit 1 */
- writeb(iouart & 0xff, lp->base + MOT_UART + CISREG_IOBASE_0);
- writeb((iouart >> 8) & 0xff, lp->base + MOT_UART + CISREG_IOBASE_1);
- writeb(MOT_NORMAL, lp->base + MOT_UART + CISREG_COR);
+ writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
+ writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
+ writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR);
/* Set SMC base address and force map with COR bit 1 */
- writeb(ioaddr & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_0);
- writeb((ioaddr >> 8) & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_1);
- writeb(MOT_NORMAL, lp->base + MOT_LAN + CISREG_COR);
+ writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0);
+ writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
+ writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR);
/* Wait for things to settle down */
mdelay(100);
}
static int mot_setup(dev_link_t *link) {
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr;
int i, wait, loop;
unsigned int addr;
@@ -699,7 +695,8 @@ static int mot_setup(dev_link_t *link) {
static int smc_config(dev_link_t *link)
{
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[255];
@@ -731,7 +728,8 @@ static int smc_config(dev_link_t *link)
static int smc_setup(dev_link_t *link)
{
client_handle_t handle = link->handle;
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
cisparse_t parse;
cistpl_lan_node_id_t *node_id;
@@ -774,7 +772,8 @@ static int smc_setup(dev_link_t *link)
static int osi_config(dev_link_t *link)
{
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
int i, j;
@@ -808,7 +807,8 @@ static int osi_config(dev_link_t *link)
static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
{
client_handle_t handle = link->handle;
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
u_char buf[255];
int i;
@@ -862,7 +862,8 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
static int check_sig(dev_link_t *link)
{
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr;
int width;
u_short s;
@@ -920,8 +921,8 @@ if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }
static void smc91c92_config(dev_link_t *link)
{
client_handle_t handle = link->handle;
- struct net_device *dev = link->priv;
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
tuple_t tuple;
cisparse_t parse;
u_short buf[32];
@@ -943,19 +944,19 @@ static void smc91c92_config(dev_link_t *link)
tuple.DesiredTuple = CISTPL_MANFID;
tuple.Attributes = TUPLE_RETURN_COMMON;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- lp->manfid = parse.manfid.manf;
- lp->cardid = parse.manfid.card;
+ smc->manfid = parse.manfid.manf;
+ smc->cardid = parse.manfid.card;
}
/* Configure card */
link->state |= DEV_CONFIG;
- if (lp->manfid == MANFID_OSITECH) {
+ if (smc->manfid == MANFID_OSITECH) {
i = osi_config(link);
- } else if (lp->manfid == MANFID_MOTOROLA
- || ((lp->manfid == MANFID_MEGAHERTZ)
- && ((lp->cardid == PRODID_MEGAHERTZ_VARIOUS)
- || (lp->cardid == PRODID_MEGAHERTZ_EM3288)))) {
+ } else if (smc->manfid == MANFID_MOTOROLA
+ || ((smc->manfid == MANFID_MEGAHERTZ)
+ && ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS)
+ || (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
i = mhz_mfc_config(link);
} else {
i = smc_config(link);
@@ -967,7 +968,7 @@ static void smc91c92_config(dev_link_t *link)
i = CardServices(RequestConfiguration, link->handle, &link->conf);
CS_EXIT_TEST(i, RequestConfiguration, config_failed);
- if (lp->manfid == MANFID_MOTOROLA)
+ if (smc->manfid == MANFID_MOTOROLA)
mot_config(link);
dev->irq = link->irq.AssignedIRQ;
@@ -983,10 +984,10 @@ static void smc91c92_config(dev_link_t *link)
goto config_undo;
}
- switch (lp->manfid) {
+ switch (smc->manfid) {
case MANFID_OSITECH:
case MANFID_PSION:
- i = osi_setup(link, lp->manfid, lp->cardid); break;
+ i = osi_setup(link, smc->manfid, smc->cardid); break;
case MANFID_SMC:
case MANFID_NEW_MEDIA:
i = smc_setup(link); break;
@@ -1004,7 +1005,7 @@ static void smc91c92_config(dev_link_t *link)
goto config_undo;
}
- link->dev = &lp->node;
+ link->dev = &smc->node;
link->state &= ~DEV_CONFIG_PENDING;
rev = check_sig(link);
@@ -1060,13 +1061,13 @@ config_failed: /* CS_EXIT_TEST() calls jump to here... */
static void smc91c92_release(u_long arg)
{
dev_link_t *link = (dev_link_t *)arg;
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
DEBUG(0, "smc91c92_release(0x%p)\n", link);
if (link->open) {
DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
- dev->name);
+ link->dev->dev_name);
link->state |= DEV_STALE_CONFIG;
return;
}
@@ -1075,8 +1076,7 @@ static void smc91c92_release(u_long arg)
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
if (link->win) {
- struct smc_private *lp = dev->priv;
- iounmap(lp->base);
+ iounmap(smc->base);
CardServices(ReleaseWindow, link->win);
}
@@ -1097,7 +1097,8 @@ static int smc91c92_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ struct smc_private *smc = link->priv;
+ struct net_device *dev = &smc->dev;
DEBUG(1, "smc91c92_event(0x%06x)\n", event);
@@ -1132,15 +1133,14 @@ static int smc91c92_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_CARD_RESET:
if (link->state & DEV_CONFIG) {
- struct smc_private *lp = dev->priv;
- if ((lp->manfid == MANFID_MEGAHERTZ) &&
- (lp->cardid == PRODID_MEGAHERTZ_EM3288))
+ if ((smc->manfid == MANFID_MEGAHERTZ) &&
+ (smc->cardid == PRODID_MEGAHERTZ_EM3288))
mhz_3288_power(link);
CardServices(RequestConfiguration, link->handle, &link->conf);
- if (lp->manfid == MANFID_MOTOROLA)
+ if (smc->manfid == MANFID_MOTOROLA)
mot_config(link);
- if ((lp->manfid == MANFID_OSITECH) &&
- (lp->cardid != PRODID_OSITECH_SEVEN)) {
+ if ((smc->manfid == MANFID_OSITECH) &&
+ (smc->cardid != PRODID_OSITECH_SEVEN)) {
/* Power up the card and enable interrupts */
set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
@@ -1181,8 +1181,8 @@ static void smc_dump(struct net_device *dev)
static int smc91c92_open(struct net_device *dev)
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
- dev_link_t *link;
+ struct smc_private *smc = dev->priv;
+ dev_link_t *link = &smc->link;
#ifdef PCMCIA_DEBUG
DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
@@ -1191,11 +1191,9 @@ static int smc91c92_open(struct net_device *dev)
#endif
/* Check that the PCMCIA card is still here. */
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- /* Physical device present signature. */
if (!DEV_OK(link))
return -ENODEV;
+ /* Physical device present signature. */
if (check_sig(link) < 0) {
printk("smc91c92_cs: Yikes! Bad chip signature!\n");
return -ENODEV;
@@ -1204,14 +1202,14 @@ static int smc91c92_open(struct net_device *dev)
MOD_INC_USE_COUNT;
dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
- lp->saved_skb = 0;
- lp->packets_waiting = 0;
+ smc->saved_skb = 0;
+ smc->packets_waiting = 0;
smc_reset(dev);
- lp->media.function = &media_check;
- lp->media.data = (u_long)dev;
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
+ smc->media.function = &media_check;
+ smc->media.data = (u_long)smc;
+ smc->media.expires = jiffies + HZ;
+ add_timer(&smc->media);
return 0;
} /* smc91c92_open */
@@ -1220,8 +1218,9 @@ static int smc91c92_open(struct net_device *dev)
static int smc91c92_close(struct net_device *dev)
{
+ struct smc_private *smc = dev->priv;
+ dev_link_t *link = &smc->link;
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
dev->name, inw(ioaddr + BANK_SELECT));
@@ -1241,13 +1240,8 @@ static int smc91c92_close(struct net_device *dev)
SMC_SELECT_BANK( 1 );
outw(CTL_POWERDOWN, ioaddr + CONTROL );
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev) break;
- if (link == NULL)
- return -ENODEV;
-
link->open--; dev->start = 0;
- del_timer(&((struct smc_private *)dev->priv)->media);
+ del_timer(&smc->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
@@ -1269,8 +1263,8 @@ static int smc91c92_close(struct net_device *dev)
static void smc_hardware_send_packet( struct net_device * dev )
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
- struct sk_buff *skb = lp->saved_skb;
+ struct smc_private *smc = dev->priv;
+ struct sk_buff *skb = smc->saved_skb;
ioaddr_t ioaddr = dev->base_addr;
unsigned char packet_no;
@@ -1286,12 +1280,12 @@ static void smc_hardware_send_packet( struct net_device * dev )
printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
" failed, status %#2.2x.\n", dev->name, packet_no);
dev_kfree_skb (skb);
- lp->saved_skb = NULL;
+ smc->saved_skb = NULL;
dev->tbusy = 0;
return;
}
- lp->stats.tx_bytes += skb->len;
+ smc->stats.tx_bytes += skb->len;
/* The card should use the just-allocated buffer. */
outw( packet_no, ioaddr + PNR_ARR );
/* point to the beginning of the packet */
@@ -1332,7 +1326,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
/* The chip does the rest of the work. */
outw( MC_ENQUEUE , ioaddr + MMU_CMD );
- lp->saved_skb = NULL;
+ smc->saved_skb = NULL;
dev_kfree_skb (skb);
dev->trans_start = jiffies;
dev->tbusy = 0;
@@ -1343,7 +1337,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = dev->priv;
ioaddr_t ioaddr = dev->base_addr;
unsigned short num_pages;
short time_out, ir;
@@ -1356,11 +1350,11 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
"Tx_status %2.2x status %4.4x.\n",
dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
- lp->stats.tx_errors++;
+ smc->stats.tx_errors++;
smc_reset(dev);
dev->trans_start = jiffies;
dev->tbusy = 0;
- lp->saved_skb = NULL;
+ smc->saved_skb = NULL;
}
DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
@@ -1372,26 +1366,26 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
- if ( lp->saved_skb) {
+ if ( smc->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
- lp->stats.tx_aborted_errors++;
+ smc->stats.tx_aborted_errors++;
printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
dev->name);
return 1;
}
- lp->saved_skb = skb;
+ smc->saved_skb = skb;
num_pages = skb->len >> 8;
if (num_pages > 7) {
printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
dev_kfree_skb (skb);
- lp->saved_skb = NULL;
- lp->stats.tx_dropped++;
+ smc->saved_skb = NULL;
+ smc->stats.tx_dropped++;
return 0; /* Do not re-queue this packet. */
}
/* A packet is now waiting. */
- lp->packets_waiting++;
+ smc->packets_waiting++;
SMC_SELECT_BANK( 2 ); /* Paranoia, we should always be in window 2 */
@@ -1422,7 +1416,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void smc_tx_err( struct net_device * dev )
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = (struct smc_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
@@ -1436,12 +1430,12 @@ static void smc_tx_err( struct net_device * dev )
tx_status = inw(ioaddr + DATA_1);
- lp->stats.tx_errors++;
- if (tx_status & TS_LOSTCAR) lp->stats.tx_carrier_errors++;
- if (tx_status & TS_LATCOL) lp->stats.tx_window_errors++;
+ smc->stats.tx_errors++;
+ if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;
+ if (tx_status & TS_LATCOL) smc->stats.tx_window_errors++;
if (tx_status & TS_16COL) {
- lp->stats.tx_aborted_errors++;
- lp->tx_err++;
+ smc->stats.tx_aborted_errors++;
+ smc->tx_err++;
}
if ( tx_status & TS_SUCCESS ) {
@@ -1456,7 +1450,7 @@ static void smc_tx_err( struct net_device * dev )
outw( MC_FREEPKT, ioaddr + MMU_CMD ); /* Free the packet memory. */
/* one less packet waiting for me */
- lp->packets_waiting--;
+ smc->packets_waiting--;
outw( saved_packet, ioaddr + PNR_ARR );
return;
@@ -1466,7 +1460,7 @@ static void smc_tx_err( struct net_device * dev )
static void smc_eph_irq(struct net_device *dev)
{
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = dev->priv;
ioaddr_t ioaddr = dev->base_addr;
unsigned short card_stats, ephs;
@@ -1477,10 +1471,10 @@ static void smc_eph_irq(struct net_device *dev)
/* Could be a counter roll-over warning: update stats. */
card_stats = inw( ioaddr + COUNTER );
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ smc->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ smc->stats.collisions += card_stats & 0xF;
#if 0 /* These are for when linux supports these statistics */
card_stats >>= 4; /* deferred */
card_stats >>= 4; /* excess deferred */
@@ -1500,13 +1494,13 @@ static void smc_eph_irq(struct net_device *dev)
static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = dev_id;
- struct smc_private *lp;
+ struct smc_private *smc = dev_id;
+ struct net_device *dev = &smc->dev;
ioaddr_t ioaddr;
u_short saved_bank, saved_pointer, mask, status;
char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
- if ((dev == NULL) || !dev->start)
+ if ((smc == NULL) || !dev->start)
return;
ioaddr = dev->base_addr;
@@ -1522,8 +1516,7 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq, ioaddr);
#endif
- lp = (struct smc_private *)dev->priv;
- lp->watchdog = 0;
+ smc->watchdog = 0;
saved_bank = inw(ioaddr + BANK_SELECT);
if ((saved_bank & 0xff00) != 0x3300) {
/* The device does not exist -- the card could be off-line, or
@@ -1553,7 +1546,7 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & IM_RCV_INT) {
/* Got a packet(s). */
smc_rx(dev);
- lp->last_rx = jiffies;
+ smc->last_rx = jiffies;
}
if (status & IM_TX_INT) {
smc_tx_err(dev);
@@ -1563,8 +1556,8 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & IM_TX_EMPTY_INT) {
outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
mask &= ~IM_TX_EMPTY_INT;
- lp->stats.tx_packets += lp->packets_waiting;
- lp->packets_waiting = 0;
+ smc->stats.tx_packets += smc->packets_waiting;
+ smc->packets_waiting = 0;
}
if (status & IM_ALLOC_INT) {
/* Clear this interrupt so it doesn't happen again */
@@ -1579,8 +1572,8 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mark_bh( NET_BH );
}
if (status & IM_RX_OVRN_INT) {
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ smc->stats.rx_errors++;
+ smc->stats.rx_fifo_errors++;
outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
}
if (status & IM_EPH_INT)
@@ -1602,25 +1595,25 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq_done:
- if ((lp->manfid == MANFID_OSITECH) &&
- (lp->cardid != PRODID_OSITECH_SEVEN)) {
+ if ((smc->manfid == MANFID_OSITECH) &&
+ (smc->cardid != PRODID_OSITECH_SEVEN)) {
/* Retrigger interrupt if needed */
mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
}
- if (lp->manfid == MANFID_MOTOROLA) {
+ if (smc->manfid == MANFID_MOTOROLA) {
u_char cor;
- cor = readb(lp->base + MOT_UART + CISREG_COR);
- writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_UART + CISREG_COR);
- writeb(cor, lp->base + MOT_UART + CISREG_COR);
- cor = readb(lp->base + MOT_LAN + CISREG_COR);
- writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_LAN + CISREG_COR);
- writeb(cor, lp->base + MOT_LAN + CISREG_COR);
+ cor = readb(smc->base + MOT_UART + CISREG_COR);
+ writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
+ writeb(cor, smc->base + MOT_UART + CISREG_COR);
+ cor = readb(smc->base + MOT_LAN + CISREG_COR);
+ writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
+ writeb(cor, smc->base + MOT_LAN + CISREG_COR);
}
#ifdef DOES_NOT_WORK
- if (lp->base != NULL) { /* Megahertz MFC's */
- readb(lp->base+MEGAHERTZ_ISR);
- readb(lp->base+MEGAHERTZ_ISR);
+ if (smc->base != NULL) { /* Megahertz MFC's */
+ readb(smc->base+MEGAHERTZ_ISR);
+ readb(smc->base+MEGAHERTZ_ISR);
}
#endif
}
@@ -1629,7 +1622,7 @@ irq_done:
static void smc_rx(struct net_device *dev)
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = (struct smc_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
int rx_status;
int packet_length; /* Caution: not frame length, rather words
@@ -1660,7 +1653,7 @@ static void smc_rx(struct net_device *dev)
if ( skb == NULL ) {
DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
- lp->stats.rx_dropped++;
+ smc->stats.rx_dropped++;
outw( MC_RELEASE, ioaddr + MMU_CMD );
return;
}
@@ -1673,18 +1666,18 @@ static void smc_rx(struct net_device *dev)
skb->dev = dev;
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
+ smc->stats.rx_packets++;
+ smc->stats.rx_bytes += skb->len;
if (rx_status & RS_MULTICAST)
- lp->stats.multicast++;
+ smc->stats.multicast++;
} else {
/* error ... */
- lp->stats.rx_errors++;
+ smc->stats.rx_errors++;
- if (rx_status & RS_ALGNERR) lp->stats.rx_frame_errors++;
+ if (rx_status & RS_ALGNERR) smc->stats.rx_frame_errors++;
if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
- lp->stats.rx_length_errors++;
- if (rx_status & RS_BADCRC) lp->stats.rx_crc_errors++;
+ smc->stats.rx_length_errors++;
+ if (rx_status & RS_BADCRC) smc->stats.rx_crc_errors++;
}
/* Let the MMU free the memory of this packet. */
outw(MC_RELEASE, ioaddr + MMU_CMD);
@@ -1696,9 +1689,9 @@ static void smc_rx(struct net_device *dev)
static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = (struct smc_private *)dev->priv;
/* Nothing to update - the 91c92 is a pretty primative chip. */
- return &lp->stats;
+ return &smc->stats;
}
/*======================================================================
@@ -1801,9 +1794,9 @@ static void set_rx_mode(struct net_device *dev)
static int s9k_config(struct net_device *dev, struct ifmap *map)
{
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = dev->priv;
if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
- if (lp->cfg & CFG_MII_SELECT)
+ if (smc->cfg & CFG_MII_SELECT)
return -EOPNOTSUPP;
else if (map->port > 2)
return -EINVAL;
@@ -1827,24 +1820,24 @@ static int s9k_config(struct net_device *dev, struct ifmap *map)
*/
static void smc_set_xcvr(struct net_device *dev, int if_port)
{
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = (struct smc_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
u_short saved_bank;
saved_bank = inw(ioaddr + BANK_SELECT);
SMC_SELECT_BANK(1);
if (if_port == 2) {
- outw(lp->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
- if ((lp->manfid == MANFID_OSITECH) &&
- (lp->cardid != PRODID_OSITECH_SEVEN))
+ outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
+ if ((smc->manfid == MANFID_OSITECH) &&
+ (smc->cardid != PRODID_OSITECH_SEVEN))
set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
- lp->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
+ smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
} else {
- outw(lp->cfg, ioaddr + CONFIG);
- if ((lp->manfid == MANFID_OSITECH) &&
- (lp->cardid != PRODID_OSITECH_SEVEN))
+ outw(smc->cfg, ioaddr + CONFIG);
+ if ((smc->manfid == MANFID_OSITECH) &&
+ (smc->cardid != PRODID_OSITECH_SEVEN))
mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
- lp->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
+ smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
}
SMC_SELECT_BANK(saved_bank);
}
@@ -1852,7 +1845,7 @@ static void smc_set_xcvr(struct net_device *dev, int if_port)
static void smc_reset(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- struct smc_private *lp = dev->priv;
+ struct smc_private *smc = dev->priv;
int i;
DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
@@ -1875,12 +1868,12 @@ static void smc_reset(struct net_device *dev)
Accept link errors, counter and Tx error interrupts. */
outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
ioaddr + CONTROL);
- lp->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
- lp->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC |
- (lp->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0);
+ smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
+ smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC |
+ (smc->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0);
smc_set_xcvr(dev, dev->if_port);
- if ((lp->manfid == MANFID_OSITECH) &&
- (lp->cardid != PRODID_OSITECH_SEVEN))
+ if ((smc->manfid == MANFID_OSITECH) &&
+ (smc->cardid != PRODID_OSITECH_SEVEN))
outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
(inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
ioaddr - 0x10 + OSITECH_AUI_PWR);
@@ -1897,7 +1890,7 @@ static void smc_reset(struct net_device *dev)
/* Re-enable the chip. */
SMC_SELECT_BANK(0);
- outw(((lp->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
+ outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
set_rx_mode(dev);
@@ -1915,14 +1908,13 @@ static void smc_reset(struct net_device *dev)
static void media_check(u_long arg)
{
- struct net_device *dev = (struct net_device *)(arg);
- struct smc_private *lp = (struct smc_private *)dev->priv;
+ struct smc_private *smc = (struct smc_private *)(arg);
+ struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr;
u_short i, media, saved_bank;
if (dev->start == 0) goto reschedule;
- lp = (struct smc_private *)dev->priv;
saved_bank = inw(ioaddr + BANK_SELECT);
SMC_SELECT_BANK(2);
i = inw(ioaddr + INTERRUPT);
@@ -1934,36 +1926,36 @@ static void media_check(u_long arg)
/* Check for pending interrupt with watchdog flag set: with
this, we can limp along even if the interrupt is blocked */
- if (lp->watchdog++ && ((i>>8) & i)) {
- if (!lp->fast_poll)
+ if (smc->watchdog++ && ((i>>8) & i)) {
+ if (!smc->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- smc_interrupt(dev->irq, dev, NULL);
- lp->fast_poll = HZ;
+ smc_interrupt(dev->irq, smc, NULL);
+ smc->fast_poll = HZ;
}
- if (lp->fast_poll) {
- lp->fast_poll--;
- lp->media.expires = jiffies + 1;
- add_timer(&lp->media);
+ if (smc->fast_poll) {
+ smc->fast_poll--;
+ smc->media.expires = jiffies + 1;
+ add_timer(&smc->media);
return;
}
- if (lp->cfg & CFG_MII_SELECT)
+ if (smc->cfg & CFG_MII_SELECT)
goto reschedule;
/* Ignore collisions unless we've had no rx's recently */
- if (jiffies - lp->last_rx > HZ) {
- if (lp->tx_err || (lp->media_status & EPH_16COL))
+ if (jiffies - smc->last_rx > HZ) {
+ if (smc->tx_err || (smc->media_status & EPH_16COL))
media |= EPH_16COL;
}
- lp->tx_err = 0;
+ smc->tx_err = 0;
- if (media != lp->media_status) {
- if ((media & lp->media_status & 1) &&
- ((lp->media_status ^ media) & EPH_LINK_OK))
+ if (media != smc->media_status) {
+ if ((media & smc->media_status & 1) &&
+ ((smc->media_status ^ media) & EPH_LINK_OK))
printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (lp->media_status & EPH_LINK_OK ? "lost" : "found"));
- else if ((media & lp->media_status & 2) &&
- ((lp->media_status ^ media) & EPH_16COL))
+ (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
+ else if ((media & smc->media_status & 2) &&
+ ((smc->media_status ^ media) & EPH_16COL))
printk(KERN_INFO "%s: coax cable %s\n", dev->name,
(media & EPH_16COL ? "problem" : "ok"));
if (dev->if_port == 0) {
@@ -1981,12 +1973,12 @@ static void media_check(u_long arg)
dev->name);
}
}
- lp->media_status = media;
+ smc->media_status = media;
}
reschedule:
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
+ smc->media.expires = jiffies + HZ;
+ add_timer(&smc->media);
}
/*====================================================================*/
diff --git a/drivers/net/pcmcia/tulip_cb.c b/drivers/net/pcmcia/tulip_cb.c
index eabffab80..ee49f58eb 100644
--- a/drivers/net/pcmcia/tulip_cb.c
+++ b/drivers/net/pcmcia/tulip_cb.c
@@ -39,13 +39,6 @@ static const char * const medianame[] = {
"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
};
-/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
-#ifdef REVERSE_PROBE_ORDER
-static int reverse_probe = 1;
-#else
-static int reverse_probe = 0;
-#endif
-
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
@@ -126,6 +119,7 @@ static int csr0 = 0x00A00000 | 0x4800;
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -262,58 +256,6 @@ them. The MII transceiver status is polled using an kernel timer.
*/
-static struct net_device *
-tulip_probe1(int pci_bus, int pci_devfn, struct net_device *dev, long ioaddr,
- int irq, int chip_idx, int board_idx);
-
-/* This table drives the PCI probe routines. It's mostly boilerplate in all
- of the drivers, and will likely be provided by some future kernel.
- Note the matching code -- the first table entry matchs all 56** cards but
- second only the 1234 card.
-*/
-enum pci_flags_bit {
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
-
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int io_size, min_latency;
- struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
- long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-#ifndef CARDBUS
-static struct pci_id_info pci_tbl[] = {
- { "Digital DC21040 Tulip",
- 0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- { "Digital DC21041 Tulip",
- 0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- { "Digital DS21140 Tulip",
- 0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- { "Digital DS21143 Tulip",
- 0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- { "Lite-On 82c168 PNIC",
- 0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "Macronix 98713 PMAC",
- 0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "Macronix 98715 PMAC",
- 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "Macronix 98725 PMAC",
- 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "ASIX AX88140",
- 0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- { "Lite-On LC82C115 PNIC-II",
- 0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "ADMtek AN981 Comet",
- 0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
- { "Compex RL100-TX",
- 0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
- {0},
-};
-#endif /* !CARD_BUS */
-
/* This table use during operation for capabilities and media timer. */
static void tulip_timer(unsigned long data);
@@ -456,7 +398,6 @@ struct mediainfo {
struct tulip_private {
char devname[8]; /* Used only for kernel debugging. */
const char *product_name;
- struct net_device *next_module;
struct tulip_rx_desc rx_ring[RX_RING_SIZE];
struct tulip_tx_desc tx_ring[TX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -574,107 +515,6 @@ static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
restore_flags(flags);
}
-/* A list of all installed Tulip devices. */
-static struct net_device *root_tulip_dev = NULL;
-
-#ifndef CARDBUS
-int tulip_probe(struct net_device *dev)
-{
- int cards_found = 0;
- int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
-
- if ( ! pcibios_present())
- return -ENODEV;
-
- for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command;
- int chip_idx;
- int irq;
- long ioaddr;
-
- if (pcibios_find_class
- (PCI_CLASS_NETWORK_ETHERNET << 8,
- reverse_probe ? 0xfe - pci_index : pci_index,
- &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
- if (reverse_probe)
- continue;
- else
- break;
- }
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_DEVICE_ID, &device);
-
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == pci_tbl[chip_idx].vendor_id
- && (device & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0)
- continue;
-
- {
-#if defined(PCI_SUPPORT_VER2)
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->base_address[0] & ~3;
- irq = pdev->irq;
-#elif defined(PCI_SUPPORT_VER3)
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
-#else
- u32 pci_ioaddr;
- u8 pci_irq_line;
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- ioaddr = pci_ioaddr & ~3;
- irq = pci_irq_line;
-#endif
- }
-
- if (debug > 2)
- printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
- pci_tbl[chip_idx].name, ioaddr);
-
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the"
- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
-
- dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
- irq, chip_idx, cards_found);
-
- /* Get and check the bus-master and latency values. */
- if (dev) {
- u8 pci_latency;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 10) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to 64 clocks.\n",
- pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 64);
- }
- }
- dev = 0;
- cards_found++;
- }
-
- return cards_found ? 0 : -ENODEV;
-}
-#endif /* not CARDBUS */
-
static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
struct net_device *dev, long ioaddr, int irq,
int chip_idx, int board_idx)
@@ -851,9 +691,6 @@ static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
memset(tp, 0, sizeof(*tp));
dev->priv = tp;
- tp->next_module = root_tulip_dev;
- root_tulip_dev = dev;
-
tp->pci_bus = pci_bus;
tp->pci_devfn = pci_devfn;
tp->chip_id = chip_idx;
@@ -2641,7 +2478,7 @@ static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if (test_and_set_bit(0, (void*)&dev->interrupt)) {
printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by "
"processor %d.\n",
- dev->name, hard_smp_processor_id());
+ dev->name, smp_processor_id());
dev->interrupt = 0;
return;
}
@@ -3251,127 +3088,93 @@ static void set_rx_mode(struct net_device *dev)
outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
}
-#ifdef CARDBUS
+static const struct pci_device_id tulip_pci_table[] __devinitdata = {
+ { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
+ { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
+ { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 },
+ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
+ { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
+ { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
+ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
+ { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ {0},
+};
-#include <pcmcia/driver_ops.h>
+MODULE_DEVICE_TABLE(pci, tulip_pci_table);
-static dev_node_t *tulip_attach(dev_locator_t *loc)
+static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct net_device *dev;
- u16 dev_id;
- u16 vendor_id;
- u32 io;
- u8 bus, devfn, irq;
-
- if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
- pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
- if (dev_id == 0x0003 && vendor_id == 0x115d)
- dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, X3201_3, 0);
- else
- dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0);
+ static int board_idx = 0;
+
+ printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
+
+ pci_set_master(pdev);
+ dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL,
+ pdev->resource[0].start, pdev->irq,
+ id->driver_data, board_idx++);
if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
- node->major = node->minor = 0;
- node->next = NULL;
- MOD_INC_USE_COUNT;
- return node;
+ pdev->driver_data = dev;
+ return 0;
}
- return NULL;
+ return -ENODEV;
}
-static void tulip_suspend(dev_node_t *node)
+static void tulip_suspend(struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name);
- for (dev = root_tulip_dev; dev; dev = next) {
- next = ((struct tulip_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
- if (dev) {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- if (tp->open) tulip_down(dev);
- }
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_suspend(%s)\n", dev->name);
+ if (tp->open) tulip_down(dev);
}
-static void tulip_resume(dev_node_t *node)
+static void tulip_resume(struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name);
- for (dev = root_tulip_dev; dev; dev = next) {
- next = ((struct tulip_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
- if (dev) {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- if (tp->open) tulip_up(dev);
- }
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_resume(%s)\n", dev->name);
+ if (tp->open) tulip_up(dev);
}
-static void tulip_detach(dev_node_t *node)
+static void __devexit tulip_remove(struct pci_dev *pdev)
{
- struct net_device **devp, **next;
- printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
- for (devp = &root_tulip_dev; *devp; devp = next) {
- next = &((struct tulip_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
- struct net_device *dev = *devp;
- struct tulip_private *tp = dev->priv;
- *devp = *next;
- unregister_netdev(dev);
- kfree(dev);
- kfree(tp);
- kfree(node);
- MOD_DEC_USE_COUNT;
- }
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ printk(KERN_INFO "tulip_detach(%s)\n", dev->name);
+ unregister_netdev(dev);
+ kfree(dev);
+ kfree(tp);
}
-struct driver_operations tulip_ops = {
- "tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach
+static struct pci_driver tulip_ops = {
+ name: "tulip_cb",
+ id_table: tulip_pci_table,
+ probe: tulip_pci_probe,
+ remove: tulip_remove,
+ suspend: tulip_suspend,
+ resume: tulip_resume
};
-#endif /* Cardbus support */
-
-#ifdef MODULE
-int init_module(void)
+static int __init tulip_init(void)
{
-#ifdef CARDBUS
- reverse_probe = 0; /* Not used. */
- register_driver(&tulip_ops);
+ pci_register_driver(&tulip_ops);
return 0;
-#else
- return tulip_probe(NULL);
-#endif
}
-void cleanup_module(void)
+static __exit void tulip_exit(void)
{
- struct net_device *next_dev;
-
-#ifdef CARDBUS
- unregister_driver(&tulip_ops);
-#endif
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_tulip_dev) {
- struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;
- next_dev = tp->next_module;
- unregister_netdev(root_tulip_dev);
- release_region(root_tulip_dev->base_addr,
- tulip_tbl[tp->chip_id].io_size);
- kfree(root_tulip_dev);
- root_tulip_dev = next_dev;
- }
+ pci_unregister_driver(&tulip_ops);
}
-#endif /* MODULE */
+module_init(tulip_init)
+module_exit(tulip_exit)
+
/*
* Local variables:
diff --git a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/pcmcia/wavelan_cs.c
index 5e9c9e6e2..c1c38aa28 100644
--- a/drivers/net/pcmcia/wavelan_cs.c
+++ b/drivers/net/pcmcia/wavelan_cs.c
@@ -2105,7 +2105,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
}
/* only super-user can see encryption key */
- if(!suser())
+ if(!capable(CAP_NET_ADMIN))
{
ret = -EPERM;
break;
@@ -2437,7 +2437,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
/* ------------------ PRIVATE IOCTL ------------------ */
case SIOCSIPQTHR:
- if(!suser())
+ if(!capable(CAP_NET_ADMIN))
{
ret = -EPERM;
break;
@@ -2476,7 +2476,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#ifdef HISTOGRAM
case SIOCSIPHISTO:
/* Verif if the user is root */
- if(!suser())
+ if(!capable(CAP_NET_ADMIN))
{
ret = -EPERM;
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 0b9c4bd3a..0c4f72ae7 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1,37 +1,44 @@
-/* [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55)
- * Xircom Creditcard Ethernet Adapter IIps driver
+/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03)
+ * Xircom CreditCard Ethernet Adapter IIps driver
+ * Xircom Realport 10/100 (RE-100) driver
*
- * This driver works for the CE2, CEM28, CEM33, CE3 and CEM56 cards.
- * The CEM56 has some problems, but it works.
- * The CEII card with the 14k4 modem and other old cards do not work.
+ * This driver originally was made by Werner Koch. Since the driver was left
+ * unmaintained for some time, there have been some improvements and changes
+ * since. These include supporting some of the "Realport" cards and develop-
+ * ing enhancements to support the new ones.
+ * It is made for CE2, CEM28, CEM33, CE33 and
+ * CEM56 cards. The CEM56 cards work both with their modem and ethernet
+ * interface. The RealPort 10/100 Modem and similar cards are supported but
+ * with some bugs which are being corrected as they are detected.
+ *
+ * Code revised and maintained by Allan Baker Ortegon
+ * al527261@prodigy.net.mx
+ * Written originally by Werner Koch based on David Hinds' skeleton of the
+ * PCMCIA driver. The code has been modified as to make the newer cards
+ * available.
*
- * Written by Werner Koch (werner.koch@guug.de),
- * based on David Hinds skeleton driver.
+ * The latest code for the driver, information on the development project
+ * for the Xircom RealPort and CE cards for the PCMCIA driver, and other
+ * related material, can be found at the following URL, which is underway:
+ *
+ * "http://xirc2ps.linuxbox.com/index.html"
*
- * You can get the latest driver revision from
- * "http://www.d.shuttle.de/isil/xircom/xirc2ps.html"
+ * Any bugs regarding this driver, please send them to:
+ * alanyuu@linuxbox.com
*
- * Please report bugs to: "xircom-bugs@isil.d.shuttle.de"
- *
- * A bug fix for the CEM56 to use modem and ethernet simultaneously
- * was provided by Koen Van Herck (Koen.Van.Herck@xircom.com).
- *
- * If your card locks up you should use the option "lockup_hack=1";
- * this may solve the problem but violates a kernel timing convention
- * (Thanks to David Luyer).
- *
- * Thanks to David Hinds for the PCMCIA package, Donald Becker for some
- * advice, Xircom for providing specs and help, 4PC GmbH Duesseldorf for
- * providing some hardware and last not least to all folks who helped to
- * develop this driver.
- *
- * For those, who are willing to do alpha testing of drivers, I have setup
- * the mailing list "xircom-devel@isil.d.shuttle.de" (To subscribe send a
- * message containing the word "subscribe" in the subject or somewhere at
- * the beginning of a line to "xircom-devel-request@isil.d.shuttle.de").
+ * The driver is still evolving and there are many cards which will benefit
+ * from having alpha testers. If you have a particular card and would like
+ * to be involved in this ongoing effort, please send mail to the maintainer.
+ *
+ * Special thanks to David Hinds, to Xircom for the specifications and their
+ * software development kit, and all others who may have colaborated in the
+ * development of the driver: Koen Van Herck (Koen.Van.Herck@xircom.com),
+ * 4PC GmbH Duesseldorf, David Luger, et al.
+ *
*
************************************************************************
* Copyright (c) 1997,1998 Werner Koch (dd9jn)
+ * Copyright (c) 1999 Allan Baker Ortegon
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -70,7 +77,7 @@
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -388,6 +395,8 @@ static dev_link_t *dev_list = NULL;
*/
typedef struct local_info_t {
+ dev_link_t link;
+ struct net_device dev;
dev_node_t node;
struct enet_statistics stats;
int card_type;
@@ -472,14 +481,18 @@ get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
static void
busy_loop(u_long len)
{
- u_long timeout = jiffies + len;
- u_long flags;
-
- save_flags(flags);
- sti();
- while (timeout >= jiffies)
- ;
- restore_flags(flags);
+ if (in_interrupt()) {
+ u_long timeout = jiffies + len;
+ u_long flags;
+ save_flags(flags);
+ sti();
+ while (timeout >= jiffies)
+ ;
+ restore_flags(flags);
+ } else {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(len);
+ }
}
/*====== Functions used for debugging =================================*/
@@ -674,9 +687,13 @@ xirc2ps_attach(void)
DEBUG(0, "attach()\n");
flush_stale_links();
- /* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- memset(link, 0, sizeof(struct dev_link_t));
+ /* Allocate the device structure */
+ local = kmalloc(sizeof(*local), GFP_KERNEL);
+ if (!local) return NULL;
+ memset(local, 0, sizeof(*local));
+ link = &local->link; dev = &local->dev;
+ link->priv = dev->priv = local;
+
link->release.function = &xirc2ps_release;
link->release.data = (u_long) link;
@@ -686,13 +703,8 @@ xirc2ps_attach(void)
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
-
- /* Allocate space for a device structure */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- memset(dev, 0, sizeof(struct net_device));
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
- memset(local, 0, sizeof(local_info_t));
- dev->priv = local;
+ link->irq.Handler = xirc2ps_interrupt;
+ link->irq.Instance = dev;
/* Fill in card specific entries */
dev->hard_start_xmit = &do_start_xmit;
@@ -706,7 +718,6 @@ xirc2ps_attach(void)
dev->open = &do_open;
dev->stop = &do_stop;
dev->tbusy = 1;
- link->priv = dev;
/* Register with Card Services */
link->next = dev_list;
@@ -739,6 +750,7 @@ xirc2ps_attach(void)
static void
xirc2ps_detach(dev_link_t * link)
{
+ local_info_t *local = link->priv;
dev_link_t **linkp;
long flags;
@@ -778,17 +790,11 @@ xirc2ps_detach(dev_link_t * link)
if (link->handle)
CardServices(DeregisterClient, link->handle);
- /* Unlink device structure, free pieces */
+ /* Unlink device structure, free it */
*linkp = link->next;
- if (link->priv) {
- struct net_device *dev = link->priv;
- if (link->dev != NULL)
- unregister_netdev(dev);
- if (dev->priv)
- kfree(dev->priv);
- kfree(link->priv);
- }
- kfree(link);
+ if (link->dev)
+ unregister_netdev(&local->dev);
+ kfree(local);
} /* xirc2ps_detach */
@@ -813,8 +819,7 @@ xirc2ps_detach(dev_link_t * link)
static int
set_card_type(dev_link_t *link, const void *s)
{
- struct net_device *dev = link->priv;
- local_info_t *local = dev->priv;
+ local_info_t *local = link->priv;
#ifdef PCMCIA_DEBUG
unsigned cisrev = ((const unsigned char *)s)[2];
#endif
@@ -907,20 +912,17 @@ has_ce2_string(dev_link_t * link)
static void
xirc2ps_config(dev_link_t * link)
{
- client_handle_t handle;
+ client_handle_t handle = link->handle;
+ local_info_t *local = link->priv;
+ struct net_device *dev = &local->dev;
tuple_t tuple;
cisparse_t parse;
- struct net_device *dev;
- local_info_t *local;
ioaddr_t ioaddr;
int err, i;
u_char buf[64];
cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
- handle = link->handle;
- dev = link->priv;
- local = dev->priv;
local->dingo_ccr = 0;
DEBUG(0, "config(0x%p)\n", link);
@@ -1034,8 +1036,6 @@ xirc2ps_config(dev_link_t * link)
for (i = 0; i < 4; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
}
- link->irq.Handler = xirc2ps_interrupt;
- link->irq.Instance = dev;
if (local->modem) {
int pass;
@@ -1124,7 +1124,7 @@ xirc2ps_config(dev_link_t * link)
* the I/O windows and the interrupt mapping.
*/
if ((err=CardServices(RequestConfiguration,
- link->handle, &link->conf))) {
+ link->handle, &link->conf))) {
cs_error(link->handle, RequestConfiguration, err);
goto config_error;
}
@@ -1146,7 +1146,7 @@ xirc2ps_config(dev_link_t * link)
reg.Offset = CISREG_IOBASE_0;
reg.Value = link->io.BasePort2 & 0xff;
if ((err = CardServices(AccessConfigurationRegister, link->handle,
- &reg))) {
+ &reg))) {
cs_error(link->handle, AccessConfigurationRegister, err);
goto config_error;
}
@@ -1154,7 +1154,7 @@ xirc2ps_config(dev_link_t * link)
reg.Offset = CISREG_IOBASE_1;
reg.Value = (link->io.BasePort2 >> 8) & 0xff;
if ((err = CardServices(AccessConfigurationRegister, link->handle,
- &reg))) {
+ &reg))) {
cs_error(link->handle, AccessConfigurationRegister, err);
goto config_error;
}
@@ -1213,20 +1213,19 @@ xirc2ps_config(dev_link_t * link)
}
#endif
- writeb(0x01 , local->dingo_ccr + 0x20);
- writeb(0x0c , local->dingo_ccr + 0x22);
- writeb(0x00 , local->dingo_ccr + 0x24);
- writeb(0x00 , local->dingo_ccr + 0x26);
- writeb(0x00 , local->dingo_ccr + 0x28);
+ writeb(0x01, local->dingo_ccr + 0x20);
+ writeb(0x0c, local->dingo_ccr + 0x22);
+ writeb(0x00, local->dingo_ccr + 0x24);
+ writeb(0x00, local->dingo_ccr + 0x26);
+ writeb(0x00, local->dingo_ccr + 0x28);
}
/* The if_port symbol can be set when the module is loaded */
local->probe_port=0;
if (!if_port) {
- local->probe_port=1;
- dev->if_port = 1;
- }
- else if ((if_port >= 1 && if_port <= 2) || (local->mohawk && if_port==4))
+ local->probe_port = dev->if_port = 1;
+ } else if ((if_port >= 1 && if_port <= 2) ||
+ (local->mohawk && if_port==4))
dev->if_port = if_port;
else
printk(KNOT_XIRC "invalid if_port requested\n");
@@ -1275,7 +1274,8 @@ static void
xirc2ps_release(u_long arg)
{
dev_link_t *link = (dev_link_t *) arg;
- struct net_device *dev = link->priv;
+ local_info_t *local = link->priv;
+ struct net_device *dev = &local->dev;
DEBUG(0, "release(0x%p)\n", link);
@@ -1322,8 +1322,8 @@ xirc2ps_event(event_t event, int priority,
event_callback_args_t * args)
{
dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
- local_info_t *lp = dev? dev->priv : NULL;
+ local_info_t *lp = link->priv;
+ struct net_device *dev = &lp->dev;
DEBUG(0, "event(%d)\n", (int)event);
@@ -1382,7 +1382,7 @@ static void
xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *)dev_id;
- local_info_t *lp;
+ local_info_t *lp = dev->priv;
ioaddr_t ioaddr;
u_char saved_page;
unsigned bytes_rcvd;
@@ -1401,7 +1401,6 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
dev->interrupt = 1;
- lp = dev->priv;
ioaddr = dev->base_addr;
if (lp->mohawk) { /* must disable the interrupt */
PutByte(XIRCREG_CR, 0);
@@ -1441,7 +1440,7 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* too many bytes received during this int, drop the rest of the
* packets */
lp->stats.rx_dropped++;
- printk(KINF_XIRC "%s: RX drop, too much done\n", dev->name);
+ DEBUG(2, "%s: RX drop, too much done\n", dev->name);
PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
} else if (rsr & PktRxOk) {
struct sk_buff *skb;
@@ -1782,8 +1781,6 @@ do_config(struct net_device *dev, struct ifmap *map)
DEBUG(0, "do_config(%p)\n", dev);
if (map->port != 255 && map->port != dev->if_port) {
- if (local->new_mii)
- return -EOPNOTSUPP;
if (map->port > 4)
return -EINVAL;
if (!map->port) {
@@ -1813,14 +1810,11 @@ static int
do_open(struct net_device *dev)
{
local_info_t *lp = dev->priv;
- dev_link_t *link;
+ dev_link_t *link = &lp->link;
DEBUG(0, "do_open(%p)\n", dev);
/* Check that the PCMCIA card is still here. */
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev)
- break;
/* Physical device present signature. */
if (!DEV_OK(link))
return -ENODEV;
@@ -1858,7 +1852,7 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
break;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16);
break;
@@ -2064,7 +2058,7 @@ init_mii(struct net_device *dev)
local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff);
- if (local->new_mii || local->probe_port)
+ if (local->probe_port)
control = 0x1000; /* auto neg */
else if (dev->if_port == 4)
control = 0x2000; /* no auto neg, 100mbs mode */
@@ -2081,8 +2075,8 @@ init_mii(struct net_device *dev)
return 0;
}
- if (local->new_mii || local->probe_port) {
- /* according to the DP83840A specs the auto negotation process
+ if (local->probe_port) {
+ /* according to the DP83840A specs the auto negotiation process
* may take up to 3.5 sec, so we use this also for our ML6692
* Fixme: Better to use a timer here!
*/
@@ -2094,7 +2088,7 @@ init_mii(struct net_device *dev)
}
if (!(status & 0x0020)) {
- printk(KERN_INFO "%s: auto negotation failed;"
+ printk(KERN_INFO "%s: autonegotiation failed;"
" using 10mbs\n", dev->name);
if (!local->new_mii) {
control = 0x0000;
@@ -2112,7 +2106,6 @@ init_mii(struct net_device *dev)
} else
dev->if_port = 1;
}
- local->probe_port = 0;
}
#ifdef PCMCIA_DEBUG
@@ -2140,13 +2133,11 @@ static int
do_stop(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link;
+ local_info_t *lp = dev->priv;
+ dev_link_t *link = &lp->link;
DEBUG(0, "do_stop(%p)\n", dev);
- for (link = dev_list; link; link = link->next)
- if (link->priv == dev)
- break;
if (!link)
return -ENODEV;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 89b1661a4..471afb6d3 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -594,6 +594,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
case 0x2627:
chipname = "PCnet/FAST III 79C975";
fdx = 1; mii = 1;
+ break;
default:
printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
return ENODEV;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index a3b04feab..1058341b6 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -318,7 +318,6 @@ plip_init_dev(struct net_device *dev, struct parport *pb)
dev->open = plip_open;
dev->stop = plip_close;
dev->get_stats = plip_get_stats;
- dev->set_config = plip_config;
dev->do_ioctl = plip_ioctl;
dev->header_cache_update = NULL;
dev->tx_queue_len = 10;
@@ -1229,27 +1228,6 @@ plip_get_stats(struct net_device *dev)
}
static int
-plip_config(struct net_device *dev, struct ifmap *map)
-{
- struct net_local *nl = (struct net_local *) dev->priv;
- struct pardevice *pardev = nl->pardev;
-
- if (dev->flags & IFF_UP)
- return -EBUSY;
-
- printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n");
- printk(KERN_WARNING "plip: Next time, please set with /proc/parport/*/irq instead.\n");
-
- if (map->irq != (unsigned char)-1) {
- pardev->port->irq = dev->irq = map->irq;
- /* Dummy request */
- request_irq(dev->irq, plip_interrupt, SA_INTERRUPT,
- pardev->name, NULL);
- }
- return 0;
-}
-
-static int
plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_local *nl = (struct net_local *) dev->priv;
@@ -1375,6 +1353,7 @@ plip_init(void)
if (!dev_plip[i]->name) {
printk(KERN_ERR "plip: memory squeeze.\n");
kfree(dev_plip[i]);
+ dev_plip[i] = NULL;
break;
}
sprintf(dev_plip[i]->name, "plip%d", i);
@@ -1382,6 +1361,7 @@ plip_init(void)
if (plip_init_dev(dev_plip[i],pb) || register_netdev(dev_plip[i])) {
kfree(dev_plip[i]->name);
kfree(dev_plip[i]);
+ dev_plip[i] = NULL;
} else {
i++;
}
diff --git a/drivers/net/setup.c b/drivers/net/setup.c
index 045e226fe..601617f79 100644
--- a/drivers/net/setup.c
+++ b/drivers/net/setup.c
@@ -30,6 +30,7 @@ extern int arcnet_init(void);
extern int bigmac_probe(void);
extern int bmac_probe(void);
extern int cpm_enet_init(void);
+extern int oaknet_init(void);
extern int dlci_setup(void);
extern int dgrs_probe(void);
extern int dmfe_reg_board(void);
@@ -165,6 +166,13 @@ struct net_probe pci_probes[] __initdata = {
#endif
/*
+ * IBM "Oak" Evaluation board
+ */
+#ifdef CONFIG_OAKNET
+ {oaknet_init, 0},
+#endif
+
+/*
* PCI Ethernet
*/
#ifdef CONFIG_DGRS
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 3c6589a06..02c76f50a 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -557,6 +557,13 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data;
struct shaper *sh=dev->priv;
+
+ if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
+ {
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ }
+
switch(ss->ss_cmd)
{
case SHAPER_SET_DEV:
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 16af6660c..6a5555983 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -480,14 +480,14 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
if (dev->priv != NULL) {
- /* NB: ultra_close_card() does free_irq + irq2dev */
+ /* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
- kfree(dev->priv);
- release_region(ioaddr, ULTRA_IO_EXTENT);
unregister_netdev(dev);
- dev->priv = NULL;
+ release_region(ioaddr, ULTRA_IO_EXTENT);
+ kfree(dev->priv);
}
}
+ unlock_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 7e260fb2c..1cb255f91 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1,4 +1,4 @@
-/********************************************************************
+/*******************************************************************************
*
* Linux ThunderLAN Driver
*
@@ -7,6 +7,7 @@
*
* (C) 1997-1998 Caldera, Inc.
* (C) 1998 James Banks
+ * (C) 1999, 2000 Torben Mathiasen
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
@@ -34,12 +35,21 @@
*
* Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
*
- * v1.1 Dec 20 -- Removed linux version checking(patch from
- * Tigran Aivazian). v1.1 includes Alan's SMP
- * opdates. We still have problems on SMP though,
- * but I'm looking into that.
+ * v1.1 Dec 20, 1999 - Removed linux version checking
+ * Patch from Tigran Aivazian.
+ * - v1.1 includes Alan's SMP updates.
+ * - We still have problems on SMP though,
+ * but I'm looking into that.
+ *
+ * v1.2 Jan 02, 2000 - Hopefully fixed the SMP deadlock.
+ * - Removed dependency of HZ being 100.
+ * - We now allow higher priority timers to
+ * overwrite timers like TLAN_TIMER_ACTIVITY
+ * Patch from John Cagle <john.cagle@compaq.com>.
+ * - Fixed a few compiler warnings.
+ *
*
- ********************************************************************/
+ *******************************************************************************/
#include <linux/module.h>
@@ -81,7 +91,7 @@ static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 1;
+static int TLanVersionMinor = 2;
static TLanAdapterEntry TLanAdapterList[] = {
@@ -244,7 +254,8 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
- if ( priv->timer.function != NULL ) {
+ if ( priv->timer.function != NULL &&
+ priv->timerType != TLAN_TIMER_ACTIVITY) {
spin_unlock_irqrestore(&priv->lock, flags);
return;
}
@@ -1160,7 +1171,12 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ priv->timer.function = &TLan_Timer;
+ priv->timer.data = (unsigned long) dev;
+ priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+ priv->timerSetAt = jiffies;
+ priv->timerType = TLAN_TIMER_ACTIVITY;
+ add_timer(&priv->timer);
} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
}
@@ -1316,7 +1332,12 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ priv->timer.function = &TLan_Timer;
+ priv->timer.data = (unsigned long) dev;
+ priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+ priv->timerSetAt = jiffies;
+ priv->timerType = TLAN_TIMER_ACTIVITY;
+ add_timer(&priv->timer);
} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
}
@@ -1554,7 +1575,7 @@ u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int )
* for a short period to power up the LED so it
* can be seen. This delay can be changed by
* changing the TLAN_TIMER_ACT_DELAY in tlan.h,
- * if desired. 10 jiffies produces a slightly
+ * if desired. 100 ms produces a slightly
* sluggish response.
*
**************************************************************/
@@ -1564,7 +1585,7 @@ void TLan_Timer( unsigned long data )
struct net_device *dev = (struct net_device *) data;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
u32 elapsed;
- unsigned long flags;
+ unsigned long flags = 0;
priv->timer.function = NULL;
@@ -2203,11 +2224,11 @@ void TLan_PhyPowerDown( struct net_device *dev )
TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
}
- /* Wait for 5 jiffies (50 ms) and powerup
+ /* Wait for 50 ms and powerup
* This is abitrary. It is intended to make sure the
* tranceiver settles.
*/
- TLan_SetTimer( dev, 5, TLAN_TIMER_PHY_PUP );
+ TLan_SetTimer( dev, (50/(1000/HZ)), TLAN_TIMER_PHY_PUP );
} /* TLan_PhyPowerDown */
@@ -2224,11 +2245,11 @@ void TLan_PhyPowerUp( struct net_device *dev )
value = MII_GC_LOOPBK;
TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
- /* Wait for 50 jiffies (500 ms) and reset the
+ /* Wait for 500 ms and reset the
* tranceiver. The TLAN docs say both 50 ms and
* 500 ms, so do the longer, just in case
*/
- TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_RESET );
+ TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_RESET );
} /* TLan_PhyPowerUp */
@@ -2253,10 +2274,10 @@ void TLan_PhyReset( struct net_device *dev )
}
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
- /* Wait for 50 jiffies (500 ms) and initialize.
+ /* Wait for 500 ms and initialize.
* I don't remember why I wait this long.
*/
- TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_START_LINK );
+ TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_START_LINK );
} /* TLan_PhyReset */
@@ -2299,13 +2320,13 @@ void TLan_PhyStartLink( struct net_device *dev )
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
- /* Wait for 400 jiffies (4 sec) for autonegotiation
+ /* Wait for 4 sec for autonegotiation
* to complete. The max spec time is less than this
* but the card need additional time to start AN.
* .5 sec should be plenty extra.
*/
printk( "TLAN: %s: Starting autonegotiation.\n", dev->name );
- TLan_SetTimer( dev, 400, TLAN_TIMER_PHY_FINISH_AN );
+ TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
return;
}
@@ -2334,10 +2355,10 @@ void TLan_PhyStartLink( struct net_device *dev )
TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
}
- /* Wait for 100 jiffies (1 sec) to give the tranceiver time
+ /* Wait for 1 sec to give the tranceiver time
* to establish link.
*/
- TLan_SetTimer( dev, 100, TLAN_TIMER_FINISH_RESET );
+ TLan_SetTimer( dev, HZ, TLAN_TIMER_FINISH_RESET );
} /* TLan_PhyStartLink */
@@ -2358,11 +2379,11 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
if ( ! ( status & MII_GS_AUTOCMPLT ) ) {
- /* Wait for 800 jiffies (8 sec) to give the process
+ /* Wait for 8 sec to give the process
* more time. Perhaps we should fail after a while.
*/
printk( "TLAN: Giving autonegotiation more time.\n" );
- TLan_SetTimer( dev, 800, TLAN_TIMER_PHY_FINISH_AN );
+ TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN );
return;
}
@@ -2394,9 +2415,9 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
}
}
- /* Wait for 10 jiffies (100 ms). No reason in partiticular.
+ /* Wait for 100 ms. No reason in partiticular.
*/
- TLan_SetTimer( dev, 10, TLAN_TIMER_FINISH_RESET );
+ TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET );
} /* TLan_PhyFinishAutoNeg */
@@ -2447,7 +2468,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
int err;
int minten;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- unsigned long flags;
+ unsigned long flags = 0;
err = FALSE;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
@@ -2616,7 +2637,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
{
u16 sio;
int minten;
- unsigned long flags;
+ unsigned long flags = 0;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
@@ -2847,7 +2868,7 @@ int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data )
{
int err;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
- unsigned long flags;
+ unsigned long flags = 0;
int ret=0;
if ( dev->interrupt == 0 )
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index 978c208d5..91a72ca9f 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -8,7 +8,8 @@
* by James Banks
*
* (C) 1997-1998 Caldera, Inc.
- *
+ * (C) 1999-2000 Torben Mathiasen
+ *
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
@@ -206,7 +207,7 @@ typedef struct tlan_private_tag {
#define TLAN_TIMER_PHY_FINISH_AN 7
#define TLAN_TIMER_FINISH_RESET 8
-#define TLAN_TIMER_ACT_DELAY 10
+#define TLAN_TIMER_ACT_DELAY (HZ/10)
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 64ce20902..26956af06 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -1651,7 +1651,7 @@ static void tr_rx(struct net_device *dev)
ti->tr_stats.rx_packets++;
skb->protocol = tr_type_trans(skb,dev);
- if (IPv4_p){
+ if (IPv4_p && (skb->protocol == ETH_P_IP)) {
skb->csum = chksum;
skb->ip_summed = 1;
}
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 8f1f6cce0..fcb3ccd76 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -25,10 +25,11 @@
* 8/18/99 - Updated driver for 2.3.13 kernel to use new pci
* resource. Driver also reports the card name returned by
* the pci resource.
+ * 1/11/00 - Added spinlocks for smp
*
* To Do:
*
- * Sanitize for smp
+ * IPv6 Multicast
*
* If Problems do Occur
* Most problems can be rectified by either closing and opening the interface
@@ -69,6 +70,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -86,7 +88,7 @@
*/
static char *version =
-"Olympic.c v0.3.0 8/18/99 - Peter De Schrijver & Mike Phillips" ;
+"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ;
static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion",
"Address Verification", "Neighbor Notification (Ring Poll)",
@@ -202,7 +204,6 @@ static int __init olympic_scan(struct net_device *dev)
olympic_priv->olympic_ring_speed = ringspeed[card_no] ;
olympic_priv->olympic_message_level = message_level[card_no] ;
- olympic_priv->olympic_multicast_set = 0 ;
if(olympic_init(dev)==-1) {
unregister_netdevice(dev);
@@ -251,6 +252,8 @@ static int __init olympic_init(struct net_device *dev)
}
}
+ spin_lock_init(&olympic_priv->olympic_lock) ;
+
#if OLYMPIC_DEBUG
printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -757,6 +760,8 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (!(sisr & SISR_MI)) /* Interrupt isn't for us */
return ;
+ spin_lock(&olympic_priv->olympic_lock);
+
if (dev->interrupt)
printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ;
@@ -835,15 +840,20 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->interrupt = 0 ;
writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
-
+
+ spin_unlock(&olympic_priv->olympic_lock) ;
}
static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
- __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+ __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+ unsigned long flags ;
+
+ spin_lock_irqsave(&olympic_priv->olympic_lock, flags);
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 1;
}
@@ -860,10 +870,12 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
dev->tbusy=0;
-
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 0;
- } else
+ } else {
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 1;
+ }
}
@@ -936,9 +948,11 @@ static void olympic_set_rx_mode(struct net_device *dev)
{
struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
__u8 *olympic_mmio = olympic_priv->olympic_mmio ;
- __u8 options = 0, set_mc_list = 0 ;
- __u8 *srb, *ata ;
+ __u8 options = 0;
+ __u8 *srb;
struct dev_mc_list *dmi ;
+ unsigned char dev_mc_address[4] ;
+ int i ;
writel(olympic_priv->srb,olympic_mmio+LAPA);
srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -949,10 +963,6 @@ static void olympic_set_rx_mode(struct net_device *dev)
else
options &= ~(3<<5) ;
- if (dev->mc_count) {
- set_mc_list = 1 ;
- }
-
/* Only issue the srb if there is a change in options */
if ((options ^ olympic_priv->olympic_copy_all_options)) {
@@ -975,60 +985,30 @@ static void olympic_set_rx_mode(struct net_device *dev)
return ;
}
- if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */
-
- dmi = dev->mc_list ;
+ /* Set the functional addresses we need for multicast */
- if (set_mc_list) { /* Turn multicast on */
-
- /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
- * We do this with a set functional address mask.
- */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11)|4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 1 ;
- }
-
-
- } else { /* Turn multicast off */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11) & ~4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 0 ;
- }
- }
+ dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
+ for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) {
+ dev_mc_address[0] |= dmi->dmi_addr[2] ;
+ dev_mc_address[1] |= dmi->dmi_addr[3] ;
+ dev_mc_address[2] |= dmi->dmi_addr[4] ;
+ dev_mc_address[3] |= dmi->dmi_addr[5] ;
}
+ writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+ writeb(0,srb+1);
+ writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+ writeb(0,srb+3);
+ writeb(0,srb+4);
+ writeb(0,srb+5);
+ writeb(dev_mc_address[0],srb+6);
+ writeb(dev_mc_address[1],srb+7);
+ writeb(dev_mc_address[2],srb+8);
+ writeb(dev_mc_address[3],srb+9);
+
+ olympic_priv->srb_queued = 2 ;
+ writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
}
@@ -1069,7 +1049,6 @@ static void olympic_srb_bh(struct net_device *dev)
case SRB_SET_GROUP_ADDRESS:
switch (readb(srb+2)) {
case 0x00:
- olympic_priv->olympic_multicast_set = 1 ;
break ;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;
@@ -1097,7 +1076,6 @@ static void olympic_srb_bh(struct net_device *dev)
case SRB_RESET_GROUP_ADDRESS:
switch (readb(srb+2)) {
case 0x00:
- olympic_priv->olympic_multicast_set = 0 ;
break ;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;
diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h
index d5a06423a..ba83366c7 100644
--- a/drivers/net/tokenring/olympic.h
+++ b/drivers/net/tokenring/olympic.h
@@ -245,6 +245,8 @@ struct olympic_private {
__u8 *olympic_lap;
char *olympic_card_name ;
+ spinlock_t olympic_lock ;
+
volatile int srb_queued; /* True if an SRB is still posted */
wait_queue_head_t srb_wait;
@@ -265,7 +267,6 @@ struct olympic_private {
__u8 olympic_ring_speed ;
__u16 pkt_buf_sz ;
__u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;
- __u8 olympic_multicast_set ;
__u16 olympic_addr_table_addr, olympic_parms_addr ;
__u8 olympic_laa[6] ;
};
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 13d431b46..5d024c2d4 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2470,7 +2470,8 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
tp->RplHead = SaveHead;
break; /* Return to tms380tr_interrupt */
}
-
+#if 0 /* This might happen for multicast or broadcast packets.
+ The upper layers are expected to handle this, not here */
/* Drop frames sent by myself */
if(tms380tr_chk_frame(dev, rpl->MData))
{
@@ -2480,6 +2481,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
dev_kfree_skb(rpl->Skb);
}
else
+#endif
{
tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index a0fc42764..5f5b16ee9 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -102,7 +102,6 @@ static int rx_copybreak = 100;
#endif
#if (LINUX_VERSION_CODE < 0x20123)
-#define hard_smp_processor_id() smp_processor_id()
#define test_and_set_bit(val, addr) set_bit(val, addr)
#endif
@@ -2164,7 +2163,7 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
#ifdef SMP_CHECK
printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
" proc %d already handling.\n", dev->name,
- tp->smp_proc_id, hard_smp_processor_id());
+ tp->smp_proc_id, smp_processor_id());
#else
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
#endif
@@ -2172,7 +2171,7 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
}
dev->interrupt = 1;
#ifdef SMP_CHECK
- tp->smp_proc_id = hard_smp_processor_id();
+ tp->smp_proc_id = smp_processor_id();
#endif
do {
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index 53cb71837..491b04057 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -1,13 +1,13 @@
/*
* cycx_drv.c Cyclom 2X Support Module.
*
-* This module is a library of common hardware-specific
+* This module is a library of common hardware specific
* functions used by the Cyclades Cyclom 2X sync card.
*
-* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
+* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo
+*
* Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
*
* This program is free software; you can redistribute it and/or
@@ -15,15 +15,16 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* 1999/11/11 acme set_current_state(TASK_INTERRUPTIBLE), code cleanup
+* 1999/11/11 acme set_current_state(TASK_INTERRUPTIBLE), code
+* cleanup
* 1999/11/08 acme init_cyc2x deleted, doing nothing
* 1999/11/06 acme back to read[bw], write[bw] and memcpy_to and
* fromio to use dpmbase ioremaped
-* 1999/10/26 acme use isa_read[bw], isa_write[bw] and isa_memcpy_to
-* and fromio
+* 1999/10/26 acme use isa_read[bw], isa_write[bw] & isa_memcpy_to
+* & fromio
* 1999/10/23 acme cleanup to only supports cyclom2x: all the other
-* boards are no longer manufactured by cyclades, if
-* someone wants to support them... be my guest!
+* boards are no longer manufactured by cyclades,
+* if someone wants to support them... be my guest!
* 1999/05/28 acme cycx_intack & cycx_intde gone for good
* 1999/05/18 acme lots of unlogged work, submitting to Linus...
* 1999/01/03 acme more judicious use of data types
@@ -65,7 +66,7 @@
#include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */
#define MOD_VERSION 0
-#define MOD_RELEASE 4
+#define MOD_RELEASE 5
#ifdef MODULE
MODULE_AUTHOR("Arnaldo Carvalho de Melo");
@@ -103,7 +104,8 @@ static u16 checksum(u8 *buf, u32 len);
/* private data */
static char modname[] = "cycx_drv";
static char fullname[] = "Cyclom 2X Support Module";
-static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo "
+ "<acme@conectiva.com.br>";
/* Hardware configuration options.
* These are arrays of configuration options used by verification routines.
@@ -130,8 +132,9 @@ static u32 cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
#ifdef MODULE
int init_module(void)
{
- printk(KERN_INFO "%s v%u.%u %s\n",
- fullname, MOD_VERSION, MOD_RELEASE, copyright);
+ printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE,
+ copyright);
+
return 0;
}
/* Module 'remove' entry point.
@@ -198,6 +201,7 @@ EXPORT_SYMBOL(cycx_down);
int cycx_down(cycxhw_t *hw)
{
iounmap((u32 *)hw->dpmbase);
+
return 0;
}
@@ -226,7 +230,9 @@ int cycx_exec(u32 addr)
while (cyc2x_readw(addr)) {
udelay(1000);
- if (++i > 50) return -1;
+
+ if (++i > 50)
+ return -1;
}
return 0;
@@ -271,7 +277,8 @@ static int memory_exists(u32 addr)
cyc2x_writew(TEST_PATTERN, addr + 0x10);
if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
- if (cyc2x_readw(addr + 0x10) == TEST_PATTERN) return 1;
+ if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
+ return 1;
delay_cycx(1);
}
@@ -298,6 +305,7 @@ static int buffer_load(u32 addr, u8 *buffer, u32 cnt)
{
cyc2x_memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
cyc2x_writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
+
return wait_cyc(addr);
}
@@ -434,38 +442,39 @@ static int load_cyc2x(cycxhw_t *hw, cfm_t *cfm, u32 len)
if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
*/
if (cksum != cfm->checksum) {
- printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n", modname);
+ printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n",
+ modname);
printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
- len - sizeof(cfm_t) - 1, cfm->info.codesize);
+ len - sizeof(cfm_t) - 1, cfm->info.codesize);
printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
- cksum, cfm->checksum);
+ cksum, cfm->checksum);
return -EINVAL;
}
/* If everything is ok, set reset, data and code pointers */
- img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1);
+ img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
#ifdef FIRMWARE_DEBUG
printk(KERN_INFO "%s:" __FUNCTION__ ": image sizes\n", modname);
printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
printk(KERN_INFO " data=%lu\n", img_hdr->data_size);
printk(KERN_INFO " code=%lu\n", img_hdr->code_size);
#endif
- reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t);
+ reset_image = ((u8 *)img_hdr) + sizeof(cycx_header_t);
data_image = reset_image + img_hdr->reset_size;
code_image = data_image + img_hdr->data_size;
/*---- Start load ----*/
/* Announce */
printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname,
- (cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware",
- cfm->info.codeid);
+ cfm->descr[0] ? cfm->descr : "unknown firmware",
+ cfm->info.codeid);
for (i = 0 ; i < 5 ; i++) {
/* Reset Cyclom hardware */
if (!reset_cyc2x(hw->dpmbase)) {
- printk(KERN_ERR "%s: dpm problem or board not "
- "found.\n", modname);
+ printk(KERN_ERR "%s: dpm problem or board not found\n",
+ modname);
return -EINVAL;
}
@@ -536,6 +545,7 @@ static void cycx_bootcfg(cycxhw_t *hw)
static int detect_cyc2x(u32 addr)
{
reset_cyc2x(addr);
+
return memory_exists(addr);
}
@@ -560,6 +570,7 @@ static int reset_cyc2x(u32 addr)
delay_cycx(2);
cyc2x_writeb(0, addr + RST_DISABLE);
delay_cycx(2);
+
return memory_exists(addr);
}
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index ecca37521..b9b72ddeb 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -3,7 +3,7 @@
*
* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
-* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo
+* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo
*
* Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
* Jaspreet Singh <jaspreet@sangoma.com>
@@ -13,6 +13,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* 2000/01/08 acme cleanup
* 1999/11/06 acme cycx_down back to life (it needs to be
* called to iounmap the dpmbase)
* 1999/08/09 acme removed references to enable_tx_int
@@ -48,7 +49,7 @@ MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
/* Defines & Macros */
#define DRV_VERSION 0 /* version number */
-#define DRV_RELEASE 4 /* release (minor version) number */
+#define DRV_RELEASE 5 /* release (minor version) number */
#define MAX_CARDS 1 /* max number of adapters */
#ifndef CONFIG_CYCLOMX_CARDS /* configurable option */
@@ -76,7 +77,8 @@ static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs);
/* private data */
static char drvname[] = "cyclomx";
static char fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
-static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo "
+ "<acme@conectiva.com.br>";
static int ncards = CONFIG_CYCLOMX_CARDS;
static cycx_t *card_array = NULL; /* adapter data space */
@@ -88,7 +90,7 @@ static cycx_t *card_array = NULL; /* adapter data space */
* o allocate adapter data space
* o initialize static data
* o register all cards with WAN router
- * o calibrate CYCX shared memory access delay.
+ * o calibrate Cyclom 2X shared memory access delay.
*
* Return: 0 Ok
* < 0 error.
@@ -110,7 +112,8 @@ int __init cyclomx_init (void)
ncards = max(ncards, 1);
card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
- if (card_array == NULL) return -ENOMEM;
+ if (!card_array)
+ return -ENOMEM;
memset(card_array, 0, sizeof(cycx_t) * ncards);
@@ -136,7 +139,8 @@ int __init cyclomx_init (void)
}
}
- if (cnt) ncards = cnt; /* adjust actual number of cards */
+ if (cnt)
+ ncards = cnt; /* adjust actual number of cards */
else {
kfree(card_array);
err = -ENODEV;
@@ -165,13 +169,12 @@ void cleanup_module (void)
#endif
/* WAN Device Driver Entry Points */
/*
- * Setup/confugure WAN link driver.
+ * Setup/configure WAN link driver.
* o check adapter state
* o make sure firmware is present in configuration
* o allocate interrupt vector
- * o setup CYCLOM X hardware
+ * o setup Cyclom 2X hardware
* o call appropriate routine to perform protocol-specific initialization
- * o mark I/O region as used
*
* This function is called when router handles ROUTER_SETUP IOCTL. The
* configuration structure is in kernel memory (including extended data, if
@@ -184,13 +187,15 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf)
int irq;
/* Sanity checks */
- if (!wandev || !wandev->private || !conf) return -EFAULT;
+ if (!wandev || !wandev->private || !conf)
+ return -EFAULT;
card = wandev->private;
- if (wandev->state != WAN_UNCONFIGURED) return -EBUSY;
+ if (wandev->state != WAN_UNCONFIGURED)
+ return -EBUSY;
- if (!conf->data_size || (conf->data == NULL)) {
+ if (!conf->data_size || !conf->data) {
printk(KERN_ERR "%s: firmware not found in configuration "
"data!\n", wandev->name);
return -EINVAL;
@@ -213,7 +218,7 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf)
/* Configure hardware, load firmware, etc. */
memset(&card->hw, 0, sizeof(cycxhw_t));
- card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
+ card->hw.irq = irq;
card->hw.dpmbase = conf->maddr;
card->hw.dpmsize = CYCX_WINDOWSIZE;
card->hw.fwid = CFID_X25_2X;
@@ -230,7 +235,7 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf)
return err;
}
- /* Intialize WAN device data space */
+ /* Initialize WAN device data space */
wandev->irq = irq;
wandev->dma = wandev->ioport = 0;
wandev->maddr = (unsigned long*)card->hw.dpmbase;
@@ -241,7 +246,9 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf)
/* Protocol-specific initialization */
switch (card->hw.fwid) {
#ifdef CONFIG_CYCLOMX_X25
- case CFID_X25_2X: err = cyx_init(card, conf); break;
+ case CFID_X25_2X:
+ err = cyx_init(card, conf);
+ break;
#endif
default:
printk(KERN_ERR "%s: this firmware is not supported!\n",
@@ -271,15 +278,19 @@ static int shutdown (wan_device_t *wandev)
cycx_t *card;
/* sanity checks */
- if (!wandev || !wandev->private) return -EFAULT;
+ if (!wandev || !wandev->private)
+ return -EFAULT;
- if (wandev->state == WAN_UNCONFIGURED) return 0;
+ if (wandev->state == WAN_UNCONFIGURED)
+ return 0;
card = wandev->private;
wandev->state = WAN_UNCONFIGURED;
cycx_down(&card->hw);
- printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name, wandev->irq);
+ printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,
+ wandev->irq);
free_irq(wandev->irq, card);
+
return 0;
}
@@ -289,7 +300,9 @@ static int shutdown (wan_device_t *wandev)
* o perform requested action
*
* This function is called when router handles one of the reserved user
- * IOCTLs. Note that 'arg' stil points to user address space.
+ * IOCTLs. Note that 'arg' still points to user address space.
+ *
+ * no reserved ioctls for the cyclom 2x up to now
*/
static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
{
@@ -298,8 +311,8 @@ static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
/* Miscellaneous */
/*
- * CYCX Interrupt Service Routine.
- * o acknowledge CYCX hardware interrupt.
+ * Cyclom 2X Interrupt Service Routine.
+ * o acknowledge Cyclom 2X hardware interrupt.
* o call protocol-specific interrupt service routine, if any.
*/
static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
@@ -347,27 +360,22 @@ void cyclomx_close (cycx_t *card)
void cyclomx_set_state (cycx_t *card, int state)
{
unsigned long host_cpu_flags;
+ char *string_state = NULL;
spin_lock_irqsave(&card->lock, host_cpu_flags);
if (card->wandev.state != state) {
switch (state) {
case WAN_CONNECTED:
- printk (KERN_INFO "%s: link connected!\n",
- card->devname);
- break;
-
- case WAN_CONNECTING:
- printk (KERN_INFO "%s: link connecting...\n",
- card->devname);
+ string_state = "connected!";
break;
case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: link disconnected!\n",
- card->devname);
+ string_state = "disconnected!";
break;
}
+ printk(KERN_INFO "%s: link %s\n", card->devname, string_state);
card->wandev.state = state;
}
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index cb41eb5b1..e9156df92 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -1,8 +1,9 @@
/*
-* cycx_x25.c CYCLOM X WAN Link Driver. X.25 module.
+* cycx_x25.c Cyclom 2X WAN Link Driver. X.25 module.
*
* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo
*
* Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
*
@@ -11,7 +12,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* 1999/10/27 acme use ARPHRD_HWX25 so that the x25 stack know
+* 2000/01/08 acme cleanup
+* 1999/10/27 acme use ARPHRD_HWX25 so that the X.25 stack know
* that we have a X.25 stack implemented in
* firmware onboard
* 1999/10/18 acme support for X.25 sockets in if_send,
@@ -35,7 +37,7 @@
* AFAIT, with ARPHRD_ETHER). This seems to be
* needed to use socket(AF_X25)...
* Now the config file must specify a peer media
-* address for svc channes over a crossover cable.
+* address for svc channels over a crossover cable.
* Removed hold_timeout from x25_channel_t,
* not used.
* A little enhancement in the DEBUG processing
@@ -79,7 +81,7 @@
#include <linux/wanrouter.h> /* WAN router definitions */
#include <asm/byteorder.h> /* htons(), etc. */
#include <linux/if_arp.h> /* ARPHRD_HWX25 */
-#include <linux/cyclomx.h> /* CYCLOM X common user API definitions */
+#include <linux/cyclomx.h> /* Cyclom 2X common user API definitions */
#include <linux/cycx_x25.h> /* X.25 firmware API definitions */
/* Defines & Macros */
@@ -87,7 +89,7 @@
#define X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */
/* Data Structures */
-/* This is an extention of the 'struct net_device' we create for each network
+/* This is an extension of the 'struct net_device' we create for each network
interface to keep the rest of X.25 channel-specific data. */
typedef struct x25_channel {
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
@@ -110,7 +112,8 @@ typedef struct x25_channel {
/* Function Prototypes */
/* WAN link driver entry points. These are called by the WAN router module. */
static int update (wan_device_t *wandev),
- new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf),
+ new_if (wan_device_t *wandev, struct net_device *dev,
+ wanif_conf_t *conf),
del_if (wan_device_t *wandev, struct net_device *dev);
/* Network device interface */
@@ -139,7 +142,8 @@ static void cyx_isr (cycx_t *card),
/* X.25 firmware interface functions */
static int x25_configure (cycx_t *card, TX25Config *conf),
x25_get_stats (cycx_t *card),
- x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf),
+ x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,
+ void *buf),
x25_connect_response (cycx_t *card, x25_channel_t *chan),
x25_disconnect_response (cycx_t *card, u8 link, u8 lcn);
@@ -182,7 +186,7 @@ static void x25_dump_devs(wan_device_t *wandev);
/* X.25 Protocol Initialization routine.
*
- * This routine is called by the main CYCLOM X module during setup. At this
+ * This routine is called by the main Cyclom 2X module during setup. At this
* point adapter is completely initialized and X.25 firmware is running.
* o read firmware version (to make sure it's alive)
* o configure adapter
@@ -206,7 +210,7 @@ int cyx_init (cycx_t *card, wandev_conf_t *conf)
card->u.x.connection_keys = 0;
card->u.x.lock = SPIN_LOCK_UNLOCKED;
- /* Configure adapter. Here we set resonable defaults, then parse
+ /* Configure adapter. Here we set reasonable defaults, then parse
* device configuration structure and set configuration options.
* Most configuration options are verified and corrected (if
* necessary) since we can't rely on the adapter to do so and don't
@@ -302,6 +306,7 @@ int cyx_init (cycx_t *card, wandev_conf_t *conf)
card->wandev.new_if = new_if;
card->wandev.del_if = del_if;
card->wandev.state = WAN_DISCONNECTED;
+
return 0;
}
@@ -317,6 +322,7 @@ static int update (wan_device_t *wandev)
return -ENODEV;
x25_get_stats(wandev->private);
+
return 0;
}
@@ -326,7 +332,7 @@ static int update (wan_device_t *wandev)
* o parse media- and hardware-specific configuration
* o make sure that a new channel can be created
* o allocate resources, if necessary
- * o prepare network device structure for registaration.
+ * o prepare network device structure for registration.
*
* Return: 0 o.k.
* < 0 failure (channel will not be created) */
@@ -380,7 +386,7 @@ static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *c
strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
init_timer(&chan->timer);
chan->timer.function = chan_timer;
- chan->timer.data = (unsigned long) dev;
+ chan->timer.data = (unsigned long)dev;
/* Set channel timeouts (default if not specified) */
chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
@@ -413,6 +419,7 @@ static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *c
dev->name = chan->name;
dev->init = if_init;
dev->priv = chan;
+
return 0;
}
@@ -480,6 +487,7 @@ static int if_init (struct net_device *dev)
/* Initialize socket buffers */
dev_init_buffers(dev);
set_chan_state(dev, WAN_DISCONNECTED);
+
return 0;
}
@@ -518,6 +526,7 @@ static int if_close (struct net_device *dev)
chan_disconnect(dev);
cyclomx_close(card);
+
return 0;
}
@@ -533,6 +542,7 @@ static int if_header (struct sk_buff *skb, struct net_device *dev,
u16 type, void *daddr, void *saddr, unsigned len)
{
skb->protocol = type;
+
return dev->hard_header_len;
}
@@ -632,6 +642,7 @@ static int if_send (struct sk_buff *skb, struct net_device *dev)
free_packet:
dev_kfree_skb(skb);
+
return 0;
}
@@ -710,7 +721,7 @@ static void tx_intr (cycx_t *card, TX25Cmd *cmd)
cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
/* unbusy device and then dev_tint(); */
- if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) {
+ if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
card->buff_int_mode_unbusy = 1;
dev->tbusy = 0;
} else
@@ -721,14 +732,14 @@ static void tx_intr (cycx_t *card, TX25Cmd *cmd)
/* Receive interrupt handler.
* This routine handles fragmented IP packets using M-bit according to the
* RFC1356.
- * o map ligical channel number to network interface.
+ * o map logical channel number to network interface.
* o allocate socket buffer or append received packet to the existing one.
* o if M-bit is reset (i.e. it's the last packet in a sequence) then
* decapsulate packet and pass socket buffer to the protocol stack.
*
* Notes:
* 1. When allocating a socket buffer, if M-bit is set then more data is
- * comming and we have to allocate buffer for the maximum IP packet size
+ * coming and we have to allocate buffer for the maximum IP packet size
* expected on this channel.
* 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
* socket buffers available) the whole packet sequence must be discarded. */
@@ -884,7 +895,7 @@ static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
set_chan_state(dev, WAN_CONNECTED);
}
-/* Disonnect confirm interrupt handler. */
+/* Disconnect confirm interrupt handler. */
static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
{
wan_device_t *wandev = &card->wandev;
@@ -934,7 +945,7 @@ static void log_intr (cycx_t *card, TX25Cmd *cmd)
cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
- /* at most 20 bytes are available... thanx to Daniela :) */
+ /* at most 20 bytes are available... thanks to Daniela :) */
toread = size < 20 ? size : 20;
cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
@@ -987,8 +998,9 @@ static void hex_dump(char *msg, unsigned char *p, int len)
printk(KERN_INFO "%s: %s\n", msg, hex);
}
#endif
-/* CYCLOM X Firmware-Specific Functions */
-/* Exec x25 command. */
+
+/* Cyclom 2X Firmware-Specific Functions */
+/* Exec X.25 command. */
static int x25_exec (cycx_t *card, int command, int link,
void *d1, int len1, void *d2, int len2)
{
@@ -1007,7 +1019,7 @@ static int x25_exec (cycx_t *card, int command, int link,
/* write command */
cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
- /* write x25 data */
+ /* write X.25 data */
if (d1) {
cycx_poke(&card->hw, addr, d1, len1);
@@ -1016,7 +1028,7 @@ static int x25_exec (cycx_t *card, int command, int link,
u32 addr1 = 0xA00 + 0x400 * link;
cycx_poke(&card->hw, addr + len1, d2, 249);
- cycx_poke(&card->hw, addr1, ((u8*) d2) + 249,
+ cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,
len2 - 249);
} else
cycx_poke(&card->hw, addr + len1, d2, len2);
@@ -1069,7 +1081,7 @@ static int x25_configure (cycx_t *card, TX25Config *conf)
static int x25_get_stats (cycx_t *card)
{
/* the firmware expects 20 in the size field!!!
- thanx to Daniela */
+ thanks to Daniela */
int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
if (err)
@@ -1095,6 +1107,7 @@ static int x25_get_stats (cycx_t *card)
card->wandev.stats.tx_errors = 0; /* not available from fw */
x25_dump_devs(&card->wandev);
+
return 0;
}
@@ -1180,7 +1193,7 @@ static int x25_place_call (cycx_t *card, x25_channel_t *chan)
++len;
d[5] = mylen << 4 | remotelen;
- d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */
+ d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
&d, 7 + len + 1, NULL, 0)) != 0)
@@ -1200,7 +1213,7 @@ static int x25_connect_response (cycx_t *card, x25_channel_t *chan)
d[0] = d[3] = chan->lcn;
d[2] = 0x10;
d[4] = 0x0F;
- d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */
+ d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */
return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
}
@@ -1214,6 +1227,7 @@ static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn)
d[0] = d[3] = lcn;
d[2] = 0x10;
d[4] = 0x17;
+
return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
}
@@ -1252,6 +1266,7 @@ static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
for (; dev; dev = dev->slave)
if (((x25_channel_t*)dev->priv)->lcn == lcn)
break;
+
return dev;
}
@@ -1261,8 +1276,9 @@ static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
struct net_device *dev = wandev->dev;
for (; dev; dev = dev->slave)
- if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte))
+ if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte))
break;
+
return dev;
}
@@ -1281,10 +1297,13 @@ static int chan_connect (struct net_device *dev)
if (chan->svc) {
if (!chan->addr[0])
return -EINVAL; /* no destination address */
+
dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
card->devname, chan->addr);
+
if (x25_place_call(card, chan))
return -EIO;
+
set_chan_state(dev, WAN_CONNECTING);
return 1;
} else
@@ -1309,18 +1328,14 @@ static void chan_disconnect (struct net_device *dev)
/* Called by kernel timer */
static void chan_timer (unsigned long d)
{
- struct net_device *dev = (struct net_device*) d;
+ struct net_device *dev = (struct net_device *)d;
x25_channel_t *chan = dev->priv;
- switch (chan->state) {
- case WAN_CONNECTED:
- chan_disconnect(dev);
- break;
- default:
- printk (KERN_ERR "%s: chan_timer for svc (%s) not "
- "connected!\n",
- chan->card->devname, dev->name);
- }
+ if (chan->state == WAN_CONNECTED)
+ chan_disconnect(dev);
+ else
+ printk(KERN_ERR "%s: chan_timer for svc (%s) not connected!\n",
+ chan->card->devname, dev->name);
}
/* Set logical channel state. */
@@ -1329,6 +1344,7 @@ static void set_chan_state (struct net_device *dev, u8 state)
x25_channel_t *chan = dev->priv;
cycx_t *card = chan->card;
u32 flags = 0;
+ char *string_state = NULL;
spin_lock_irqsave(&card->lock, flags);
@@ -1338,9 +1354,7 @@ static void set_chan_state (struct net_device *dev, u8 state)
switch (state) {
case WAN_CONNECTED:
- printk (KERN_INFO "%s: interface %s "
- "connected!\n",
- card->devname, dev->name);
+ string_state = "connected!";
*(u16*)dev->dev_addr = htons(chan->lcn);
dev->tbusy = 0;
reset_timer(dev);
@@ -1351,21 +1365,16 @@ static void set_chan_state (struct net_device *dev, u8 state)
break;
case WAN_CONNECTING:
- printk (KERN_INFO "%s: interface %s "
- "connecting...\n",
- card->devname, dev->name);
+ string_state = "connecting...";
break;
case WAN_DISCONNECTING:
- printk (KERN_INFO "%s: interface %s "
- "disconnecting...\n",
- card->devname, dev->name);
+ string_state = "disconnecting...";
break;
case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: interface %s "
- "disconnected!\n",
- card->devname, dev->name);
+ string_state = "disconnected!";
+
if (chan->svc) {
*(unsigned short*)dev->dev_addr = 0;
chan->lcn = 0;
@@ -1378,6 +1387,8 @@ static void set_chan_state (struct net_device *dev, u8 state)
break;
}
+ printk (KERN_INFO "%s: interface %s %s\n", card->devname,
+ dev->name, string_state);
chan->state = state;
}
@@ -1419,6 +1430,7 @@ static int chan_send (struct net_device *dev, struct sk_buff *skb)
++chan->ifstats.tx_packets;
chan->ifstats.tx_bytes += len;
+
return 0;
}
@@ -1488,7 +1500,7 @@ static unsigned dec_to_uint (u8 *str, int len)
len = strlen(str);
for (; len && is_digit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned)'0');
+ val = (val * 10) + (*str - (unsigned) '0');
return val;
}
@@ -1497,66 +1509,65 @@ static void reset_timer(struct net_device *dev)
{
x25_channel_t *chan = dev->priv;
- if (!chan->svc)
- return;
-
- del_timer(&chan->timer);
- chan->timer.expires = jiffies + chan->idle_tmout * HZ;
- add_timer(&chan->timer);
+ if (chan->svc) {
+ del_timer(&chan->timer);
+ chan->timer.expires = jiffies + chan->idle_tmout * HZ;
+ add_timer(&chan->timer);
+ }
}
#ifdef CYCLOMX_X25_DEBUG
static void x25_dump_config(TX25Config *conf)
{
- printk (KERN_INFO "x25 configuration\n");
- printk (KERN_INFO "-----------------\n");
- printk (KERN_INFO "link number=%d\n", conf->link);
- printk (KERN_INFO "line speed=%d\n", conf->speed);
- printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
- printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
- printk (KERN_INFO "level 2 window=%d\n", conf->n2win);
- printk (KERN_INFO "level 3 window=%d\n", conf->n3win);
- printk (KERN_INFO "# logical channels=%d\n", conf->nvc);
- printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
- printk (KERN_INFO "my address=%d\n", conf->locaddr);
- printk (KERN_INFO "remote address=%d\n", conf->remaddr);
- printk (KERN_INFO "t1=%d seconds\n", conf->t1);
- printk (KERN_INFO "t2=%d seconds\n", conf->t2);
- printk (KERN_INFO "t21=%d seconds\n", conf->t21);
- printk (KERN_INFO "# PVCs=%d\n", conf->npvc);
- printk (KERN_INFO "t23=%d seconds\n", conf->t23);
- printk (KERN_INFO "flags=0x%x\n", conf->flags);
+ printk(KERN_INFO "X.25 configuration\n");
+ printk(KERN_INFO "-----------------\n");
+ printk(KERN_INFO "link number=%d\n", conf->link);
+ printk(KERN_INFO "line speed=%d\n", conf->speed);
+ printk(KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
+ printk(KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
+ printk(KERN_INFO "level 2 window=%d\n", conf->n2win);
+ printk(KERN_INFO "level 3 window=%d\n", conf->n3win);
+ printk(KERN_INFO "# logical channels=%d\n", conf->nvc);
+ printk(KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
+ printk(KERN_INFO "my address=%d\n", conf->locaddr);
+ printk(KERN_INFO "remote address=%d\n", conf->remaddr);
+ printk(KERN_INFO "t1=%d seconds\n", conf->t1);
+ printk(KERN_INFO "t2=%d seconds\n", conf->t2);
+ printk(KERN_INFO "t21=%d seconds\n", conf->t21);
+ printk(KERN_INFO "# PVCs=%d\n", conf->npvc);
+ printk(KERN_INFO "t23=%d seconds\n", conf->t23);
+ printk(KERN_INFO "flags=0x%x\n", conf->flags);
}
static void x25_dump_stats(TX25Stats *stats)
{
- printk (KERN_INFO "x25 statistics\n");
- printk (KERN_INFO "--------------\n");
- printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
- printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
- printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
- printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
- printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
- printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
- printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
- printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
- printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
- printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
+ printk(KERN_INFO "X.25 statistics\n");
+ printk(KERN_INFO "--------------\n");
+ printk(KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
+ printk(KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
+ printk(KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
+ printk(KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
+ printk(KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
+ printk(KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
+ printk(KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
+ printk(KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
+ printk(KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
+ printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
}
static void x25_dump_devs(wan_device_t *wandev)
{
struct net_device *dev = wandev->dev;
- printk (KERN_INFO "x25 dev states\n");
- printk (KERN_INFO "name: addr: tbusy: protocol:\n");
- printk (KERN_INFO "---------------------------------------\n");
+ printk(KERN_INFO "X.25 dev states\n");
+ printk(KERN_INFO "name: addr: tbusy: protocol:\n");
+ printk(KERN_INFO "---------------------------------------\n");
for (; dev; dev = dev->slave) {
x25_channel_t *chan = dev->priv;
- printk (KERN_INFO "%-5.5s %-15.15s %ld ETH_P_%s\n",
- chan->name, chan->addr, dev->tbusy,
- chan->protocol == ETH_P_IP ? "IP" : "X25");
+ printk(KERN_INFO "%-5.5s %-15.15s %ld ETH_P_%s\n",
+ chan->name, chan->addr, dev->tbusy,
+ chan->protocol == ETH_P_IP ? "IP" : "X25");
}
}
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index bfa2bf89f..6113365c1 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -660,14 +660,14 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
h = (struct cisco_packet *)skb->data;
skb_pull(skb, sizeof(struct cisco_packet*));
if (sp->pp_flags & PP_DEBUG)
- printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n",
+ printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n",
dev->name, skb->len,
ntohl (h->type), h->par1, h->par2, h->rel,
h->time0, h->time1);
switch (ntohl (h->type)) {
default:
if (sp->pp_flags & PP_DEBUG)
- printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n",
+ printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n",
dev->name, ntohl (h->type));
break;
case CISCO_ADDR_REPLY:
@@ -814,7 +814,7 @@ static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
ch->time1 = htons ((u16) t);
if (sp->pp_flags & PP_DEBUG)
- printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n",
+ printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n",
dev->name, ntohl (ch->type), ch->par1,
ch->par2, ch->rel, ch->time0, ch->time1);
sp->obytes += skb->len;
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index a802170ce..f6b385de5 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -5,18 +5,18 @@
* 2 of the License, or (at your option) any later version.
*
* (c) Copyright 1998 Building Number Three Ltd
+ * (c) Copyright 2000 Red Hat Software
*
* Development of this driver was funded by Equiinet Ltd
* http://www.equiinet.com
*
* ChangeLog:
*
- * Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
+ * Asynchronous mode dropped for 2.2. For 2.5 we will attempt the
* unification of all the Z85x30 asynchronous drivers for real.
*
- * To Do:
- *
- * Finish DMA mode support.
+ * DMA now uses get_free_page as kmalloc buffers may span a 64K
+ * boundary.
*
* Performance
*
@@ -170,7 +170,7 @@ EXPORT_SYMBOL(z8530_hdlc_kilostream);
/*
* As above but for enhanced chips.
*/
-
+
u8 z8530_hdlc_kilostream_85230[]=
{
4, SYNC_ENAB|SDLC|X1CLK,
@@ -355,13 +355,15 @@ static void z8530_status(struct z8530_channel *chan)
z8530_tx_done(chan);
}
- if(altered&DCD)
+ if(altered&chan->dcdcheck)
{
- if(status&DCD)
+ if(status&chan->dcdcheck)
{
printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
- if(chan->netdevice)
+ if(chan->netdevice &&
+ ((chan->netdevice->type == ARPHRD_HDLC) ||
+ (chan->netdevice->type == ARPHRD_PPP)))
sppp_reopen(chan->netdevice);
}
else
@@ -441,7 +443,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
if(status&TxEOM)
{
flags=claim_dma_lock();
- /* Transmit underrun */
disable_dma(chan->txdma);
clear_dma_ff(chan->txdma);
chan->txdma_on=0;
@@ -449,13 +450,15 @@ static void z8530_dma_status(struct z8530_channel *chan)
z8530_tx_done(chan);
}
}
- if(altered&DCD)
+ if(altered&chan->dcdcheck)
{
- if(status&DCD)
+ if(status&chan->dcdcheck)
{
printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
- if(chan->netdevice)
+ if(chan->netdevice &&
+ ((chan->netdevice->type == ARPHRD_HDLC) ||
+ (chan->netdevice->type == ARPHRD_PPP)))
sppp_reopen(chan->netdevice);
}
else
@@ -662,39 +665,28 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
c->txdma_on = 0;
/*
- * Allocate the DMA flip buffers
+ * Allocate the DMA flip buffers. Limit by page size.
+ * Everyone runs 1500 mtu or less on wan links so this
+ * should be fine.
*/
- c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ if(c->mtu > PAGE_SIZE/2)
+ return -EMSGSIZE;
+
+ c->rx_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
if(c->rx_buf[0]==NULL)
return -ENOBUFS;
- c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
- if(c->rx_buf[1]==NULL)
- {
- kfree(c->rx_buf[0]);
- c->rx_buf[0]=NULL;
- return -ENOBUFS;
- }
+ c->rx_buf[1]=c->rx_buf[0]+PAGE_SIZE/2;
- c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
if(c->tx_dma_buf[0]==NULL)
{
- kfree(c->rx_buf[0]);
- kfree(c->rx_buf[1]);
- c->rx_buf[0]=NULL;
- return -ENOBUFS;
- }
- c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
- if(c->tx_dma_buf[1]==NULL)
- {
- kfree(c->tx_dma_buf[0]);
- kfree(c->rx_buf[0]);
- kfree(c->rx_buf[1]);
+ free_page((unsigned long)c->rx_buf[0]);
c->rx_buf[0]=NULL;
- c->rx_buf[1]=NULL;
- c->tx_dma_buf[0]=NULL;
return -ENOBUFS;
}
+ c->tx_dma_buf[1]=c->tx_dma_buf[0]+PAGE_SIZE/2;
+
c->tx_dma_used=0;
c->dma_tx = 1;
c->dma_num=0;
@@ -806,24 +798,14 @@ int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
if(c->rx_buf[0])
{
- kfree(c->rx_buf[0]);
+ free_page((unsigned long)c->rx_buf[0]);
c->rx_buf[0]=NULL;
}
- if(c->rx_buf[1])
- {
- kfree(c->rx_buf[1]);
- c->rx_buf[1]=NULL;
- }
if(c->tx_dma_buf[0])
{
- kfree(c->tx_dma_buf[0]);
+ free_page((unsigned long)c->tx_dma_buf[0]);
c->tx_dma_buf[0]=NULL;
}
- if(c->tx_dma_buf[1])
- {
- kfree(c->tx_dma_buf[1]);
- c->tx_dma_buf[1]=NULL;
- }
chk=read_zsreg(c,R0);
write_zsreg(c, R3, c->regs[R3]);
z8530_rtsdtr(c,0);
@@ -857,25 +839,21 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
c->rxdma_on = 0;
c->txdma_on = 0;
- c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ /*
+ * Allocate the DMA flip buffers. Limit by page size.
+ * Everyone runs 1500 mtu or less on wan links so this
+ * should be fine.
+ */
+
+ if(c->mtu > PAGE_SIZE/2)
+ return -EMSGSIZE;
+
+ c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
if(c->tx_dma_buf[0]==NULL)
- {
- kfree(c->rx_buf[0]);
- kfree(c->rx_buf[1]);
- c->rx_buf[0]=NULL;
return -ENOBUFS;
- }
- c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
- if(c->tx_dma_buf[1]==NULL)
- {
- kfree(c->tx_dma_buf[0]);
- kfree(c->rx_buf[0]);
- kfree(c->rx_buf[1]);
- c->rx_buf[0]=NULL;
- c->rx_buf[1]=NULL;
- c->tx_dma_buf[0]=NULL;
- return -ENOBUFS;
- }
+
+ c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE/2;
+
c->tx_dma_used=0;
c->dma_num=0;
c->dma_ready=1;
@@ -960,14 +938,9 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
if(c->tx_dma_buf[0])
{
- kfree(c->tx_dma_buf[0]);
+ free_page((unsigned long)c->tx_dma_buf[0]);
c->tx_dma_buf[0]=NULL;
}
- if(c->tx_dma_buf[1])
- {
- kfree(c->tx_dma_buf[1]);
- c->tx_dma_buf[1]=NULL;
- }
chk=read_zsreg(c,R0);
write_zsreg(c, R3, c->regs[R3]);
z8530_rtsdtr(c,0);
@@ -1012,6 +985,8 @@ int z8530_init(struct z8530_dev *dev)
floating IRQ transition when we reset the chip */
dev->chanA.irqs=&z8530_nop;
dev->chanB.irqs=&z8530_nop;
+ dev->chanA.dcdcheck=DCD;
+ dev->chanB.dcdcheck=DCD;
/* Reset the chip */
write_zsreg(&dev->chanA, R9, 0xC0);
udelay(200);
@@ -1104,7 +1079,7 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
c->mtu=1500;
c->max=0;
c->count=0;
- c->status=0; /* Fixme - check DCD now */
+ c->status=read_zsreg(c, R0);
c->sync=1;
write_zsreg(c, R3, c->regs[R3]|RxENABLE);
return 0;
@@ -1251,7 +1226,7 @@ static void z8530_rx_done(struct z8530_channel *c)
* Save the ready state and the buffer currently
* being used as the DMA target
*/
-
+
int ready=c->dma_ready;
unsigned char *rxb=c->rx_buf[c->dma_num];
unsigned long flags;
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index 0b4b48748..dcad711b0 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -270,6 +270,7 @@ struct z8530_channel
struct sk_buff *skb; /* Buffer dptr points into */
struct sk_buff *skb2; /* Pending buffer */
u8 status; /* Current DCD */
+ u8 dcdcheck; /* which bit to check for line */
u8 sync; /* Set if in sync mode */
u8 regs[32]; /* Register map for the chip */
@@ -413,7 +414,7 @@ extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb);
* Standard interrupt vector sets
*/
-struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
+extern struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
/*
* Asynchronous Interfacing
diff --git a/drivers/parport/Config.in b/drivers/parport/Config.in
index 3297568f0..d2af7d8f6 100644
--- a/drivers/parport/Config.in
+++ b/drivers/parport/Config.in
@@ -14,7 +14,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
if [ "$CONFIG_PARPORT_PC" = "y" ]; then
# Don't bother with this if parport_pc is a module; it only affects
# the presence or not of some __init's, which are no-ops for modules.
- if [ "$CONFIG_PCMCIA" != "n" ]; then
+ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
bool ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA
fi
fi
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
index 41dd5abb9..df2779bb5 100644
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -56,6 +56,7 @@ size_t parport_ieee1284_write_compat (struct parport *port,
}
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+ parport_write_control (port, ctl);
while (count < len) {
long expire = jiffies + dev->timeout;
long wait = (HZ + 99) / 100;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 376d01d30..57e6ac684 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -153,9 +153,7 @@ static int get_fifo_residue (struct parport *p)
const struct parport_pc_private *priv = p->physport->private_data;
/* Prevent further data transfer. */
- parport_frob_control (p,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
+ frob_econtrol (p, 0xe0, ECR_TST << 5);
/* Adjust for the contents of the FIFO. */
for (residue = priv->fifo_depth; ; residue--) {
@@ -171,7 +169,6 @@ static int get_fifo_residue (struct parport *p)
/* Reset the FIFO. */
frob_econtrol (p, 0xe0, ECR_PS2 << 5);
- parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
/* Now change to config mode and clean up. FIXME */
frob_econtrol (p, 0xe0, ECR_CNF << 5);
@@ -500,7 +497,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
ret = 0;
if (!time_before (jiffies, expire)) {
/* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
+ printk (KERN_DEBUG "FIFO write timed out\n");
break;
}
ecrval = inb (ECONTROL (port));
@@ -601,7 +598,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
ret = 0;
if (!time_before (jiffies, expire)) {
/* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
+ printk (KERN_DEBUG "DMA write timed out\n");
break;
}
/* Is serviceIntr set? */
@@ -677,9 +674,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
/* Prevent further data transfer. */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
+ frob_econtrol (port, 0xe0, ECR_TST << 5);
/* Adjust for the contents of the FIFO. */
for (written -= priv->fifo_depth; ; written++) {
@@ -692,9 +687,6 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
/* Reset the FIFO and return to PS2 mode. */
frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
- /* De-assert strobe. */
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
}
parport_wait_peripheral (port,
@@ -748,9 +740,7 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
/* Prevent further data transfer. */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
+ frob_econtrol (port, 0xe0, ECR_TST << 5);
/* Adjust for the contents of the FIFO. */
for (written -= priv->fifo_depth; ; written++) {
@@ -764,9 +754,6 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
/* Reset the FIFO and return to PS2 mode. */
frob_econtrol (port, 0xe0, ECR_PS2 << 5);
- /* De-assert strobe. */
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-
/* Host transfer recovery. */
parport_pc_data_reverse (port); /* Must be in PS2 mode */
udelay (5);
@@ -878,7 +865,7 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
ret = 0;
if (!time_before (jiffies, expire)) {
/* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
+ printk (KERN_DEBUG "PIO read timed out\n");
break;
}
ecrval = inb (ECONTROL (port));
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 41829a29c..945b19bd4 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -24,10 +24,10 @@ ifdef CONFIG_PROC_FS
O_OBJS += proc.o
endif
-L_OBJS += compat.o names.o helper.o
+L_OBJS += compat.o names.o setup-res.o setup-bus.o setup-irq.o
ifndef CONFIG_X86
-L_OBJS += syscall.o setup.o
+L_OBJS += syscall.o
endif
include $(TOPDIR)/Rules.make
diff --git a/drivers/pci/helper.c b/drivers/pci/helper.c
deleted file mode 100644
index cd21631e3..000000000
--- a/drivers/pci/helper.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * $Id$
- *
- * drivers/pci/helper.c
- *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
- * This software is free. See the file COPYING for licensing details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-
-int pci_simple_probe (const struct pci_simple_probe_entry *list,
- size_t match_limit, pci_simple_probe_callback cb,
- void *drvr_data)
-{
- struct pci_dev *dev;
- const struct pci_simple_probe_entry *ent;
- size_t matches = 0;
- unsigned short vendor, device;
- int rc;
-
- if (!list || !cb)
- return -1;
-
- dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, NULL);
- while (dev) {
- ent = list;
- while (ent->vendor && ent->device) {
- vendor = ent->vendor;
- device = ent->device;
-
- if (((vendor != 0xFFFF) &&
- (vendor != dev->vendor)) ||
- ((device != 0xFFFF) &&
- (device != dev->device))) {
- ent++;
- continue;
- }
-
- if (((ent->subsys_vendor) &&
- (ent->subsys_vendor != dev->subsystem_vendor)) ||
- ((ent->subsys_device) &&
- (ent->subsys_device != dev->subsystem_device))) {
- ent++;
- continue;
- }
-
- rc = (* cb) (dev, matches, ent, drvr_data);
- if (rc < 0)
- return rc;
-
- matches++;
-
- if (match_limit && match_limit == matches)
- return matches;
-
- break; /* stop list search on first match */
- }
-
- dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, dev);
- }
-
- return matches;
-}
-
-
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1f98f50de..f109cef46 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -9,6 +9,7 @@
* Copyright 1997 -- 2000 Martin Mares <mj@suse.cz>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -195,6 +196,138 @@ pci_enable_device(struct pci_dev *dev)
return 0;
}
+/*
+ * Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+static LIST_HEAD(pci_drivers);
+
+const struct pci_device_id *
+pci_match_device(const struct pci_device_id *ids, struct pci_dev *dev)
+{
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+ (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+ (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
+ (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
+ !((ids->class ^ dev->class) & ids->class_mask))
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
+
+static int
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+ const struct pci_device_id *id;
+
+ if (drv->id_table) {
+ id = pci_match_device(drv->id_table, dev);
+ if (!id)
+ return 0;
+ } else
+ id = NULL;
+ if (drv->probe(dev, id) >= 0) {
+ dev->driver = drv;
+ return 1;
+ }
+ return 0;
+}
+
+int
+pci_register_driver(struct pci_driver *drv)
+{
+ struct pci_dev *dev;
+ int count = 0;
+
+ list_add_tail(&drv->node, &pci_drivers);
+ pci_for_each_dev(dev) {
+ if (!pci_dev_driver(dev))
+ count += pci_announce_device(drv, dev);
+ }
+ return count;
+}
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+ struct pci_dev *dev;
+
+ list_del(&drv->node);
+ pci_for_each_dev(dev) {
+ if (dev->driver == drv) {
+ if (drv->remove)
+ drv->remove(dev);
+ dev->driver = NULL;
+ }
+ }
+}
+
+#ifdef CONFIG_HOTPLUG
+
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+ struct list_head *ln;
+
+ list_add_tail(&dev->bus_list, &bus->devices);
+ list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+ pci_proc_attach_device(dev);
+#endif
+ for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+ struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+ if (drv->remove && pci_announce_device(drv, dev))
+ break;
+ }
+}
+
+static void pci_free_resources(struct pci_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = dev->resource + i;
+ if (res->parent)
+ release_resource(res);
+ }
+}
+
+void
+pci_remove_device(struct pci_dev *dev)
+{
+ if (dev->driver->remove)
+ dev->driver->remove(dev);
+ dev->driver = NULL;
+ list_del(&dev->bus_list);
+ list_del(&dev->global_list);
+ pci_free_resources(dev);
+#ifdef CONFIG_PROC_FS
+ pci_proc_detach_device(dev);
+#endif
+}
+
+#endif
+
+static struct pci_driver pci_compat_driver = {
+ name: "compat"
+};
+
+struct pci_driver *
+pci_dev_driver(struct pci_dev *dev)
+{
+ if (dev->driver)
+ return dev->driver;
+ else {
+ int i;
+ for(i=0; i<=PCI_ROM_RESOURCE; i++)
+ if (dev->resource[i].flags & IORESOURCE_BUSY)
+ return &pci_compat_driver;
+ }
+ return NULL;
+}
+
/*
* This interrupt-safe spinlock protects all accesses to PCI
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 4bac2162d..49e031869 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -356,6 +356,12 @@
2001 79c978 [HomePNA]
2020 53c974 [PCscsi]
2040 79c974
+ 7006 IronGate Host
+ 7403 Viper Power Management
+ 7408 Viper ISA
+ 7409 Viper IDE
+ 740B Viper ACPI
+ 740C Viper USB
1023 Trident Microsystems
0194 82C194
2000 4DWave DX
@@ -931,8 +937,9 @@
0640 PCI0640
0643 PCI0643
0646 PCI0646
- 0650 PBC0650A
0647 PCI0647
+ 0648 PCI0648
+ 0650 PBC0650A
0670 USB0670
0673 USB0673
1096 Alacron
diff --git a/drivers/pci/pcisyms.c b/drivers/pci/pcisyms.c
index 28adb8e8a..64b6a0f3e 100644
--- a/drivers/pci/pcisyms.c
+++ b/drivers/pci/pcisyms.c
@@ -24,13 +24,15 @@ EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
EXPORT_SYMBOL(pci_set_master);
-EXPORT_SYMBOL(pci_simple_probe);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_assign_resource);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
+
+#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_setup_device);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(pci_proc_attach_device);
-EXPORT_SYMBOL(pci_proc_detach_device);
+EXPORT_SYMBOL(pci_insert_device);
+EXPORT_SYMBOL(pci_remove_device);
#endif
/* Obsolete functions */
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index e2cb9e9d6..b687d6122 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -224,6 +224,7 @@ get_pci_dev_info(char *buf, char **start, off_t pos, int count)
cnt = 0;
pci_for_each_dev(dev) {
+ struct pci_driver *drv = pci_dev_driver(dev);
len = sprintf(buf, "%02x%02x\t%04x%04x\t%x",
dev->bus->number,
dev->devfn,
@@ -237,6 +238,9 @@ get_pci_dev_info(char *buf, char **start, off_t pos, int count)
for(i=0; i<7; i++)
len += sprintf(buf+len, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ?
dev->resource[i].end - dev->resource[i].start + 1 : 0);
+ buf[len++] = '\t';
+ if (drv)
+ len += sprintf(buf+len, "%s", drv->name);
buf[len++] = '\n';
at += len;
if (at >= pos) {
diff --git a/drivers/pci/setup.c b/drivers/pci/setup-bus.c
index 96d35c2ba..401185890 100644
--- a/drivers/pci/setup.c
+++ b/drivers/pci/setup-bus.c
@@ -1,5 +1,5 @@
/*
- * drivers/pci/setup.c
+ * drivers/pci/setup-bus.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
@@ -9,8 +9,6 @@
* Support routines for initializing a PCI subsystem.
*/
-/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
-
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -26,129 +24,6 @@
# 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) {
- err = request_resource(root, res);
- if (err) {
- printk(KERN_ERR "PCI: Address space collision on "
- "region %d of device %s [%lx:%lx]\n",
- resource, dev->name, res->start, res->end);
- }
- } else {
- printk(KERN_ERR "PCI: No parent found for 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. */
- res->end -= res->start;
- res->start = 0;
- 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 + 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, pcibios_align_resource, dev) < 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. */
-
- if (dev->rom_base_reg) {
- pci_read_config_dword(dev, dev->rom_base_reg, &reg);
- reg &= ~PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, dev->rom_base_reg, reg);
- dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
- }
-
- /* 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;
-
- pci_for_each_dev(dev) {
- pdev_assign_unassigned_resources(dev, min_io, min_mem);
- }
-}
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
@@ -279,53 +154,3 @@ pci_set_bus_ranges(void)
for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
pbus_set_ranges(pci_bus_b(ln), NULL);
}
-
-static void __init
-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;
- pci_for_each_dev(dev) {
- pdev_fixup_irq(dev, swizzle, map_irq);
- }
-}
-
-int
-pcibios_enable_device(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
new file mode 100644
index 000000000..f15eba9dd
--- /dev/null
+++ b/drivers/pci/setup-irq.c
@@ -0,0 +1,71 @@
+/*
+ * drivers/pci/setup-irq.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 <linux/cache.h>
+
+
+#define DEBUG_CONFIG 0
+#if DEBUG_CONFIG
+# define DBGC(args) printk args
+#else
+# define DBGC(args)
+#endif
+
+
+static void __init
+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;
+ pci_for_each_dev(dev) {
+ pdev_fixup_irq(dev, swizzle, map_irq);
+ }
+}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
new file mode 100644
index 000000000..84639a5a2
--- /dev/null
+++ b/drivers/pci/setup-res.c
@@ -0,0 +1,164 @@
+/*
+ * drivers/pci/setup-res.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.
+ */
+
+/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/cache.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) {
+ err = request_resource(root, res);
+ if (err) {
+ printk(KERN_ERR "PCI: Address space collision on "
+ "region %d of device %s [%lx:%lx]\n",
+ resource, dev->name, res->start, res->end);
+ }
+ } else {
+ printk(KERN_ERR "PCI: No parent found for region %d "
+ "of device %s\n", resource, dev->name);
+ }
+
+ return err;
+}
+
+int
+pci_assign_resource(struct pci_dev *dev, int i)
+{
+ struct resource *root, *res;
+ unsigned long size, min;
+
+ res = &dev->resource[i];
+
+ /* Determine the root we allocate from. */
+ res->end -= res->start;
+ res->start = 0;
+ root = pci_find_parent_resource(dev, res);
+ if (root == NULL) {
+ printk(KERN_ERR "PCI: Cannot find parent resource for "
+ "device %s\n", dev->slot_name);
+ return -EINVAL;
+ }
+
+ min = (res->flags & IORESOURCE_IO ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM);
+ size = res->end + 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,
+ pcibios_align_resource, dev) < 0) {
+ printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n",
+ i, dev->name);
+ return -EBUSY;
+ }
+
+ 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);
+
+ return 0;
+}
+
+static void
+pdev_assign_unassigned_resources(struct pci_dev *dev)
+{
+ 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 *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;
+
+ pci_assign_resource(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. */
+
+ if (dev->rom_base_reg) {
+ pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+ reg &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, dev->rom_base_reg, reg);
+ dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
+ }
+
+ /* 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(void)
+{
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ pdev_assign_unassigned_resources(dev);
+ }
+}
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index a58098024..c935efd9a 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -120,7 +120,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
err = get_user(word, (u16 *)buf);
if (err)
break;
- err = pci_write_config_byte(dev, off, word);
+ err = pci_write_config_word(dev, off, word);
if (err != PCIBIOS_SUCCESSFUL)
err = -EIO;
break;
@@ -129,7 +129,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
err = get_user(dword, (u32 *)buf);
if (err)
break;
- pci_write_config_byte(dev, off, dword);
+ err = pci_write_config_dword(dev, off, dword);
if (err != PCIBIOS_SUCCESSFUL)
err = -EIO;
break;
diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c
index 269f5c337..1c0a21146 100644
--- a/drivers/pcmcia/bulkmem.c
+++ b/drivers/pcmcia/bulkmem.c
@@ -2,7 +2,7 @@
PCMCIA Bulk Memory Services
- bulkmem.c 1.33 1999/10/25 20:03:33
+ bulkmem.c 1.34 1999/11/17 01:37:55
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -179,7 +179,7 @@ static void retry_erase(erase_busy_t *busy, u_int cause)
}
busy->client->event_callback_args.info = erase;
EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
- kfree_s(busy, sizeof(*busy));
+ kfree(busy);
/* Resubmit anything waiting for a request to finish */
wake_up_interruptible(&mtd->mtd_req);
retry_erase_list(&mtd->erase_busy, 0);
@@ -484,6 +484,7 @@ int pcmcia_register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header,
if ((handle == NULL) || CHECK_HANDLE(*handle))
return CS_BAD_HANDLE;
queue = kmalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue) return CS_OUT_OF_RESOURCE;
queue->eraseq_magic = ERASEQ_MAGIC;
queue->handle = *handle;
queue->count = header->QueueEntryCnt;
@@ -502,7 +503,7 @@ int pcmcia_deregister_erase_queue(eraseq_handle_t eraseq)
if (i < eraseq->count)
return CS_BUSY;
eraseq->eraseq_magic = 0;
- kfree_s(eraseq, sizeof(*eraseq));
+ kfree(eraseq);
return CS_SUCCESS;
} /* deregister_erase_queue */
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 88175e08d..74114b4fe 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -99,11 +99,6 @@ static int pc_debug = PCMCIA_DEBUG;
#define PCDATA_CODE_TYPE 0x0014
#define PCDATA_INDICATOR 0x0015
-#ifndef CONFIG_PROC_FS
-#define pci_proc_attach_device(dev) do { } while (0)
-#define pci_proc_detach_device(dev) do { } while (0)
-#endif
-
typedef struct cb_config_t {
struct pci_dev dev;
} cb_config_t;
@@ -111,39 +106,12 @@ typedef struct cb_config_t {
/*=====================================================================
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.
+ image number and an offset within that image. 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;
@@ -261,6 +229,21 @@ fail:
=====================================================================*/
+static int cb_assign_irq(u32 mask)
+{
+ int irq, try;
+
+ for (try = 0; try < 2; try++) {
+ for (irq = 1; irq < 32; irq++) {
+ if ((mask >> irq) & 1) {
+ if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0)
+ return irq;
+ }
+ }
+ }
+ return 0;
+}
+
int cb_alloc(socket_info_t * s)
{
struct pci_bus *bus;
@@ -268,6 +251,7 @@ int cb_alloc(socket_info_t * s)
u_short vend, v, dev;
u_char i, hdr, fn;
cb_config_t *c;
+ int irq;
bus = s->cap.cb_dev->subordinate;
memset(&tmp, 0, sizeof(tmp));
@@ -297,8 +281,10 @@ int cb_alloc(socket_info_t * s)
return CS_OUT_OF_RESOURCE;
memset(c, 0, fn * sizeof(struct cb_config_t));
+ irq = s->cap.pci_irq;
for (i = 0; i < fn; i++) {
struct pci_dev *dev = &c[i].dev;
+ u8 irq_pin;
int r;
dev->bus = bus;
@@ -306,41 +292,35 @@ int cb_alloc(socket_info_t * s)
dev->devfn = i;
dev->vendor = vend;
pci_readw(dev, PCI_DEVICE_ID, &dev->device);
- dev->hdr_type = hdr;
+ dev->hdr_type = hdr & 0x7f;
pci_setup_device(dev);
+
/* FIXME: Do we need to enable the expansion ROM? */
for (r = 0; r < 7; r++) {
struct resource *res = dev->resource + r;
- if (res->flags) {
- /* Unset resource address, assign new one! */
- res->end -= res->start;
- res->start = 0;
+ if (res->flags)
pci_assign_resource(dev, r);
- }
}
-
- list_add_tail(&dev->bus_list, &bus->devices);
- list_add_tail(&dev->global_list, &pci_devices);
- pci_proc_attach_device(dev);
pci_enable_device(dev);
+
+ /* Does this function have an interrupt at all? */
+ pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
+ if (irq_pin) {
+ if (!irq)
+ irq = cb_assign_irq(s->cap.irq_mask);
+ dev->irq = irq;
+ pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
+ }
+
+ pci_insert_device(dev, bus);
}
s->cb_config = c;
+ s->irq.AssignedIRQ = irq;
return CS_SUCCESS;
}
-static void free_resources(struct pci_dev *dev)
-{
- int i;
-
- for (i = 0; i < 7; i++) {
- struct resource *res = dev->resource + i;
- if (res->parent)
- release_resource(res);
- }
-}
-
void cb_free(socket_info_t * s)
{
cb_config_t *c = s->cb_config;
@@ -349,14 +329,9 @@ void cb_free(socket_info_t * s)
int i;
s->cb_config = NULL;
- for(i=0; i<s->functions; i++) {
- struct pci_dev *dev = &c[i].dev;
+ for (i = 0 ; i < s->functions ; i++)
+ pci_remove_device(&c[i].dev);
- list_del(&dev->bus_list);
- list_del(&dev->global_list);
- free_resources(dev);
- pci_proc_detach_device(dev);
- }
kfree(c);
printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
}
@@ -374,54 +349,8 @@ void cb_free(socket_info_t * s)
======================================================================*/
-static int cb_assign_irq(u32 mask)
-{
- int irq, try;
-
- for (try = 0; try < 2; try++) {
- for (irq = 1; irq < 32; irq++) {
- if ((mask >> irq) & 1) {
- if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0)
- return irq;
- }
- }
- }
- return 0;
-}
-
int cb_config(socket_info_t * s)
{
- cb_config_t *c = s->cb_config;
- u_char fn = s->functions;
- int i, irq;
-
- printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number);
-
- /*
- * If we have a PCI interrupt for the bridge,
- * then use that..
- */
- irq = s->cap.pci_irq;
-
- for (i = 0; i < fn; i++) {
- struct pci_dev *dev = &c[i].dev;
- u8 irq_pin;
-
- /* Does this function have an interrupt at all? */
- pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
- if (!irq_pin)
- continue;
-
- if (!irq) {
- irq = cb_assign_irq(s->cap.irq_mask);
- if (!irq)
- return CS_OUT_OF_RESOURCE;
- }
-
- dev->irq = irq;
- pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
- }
- s->irq.AssignedIRQ = irq;
return CS_SUCCESS;
}
diff --git a/drivers/pcmcia/cb_enabler.c b/drivers/pcmcia/cb_enabler.c
index bb8fe17b2..0e5ddeb93 100644
--- a/drivers/pcmcia/cb_enabler.c
+++ b/drivers/pcmcia/cb_enabler.c
@@ -1,8 +1,8 @@
/*======================================================================
- Cardbus device enabler
+ CardBus device enabler
- cb_enabler.c 1.25 1999/10/25 20:03:33
+ cb_enabler.c 1.28 1999/12/09 20:57:37
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -58,11 +58,14 @@ 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.25 1999/10/25 20:03:33 (David Hinds)";
+"cb_enabler.c 1.28 1999/12/09 20:57:37 (David Hinds)";
#else
#define DEBUG(n, args...) do { } while (0)
#endif
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("CardBus stub enabler module");
+
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
@@ -126,10 +129,11 @@ struct dev_link_t *cb_attach(int n)
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));
+ if (!link) return NULL;
+ MOD_INC_USE_COUNT;
+ memset(link, 0, sizeof(struct dev_link_t));
link->conf.IntType = INT_CARDBUS;
link->conf.Vcc = 33;
@@ -142,7 +146,7 @@ struct dev_link_t *cb_attach(int n)
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 =
+ client_reg.EventMask = CS_EVENT_RESET_PHYSICAL |
CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
@@ -186,7 +190,7 @@ static void cb_detach(dev_link_t *link)
pcmcia_deregister_client(link->handle);
*linkp = link->next;
- kfree_s(link, sizeof(struct dev_link_t));
+ kfree(link);
MOD_DEC_USE_COUNT;
}
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index eb287bee9..acca17316 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -2,7 +2,7 @@
PCMCIA Card Information Structure parser
- cistpl.c 1.74 1999/11/08 20:47:02
+ cistpl.c 1.77 2000/01/16 19:19:01
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -52,6 +52,7 @@
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/bulkmem.h>
+#include <pcmcia/cisreg.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
#include "rsrc_mgr.h"
@@ -83,12 +84,15 @@ static const u_int exponent[] = {
======================================================================*/
+/* Bits in attr field */
+#define IS_ATTR 1
+#define IS_INDIRECT 8
+
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;
+ u_char *sys, *buf = ptr;
DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (setup_cis_mem(s) != 0) {
@@ -96,47 +100,81 @@ void read_cis_mem(socket_info_t *s, int attr, u_int addr,
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) {
+ sys = s->cis_virt;
+
+ if (attr & IS_INDIRECT) {
+ /* Indirect accesses use a bunch of special registers at fixed
+ locations in common memory */
+ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+ if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+ mem->card_start = 0;
s->ss_entry->set_mem_map(s->sock, 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);
+ bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+ bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+ bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+ bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+ bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+ for ( ; len > 0; len--, buf++)
+ *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0);
+ } else {
+ u_int inc = 1;
+ if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+ sys += (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->set_mem_map(s->sock, mem);
+ for ( ; len > 0; len--, buf++, sys += inc) {
+ if (sys == s->cis_virt+s->cap.map_size) break;
+ *buf = bus_readb(s->cap.bus, sys);
+ }
+ mem->card_start += s->cap.map_size;
}
- mem->card_start += s->cap.map_size;
}
+ DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+ *(u_char *)(ptr+0), *(u_char *)(ptr+1),
+ *(u_char *)(ptr+2), *(u_char *)(ptr+3));
}
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;
+ u_char *sys, *buf = ptr;
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) {
+ mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
+ sys = s->cis_virt;
+
+ if (attr & IS_INDIRECT) {
+ /* Indirect accesses use a bunch of special registers at fixed
+ locations in common memory */
+ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+ if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+ mem->card_start = 0;
s->ss_entry->set_mem_map(s->sock, 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);
+ bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+ bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+ bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+ bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+ bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+ for ( ; len > 0; len--, buf++)
+ bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0);
+ } else {
+ int inc = 1;
+ if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+ sys += (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->set_mem_map(s->sock, mem);
+ for ( ; len > 0; len--, buf++, sys += inc) {
+ if (sys == s->cis_virt+s->cap.map_size) break;
+ bus_writeb(s->cap.bus, *buf, sys);
+ }
+ mem->card_start += s->cap.map_size;
}
- mem->card_start += s->cap.map_size;
}
}
@@ -342,10 +380,10 @@ int pcmcia_replace_cis(client_handle_t handle, cisdump_t *cis)
======================================================================*/
typedef struct tuple_flags {
- u_int link_space:3;
+ u_int link_space:4;
u_int has_link:1;
u_int mfc_fn:3;
- u_int space:3;
+ u_int space:4;
} tuple_flags;
#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
@@ -469,18 +507,24 @@ int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
(link[0] == CISTPL_LONGLINK_C) ||
(link[0] == CISTPL_LONGLINK_MFC) ||
(link[0] == CISTPL_LINKTARGET) ||
+ (link[0] == CISTPL_INDIRECT) ||
(link[0] == CISTPL_NO_LINK)) {
switch (link[0]) {
case CISTPL_LONGLINK_A:
HAS_LINK(tuple->Flags) = 1;
- LINK_SPACE(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
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;
+ LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
break;
+ case CISTPL_INDIRECT:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
+ tuple->LinkOffset = 0;
+ break;
case CISTPL_LONGLINK_MFC:
tuple->LinkOffset = ofs + 3;
LINK_SPACE(tuple->Flags) = attr;
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index d44d505ca..bd671c1b2 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -2,7 +2,7 @@
PCMCIA Card Services -- core services
- cs.c 1.235 1999/11/11 17:52:05
+ cs.c 1.247 2000/01/15 04:30:35
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -59,7 +59,6 @@
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/bus_ops.h>
-
#include "cs_internal.h"
#include "rsrc_mgr.h"
@@ -72,28 +71,40 @@ static int handle_apm_event(apm_event_t event);
int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
static const char *version =
-"cs.c 1.235 1999/11/11 17:52:05 (David Hinds)";
+"cs.c 1.247 2000/01/15 04:30:35 (David Hinds)";
#endif
-static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
-#ifdef MODULE
-static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION;
-#endif
-static const char *options = "options: "
#ifdef CONFIG_PCI
-" [pci]"
+#define PCI_OPT " [pci]"
+#else
+#define PCI_OPT ""
#endif
#ifdef CONFIG_CARDBUS
-" [cardbus]"
+#define CB_OPT " [cardbus]"
+#else
+#define CB_OPT ""
#endif
#ifdef CONFIG_APM
-" [apm]"
+#define APM_OPT " [apm]"
+#else
+#define APM_OPT ""
#endif
#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \
- !defined(CONFIG_APM) && !defined(CONFIG_PNP_BIOS)
-" none"
+ !defined(CONFIG_APM)
+#define OPTIONS " none"
+#else
+#define OPTIONS PCI_OPT CB_OPT APM_OPT
+#endif
+
+static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+#ifdef MODULE
+static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION;
#endif
-;
+static const char *options = "options: " OPTIONS;
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE
+ "\n options:" OPTIONS);
/*====================================================================*/
@@ -263,11 +274,6 @@ static int set_socket(socket_info_t *s, socket_state_t *state)
return s->ss_entry->set_socket(s->sock, state);
}
-static int get_io_map(socket_info_t *s, struct pccard_io_map *io)
-{
- return s->ss_entry->get_io_map(s->sock, io);
-}
-
static int set_io_map(socket_info_t *s, struct pccard_io_map *io)
{
return s->ss_entry->set_io_map(s->sock, io);
@@ -734,18 +740,18 @@ static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base,
int i;
ioaddr_t try, align;
- align = (*base) ? (1<<lines) : 1;
+ align = (*base) ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
- printk(KERN_INFO "odd IO request: num %04x align %04x\n",
- num, align);
- if (*base)
+ if (*base) {
+ DEBUG(0, "odd IO request: num %04x align %04x\n",
+ num, align);
align = 0;
- else
+ } else
while (align && (align < num)) align <<= 1;
}
if (*base & ~(align-1)) {
- printk(KERN_INFO "odd IO request: base %04x align %04x\n",
- *base, align);
+ DEBUG(0, "odd IO request: base %04x align %04x\n",
+ *base, align);
align = 0;
}
for (i = 0; i < MAX_IO_WIN; i++) {
@@ -862,6 +868,7 @@ int pcmcia_bind_device(bind_req_t *req)
s = SOCKET(req);
client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);
+ if (!client) return CS_OUT_OF_RESOURCE;
memset(client, '\0', sizeof(client_t));
client->client_magic = CLIENT_MAGIC;
strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
@@ -1122,18 +1129,18 @@ int pcmcia_get_window(window_handle_t *handle, int idx, win_req_t *req)
if (win->ctl.flags & MAP_ACTIVE)
req->Attributes |= WIN_ENABLE;
if (win->ctl.flags & MAP_16BIT)
- req->Attributes |= WIN_DATA_WIDTH;
+ req->Attributes |= WIN_DATA_WIDTH_16;
if (win->ctl.flags & MAP_USE_WAIT)
req->Attributes |= WIN_USE_WAIT;
*handle = win;
return CS_SUCCESS;
} /* get_window */
-int pcmcia_get_first_window(client_handle_t *handle, win_req_t *req)
+int pcmcia_get_first_window(window_handle_t *win, win_req_t *req)
{
- if ((handle == NULL) || CHECK_HANDLE(*handle))
+ if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC))
return CS_BAD_HANDLE;
- return pcmcia_get_window((window_handle_t *)handle, 0, req);
+ return pcmcia_get_window(win, 0, req);
}
int pcmcia_get_next_window(window_handle_t *win, win_req_t *req)
@@ -1143,6 +1150,29 @@ int pcmcia_get_next_window(window_handle_t *win, win_req_t *req)
return pcmcia_get_window(win, (*win)->index+1, req);
}
+/*=====================================================================
+
+ Return the PCI device associated with a card..
+
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+struct pci_bus *pcmcia_lookup_bus(client_handle_t handle)
+{
+ socket_info_t *s;
+
+ if (CHECK_HANDLE(handle))
+ return NULL;
+ s = SOCKET(handle);
+ if (!(s->state & SOCKET_CARDBUS))
+ return NULL;
+
+ return s->cap.cb_dev->subordinate;
+}
+
+#endif
+
/*======================================================================
Get the current socket state bits. We don't support the latched
@@ -1308,7 +1338,7 @@ int pcmcia_modify_window(window_handle_t win, modwin_t *req)
win->ctl.flags |= MAP_ATTRIB;
if (req->Attributes & WIN_ENABLE)
win->ctl.flags |= MAP_ACTIVE;
- if (req->Attributes & WIN_DATA_WIDTH)
+ if (req->Attributes & WIN_DATA_WIDTH_16)
win->ctl.flags |= MAP_16BIT;
if (req->Attributes & WIN_USE_WAIT)
win->ctl.flags |= MAP_USE_WAIT;
@@ -1403,7 +1433,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
int pcmcia_release_configuration(client_handle_t handle)
{
- pccard_io_map io;
+ pccard_io_map io = { 0, 0, 0, 0, 1 };
socket_info_t *s;
int i;
@@ -1437,8 +1467,6 @@ int pcmcia_release_configuration(client_handle_t handle)
if (s->io[i].Config != 0)
continue;
io.map = i;
- get_io_map(s, &io);
- io.flags &= ~MAP_ACTIVE;
set_io_map(s, &io);
}
c->state &= ~CONFIG_LOCKED;
@@ -1840,7 +1868,8 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
{
socket_info_t *s;
window_t *win;
- int w, align;
+ u_long align;
+ int w;
if (CHECK_HANDLE(*handle))
return CS_BAD_HANDLE;
@@ -1850,16 +1879,25 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
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;
+ align = (((s->cap.features & SS_CAP_MEM_ALIGN) ||
+ (req->Attributes & WIN_STRICT_ALIGN)) ?
+ req->Size : s->cap.map_size);
+ if (req->Size & (s->cap.map_size-1))
+ return CS_BAD_SIZE;
+ if (req->Base & (align-1))
+ return CS_BAD_BASE;
+ if (req->Base)
+ align = 0;
/* Allocate system memory window */
+ for (w = 0; w < MAX_WIN; w++)
+ if (!(s->state & SOCKET_WIN_REQ(w))) break;
+ if (w == MAX_WIN)
+ return CS_OUT_OF_RESOURCE;
+
win = &s->win[w];
win->magic = WINDOW_MAGIC;
win->index = w;
@@ -1867,10 +1905,8 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
win->sock = s;
win->base = req->Base;
win->size = req->Size;
- align = ((s->cap.features & SS_CAP_MEM_ALIGN) ||
- (req->Attributes & WIN_STRICT_ALIGN));
- if (find_mem_region(&win->base, win->size,
- (align ? req->Size : s->cap.map_size),
+
+ if (find_mem_region(&win->base, win->size, align,
(req->Attributes & WIN_MAP_BELOW_1MB) ||
!(s->cap.features & SS_CAP_PAGE_REGS),
(*handle)->dev_info))
@@ -1886,7 +1922,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
win->ctl.flags |= MAP_ATTRIB;
if (req->Attributes & WIN_ENABLE)
win->ctl.flags |= MAP_ACTIVE;
- if (req->Attributes & WIN_DATA_WIDTH)
+ if (req->Attributes & WIN_DATA_WIDTH_16)
win->ctl.flags |= MAP_16BIT;
if (req->Attributes & WIN_USE_WAIT)
win->ctl.flags |= MAP_USE_WAIT;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5a9b1a4e7..f85e2b4f9 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -2,7 +2,7 @@
PC Card Driver Services
- ds.c 1.100 1999/11/08 20:47:02
+ ds.c 1.104 2000/01/11 01:18:02
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -46,6 +46,7 @@
#include <linux/ioctl.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
+#include <linux/pci.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
@@ -59,11 +60,14 @@ 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.100 1999/11/08 20:47:02 (David Hinds)";
+"ds.c 1.104 2000/01/11 01:18:02 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
+
/*====================================================================*/
typedef struct driver_info_t {
@@ -154,6 +158,7 @@ int register_pccard_driver(dev_info_t *dev_info,
break;
if (!driver) {
driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+ if (!driver) return -ENOMEM;
strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
driver->use_count = 0;
driver->status = init_status;
@@ -192,7 +197,7 @@ int unregister_pccard_driver(dev_info_t *dev_info)
DEV_NAME_LEN) != 0))
d = &(*d)->next;
if (*d == NULL)
- return -1;
+ return -ENODEV;
target = *d;
if (target->use_count == 0) {
@@ -376,6 +381,7 @@ static int bind_request(int i, bind_info_t *bind_info)
break;
if (driver == NULL) {
driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+ if (!driver) return -ENOMEM;
strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN);
driver->use_count = 0;
driver->next = root_driver;
@@ -429,15 +435,55 @@ 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;
-
+
+#ifdef CONFIG_CARDBUS
+ /*
+ * Some unbelievably ugly code to associate the PCI cardbus
+ * device and its driver with the PCMCIA "bind" information.
+ */
+ {
+ struct pci_bus *bus;
+
+ bus = pcmcia_lookup_bus(s->handle);
+ if (bus) {
+ struct list_head *list;
+ struct pci_dev *dev = NULL;
+
+ list = bus->devices.next;
+ while (list != &bus->devices) {
+ struct pci_dev *pdev = pci_dev_b(list);
+ list = list->next;
+
+ if (first) {
+ dev = pdev;
+ break;
+ }
+
+ /* Try to handle "next" here some way? */
+ }
+ if (dev && dev->driver) {
+ strncpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+ bind_info->name[DEV_NAME_LEN-1] = '\0';
+ bind_info->major = 0;
+ bind_info->minor = 0;
+ bind_info->next = NULL;
+ return 0;
+ }
+ }
+ }
+#endif
+
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))
+
+ if (b->instance == NULL)
return -EAGAIN;
+ if (b->instance->state & DEV_CONFIG_PENDING)
+ return -EAGAIN;
+
if (first)
node = b->instance->dev;
else
@@ -481,11 +527,11 @@ static int unbind_request(int i, bind_info_t *bind_info)
for (d = &root_driver; *d; d = &((*d)->next))
if (c->driver == *d) break;
*d = (*d)->next;
- kfree_s(c->driver, sizeof(driver_info_t));
+ kfree(c->driver);
}
}
*b = c->next;
- kfree_s(c, sizeof(socket_bind_t));
+ kfree(c);
return 0;
} /* unbind_request */
@@ -513,8 +559,9 @@ static int ds_open(struct inode *inode, struct file *file)
s->state |= SOCKET_BUSY;
}
- MOD_INC_USE_COUNT;
user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+ if (!user) return -ENOMEM;
+ MOD_INC_USE_COUNT;
user->event_tail = user->event_head = 0;
user->next = s->user;
user->user_magic = USER_MAGIC;
@@ -552,7 +599,7 @@ static int ds_release(struct inode *inode, struct file *file)
return 0;
*link = user->next;
user->user_magic = 0;
- kfree_s(user, sizeof(user_info_t));
+ kfree(user);
MOD_DEC_USE_COUNT;
return 0;
@@ -663,7 +710,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
/* Permission check */
- if (!(cmd & IOC_OUT) && !suser())
+ if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
return -EPERM;
if (cmd & IOC_IN) {
@@ -732,7 +779,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = pcmcia_insert_card(s->handle, NULL);
break;
case DS_ACCESS_CONFIGURATION_REGISTER:
- if ((buf.conf_reg.Action == CS_WRITE) && !suser())
+ if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
return -EPERM;
ret = pcmcia_access_configuration_register(s->handle, &buf.conf_reg);
break;
@@ -757,7 +804,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = pcmcia_replace_cis(s->handle, &buf.cisdump);
break;
case DS_BIND_REQUEST:
- if (!suser()) return -EPERM;
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
err = bind_request(i, &buf.bind_info);
break;
case DS_GET_DEVICE_INFO:
@@ -806,17 +853,12 @@ static int ds_ioctl(struct inode * inode, struct file * file,
/*====================================================================*/
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 */
+ open: ds_open,
+ release: ds_release,
+ ioctl: ds_ioctl,
+ read: ds_read,
+ write: ds_write,
+ poll: ds_poll
};
EXPORT_SYMBOL(register_pccard_driver);
@@ -846,6 +888,7 @@ int __init init_pcmcia_ds(void)
sockets = serv.Count;
socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
+ if (!socket_table) return -1;
for (i = 0, s = socket_table; i < sockets; i++, s++) {
s->state = 0;
s->user = NULL;
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 8c96585c6..73c177d8d 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -66,7 +66,6 @@
/* PCI-bus controllers */
#include "old-yenta.h"
-#include "ti113x.h"
#include "smc34c90.h"
#include "topic.h"
diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
index 51981e41e..3f4463e75 100644
--- a/drivers/pcmcia/pci_socket.c
+++ b/drivers/pcmcia/pci_socket.c
@@ -70,9 +70,8 @@ static int pci_inquire_socket(unsigned int sock, socket_cap_t *cap)
{
pci_socket_t *socket = pci_socket_array + sock;
- if (socket->op && socket->op->inquire)
- return socket->op->inquire(socket, cap);
- return -EINVAL;
+ *cap = socket->cap;
+ return 0;
}
static int pci_get_status(unsigned int sock, unsigned int *value)
@@ -166,8 +165,10 @@ static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_
{
pci_socket_t *socket = nr + pci_socket_array;
+ memset(socket, 0, sizeof(*socket));
socket->dev = dev;
socket->op = ops;
+ init_waitqueue_head(&socket->wait);
return socket->op->open(socket);
}
diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h
index 41ea4ec09..8db7c68b5 100644
--- a/drivers/pcmcia/pci_socket.h
+++ b/drivers/pcmcia/pci_socket.h
@@ -4,6 +4,9 @@
* (C) Copyright 1999 Linus Torvalds
*/
+#ifndef __PCI_SOCKET_H
+#define __PCI_SOCKET_H
+
struct pci_socket_ops;
typedef struct pci_socket {
@@ -14,7 +17,11 @@ typedef struct pci_socket {
void *info;
struct pci_socket_ops *op;
socket_cap_t cap;
- struct timer_list timer;
+ wait_queue_head_t wait;
+ unsigned int events;
+
+ /* A few words of private data for the low-level driver.. */
+ unsigned int private[8];
} pci_socket_t;
struct pci_socket_ops {
@@ -23,7 +30,6 @@ struct pci_socket_ops {
int (*init)(struct pci_socket *);
int (*suspend)(struct pci_socket *);
- int (*inquire)(struct pci_socket *, socket_cap_t *cap);
int (*get_status)(struct pci_socket *, unsigned int *);
int (*get_socket)(struct pci_socket *, socket_state_t *);
int (*set_socket)(struct pci_socket *, socket_state_t *);
@@ -37,3 +43,4 @@ struct pci_socket_ops {
extern struct pci_socket_ops yenta_operations;
extern struct pci_socket_ops ricoh_operations;
+#endif
diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
index 8cfd30dac..3084dd5b9 100644
--- a/drivers/pcmcia/ricoh.h
+++ b/drivers/pcmcia/ricoh.h
@@ -30,6 +30,8 @@
#ifndef _LINUX_RICOH_H
#define _LINUX_RICOH_H
+#include <linux/config.h>
+
#define RF5C_MODE_CTL 0x1f /* Mode control */
#define RF5C_PWR_CTL 0x2f /* Mixed voltage control */
#define RF5C_CHIP_ID 0x3a /* Chip identification */
@@ -70,25 +72,6 @@
/* 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
@@ -129,4 +112,55 @@
#define RL5C4XX_HOLD_MASK 0x1c00
#define RL5C4XX_HOLD_SHIFT 10
+#ifdef __YENTA_H
+
+#define rl_misc(socket) ((socket)->private[0])
+#define rl_ctl(socket) ((socket)->private[1])
+#define rl_io(socket) ((socket)->private[2])
+#define rl_mem(socket) ((socket)->private[3])
+
+/*
+ * Magic Ricoh initialization code.. Save state at
+ * beginning, re-initialize it after suspend.
+ */
+static int ricoh_open(pci_socket_t *socket)
+{
+ rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
+ rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
+ rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
+ rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
+
+ /* Set the default timings, don't trust the original values */
+ rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+ return 0;
+}
+
+static int ricoh_init(pci_socket_t *socket)
+{
+ yenta_init(socket);
+
+ config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
+ config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
+ config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
+ config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+ return 0;
+}
+
+static struct pci_socket_ops ricoh_ops = {
+ ricoh_open,
+ yenta_close,
+ ricoh_init,
+ yenta_suspend,
+ yenta_get_status,
+ yenta_get_socket,
+ yenta_set_socket,
+ yenta_get_io_map,
+ yenta_set_io_map,
+ yenta_get_mem_map,
+ yenta_set_mem_map,
+ yenta_proc_setup
+};
+
+#endif /* CONFIG_CARDBUS */
+
#endif /* _LINUX_RICOH_H */
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 569ff8678..d059c4fdb 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -2,7 +2,7 @@
Resource management routines
- rsrc_mgr.c 1.76 1999/11/08 20:47:02
+ rsrc_mgr.c 1.77 1999/11/16 03:32:59
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -124,10 +124,11 @@ static int add_interval(resource_map_t *map, u_long base, u_long num)
break;
}
q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+ if (!q) return CS_OUT_OF_RESOURCE;
q->base = base; q->num = num;
q->next = p->next; p->next = q;
- return 0;
-} /* add_interval */
+ return CS_SUCCESS;
+}
/*====================================================================*/
@@ -158,6 +159,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num)
} else {
/* Split the block into two pieces */
p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+ if (!p) return CS_OUT_OF_RESOURCE;
p->base = base+num;
p->num = q->base+q->num - p->base;
q->num = base - q->base;
@@ -165,8 +167,8 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num)
}
}
}
- return 0;
-} /* sub_interval */
+ return CS_SUCCESS;
+}
/*======================================================================
@@ -383,7 +385,7 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
}
}
return -1;
-} /* find_io_region */
+}
int find_mem_region(u_long *base, u_long num, u_long align,
int force_low, char *name)
@@ -411,7 +413,7 @@ int find_mem_region(u_long *base, u_long num, u_long align,
force_low++;
}
return -1;
-} /* find_mem_region */
+}
/*======================================================================
@@ -482,7 +484,7 @@ int try_irq(u_int Attributes, int irq, int specific)
}
}
return 0;
-} /* try_irq */
+}
#endif
@@ -524,34 +526,35 @@ void undo_irq(u_int Attributes, int irq)
static int adjust_memory(adjust_t *adj)
{
u_long base, num;
- int i;
+ int i, ret;
base = adj->resource.memory.Base;
num = adj->resource.memory.Size;
if ((num == 0) || (base+num-1 < base))
return CS_BAD_SIZE;
+ ret = CS_SUCCESS;
switch (adj->Action) {
case ADD_MANAGED_RESOURCE:
- if (add_interval(&mem_db, base, num) != 0)
- return CS_IN_USE;
+ ret = add_interval(&mem_db, base, num);
break;
case REMOVE_MANAGED_RESOURCE:
- sub_interval(&mem_db, base, num);
- for (i = 0; i < sockets; i++) {
- release_cis_mem(socket_table[i]);
+ ret = sub_interval(&mem_db, base, num);
+ if (ret == CS_SUCCESS) {
+ for (i = 0; i < sockets; i++) {
+ release_cis_mem(socket_table[i]);
#ifdef CONFIG_CARDBUS
- cb_release_cis_mem(socket_table[i]);
+ cb_release_cis_mem(socket_table[i]);
#endif
+ }
}
break;
default:
- return CS_UNSUPPORTED_FUNCTION;
- break;
+ ret = CS_UNSUPPORTED_FUNCTION;
}
- return CS_SUCCESS;
-} /* adjust_mem */
+ return ret;
+}
/*====================================================================*/
@@ -584,7 +587,7 @@ static int adjust_io(adjust_t *adj)
}
return CS_SUCCESS;
-} /* adjust_io */
+}
/*====================================================================*/
@@ -625,7 +628,7 @@ static int adjust_irq(adjust_t *adj)
}
#endif
return CS_SUCCESS;
-} /* adjust_irq */
+}
/*====================================================================*/
@@ -646,7 +649,7 @@ int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
break;
}
return CS_UNSUPPORTED_FUNCTION;
-} /* adjust_resource_info */
+}
/*====================================================================*/
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index d5900c6f8..ff25ac893 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -2,7 +2,7 @@
Device driver for Databook TCIC-2 PCMCIA controller
- tcic.c 1.107 1999/10/25 20:03:34
+ tcic.c 1.108 1999/12/09 20:17:29
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -60,12 +60,15 @@
static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
static const char *version =
-"tcic.c 1.107 1999/10/25 20:03:34 (David Hinds)";
+"tcic.c 1.108 1999/12/09 20:17:29 (David Hinds)";
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
#else
#define DEBUG(n, args...)
#endif
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
+
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index f37faeba5..b8664c6b5 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -30,49 +30,7 @@
#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_1450
-#define PCI_DEVICE_ID_TI_1450 0xac1b
-#endif
-#ifndef PCI_DEVICE_ID_TI_1225
-#define PCI_DEVICE_ID_TI_1225 0xac1c
-#endif
-#ifndef PCI_DEVICE_ID_TI_1251A
-#define PCI_DEVICE_ID_TI_1251A 0xac1d
-#endif
-#ifndef PCI_DEVICE_ID_TI_1211
-#define PCI_DEVICE_ID_TI_1211 0xac1e
-#endif
-#ifndef PCI_DEVICE_ID_TI_1251B
-#define PCI_DEVICE_ID_TI_1251B 0xac1f
-#endif
-#ifndef PCI_DEVICE_ID_TI_1420
-#define PCI_DEVICE_ID_TI_1420 0xac51
-#endif
+#include <linux/config.h>
/* Register definitions for TI 113X PCI-to-CardBus bridges */
@@ -176,5 +134,86 @@
/* ExCA IO offset registers */
#define TI113X_IO_OFFSET(map) (0x36+((map)<<1))
+#ifdef CONFIG_CARDBUS
+
+#define ti_sysctl(socket) ((socket)->private[0])
+#define ti_cardctl(socket) ((socket)->private[1])
+#define ti_devctl(socket) ((socket)->private[2])
+
+static int ti113x_open(pci_socket_t *socket)
+{
+ ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL);
+ ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL);
+ ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL);
+
+ ti_cardctl(socket) &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
+ if (socket->cb_irq)
+ ti_cardctl(socket) |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
+ return 0;
+}
+
+static int ti113x_init(pci_socket_t *socket)
+{
+ yenta_init(socket);
+
+ config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
+ config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
+ config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
+
+ return 0;
+}
+
+static struct pci_socket_ops ti113x_ops = {
+ ti113x_open,
+ yenta_close,
+ ti113x_init,
+ yenta_suspend,
+ yenta_get_status,
+ yenta_get_socket,
+ yenta_set_socket,
+ yenta_get_io_map,
+ yenta_set_io_map,
+ yenta_get_mem_map,
+ yenta_set_mem_map,
+ yenta_proc_setup
+};
+
+#define ti_diag(socket) ((socket)->private[0])
+
+static int ti1250_open(pci_socket_t *socket)
+{
+ ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC);
+
+ ti_diag(socket) &= ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ);
+ if (socket->cb_irq)
+ ti_diag(socket) |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
+ return 0;
+}
+
+static int ti1250_init(pci_socket_t *socket)
+{
+ yenta_init(socket);
+
+ config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
+ return 0;
+}
+
+static struct pci_socket_ops ti1250_ops = {
+ ti1250_open,
+ yenta_close,
+ ti1250_init,
+ yenta_suspend,
+ yenta_get_status,
+ yenta_get_socket,
+ yenta_set_socket,
+ yenta_get_io_map,
+ yenta_set_io_map,
+ yenta_get_mem_map,
+ yenta_set_mem_map,
+ yenta_proc_setup
+};
+
+#endif /* CONFIG_CARDBUS */
+
#endif /* _LINUX_TI113X_H */
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index e686a6436..b5a2e35de 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -15,7 +15,6 @@
#include "yenta.h"
#include "i82365.h"
-#include "ricoh.h"
/* Don't ask.. */
#define to_cycles(ns) ((ns)/120)
@@ -68,12 +67,6 @@ static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val)
exca_writeb(socket, reg+1, val >> 8);
}
-static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
-{
- *cap = socket->cap;
- return 0;
-}
-
/*
* Ugh, mixed-mode cardbus and 16-bit pccard state: things depend
* on what kind of card is inserted..
@@ -190,20 +183,22 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state)
u16 bridge;
yenta_set_power(socket, state);
- bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST;
+ socket->io_irq = state->io_irq;
+ bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
- bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
/* ISA interrupt control? */
- if (bridge & CB_BRIDGE_INTR) {
+ if (!socket->cb_irq) {
u8 intr = exca_readb(socket, I365_INTCTL);
intr = (intr & ~0xf) | state->io_irq;
exca_writeb(socket, I365_INTCTL, intr);
+ bridge |= CB_BRIDGE_INTR;
}
} else {
u8 reg;
+ bridge |= CB_BRIDGE_INTR;
reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
@@ -385,13 +380,12 @@ static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base)
/* Not done yet */
}
-static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static unsigned int yenta_events(pci_socket_t *socket)
{
u8 csc;
u32 cb_event;
unsigned int events;
- pci_socket_t *socket = (pci_socket_t *) dev_id;
-
+
/* Clear interrupt status for the event */
cb_event = cb_readl(socket, CB_SOCKET_EVENT);
cb_writel(socket, CB_SOCKET_EVENT, cb_event);
@@ -407,16 +401,50 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
events |= (csc & I365_CSC_READY) ? SS_READY : 0;
}
+ return events;
+}
- if (events && socket->handler)
- socket->handler(socket->info, events);
+static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int events;
+ pci_socket_t *socket = (pci_socket_t *) dev_id;
- mod_timer(&socket->timer, jiffies + HZ);
+ events = yenta_events(socket);
+ if (events) {
+ socket->events |= events;
+ wake_up_interruptible(&socket->wait);
+ }
}
-static void yenta_timer(unsigned long data)
+/*
+ * Watch a socket every second (and possibly in a
+ * more timely manner if the state change interrupt
+ * works..)
+ */
+static int yenta_socket_thread(void * data)
{
- yenta_interrupt(0, (pci_socket_t *) data, NULL);
+ pci_socket_t * socket = (pci_socket_t *) data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ daemonize();
+ strcpy(current->comm, "CardBus Watcher");
+
+ do {
+ unsigned int events = socket->events | yenta_events(socket);
+
+ if (events) {
+ socket->events = 0;
+ if (socket->handler)
+ socket->handler(socket->info, events);
+ }
+
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&socket->wait, &wait);
+ if (!socket->events)
+ schedule_timeout(HZ);
+ remove_wait_queue(&socket->wait, &wait);
+ } while (!signal_pending(current));
+ return 0;
}
static unsigned int yenta_probe_irq(pci_socket_t *socket)
@@ -424,20 +452,10 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
int i;
unsigned long val;
u16 bridge_ctrl;
+ u32 mask;
- /* Are we set up to route the IO irq to the PCI irq? */
+ /* Set up ISA irq routing to probe the ISA irqs.. */
bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
- if (socket->cb_irq) {
- if (bridge_ctrl & CB_BRIDGE_INTR) {
- bridge_ctrl &= ~CB_BRIDGE_INTR;
- config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
- }
- printk("CardBus: using PCI interrupt %d\n", socket->cb_irq);
- return 1 << socket->cb_irq;
- }
-
- /* Uhhuh. No PCI interrupt: try falling back on ISA interrupts */
- printk("CardBus: Hmm.. No PCI irq routing (irq%d).\n", socket->cb_irq);
if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
bridge_ctrl |= CB_BRIDGE_INTR;
config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
@@ -459,7 +477,13 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
cb_writel(socket, CB_SOCKET_EVENT, -1);
}
cb_writel(socket, CB_SOCKET_MASK, 0);
- return probe_irq_mask(val) & 0xffff;
+
+ mask = probe_irq_mask(val) & 0xffff;
+
+ bridge_ctrl &= ~CB_BRIDGE_INTR;
+ config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+
+ return mask;
}
static void yenta_clear_maps(pci_socket_t *socket)
@@ -483,6 +507,7 @@ static void yenta_clear_maps(pci_socket_t *socket)
/* Called at resume and initialization events */
static int yenta_init(pci_socket_t *socket)
{
+ u16 bridge;
struct pci_dev *dev = socket->dev;
pci_set_power_state(socket->dev, 0);
@@ -503,6 +528,19 @@ static int yenta_init(pci_socket_t *socket)
config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number);
config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number);
+ /*
+ * Set up the bridging state:
+ * - enable write posting.
+ * - memory window 0 prefetchable, window 1 non-prefetchable
+ * - PCI interrupts enabled if a PCI interrupt exists..
+ */
+ bridge = config_readw(socket, CB_BRIDGE_CONTROL);
+ bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN);
+ bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
+ if (!socket->cb_irq)
+ bridge |= CB_BRIDGE_INTR;
+ config_writew(socket, CB_BRIDGE_CONTROL, bridge);
+
exca_writeb(socket, I365_GBLCTL, 0x00);
exca_writeb(socket, I365_GENCTL, 0x00);
@@ -510,29 +548,6 @@ static int yenta_init(pci_socket_t *socket)
return 0;
}
-/*
- * More of an example than anything else... The standard
- * yenta init code works well enough - but this is how
- * you'd do it if you wanted to have a special init sequence.
- */
-static int ricoh_init(pci_socket_t *socket)
-{
- u16 misc = config_readw(socket, RL5C4XX_MISC);
- u16 ctl = config_readw(socket, RL5C4XX_16BIT_CTL);
- u16 io = config_readw(socket, RL5C4XX_16BIT_IO_0);
- u16 mem = config_readw(socket, RL5C4XX_16BIT_MEM_0);
-
- ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
-
- config_writew(socket, RL5C4XX_MISC, misc);
- config_writew(socket, RL5C4XX_16BIT_CTL, ctl);
- config_writew(socket, RL5C4XX_16BIT_IO_0, io);
- config_writew(socket, RL5C4XX_16BIT_MEM_0, mem);
-
- return yenta_init(socket);
-}
-
-
static int yenta_suspend(pci_socket_t *socket)
{
yenta_set_socket(socket, &dead_socket);
@@ -552,7 +567,7 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket)
socket->cap.cb_dev = socket->dev;
socket->cap.bus = NULL;
- printk("Yenta IRQ list %04x\n", socket->cap.irq_mask);
+ printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
}
static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
@@ -585,11 +600,11 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
}
align = size = 4*1024*1024;
- min = 0x10000000; max = ~0U;
+ min = PCIBIOS_MIN_MEM; max = ~0U;
if (type & IORESOURCE_IO) {
align = 1024;
size = 256;
- min = 0x1000;
+ min = PCIBIOS_MIN_IO;
max = 0xffff;
}
@@ -611,12 +626,50 @@ static void yenta_allocate_resources(pci_socket_t *socket)
}
/*
+ * Close it down - release our resources and go home..
+ */
+static void yenta_close(pci_socket_t *sock)
+{
+ if (sock->cb_irq)
+ free_irq(sock->cb_irq, sock);
+ if (sock->base)
+ iounmap(sock->base);
+}
+
+#include "ti113x.h"
+#include "ricoh.h"
+
+/*
+ * Different cardbus controllers have slightly different
+ * initialization sequences etc details. List them here..
+ */
+#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y
+static struct cardbus_override_struct {
+ unsigned short vendor;
+ unsigned short device;
+ struct pci_socket_ops *op;
+} cardbus_override[] = {
+ { PD(TI,1130), &ti113x_ops },
+ { PD(TI,1131), &ti113x_ops },
+ { PD(TI,1250), &ti1250_ops },
+
+ { PD(RICOH,RL5C465), &ricoh_ops },
+ { PD(RICOH,RL5C466), &ricoh_ops },
+ { PD(RICOH,RL5C475), &ricoh_ops },
+ { PD(RICOH,RL5C476), &ricoh_ops },
+ { PD(RICOH,RL5C478), &ricoh_ops }
+};
+
+#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))
+
+/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
* socket information structure..
*/
static int yenta_open(pci_socket_t *socket)
{
+ int i;
struct pci_dev *dev = socket->dev;
/*
@@ -645,38 +698,31 @@ static int yenta_open(pci_socket_t *socket)
/* Set up the bridge regions.. */
yenta_allocate_resources(socket);
- /*
- * Always poll the socket too, just in case the cardbus interrupt
- * doesn't exist (it happens), or we just lose an interrupt..
- */
- init_timer(&socket->timer);
- socket->timer.expires = jiffies + HZ;
- socket->timer.data = (unsigned long)socket;
- socket->timer.function = yenta_timer;
- add_timer(&socket->timer);
-
if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
socket->cb_irq = dev->irq;
/* And figure out what the dang thing can do for the PCMCIA layer... */
yenta_get_socket_capabilities(socket);
+ /* Do we have special options for the device? */
+ for (i = 0; i < NR_OVERRIDES; i++) {
+ struct cardbus_override_struct *d = cardbus_override+i;
+ if (dev->vendor == d->vendor && dev->device == d->device) {
+ socket->op = d->op;
+ if (d->op->open) {
+ int retval = d->op->open(socket);
+ if (retval < 0)
+ return retval;
+ }
+ }
+ }
+
+ kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
return 0;
}
/*
- * Close it down - release our resources and go home..
- */
-static void yenta_close(pci_socket_t *sock)
-{
- if (sock->cb_irq)
- free_irq(sock->cb_irq, sock);
- if (sock->base)
- iounmap(sock->base);
-}
-
-/*
* Standard plain cardbus - no frills, no extensions
*/
struct pci_socket_ops yenta_operations = {
@@ -684,7 +730,6 @@ struct pci_socket_ops yenta_operations = {
yenta_close,
yenta_init,
yenta_suspend,
- yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
@@ -704,7 +749,6 @@ struct pci_socket_ops ricoh_operations = {
yenta_close,
ricoh_init,
yenta_suspend,
- yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index 9a8ad136c..9c024342a 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -12,18 +12,26 @@ SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS)
-L_TARGET := pnp.a
-MX_OBJS :=
-LX_OBJS :=
-MI_OBJS :=
-MIX_OBJS :=
+PROC_OBJS :=
+
+ifdef CONFIG_PROC_FS
+PROC_OBJS += isapnp_proc.o
+endif
+
+ifeq ($(CONFIG_ISAPNP),m)
+ M_OBJS := isa-pnp.o
+ MIX_OBJS := isapnp.o
+ MI_OBJS := quirks.o $(PROC_OBJS)
+endif
ifeq ($(CONFIG_ISAPNP),y)
- LX_OBJS += isapnp.o quirks.o
-else
- ifeq ($(CONFIG_ISAPNP),m)
- MX_OBJS += isapnp.o quirks.o
- endif
+ O_TARGET := isa-pnp.o
+ OX_OBJS := isapnp.o
+ O_OBJS := quirks.o $(PROC_OBJS)
endif
+
include $(TOPDIR)/Rules.make
+
+isa-pnp.o: isapnp.o quirks.o $(PROC_OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ isapnp.o quirks.o $(PROC_OBJS)
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
index 8b6a42b7d..ec81da498 100644
--- a/drivers/pnp/isapnp.c
+++ b/drivers/pnp/isapnp.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Changelog:
- * 2000-01-01 Added ISAPnP quirks handling
+ * 2000-01-01 Added quirks handling for buggy hardware
* Peter Denison <peterd@pnd-pc.demon.co.uk>
*/
@@ -30,31 +30,17 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/malloc.h>
-#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/poll.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
#include <linux/isapnp.h>
LIST_HEAD(isapnp_cards);
LIST_HEAD(isapnp_devices);
-#define isapnp_for_each_card(card) \
- for(card = pci_bus_b(isapnp_cards.next); card != pci_bus_b(&isapnp_cards); card = pci_bus_b(card->node.next))
-#define isapnp_for_each_dev(dev) \
- for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next))
-
-
-#ifdef CONFIG_PROC_FS
-#include "isapnp_proc.c"
-#endif
-
#if 0
#define ISAPNP_REGION_OK
#endif
@@ -286,6 +272,12 @@ static int isapnp_next_rdp(void)
return 0;
}
rdp += RDP_STEP;
+ /*
+ * We cannot use NE2000 probe spaces for ISAPnP or we
+ * will lock up machines.
+ */
+ if(rdp >= 0x280 && rdp <= 0x380)
+ continue;
}
return -1;
}
@@ -298,12 +290,8 @@ static inline void isapnp_set_rdp(void)
}
/*
- * This code is badly broken. We cannot simply pick ports as the
- * ISAPnP specification implies. We should try 4 or 5 safe ports
- * then bale by default.
- *
- * This code touches NE2K cards or other devices and your box is
- * history.
+ * Perform an isolation. The port selection code now tries to avoid
+ * "dangerous to read" ports.
*/
static int __init isapnp_isolate_rdp_select(void)
@@ -996,6 +984,8 @@ static int __init isapnp_build_device_list(void)
card->device = (header[3] << 8) | header[2];
card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
isapnp_checksum_value = 0x00;
+ INIT_LIST_HEAD(&card->children);
+ INIT_LIST_HEAD(&card->devices);
isapnp_parse_resource_map(card);
if (isapnp_checksum_value != 0x00)
printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
@@ -1196,10 +1186,11 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card,
struct list_head *list;
list = card->devices.next;
- if (from)
+ if (from) {
list = from->bus_list.next;
- if (from->bus != card) /* something is wrong */
- return NULL;
+ if (from->bus != card) /* something is wrong */
+ return NULL;
+ }
while (list != &card->devices) {
int idx;
struct pci_dev *dev = pci_dev_b(list);
@@ -1633,7 +1624,10 @@ static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
int i;
struct pci_dev *dev;
- if (dma < 0 || dma == 4 || dma > 7)
+ /* Some machines allow DMA 0, but others don't. In fact on some
+ boxes DMA 0 is the memory refresh. Play safe */
+
+ if (dma < 1 || dma == 4 || dma > 7)
return 1;
for (i = 0; i < 8; i++) {
if (isapnp_reserve_dma[i] == dma)
@@ -1773,8 +1767,8 @@ static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx)
mem = cfg->mem[idx];
if (!mem)
return -EINVAL;
- value1 = &cfg->result.resource[idx].start;
- value2 = &cfg->result.resource[idx].end;
+ value1 = &cfg->result.resource[idx + 8].start;
+ value2 = &cfg->result.resource[idx + 8].end;
if (cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO) {
cfg->result.resource[idx + 8].flags &= ~IORESOURCE_AUTO;
*value1 = mem->min;
@@ -1785,7 +1779,7 @@ static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx)
do {
*value1 += mem->align;
*value2 = *value1 + mem->size - 1;
- if (*value1 >= 8 || !mem->align) {
+ if (*value1 > mem->max || !mem->align) {
if (mem->res && mem->res->alt) {
if ((err = isapnp_alternative_switch(cfg, mem->res, mem->res->alt))<0)
return err;
diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c
index 1a742823f..a26670fc7 100644
--- a/drivers/pnp/isapnp_proc.c
+++ b/drivers/pnp/isapnp_proc.c
@@ -19,6 +19,17 @@
*
*/
+#define __NO_VERSION__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <linux/isapnp.h>
+
struct isapnp_info_buffer {
char *buffer; /* pointer to begin of buffer */
char *curr; /* current position in buffer */
@@ -31,6 +42,8 @@ struct isapnp_info_buffer {
typedef struct isapnp_info_buffer isapnp_info_buffer_t;
static struct proc_dir_entry *isapnp_proc_entry = NULL;
+static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
+static struct proc_dir_entry *isapnp_proc_devices_entry = NULL;
static void isapnp_info_read(isapnp_info_buffer_t *buffer);
static void isapnp_info_write(isapnp_info_buffer_t *buffer);
@@ -56,6 +69,18 @@ int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
return res;
}
+static void isapnp_devid(char *str, unsigned short vendor, unsigned short device)
+{
+ sprintf(str, "%c%c%c%x%x%x%x",
+ 'A' + ((vendor >> 2) & 0x3f) - 1,
+ 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+ 'A' + ((vendor >> 8) & 0x1f) - 1,
+ (device >> 4) & 0x0f,
+ device & 0x0f,
+ (device >> 12) & 0x0f,
+ (device >> 8) & 0x0f);
+}
+
static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
{
switch (orig) {
@@ -175,17 +200,6 @@ static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
return POLLIN | POLLRDNORM;
}
-static int isapnp_info_entry_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return -EINVAL;
-}
-
-static int isapnp_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
-{
- return -ENXIO;
-}
-
static struct file_operations isapnp_info_entry_operations =
{
isapnp_info_entry_lseek, /* lseek */
@@ -193,8 +207,8 @@ static struct file_operations isapnp_info_entry_operations =
isapnp_info_entry_write, /* write */
NULL, /* readdir */
isapnp_info_entry_poll, /* poll */
- isapnp_info_entry_ioctl, /* ioctl - default */
- isapnp_info_entry_mmap, /* mmap */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
isapnp_info_entry_open, /* open */
NULL, /* flush */
isapnp_info_entry_release, /* release */
@@ -208,24 +222,210 @@ static struct inode_operations isapnp_info_entry_inode_operations =
&isapnp_info_entry_operations, /* default sound info directory file-ops */
};
-static int __init isapnp_proc_init(void)
+static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
+{
+ loff_t new;
+
+ switch (whence) {
+ case 0:
+ new = off;
+ break;
+ case 1:
+ new = file->f_pos + off;
+ break;
+ case 2:
+ new = 256 + off;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (new < 0 || new > 256)
+ return -EINVAL;
+ return (file->f_pos = new);
+}
+
+static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+ struct inode *ino = file->f_dentry->d_inode;
+ struct proc_dir_entry *dp = ino->u.generic_ip;
+ struct pci_dev *dev = dp->data;
+ int pos = *ppos;
+ int cnt, size = 256;
+
+ if (pos >= size)
+ return 0;
+ if (nbytes >= size)
+ nbytes = size;
+ if (pos + nbytes > size)
+ nbytes = size - pos;
+ cnt = nbytes;
+
+ if (!access_ok(VERIFY_WRITE, buf, cnt))
+ return -EINVAL;
+
+ isapnp_cfg_begin(dev->bus->number, dev->devfn);
+ for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
+ unsigned char val;
+ val = isapnp_read_byte(pos);
+ __put_user(val, buf);
+ }
+ isapnp_cfg_end();
+
+ *ppos = pos;
+ return nbytes;
+}
+
+static struct file_operations isapnp_proc_bus_file_operations =
+{
+ isapnp_proc_bus_lseek, /* lseek */
+ isapnp_proc_bus_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+ NULL, /* can't fsync */
+ NULL, /* fasync */
+ NULL, /* lock */
+};
+
+static struct inode_operations isapnp_proc_bus_inode_operations =
+{
+ &isapnp_proc_bus_file_operations,
+};
+
+static int isapnp_proc_attach_device(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+ struct proc_dir_entry *de, *e;
+ char name[16];
+
+ if (!(de = bus->procdir)) {
+ sprintf(name, "%02x", bus->number);
+ de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
+ if (!de)
+ return -ENOMEM;
+ }
+ sprintf(name, "%02x", dev->devfn);
+ e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
+ if (!e)
+ return -ENOMEM;
+ e->ops = &isapnp_proc_bus_inode_operations;
+ e->data = dev;
+ e->size = 256;
+ return 0;
+}
+
+#ifdef MODULE
+static int __exit isapnp_proc_detach_device(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+ struct proc_dir_entry *de;
+ char name[16];
+
+ if (!(de = bus->procdir))
+ return -EINVAL;
+ sprintf(name, "%02x", dev->devfn);
+ remove_proc_entry(name, de);
+ return 0;
+}
+
+static int __exit isapnp_proc_detach_bus(struct pci_bus *bus)
+{
+ struct proc_dir_entry *de;
+ char name[16];
+
+ if (!(de = bus->procdir))
+ return -EINVAL;
+ sprintf(name, "%02x", bus->number);
+ remove_proc_entry(name, isapnp_proc_bus_dir);
+ return 0;
+}
+#endif
+
+static int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count)
+{
+ struct pci_dev *dev;
+ off_t at = 0;
+ int len, cnt, i;
+
+ cnt = 0;
+ isapnp_for_each_dev(dev) {
+ char bus_id[8], device_id[8];
+
+ isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device);
+ isapnp_devid(device_id, dev->vendor, dev->device);
+ len = sprintf(buf, "%02x%02x\t%s%s\t",
+ dev->bus->number,
+ dev->devfn,
+ bus_id,
+ device_id);
+ isapnp_cfg_begin(dev->bus->number, dev->devfn);
+ len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE));
+ for (i = 0; i < 8; i++)
+ len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1)));
+ for (i = 0; i < 2; i++)
+ len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)));
+ for (i = 0; i < 2; i++)
+ len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i));
+ for (i = 0; i < 4; i++)
+ len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3)));
+ isapnp_cfg_end();
+ buf[len++] = '\n';
+ at += len;
+ if (at >= pos) {
+ if (!*start) {
+ *start = buf + (pos - (at - len));
+ cnt = at - pos;
+ } else
+ cnt += len;
+ buf += len;
+ }
+ }
+ return (count > cnt) ? cnt : count;
+}
+
+int __init isapnp_proc_init(void)
{
struct proc_dir_entry *p;
+ struct pci_dev *dev;
isapnp_proc_entry = NULL;
p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
- if (!p)
- return -ENOMEM;
- p->ops = &isapnp_info_entry_inode_operations;
+ if (p)
+ p->ops = &isapnp_info_entry_inode_operations;
isapnp_proc_entry = p;
+ isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
+ isapnp_proc_devices_entry = create_proc_info_entry("devices", 0,
+ isapnp_proc_bus_dir,
+ isapnp_proc_read_devices);
+ isapnp_for_each_dev(dev) {
+ isapnp_proc_attach_device(dev);
+ }
return 0;
}
#ifdef MODULE
-static int isapnp_proc_done(void)
+int __exit isapnp_proc_done(void)
{
+ struct pci_dev *dev;
+ struct pci_bus *card;
+
+ isapnp_for_each_dev(dev) {
+ isapnp_proc_detach_device(dev);
+ }
+ isapnp_for_each_card(card) {
+ isapnp_proc_detach_bus(card);
+ }
+ if (isapnp_proc_devices_entry)
+ remove_proc_entry("devices", isapnp_proc_devices_entry);
+ if (isapnp_proc_bus_dir)
+ remove_proc_entry("isapnp", proc_bus);
if (isapnp_proc_entry)
- remove_proc_entry("isapnp",&proc_root);
+ remove_proc_entry("isapnp", &proc_root);
return 0;
}
#endif /* MODULE */
@@ -238,14 +438,7 @@ static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vend
{
char tmp[8];
- sprintf(tmp, "%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f,
- (device >> 12) & 0x0f,
- (device >> 8) & 0x0f);
+ isapnp_devid(tmp, vendor, device);
isapnp_printf(buffer, tmp);
}
@@ -533,10 +726,9 @@ static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *de
static void isapnp_info_read(isapnp_info_buffer_t *buffer)
{
- struct list_head *card_list;
-
- for (card_list = isapnp_cards.next; card_list != &isapnp_cards; card_list = card_list->next) {
- struct pci_bus *card = list_entry(card_list, struct pci_bus, node);
+ struct pci_bus *card;
+
+ isapnp_for_each_card(card) {
struct list_head *dev_list;
isapnp_printf(buffer, "Card %i '", card->number);
@@ -547,10 +739,8 @@ static void isapnp_info_read(isapnp_info_buffer_t *buffer)
if (card->productver)
isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
isapnp_printf(buffer,"\n");
- for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) {
- struct pci_dev *dev = list_entry(dev_list, struct pci_dev, bus_list);
- isapnp_print_device(buffer, dev);
- }
+ for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next)
+ isapnp_print_device(buffer, pci_dev_b(dev_list));
}
}
@@ -644,12 +834,13 @@ static int isapnp_select_csn(char *line)
isapnp_info_device = NULL;
isapnp_get_str(index, line, sizeof(index));
csn = simple_strtoul(index, NULL, 0);
+
for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
- isapnp_info_card = list_entry(list, struct pci_bus, node);
+ isapnp_info_card = pci_bus_b(list);
if (isapnp_info_card->number == csn)
break;
}
- if (isapnp_info_card == NULL) {
+ if (list == &isapnp_cards) {
printk("isapnp: cannot find CSN %i\n", csn);
return 1;
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 028eda7da..838241de2 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -16,6 +16,8 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/isapnp.h>
+#include <linux/string.h>
+
static void __init quirk_awe32_resources(struct pci_dev *dev)
{
@@ -55,6 +57,10 @@ static void __init quirk_awe32_resources(struct pci_dev *dev)
static struct isapnp_fixup isapnp_fixups[] __initdata = {
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0021),
quirk_awe32_resources },
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0022),
+ quirk_awe32_resources },
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0023),
+ quirk_awe32_resources },
{ 0 }
};
@@ -65,8 +71,8 @@ void isapnp_fixup_device(struct pci_dev *dev)
while (isapnp_fixups[i].vendor != 0) {
if ((isapnp_fixups[i].vendor == dev->vendor) &&
(isapnp_fixups[i].device == dev->device)) {
- printk(KERN_DEBUG "PnP: Calling quirk for %s\n",
- dev->slot_name);
+ printk(KERN_DEBUG "PnP: Calling quirk for %02x:%02x\n",
+ dev->bus->number, dev->devfn);
isapnp_fixups[i].quirk_function(dev);
}
i++;
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 92f064f25..602c7b670 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.13 1999/12/19 23:28:07 davem Exp $
+/* $Id: envctrl.c,v 1.14 2000/01/09 15:43:45 ecd Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
@@ -29,8 +29,8 @@
#undef U450_SUPPORT /* might fry you machine, careful here !!! */
-#define DEBUG 1
-#define DEBUG_BUS_SCAN 1
+#undef DEBUG
+#undef DEBUG_BUS_SCAN
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c
index 238b76006..1c5846ade 100644
--- a/drivers/sbus/char/pcikbd.c
+++ b/drivers/sbus/char/pcikbd.c
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.40 1999/12/01 10:45:53 davem Exp $
+/* $Id: pcikbd.c,v 1.41 2000/01/08 07:01:20 davem Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index fc6cc40d2..f884dfb1e 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,9 @@
+Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+ * revision 3.2e
+ - Add year 2000 copyright.
+ - Display correctly bus signals when bus is detected wrong.
+ - Remove the dead code that broke driver 3.2d.
+
Mon Dec 6 22:00 1999 Gerard Roudier (groudier@club-internet.fr)
* revision 3.2d
- Change messages written by the driver at initialisation and
diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx
index 4980c2683..ed169320a 100644
--- a/drivers/scsi/ChangeLog.sym53c8xx
+++ b/drivers/scsi/ChangeLog.sym53c8xx
@@ -1,3 +1,9 @@
+Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5h
+ - Add year 2000 copyright.
+ - Display correctly bus signals when bus is detected wrong.
+ - Some fix for Sparc from DSM that went directly to kernel tree.
+
Mon Dec 6 22:00 1999 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.5g
- Change messages written by the driver at initialisation and
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 90ec7ef77..979f1295c 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -879,6 +879,8 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
int retcode;
struct Scsi_Host *shpnt;
#if DO_DETECT
+ int i = 0;
+ int j = 0;
const int buflen = 255;
Scsi_Cmnd SCinit;
unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 };
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5a13b0e48..594116c1f 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -165,21 +165,25 @@ static void __init internal_setup(int board, char *str, int *ints){
printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
return;
}
+ break;
case BOARD_NCR53C400:
if (ints[0] != 2) {
printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
return;
}
+ break;
case BOARD_NCR53C400A:
if (ints[0] != 2) {
printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
return;
}
+ break;
case BOARD_DTC3181E:
if (ints[0] != 2) {
printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
return;
}
+ break;
}
if (commandline_current < NO_OVERRIDES) {
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 6554ee2f0..1a209c14e 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -31,6 +31,7 @@
#define IDESCSI_VERSION "0.9"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -579,6 +580,17 @@ int idescsi_init (void)
for (i = 0; media[i] != 255; i++) {
failed = 0;
while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+#ifndef CONFIG_BLK_DEV_IDETAPE
+ /*
+ * The Onstream DI-30 does not handle clean emulation, yet.
+ */
+ if (strstr(drive->id->model, "OnStream DI-30")) {
+ printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+ continue;
+ }
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+
if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
continue;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 7df2b9e58..863bb3fce 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -9,7 +9,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version : 1.04
+ * Version : 1.05
*
* Description: Linux device driver for AMI MegaRAID controller
*
@@ -111,6 +111,16 @@
* The addtional 32 bit field for 64bit address in the newly defined
* mailbox64 structure is set to 0 at this point.
*
+ * Version 1.05
+ * Changed the queing implementation for handling SCBs and completed
+ * commands.
+ * Added spinlocks in the interrupt service routine to enable the dirver
+ * function in the SMP environment.
+ * Fixed the problem of unnecessary aborts in the abort entry point, which
+ * also enables the driver to handle large amount of I/O requests for
+ * long duration of time.
+ *
+ *
* BUGS:
* Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
* fails to detect the controller as a pci device on the system.
@@ -125,7 +135,8 @@
#define CRLFSTR "\n"
#define IOCTL_CMD_NEW 0x81
-#define MEGARAID_VERSION "v1.04 (August 16, 1999)"
+#define MEGARAID_VERSION "v1.05 (October 27, 1999)"
+
#include <linux/version.h>
@@ -143,8 +154,6 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver");
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
@@ -181,31 +190,6 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver");
#define MAX_SERBUF 160
#define COM_BASE 0x2f8
-#define ENQUEUE(obj,type,list,next) \
-{ type **node; long cpuflag; \
- spin_lock_irqsave(&mega_lock,cpuflag);\
- for(node=&(list); *node; node=(type **)&(*node)->##next); \
- (*node) = obj; \
- (*node)->##next = NULL; \
- spin_unlock_irqrestore(&mega_lock,cpuflag);\
-}
-
-/* a non-locking version (if we already have the lock) */
-#define ENQUEUE_NL(obj,type,list,next) \
-{ type **node; \
- for(node=&(list); *node; node=(type **)&(*node)->##next); \
- (*node) = obj; \
- (*node)->##next = NULL; \
-}
-
-#define DEQUEUE(obj,type,list,next) \
-{ long cpuflag; \
- spin_lock_irqsave(&mega_lock,cpuflag);\
- if ((obj=list) != NULL) {\
- list = (type *)(list)->##next; \
- } \
- spin_unlock_irqrestore(&mega_lock,cpuflag);\
-};
u32 RDINDOOR (mega_host_config * megaCfg)
{
@@ -239,19 +223,67 @@ static int megaIssueCmd (mega_host_config * megaCfg,
u_char * mboxData,
mega_scb * scb,
int intr);
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
u32 * buffer, u32 * length);
static int mega_busyWaitMbox(mega_host_config *);
static void mega_runpendq (mega_host_config *);
-static void mega_rundoneq (void);
+static void mega_rundoneq (mega_host_config *);
static void mega_cmd_done (mega_host_config *, mega_scb *, int);
static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
-static inline void freeSgList(mega_host_config *megaCfg);
+static inline void mega_freeSgList(mega_host_config *megaCfg);
static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry,
mega_Enquiry3 *enquiry3,
megaRaidProductInfo *productInfo );
+
+
+
+
+#if LINUX_VERSION_CODE > 0x020100
+# include <asm/spinlock.h>
+# include <linux/smp.h>
+# define cpuid smp_processor_id()
+# if LINUX_VERSION_CODE < 0x020195
+# define DRIVER_LOCK_T unsigned long cpu_flags = 0;
+# define DRIVER_LOCK_INIT(p) \
+ spin_lock_init(&p->mega_lock);
+# define DRIVER_LOCK(p) \
+ if(!p->cpu_lock_count[cpuid]) { \
+ spin_lock_irqsave(&p->mega_lock, cpu_flags); \
+ p->cpu_lock_count[cpuid]++; \
+ } else { \
+ p->cpu_lock_count[cpuid]++; \
+ }
+# define DRIVER_UNLOCK(p) \
+ if(--p->cpu_lock_count[cpuid] == 0) \
+ spin_unlock_irqrestore(&p->mega_lock, cpu_flags);
+# define IO_LOCK(p) spin_lock_irqsave(&io_request_lock,cpu_flags);
+# define IO_UNLOCK(p) spin_unlock_irqrestore(&io_request_lock,cpu_flags);
+# else
+# define DRIVER_LOCK_T
+# define DRIVER_LOCK_INIT(p)
+# define DRIVER_LOCK(p)
+# define DRIVER_UNLOCK(p)
+# define IO_LOCK_T unsigned long io_flags = 0;
+# define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+# define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+# endif
+#else
+# define cpuid 0
+# define DRIVER_LOCK_T long cpu_flags;
+# define DRIVER_LOCK_INIT(p)
+# define DRIVER_LOCK(p) \
+ save_flags(cpu_flags); \
+ cli();
+# define DRIVER_UNLOCK(p) \
+ restore_flags(cpu_flags);
+# define IO_LOCK(p) DRIVER_LOCK(p)
+# define IO_UNLOCK(p) DRIVER_UNLOCK(p)
+# define le32_to_cpu(x) (x)
+# define cpu_to_le32(x) (x)
+#endif
+
/* set SERDEBUG to 1 to enable serial debugging */
#define SERDEBUG 0
#if SERDEBUG
@@ -286,13 +318,10 @@ static u32 maxCmdTime = 0;
static mega_scb *pLastScb = NULL;
-/* Queue of pending/completed SCBs */
-static Scsi_Cmnd *qCompleted = NULL;
#if SERDEBUG
static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
#endif
-static spinlock_t mega_lock = SPIN_LOCK_UNLOCKED;
#if SERDEBUG
static char strbuf[MAX_SERBUF + 1];
@@ -352,7 +381,7 @@ static int ser_printk (const char *fmt,...)
#define TRACE(A)
#endif
-void callDone (Scsi_Cmnd * SCpnt)
+static void callDone (Scsi_Cmnd * SCpnt)
{
if (SCpnt->result) {
TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
@@ -372,37 +401,66 @@ void callDone (Scsi_Cmnd * SCpnt)
* Free a SCB structure
*=======================
*/
-static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
+static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
{
- mega_scb **ppScb;
+
+ mega_scb *pScbtmp;
+
+ if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+ return ;
+ }
/* Unlink from pending queue */
- for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) {
- if (*ppScb == pScb) {
- *ppScb = pScb->next;
+
+ if(pScb == megaCfg->qPendingH) {
+ if(megaCfg->qPendingH == megaCfg->qPendingT )
+ megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+ else {
+ megaCfg->qPendingH = megaCfg->qPendingH->next;
+ }
+ megaCfg->qPcnt--;
+ }
+ else {
+ for(pScbtmp=megaCfg->qPendingH; pScbtmp; pScbtmp=pScbtmp->next) {
+ if (pScbtmp->next == pScb) {
+ pScbtmp->next = pScb->next;
+ if(pScb == megaCfg->qPendingT) {
+ megaCfg->qPendingT = pScbtmp;
+ }
+ megaCfg->qPcnt--;
break;
}
}
+ }
- /* Link back into list */
+ /* Link back into free list */
pScb->state = SCB_FREE;
pScb->SCpnt = NULL;
- pScb->next = megaCfg->qFree;
- megaCfg->qFree = pScb;
+ if(megaCfg->qFreeH == (mega_scb *) NULL ) {
+ megaCfg->qFreeH = megaCfg->qFreeT = pScb;
+ }
+ else {
+ megaCfg->qFreeT->next = pScb;
+ megaCfg->qFreeT = pScb;
+ }
+ megaCfg->qFreeT->next = NULL;
+ megaCfg->qFcnt++;
+
}
/*===========================
* Allocate a SCB structure
*===========================
*/
-static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
{
mega_scb *pScb;
/* Unlink command from Free List */
- if ((pScb = megaCfg->qFree) != NULL) {
- megaCfg->qFree = pScb->next;
+ if ((pScb = megaCfg->qFreeH) != NULL) {
+ megaCfg->qFreeH = pScb->next;
+ megaCfg->qFcnt--;
pScb->isrcount = jiffies;
pScb->next = NULL;
@@ -421,62 +479,72 @@ static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
* Initialize SCB structures
*================================================
*/
-static int initSCB (mega_host_config * megaCfg)
+static int mega_initSCB (mega_host_config * megaCfg)
{
int idx;
- megaCfg->qFree = NULL;
+ megaCfg->qFreeH = NULL;
+ megaCfg->qFcnt = 0;
+#if DEBUG
+if(megaCfg->max_cmds >= MAX_COMMANDS) {
+printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS);
+}
+#endif
+
for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
megaCfg->scbList[idx].idx = idx;
megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
GFP_ATOMIC | GFP_DMA);
if (megaCfg->scbList[idx].sgList == NULL) {
printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
- freeSgList(megaCfg);
+ mega_freeSgList(megaCfg);
return -1;
}
if (idx < MAX_COMMANDS) {
/* Link to free list */
- freeSCB(megaCfg, &megaCfg->scbList[idx]);
+ mega_freeSCB(megaCfg, &megaCfg->scbList[idx]);
}
}
return 0;
}
/* Run through the list of completed requests */
-static void mega_rundoneq ()
+static void mega_rundoneq (mega_host_config *megaCfg)
{
Scsi_Cmnd *SCpnt;
- while (1) {
- DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
- if (SCpnt == NULL)
- return;
+ while ((SCpnt = megaCfg->qCompletedH) != NULL) {
+ megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+ megaCfg->qCcnt--;
+ SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
/* Callback */
callDone (SCpnt);
}
+ megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
}
/*
- Runs through the list of pending requests
- Assumes that mega_lock spin_lock has been acquired.
-*/
+ * Runs through the list of pending requests
+ * Assumes that mega_lock spin_lock has been acquired.
+ */
static void mega_runpendq(mega_host_config *megaCfg)
{
mega_scb *pScb;
/* Issue any pending commands to the card */
- for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+ for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
if (pScb->state == SCB_ACTIVE) {
- megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1);
+ if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))
+ return;
}
}
}
/* Add command to the list of completed requests */
-static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb,
+static void
+mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb,
int status)
{
int islogical;
@@ -499,7 +567,7 @@ static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb,
TRACE(("pScb->idx = ",pScb->idx));
TRACE(("pScb->state = ",pScb->state));
TRACE(("pScb->state = ",pScb->state));
- printk("Problem...!\n");
+ printk("megaraid:Problem...!\n");
while(1);
}
@@ -554,10 +622,18 @@ else{
/* not IOCTL_CMD_NEW SCB, freeSCB()*/
/* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
* after copy data back to user space*/
- freeSCB(megaCfg, pScb);
+ mega_freeSCB(megaCfg, pScb);
/* Add Scsi_Command to end of completed queue */
- ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ if( megaCfg->qCompletedH == NULL ) {
+ megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+ }
+ else {
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+ megaCfg->qCompletedT = SCpnt;
+ }
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+ megaCfg->qCcnt++;
}
/*-------------------------------------------------------------------
@@ -627,7 +703,7 @@ static mega_scb * mega_build_cmd (mega_host_config * megaCfg,
case READ_CAPACITY:
case INQUIRY:
/* Allocate a SCB and initialize passthru */
- if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
SCpnt->result = (DID_ERROR << 16);
callDone (SCpnt);
return NULL;
@@ -658,7 +734,7 @@ static mega_scb * mega_build_cmd (mega_host_config * megaCfg,
case READ_10:
case WRITE_10:
/* Allocate a SCB and initialize mailbox */
- if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
SCpnt->result = (DID_ERROR << 16);
callDone (SCpnt);
return NULL;
@@ -694,7 +770,7 @@ static mega_scb * mega_build_cmd (mega_host_config * megaCfg,
}
/* Calculate Scatter-Gather info */
- mbox->numsgelements = build_sglist (megaCfg, pScb,
+ mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
(u32 *) & mbox->xferaddr,
(u32 *) & seg);
@@ -713,7 +789,7 @@ static mega_scb * mega_build_cmd (mega_host_config * megaCfg,
*-----------------------------------------------------*/
else {
/* Allocate a SCB and initialize passthru */
- if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
SCpnt->result = (DID_ERROR << 16);
callDone (SCpnt);
return NULL;
@@ -734,7 +810,7 @@ static mega_scb * mega_build_cmd (mega_host_config * megaCfg,
pthru->cdblen = SCpnt->cmd_len;
memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
- pthru->numsgelements = build_sglist (megaCfg, pScb,
+ pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
(u32 *) & pthru->dataxferaddr,
(u32 *) & pthru->dataxferlen);
@@ -761,19 +837,12 @@ static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
unsigned char *data = (unsigned char *)SCpnt->request_buffer;
int i;
- if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
SCpnt->result = (DID_ERROR << 16);
callDone (SCpnt);
return NULL;
}
-#if 0
- printk("\nBUF: ");
- for (i=0;i<18;i++) {
- printk(" %x",data[i]);
- }
- printk("......\n");
-#endif
mboxdata = (u8 *) & pScb->mboxData;
mbox = (mega_ioctl_mbox *) & pScb->mboxData;
@@ -797,7 +866,7 @@ static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
mailbox->xferaddr = virt_to_bus (pthru);
- pthru->numsgelements = build_sglist (megaCfg, pScb,
+ pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
(u32 *) & pthru->dataxferaddr,
(u32 *) & pthru->dataxferlen);
@@ -856,7 +925,7 @@ static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
}
else {
- mbox->numsgelements = build_sglist (megaCfg, pScb,
+ mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
(u32 *) & mbox->xferaddr,
(u32 *) & seg);
@@ -884,30 +953,32 @@ static void showMbox(mega_scb *pScb)
}
#endif
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+#endif
+
/*--------------------------------------------------------------------
* Interrupt service routine
*--------------------------------------------------------------------*/
static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
{
+ IO_LOCK_T
mega_host_config *megaCfg;
u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
- u32 dword;
+ u32 dword=0;
mega_mailbox *mbox;
mega_scb *pScb;
- long flags;
- int qCnt, qStatus;
+ u_char qCnt, qStatus;
+ u_char completed[MAX_FIRMWARE_STATUS];
+ Scsi_Cmnd *SCpnt;
megaCfg = (mega_host_config *) devp;
mbox = (mega_mailbox *)tmpBox;
- spin_lock_irqsave (&io_request_lock, flags);
-
- while (megaCfg->host->irq == irq) {
-
- spin_lock_irqsave (&mega_lock, flags);
-
+ if (megaCfg->host->irq == irq) {
if (megaCfg->flag & IN_ISR) {
- TRACE (("ISR called reentrantly!!\n"));
+ printk(KERN_ERR "ISR called reentrantly!!\n");
}
megaCfg->flag |= IN_ISR;
@@ -916,48 +987,73 @@ static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
printk(KERN_WARNING "Error: mailbox busy in isr!\n");
}
-
/* Check if a valid interrupt is pending */
if (megaCfg->flag & BOARD_QUARTZ) {
dword = RDOUTDOOR (megaCfg);
if (dword != 0x10001234) {
/* Spurious interrupt */
megaCfg->flag &= ~IN_ISR;
- spin_unlock_irqrestore (&mega_lock, flags);
- break;
+//#if LINUX_VERSION_CODE >= 0x20100
+// IO_UNLOCK;
+//#endif
+// break;
+ return;
}
- WROUTDOOR (megaCfg, dword);
-
- /* Copy to temp location */
- memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
-
- /* Acknowledge interrupt */
- WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
- while (RDINDOOR (megaCfg) & 0x02);
}
else {
byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
if ((byte & VALID_INTR_BYTE) == 0) {
/* Spurious interrupt */
megaCfg->flag &= ~IN_ISR;
- spin_unlock_irqrestore (&mega_lock, flags);
- break;
+//#if LINUX_VERSION_CODE >= 0x20100
+// IO_UNLOCK;
+//#endif
+// break;
+ return;
}
WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+ }
+
+ for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;
+
+ IO_LOCK;
+
+ qCnt = 0xff;
+ while ((qCnt = megaCfg->mbox->numstatus) == 0xFF)
+ ;
- /* Copy to temp location */
- memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+ qStatus = 0xff;
+ while ((qStatus = megaCfg->mbox->status) == 0xFF)
+ ;
+ /* Get list of completed requests */
+ for (idx = 0; idx<qCnt; idx++) {
+ while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
+ printk("p");
+ }
+ completed[idx] = sIdx;
+ sIdx = 0xFF;
+ }
+
+ if (megaCfg->flag & BOARD_QUARTZ) {
+ WROUTDOOR (megaCfg, dword);
/* Acknowledge interrupt */
+ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+ while (RDINDOOR (megaCfg) & 0x02);
+ }
+ else {
CLEAR_INTR (megaCfg->host->io_port);
}
- qCnt = mbox->numstatus;
- qStatus = mbox->status;
+#if DEBUG
+ if(qCnt >= MAX_FIRMWARE_STATUS) {
+ printk("megaraid_isr: cmplt=%d ", qCnt);
+ }
+#endif
for (idx = 0; idx < qCnt; idx++) {
- sIdx = mbox->completed[idx];
- if (sIdx > 0) {
+ sIdx = completed[idx];
+ if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
pScb = &megaCfg->scbList[sIdx - 1];
/* ASSERT(pScb->state == SCB_ISSUED); */
@@ -965,12 +1061,33 @@ static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
#if DEBUG
if (((jiffies) - pScb->isrcount) > maxCmdTime) {
maxCmdTime = (jiffies) - pScb->isrcount;
- printk("cmd time = %u\n", maxCmdTime);
+ printk("megaraid_isr : cmd time = %u\n", maxCmdTime);
}
#endif
-
+/*
+ * Assuming that the scsi command, for which an abort request was received
+ * earlier has completed.
+ */
if (pScb->state == SCB_ABORTED) {
- printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
+ SCpnt = pScb->SCpnt;
+#if DEBUG
+printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt);
+#endif
+ }
+ if (pScb->state == SCB_RESET) {
+ SCpnt = pScb->SCpnt;
+ mega_freeSCB (megaCfg, pScb);
+ SCpnt->result = (DID_RESET << 16) ;
+ if( megaCfg->qCompletedH == NULL ) {
+ megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+ }
+ else {
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+ megaCfg->qCompletedT = SCpnt;
+ }
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+ megaCfg->qCcnt++;
+ continue;
}
if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW)
@@ -981,22 +1098,22 @@ static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
mega_cmd_done(megaCfg, pScb, qStatus);
}
-
+ else {
+ printk(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
+ }
}
- spin_unlock_irqrestore (&mega_lock, flags);
- megaCfg->flag &= ~IN_ISR;
+ mega_rundoneq(megaCfg);
- mega_rundoneq();
+ megaCfg->flag &= ~IN_ISR;
/* Loop through any pending requests */
- spin_lock_irqsave(&mega_lock, flags);
mega_runpendq(megaCfg);
- spin_unlock_irqrestore(&mega_lock,flags);
+#if LINUX_VERSION_CODE >= 0x20100
+ IO_UNLOCK;
+#endif
}
-
- spin_unlock_irqrestore (&io_request_lock, flags);
}
/*==================================================*/
@@ -1040,7 +1157,6 @@ static int megaIssueCmd (mega_host_config * megaCfg,
mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
u_char byte;
u32 cmdDone;
- Scsi_Cmnd *SCpnt;
u32 phys_mbox;
u8 retval=-1;
@@ -1049,18 +1165,15 @@ static int megaIssueCmd (mega_host_config * megaCfg,
phys_mbox = virt_to_bus (megaCfg->mbox);
-#if 0
- if (intr && mbox->busy) {
- return 0;
- }
-#endif
-
#if DEBUG
showMbox(pScb);
#endif
/* Wait until mailbox is free */
- while (mega_busyWaitMbox (megaCfg)) {
+#if 0
+ while (mega_busyWaitMbox (megaCfg))
+#endif
+ if (mega_busyWaitMbox (megaCfg)) {
printk("Blocked mailbox......!!\n");
udelay(1000);
@@ -1070,14 +1183,10 @@ static int megaIssueCmd (mega_host_config * megaCfg,
/* Abort command */
if (pScb == NULL) {
- printk("NULL pScb in megaIssue\n");
TRACE(("NULL pScb in megaIssue\n"));
+ printk("NULL pScb in megaIssue\n");
}
- SCpnt = pScb->SCpnt;
- freeSCB(megaCfg, pScb);
-
- SCpnt->result = (DID_ABORT << 16);
- callDone(SCpnt);
+ mega_cmd_done (megaCfg, pScb, 0x08);
return -1;
}
@@ -1116,7 +1225,7 @@ static int megaIssueCmd (mega_host_config * megaCfg,
if (pScb) {
mega_cmd_done (megaCfg, pScb, mbox->status);
- mega_rundoneq ();
+// mega_rundoneq (megaCfg);
}
WRINDOOR (megaCfg, phys_mbox | 0x2);
@@ -1130,26 +1239,26 @@ static int megaIssueCmd (mega_host_config * megaCfg,
while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID));
WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
-
ENABLE_INTR (megaCfg->host->io_port);
CLEAR_INTR (megaCfg->host->io_port);
if (pScb) {
mega_cmd_done (megaCfg, pScb, mbox->status);
- mega_rundoneq ();
+// mega_rundoneq (megaCfg);
}
else {
TRACE (("Error: NULL pScb!\n"));
}
-
}
enable_irq(megaCfg->host->irq);
retval=mbox->status;
}
+#if DEBUG
while (mega_busyWaitMbox (megaCfg)) {
printk("Blocked mailbox on exit......!\n");
udelay(1000);
}
+#endif
return retval;
}
@@ -1157,7 +1266,7 @@ static int megaIssueCmd (mega_host_config * megaCfg,
/*-------------------------------------------------------------------
* Copies data to SGLIST
*-------------------------------------------------------------------*/
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
u32 * buffer, u32 * length)
{
struct scatterlist *sgList;
@@ -1216,9 +1325,7 @@ static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
paddr = (paddr + 4 + 16) & 0xfffffff0;
/* Register mailbox area with the firmware */
- if (megaCfg->flag & BOARD_QUARTZ) {
- }
- else {
+ if (!(megaCfg->flag & BOARD_QUARTZ)) {
WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF);
WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
@@ -1276,7 +1383,6 @@ static int mega_i_query_adapter (mega_host_config * megaCfg)
u32 paddr;
u8 retval;
- spin_lock_init (&mega_lock);
/* Initialize adapter inquiry mailbox*/
paddr = virt_to_bus (megaCfg->mega_buffer);
@@ -1337,9 +1443,17 @@ static int mega_i_query_adapter (mega_host_config * megaCfg)
/*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/
megaCfg->host->max_lun = /* max lun */
(megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
+ megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
megaCfg->numldrv = enquiry3Pnt->numLDrv;
megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+ if(megaCfg->max_cmds > MAX_COMMANDS) megaCfg->max_cmds = MAX_COMMANDS - 1;
+
+ megaCfg->host->can_queue = megaCfg->max_cmds;
+
+ if (megaCfg->host->can_queue >= MAX_COMMANDS) {
+ megaCfg->host->can_queue = MAX_COMMANDS-1;
+ }
#if 0
int i;
@@ -1405,7 +1519,7 @@ int megaraid_proc_info (char *buffer, char **start, off_t offset,
return 0;
}
-int findCard (Scsi_Host_Template * pHostTmpl,
+int mega_findCard (Scsi_Host_Template * pHostTmpl,
u16 pciVendor, u16 pciDev,
long flag)
{
@@ -1429,6 +1543,21 @@ int findCard (Scsi_Host_Template * pHostTmpl,
pciDev,
pdev->slot_name);
+ /*
+ * Dont crash on boot with AMI cards configured for I2O.
+ * (our I2O code will find them then they will fail oddly until
+ * we figure why they upset our I2O code). This driver will die
+ * if it tries to boot an I2O mode board and we dont stop it now.
+ * - Alan Cox , Red Hat Software, Jan 2000
+ */
+
+ if((pdev->class >> 8) == PCI_CLASS_INTELLIGENT_I2O)
+ {
+ printk( KERN_INFO "megaraid: Board configured for I2O, ignoring this card. Reconfigure the card\n"
+ KERN_INFO "megaraid: in the BIOS for \"mass storage\" to use it with this driver.\n");
+ continue;
+ }
+
/* Read the base port and IRQ from PCI */
megaBase = pdev->resource[0].start;
megaIrq = pdev->irq;
@@ -1452,8 +1581,15 @@ int findCard (Scsi_Host_Template * pHostTmpl,
host->host_no, (u_int) megaBase, megaIrq);
/* Copy resource info into structure */
- megaCfg->qPending = NULL;
- megaCfg->qFree = NULL;
+ megaCfg->qCompletedH = NULL;
+ megaCfg->qCompletedT = NULL;
+ megaCfg->qPendingH = NULL;
+ megaCfg->qPendingT = NULL;
+ megaCfg->qFreeH = NULL;
+ megaCfg->qFreeT = NULL;
+ megaCfg->qFcnt = 0;
+ megaCfg->qPcnt = 0;
+ megaCfg->qCcnt = 0;
megaCfg->flag = flag;
megaCfg->host = host;
megaCfg->base = megaBase;
@@ -1485,7 +1621,7 @@ int findCard (Scsi_Host_Template * pHostTmpl,
mega_i_query_adapter (megaCfg);
/* Initialize SCBs */
- if (initSCB (megaCfg)) {
+ if (mega_initSCB (megaCfg)) {
scsi_unregister (host);
continue;
}
@@ -1511,9 +1647,9 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
- count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
- count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
- count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+ count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
+ count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
+ count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
return count;
}
@@ -1548,13 +1684,13 @@ int megaraid_release (struct Scsi_Host *pSHost)
release_region (megaCfg->host->io_port, 16);
}
- freeSgList(megaCfg);
+ mega_freeSgList(megaCfg);
scsi_unregister (pSHost);
return 0;
}
-static inline void freeSgList(mega_host_config *megaCfg)
+static inline void mega_freeSgList(mega_host_config *megaCfg)
{
int i;
@@ -1600,13 +1736,12 @@ const char * megaraid_info (struct Scsi_Host *pSHost)
*-----------------------------------------------------------------*/
int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
{
+ DRIVER_LOCK_T
mega_host_config *megaCfg;
mega_scb *pScb;
- long flags;
-
- spin_lock_irqsave(&mega_lock,flags);
megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+ DRIVER_LOCK(megaCfg);
if (!(megaCfg->flag & (1L << SCpnt->channel))) {
if (SCpnt->channel < SCpnt->host->max_channel)
@@ -1623,33 +1758,69 @@ int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
/* If driver in abort or reset.. cancel this command */
if (megaCfg->flag & IN_ABORT) {
+#if DEBUG
+printk("mq: got a request while in abort\n");
+#endif
SCpnt->result = (DID_ABORT << 16);
- ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ /* Add Scsi_Command to end of completed queue */
+ if( megaCfg->qCompletedH == NULL ) {
+ megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+ }
+ else {
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+ megaCfg->qCompletedT = SCpnt;
+ }
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+ megaCfg->qCcnt++;
- spin_unlock_irqrestore(&mega_lock,flags);
+ DRIVER_UNLOCK(megaCfg);
return 0;
}
else if (megaCfg->flag & IN_RESET) {
+#if DEBUG
+printk("mq: got a request while in reset\n");
+#endif
SCpnt->result = (DID_RESET << 16);
- ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ /* Add Scsi_Command to end of completed queue */
+ if( megaCfg->qCompletedH == NULL ) {
+ megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+ }
+ else {
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+ megaCfg->qCompletedT = SCpnt;
+ }
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+ megaCfg->qCcnt++;
- spin_unlock_irqrestore(&mega_lock,flags);
+ DRIVER_UNLOCK(megaCfg);
return 0;
}
+ megaCfg->flag |= IN_QUEUE;
/* Allocate and build a SCB request */
if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
/*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/
/* Add SCB to the head of the pending queue */
- ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
-
- /* Issue any pending command to the card if not in ISR */
- if (!(megaCfg->flag & IN_ISR)) {
- mega_runpendq(megaCfg);
+ /* Add SCB to the head of the pending queue */
+ if( megaCfg->qPendingH == NULL ) {
+ megaCfg->qPendingH = megaCfg->qPendingT = pScb;
}
else {
- printk("IRQ pend...\n");
+ megaCfg->qPendingT->next = pScb;
+ megaCfg->qPendingT = pScb;
}
+ megaCfg->qPendingT->next = NULL;
+ megaCfg->qPcnt++;
+
+
+ /* Issue any pending command to the card if not in ISR */
+// if (!(megaCfg->flag & IN_ISR)) {
+ mega_runpendq(megaCfg);
+// }
+/*
+ * try running the pend queue, irrespective of the driver's context.
+ * -cn
+ */
if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
{ /* user data from external user buffer */
@@ -1666,12 +1837,12 @@ int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
kfree(pScb->kern_area);
- freeSCB(megaCfg, pScb);
+ mega_freeSCB(megaCfg, pScb);
}
-
}
- spin_unlock_irqrestore(&mega_lock,flags);
+ megaCfg->flag &= ~IN_QUEUE;
+ DRIVER_UNLOCK(megaCfg);
return 0;
}
@@ -1709,41 +1880,70 @@ int megaraid_command (Scsi_Cmnd * SCpnt)
/*---------------------------------------------------------------------
* Abort a previous SCSI request
*---------------------------------------------------------------------*/
-int megaraid_abort (Scsi_Cmnd * SCpnt)
+int
+megaraid_abort (Scsi_Cmnd * SCpnt)
{
mega_host_config *megaCfg;
- int rc, idx;
- long flags;
+ int rc; //, idx;
mega_scb *pScb;
- rc = SCSI_ABORT_SUCCESS;
-
- spin_lock_irqsave (&mega_lock, flags);
+ rc = SCSI_ABORT_NOT_RUNNING;
megaCfg = (mega_host_config *) SCpnt->host->hostdata;
megaCfg->flag |= IN_ABORT;
- for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+#if DEBUG
+printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt);
+#endif
+ for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
if (pScb->SCpnt == SCpnt) {
/* Found an aborting command */
#if DEBUG
showMbox(pScb);
#endif
- printk("Abort: %d %u\n",
- SCpnt->timeout_per_command,
- (uint)((jiffies) - pScb->isrcount));
+/*
+ * If the command is queued to be issued to the firmware, abort the scsi cmd,
+ * If the command is already aborted in a previous call to the _abort entry
+ * point, return SCSI_ABORT_SNOOZE, suggesting a reset.
+ * If the command is issued to the firmware, which might complete after
+ * some time, we will mark the scb as aborted, and return to the mid layer,
+ * that abort could not be done.
+ * In the ISR, when this command actually completes, we will perform a normal
+ * completion.
+ *
+ * Oct 27, 1999
+ */
switch(pScb->state) {
case SCB_ABORTED: /* Already aborted */
rc = SCSI_ABORT_SNOOZE;
break;
case SCB_ISSUED: /* Waiting on ISR result */
- rc = SCSI_ABORT_PENDING;
+ rc = SCSI_ABORT_NOT_RUNNING;
pScb->state = SCB_ABORTED;
break;
+ case SCB_ACTIVE: /* still on the pending queue */
+ mega_freeSCB (megaCfg, pScb);
+ SCpnt->result = (DID_ABORT << 16) ;
+ if( megaCfg->qCompletedH == NULL ) {
+ megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+ }
+ else {
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+ megaCfg->qCompletedT = SCpnt;
+ }
+ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+ megaCfg->qCcnt++;
+ rc = SCSI_ABORT_SUCCESS;
+ break;
+ default:
+ printk("megaraid_abort: unknown command state!!\n");
+ rc = SCSI_ABORT_NOT_RUNNING;
+ break;
}
+ break;
}
}
@@ -1761,26 +1961,29 @@ int megaraid_abort (Scsi_Cmnd * SCpnt)
}
}
#endif
-
- /*
- * Walk list of SCBs for any that are still outstanding
- */
- for (idx = 0; idx < megaCfg->max_cmds; idx++) {
- if (megaCfg->scbList[idx].state != SCB_FREE) {
- if (megaCfg->scbList[idx].SCpnt == SCpnt) {
- freeSCB (megaCfg, &megaCfg->scbList[idx]);
-
- SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24);
- ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
- }
- }
- }
-
megaCfg->flag &= ~IN_ABORT;
- spin_unlock_irqrestore (&mega_lock, flags);
+#if DEBUG
+if(megaCfg->flag & IN_QUEUE) printk("ma:flag is in queue\n");
+if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");
+#endif
+
+/*
+ * This is required here to complete any completed requests to be communicated
+ * over to the mid layer.
+ * Calling just mega_rundoneq() did not work.
+ */
+if(megaCfg->qCompletedH) {
+ SCpnt = megaCfg->qCompletedH;
+ megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+ megaCfg->qCcnt--;
+
+ SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
+ /* Callback */
+ callDone (SCpnt);
+}
+ mega_rundoneq(megaCfg);
- mega_rundoneq();
return rc;
}
@@ -1792,14 +1995,18 @@ int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
{
mega_host_config *megaCfg;
int idx;
- long flags;
-
- spin_lock_irqsave (&mega_lock, flags);
+ int rc;
+ mega_scb *pScb;
+ rc = SCSI_RESET_NOT_RUNNING;
megaCfg = (mega_host_config *) SCpnt->host->hostdata;
megaCfg->flag |= IN_RESET;
+ printk ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
+ SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+ SCpnt->lun, rstflags);
+
TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
SCpnt->lun));
@@ -1810,20 +2017,18 @@ int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
for (idx = 0; idx < megaCfg->max_cmds; idx++) {
if (megaCfg->scbList[idx].state != SCB_FREE) {
SCpnt = megaCfg->scbList[idx].SCpnt;
+ pScb = &megaCfg->scbList[idx];
if (SCpnt != NULL) {
- freeSCB (megaCfg, &megaCfg->scbList[idx]);
- SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
- ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ pScb->state = SCB_RESET;
+ break;
}
}
}
megaCfg->flag &= ~IN_RESET;
- spin_unlock_irqrestore (&mega_lock, flags);
-
- mega_rundoneq();
- return SCSI_RESET_PUNT;
+ mega_rundoneq(megaCfg);
+ return rc;
}
/*-------------------------------------------------------------
@@ -1886,4 +2091,3 @@ Scsi_Host_Template driver_template = MEGARAID;
#include "scsi_module.c"
#endif
-
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index a4771100e..9a8935935 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -8,9 +8,11 @@
#define IN_ISR 0x80000000L
#define IN_ABORT 0x40000000L
#define IN_RESET 0x20000000L
+#define IN_QUEUE 0x10000000L
#define BOARD_QUARTZ 0x08000000L
#define BOARD_40LD 0x04000000L
+#ifndef HOSTS_C
#define SCB_FREE 0x0
#define SCB_ACTIVE 0x1
#define SCB_WAITQ 0x2
@@ -18,12 +20,19 @@
#define SCB_COMPLETE 0x4
#define SCB_ABORTED 0x5
#define SCB_RESET 0x6
+#endif
#define MEGA_CMD_TIMEOUT 10
-#define MAX_SGLIST 17
-#define MAX_COMMANDS 250
+/* Feel free to fiddle with these.. max values are:
+ SGLIST 0..26
+ COMMANDS 0..253
+ CMDPERLUN 0..63
+*/
+#define MAX_SGLIST 0x1A
+#define MAX_COMMANDS 127
#define MAX_CMD_PER_LUN 63
+#define MAX_FIRMWARE_STATUS 46
#define MAX_LOGICAL_DRIVES 8
#define MAX_CHANNEL 5
@@ -143,8 +152,8 @@
sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\
cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\
present: 0, /* Present */\
- unchecked_isa_dma:0, /* Default Unchecked ISA DMA */\
- use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\
+ unchecked_isa_dma:1, /* Default Unchecked ISA DMA */\
+ use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\
}
#endif
@@ -505,7 +514,7 @@ typedef struct mega_passthru {
u32 dataxferlen;
} mega_passthru;
-typedef struct _mega_mailbox {
+struct _mega_mailbox {
/* 0x0 */ u8 cmd;
/* 0x1 */ u8 cmdid;
/* 0x2 */ u16 numsectors;
@@ -520,8 +529,9 @@ typedef struct _mega_mailbox {
/* 0x12 */ u8 completed[46];
u8 mraid_poll;
u8 mraid_ack;
- u8 pad[16];
-} mega_mailbox;
+ u8 pad[16]; /* for alignment purposes */
+}__attribute__((packed));
+typedef struct _mega_mailbox mega_mailbox;
typedef struct {
u32 xferSegment; /* for 64-bit controllers */
@@ -575,8 +585,16 @@ typedef struct _mega_host_config {
u32 flag;
u32 base;
- mega_scb *qFree;
- mega_scb *qPending;
+ mega_scb *qFreeH;
+ mega_scb *qFreeT;
+ mega_scb *qPendingH;
+ mega_scb *qPendingT;
+
+ Scsi_Cmnd *qCompletedH;
+ Scsi_Cmnd *qCompletedT;
+ u32 qFcnt;
+ u32 qPcnt;
+ u32 qCcnt;
u32 nReads[FC_MAX_LOGICAL_DRIVES];
u32 nWrites[FC_MAX_LOGICAL_DRIVES];
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index b876bb8bc..d2943f103 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -73,7 +73,7 @@
*/
/*
-** December 6 1999, version 3.2d
+** January 8 2000, version 3.2e
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -104,7 +104,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2d"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2e"
#define SCSI_NCR_DEBUG_FLAGS (0)
@@ -5415,11 +5415,13 @@ static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
** We are expecting RESET to be TRUE and other signals to be
** FALSE.
*/
- term = INB(nc_sstat0); /* rst, sdp0 */
- term = ((term & 2) << 7) + ((term & 1) << 16);
- term |= ((INB(nc_sstat2) & 0x01) << 25) | /* sdp1 */
- (INW(nc_sbdl) << 9) | /* d15-0 */
- INB(nc_sbcl); /* req, ack, bsy, sel, atn, msg, cd, io */
+
+ term = INB(nc_sstat0);
+ term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */
+ term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */
+ ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */
+ ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */
+ INB(nc_sbcl); /* req ack bsy sel atn msg cd io */
if (!(np->features & FE_WIDE))
term &= 0x3ffff;
@@ -9706,9 +9708,6 @@ ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
uint irq;
ulong base, base_2, io_port;
int i;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- ncr_nvram *nvram = device->nvram;
-#endif
ncr_chip *chip;
/*
@@ -10047,52 +10046,7 @@ ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
device->slot.io_port = io_port;
device->slot.irq = irq;
device->attach_done = 0;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- if (!nvram)
- goto out;
- /*
- ** Get access to chip IO registers
- */
-#ifdef NCR_IOMAPPED
- request_region(io_port, 128, "ncr53c8xx");
- device->slot.port = io_port;
-#else
- device->slot.reg = (struct ncr_reg *) remap_pci_mem((ulong) base, 128);
- if (!device->slot.reg)
- goto out;
-#endif
-
- /*
- ** Try to read SYMBIOS nvram.
- ** Data can be used to order booting of boards.
- **
- ** Data is saved in ncr_device structure if NVRAM found. This
- ** is then used to find drive boot order for ncr_attach().
- **
- ** NVRAM data is passed to Scsi_Host_Template later during ncr_attach()
- ** for any device set up.
- **
- ** Try to read TEKRAM nvram if Symbios nvram not found.
- */
-
- if (!ncr_get_Symbios_nvram(&device->slot, &nvram->data.Symbios))
- nvram->type = SCSI_NCR_SYMBIOS_NVRAM;
- else if (!ncr_get_Tekram_nvram(&device->slot, &nvram->data.Tekram))
- nvram->type = SCSI_NCR_TEKRAM_NVRAM;
- else
- nvram->type = 0;
-out:
- /*
- ** Release access to chip IO registers
- */
-#ifdef NCR_IOMAPPED
- release_region(device->slot.port, 128);
-#else
- unmap_pci_mem((vm_offset_t) device->slot.reg, (u_long) 128);
-#endif
-
-#endif /* SCSI_NCR_NVRAM_SUPPORT */
return 0;
}
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
index b15a6a075..d41a5298a 100644
--- a/drivers/scsi/psi240i.h
+++ b/drivers/scsi/psi240i.h
@@ -211,6 +211,8 @@ typedef struct _READ_CAPACITY_DATA
} READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
// SCSI inquiry data
+#ifndef HOSTS_C
+
typedef struct _INQUIRYDATA
{
UCHAR DeviceType :5;
@@ -235,6 +237,7 @@ typedef struct _INQUIRYDATA
UCHAR VendorSpecific[20];
UCHAR Reserved3[40];
} INQUIRYDATA, *PINQUIRYDATA;
+#endif
// IDE IDENTIFY data
typedef struct _IDENTIFY_DATA
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 18185133d..eeff3d5fd 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1768,14 +1768,24 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *host;
Scsi_Device *device;
+ unsigned long flags;
ASSERT_LOCK(&io_request_lock, 0);
host = SCpnt->host;
device = SCpnt->device;
+ /*
+ * We need to protect the decrement, as otherwise a race condition
+ * would exist. Fiddling with SCpnt isn't a problem as the
+ * design only allows a single SCpnt to be active in only
+ * one execution context, but the device and host structures are
+ * shared.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
host->host_busy--; /* Indicate that we are free */
device->device_busy--; /* Decrement device usage counter. */
+ spin_unlock_irqrestore(&io_request_lock, flags);
/*
* Clear the flags which say that the device/host is no longer
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 07022ed38..48b1c977d 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -947,23 +947,23 @@ void scsi_request_fn(request_queue_t * q)
* get those allocated here.
*/
if (!SDpnt->scsi_init_io_fn(SCpnt)) {
- SHpnt->host_busy--;
- SDpnt->device_busy--;
scsi_end_request(SCpnt, 0,
SCpnt->request.nr_sectors);
spin_lock_irq(&io_request_lock);
+ SHpnt->host_busy--;
+ SDpnt->device_busy--;
continue;
}
/*
* Initialize the actual SCSI command for this request.
*/
if (!STpnt->init_command(SCpnt)) {
- SHpnt->host_busy--;
- SDpnt->device_busy--;
scsi_release_buffers(SCpnt);
scsi_end_request(SCpnt, 0,
SCpnt->request.nr_sectors);
spin_lock_irq(&io_request_lock);
+ SHpnt->host_busy--;
+ SDpnt->device_busy--;
continue;
}
}
diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
index 4a62566f1..162088204 100644
--- a/drivers/scsi/scsi_queue.c
+++ b/drivers/scsi/scsi_queue.c
@@ -79,6 +79,7 @@ static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/s
int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
{
struct Scsi_Host *host;
+ unsigned long flags;
SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd));
@@ -136,8 +137,10 @@ int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
* Decrement the counters, since these commands are no longer
* active on the host/device.
*/
+ spin_lock_irqsave(&io_request_lock, flags);
cmd->host->host_busy--;
cmd->device->device_busy--;
+ spin_unlock_irqrestore(&io_request_lock, flags);
/*
* Insert this command at the head of the queue for it's device.
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 01fd69803..b615f8a38 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -19,17 +19,8 @@
* scsi disks using eight major numbers.
*/
+#include <linux/config.h>
#include <linux/module.h>
-#ifdef MODULE
-/*
- * This is a variable in scsi.c that is set when we are processing something
- * after boot time. By definition, this is true when we are a loadable module
- * ourselves.
- */
-#define MODULE_FLAG 1
-#else
-#define MODULE_FLAG scsi_loadable_module_flag
-#endif /* MODULE */
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -452,7 +443,6 @@ static int sd_open(struct inode *inode, struct file *filp)
static int sd_release(struct inode *inode, struct file *file)
{
int target;
- fsync_dev(inode->i_rdev);
target = DEVICE_NR(inode->i_rdev);
@@ -469,8 +459,6 @@ static int sd_release(struct inode *inode, struct file *file)
return 0;
}
-static void sd_geninit(struct gendisk *);
-
static struct block_device_operations sd_fops =
{
open: sd_open,
@@ -491,8 +479,6 @@ static struct gendisk sd_gendisk =
"sd", /* Major name */
4, /* Bits to shift to get real from partition */
1 << 4, /* Number of partitions per real */
- 0, /* maximum number of real */
- sd_geninit, /* init function */
NULL, /* hd struct */
NULL, /* block sizes */
0, /* number */
@@ -505,15 +491,6 @@ static struct gendisk *sd_gendisks = &sd_gendisk;
#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
#define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1]
-static void sd_geninit(struct gendisk *ignored)
-{
- int i;
-
- for (i = 0; i < sd_template.dev_max; ++i)
- if (rscsi_disks[i].device)
- sd[i << 4].nr_sects = rscsi_disks[i].capacity;
-}
-
/*
* rw_intr is the interrupt routine for the device driver.
* It will be notified on the end of a SCSI read / write, and
@@ -1018,8 +995,6 @@ static int sd_init()
sd_gendisks[i].major_name = "sd";
sd_gendisks[i].minor_shift = 4;
sd_gendisks[i].max_p = 1 << 4;
- sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR;
- sd_gendisks[i].init = sd_geninit;
sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4);
sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
sd_gendisks[i].nr_real = 0;
@@ -1028,8 +1003,6 @@ static int sd_init()
(void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
}
- LAST_SD_GENDISK.max_nr =
- (sd_template.dev_max - 1) % SCSI_DISKS_PER_MAJOR + 1;
LAST_SD_GENDISK.next = NULL;
return 0;
}
@@ -1051,16 +1024,15 @@ static void sd_finish()
gendisk_head = sd_gendisks;
}
for (i = 0; i < sd_template.dev_max; ++i)
- if (!rscsi_disks[i].capacity &&
- rscsi_disks[i].device) {
- if (MODULE_FLAG
- && !rscsi_disks[i].has_part_table) {
+ if (!rscsi_disks[i].capacity && rscsi_disks[i].device) {
+ sd_init_onedisk(i);
+ if (!rscsi_disks[i].has_part_table) {
sd_sizes[i << 4] = rscsi_disks[i].capacity;
- /* revalidate does sd_init_onedisk via MAYBE_REINIT */
- revalidate_scsidisk(MKDEV_SD(i), 0);
- } else
- i = sd_init_onedisk(i);
- rscsi_disks[i].has_part_table = 1;
+ register_disk(&SD_GENDISK(i), MKDEV_SD(i),
+ 1<<4, &sd_fops,
+ rscsi_disks[i].capacity);
+ rscsi_disks[i].has_part_table = 1;
+ }
}
/* If our host adapter is capable of scatter-gather, then we increase
* the read-ahead to 60 blocks (120 sectors). If not, we use
@@ -1175,11 +1147,8 @@ int revalidate_scsidisk(kdev_t dev, int maxusage)
MAYBE_REINIT;
#endif
- sd_gendisks->part[start].nr_sects = CAPACITY;
- if (!rscsi_disks[target].device)
- return -EBUSY;
- resetup_one_dev(&SD_GENDISK(target),
- target % SCSI_DISKS_PER_MAJOR);
+ grok_partitions(&SD_GENDISK(target), target % SCSI_DISKS_PER_MAJOR,
+ 1<<4, CAPACITY);
DEVICE_BUSY = 0;
return 0;
@@ -1216,6 +1185,7 @@ static void sd_detach(Scsi_Device * SDp)
sd_gendisks->part[index].nr_sects = 0;
sd_sizes[index] = 0;
}
+ /* unregister_disk() */
dpnt->has_part_table = 0;
dpnt->device = NULL;
dpnt->capacity = 0;
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 402b6e1c4..9b82cc839 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -244,6 +244,10 @@ static unsigned char controller_type = 0; /* set to SEAGATE for ST0x
boards */
static int irq = IRQ;
+MODULE_PARM(base_address, "i");
+MODULE_PARM(controller_type, "b");
+MODULE_PARM(irq, "i");
+
#define retcode(result) (((result) << 16) | (message << 8) | status)
#define STATUS ((u8) isa_readb(st0x_cr_sr))
#define DATA ((u8) isa_readb(st0x_dr))
diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
index 6c660aa73..5e01bc118 100644
--- a/drivers/scsi/sym53c416.h
+++ b/drivers/scsi/sym53c416.h
@@ -22,7 +22,9 @@
#include <linux/version.h>
#endif
+#ifndef LinuxVersionCode
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
#include <linux/types.h>
#include <linux/kdev_t.h>
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index 15dbbd965..f56d66756 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-2000 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
@@ -55,7 +55,7 @@
*/
/*
-** December 6 1999, sym53c8xx 1.5g
+** January 9 2000, sym53c8xx 1.5h
**
** Supported SCSI features:
** Synchronous data transfers
@@ -84,7 +84,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5g"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5h"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -6367,11 +6367,12 @@ static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
** We are expecting RESET to be TRUE and other signals to be
** FALSE.
*/
- term = INB(nc_sstat0); /* rst, sdp0 */
- term = ((term & 2) << 7) + ((term & 1) << 16);
- term |= ((INB(nc_sstat2) & 0x01) << 25) | /* sdp1 */
- (INW(nc_sbdl) << 9) | /* d15-0 */
- INB(nc_sbcl); /* req, ack, bsy, sel, atn, msg, cd, io */
+ term = INB(nc_sstat0);
+ term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */
+ term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */
+ ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */
+ ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */
+ INB(nc_sbcl); /* req ack bsy sel atn msg cd io */
if (!(np->features & FE_WIDE))
term &= 0x3ffff;
diff --git a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h
index 4e39980c4..128fe165d 100644
--- a/drivers/scsi/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx.h
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-2000 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
diff --git a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h
index 99d894ca9..a035efd31 100644
--- a/drivers/scsi/sym53c8xx_defs.h
+++ b/drivers/scsi/sym53c8xx_defs.h
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-2000 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c
index 9c6851832..c7bbffca6 100644
--- a/drivers/sound/cmpci.c
+++ b/drivers/sound/cmpci.c
@@ -62,7 +62,7 @@
* 18.08.99 1.5 Only deallocate DMA buffer when unloading.
* 02.09.99 1.6 Enable SPDIF LOOP
* Change the mixer read back
- * 21.09.99 2.33 Use RCS version aas driver version.
+ * 21.09.99 2.33 Use RCS version as driver version.
* Add support for modem, S/PDIF loop and 4 channels.
* (8738 only)
* Fix bug cause x11amp cannot play.
@@ -2372,6 +2372,7 @@ int __init init_cmpci(void)
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
s->magic = CM_MAGIC;
s->iobase = pcidev->resource[0].start;
s->iosynth = 0x388;
diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c
index 89fcbf2b6..acea8e22f 100644
--- a/drivers/sound/es1370.c
+++ b/drivers/sound/es1370.c
@@ -114,6 +114,8 @@
* 03.09.1999 0.30 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
* 28.10.1999 0.31 More waitqueue races fixed
+ * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
*
* some important things missing in Ensoniq documentation:
*
@@ -1331,6 +1333,7 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
VALIDATE_STATE(s);
@@ -1508,7 +1511,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
- abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac2.dmasize - count;
abinfo.fragstotal = s->dma_dac2.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1522,7 +1528,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1537,9 +1546,11 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
- val = s->dma_dac2.count;
+ count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
@@ -1547,7 +1558,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -1560,7 +1574,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
- cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac2.fragshift;
cinfo.ptr = s->dma_dac2.hwptr;
if (s->dma_dac2.mapped)
s->dma_dac2.count &= s->dma_dac2.fragsize-1;
@@ -1853,6 +1870,7 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
unsigned ctrl;
int val, ret;
@@ -1961,7 +1979,10 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_dac1.fragsize;
- abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac1.dmasize - count;
abinfo.fragstotal = s->dma_dac1.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1974,9 +1995,11 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int
case SNDCTL_DSP_GETODELAY:
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
- val = s->dma_dac1.count;
+ count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
@@ -1984,7 +2007,10 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_dac1.total_bytes;
- cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac1.fragshift;
cinfo.ptr = s->dma_dac1.hwptr;
if (s->dma_dac1.mapped)
s->dma_dac1.count &= s->dma_dac1.fragsize-1;
@@ -2444,7 +2470,7 @@ static int __init init_es1370(void)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1370: version v0.32 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
if (!RSRCISIOREGION(pcidev, 0))
diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c
index 2ef9d0bf5..1a4844d47 100644
--- a/drivers/sound/es1371.c
+++ b/drivers/sound/es1371.c
@@ -96,6 +96,8 @@
* detect ES137x chip and derivatives.
* 05.01.2000 0.22 Should now work with rev7 boards; patch by
* Eric Lemar, elemar@cs.washington.edu
+ * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
*/
/*****************************************************************************/
@@ -1911,6 +1913,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
VALIDATE_STATE(s);
@@ -2085,7 +2088,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
- abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac2.dmasize - count;
abinfo.fragstotal = s->dma_dac2.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -2099,7 +2105,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -2114,9 +2123,11 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
- val = s->dma_dac2.count;
+ count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
@@ -2124,7 +2135,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -2137,7 +2151,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
- cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac2.fragshift;
cinfo.ptr = s->dma_dac2.hwptr;
if (s->dma_dac2.mapped)
s->dma_dac2.count &= s->dma_dac2.fragsize-1;
@@ -2430,6 +2447,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, ret;
VALIDATE_STATE(s);
@@ -2529,7 +2547,10 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_dac1.fragsize;
- abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac1.dmasize - count;
abinfo.fragstotal = s->dma_dac1.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -2542,9 +2563,11 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
case SNDCTL_DSP_GETODELAY:
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
- val = s->dma_dac1.count;
+ count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
@@ -2552,7 +2575,10 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_dac1.total_bytes;
- cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac1.fragshift;
cinfo.ptr = s->dma_dac1.hwptr;
if (s->dma_dac1.mapped)
s->dma_dac1.count &= s->dma_dac1.fragsize-1;
@@ -3229,7 +3255,7 @@ static int __init init_es1371(void)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1371: version v0.23 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) {
if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) {
if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 &&
diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c
index 2d33c895a..255efbc2b 100644
--- a/drivers/sound/esssolo1.c
+++ b/drivers/sound/esssolo1.c
@@ -3,7 +3,7 @@
/*
* esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver.
*
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* 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
@@ -28,41 +28,44 @@
* /dev/midi simple MIDI UART interface, no ioctl
*
* Revision history
- * 10.11.98 0.1 Initial release (without any hardware)
- * 22.03.99 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.99 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * 15.06.99 0.4 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.99 0.5 Add pci_set_master
- * 12.08.99 0.6 Fix MIDI UART crashing the driver
- * Changed mixer semantics from OSS documented
- * behaviour to OSS "code behaviour".
- * Recording might actually work now.
- * The real DDMA controller address register is at PCI config
- * 0x60, while the register at 0x18 is used as a placeholder
- * register for BIOS address allocation. This register
- * is supposed to be copied into 0x60, according
- * to the Solo1 datasheet. When I do that, I can access
- * the DDMA registers except the mask bit, which
- * is stuck at 1. When I copy the contents of 0x18 +0x10
- * to the DDMA base register, everything seems to work.
- * 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)
- * 03.09.99 0.8 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 07.10.99 0.9 Fix initialization; complain if sequencer writes time out
- * Revised resource grabbing for the FM synthesizer
- * 28.10.99 0.10 More waitqueue races fixed
- * 09.12.99 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
- * Disabling recording on Alpha
+ * 10.11.1998 0.1 Initial release (without any hardware)
+ * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
+ * reported by Johan Maes <joma@telindus.be>
+ * return EAGAIN instead of EBUSY when O_NONBLOCK
+ * read/write cannot be executed
+ * 07.04.1999 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+ * Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ * 15.06.1999 0.4 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
+ * 28.06.1999 0.5 Add pci_set_master
+ * 12.08.1999 0.6 Fix MIDI UART crashing the driver
+ * Changed mixer semantics from OSS documented
+ * behaviour to OSS "code behaviour".
+ * Recording might actually work now.
+ * The real DDMA controller address register is at PCI config
+ * 0x60, while the register at 0x18 is used as a placeholder
+ * register for BIOS address allocation. This register
+ * is supposed to be copied into 0x60, according
+ * to the Solo1 datasheet. When I do that, I can access
+ * the DDMA registers except the mask bit, which
+ * is stuck at 1. When I copy the contents of 0x18 +0x10
+ * to the DDMA base register, everything seems to work.
+ * 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.1999 0.7 add spin_lock_init
+ * replaced current->state = x with set_current_state(x)
+ * 03.09.1999 0.8 change read semantics for MIDI to match
+ * OSS more closely; remove possible wakeup race
+ * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out
+ * Revised resource grabbing for the FM synthesizer
+ * 28.10.1999 0.10 More waitqueue races fixed
+ * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
+ * Disabling recording on Alpha
+ * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * Integrated (aka redid 8-)) APM support patch by Zach Brown
*
*/
@@ -79,6 +82,7 @@
#include <linux/soundcard.h>
#include <linux/pci.h>
#include <linux/bitops.h>
+#include <linux/apm_bios.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
@@ -1224,7 +1228,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
- int val, mapped, ret;
+ int val, mapped, ret, count;
int div1, div2;
unsigned rate1, rate2;
@@ -1304,7 +1308,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
stop_dac(s);
s->dma_adc.ready = s->dma_dac.ready = 0;
/* program channels */
- s->channels = val ? 2 : 1;
+ s->channels = (val >= 2) ? 2 : 1;
prog_codec(s);
}
return put_user(s->channels, (int *)arg);
@@ -1368,7 +1372,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac.dmasize - count;
abinfo.fragstotal = s->dma_dac.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1397,9 +1404,11 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
- val = s->dma_dac.count;
+ count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
@@ -1420,7 +1429,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac.fragshift;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
@@ -2132,6 +2144,79 @@ static struct initvol {
{ SOUND_MIXER_WRITE_MIC, 0x4040 }
};
+static int setup_solo1(struct solo1_state *s)
+{
+ struct pci_dev *pcidev = s->pcidev;
+ mm_segment_t fs;
+ int i, val;
+
+ /* initialize the chips */
+ if (!reset_ctrl(s)) {
+ printk(KERN_ERR "esssolo1: cannot reset controller\n");
+ return -1;
+ }
+ outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
+
+ /* initialize mixer regs */
+ write_mixer(s, 0x7f, 0); /* disable music digital recording */
+ write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
+ write_mixer(s, 0x64, 0x45); /* volume control */
+ write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
+ write_mixer(s, 0x50, 0); /* disable spatializer */
+ write_mixer(s, 0x52, 0);
+ write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
+ write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
+ outb(0, s->ddmabase+0xd); /* DMA master clear */
+ outb(1, s->ddmabase+0xf); /* mask channel */
+ /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
+
+ pci_set_master(pcidev); /* enable bus mastering */
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ val = SOUND_MASK_LINE;
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ val = initvol[i].vol;
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ val = 1; /* enable mic preamp */
+ mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
+ set_fs(fs);
+ return 0;
+}
+
+#ifdef CONFIG_APM
+
+static int solo1_apm_callback(apm_event_t event)
+{
+ struct solo1_state *s;
+
+ switch(event) {
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ case APM_STANDBY_RESUME:
+ for(s = devs ; s ; s = s->next)
+ setup_solo1(s);
+ break;
+
+ default:
+ for(s = devs ; s ; s = s->next) {
+ outb(0, s->iobase+6);
+ /* DMA master clear */
+ outb(0, s->ddmabase+0xd);
+ /* reset sequencer and FIFO */
+ outb(3, s->sbbase+6);
+ /* turn off DDMA controller address space */
+ pci_write_config_word(s->pcidev, 0x60, 0);
+ }
+ }
+ return 0;
+}
+
+#endif
+
+
#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)
@@ -2141,12 +2226,11 @@ static int __init init_solo1(void)
{
struct solo1_state *s;
struct pci_dev *pcidev = NULL;
- mm_segment_t fs;
- int i, val, index = 0;
+ int index = 0;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.12 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
if (!RSRCISIOREGION(pcidev, 0) ||
@@ -2192,13 +2276,7 @@ static int __init init_solo1(void)
printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
goto err_irq;
}
- /* initialize DDMA base address */
printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
- pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
- /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
- pci_write_config_dword(pcidev, 0x50, 0);
- /* disable legacy audio address decode */
- pci_write_config_word(pcidev, 0x40, 0x907f);
printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
@@ -2211,39 +2289,8 @@ static int __init init_solo1(void)
goto err_dev3;
if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
goto err_dev4;
- /* initialize the chips */
- if (!reset_ctrl(s)) {
- printk(KERN_ERR "esssolo1: cannot reset controller\n");
+ if (setup_solo1(s))
goto err;
- }
- outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
-
- /* initialize mixer regs */
- write_mixer(s, 0x7f, 0); /* disable music digital recording */
- write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
- write_mixer(s, 0x64, 0x45); /* volume control */
- write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
- write_mixer(s, 0x50, 0); /* disable spatializer */
- write_mixer(s, 0x52, 0);
- write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
- write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(1, s->ddmabase+0xf); /* mask channel */
- /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
-
- pci_set_master(pcidev); /* enable bus mastering */
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- val = 1; /* enable mic preamp */
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
- set_fs(fs);
/* queue it for later freeing */
s->next = devs;
devs = s;
@@ -2259,7 +2306,7 @@ static int __init init_solo1(void)
err_dev2:
unregister_sound_dsp(s->dev_audio);
err_dev1:
- printk(KERN_ERR "solo1: cannot register misc device\n");
+ printk(KERN_ERR "solo1: initialisation error\n");
free_irq(s->irq, s);
err_irq:
release_region(s->iobase, IOBASE_EXTENT);
@@ -2271,6 +2318,9 @@ static int __init init_solo1(void)
}
if (!devs)
return -ENODEV;
+#ifdef CONFIG_APM
+ apm_register_callback(solo1_apm_callback);
+#endif
return 0;
}
@@ -2302,6 +2352,9 @@ static void __exit cleanup_solo1(void)
unregister_sound_special(s->dev_dmfm);
kfree_s(s, sizeof(struct solo1_state));
}
+#ifdef CONFIG_APM
+ apm_unregister_callback(solo1_apm_callback);
+#endif
printk(KERN_INFO "solo1: unloading\n");
}
diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c
index 4bfca0875..e47c30f90 100644
--- a/drivers/sound/msnd.c
+++ b/drivers/sound/msnd.c
@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $
+ * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $
*
********************************************************************/
@@ -66,7 +66,7 @@ int msnd_register(multisound_dev_t *dev)
if (i == MSND_MAX_DEVS)
return -ENOMEM;
-
+
devs[i] = dev;
++num_devs;
@@ -106,13 +106,21 @@ multisound_dev_t *msnd_get_dev(int j)
for (i = 0; i < MSND_MAX_DEVS && j; ++i)
if (devs[i] != NULL)
--j;
-
+
if (i == MSND_MAX_DEVS || j != 0)
return NULL;
return devs[i];
}
+void msnd_init_queue(unsigned long base, int start, int size)
+{
+ isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
+ isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ isa_writew(0, base + JQS_wHead);
+ isa_writew(0, base + JQS_wTail);
+}
+
void msnd_fifo_init(msnd_fifo *f)
{
f->data = NULL;
@@ -152,11 +160,11 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
if (f->len == f->n)
return 0;
-
+
while ((count < len) && (f->len != f->n)) {
-
+
int nwritten;
-
+
if (f->head <= f->tail) {
nwritten = len - count;
if (nwritten > f->n - f->tail)
@@ -180,7 +188,7 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
f->tail += nwritten;
f->tail %= f->n;
}
-
+
return count;
}
@@ -190,11 +198,11 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
if (f->len == 0)
return f->len;
-
+
while ((count < len) && (f->len > 0)) {
-
+
int nread;
-
+
if (f->tail <= f->head) {
nread = len - count;
if (nread > f->n - f->head)
@@ -205,20 +213,20 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
if (nread > len - count)
nread = len - count;
}
-
+
if (user) {
if (copy_to_user(buf, f->data + f->head, nread))
return -EFAULT;
} else
memcpy(buf, f->data + f->head, nread);
-
+
count += nread;
buf += nread;
f->len -= nread;
f->head += nread;
f->head %= f->n;
}
-
+
return count;
}
@@ -259,7 +267,7 @@ int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
spin_unlock_irqrestore(&dev->lock, flags);
printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
-
+
return -EIO;
}
@@ -307,7 +315,7 @@ int msnd_enable_irq(multisound_dev_t *dev)
return 0;
printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
-
+
spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_TXDE(dev) == 0) {
outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
@@ -316,6 +324,7 @@ int msnd_enable_irq(multisound_dev_t *dev)
outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
enable_irq(dev->irq);
+ msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
@@ -360,6 +369,8 @@ EXPORT_SYMBOL(msnd_unregister);
EXPORT_SYMBOL(msnd_get_num_devs);
EXPORT_SYMBOL(msnd_get_dev);
+EXPORT_SYMBOL(msnd_init_queue);
+
EXPORT_SYMBOL(msnd_fifo_init);
EXPORT_SYMBOL(msnd_fifo_free);
EXPORT_SYMBOL(msnd_fifo_alloc);
diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h
index 54bf5fd01..219a6bfe0 100644
--- a/drivers/sound/msnd.h
+++ b/drivers/sound/msnd.h
@@ -24,13 +24,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd.h,v 1.33 1998/11/05 20:26:18 andrewtv Exp $
+ * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_H
#define __MSND_H
-#define VERSION "0.8.2.2"
+#define VERSION "0.8.3.1"
#define DEFSAMPLERATE DSP_DEFAULT_SPEED
#define DEFSAMPLESIZE AFMT_U8
@@ -202,6 +202,7 @@ typedef struct multisound_dev {
/* Linux device info */
char *name;
int dsp_minor, mixer_minor;
+ int ext_midi_dev, hdr_midi_dev;
/* Hardware resources */
int io, numio;
@@ -214,6 +215,7 @@ typedef struct multisound_dev {
unsigned long SMA;
unsigned long DAPQ, DARQ, MODQ, MIDQ, DSPQ;
unsigned long pwDSPQData, pwMIDQData, pwMODQData;
+ int dspq_data_buff, dspq_buff_size;
/* State variables */
enum { msndClassic, msndPinnacle } type;
@@ -229,7 +231,7 @@ typedef struct multisound_dev {
#define F_READING 7
#define F_READBLOCK 8
#define F_EXT_MIDI_INUSE 9
-#define F_INT_MIDI_INUSE 10
+#define F_HDR_MIDI_INUSE 10
#define F_DISABLE_WRITE_NDELAY 11
wait_queue_head_t writeblock;
wait_queue_head_t readblock;
@@ -269,6 +271,8 @@ void msnd_unregister(multisound_dev_t *dev);
int msnd_get_num_devs(void);
multisound_dev_t * msnd_get_dev(int i);
+void msnd_init_queue(unsigned long, int start, int size);
+
void msnd_fifo_init(msnd_fifo *f);
void msnd_fifo_free(msnd_fifo *f);
int msnd_fifo_alloc(msnd_fifo *f, size_t n);
diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h
index 25898f8e0..83c3c46ff 100644
--- a/drivers/sound/msnd_classic.h
+++ b/drivers/sound/msnd_classic.h
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $
+ * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_CLASSIC_H
@@ -108,13 +108,13 @@
#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
-#define MOP_PROTEUS 0x10
+#define MOP_SYNTH 0x10
#define MOP_EXTOUT 0x32
#define MOP_EXTTHRU 0x02
#define MOP_OUTMASK 0x01
#define MIP_EXTIN 0x01
-#define MIP_PROTEUS 0x00
+#define MIP_SYNTH 0x00
#define MIP_INMASK 0x32
/* Classic SMA Common Data */
diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c
index d90bb071a..dd1b596f4 100644
--- a/drivers/sound/msnd_pinnacle.c
+++ b/drivers/sound/msnd_pinnacle.c
@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_pinnacle.c,v 1.73 1998/12/04 14:41:02 andrewtv Exp $
+ * $Id: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv Exp $
*
********************************************************************/
@@ -254,7 +254,7 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case SNDCTL_DSP_SYNC:
dsp_write_flush();
return 0;
-
+
case SNDCTL_DSP_GETBLKSIZE:
tmp = dsp_get_frag_size();
if (put_user(tmp, (int *)arg))
@@ -352,7 +352,7 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
}
-
+
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
if (file->f_mode & FMODE_WRITE)
isa_writew(data, lpDAQ + DAQDS_wChannels);
@@ -570,7 +570,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
return 0;
} else if (((cmd >> 8) & 0xff) == 'M') {
int val = 0;
-
+
if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
switch (cmd & 0xff) {
case SOUND_MIXER_RECSRC:
@@ -578,7 +578,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
return -EFAULT;
val = set_recsrc(val);
break;
-
+
default:
if (get_user(val, (int *)arg))
return -EFAULT;
@@ -592,7 +592,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
case SOUND_MIXER_RECSRC:
val = dev.recsrc;
break;
-
+
case SOUND_MIXER_DEVMASK:
case SOUND_MIXER_STEREODEVS:
val = SOUND_MASK_PCM |
@@ -620,7 +620,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
case SOUND_MIXER_CAPS:
val = SOUND_CAP_EXCL_INPUT;
break;
-
+
default:
if ((val = mixer_get(cmd & 0xff)) < 0)
return -EINVAL;
@@ -787,7 +787,7 @@ static int dev_open(struct inode *inode, struct file *file)
/* nothing */
} else
err = -EINVAL;
-
+
if (err >= 0)
mod_inc_ref();
@@ -873,7 +873,7 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
register int n;
unsigned long flags;
-
+
/* Write the data to the new tail */
if (protect) {
/* Critical section: protect fifo in non-interrupt */
@@ -910,11 +910,9 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
/* Then advance the tail */
DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
-
/* Tell the DSP to play the bank */
msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
}
-
return nbanks;
}
@@ -999,7 +997,7 @@ static int dsp_write(const char *buf, size_t len)
return -EINTR;
}
}
-
+
return len - count;
}
@@ -1142,7 +1140,7 @@ static struct file_operations dev_fileops = {
static int reset_dsp(void)
{
int timeout = 100;
-
+
outb(HPDSPRESET_ON, dev.io + HP_DSPR);
mdelay(1);
#ifndef MSND_CLASSIC
@@ -1190,7 +1188,7 @@ static int __init probe_multisound(void)
case 0x3: xv = "1.4"; break;
default: xv = "unknown"; break;
}
-
+
switch (dev.info & 0x7) {
case 0x0: rev = "I"; dev.name = pin; break;
case 0x1: rev = "F"; dev.name = pin; break;
@@ -1216,18 +1214,9 @@ static int __init probe_multisound(void)
dev.base, dev.base + 0x7fff);
release_region(dev.io, dev.numio);
-
return 0;
}
-static void msnd_init_queue(unsigned long base, int start, int size)
-{
- isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
- isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
- isa_writew(0, base + JQS_wHead);
- isa_writew(0, base + JQS_wTail);
-}
-
static int init_sma(void)
{
static int initted;
@@ -1383,7 +1372,7 @@ static int initialize(void)
if ((err = reset_dsp()) < 0)
return err;
-
+
if ((err = upload_dsp_code()) < 0) {
printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
return err;
@@ -1462,12 +1451,14 @@ static int __init attach_multisound(void)
return dev.mixer_minor;
}
+ dev.ext_midi_dev = dev.hdr_midi_dev = -1;
+
disable_irq(dev.irq);
calibrate_adc(dev.play_sample_rate);
#ifndef MSND_CLASSIC
force_recsrc(SOUND_MASK_IMIX);
#endif
-
+
return 0;
}
@@ -1593,7 +1584,7 @@ static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cf
/* Configure specified devices */
for (i = 0; i < 4; ++i) {
-
+
switch (i) {
case 0: /* DSP */
if (!(device[i].io0 && device[i].irq && device[i].mem))
@@ -1776,7 +1767,7 @@ int __init msnd_pinnacle_init(void)
printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
VERSION ", Copyright (C) 1998 Andrew Veliath\n");
-
+
if (io == -1 || irq == -1 || mem == -1)
printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
@@ -1792,7 +1783,7 @@ int __init msnd_pinnacle_init(void)
printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n");
return -EINVAL;
}
-
+
if (irq == -1 ||
!(irq == 5 ||
irq == 7 ||
@@ -1849,7 +1840,7 @@ int __init msnd_pinnacle_init(void)
pinnacle_devs[0].mem = mem;
/* The following are Pinnacle specific */
-
+
/* MPU */
pinnacle_devs[1].io0 = mpu_io;
pinnacle_devs[1].irq = mpu_irq;
@@ -1896,6 +1887,8 @@ int __init msnd_pinnacle_init(void)
dev.fifosize = fifosize * 1024;
dev.calibrate_signal = calibrate_signal ? 1 : 0;
dev.recsrc = 0;
+ dev.dspq_data_buff = DSPQ_DATA_BUFF;
+ dev.dspq_buff_size = DSPQ_BUFF_SIZE;
dev.inc_ref = mod_inc_ref;
dev.dec_ref = mod_dec_ref;
if (write_ndelay == -1)
@@ -1934,7 +1927,7 @@ int __init msnd_pinnacle_init(void)
msnd_fifo_free(&dev.DARF);
return err;
}
-
+
if ((err = attach_multisound()) < 0) {
printk(KERN_ERR LOGNAME ": Attach failed\n");
msnd_fifo_free(&dev.DAPF);
diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h
index 2f572af2c..e85aef4a5 100644
--- a/drivers/sound/msnd_pinnacle.h
+++ b/drivers/sound/msnd_pinnacle.h
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $
+ * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_PINNACLE_H
@@ -141,18 +141,16 @@
#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
-#define WAVEHDR_MOP 0
-#define EXTOUT_MOP 1
-#define HWINIT_MOP 0xFE
-#define NO_MOP 0xFF
+#define MOP_WAVEHDR 0
+#define MOP_EXTOUT 1
+#define MOP_HWINIT 0xfe
+#define MOP_NONE 0xff
+#define MOP_MAX 1
-#define MAX_MOP 1
-
-#define EXTIN_MIP 0
-#define WAVEHDR_MIP 1
-#define HWINIT_MIP 0xFE
-
-#define MAX_MIP 1
+#define MIP_EXTIN 0
+#define MIP_WAVEHDR 1
+#define MIP_HWINIT 0xfe
+#define MIP_MAX 1
/* Pinnacle/Fiji SMA Common Data */
#define SMA_wCurrPlayBytes 0x0000
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index f52ec2247..245d16a19 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -84,6 +84,9 @@
* 28.10.1999 0.22 More waitqueue races fixed
* 01.12.1999 0.23 New argument to allocate_resource
* 07.12.1999 0.24 More allocate_resource semantics change
+ * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * use Martin Mares' pci_assign_resource
*
*/
@@ -131,6 +134,10 @@
#define SV_EXTENT_GAME 0x8
#define SV_EXTENT_DMA 0x10
+/*
+ * we are not a bridge and thus use a resource for DDMA that is used for bridges but
+ * left empty for normal devices
+ */
#define RESOURCE_SB 0
#define RESOURCE_ENH 1
#define RESOURCE_SYNTH 2
@@ -1533,6 +1540,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
unsigned char fmtm, fmtd;
@@ -1700,7 +1708,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac.dmasize - count;
abinfo.fragstotal = s->dma_dac.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1714,7 +1725,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1729,9 +1743,11 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return -EINVAL;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
- val = s->dma_dac.count;
+ count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
@@ -1739,7 +1755,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -1752,7 +1771,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac.fragshift;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
@@ -2427,7 +2449,7 @@ static int __init init_sonicvibes(void)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.24 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.25 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");
@@ -2444,20 +2466,20 @@ static int __init init_sonicvibes(void)
continue;
/* try to allocate a DDMA resource if not already available */
if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
- /* take care of ISA aliases */
+ pcidev->resource[RESOURCE_DDMA].start = 0;
+ pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
+ pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
ddmanamelen = strlen(sv_ddma_name)+1;
if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
continue;
memcpy(ddmaname, sv_ddma_name, ddmanamelen);
pcidev->resource[RESOURCE_DDMA].name = ddmaname;
- if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA,
- 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024, NULL, NULL)) {
+ if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
pcidev->resource[RESOURCE_DDMA].name = NULL;
kfree(ddmaname);
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");
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 4acffcf6d..4dce39e81 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -3,7 +3,6 @@
*
* Low level driver for Ensoniq SoundScape
*/
-
/*
* Copyright (C) by Hannu Savolainen 1993-1997
*
@@ -11,9 +10,10 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
-
+
/*
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Sergey Smitienko : ensoniq p'n'p support
*/
#include <linux/config.h>
@@ -21,6 +21,26 @@
#include "sound_config.h"
#include "soundmodule.h"
+#include "sound_firmware.h"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/ctype.h>
+#include <linux/stddef.h>
+#include <linux/kmod.h>
+#ifdef __KERNEL__
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <linux/wait.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#endif /* __KERNEL__ */
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+
#ifdef CONFIG_SSCAPE
@@ -71,10 +91,10 @@
#define CMD_GET_BOARD_TYPE 0x82
#define CMD_SET_CONTROL 0x88 /* Old firmware only */
#define CMD_GET_CONTROL 0x89 /* Old firmware only */
-#define CTL_MASTER_VOL 0
-#define CTL_MIC_MODE 2
-#define CTL_SYNTH_VOL 4
-#define CTL_WAVE_VOL 7
+#define CTL_MASTER_VOL 0
+#define CTL_MIC_MODE 2
+#define CTL_SYNTH_VOL 4
+#define CTL_WAVE_VOL 7
#define CMD_SET_EXTMIDI 0x8a
#define CMD_GET_EXTMIDI 0x8b
#define CMD_SET_MT32 0x8c
@@ -82,9 +102,20 @@
#define CMD_ACK 0x80
+#define IC_ODIE 1
+#define IC_OPUS 2
+
typedef struct sscape_info
{
int base, irq, dma;
+
+ int codec, codec_irq; /* required to setup pnp cards*/
+ int codec_type;
+ int ic_type;
+ char* raw_buf;
+ unsigned long raw_buf_phys;
+ int buffsize; /* -------------------------- */
+
int ok; /* Properly detected */
int failed;
int dma_allocated;
@@ -152,6 +183,31 @@ static void sscape_write(struct sscape_info *devc, int reg, int data)
restore_flags(flags);
}
+static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg)
+{
+ unsigned char res;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb( reg, devc -> codec);
+ res = inb (devc -> codec + 1);
+ restore_flags(flags);
+ return res;
+
+}
+
+static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb( reg, devc -> codec);
+ outb( data, devc -> codec + 1);
+ restore_flags(flags);
+}
+
static void host_open(struct sscape_info *devc)
{
outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */
@@ -218,6 +274,13 @@ static int host_read(struct sscape_info *devc)
return data;
}
+static int host_command1(struct sscape_info *devc, int cmd)
+{
+ unsigned char buf[10];
+ buf[0] = (unsigned char) (cmd & 0xff);
+ return host_write(devc, buf, 1);
+}
+
static int host_command2(struct sscape_info *devc, int cmd, int parm1)
{
@@ -544,6 +607,7 @@ static coproc_operations sscape_coproc_operations =
};
static int sscape_detected = 0;
+static int sscape_is_pnp = 0;
void attach_sscape(struct address_info *hw_config)
{
@@ -563,14 +627,14 @@ void attach_sscape(struct address_info *hw_config)
*/
#define SSCAPE_REGS { \
/* I0 */ 0x00, \
- 0xf0, /* Note! Ignored. Set always to 0xf0 */ \
- 0x20, /* Note! Ignored. Set always to 0x20 */ \
- 0x20, /* Note! Ignored. Set always to 0x20 */ \
- 0xf5, /* Ignored */ \
- 0x10, \
- 0x00, \
- 0x2e, /* I7 MEM config A. Likely to vary between models */ \
- 0x00, /* I8 MEM config B. Likely to vary between models */ \
+/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \
+/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \
+/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \
+/* I4 */ 0xf5, /* Ignored */ \
+/* I5 */ 0x10, \
+/* I6 */ 0x00, \
+/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \
+/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \
/* I9 */ 0x40 /* Ignored */ \
}
#endif
@@ -605,11 +669,13 @@ void attach_sscape(struct address_info *hw_config)
printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
return;
}
- save_flags(flags);
- cli();
-
- for (i = 1; i < 10; i++)
- {
+
+ if (sscape_is_pnp == 0) {
+
+ save_flags(flags);
+ cli();
+ for (i = 1; i < 10; i++)
+ {
switch (i)
{
case 1: /* Host interrupt enable */
@@ -640,9 +706,9 @@ void attach_sscape(struct address_info *hw_config)
default:
sscape_write(devc, i, regs[i]);
}
+ }
+ restore_flags(flags);
}
- restore_flags(flags);
-
#ifdef SSCAPE_DEBUG2
/*
* Temporary debugging aid. Print contents of the registers after
@@ -733,6 +799,452 @@ static int detect_ga(sscape_info * devc)
return 1;
}
+static int sscape_read_host_ctrl(sscape_info* devc)
+{
+ return host_read(devc);
+}
+
+static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b)
+{
+ host_command2(devc, a, b);
+}
+
+static int sscape_alloc_dma(sscape_info *devc)
+{
+ char *start_addr, *end_addr;
+ int i, dma_pagesize;
+ int sz, size;
+
+ if (devc->raw_buf != NULL) return 0; /* Already done */
+ dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024);
+ devc->raw_buf = NULL;
+ devc->buffsize = 8192*4;
+ if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize;
+ start_addr = NULL;
+ /*
+ * Now loop until we get a free buffer. Try to get smaller buffer if
+ * it fails. Don't accept smaller than 8k buffer for performance
+ * reasons.
+ */
+ while (start_addr == NULL && devc->buffsize > PAGE_SIZE) {
+ for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
+ devc->buffsize = PAGE_SIZE * (1 << sz);
+ start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);
+ if (start_addr == NULL) devc->buffsize /= 2;
+ }
+
+ if (start_addr == NULL) {
+ printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n");
+ return 0;
+ } else {
+ /* make some checks */
+ end_addr = start_addr + devc->buffsize - 1;
+ /* now check if it fits into the same dma-pagesize */
+
+ if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))
+ || end_addr >= (char *) (MAX_DMA_ADDRESS)) {
+ printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize);
+ return 0;
+ }
+ }
+ devc->raw_buf = start_addr;
+ devc->raw_buf_phys = virt_to_bus(start_addr);
+
+ for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+ set_bit(PG_reserved, &mem_map[i].flags);;
+ return 1;
+}
+
+static void sscape_free_dma(sscape_info *devc)
+{
+ int sz, size, i;
+ unsigned long start_addr, end_addr;
+
+ if (devc->raw_buf == NULL) return;
+ for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
+ start_addr = (unsigned long) devc->raw_buf;
+ end_addr = start_addr + devc->buffsize;
+
+ for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+ clear_bit(PG_reserved, &mem_map[i].flags);;
+
+ free_pages((unsigned long) devc->raw_buf, sz);
+ devc->raw_buf = NULL;
+}
+
+/* Intel version !!!!!!!!! */
+
+static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode)
+{
+ unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ set_dma_mode(chan, dma_mode);
+ set_dma_addr(chan, physaddr);
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+ return 0;
+}
+
+static void sscape_pnp_start_dma(sscape_info* devc, int arg )
+{
+ int reg;
+ if (arg == 0) reg = 2;
+ else reg = 3;
+
+ sscape_write(devc, reg, sscape_read( devc, reg) | 0x01);
+ sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE);
+}
+
+static int sscape_pnp_wait_dma (sscape_info* devc, int arg )
+{
+ int reg;
+ unsigned long i;
+ unsigned char d;
+
+ if (arg == 0) reg = 2;
+ else reg = 3;
+
+ sleep ( 1 );
+ i = 0;
+ do {
+ d = sscape_read(devc, reg) & 1;
+ if ( d == 1) break;
+ i++;
+ } while (i < 500000);
+ d = sscape_read(devc, reg) & 1;
+ return d;
+}
+
+static int sscape_pnp_alloc_dma(sscape_info* devc)
+{
+ /* printk(KERN_INFO "sscape: requesting dma\n"); */
+ if (request_dma(devc -> dma, "sscape")) return 0;
+ /* printk(KERN_INFO "sscape: dma channel allocated\n"); */
+ if (!sscape_alloc_dma(devc)) {
+ free_dma(devc -> dma);
+ return 0;
+ };
+ return 1;
+}
+
+static void sscape_pnp_free_dma(sscape_info* devc)
+{
+ sscape_free_dma( devc);
+ free_dma(devc -> dma );
+ /* printk(KERN_INFO "sscape: dma released\n"); */
+}
+
+static int sscape_pnp_upload_file(sscape_info* devc, char* fn)
+{
+ int done = 0;
+ int timeout_val;
+ char* data,*dt;
+ int len,l;
+ unsigned long flags;
+
+ sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F );
+ sscape_write( devc, 2, (devc -> dma << 4) | 0x80 );
+ sscape_write( devc, 3, 0x20 );
+ sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 );
+
+ len = mod_firmware_load(fn, &data);
+ if (len == 0) {
+ printk(KERN_ERR "sscape: file not found: %s\n", fn);
+ return 0;
+ }
+ dt = data;
+ save_flags(flags);
+ cli();
+ while ( len > 0 ) {
+ if (len > devc -> buffsize) l = devc->buffsize;
+ else l = len;
+ len -= l;
+ memcpy(devc->raw_buf, dt, l); dt += l;
+ sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48);
+ sscape_pnp_start_dma ( devc, 0 );
+ if (sscape_pnp_wait_dma ( devc, 0 ) == 0) return 0;
+ }
+
+ restore_flags(flags);
+ vfree(data);
+
+ outb(0, devc -> base + 2);
+ outb(0, devc -> base);
+
+ sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40);
+
+ timeout_val = 5 * HZ;
+ while (!done && timeout_val-- > 0)
+ {
+ unsigned char x;
+ sleep(1);
+ x = inb( devc -> base + 3);
+ if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */
+ {
+ //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
+ done = 1;
+ }
+ }
+ timeout_val = 5 * HZ;
+ done = 0;
+ while (!done && timeout_val-- > 0)
+ {
+ unsigned char x;
+ sleep(1);
+ x = inb( devc -> base + 3);
+ if (x == 0xfe) /* OBP startup acknowledge */
+ {
+ //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
+ done = 1;
+ }
+ }
+
+ if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
+
+ sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
+ sscape_write( devc, 3, (devc -> dma << 4) + 0x80);
+ return 1;
+}
+
+static void sscape_pnp_init_hw(sscape_info* devc)
+{
+ unsigned char midi_irq = 0, sb_irq = 0;
+ unsigned i;
+ static char code_file_name[23] = "/sndscape/sndscape.cox";
+
+ int sscape_sb_enable = 0;
+ int sscape_joystic_enable = 0x7f;
+ int sscape_mic_enable = 0;
+ int sscape_ext_midi = 0;
+
+ if ( !sscape_pnp_alloc_dma(devc) ) {
+ printk(KERN_ERR "sscape: faild to allocate dma\n");
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if ( devc -> irq == valid_interrupts[i] )
+ midi_irq = i;
+ if ( devc -> codec_irq == valid_interrupts[i] )
+ sb_irq = i;
+ }
+
+ sscape_write( devc, 5, 0x50);
+ sscape_write( devc, 7, 0x2e);
+ sscape_write( devc, 8, 0x00);
+
+ sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
+ sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
+
+ if ( sscape_sb_enable )
+ sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq);
+ else
+ sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
+
+ i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
+ if ( sscape_sb_enable )
+ i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07;
+ if (sscape_joystic_enable) i |= 8;
+
+ sscape_write (devc, 9, i);
+ sscape_write (devc, 6, 0x80);
+ sscape_write (devc, 1, 0x80);
+
+ if (devc -> codec_type == 2) {
+ sscape_pnp_write_codec( devc, 0x0C, 0x50);
+ sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F);
+ sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0);
+ sscape_pnp_write_codec( devc, 29, 0x20);
+ }
+
+ if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) {
+ printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n");
+ sscape_pnp_free_dma(devc);
+ return;
+ }
+
+ i = sscape_read_host_ctrl( devc );
+
+ if ( (i & 0x0F) > 7 ) {
+ printk(KERN_ERR "sscape: scope.cod faild\n");
+ sscape_pnp_free_dma(devc);
+ return;
+ }
+ if ( i & 0x10 ) sscape_write( devc, 7, 0x2F);
+ code_file_name[21] = (char) ( i & 0x0F) + 0x30;
+ if (sscape_pnp_upload_file( devc, code_file_name) == 0) {
+ printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name);
+ sscape_pnp_free_dma(devc);
+ return;
+ }
+
+ if (devc->ic_type != IC_ODIE) {
+ sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) |
+ ( sscape_mic_enable == 0 ? 0x00 : 0x80) );
+ }
+ sscape_write_host_ctrl2( devc, 0x84, 0x32 );
+ sscape_write_host_ctrl2( devc, 0x86, 0x32 );
+ sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi);
+
+ sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL
+ sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL
+ sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL
+ sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR
+
+ if (devc -> codec_type == 1) {
+ sscape_pnp_write_codec ( devc, 4, 0x1F );
+ sscape_pnp_write_codec ( devc, 5, 0x1F );
+ sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable);
+ } else {
+ int t;
+ sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1);
+ sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1));
+
+ t = sscape_pnp_read_codec( devc, 0x00) & 0xDF;
+ if ( (sscape_mic_enable == 0)) t |= 0;
+ else t |= 0x20;
+ sscape_pnp_write_codec ( devc, 0x00, t);
+ t = sscape_pnp_read_codec( devc, 0x01) & 0xDF;
+ if ( (sscape_mic_enable == 0) ) t |= 0;
+ else t |= 0x20;
+ sscape_pnp_write_codec ( devc, 0x01, t);
+ sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20);
+ outb(0, devc -> codec);
+ }
+ if (devc -> ic_type == IC_OPUS ) {
+ int i = sscape_read( devc, 9 );
+ sscape_write( devc, 9, i | 3 );
+ sscape_write( devc, 3, 0x40);
+
+ if (check_region(0x228, 1)) {
+ outb(0, 0x228);
+ release_region(0x228,1);
+ }
+ sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
+ sscape_write( devc, 9, i );
+ }
+
+ host_close ( devc );
+ sscape_pnp_free_dma(devc);
+}
+
+static int detect_sscape_pnp(sscape_info* devc)
+{
+ long i, irq_bits = 0xff;
+ unsigned int d;
+
+ DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
+
+ if (check_region(devc->base, 8)) {
+ printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->base);
+ return 0;
+ }
+
+ if (check_region(devc->codec, 2)) {
+ printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);
+ return 0;
+ }
+
+ if ( (inb( devc -> base + 2) & 0x78) != 0) return 0;
+
+ d = inb ( devc -> base + 4) & 0xF0;
+ if ( (d & 0x80) != 0) return 0;
+
+ if (d == 0) {
+ devc->codec_type = 1;
+ devc->ic_type = IC_ODIE;
+ }
+ else if ( (d & 0x60) != 0) {
+ devc->codec_type = 2;
+ devc->ic_type = IC_OPUS;
+ }
+ else if ( (d & 0x40) != 0) {
+ devc->codec_type = 2;
+ devc->ic_type = IC_ODIE;
+ }
+ else return 0;
+
+ sscape_is_pnp = 1;
+
+ outb(0xFA, devc -> base+4);
+ if ((inb( devc -> base+4) & 0x9F) != 0x0A)
+ return 0;
+ outb(0xFE, devc -> base+4);
+ if ( (inb(devc -> base+4) & 0x9F) != 0x0E)
+ return 0;
+ if ( (inb(devc -> base+5) & 0x9F) != 0x0E)
+ return 0;
+
+ if (devc->codec_type == 2) {
+ if (devc -> codec != devc -> base + 8)
+ printk("soundscape warning: incorrect codec port specified\n");
+ devc -> codec = devc -> base + 8;
+ d = 0x10 | (sscape_read(devc, 9) & 0xCF);
+ sscape_write(devc, 9, d);
+ sscape_write(devc, 6, 0x80);
+ } else {
+ //todo: check codec is not base + 8
+ }
+
+ d = (sscape_read(devc, 9) & 0x3F) | 0xC0;
+ sscape_write(devc, 9, d);
+
+ for (i = 0; i < 550000; i++)
+ if ( !(inb(devc -> codec) & 0x80) ) break;
+
+ d = inb(devc -> codec);
+ if (d & 0x80)
+ return 0;
+ if ( inb(devc -> codec + 2) == 0xFF)
+ return 0;
+
+ sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F );
+
+ d = inb(devc -> codec) & 0x80;
+ if ( d == 0) {
+ printk(KERN_INFO "soundscape: hardware detected\n");
+ valid_interrupts = valid_interrupts_new;
+ } else {
+ printk(KERN_INFO "soundscape: board looks like media fx\n");
+ valid_interrupts = valid_interrupts_old;
+ old_hardware = 1;
+ }
+
+ sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) );
+
+ for (i = 0; i < 550000; i++)
+ if ( !(inb(devc -> codec) & 0x80))
+ break;
+
+ sscape_pnp_init_hw(devc);
+
+ for (i = 0; i < sizeof(valid_interrupts); i++)
+ {
+ if (devc->codec_irq == valid_interrupts[i]) {
+ irq_bits = i;
+ break;
+ }
+ }
+ sscape_write(devc, GA_INTENA_REG, 0x00);
+ sscape_write(devc, GA_DMACFG_REG, 0x50);
+ sscape_write(devc, GA_DMAA_REG, 0x70);
+ sscape_write(devc, GA_DMAB_REG, 0x20);
+ sscape_write(devc, GA_INTCFG_REG, 0xf0);
+ sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1));
+
+ sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
+ sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
+
+ release_region(devc->codec, 2);
+ release_region(devc->base, 8);
+
+ return 1;
+}
+
int probe_sscape(struct address_info *hw_config)
{
@@ -758,8 +1270,13 @@ int probe_sscape(struct address_info *hw_config)
#endif
devc->failed = 1;
- if (!detect_ga(devc))
- return 0;
+ if (!detect_ga(devc)) {
+ if (detect_sscape_pnp(devc)) {
+ sscape_detected = hw_config->io_base;
+ return 1;
+ }
+ else return 0;
+ }
if (old_hardware) /* Check that it's really an old Spea/Reveal card. */
{
@@ -781,11 +1298,11 @@ int probe_ss_ms_sound(struct address_info *hw_config)
{
int i, irq_bits = 0xff;
int ad_flags = 0;
-
+
if (devc->failed)
{
- printk(KERN_ERR "soundscape: Card not detected\n");
- return 0;
+ printk(KERN_ERR "soundscape: Card not detected\n");
+ return 0;
}
if (devc->ok == 0)
{
@@ -805,9 +1322,19 @@ int probe_ss_ms_sound(struct address_info *hw_config)
printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
return 0;
}
- if (old_hardware)
- ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
- return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+
+ if (!sscape_is_pnp) {
+ if (old_hardware)
+ ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+ return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+ }
+ else {
+ if (old_hardware)
+ ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+ else
+ ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */
+ return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+ }
}
void attach_ss_ms_sound(struct address_info *hw_config)
@@ -820,44 +1347,52 @@ void attach_ss_ms_sound(struct address_info *hw_config)
int i, irq_bits = 0xff;
- hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */
-
- /*
- * Setup the DMA polarity.
- */
-
- sscape_write(devc, GA_DMACFG_REG, 0x50);
-
- /*
- * Take the gate-array off of the DMA channel.
- */
-
- sscape_write(devc, GA_DMAB_REG, 0x20);
-
- /*
- * Init the AD1848 (CD-ROM) config reg.
- */
-
- for (i = 0; i < sizeof(valid_interrupts); i++)
- {
- if (hw_config->irq == valid_interrupts[i])
- {
- irq_bits = i;
- break;
- }
- }
- sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
-
- if (hw_config->irq == devc->irq)
- printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
-
- hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma,
- 0,
- devc->osp);
-
+
+ if (!sscape_is_pnp) /*pnp is already setup*/
+ {
+ /*
+ * Setup the DMA polarity.
+ */
+ sscape_write(devc, GA_DMACFG_REG, 0x50);
+
+ /*
+ * Take the gate-array off of the DMA channel.
+ */
+ sscape_write(devc, GA_DMAB_REG, 0x20);
+
+ /*
+ * Init the AD1848 (CD-ROM) config reg.
+ */
+ for (i = 0; i < sizeof(valid_interrupts); i++)
+ {
+ if (hw_config->irq == valid_interrupts[i])
+ {
+ irq_bits = i;
+ break;
+ }
+ }
+ sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
+ }
+
+ if (hw_config->irq == devc->irq)
+ printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
+
+ if (! sscape_is_pnp )
+ hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma,
+ 0,
+ devc->osp);
+
+ else
+ hw_config->slots[0] = ad1848_init("SoundScape PNP", hw_config->io_base,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma,
+ 0,
+ devc->osp);
+
if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */
{
audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations;
@@ -867,6 +1402,7 @@ void attach_ss_ms_sound(struct address_info *hw_config)
/* Set proper routings here (what are they) */
AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
}
+
#ifdef SSCAPE_DEBUG5
/*
* Temporary debugging aid. Print contents of the registers
@@ -937,6 +1473,13 @@ int init_module(void)
printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n");
return -EINVAL;
}
+
+ devc->codec = io;
+ devc->codec_irq = irq;
+ devc->codec_type = 0;
+ devc->ic_type = 0;
+ devc->raw_buf = NULL;
+
config.irq = irq;
config.dma = dma;
config.io_base = io;
diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c
index bfb92dd5e..c8c0cd0c3 100644
--- a/drivers/sound/trident.c
+++ b/drivers/sound/trident.c
@@ -29,6 +29,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* History
+ * v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
+ * adapt to 2.3.x new __setup/__initcall
* v0.04 Dec 31 1999 Ollie Lho
* Multiple Open, useing Middle Loop Interrupt to smooth playback
* v0.03 Dec 24 1999 Ollie Lho
@@ -68,7 +70,7 @@
#undef DEBUG
-#define DRIVER_VERSION "0.03"
+#define DRIVER_VERSION "0.05"
#define TRIDENT_FMT_STEREO 0x01
#define TRIDENT_FMT_16BIT 0x02
@@ -2921,11 +2923,7 @@ static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_in
return 1;
}
-#ifdef MODULE
-int init_module(void)
-#else
-int __init init_trident(void)
-#endif
+static int __init init_trident(void)
{
struct pci_dev *pcidev = NULL;
int foundone = 0;
@@ -2951,15 +2949,14 @@ int __init init_trident(void)
return 0;
}
-#ifdef MODULE
-MODULE_AUTHOR("Alan Cox <alan@redhat.com>");
+MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
#ifdef DEBUG
MODULE_PARM(debug,"i");
#endif
-void cleanup_module(void)
+static void __exit cleanup_trident(void)
{
while (devs != NULL) {
/* Kill interrupts, and SP/DIF */
@@ -2978,6 +2975,8 @@ void cleanup_module(void)
devs = devs->next;
}
}
-#endif /* MODULE */
+
+module_init(init_trident);
+module_exit(cleanup_trident);
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 8385af46a..0d590da23 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -1973,7 +1973,7 @@ static void aec_stop(int board)
ixj_WriteDSPCommand(0x0700, board);
}
- if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1);
+ if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1)
{
ixj_WriteDSPCommand(0xB002, board); // AEC Stop
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index cd614ba1c..b0a372455 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -8,20 +8,25 @@ tristate 'Support for USB' CONFIG_USB
if [ ! "$CONFIG_USB" = "n" ]; then
comment 'USB Controllers'
- dep_tristate ' UHCI (Intel PIIX4, VIA, and others) support' CONFIG_USB_UHCI $CONFIG_USB
- dep_tristate ' OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, and others) support' CONFIG_USB_OHCI_HCD $CONFIG_USB
+ dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ dep_tristate ' OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI_HCD $CONFIG_USB
comment 'Miscellaneous USB options'
- if [ "$CONFIG_PROC_FS" != "n" ]; then
- bool ' /proc/bus/usb support' CONFIG_USB_PROC
- fi
+ bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
comment 'USB Devices'
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
- dep_tristate ' USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
+ dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
+ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
+ bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
+ bool ' USB ConnectTech WhiteHEAT Serial Driver' CONFIG_USB_SERIAL_WHITEHEAT
+ bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR
+ bool ' USB Belkin Single Port Serial Driver' CONFIG_USB_SERIAL_BELKIN
+ bool ' USB Peracom Single Port Serial Driver' CONFIG_USB_SERIAL_PERACOM
+ fi
dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
@@ -29,7 +34,6 @@ comment 'USB Devices'
if [ "$CONFIG_USB_SCSI" != "n" ]; then
bool ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG
fi
- dep_tristate ' EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
@@ -39,6 +43,8 @@ comment 'USB HID'
dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB
dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB
fi
+ dep_tristate ' Wacom Graphire tablet support' CONFIG_USB_GRAPHIRE $CONFIG_USB
+ dep_tristate ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB
dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index be2c90a3f..9eb62b6a1 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -29,8 +29,8 @@ usb-scsi-objs := usb_scsi.o
# Optional parts of multipart objects.
-ifeq ($(CONFIG_USB_PROC),y)
- usbcore-objs += proc_usb.o
+ifeq ($(CONFIG_USB_DEVICEFS),y)
+ usbcore-objs += devio.o inode.o drivers.o devices.o
endif
ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
usb-scsi-objs += usb_scsi_debug.o
@@ -52,6 +52,8 @@ obj-$(CONFIG_USB_OHCI_HCD) += usb-ohci-hcd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o
obj-$(CONFIG_USB_HID) += hid.o input.o
obj-$(CONFIG_USB_KBD) += usbkbd.o input.o
+obj-$(CONFIG_USB_GRAPHIRE) += graphire.o input.o
+obj-$(CONFIG_USB_WMFORCE) += wmforce.o input.o
obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o
@@ -65,7 +67,6 @@ obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_CPIA) += cpia.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
obj-$(CONFIG_USB_SCSI) += usb-scsi.o
-obj-$(CONFIG_USB_EZUSB) += ezusb.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index c14d53d06..154d5cd22 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -1,10 +1,10 @@
/*
- * acm.c Version 0.11
+ * acm.c Version 0.14
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
* Copyright (c) 1999 Johannes Erdfelt <jerdfelt@valinux.com>
- * Copyright (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
*
* USB Abstract Control Model driver for USB modems and ISDN adapters
*
@@ -15,6 +15,8 @@
* v0.10 - some more cleanups
* v0.11 - fixed flow control, read error doesn't stop reads
* v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
+ * v0.13 - added termios, added hangup
+ * v0.14 - sized down struct acm
*/
/*
@@ -51,6 +53,14 @@
#include "usb.h"
/*
+ * CMSPAR, some architectures can't have space and mark parity.
+ */
+
+#ifndef CMSPAR
+#define CMSPAR 0
+#endif
+
+/*
* Major and minor numbers.
*/
@@ -75,7 +85,7 @@
#define ACM_REQ_SEND_BREAK 0x23
/*
- * IRQs
+ * IRQs.
*/
#define ACM_IRQ_NETWORK 0x00
@@ -105,7 +115,7 @@
* Line speed and caracter encoding.
*/
-struct acm_coding {
+struct acm_line {
__u32 speed;
__u8 stopbits;
__u8 parity;
@@ -118,23 +128,22 @@ struct acm_coding {
struct acm {
struct usb_device *dev; /* the coresponding usb device */
- struct usb_config_descriptor *cfg; /* configuration number on this device */
+ struct usb_interface *iface; /* the interfaces - +0 control +1 data */
struct tty_struct *tty; /* the coresponding tty */
- unsigned int ctrlif; /* interface number for acm control messages */
+ struct urb ctrlurb, readurb, writeurb; /* urbs */
+ struct acm_line line; /* line coding (bits, stop, parity) */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
unsigned int ctrlout; /* output control lines (DTR, RTS) */
- struct acm_coding linecoding; /* line coding (bits, stop, parity) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
- struct urb ctrlurb, readurb, writeurb; /* urbs */
- unsigned int minor; /* acm minor number */
- unsigned int present; /* this device is connected to the usb bus */
unsigned int used; /* someone has this acm's device open */
+ unsigned int minor; /* acm minor number */
+ unsigned char clocal; /* termios CLOCAL */
};
static struct usb_driver acm_driver;
-static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, NULL, NULL, /* .... */ };
+static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
-#define ACM_READY(acm) (acm && acm->present && acm->used)
+#define ACM_READY(acm) (acm && acm->dev && acm->used)
/*
* Functions for ACM control messages.
@@ -143,13 +152,13 @@ static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, NULL, NULL, /* .... */ };
static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
{
int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
- request, USB_RT_ACM, value, acm->ctrlif, buf, len, HZ * 5);
+ request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
return retval < 0 ? retval : 0;
}
-#define acm_set_control(acm, control) acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
-#define acm_set_coding(acm, coding) acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, coding, sizeof(struct acm_coding))
+#define acm_set_control(acm, control) acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
+#define acm_set_line(acm, line) acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
#define acm_send_break(acm, ms) acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
/*
@@ -161,6 +170,7 @@ static void acm_ctrl_irq(struct urb *urb)
struct acm *acm = urb->context;
devrequest *dr = urb->transfer_buffer;
unsigned char *data = (unsigned char *)(dr + 1);
+ int newctrl;
if (!ACM_READY(acm)) return;
@@ -178,7 +188,14 @@ static void acm_ctrl_irq(struct urb *urb)
case ACM_IRQ_LINE_STATE:
- acm->ctrlin = data[0] | (((unsigned int) data[1]) << 8);
+ newctrl = le16_to_cpup((__u16 *) data);
+
+ if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+ dbg("calling hangup");
+ tty_hangup(acm->tty);
+ }
+
+ acm->ctrlin = newctrl;
dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
@@ -248,7 +265,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = acm_table[MINOR(tty->device)];
- if (!acm || !acm->present) return -EINVAL;
+ if (!acm || !acm->dev) return -EINVAL;
tty->driver_data = acm;
acm->tty = tty;
@@ -278,7 +295,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (--acm->used) return;
- if (acm->present) {
+ if (acm->dev) {
acm_set_control(acm, acm->ctrlout = 0);
usb_unlink_urb(&acm->ctrlurb);
usb_unlink_urb(&acm->writeurb);
@@ -352,7 +369,7 @@ static void acm_tty_break_ctl(struct tty_struct *tty, int state)
static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct acm *acm = tty->driver_data;
- unsigned int retval, ctrl, old;
+ unsigned int retval, mask, newctrl;
if (!ACM_READY(acm)) return -EINVAL;
@@ -371,26 +388,68 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int
case TIOCMBIS:
case TIOCMBIC:
- if ((retval = get_user(ctrl, (unsigned long *) arg))) return retval;
+ if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
- ctrl = (ctrl & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (ctrl & TIOCM_RTS ? ACM_CTRL_RTS : 0);
- old = acm->ctrlout;
+ newctrl = acm->ctrlout;
+ mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
switch (cmd) {
- case TIOCMSET: acm->ctrlout = ctrl; break;
- case TIOCMBIS: acm->ctrlout |= ctrl; break;
- case TIOCMBIC: acm->ctrlout &= ~ctrl; break;
+ case TIOCMSET: newctrl = mask; break;
+ case TIOCMBIS: newctrl |= mask; break;
+ case TIOCMBIC: newctrl &= ~mask; break;
}
- if (acm->ctrlout == old) return 0;
- return acm_set_control(acm, acm->ctrlout);
+ if (acm->ctrlout == newctrl) return 0;
+ return acm_set_control(acm, acm->ctrlout = newctrl);
}
- dbg("unknown ioctl %#x", cmd);
-
return -ENOIOCTLCMD;
}
+static __u32 acm_tty_speed[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600,
+ 1200, 1800, 2400, 4800, 9600, 19200, 38400,
+ 57600, 115200, 230400, 460800, 500000, 576000,
+ 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+};
+
+static __u8 acm_tty_size[] = {
+ 5, 6, 7, 8
+};
+
+static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+{
+ struct acm *acm = tty->driver_data;
+ struct termios *termios = tty->termios;
+ struct acm_line newline;
+
+ if (!ACM_READY(acm)) return;
+
+ newline.speed = cpu_to_le32p(acm_tty_speed +
+ (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
+ newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
+ newline.parity = termios->c_cflag & PARENB ?
+ (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+ newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
+
+ acm->clocal = termios->c_cflag & CLOCAL;
+
+ if (!memcmp(&acm->line, &newline, sizeof(struct acm_line)))
+ return;
+
+ memcpy(&acm->line, &newline, sizeof(struct acm_line));
+
+ if (!newline.speed) {
+ if (acm->ctrlout) acm_set_control(acm, acm->ctrlout = 0);
+ return;
+ }
+
+ acm_set_line(acm, &acm->line);
+
+ dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
+}
+
/*
* USB probe and disconnect routines.
*/
@@ -398,36 +457,21 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int
static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
{
struct acm *acm;
+ struct usb_config_descriptor *cfacm;
struct usb_interface_descriptor *ifcom, *ifdata;
struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
int readsize, ctrlsize, minor, i;
unsigned char *buf;
- for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-
- if (acm_table[minor]) {
- dbg("no more free acm devices");
- return NULL;
- }
-
- if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) return NULL;
- memset(acm, 0, sizeof(struct acm));
-
- acm_table[minor] = acm;
- acm->minor = minor;
- acm->dev = dev;
-
if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
- || dev->descriptor.bDeviceProtocol != 0) {
- return NULL;
- }
+ || dev->descriptor.bDeviceProtocol != 0) return NULL;
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- acm->cfg = dev->config + i;
- dbg("probing config %d", acm->cfg->bConfigurationValue);
+ cfacm = dev->config + i;
+ dbg("probing config %d", cfacm->bConfigurationValue);
- ifcom = acm->cfg->interface[0].altsetting + 0;
+ ifcom = cfacm->interface[0].altsetting + 0;
if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
continue;
@@ -436,12 +480,12 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3)
continue;
- ifdata = acm->cfg->interface[1].altsetting + 0;
+ ifdata = cfacm->interface[1].altsetting + 0;
if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
continue;
- if (usb_interface_claimed(acm->cfg->interface + 0) ||
- usb_interface_claimed(acm->cfg->interface + 1))
+ if (usb_interface_claimed(cfacm->interface + 0) ||
+ usb_interface_claimed(cfacm->interface + 1))
continue;
epread = ifdata->endpoint + 0;
@@ -456,13 +500,32 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
epwrite = ifdata->endpoint + 0;
}
- usb_set_configuration(dev, acm->cfg->bConfigurationValue);
+ usb_set_configuration(dev, cfacm->bConfigurationValue);
+
+ for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+ if (acm_table[minor]) {
+ err("no more free acm devices");
+ return NULL;
+ }
+
+ if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+ err("out of memory");
+ return NULL;
+ }
+ memset(acm, 0, sizeof(struct acm));
ctrlsize = epctrl->wMaxPacketSize;
readsize = epread->wMaxPacketSize;
acm->writesize = epwrite->wMaxPacketSize;
-
- if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) return NULL;
+ acm->iface = cfacm->interface;
+ acm->minor = minor;
+ acm->dev = dev;
+
+ if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+ err("out of memory");
+ kfree(acm);
+ return NULL;
+ }
FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
@@ -471,24 +534,20 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
buf += ctrlsize, readsize, acm_read_bulk, acm);
FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
- buf += readsize , acm->writesize, acm_write_bulk, acm);
-
- acm->ctrlif = ifcom->bInterfaceNumber;
+ buf += readsize, acm->writesize, acm_write_bulk, acm);
printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
acm_set_control(acm, acm->ctrlout);
- acm->linecoding.speed = 115200;
- acm->linecoding.databits = 8;
- acm_set_coding(acm, &acm->linecoding);
+ acm->line.speed = cpu_to_le32(9600);
+ acm->line.databits = 8;
+ acm_set_line(acm, &acm->line);
- usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 0, acm);
- usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 1, acm);
+ usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+ usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
- acm->present = 1;
-
- return acm;
+ return acm_table[minor] = acm;
}
return NULL;
@@ -498,12 +557,12 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
{
struct acm *acm = ptr;
- if (!acm || !acm->present) {
+ if (!acm || !acm->dev) {
dbg("disconnect on nonexisting interface");
return;
}
- acm->present = 0;
+ acm->dev = NULL;
usb_unlink_urb(&acm->ctrlurb);
usb_unlink_urb(&acm->readurb);
@@ -511,13 +570,17 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
kfree(acm->ctrlurb.transfer_buffer);
- usb_driver_release_interface(&acm_driver, acm->cfg->interface + 0);
- usb_driver_release_interface(&acm_driver, acm->cfg->interface + 1);
+ usb_driver_release_interface(&acm_driver, acm->iface + 0);
+ usb_driver_release_interface(&acm_driver, acm->iface + 1);
if (!acm->used) {
acm_table[acm->minor] = NULL;
kfree(acm);
+ return;
}
+
+ if (acm->tty)
+ tty_hangup(acm->tty);
}
/*
@@ -565,7 +628,8 @@ static struct tty_driver acm_tty_driver = {
throttle: acm_tty_throttle,
unthrottle: acm_tty_unthrottle,
chars_in_buffer: acm_tty_chars_in_buffer,
- break_ctl: acm_tty_break_ctl
+ break_ctl: acm_tty_break_ctl,
+ set_termios: acm_tty_set_termios
};
/*
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index b94670c70..a290f7c4d 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999 by David Brownell <david-b@pacbell.net>
+ * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.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
@@ -41,6 +41,7 @@
* 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0);
* added timeouts to bulk_msg calls. Minor updates, docs.
* 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
+ * 08 Jan, 2000 .. multiple camera support
*
* Thanks to: the folk who've provided USB product IDs, sent in
* patches, and shared their sucesses!
@@ -61,11 +62,17 @@
#include "usb.h"
-/* XXX need to get registered minor number, cdev 10/MINOR */
-/* XXX or: cdev USB_MAJOR(180)/USB_CAMERA_MINOR */
-#define USB_CAMERA_MINOR 170
+/* current USB framework handles max of 16 USB devices per driver */
+#define MAX_CAMERAS 8
+
+/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
+#define USB_CAMERA_MINOR_BASE 80
+
+
+// XXX remove packet size limit, now that bulk transfers seem fixed
+
/* Application protocol limit is 0x8002; USB has disliked that limit! */
#define MAX_PACKET_SIZE 0x2000 /* e.g. image downloading */
@@ -80,39 +87,35 @@ static const struct camera {
short idProduct;
/* plus hooks for camera-specific info if needed */
} cameras [] = {
+ /* These have the same application level protocol */
{ 0x040a, 0x0120 }, // Kodak DC-240
{ 0x040a, 0x0130 }, // Kodak DC-280
- /* Kodak has several other USB-enabled devices, which (along with
- * models from other vendors) all use the Flashpoint "Digita
- * OS" and its wire protocol. These use a different application
- * level protocol from the DC-240/280 models. Note that Digita
- * isn't just for cameras -- Epson has a non-USB Digita printer.
- */
-// { 0x040a, 0x0100 }, // Kodak DC-220
+ /* These have a different application level protocol which
+ * is part of the Flashpoint "DigitaOS". That supports some
+ * non-camera devices, and some non-Kodak cameras.
+ */
+ { 0x040a, 0x0100 }, // Kodak DC-220
{ 0x040a, 0x0110 }, // Kodak DC-260
{ 0x040a, 0x0111 }, // Kodak DC-265
{ 0x040a, 0x0112 }, // Kodak DC-290
-
// { 0x03f0, 0xffff }, // HP PhotoSmart C500
- /* Other USB cameras may well work here too, so long as they
- * just stick to half duplex packet exchanges and bulk messages.
- * Some non-camera devices have also been shown to work.
+ /* Other USB devices may well work here too, so long as they
+ * just stick to half duplex bulk packet exchanges.
*/
};
struct camera_state {
- /* these fields valid (dev != 0) iff camera connected */
struct usb_device *dev; /* USB device handle */
char inEP; /* read endpoint */
char outEP; /* write endpoint */
const struct camera *info; /* DC-240, etc */
-
- /* valid iff isOpen */
- int isOpen; /* device opened? */
+ int subminor; /* which minor dev #? */
int isActive; /* I/O taking place? */
+
+ /* this is non-null iff the device is open */
char *buf; /* buffer for I/O */
/* always valid */
@@ -120,11 +123,8 @@ struct camera_state {
};
-/* For now, we only support one camera at a time: there's one
- * application-visible device (e.g. /dev/kodak) and the second
- * (to Nth) camera detected on the bus is ignored.
- */
-static struct camera_state static_camera_state;
+/* Support multiple cameras, possibly of different types. */
+static struct camera_state *minor_data [MAX_CAMERAS];
static ssize_t camera_read (struct file *file,
@@ -133,9 +133,12 @@ static ssize_t camera_read (struct file *file,
struct camera_state *camera;
int retries;
- camera = (struct camera_state *) file->private_data;
if (len > MAX_PACKET_SIZE)
return -EINVAL;
+
+ camera = (struct camera_state *) file->private_data;
+ if (!camera->dev)
+ return -ENODEV;
if (camera->isActive++)
return -EBUSY;
@@ -161,7 +164,7 @@ static ssize_t camera_read (struct file *file,
usb_rcvbulkpipe (camera->dev, camera->inEP),
camera->buf, len, &count, HZ*10);
- dbg("read (%d) - 0x%x %ld", len, result, count);
+ dbg ("read (%d) - 0x%x %ld", len, result, count);
if (!result) {
if (copy_to_user (buf, camera->buf, count))
@@ -173,7 +176,7 @@ static ssize_t camera_read (struct file *file,
break;
interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
- dbg("read (%d) - retry", len);
+ dbg ("read (%d) - retry", len);
}
camera->isActive = 0;
return -EIO;
@@ -185,9 +188,12 @@ static ssize_t camera_write (struct file *file,
struct camera_state *camera;
ssize_t bytes_written = 0;
- camera = (struct camera_state *) file->private_data;
if (len > MAX_PACKET_SIZE)
return -EINVAL;
+
+ camera = (struct camera_state *) file->private_data;
+ if (!camera->dev)
+ return -ENODEV;
if (camera->isActive++)
return -EBUSY;
@@ -228,7 +234,7 @@ static ssize_t camera_write (struct file *file,
obuf, thistime, &count, HZ*10);
if (result)
- dbg("write USB err - %x", result);
+ dbg ("write USB err - %x", result);
if (count) {
obuf += count;
@@ -258,26 +264,26 @@ static ssize_t camera_write (struct file *file,
}
done:
camera->isActive = 0;
-
- dbg("write %d", bytes_written);
-
+ dbg ("wrote %d", bytes_written);
return bytes_written;
}
static int camera_open (struct inode *inode, struct file *file)
{
- struct camera_state *camera = &static_camera_state;
+ struct camera_state *camera;
+ int subminor;
- /* ignore camera->dev so it can be turned on "late" */
+ subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
+ if (subminor < 0 || subminor >= MAX_CAMERAS
+ || !(camera = minor_data [subminor])) {
+ return -ENODEV;
+ }
- if (camera->isOpen++)
- return -EBUSY;
if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
- camera->isOpen = 0;
return -ENOMEM;
}
- dbg("open");
+ dbg ("open");
/* Keep driver from being unloaded while it's in use */
MOD_INC_USE_COUNT;
@@ -293,10 +299,16 @@ static int camera_release (struct inode *inode, struct file *file)
camera = (struct camera_state *) file->private_data;
kfree (camera->buf);
- camera->isOpen = 0;
+
+ /* If camera was unplugged with open file ... */
+ if (!camera->dev) {
+ minor_data [camera->subminor] = NULL;
+ kfree (camera);
+ }
+
MOD_DEC_USE_COUNT;
- dbg("close");
+ dbg ("close");
return 0;
}
@@ -306,26 +318,11 @@ static int camera_release (struct inode *inode, struct file *file)
* apps should be able to see the camera type.
*/
static /* const */ struct file_operations usb_camera_fops = {
- NULL, /* llseek */
- camera_read,
- camera_write,
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- camera_open,
- NULL, /* flush */
- camera_release,
- NULL, /* async */
- NULL, /* fasync */
- NULL, /* lock */
-};
-
-static struct miscdevice usb_camera = {
- USB_CAMERA_MINOR,
- "USB camera (Kodak DC-2xx)",
- &usb_camera_fops
- // next, prev
+ /* Uses GCC initializer extension; simpler to maintain */
+ read: camera_read,
+ write: camera_write,
+ open: camera_open,
+ release: camera_release,
};
@@ -337,8 +334,7 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
int direction, ep;
-
- struct camera_state *camera = &static_camera_state;
+ struct camera_state *camera;
/* Is it a supported camera? */
for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) {
@@ -355,7 +351,7 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
/* these have one config, one interface */
if (dev->descriptor.bNumConfigurations != 1
|| dev->config[0].bNumInterfaces != 1) {
- dbg("Bogus camera config info");
+ dbg ("Bogus camera config info");
return NULL;
}
@@ -367,18 +363,34 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
|| interface->bInterfaceProtocol != 0
|| interface->bNumEndpoints != 2
) {
- dbg("Bogus camera interface info");
+ dbg ("Bogus camera interface info");
return NULL;
}
- /* can only show one camera at a time through /dev ... */
- if (!camera->dev) {
- camera->dev = dev;
- info("USB Camera is connected");
- } else {
- info("Ignoring additional USB Camera");
+
+ /* select "subminor" number (part of a minor number) */
+ for (i = 0; i < MAX_CAMERAS; i++) {
+ if (!minor_data [i])
+ break;
+ }
+ if (i >= MAX_CAMERAS) {
+ info ("Ignoring additional USB Camera");
+ return NULL;
+ }
+
+ /* allocate & init camera state */
+ camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
+ if (!camera) {
+ err ("no memory!");
return NULL;
}
+ camera->dev = dev;
+ camera->subminor = i;
+ camera->isActive = 0;
+ camera->buf = NULL;
+ init_waitqueue_head (&camera->wait);
+ info ("USB Camera #%d connected", camera->subminor);
+
/* get input and output endpoints (either order) */
endpoint = interface->endpoint;
@@ -402,14 +414,14 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
|| endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK
|| endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
) {
- dbg("Bogus camera endpoints");
+ dbg ("Bogus endpoints");
camera->dev = NULL;
return NULL;
}
if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {
- err("Failed usb_set_configuration");
+ err ("Failed usb_set_configuration");
camera->dev = NULL;
return NULL;
}
@@ -421,21 +433,18 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
static void camera_disconnect(struct usb_device *dev, void *ptr)
{
struct camera_state *camera = (struct camera_state *) ptr;
+ int subminor = camera->subminor;
- if (camera->dev != dev)
- return;
-
- /* Currently not reflecting this up to userland; at one point
- * it got called on bus reconfig, which we clearly don't want.
- * A good consequence is the ability to remove camera for
- * a while without apps needing to do much more than ignore
- * some particular error returns. On the bad side, if one
- * camera is swapped for another one, we won't be telling.
+ /* If camera's not opened, we can clean up right away.
+ * Else apps see a disconnect on next I/O; the release cleans.
*/
- camera->info = NULL;
- camera->dev = NULL;
+ if (!camera->buf) {
+ minor_data [subminor] = NULL;
+ kfree (camera);
+ } else
+ camera->dev = NULL;
- info("USB Camera disconnected");
+ info ("USB Camera #%d disconnected", subminor);
}
static /* const */ struct usb_driver camera_driver = {
@@ -443,47 +452,26 @@ static /* const */ struct usb_driver camera_driver = {
camera_probe,
camera_disconnect,
{ NULL, NULL },
-
- NULL, /* &usb_camera_fops, */
- 0 /* USB_CAMERA_MINOR */
+ &usb_camera_fops,
+ USB_CAMERA_MINOR_BASE
};
-#ifdef MODULE
-static __init
-#endif
-int usb_dc2xx_init(void)
+int __init usb_dc2xx_init(void)
{
- struct camera_state *camera = &static_camera_state;
-
- camera->dev = NULL;
- camera->isOpen = 0;
- camera->isActive = 0;
- init_waitqueue_head (&camera->wait);
-
- if (usb_register (&camera_driver) < 0)
- return -1;
- misc_register (&usb_camera);
-
+ if (usb_register (&camera_driver) < 0)
+ return -1;
return 0;
}
-#ifdef MODULE
-static __exit
-#endif
-void usb_dc2xx_cleanup(void)
+void __exit usb_dc2xx_cleanup(void)
{
usb_deregister (&camera_driver);
- misc_deregister (&usb_camera);
}
-#ifdef MODULE
-
MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
module_init (usb_dc2xx_init);
module_exit (usb_dc2xx_cleanup);
-
-#endif /* MODULE */
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
new file mode 100644
index 000000000..1fc6d5001
--- /dev/null
+++ b/drivers/usb/devices.c
@@ -0,0 +1,526 @@
+/*
+ * devices.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * $id$
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *************************************************************
+ *
+ * <mountpoint>/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /proc/bus/usb/devices/device# for each device
+ * as it is attached or detached, but I didn't like this for some
+ * reason -- maybe it's just too deep of a directory structure.
+ * I also don't like looking in multiple places to gather and view
+ * the data. Having only one file for ./devices also prevents race
+ * conditions that could arise if a program was reading device info
+ * for devices that are being removed (unplugged). (That is, the
+ * program may find a directory for devnum_12 then try to open it,
+ * but it was just unplugged, so the directory is now deleted.
+ * But programs would just have to be prepared for situations like
+ * this in any plug-and-play environment.)
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Converted the whole proc stuff to real
+ * read methods. Now not the whole device list needs to fit
+ * into one page, only the device list for one bus.
+ * Added a poll method to /proc/bus/usb/devices, to wake
+ * up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Turned into its own filesystem
+ *
+ * $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+#define MAX_TOPO_LEVEL 6
+
+/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
+#define ALLOW_SERIAL_NUMBER
+
+static char *format_topo =
+/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
+ "T: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
+
+static char *format_string_manufacturer =
+/* S: Manufacturer=xxxx */
+ "S: Manufacturer=%.100s\n";
+
+static char *format_string_product =
+/* S: Product=xxxx */
+ "S: Product=%.100s\n";
+
+#ifdef ALLOW_SERIAL_NUMBER
+static char *format_string_serialnumber =
+/* S: SerialNumber=xxxx */
+ "S: SerialNumber=%.100s\n";
+#endif
+
+static char *format_bandwidth =
+/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
+ "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
+
+static char *format_device1 =
+/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+ "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+
+static char *format_device2 =
+/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
+ "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
+
+static char *format_config =
+/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+ "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+
+static char *format_iface =
+/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
+ "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+
+static char *format_endpt =
+/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
+ "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+
+
+/*
+ * Need access to the driver and USB bus lists.
+ * extern struct list_head usb_driver_list;
+ * extern struct list_head usb_bus_list;
+ * However, these will come from functions that return ptrs to each of them.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+static unsigned int conndiscevcnt = 0;
+
+/* this struct stores the poll state for <mountpoint>/devices pollers */
+struct usb_device_status {
+ unsigned int lastev;
+};
+
+struct class_info {
+ int class;
+ char *class_name;
+};
+
+static const struct class_info clas_info[] =
+{ /* max. 5 chars. per name string */
+ {USB_CLASS_PER_INTERFACE, ">ifc"},
+ {USB_CLASS_AUDIO, "audio"},
+ {USB_CLASS_COMM, "comm."},
+ {USB_CLASS_HID, "HID"},
+ {USB_CLASS_HUB, "hub"},
+ {USB_CLASS_PRINTER, "print"},
+ {USB_CLASS_MASS_STORAGE, "stor."},
+ {USB_CLASS_DATA, "data"},
+ {USB_CLASS_VENDOR_SPEC, "vend."},
+ {-1, "unk."} /* leave as last */
+};
+
+/*****************************************************************/
+
+void usbdevfs_conn_disc_event(void)
+{
+ wake_up(&deviceconndiscwq);
+ conndiscevcnt++;
+}
+
+static const char *class_decode(const int class)
+{
+ int ix;
+
+ for (ix = 0; clas_info[ix].class != -1; ix++)
+ if (clas_info[ix].class == class)
+ break;
+ return (clas_info[ix].class_name);
+}
+
+static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
+{
+ char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+
+ if (start > end)
+ return start;
+ start += sprintf(start, format_endpt, desc->bEndpointAddress,
+ (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
+ desc->bmAttributes, EndpointType[desc->bmAttributes & 3],
+ desc->wMaxPacketSize, desc->bInterval);
+ return start;
+}
+
+static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
+{
+ return usb_dump_endpoint_descriptor(start, end, endpoint);
+}
+
+static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+ struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+
+ if (start > end)
+ return start;
+ start += sprintf(start, format_iface,
+ desc->bInterfaceNumber,
+ desc->bAlternateSetting,
+ desc->bNumEndpoints,
+ desc->bInterfaceClass,
+ class_decode(desc->bInterfaceClass),
+ desc->bInterfaceSubClass,
+ desc->bInterfaceProtocol,
+ iface->driver ? iface->driver->name : "(none)");
+ return start;
+}
+
+static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+ struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+ int i;
+
+ start = usb_dump_interface_descriptor(start, end, iface, setno);
+ for (i = 0; i < desc->bNumEndpoints; i++) {
+ if (start > end)
+ return start;
+ start = usb_dump_endpoint(start, end, desc->endpoint + i);
+ }
+ return start;
+}
+
+/* TBD:
+ * 0. TBDs
+ * 1. marking active config and ifaces (code lists all, but should mark
+ * which ones are active, if any)
+ * 2. add <halted> status to each endpoint line
+ */
+
+static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, format_config,
+ active ? '*' : ' ', /* mark active/actual/current cfg. */
+ desc->bNumInterfaces,
+ desc->bConfigurationValue,
+ desc->bmAttributes,
+ desc->MaxPower * 2);
+ return start;
+}
+
+static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active)
+{
+ int i, j;
+ struct usb_interface *interface;
+
+ if (start > end)
+ return start;
+ if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
+ return start + sprintf(start, "(null Cfg. desc.)\n");
+ start = usb_dump_config_descriptor(start, end, config, active);
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ interface = config->interface + i;
+ if (!interface)
+ break;
+ for (j = 0; j < interface->num_altsetting; j++) {
+ if (start > end)
+ return start;
+ start = usb_dump_interface(start, end, interface, j);
+ }
+ }
+ return start;
+}
+
+/*
+ * Dump the different USB descriptors.
+ */
+static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
+{
+ if (start > end)
+ return start;
+ start += sprintf (start, format_device1,
+ desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
+ desc->bDeviceClass,
+ class_decode (desc->bDeviceClass),
+ desc->bDeviceSubClass,
+ desc->bDeviceProtocol,
+ desc->bMaxPacketSize0,
+ desc->bNumConfigurations);
+ if (start > end)
+ return start;
+ start += sprintf(start, format_device2,
+ desc->idVendor, desc->idProduct,
+ desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
+ return start;
+}
+
+/*
+ * Dump the different strings that this device holds.
+ */
+static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+{
+ char *buf;
+
+ if (start > end)
+ return start;
+ buf = kmalloc(128, GFP_KERNEL);
+ if (!buf)
+ return start;
+ if (dev->descriptor.iManufacturer) {
+ if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0)
+ start += sprintf(start, format_string_manufacturer, buf);
+ }
+ if (start > end)
+ goto out;
+ if (dev->descriptor.iProduct) {
+ if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0)
+ start += sprintf(start, format_string_product, buf);
+ }
+ if (start > end)
+ goto out;
+#ifdef ALLOW_SERIAL_NUMBER
+ if (dev->descriptor.iSerialNumber) {
+ if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0)
+ start += sprintf(start, format_string_serialnumber, buf);
+ }
+#endif
+ out:
+ kfree(buf);
+ return start;
+}
+
+static char *usb_dump_desc(char *start, char *end, const struct usb_device *dev)
+{
+ int i;
+
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_strings (start, end, dev);
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ if (start > end)
+ return start;
+ start = usb_dump_config(start, end, dev->config + i,
+ (dev->config + i) == dev->actconfig); /* active ? */
+ }
+ return start;
+}
+
+
+#ifdef PROC_EXTRA /* TBD: may want to add this code later */
+
+static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
+{
+ int leng = USB_DT_HUB_NONVAR_SIZE;
+ unsigned char *ptr = (unsigned char *)desc;
+
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
+ while (leng && start <= end) {
+ start += sprintf(start, " %02x", *ptr);
+ ptr++; leng--;
+ }
+ *start++ = '\n';
+ return start;
+}
+
+static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
+ if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+ start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
+ return start;
+}
+
+#endif /* PROC_EXTRA */
+
+/*****************************************************************/
+
+static char *usb_device_dump(char *start, char *end, const struct usb_device *usbdev,
+ int bus, int level, int index, int count)
+{
+ int chix;
+ int cnt = 0;
+ int parent_devnum = 0;
+
+ if (level > MAX_TOPO_LEVEL)
+ return start;
+ if (usbdev->parent && usbdev->parent->devnum != -1)
+ parent_devnum = usbdev->parent->devnum;
+ /*
+ * So the root hub's parent is 0 and any device that is
+ * plugged into the root hub has a parent of 0.
+ */
+ start += sprintf(start, format_topo, bus, level, parent_devnum, index, count,
+ usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
+ /*
+ * level = topology-tier level;
+ * parent_devnum = parent device number;
+ * index = parent's connector number;
+ * count = device count at this level
+ */
+ /* do not dump descriptors for root hub */
+ if (usbdev->devnum >= 0)
+ start = usb_dump_desc(start, end, usbdev);
+ if (start > end)
+ return start + sprintf(start, "(truncated)\n");
+ /* Now look at all of this device's children. */
+ for (chix = 0; chix < usbdev->maxchild; chix++) {
+ if (start > end)
+ return start;
+ if (usbdev->children[chix])
+ start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
+ }
+ return start;
+}
+
+static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+ struct list_head *buslist;
+ struct usb_bus *bus;
+ char *page, *end;
+ ssize_t ret = 0;
+ unsigned int pos, len;
+
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+ if (!(page = (char*) __get_free_pages(GFP_KERNEL,1)))
+ return -ENOMEM;
+ pos = *ppos;
+ /* enumerate busses */
+ for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
+ /* print bandwidth allocation */
+ bus = list_entry(buslist, struct usb_bus, bus_list);
+ len = sprintf(page, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
+ (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
+ bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+ end = usb_device_dump(page + len, page + (2*PAGE_SIZE - 256), bus->root_hub, bus->busnum, 0, 0, 0);
+ len = end - page;
+ if (len > pos) {
+ len -= pos;
+ if (len > nbytes)
+ len = nbytes;
+ if (copy_to_user(buf, page + pos, len)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ nbytes -= len;
+ buf += len;
+ ret += len;
+ pos = 0;
+ *ppos += len;
+ } else
+ pos -= len;
+ }
+ free_pages((unsigned long)page, 1);
+ return ret;
+}
+
+static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+ unsigned int mask = 0;
+
+ if (!st) {
+ st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
+ if (!st)
+ return POLLIN;
+ /*
+ * need to prevent the module from being unloaded, since
+ * proc_unregister does not call the release method and
+ * we would have a memory leak
+ */
+ st->lastev = conndiscevcnt;
+ file->private_data = st;
+ mask = POLLIN;
+ }
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &deviceconndiscwq, wait);
+ if (st->lastev != conndiscevcnt)
+ mask |= POLLIN;
+ st->lastev = conndiscevcnt;
+ return mask;
+}
+
+static int usb_device_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+static int usb_device_release(struct inode *inode, struct file *file)
+{
+ if (file->private_data) {
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+
+ return 0;
+}
+
+static long long usb_device_lseek(struct file * file, long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+
+ case 2:
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+struct file_operations usbdevfs_devices_fops = {
+ usb_device_lseek, /* lseek */
+ usb_device_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ usb_device_poll, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ usb_device_open, /* open */
+ NULL, /* flush */
+ usb_device_release, /* release */
+ NULL /* fsync */
+};
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
new file mode 100644
index 000000000..5fb51d93c
--- /dev/null
+++ b/drivers/usb/devio.c
@@ -0,0 +1,1021 @@
+/*****************************************************************************/
+
+/*
+ * devio.c -- User space communication with USB devices.
+ *
+ * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ * $Id: devio.c,v 1.6 2000/01/11 23:26:33 tom Exp $
+ *
+ * This file implements the usbdevfs/x/y files, where
+ * x is the bus number and y the device number.
+ *
+ * It allows user space programs/"drivers" to communicate directly
+ * with USB devices without intervening kernel driver.
+ *
+ * Revision history
+ * 22.12.1999 0.1 Initial release (split from proc_usb.c)
+ * 04.01.2000 0.2 Turned into its own filesystem
+ */
+
+/*****************************************************************************/
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+struct async {
+ struct list_head asynclist;
+ struct dev_state *ps;
+ struct task_struct *task;
+ unsigned int signr;
+ void *userbuffer;
+ void *userurb;
+ urb_t urb;
+};
+
+/*
+ * my own sync control and bulk methods. Here to experiment
+ * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE.
+ */
+
+struct sync {
+ wait_queue_head_t wait;
+};
+
+static void sync_completed(purb_t urb)
+{
+ struct sync *s = (struct sync *)urb->context;
+
+ wake_up(&s->wait);
+}
+
+static int do_sync(purb_t urb, int timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long tm;
+ signed long tmdiff;
+ struct sync s;
+ int ret;
+
+ tm = jiffies+timeout;
+ init_waitqueue_head(&s.wait);
+ add_wait_queue(&s.wait, &wait);
+ urb->context = &s;
+ urb->complete = sync_completed;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((ret = usb_submit_urb(urb)))
+ goto out;
+ while (urb->status == -EINPROGRESS) {
+ tmdiff = tm - jiffies;
+ if (tmdiff <= 0) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto out;
+ }
+ schedule_timeout(tmdiff);
+ }
+ ret = urb->status;
+ out:
+ set_current_state(TASK_RUNNING);
+ usb_unlink_urb(urb);
+ remove_wait_queue(&s.wait, &wait);
+ return ret;
+}
+
+static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+ __u16 value, __u16 index, void *data, __u16 size, int timeout)
+{
+ urb_t *urb;
+ int ret;
+
+ if (!(urb = usb_alloc_urb(0)))
+ return -ENOMEM;
+ if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ urb->setup_packet[0] = requesttype;
+ urb->setup_packet[1] = request;
+ urb->setup_packet[2] = value;
+ urb->setup_packet[3] = value >> 8;
+ urb->setup_packet[4] = index;
+ urb->setup_packet[5] = index >> 8;
+ urb->setup_packet[6] = size;
+ urb->setup_packet[7] = size >> 8;
+ urb->dev = dev;
+ urb->pipe = pipe;
+ urb->transfer_buffer = data;
+ urb->transfer_buffer_length = size;
+ ret = do_sync(urb, timeout);
+ if (ret >= 0)
+ ret = urb->status;
+ if (ret >= 0)
+ ret = urb->actual_length;
+ kfree(urb->setup_packet);
+ usb_free_urb(urb);
+ return ret;
+}
+
+static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ urb_t *urb;
+ int ret;
+
+ if (!(urb = usb_alloc_urb(0)))
+ return -ENOMEM;
+ urb->dev = dev;
+ urb->pipe = pipe;
+ urb->transfer_buffer = data;
+ urb->transfer_buffer_length = len;
+ ret = do_sync(urb, timeout);
+ if (ret >= 0)
+ ret = urb->status;
+ if (ret >= 0 && actual_length != NULL)
+ *actual_length = urb->actual_length;
+ usb_free_urb(urb);
+ return ret;
+}
+
+static long long usbdev_lseek(struct file *file, long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+
+ case 2:
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos)
+{
+ struct dev_state *ps = (struct dev_state *)file->private_data;
+ ssize_t ret = 0;
+ unsigned len;
+ loff_t pos;
+
+ pos = *ppos;
+ down_read(&ps->devsem);
+ if (!ps->dev)
+ ret = -ENODEV;
+ else if (pos < 0)
+ ret = -EINVAL;
+ else if (pos < sizeof(struct usb_device_descriptor)) {
+ len = sizeof(struct usb_device_descriptor) - pos;
+ if (len > nbytes)
+ len = nbytes;
+ if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len))
+ ret = -EFAULT;
+ else {
+ *ppos += len;
+ buf += len;
+ nbytes -= len;
+ ret += len;
+ }
+ }
+ up_read(&ps->devsem);
+ return ret;
+}
+
+extern inline unsigned int ld2(unsigned int x)
+{
+ unsigned int 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;
+}
+
+/*
+ * async list handling
+ */
+
+static struct async *alloc_async(unsigned int numisoframes)
+{
+ unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+ struct async *as = kmalloc(assize, GFP_KERNEL);
+ if (!as)
+ return NULL;
+ memset(as, 0, assize);
+ as->urb.number_of_packets = numisoframes;
+ return as;
+}
+
+static void free_async(struct async *as)
+{
+ if (as->urb.transfer_buffer)
+ kfree(as->urb.transfer_buffer);
+ kfree(as);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+ struct dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_add_tail(&as->asynclist, &ps->async_pending);
+ spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ void async_removepending(struct async *as)
+{
+ struct dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+{
+ unsigned long flags;
+ struct async *as = NULL;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ if (!list_empty(&ps->async_completed)) {
+ as = list_entry(ps->async_completed.next, struct async, asynclist);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return as;
+}
+
+extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb)
+{
+ unsigned long flags;
+ struct async *as;
+ struct list_head *p;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ for (p = ps->async_pending.next; p != &ps->async_pending; ) {
+ as = list_entry(p, struct async, asynclist);
+ p = p->next;
+ if (as->userurb != userurb)
+ continue;
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return as;
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return NULL;
+}
+
+static void async_completed(purb_t urb)
+{
+ struct async *as = (struct async *)urb->context;
+ struct dev_state *ps = as->ps;
+ struct siginfo sinfo;
+
+#if 0
+ printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n",
+ urb->status, urb->error_count, urb->actual_length, urb->pipe);
+#endif
+ spin_lock(&ps->lock);
+ list_del(&as->asynclist);
+ list_add_tail(&as->asynclist, &ps->async_completed);
+ spin_unlock(&ps->lock);
+ wake_up(&ps->wait);
+ if (as->signr) {
+ sinfo.si_signo = as->signr;
+ sinfo.si_errno = as->urb.status;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = as->userurb;
+ send_sig_info(as->signr, &sinfo, as->task);
+ }
+}
+
+static void destroy_all_async(struct dev_state *ps)
+{
+ struct async *as;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ if (!list_empty(&ps->async_pending)) {
+ as = list_entry(ps->async_pending.next, struct async, asynclist);
+ list_del(&as->asynclist);
+ INIT_LIST_HEAD(&as->asynclist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+ /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+ usb_unlink_urb(&as->urb);
+ spin_lock_irqsave(&ps->lock, flags);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ while ((as = async_getcompleted(ps)))
+ free_async(as);
+}
+
+/*
+ * interface claiming
+ */
+
+static void *driver_probe(struct usb_device *dev, unsigned int intf)
+{
+ return NULL;
+}
+
+static void driver_disconnect(struct usb_device *dev, void *context)
+{
+ struct dev_state *ps = (struct dev_state *)context;
+
+ ps->ifclaimed = 0;
+}
+
+struct usb_driver usbdevfs_driver = {
+ "usbdevfs",
+ driver_probe,
+ driver_disconnect,
+ LIST_HEAD_INIT(usbdevfs_driver.driver_list),
+ NULL,
+ 0
+};
+
+static int claimintf(struct dev_state *ps, unsigned int intf)
+{
+ struct usb_device *dev = ps->dev;
+ struct usb_interface *iface;
+ int err;
+
+ if (intf >= 8*sizeof(ps->ifclaimed) || !dev || intf >= dev->actconfig->bNumInterfaces)
+ return -EINVAL;
+ /* already claimed */
+ if (test_bit(intf, &ps->ifclaimed))
+ return 0;
+ iface = &dev->actconfig->interface[intf];
+ err = -EBUSY;
+ lock_kernel();
+ if (!usb_interface_claimed(iface)) {
+ usb_driver_claim_interface(&usbdevfs_driver, iface, ps);
+ set_bit(intf, &ps->ifclaimed);
+ err = 0;
+ }
+ unlock_kernel();
+ return err;
+}
+
+static int releaseintf(struct dev_state *ps, unsigned int intf)
+{
+ struct usb_device *dev;
+ struct usb_interface *iface;
+ int err;
+
+ if (intf >= 8*sizeof(ps->ifclaimed))
+ return -EINVAL;
+ err = -EINVAL;
+ lock_kernel();
+ dev = ps->dev;
+ if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {
+ iface = &dev->actconfig->interface[intf];
+ usb_driver_release_interface(&usbdevfs_driver, iface);
+ err = 0;
+ }
+ unlock_kernel();
+ return err;
+}
+
+static int checkintf(struct dev_state *ps, unsigned int intf)
+{
+ if (intf >= 8*sizeof(ps->ifclaimed))
+ return -EINVAL;
+ if (test_bit(intf, &ps->ifclaimed))
+ return 0;
+ /* if not yet claimed, claim it for the driver */
+ printk(KERN_WARNING "usbdevfs: process %d (%s) did not claim interface %u before use\n",
+ current->pid, current->comm, intf);
+ return claimintf(ps, intf);
+}
+
+static int findintfep(struct usb_device *dev, unsigned int ep)
+{
+ unsigned int i, j, e;
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *alts;
+ struct usb_endpoint_descriptor *endpt;
+
+ if (ep & ~(USB_DIR_IN|0xf))
+ return -EINVAL;
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ iface = &dev->actconfig->interface[i];
+ for (j = 0; j < iface->num_altsetting; j++) {
+ alts = &iface->altsetting[j];
+ for (e = 0; e < alts->bNumEndpoints; e++) {
+ endpt = &alts->endpoint[e];
+ if (endpt->bEndpointAddress == ep)
+ return i;
+ }
+ }
+ }
+ return -ENOENT;
+}
+
+static int findintfif(struct usb_device *dev, unsigned int ifn)
+{
+ unsigned int i, j;
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *alts;
+
+ if (ifn & ~0xff)
+ return -EINVAL;
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ iface = &dev->actconfig->interface[i];
+ for (j = 0; j < iface->num_altsetting; j++) {
+ alts = &iface->altsetting[j];
+ if (alts->bInterfaceNumber == ifn)
+ return i;
+ }
+ }
+ return -ENOENT;
+}
+
+/*
+ * file operations
+ */
+static int usbdev_open(struct inode *inode, struct file *file)
+{
+ struct usb_device *dev;
+ struct dev_state *ps;
+ int ret;
+
+ /*
+ * no locking necessary here, as both sys_open (actually filp_open)
+ * and the hub thread have the kernel lock
+ * (still acquire the kernel lock for safety)
+ */
+ lock_kernel();
+ ret = -ENOENT;
+ if (ITYPE(inode->i_ino) != IDEVICE)
+ goto out;
+ dev = inode->u.usbdev_i.p.dev;
+ if (!dev)
+ goto out;
+ ret = -ENOMEM;
+ if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+ goto out;
+ ret = 0;
+ ps->dev = dev;
+ ps->file = file;
+ spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->async_pending);
+ INIT_LIST_HEAD(&ps->async_completed);
+ init_waitqueue_head(&ps->wait);
+ init_rwsem(&ps->devsem);
+ ps->discsignr = 0;
+ ps->disctask = current;
+ ps->disccontext = NULL;
+ ps->ifclaimed = 0;
+ wmb();
+ list_add_tail(&ps->list, &dev->filelist);
+ file->private_data = ps;
+ out:
+ unlock_kernel();
+ return ret;
+}
+
+static int usbdev_release(struct inode *inode, struct file *file)
+{
+ struct dev_state *ps = (struct dev_state *)file->private_data;
+ unsigned int i;
+
+ lock_kernel();
+ list_del(&ps->list);
+ INIT_LIST_HEAD(&ps->list);
+ if (ps->dev) {
+ for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
+ if (test_bit(i, &ps->ifclaimed))
+ releaseintf(ps, i);
+ }
+ unlock_kernel();
+ destroy_all_async(ps);
+ kfree(ps);
+ return 0;
+}
+
+static int proc_control(struct dev_state *ps, void *arg)
+{
+ struct usb_device *dev = ps->dev;
+ struct usbdevfs_ctrltransfer ctrl;
+ unsigned int tmo;
+ unsigned char *tbuf;
+ int i, ret;
+
+ copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
+ switch (ctrl.requesttype & 0x1f) {
+ case USB_RECIP_ENDPOINT:
+ if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ break;
+ }
+ if (ctrl.length > PAGE_SIZE)
+ return -EINVAL;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ tmo = (ctrl.timeout * HZ + 999) / 1000;
+ if (ctrl.requesttype & 0x80) {
+ if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+ if ((i > 0) && ctrl.length) {
+ copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
+ }
+ } else {
+ if (ctrl.length) {
+ copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
+ }
+ i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+ }
+ free_page((unsigned long)tbuf);
+ if (i<0) {
+ printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n",
+ dev->devnum, ctrl.requesttype, ctrl.request, ctrl.length, i);
+ }
+ return i;
+}
+
+static int proc_bulk(struct dev_state *ps, void *arg)
+{
+ struct usb_device *dev = ps->dev;
+ struct usbdevfs_bulktransfer bulk;
+ unsigned int tmo, len1, pipe;
+ int len2;
+ unsigned char *tbuf;
+ int i, ret;
+
+ copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
+ if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ if (bulk.ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
+ if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
+ return -EINVAL;
+ len1 = bulk.len;
+ if (len1 > PAGE_SIZE)
+ len1 = PAGE_SIZE;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ tmo = (bulk.timeout * HZ + 999) / 1000;
+ if (bulk.ep & 0x80) {
+ if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ if (!i && len2) {
+ copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
+ }
+ } else {
+ if (len1) {
+ copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
+ }
+ i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ }
+ free_page((unsigned long)tbuf);
+ if (i < 0) {
+ printk(KERN_WARNING "usbdevfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n",
+ dev->devnum, bulk.ep, bulk.len, i);
+ return i;
+ }
+ return len2;
+}
+
+static int proc_resetep(struct dev_state *ps, void *arg)
+{
+ unsigned int ep;
+ int ret;
+
+ get_user_ret(ep, (unsigned int *)arg, -EFAULT);
+ if ((ret = findintfep(ps->dev, ep)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
+ return 0;
+}
+
+static int proc_setintf(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_setinterface setintf;
+ int ret;
+
+ copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT);
+ if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
+ return -EINVAL;
+ return 0;
+}
+
+static int proc_setconfig(struct dev_state *ps, void *arg)
+{
+ unsigned int u;
+
+ get_user_ret(u, (unsigned int *)arg, -EFAULT);
+ if (usb_set_configuration(ps->dev, u) < 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int proc_submiturb(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_urb uurb;
+ struct usbdevfs_iso_packet_desc *isopkt = NULL;
+ struct async *as;
+ unsigned int u, totlen, isofrmlen;
+ int ret;
+
+ copy_from_user_ret(&uurb, arg, sizeof(uurb), -EFAULT);
+ if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
+ return -EINVAL;
+ if (!uurb.buffer)
+ return -EINVAL;
+ if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
+ return -EINVAL;
+ if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ switch(uurb.type) {
+ case USBDEVFS_URB_TYPE_BULK:
+ uurb.number_of_packets = 0;
+ if (uurb.buffer_length > 16384)
+ return -EINVAL;
+ if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+ return -EFAULT;
+ break;
+
+ case USBDEVFS_URB_TYPE_ISO:
+ /* arbitrary limit */
+ if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
+ return -EINVAL;
+ isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
+ if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) {
+ kfree(isopkt);
+ return -EFAULT;
+ }
+ for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+ if (isopkt[u].length > 1023) {
+ kfree(isopkt);
+ return -EINVAL;
+ }
+ totlen += isopkt[u].length;
+ }
+ if (totlen > 32768) {
+ kfree(isopkt);
+ return -ENOMEM;
+ }
+ uurb.buffer_length = totlen;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if (!(as = alloc_async(uurb.number_of_packets))) {
+ if (isopkt)
+ kfree(isopkt);
+ return -ENOMEM;
+ }
+ if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+ if (isopkt)
+ kfree(isopkt);
+ free_async(as);
+ return -ENOMEM;
+ }
+ as->urb.next = NULL;
+ as->urb.dev = ps->dev;
+ as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+ as->urb.transfer_flags = uurb.flags;
+ as->urb.transfer_buffer_length = uurb.buffer_length;
+ as->urb.start_frame = uurb.start_frame;
+ as->urb.number_of_packets = uurb.number_of_packets;
+ as->urb.context = as;
+ as->urb.complete = async_completed;
+ for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+ as->urb.iso_frame_desc[u].offset = totlen;
+ as->urb.iso_frame_desc[u].length = isopkt[u].length;
+ totlen += isopkt[u].length;
+ }
+ if (isopkt)
+ kfree(isopkt);
+ as->ps = ps;
+ as->userurb = arg;
+ if (uurb.endpoint & USB_DIR_IN)
+ as->userbuffer = uurb.buffer;
+ else
+ as->userbuffer = NULL;
+ as->signr = uurb.signr;
+ as->task = current;
+ if (!(uurb.endpoint & USB_DIR_IN)) {
+ if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+ free_async(as);
+ return -EFAULT;
+ }
+ }
+ async_newpending(as);
+ if ((ret = usb_submit_urb(&as->urb))) {
+ printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
+ async_removepending(as);
+ free_async(as);
+ return ret;
+ }
+ return 0;
+}
+
+static int proc_unlinkurb(struct dev_state *ps, void *arg)
+{
+ struct async *as;
+
+ as = async_getpending(ps, arg);
+ if (!as)
+ return -EINVAL;
+ usb_unlink_urb(&as->urb);
+ return 0;
+}
+
+static int processcompl(struct async *as)
+{
+ unsigned int i;
+
+ if (as->userbuffer)
+ if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+ return -EFAULT;
+ put_user_ret(as->urb.status, &((struct usbdevfs_urb *)as->userurb)->status, -EFAULT);
+ put_user_ret(as->urb.actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length, -EFAULT);
+ put_user_ret(as->urb.error_count, &((struct usbdevfs_urb *)as->userurb)->error_count, -EFAULT);
+ if (!(usb_pipeisoc(as->urb.pipe)))
+ return 0;
+ for (i = 0; i < as->urb.number_of_packets; i++) {
+ put_user_ret(as->urb.iso_frame_desc[i].actual_length,
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length,
+ -EFAULT);
+ put_user_ret(as->urb.iso_frame_desc[i].status,
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status,
+ -EFAULT);
+ }
+ return 0;
+}
+
+static int proc_reapurb(struct dev_state *ps, void *arg)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct async *as = NULL;
+ void *addr;
+ int ret;
+
+ add_wait_queue(&ps->wait, &wait);
+ while (ps->dev) {
+ __set_current_state(TASK_INTERRUPTIBLE);
+ if ((as = async_getcompleted(ps)))
+ break;
+ if (signal_pending(current))
+ break;
+ up_read(&ps->devsem);
+ schedule();
+ down_read(&ps->devsem);
+ }
+ remove_wait_queue(&ps->wait, &wait);
+ set_current_state(TASK_RUNNING);
+ if (as) {
+ ret = processcompl(as);
+ addr = as->userurb;
+ free_async(as);
+ if (ret)
+ return ret;
+ put_user_ret(addr, (void **)arg, -EFAULT);
+ return 0;
+ }
+ if (signal_pending(current))
+ return -EINTR;
+ return -EIO;
+}
+
+static int proc_reapurbnonblock(struct dev_state *ps, void *arg)
+{
+ struct async *as;
+ void *addr;
+ int ret;
+
+ if (!(as = async_getcompleted(ps)))
+ return -EAGAIN;
+ ret = processcompl(as);
+ addr = as->userurb;
+ free_async(as);
+ if (ret)
+ return ret;
+ put_user_ret(addr, (void **)arg, -EFAULT);
+ return 0;
+}
+
+static int proc_disconnectsignal(struct dev_state *ps, void *arg)
+{
+ struct usbdevfs_disconnectsignal ds;
+
+ copy_from_user_ret(&ds, arg, sizeof(ds), -EFAULT);
+ if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
+ return -EINVAL;
+ ps->discsignr = ds.signr;
+ ps->disccontext = ds.context;
+ return 0;
+}
+
+static int proc_claiminterface(struct dev_state *ps, void *arg)
+{
+ unsigned int intf;
+ int ret;
+
+ get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+ if ((ret = findintfif(ps->dev, intf)) < 0)
+ return ret;
+ return claimintf(ps, ret);
+}
+
+static int proc_releaseinterface(struct dev_state *ps, void *arg)
+{
+ unsigned int intf;
+ int ret;
+
+ get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+ if ((ret = findintfif(ps->dev, intf)) < 0)
+ return ret;
+ return releaseintf(ps, intf);
+}
+
+static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct dev_state *ps = (struct dev_state *)file->private_data;
+ int ret = -ENOIOCTLCMD;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EPERM;
+ down_read(&ps->devsem);
+ if (!ps->dev) {
+ up_read(&ps->devsem);
+ return -ENODEV;
+ }
+ switch (cmd) {
+ case USBDEVFS_CONTROL:
+ ret = proc_control(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_BULK:
+ ret = proc_bulk(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_RESETEP:
+ ret = proc_resetep(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_SETINTERFACE:
+ ret = proc_setintf(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_SETCONFIGURATION:
+ ret = proc_setconfig(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_SUBMITURB:
+ ret = proc_submiturb(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_DISCARDURB:
+ ret = proc_unlinkurb(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_REAPURB:
+ ret = proc_reapurb(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_REAPURBNDELAY:
+ ret = proc_reapurbnonblock(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_DISCSIGNAL:
+ ret = proc_disconnectsignal(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_CLAIMINTERFACE:
+ ret = proc_claiminterface(ps, (void *)arg);
+ break;
+
+ case USBDEVFS_RELEASEINTERFACE:
+ ret = proc_releaseinterface(ps, (void *)arg);
+ break;
+
+ }
+ up_read(&ps->devsem);
+ if (ret >= 0)
+ inode->i_atime = CURRENT_TIME;
+ return ret;
+}
+
+static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct dev_state *ps = (struct dev_state *)file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &ps->wait, wait);
+ if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
+ mask |= POLLOUT | POLLWRNORM;
+ if (!ps->dev)
+ mask |= POLLERR | POLLHUP;
+ return mask;
+}
+
+static struct file_operations usbdevfs_device_file_operations = {
+ usbdev_lseek, /* lseek */
+ usbdev_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ usbdev_poll, /* poll */
+ usbdev_ioctl, /* ioctl */
+ NULL, /* mmap */
+ usbdev_open, /* open */
+ NULL, /* flush */
+ usbdev_release, /* release */
+ NULL /* fsync */
+};
+
+struct inode_operations usbdevfs_device_inode_operations = {
+ &usbdevfs_device_file_operations, /* file-ops */
+};
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
new file mode 100644
index 000000000..454130006
--- /dev/null
+++ b/drivers/usb/drivers.c
@@ -0,0 +1,126 @@
+/*
+ * drivers.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999, 2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * $id$
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *************************************************************
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Converted the whole proc stuff to real
+ * read methods. Now not the whole device list needs to fit
+ * into one page, only the device list for one bus.
+ * Added a poll method to /proc/bus/usb/devices, to wake
+ * up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Turned into its own filesystem
+ *
+ * $Id: drivers.c,v 1.3 2000/01/11 13:58:24 tom Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+
+/*****************************************************************/
+
+/*
+ * Dump usb_driver_list.
+ *
+ * We now walk the list of registered USB drivers.
+ */
+static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+ struct list_head *tmp = usb_driver_list.next;
+ char *page, *start, *end;
+ ssize_t ret = 0;
+ unsigned int pos, len;
+
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ start = page;
+ end = page + (PAGE_SIZE - 100);
+ pos = *ppos;
+ for (; tmp != &usb_driver_list; tmp = tmp->next) {
+ struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+ start += sprintf (start, "%s\n", driver->name);
+ if (start > end) {
+ start += sprintf(start, "(truncated)\n");
+ break;
+ }
+ }
+ if (start == page)
+ start += sprintf(start, "(none)\n");
+ len = start - page;
+ if (len > pos) {
+ len -= pos;
+ if (len > nbytes)
+ len = nbytes;
+ ret = len;
+ if (copy_to_user(buf, page + pos, len))
+ ret = -EFAULT;
+ else
+ *ppos += len;
+ }
+ free_page((unsigned long)page);
+ return ret;
+}
+
+static long long usb_driver_lseek(struct file * file, long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+
+ case 2:
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+struct file_operations usbdevfs_drivers_fops = {
+ usb_driver_lseek, /* lseek */
+ usb_driver_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+ NULL /* fsync */
+};
diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c
deleted file mode 100644
index eb6b23927..000000000
--- a/drivers/usb/ezusb.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*****************************************************************************/
-
-/*
- * ezusb.c -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
- *
- * Copyright (C) 1999
- * Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * 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.
- *
- * History:
- * 0.1 26.05.99 Created
- * 0.2 23.07.99 Removed EZUSB_INTERRUPT. Interrupt pipes may be polled with
- * 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 Set callback_frames to the total number of frames to make
- * it work with OHCI-HCD
- * 03.12.99 Now that USB error codes are negative, return them to application
- * instead of ENXIO
- * $Id: ezusb.c,v 1.22 1999/12/03 15:06:28 tom Exp $
- */
-
-/*****************************************************************************/
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/miscdevice.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
-//#include <linux/spinlock.h>
-
-#include "usb.h"
-#include "ezusb.h"
-
-/* --------------------------------------------------------------------- */
-
-#define NREZUSB 1
-
-static struct ezusb {
- struct semaphore mutex;
- struct usb_device *usbdev;
- struct list_head async_pending;
- struct list_head async_completed;
- wait_queue_head_t wait;
- spinlock_t lock;
-} ezusb[NREZUSB];
-
-struct async {
- struct list_head asynclist;
- struct ezusb *ez;
- void *userdata;
- unsigned datalen;
- void *context;
- urb_t urb;
-};
-
-/*-------------------------------------------------------------------*/
-
-static struct async *alloc_async(unsigned int numisoframes)
-{
- unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
- struct async *as = kmalloc(assize, GFP_KERNEL);
- if (!as)
- return NULL;
- memset(as, 0, assize);
- as->urb.number_of_packets = numisoframes;
- return as;
-}
-
-static void free_async(struct async *as)
-{
- if (as->urb.transfer_buffer)
- kfree(as->urb.transfer_buffer);
- kfree(as);
-}
-
-/* --------------------------------------------------------------------- */
-
-extern inline unsigned int ld2(unsigned int x)
-{
- unsigned int 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;
-}
-
-#if 0
-/* why doesn't this work properly on i386? */
-extern inline unsigned int ld2(unsigned int x)
-{
- unsigned int r;
-
- __asm__("bsrl %1,%0" : "=r" (r) : "g" (x));
- return r;
-}
-#endif
-
-/* --------------------------------------------------------------------- */
-
-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_removepending(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__ 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->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 void async_completed(purb_t urb)
-{
- struct async *as = (struct async *)urb->context;
- struct ezusb *ez = as->ez;
- unsigned cnt;
-
-printk(KERN_DEBUG "ezusb: async_completed: status %d errcount %d actlen %d pipe 0x%x\n",
- urb->status, urb->error_count, urb->actual_length, urb->pipe);
- spin_lock(&ez->lock);
- list_del(&as->asynclist);
- list_add_tail(&as->asynclist, &ez->async_completed);
- spin_unlock(&ez->lock);
- wake_up(&ez->wait);
-}
-
-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_pending)) {
- 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);
- /* discard_urb calls the completion handler with status == USB_ST_URB_KILLED */
- usb_unlink_urb(&as->urb);
- spin_lock_irqsave(&ez->lock, flags);
- }
- spin_unlock_irqrestore(&ez->lock, flags);
- while ((as = async_getcompleted(ez)))
- free_async(as);
-}
-
-/* --------------------------------------------------------------------- */
-
-static loff_t ezusb_llseek(struct file *file, loff_t offset, int origin)
-{
- struct ezusb *ez = (struct ezusb *)file->private_data;
-
- switch(origin) {
- case 1:
- offset += file->f_pos;
- break;
- case 2:
- offset += 0x10000;
- break;
- }
- if (offset < 0 || offset >= 0x10000)
- return -EINVAL;
- return (file->f_pos = offset);
-}
-
-static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
-{
- struct ezusb *ez = (struct ezusb *)file->private_data;
- unsigned pos = *ppos;
- unsigned ret = 0;
- unsigned len;
- unsigned char b[64];
- int i;
-
- if (*ppos < 0 || *ppos >= 0x10000)
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- while (sz > 0 && pos < 0x10000) {
- len = sz;
- if (len > sizeof(b))
- len = sizeof(b);
- if (pos + len > 0x10000)
- len = 0x10000 - pos;
- i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ);
- if (i < 0) {
- up(&ez->mutex);
- printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i);
- *ppos = pos;
- if (ret)
- return ret;
- return i;
- }
- if (copy_to_user(buf, b, len)) {
- up(&ez->mutex);
- *ppos = pos;
- if (ret)
- return ret;
- return -EFAULT;
- }
- pos += len;
- buf += len;
- sz -= len;
- ret += len;
- }
- up(&ez->mutex);
- *ppos = pos;
- return ret;
-}
-
-static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t *ppos)
-{
- struct ezusb *ez = (struct ezusb *)file->private_data;
- unsigned pos = *ppos;
- unsigned ret = 0;
- unsigned len;
- unsigned char b[64];
- int i;
-
- if (*ppos < 0 || *ppos >= 0x10000)
- return -EINVAL;
- down(&ez->mutex);
- if (!ez->usbdev) {
- up(&ez->mutex);
- return -EIO;
- }
- while (sz > 0 && pos < 0x10000) {
- len = sz;
- if (len > sizeof(b))
- len = sizeof(b);
- if (pos + len > 0x10000)
- len = 0x10000 - pos;
- if (copy_from_user(b, buf, len)) {
- up(&ez->mutex);
- *ppos = pos;
- if (ret)
- return ret;
- return -EFAULT;
- }
- printk("writemem: %d %p %d\n",pos,b,len);
- i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ);
- if (i < 0) {
- up(&ez->mutex);
- printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i);
- *ppos = pos;
- if (ret)
- return ret;
- return i;
- }
- pos += len;
- buf += len;
- sz -= len;
- ret += len;
- }
- up(&ez->mutex);
- *ppos = pos;
- return ret;
-}
-
-static int ezusb_open(struct inode *inode, struct file *file)
-{
- struct ezusb *ez = &ezusb[0];
-
- down(&ez->mutex);
- while (!ez->usbdev) {
- up(&ez->mutex);
- if (!(file->f_flags & O_NONBLOCK)) {
- return -EIO;
- }
- schedule_timeout(HZ/2);
- if (signal_pending(current))
- return -EAGAIN;
- down(&ez->mutex);
- }
- 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 int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
- unsigned char request, unsigned short value,
- unsigned short index, unsigned short length,
- unsigned int timeout, void *data)
-{
- 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, timeout);
- if (i < 0) {
- 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 i;
- }
- if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length))
- i = -EFAULT;
- if (length > 0)
- free_page((unsigned long)tbuf);
- return i;
-}
-
-static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data)
-{
- 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 = usb_bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout);
- if (ret < 0) {
- 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_resetep(struct usb_device *usbdev, unsigned int ep)
-{
- 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) < 0)
- return -EINVAL;
- return 0;
-}
-
-static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config)
-{
- if (usb_set_configuration(usbdev, config) < 0)
- return -EINVAL;
- return 0;
-}
-
-#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-
-char* stuff[512];
-
-static void int_compl(purb_t purb)
-{
- printk("INT_COMPL\n");
-
-}
-
-static int ezusb_interrupt(struct ezusb *ez, struct ezusb_interrupt *ab)
-{
- urb_t *urb;
- unsigned int pipe;
-
- urb=(urb_t*)kmalloc(sizeof(urb_t),GFP_KERNEL);
- if (!urb)
- {
- return -ENOMEM;
- }
- memset(urb,0,sizeof(urb_t));
-
-
- if ((ab->ep & ~0x80) >= 16)
- return -EINVAL;
- if (ab->ep & 0x80)
- {
- pipe = usb_rcvintpipe(ez->usbdev, ab->ep & 0x7f);
- if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len))
- return -EFAULT;
- }
- else
- pipe = usb_sndintpipe(ez->usbdev, ab->ep & 0x7f);
-
- memcpy(stuff,ab->data,64);
- urb->transfer_buffer=stuff;
- urb->transfer_buffer_length=ab->len;
- urb->complete=int_compl;
- urb->pipe=pipe;
- urb->dev=ez->usbdev;
- urb->interval=ab->interval;
- return usb_submit_urb(urb);
-}
-
-static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
-{
- struct async *as = NULL;
- void *data = NULL;
- unsigned int pipe;
- int ret;
-
- 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 (ab->len > 0 && !(data = kmalloc(ab->len, GFP_KERNEL)))
- return -ENOMEM;
- if (!(as = alloc_async(0))) {
- if (data)
- kfree(data);
- return -ENOMEM;
- }
- INIT_LIST_HEAD(&as->asynclist);
- as->ez = ez;
- as->userdata = ab->data;
- as->datalen = ab->len;
- as->context = ab->context;
- as->urb.dev = ez->usbdev;
- as->urb.pipe = pipe;
- as->urb.transfer_flags = 0;
- as->urb.transfer_buffer = data;
- as->urb.transfer_buffer_length = ab->len;
- as->urb.context = as;
- as->urb.complete = (usb_complete_t)async_completed;
- if (ab->len > 0 && !(ab->ep & 0x80)) {
- if (copy_from_user(data, ab->data, ab->len)) {
- free_async(as);
- return -EFAULT;
- }
- as->userdata = NULL; /* no need to copy back at completion */
- }
- async_newpending(as);
- if ((ret = usb_submit_urb(&as->urb))) {
- printk(KERN_DEBUG "ezusb: bulk: usb_submit_urb returned %d\n", ret);
- async_removepending(as);
- free_async(as);
- return -EINVAL; /* return ret; */
- }
- return 0;
-}
-
-static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd)
-{
- struct async *as;
- void *data = NULL;
- unsigned int maxpkt, pipe, dsize, totsize, i, j;
- int ret;
-
- 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;
-//printk(KERN_DEBUG "ezusb: iso: dsize %d\n", dsize);
- if (dsize > 65536)
- return -EINVAL;
- if (ai->ep & 0x80)
- if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize))
- return -EFAULT;
- if (dsize > 0 && !(data = kmalloc(dsize, GFP_KERNEL)))
- {
- printk("dsize: %d failed\n",dsize);
- return -ENOMEM;
- }
- if (!(as = alloc_async(ai->framecnt))) {
- if (data)
- kfree(data);
- printk("alloc_async failed\n");
- return -ENOMEM;
- }
- INIT_LIST_HEAD(&as->asynclist);
-
- as->ez = ez;
- as->userdata = ai->data;
- as->datalen = dsize;
- as->context = ai->context;
-
- as->urb.dev = ez->usbdev;
- as->urb.pipe = pipe;
- as->urb.transfer_flags = USB_ISO_ASAP;
- as->urb.transfer_buffer = data;
- as->urb.transfer_buffer_length = dsize;
- as->urb.context = as;
- as->urb.complete = (usb_complete_t)async_completed;
-
- for (i = totsize = 0; i < as->urb.number_of_packets; i++) {
- as->urb.iso_frame_desc[i].offset = totsize;
- if (get_user(j, (int *)(cmd + i * sizeof(struct ezusb_isoframestat)))) {
- free_async(as);
- return -EFAULT;
- }
- as->urb.iso_frame_desc[i].length = j;
- totsize += j;
- }
- if (dsize > 0 && totsize > 0 && !(ai->ep & 0x80)) {
- if (copy_from_user(data, ai->data, totsize)) {
- free_async(as);
- return -EFAULT;
- }
- as->userdata = NULL; /* no need to copy back at completion */
- }
- async_newpending(as);
- if ((ret = usb_submit_urb(&as->urb))) {
- printk(KERN_DEBUG "ezusb: iso: usb_submit_urb returned %d\n", ret);
- async_removepending(as);
- free_async(as);
- return -EINVAL; /* return ret; */
- }
- return 0;
-}
-
-static int ezusb_terminateasync(struct ezusb *ez, void *context)
-{
- struct async *as;
- int ret = 0;
-
- while ((as = async_getpending(ez, context))) {
- usb_unlink_urb(&as->urb);
- ret++;
- }
- return ret;
-}
-
-static int ezusb_asynccompl(struct async *as, void *arg)
-{
- struct ezusb_asynccompleted *cpl;
- unsigned int numframes, cplsize, i;
-
- if (as->userdata) {
- if (copy_to_user(as->userdata, as->urb.transfer_buffer, as->datalen)) {
- free_async(as);
- return -EFAULT;
- }
- }
- numframes = as->urb.number_of_packets;
- cplsize = sizeof(struct ezusb_asynccompleted) + numframes * sizeof(struct ezusb_isoframestat);
- if (!(cpl = kmalloc(cplsize, GFP_KERNEL))) {
- free_async(as);
- return -ENOMEM;
- }
- cpl->status = as->urb.status;
- cpl->length = as->urb.actual_length;
- cpl->context = as->context;
- for (i = 0; i < numframes; i++) {
- cpl->isostat[i].length = as->urb.iso_frame_desc[i].length;
- cpl->isostat[i].status = as->urb.iso_frame_desc[i].status;
- }
- free_async(as);
- if (copy_to_user(arg, cpl, cplsize)) {
- kfree(cpl);
- return -EFAULT;
- }
- kfree(cpl);
- 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_old_ctrltransfer opctrl;
- struct usb_proc_old_bulktransfer opbulk;
- struct usb_proc_setinterface psetintf;
- struct ezusb_ctrltransfer ctrl;
- struct ezusb_bulktransfer bulk;
- struct ezusb_old_ctrltransfer octrl;
- struct ezusb_old_bulktransfer obulk;
- struct ezusb_setinterface setintf;
- struct ezusb_asyncbulk abulk;
- struct ezusb_asynciso aiso;
- struct ezusb_interrupt ezint;
- 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.timeout * HZ + 500) / 1000, 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.timeout * HZ + 500) / 1000, pbulk.data);
- break;
-
- case USB_PROC_OLD_CONTROL:
- if (copy_from_user(&opctrl, (void *)arg, sizeof(opctrl))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_control(ez->usbdev, opctrl.requesttype, opctrl.request,
- opctrl.value, opctrl.index, opctrl.length, HZ, opctrl.data);
- break;
-
- case USB_PROC_OLD_BULK:
- if (copy_from_user(&opbulk, (void *)arg, sizeof(opbulk))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_bulk(ez->usbdev, opbulk.ep, opbulk.len, 5*HZ, opbulk.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:
- if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request,
- ctrl.value, ctrl.index, ctrl.length,
- (ctrl.timeout * HZ + 500) / 1000, ctrl.data);
- break;
-
- case EZUSB_BULK:
- if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len,
- (bulk.timeout * HZ + 500) / 1000, bulk.data);
- break;
-
- case EZUSB_OLD_CONTROL:
- if (copy_from_user(&octrl, (void *)arg, sizeof(octrl))) {
- ret = -EFAULT;
- break;
- }
- if (octrl.dlen != octrl.length) {
- ret = -EINVAL;
- break;
- }
- ret = ezusb_control(ez->usbdev, octrl.requesttype, octrl.request,
- octrl.value, octrl.index, octrl.length, HZ, octrl.data);
- break;
-
- case EZUSB_OLD_BULK:
- if (copy_from_user(&obulk, (void *)arg, sizeof(obulk))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_bulk(ez->usbdev, obulk.ep, obulk.len, 5*HZ, obulk.data);
- break;
-
- case EZUSB_RESETEP:
- if (get_user(ep, (unsigned int *)arg)) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_resetep(ez->usbdev, ep);
- break;
-
- case EZUSB_SETINTERFACE:
- 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;
- }
- ret = ezusb_setconfiguration(ez->usbdev, cfg);
- break;
-
- case EZUSB_ASYNCCOMPLETED:
- as = NULL;
- 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);
- schedule();
- down(&ez->mutex);
- }
- remove_wait_queue(&ez->wait, &wait);
- current->state = TASK_RUNNING;
- if (as) {
- ret = ezusb_asynccompl(as, (void *)arg);
- break;
- }
- if (signal_pending(current)) {
- ret = -EINTR;
- break;
- }
- ret = -EIO;
- break;
-
- case EZUSB_ASYNCCOMPLETEDNB:
- if ((as = async_getcompleted(ez))) {
- ret = ezusb_asynccompl(as, (void *)arg);
- break;
- }
- ret = -EAGAIN;
- break;
-
- case EZUSB_REQUESTBULK:
- if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_requestbulk(ez, &abulk);
- break;
-
- case EZUSB_REQUESTISO:
- if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso));
- break;
-
- case EZUSB_TERMINATEASYNC:
- if (get_user(context, (void **)arg)) {
- ret = -EFAULT;
- break;
- }
- ret = ezusb_terminateasync(ez, context);
- break;
-
- case EZUSB_GETFRAMENUMBER:
- i = usb_get_current_frame_number(ez->usbdev);
- ret = put_user(i, (int *)arg);
- break;
-
- case EZUSB_INTERRUPT:
- printk("INT START\n");
- if (copy_from_user(&ezint, (void *)arg, sizeof(ezint))) {
- ret = -EFAULT;
- break;
- }
- ret=ezusb_interrupt(ez,&ezint);
- break;
- default:
- ret = -ENOIOCTLCMD;
- break;
- }
- up(&ez->mutex);
- return ret;
-}
-
-static struct file_operations ezusb_fops = {
- ezusb_llseek,
- ezusb_read,
- ezusb_write,
- NULL, /* readdir */
- NULL, /* poll */
- ezusb_ioctl,
- NULL, /* mmap */
- ezusb_open,
- NULL, /* flush */
- ezusb_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
-};
-
-/* --------------------------------------------------------------------- */
-
-static void * ezusb_probe(struct usb_device *usbdev, unsigned int ifnum)
-{
- struct ezusb *ez = &ezusb[0];
- struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
-
-#undef KERN_DEBUG
-#define KERN_DEBUG ""
- printk(KERN_DEBUG "ezusb: probe: vendor id 0x%x, device id 0x%x\n",
- usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
-
- /* the 1234:5678 is just a self assigned test ID */
- if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131)
- #if 1
- &&
- (usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x9999) &&
- (usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678)
- #endif
- )
- return NULL;
-
- /* We don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1)
- return NULL;
-
-#if 0
- /* We don't handle multiple interfaces */
- if (usbdev->config[0].bNumInterfaces != 1)
- return NULL;
-#endif
-
- down(&ez->mutex);
- if (ez->usbdev) {
- up(&ez->mutex);
- printk(KERN_INFO "ezusb: device already used\n");
- return NULL;
- }
- ez->usbdev = usbdev;
- if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) {
- printk(KERN_ERR "ezusb: set_configuration failed\n");
- goto err;
- }
-
- interface = &usbdev->config[0].interface[0].altsetting[1];
- if (usb_set_interface(usbdev, 0, 1) < 0) {
- printk(KERN_ERR "ezusb: set_interface failed\n");
- goto err;
- }
- up(&ez->mutex);
- MOD_INC_USE_COUNT;
- return ez;
-
- err:
- up(&ez->mutex);
- ez->usbdev = NULL;
- return NULL;
-}
-
-static void ezusb_disconnect(struct usb_device *usbdev, void *ptr)
-{
- struct ezusb *ez = (struct ezusb *)ptr;
-
- down(&ez->mutex);
- destroy_all_async(ez);
- ez->usbdev = NULL;
- up(&ez->mutex);
- wake_up(&ez->wait);
- MOD_DEC_USE_COUNT;
-}
-
-static struct usb_driver ezusb_driver = {
- "ezusb",
- ezusb_probe,
- ezusb_disconnect,
- { NULL, NULL },
- &ezusb_fops,
- 192
-};
-
-/* --------------------------------------------------------------------- */
-
-int ezusb_init(void)
-{
- unsigned u;
-
- /* initialize struct */
- for (u = 0; u < NREZUSB; u++) {
- init_MUTEX(&ezusb[u].mutex);
- ezusb[u].usbdev = NULL;
- 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 */
- usb_register(&ezusb_driver);
- printk(KERN_INFO "ezusb: Anchorchip firmware download driver registered\n");
- return 0;
-}
-
-void ezusb_cleanup(void)
-{
- usb_deregister(&ezusb_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-
-int minor = 192;
-
-int init_module(void)
-{
- return ezusb_init();
-}
-
-void cleanup_module(void)
-{
- ezusb_cleanup();
-}
-
-#endif
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/ezusb.h b/drivers/usb/ezusb.h
deleted file mode 100644
index b7d480558..000000000
--- a/drivers/usb/ezusb.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*****************************************************************************/
-
-/*
- * ezusb.h -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
- *
- * Copyright (C) 1999
- * Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*****************************************************************************/
-
-#ifndef _LINUX_EZUSB_H
-#define _LINUX_EZUSB_H
-
-#include <linux/ioctl.h>
-
-/* --------------------------------------------------------------------- */
-
-struct ezusb_old_ctrltransfer {
- /* keep in sync with usb.h:devrequest */
- unsigned char requesttype;
- unsigned char request;
- unsigned short value;
- unsigned short index;
- unsigned short length;
- unsigned int dlen;
- void *data;
-};
-
-struct ezusb_old_bulktransfer {
- unsigned int ep;
- unsigned int len;
- void *data;
-};
-
-struct ezusb_ctrltransfer {
- /* keep in sync with usb.h:devrequest */
- unsigned char requesttype;
- unsigned char request;
- unsigned short value;
- unsigned short index;
- unsigned short length;
- unsigned int timeout; /* in milliseconds */
- void *data;
-};
-
-struct ezusb_bulktransfer {
- unsigned int ep;
- unsigned int len;
- unsigned int timeout; /* in milliseconds */
- void *data;
-};
-
-struct ezusb_interrupt {
- unsigned int ep;
- unsigned int len;
- unsigned int interval; /* in milliseconds */
- void *data;
-};
-struct ezusb_setinterface {
- unsigned int interface;
- unsigned int altsetting;
-};
-
-struct ezusb_isoframestat {
- unsigned int length;
- unsigned int status;
-};
-
-struct ezusb_asynccompleted {
- int status;
- unsigned length;
- void *context;
- struct ezusb_isoframestat isostat[0];
-};
-
-struct ezusb_asyncbulk {
- unsigned int ep;
- unsigned int len;
- void *context;
- void *data;
-};
-
-struct ezusb_asynciso {
- unsigned int ep;
-
- unsigned int framecnt;
- unsigned int startframe;
-
- void *context;
- void *data;
- struct ezusb_isoframestat isostat[0];
-};
-
-#define EZUSB_CONTROL _IOWR('E', 1, struct ezusb_ctrltransfer)
-#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer)
-#define EZUSB_OLD_CONTROL _IOWR('E', 0, struct ezusb_old_ctrltransfer)
-#define EZUSB_OLD_BULK _IOWR('E', 2, struct ezusb_old_bulktransfer)
-#define EZUSB_RESETEP _IOR('E', 3, unsigned int)
-#define EZUSB_SETINTERFACE _IOR('E', 4, struct ezusb_setinterface)
-#define EZUSB_SETCONFIGURATION _IOR('E', 5, unsigned int)
-#define EZUSB_ASYNCCOMPLETED _IOW('E', 8, struct ezusb_asynccompleted)
-#define EZUSB_ASYNCCOMPLETEDNB _IOW('E', 9, struct ezusb_asynccompleted)
-#define EZUSB_REQUESTBULK _IOR('E', 16, struct ezusb_asyncbulk)
-#define EZUSB_REQUESTISO _IOR('E', 17, struct ezusb_asynciso)
-#define EZUSB_TERMINATEASYNC _IOR('E', 18, void *)
-#define EZUSB_GETFRAMENUMBER _IOW('E', 19, unsigned int)
-#define EZUSB_INTERRUPT _IOWR('E', 20, struct ezusb_interrupt)
-
-/* --------------------------------------------------------------------- */
-#endif /* _LINUX_EZUSB_H */
diff --git a/drivers/usb/graphire.c b/drivers/usb/graphire.c
new file mode 100644
index 000000000..cfda14d5c
--- /dev/null
+++ b/drivers/usb/graphire.c
@@ -0,0 +1,186 @@
+/*
+ * graphire.c Version 0.1
+ *
+ * Copyright (c) 1999 Vojtech Pavlik
+ *
+ * USB Wacom Graphire tablet support
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include "usb.h"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+/*
+ * Thanks for the following information to: Andreas Bach Aaen <abach@mail1.stofanet.dk>
+ *
+ * The input report:
+ *
+ * byte 0: report ID (2)
+ * byte 1: bit7 mouse/pen/rubber near
+ * bit5-6 0 - pen, 1 - rubber, 2 - mouse
+ * bit4 1 ?
+ * bit3 0 ?
+ * bit2 mouse middle button / pen button2
+ * bit1 mouse right button / pen button1
+ * bit0 mouse left button / pen tip / rubber
+ * byte 2: X low bits
+ * byte 3: X high bits
+ * byte 4: Y low bits
+ * byte 5: Y high bits
+ * byte 6: pen pressure low bits / mouse wheel
+ * byte 7: pen presure high bits / mouse distance
+ *
+ * There are also two single-byte feature reports (2 and 3).
+ */
+
+#define USB_VENDOR_ID_WACOM 0xffff /* FIXME */
+#define USB_DEVICE_ID_WACOM_GRAPHIRE 0xffff /* FIXME */
+
+struct graphire {
+ signed char data[8];
+ int oldx, oldy;
+ struct input_dev dev;
+ struct urb irq;
+};
+
+static void graphire_irq(struct urb *urb)
+{
+ struct graphire *graphire = urb->context;
+ unsigned char *data = graphire->data;
+ struct input_dev *dev = &graphire->dev;
+
+ if (urb->status) return;
+
+ if (data[0] != 2)
+ dbg("received unknown report #%d", data[0]);
+
+ input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
+ input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
+
+ input_report_key(dev, BTN_NEAR, !!(data[1] & 0x80));
+
+ switch ((data[1] >> 5) & 3) {
+
+ case 0: /* Pen */
+ input_report_key(dev, BTN_PEN, !!(data[1] & 0x01));
+ input_report_key(dev, BTN_PEN_SIDE, !!(data[1] & 0x02));
+ input_report_key(dev, BTN_PEN_SIDE2, !!(data[1] & 0x04));
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+ break;
+
+ case 1: /* Rubber */
+ input_report_key(dev, BTN_RUBBER, !!(data[1] & 0x01));
+ input_report_key(dev, BTN_PEN_SIDE, !!(data[1] & 0x02));
+ input_report_key(dev, BTN_PEN_SIDE2, !!(data[1] & 0x04));
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+ break;
+
+ case 2: /* Mouse */
+ input_report_key(dev, BTN_LEFT, !!(data[0] & 0x01));
+ input_report_key(dev, BTN_RIGHT, !!(data[0] & 0x02));
+ input_report_key(dev, BTN_MIDDLE, !!(data[0] & 0x04));
+ input_report_abs(dev, ABS_DISTANCE, data[7]);
+
+ if (data[1] & 0x80) {
+ input_report_rel(dev, REL_X, dev->abs[ABS_X] - graphire->oldx);
+ input_report_rel(dev, REL_Y, dev->abs[ABS_Y] - graphire->oldy);
+ }
+
+ input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+ break;
+ }
+
+ graphire->oldx = dev->abs[ABS_X];
+ graphire->oldy = dev->abs[ABS_Y];
+}
+
+static void *graphire_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_endpoint_descriptor *endpoint;
+ struct graphire *graphire;
+
+ if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM ||
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE)
+ return NULL;
+
+ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+ if (!(graphire = kmalloc(sizeof(struct graphire), GFP_KERNEL))) return NULL;
+ memset(graphire, 0, sizeof(struct graphire));
+
+ graphire->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
+ graphire->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_PEN) | BIT(BTN_RUBBER);
+ graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_PEN_SIDE) | BIT(BTN_PEN_SIDE2) | BIT(BTN_NEAR);
+ graphire->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+ graphire->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+
+ FILL_INT_URB(&graphire->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ graphire->data, 8, graphire_irq, graphire, endpoint->bInterval);
+
+ if (usb_submit_urb(&graphire->irq)) {
+ kfree(graphire);
+ return NULL;
+ }
+
+ input_register_device(&graphire->dev);
+
+ printk(KERN_INFO "input%d: Wacom Graphire USB\n", graphire->dev.number);
+
+ return graphire;
+}
+
+static void graphire_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct graphire *graphire = ptr;
+ usb_unlink_urb(&graphire->irq);
+ input_unregister_device(&graphire->dev);
+ kfree(graphire);
+}
+
+static struct usb_driver graphire_driver = {
+ name: "graphire",
+ probe: graphire_probe,
+ disconnect: graphire_disconnect,
+};
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ usb_deregister(&graphire_driver);
+}
+
+int init_module(void)
+#else
+int graphire_init(void)
+#endif
+{
+ usb_register(&graphire_driver);
+ return 0;
+}
diff --git a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h
index a31c2910f..52fc94adb 100644
--- a/drivers/usb/hid-debug.h
+++ b/drivers/usb/hid-debug.h
@@ -1,8 +1,8 @@
/*
* driver/usb/hid-debug.h
*
- * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
- * (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+ * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
+ * (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
*
* Some debug stuff for the HID parser.
*
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index bdd540ac2..ec1a4639d 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -2,7 +2,7 @@
* hid.c Version 0.8
*
* Copyright (c) 1999 Andreas Gal
- * Copyright (c) 1999 Vojtech Pavlik
+ * Copyright (c) 2000 Vojtech Pavlik
*
* USB HID support for the Linux input drivers
*
@@ -38,10 +38,10 @@
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
-#include <linux/config.h>
#include <linux/spinlock.h>
#undef DEBUG
+#undef DEBUG_DATA
#include "usb.h"
#include "hid.h"
@@ -710,7 +710,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
{
report += (offset >> 5) << 2; offset &= 31;
- *(__u64*)report &= cpu_to_le64(~((1ULL << n) - 1) << offset);
+ *(__u64*)report &= cpu_to_le64(~((((__u64) 1 << n) - 1) << offset));
*(__u64*)report |= cpu_to_le64((__u64)value << offset);
}
@@ -763,6 +763,12 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
break;
+ case HID_UP_LED:
+
+ usage->code = (usage->hid - 1) & 0xf;
+ usage->type = EV_LED; bit = input->ledbit; max = LED_MAX;
+ break;
+
default:
if (field->flags & HID_MAIN_ITEM_RELATIVE) {
@@ -905,7 +911,7 @@ static void hid_irq(struct urb *urb)
return;
}
-#ifdef DEBUG
+#ifdef DEBUG_DATA
printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un");
for (n = 0; n < len; n++)
printk(" %02x", data[n]);
@@ -953,10 +959,10 @@ static void hid_irq(struct urb *urb)
static void hid_read_report(struct hid_device *hid, struct hid_report *report)
{
#if 0
- int rlen = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
+ int rlen = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
char rdata[rlen];
struct urb urb;
- int read;
+ int read, j;
memset(&urb, 0, sizeof(struct urb));
memset(rdata, 0, rlen);
@@ -974,7 +980,7 @@ static void hid_read_report(struct hid_device *hid, struct hid_report *report)
for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]);
printk("\n");
#endif
- continue;
+ return;
}
hid_irq(&urb);
@@ -982,33 +988,6 @@ static void hid_read_report(struct hid_device *hid, struct hid_report *report)
}
/*
- * Configure the input layer interface
- * Read all reports and initalize the absoulte field values.
- */
-
-static void hid_init_input(struct hid_device *hid)
-{
- struct hid_report_enum *report_enum = hid->report_enum + HID_INPUT_REPORT;
- struct list_head *list;
- int i, j;
-
- list = report_enum->report_list.next;
-
- while (list != &report_enum->report_list) {
-
- struct hid_report *report = (struct hid_report *) list;
-
- list = list->next;
-
- for (i = 0; i < report->maxfield; i++)
- for (j = 0; j < report->field[i]->maxusage; j++)
- hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
-
- hid_read_report(hid, report);
- }
-}
-
-/*
* Output the field into the report.
*/
@@ -1035,9 +1014,11 @@ void hid_output_report(struct hid_report *report, __u8 *data)
{
unsigned n;
+#if 0
/* skip the ID if we have a single report */
if (report->device->report_enum[report->type].numbered)
*data++ = report->id;
+#endif
for (n = 0; n < report->maxfield; n++)
hid_output_field(report->field[n], data);
@@ -1052,6 +1033,8 @@ void hid_output_report(struct hid_report *report, __u8 *data)
int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
{
unsigned size = field->report_size;
+
+ hid_dump_input(field->usage + offset, value);
if (offset >= field->report_count) {
dbg("offset exceeds report_count");
@@ -1072,10 +1055,104 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
return 0;
}
+static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+ struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
+ struct list_head *list = report_enum->report_list.next;
+ int i, j;
+
+ while (list != &report_enum->report_list) {
+ struct hid_report *report = (struct hid_report *) list;
+ list = list->next;
+ for (i = 0; i < report->maxfield; i++) {
+ *field = report->field[i];
+ for (j = 0; j < (*field)->maxusage; j++)
+ if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+ return j;
+ }
+ }
+ return -1;
+}
+
+static void hid_ctrl(struct urb *urb)
+{
+ if (urb->status)
+ warn("ctrl urb status %d received", urb->status);
+}
+
+static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct hid_device *hid = dev->private;
+ struct hid_field *field = NULL;
+ int offset;
+
+ if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
+ warn("event field not found");
+ return -1;
+ }
+
+ hid_set_field(field, offset, value);
+
+ if (hid->urbout.status == -EINPROGRESS) {
+ warn("had to kill output urb");
+ usb_unlink_urb(&hid->urbout);
+ }
+
+ hid_output_report(field->report, hid->bufout);
+
+ hid->dr.value = 0x200 | field->report->id;
+ hid->dr.length = ((field->report->size - 1) >> 3) + 1;
+ hid->urbout.transfer_buffer_length = hid->dr.length;
+
+ if (usb_submit_urb(&hid->urbout)) {
+ err("usb_submit_urb(out) failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Configure the input layer interface
+ * Read all reports and initalize the absoulte field values.
+ */
+
+static void hid_init_input(struct hid_device *hid)
+{
+ struct hid_report_enum *report_enum;
+ struct list_head *list;
+ int i, j, k;
+
+ hid->input.private = hid;
+ hid->input.event = hid_event;
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+
+ report_enum = hid->report_enum + k;
+ list = report_enum->report_list.next;
+
+ while (list != &report_enum->report_list) {
+
+ struct hid_report *report = (struct hid_report *) list;
+
+ list = list->next;
+
+ for (i = 0; i < report->maxfield; i++)
+ for (j = 0; j < report->field[i]->maxusage; j++)
+ hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
+
+ if (k == HID_INPUT_REPORT) {
+ usb_set_idle(hid->dev, 0, report->id);
+ hid_read_report(hid, report);
+ }
+ }
+ }
+}
+
static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
{
struct usb_interface_descriptor *interface = &dev->actconfig->interface[ifnum].altsetting[0];
- struct usb_hid_descriptor *hdesc;
+ struct hid_descriptor *hdesc;
struct hid_device *hid;
unsigned rsize = 0;
int n;
@@ -1106,7 +1183,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
return NULL;
}
-#ifdef DEBUG
+#ifdef DEBUG_DATA
printk(KERN_DEBUG __FILE__ ": report (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
printk(" %02x", (unsigned) rdesc[n]);
@@ -1149,6 +1226,15 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
return NULL;
}
+ hid->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ hid->dr.request = USB_REQ_SET_REPORT;
+ hid->dr.value = 0x200;
+ hid->dr.index = interface->bInterfaceNumber;
+ hid->dr.length = 1;
+
+ FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
+ (void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid);
+
hid->version = hdesc->bcdHID;
hid->country = hdesc->bCountryCode;
hid->dev = dev;
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index 8ccdb67bd..ab652442f 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -4,8 +4,8 @@
/*
* drivers/usb/hid.h Version 0.8
*
- * Copyright (c) 1999 Vojtech Pavlik
* Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000 Vojtech Pavlik
*
* Sponsored by SuSE
*/
@@ -36,37 +36,12 @@
#include <linux/list.h>
/*
- * Enable/Disable debug information.
- */
-
-#ifdef CONFIG_USB_HID_DEBUG
-#define hid_debug(fmt,arg...) printk(KERN_DEBUG "hid: " fmt "\n" , ##arg)
-#else
-#define hid_debug(fmt,arg...) do { } while (0)
-#endif
-
-/*
* USB HID (Human Interface Device) interface class code
*/
#define USB_INTERFACE_CLASS_HID 3
/*
- * USB interface subclass codes.
- */
-
-#define USB_INTERFACE_SUBCLASS_NONE 0
-#define USB_INTERFACE_SUBCLASS_HID_BP 1
-
-/*
- * HID protocol codes (only for boot protocol)
- */
-
-#define HID_PROTOCOL_NONE 0
-#define HID_PROTOCOL_KBD 1
-#define HID_PROTOCOL_MOUSE 2
-
-/*
* We parse each description item into this structure. Short items data
* values are expanded to 32-bit signed int, long items contain a pointer
* into the data area.
@@ -122,7 +97,6 @@ struct hid_item {
/*
* HID report descriptor main item contents
- * Warning: VOLATILE is not available for TAG_INPUT
*/
#define HID_MAIN_ITEM_CONSTANT 0x001
@@ -196,18 +170,6 @@ struct hid_item {
#define HID_GD_HATSWITCH 0x00010039
/*
- * HID interface requests (this belongs here, the USB_REQ_xxx stuff should
- * disapear).
- */
-
-#define HID_REQ_GET_REPORT 0x01
-#define HID_REQ_GET_IDLE 0x02
-#define HID_REQ_GET_PROTOCOL 0x03
-#define HID_REQ_SET_REPORT 0x09
-#define HID_REQ_SET_IDLE 0x0A
-#define HID_REQ_SET_PROTOCOL 0x0B
-
-/*
* HID report types --- Ouch! HID spec says 1 2 3!
*/
@@ -216,13 +178,6 @@ struct hid_item {
#define HID_FEATURE_REPORT 2
/*
- * HID protocols
- */
-
-#define HID_PROTOCOL_BOOT 0
-#define HID_PROTOCOL_REPORT 1
-
-/*
* This is the global enviroment of the parser. This information is
* persistent for main-items. The global enviroment can be saved and
* restored with PUSH/POP statements.
@@ -324,7 +279,10 @@ struct hid_device { /* device report descriptor */
int ifnum; /* USB interface number */
char buffer[32]; /* Receive buffer */
+ char bufout[32]; /* Transmit buffer */
+ devrequest dr; /* Startup packet */
struct urb urb; /* USB URB structure */
+ struct urb urbout; /* Output URB */
struct input_dev input; /* input device structure */
};
@@ -341,5 +299,21 @@ struct hid_parser {
struct hid_device *device;
};
+struct hid_class_descriptor {
+ __u8 bDescriptorType;
+ __u16 wDescriptorLength;
+} __attribute__ ((packed));
+
+struct hid_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u16 bcdHID;
+ __u8 bCountryCode;
+ __u8 bNumDescriptors;
+
+ struct hid_class_descriptor desc[1];
+} __attribute__ ((packed));
+
+
#endif
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index de7c65674..c066c3c43 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -48,13 +48,11 @@ static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
USB_DT_HUB << 8, 0, data, size, HZ);
}
-#if 0
-static int usb_clear_hub_feature(struct usb_device *dev, int feature)
+static int usb_clear_hub_feature(struct usb_device *dev, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0 , NULL, 0, HZ);
+ USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
}
-#endif
static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
{
@@ -359,7 +357,8 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
}
if (tries==MAX_TRIES) {
- err("can not enable port %i after %i retries, disabling port", port+1, MAX_TRIES);
+ err("Cannot enable port %i after %i retries, disabling port.", port+1, MAX_TRIES);
+ err("Maybe the USB cable is bad?");
return;
}
/* Allocate a new device struct for it */
@@ -392,6 +391,8 @@ static void usb_hub_events(void)
struct list_head *tmp;
struct usb_device *dev;
struct usb_hub *hub;
+ struct usb_hub_status hubsts;
+ unsigned short hubstatus, hubchange;
/*
* We restart the list everytime to avoid a deadlock with
@@ -444,14 +445,32 @@ static void usb_hub_events(void)
if (portchange & USB_PORT_STAT_C_SUSPEND)
dbg("port %d suspend change", i + 1);
- if (portchange & USB_PORT_STAT_C_OVERCURRENT)
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
dbg("port %d over-current change", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+ }
if (portchange & USB_PORT_STAT_C_RESET) {
dbg("port %d reset change", i + 1);
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
}
} /* end for i */
+
+ /* deal with hub status changes */
+ if (usb_get_hub_status(dev, &hubsts) < 0) {
+ err("get_hub_status failed");
+ } else {
+ hubstatus = le16_to_cpup(&hubsts.wHubStatus);
+ hubchange = le16_to_cpup(&hubsts.wHubChange);
+ if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+ dbg("hub power change");
+ usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+ }
+ if (hubchange & HUB_CHANGE_OVERCURRENT) {
+ dbg("hub overcurrent change");
+ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+ }
+ }
} /* end while (1) */
he_unlock:
diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h
index c95a07d74..0da7eb87c 100644
--- a/drivers/usb/hub.h
+++ b/drivers/usb/hub.h
@@ -4,6 +4,13 @@
#include <linux/list.h>
/*
+ * Hub request types
+ */
+
+#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+/*
* Hub Class feature numbers
*/
#define C_HUB_LOCAL_POWER 0
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
new file mode 100644
index 000000000..00a2ac523
--- /dev/null
+++ b/drivers/usb/inode.c
@@ -0,0 +1,729 @@
+/*****************************************************************************/
+
+/*
+ * inode.c -- Inode/Dentry functions for the USB device file system.
+ *
+ * Copyright (C) 2000
+ * Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ * $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $
+ *
+ * History:
+ * 0.1 04.01.2000 Created
+ */
+
+/*****************************************************************************/
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+/* --------------------------------------------------------------------- */
+
+static LIST_HEAD(superlist);
+
+extern struct inode_operations usbdevfs_bus_inode_operations;
+
+static struct inode_operations devices_inode_operations = {
+ &usbdevfs_devices_fops
+};
+
+static struct inode_operations drivers_inode_operations = {
+ &usbdevfs_drivers_fops
+};
+
+struct special {
+ const char *name;
+ struct inode_operations *iops;
+ struct list_head inodes;
+};
+
+static struct special special[] = {
+ { "devices", &devices_inode_operations, },
+ { "drivers", &drivers_inode_operations, }
+};
+
+#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
+
+/* --------------------------------------------------------------------- */
+
+static int dnumber(struct dentry *dentry)
+{
+ const char *name;
+ unsigned int s;
+
+ if (dentry->d_name.len != 3)
+ return -1;
+ name = dentry->d_name.name;
+ if (name[0] < '0' || name[0] > '9' ||
+ name[1] < '0' || name[1] > '9' ||
+ name[2] < '0' || name[2] > '9')
+ return -1;
+ s = name[0] - '0';
+ s = s * 10 + name[1] - '0';
+ s = s * 10 + name[2] - '0';
+ return s;
+}
+
+/*
+ * utility functions; should be called with the kernel lock held
+ * to protect against busses/devices appearing/disappearing
+ */
+
+static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+ struct inode *inode;
+ unsigned int devnum = dev->devnum;
+ unsigned int busnum = dev->bus->busnum;
+
+ if (devnum < 1 || devnum > 127 || busnum > 255)
+ return;
+ inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
+ if (!inode) {
+ printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
+ return;
+ }
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_uid = sb->u.usbdevfs_sb.devuid;
+ inode->i_gid = sb->u.usbdevfs_sb.devgid;
+ inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
+ inode->i_op = &usbdevfs_device_inode_operations;
+ inode->i_size = sizeof(struct usb_device_descriptor);
+ inode->u.usbdev_i.p.dev = dev;
+ list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+ list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
+}
+
+static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+ unsigned int i;
+
+ if (!dev)
+ return;
+ new_dev_inode(dev, sb);
+ for (i = 0; i < dev->maxchild; i++) {
+ if (!dev->children[i])
+ continue;
+ recurse_new_dev_inode(dev->children[i], sb);
+ }
+}
+
+static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
+{
+ struct inode *inode;
+ unsigned int busnum = bus->busnum;
+
+ if (busnum > 255)
+ return;
+ inode = iget(sb, IBUS | (busnum << 8));
+ if (!inode) {
+ printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
+ return;
+ }
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_uid = sb->u.usbdevfs_sb.busuid;
+ inode->i_gid = sb->u.usbdevfs_sb.busgid;
+ inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
+ inode->i_op = &usbdevfs_bus_inode_operations;
+ inode->u.usbdev_i.p.bus = bus;
+ list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+ list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
+}
+
+static void free_inode(struct inode *inode)
+{
+ inode->u.usbdev_i.p.bus = NULL;
+ inode->u.usbdev_i.p.dev = NULL;
+ inode->i_mode &= ~S_IRWXUGO;
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_op = NULL;
+ inode->i_size = 0;
+ list_del(&inode->u.usbdev_i.slist);
+ INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+ list_del(&inode->u.usbdev_i.dlist);
+ INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+ iput(inode);
+}
+
+static struct usb_bus *usbdevfs_findbus(int busnr)
+{
+ struct list_head *list;
+ struct usb_bus *bus;
+
+ for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+ bus = list_entry(list, struct usb_bus, bus_list);
+ if (bus->busnum == busnr)
+ return bus;
+ }
+ return NULL;
+}
+
+#if 0
+static struct usb_device *finddev(struct usb_device *dev, int devnr)
+{
+ unsigned int i;
+ struct usb_device *d2;
+
+ if (!dev)
+ return NULL;
+ if (dev->devnum == devnr)
+ return dev;
+ for (i = 0; i < dev->maxchild; i++) {
+ if (!dev->children[i])
+ continue;
+ if ((d2 = finddev(dev->children[i], devnr)))
+ return d2;
+ }
+ return NULL;
+}
+
+static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+{
+ return finddev(bus->root_hub, devnr);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (!inode)
+ return 0;
+ if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
+ return 0;
+ if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
+ return 0;
+ return 1;
+}
+
+static struct dentry_operations usbdevfs_dentry_operations = {
+ usbdevfs_revalidate, /* d_revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+};
+
+static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+{
+ int busnr;
+ unsigned long ino = 0;
+ unsigned int i;
+ struct inode *inode;
+
+ /* sanity check */
+ if (dir->i_ino != IROOT)
+ return ERR_PTR(-EINVAL);
+ dentry->d_op = &usbdevfs_dentry_operations;
+ busnr = dnumber(dentry);
+ if (busnr >= 0 && busnr <= 255)
+ ino = IBUS | (busnr << 8);
+ if (!ino) {
+ for (i = 0; i < NRSPECIAL; i++) {
+ if (strlen(special[i].name) == dentry->d_name.len &&
+ !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
+ ino = ISPECIAL | (i + IROOT + 1);
+ break;
+ }
+ }
+ }
+ if (!ino)
+ return ERR_PTR(-ENOENT);
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
+ return ERR_PTR(-EINVAL);
+ if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
+ iput(inode);
+ inode = NULL;
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode;
+ int devnr;
+
+ /* sanity check */
+ if (ITYPE(dir->i_ino) != IBUS)
+ return ERR_PTR(-EINVAL);
+ dentry->d_op = &usbdevfs_dentry_operations;
+ devnr = dnumber(dentry);
+ if (devnr < 1 || devnr > 127)
+ return ERR_PTR(-ENOENT);
+ inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
+ if (!inode)
+ return ERR_PTR(-EINVAL);
+ if (inode && inode->u.usbdev_i.p.dev == NULL) {
+ iput(inode);
+ inode = NULL;
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ unsigned long ino = inode->i_ino;
+ struct special *spec;
+ struct list_head *list;
+ struct usb_bus *bus;
+ char numbuf[8];
+ unsigned int i;
+
+ /* sanity check */
+ if (ino != IROOT)
+ return -EINVAL;
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, IROOT) < 0)
+ return 0;
+ filp->f_pos++;
+ i++;
+ /* fall through */
+
+ case 1:
+ if (filldir(dirent, "..", 2, i, IROOT) < 0)
+ return 0;
+ filp->f_pos++;
+ i++;
+ /* fall through */
+
+ default:
+
+ while (i >= 2 && i < 2+NRSPECIAL) {
+ spec = &special[filp->f_pos-2];
+ if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
+ return 0;
+ filp->f_pos++;
+ i++;
+ }
+ if (i < 2+NRSPECIAL)
+ return 0;
+ i -= 2+NRSPECIAL;
+ lock_kernel();
+ for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+ if (i > 0) {
+ i--;
+ continue;
+ }
+ bus = list_entry(list, struct usb_bus, bus_list);
+ sprintf(numbuf, "%03d", bus->busnum);
+ if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
+ break;
+ filp->f_pos++;
+ }
+ unlock_kernel();
+ return 0;
+ }
+}
+
+static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+{
+ char numbuf[8];
+ unsigned int i;
+
+ if (!dev)
+ return pos;
+ sprintf(numbuf, "%03d", dev->devnum);
+ if (pos > 0)
+ pos--;
+ else {
+ if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
+ return -1;
+ filp->f_pos++;
+ }
+ for (i = 0; i < dev->maxchild; i++) {
+ if (!dev->children[i])
+ continue;
+ pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
+ if (pos < 0)
+ return -1;
+ }
+ return pos;
+}
+
+static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ unsigned long ino = inode->i_ino;
+ struct usb_bus *bus;
+
+ /* sanity check */
+ if (ITYPE(ino) != IBUS)
+ return -EINVAL;
+ switch ((unsigned int)filp->f_pos) {
+ case 0:
+ if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0)
+ return 0;
+ filp->f_pos++;
+ /* fall through */
+
+ case 1:
+ if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0)
+ return 0;
+ filp->f_pos++;
+ /* fall through */
+
+ default:
+ lock_kernel();
+ bus = usbdevfs_findbus(IBUSNR(ino));
+ bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir);
+ unlock_kernel();
+ return 0;
+ }
+}
+
+static struct file_operations usbdevfs_root_file_operations = {
+ readdir: usbdevfs_root_readdir
+};
+
+static struct inode_operations usbdevfs_root_inode_operations = {
+ default_file_ops: &usbdevfs_root_file_operations,
+ lookup: usbdevfs_root_lookup
+};
+
+static struct file_operations usbdevfs_bus_file_operations = {
+ readdir: usbdevfs_bus_readdir
+};
+
+static struct inode_operations usbdevfs_bus_inode_operations = {
+ default_file_ops: &usbdevfs_bus_file_operations,
+ lookup: usbdevfs_bus_lookup
+};
+
+static void usbdevfs_read_inode(struct inode *inode)
+{
+ struct special *spec;
+
+ inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_mode = S_IFREG;
+ inode->i_gid = inode->i_uid = 0;
+ INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+ INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+ inode->u.usbdev_i.p.dev = NULL;
+ inode->u.usbdev_i.p.bus = NULL;
+ switch (ITYPE(inode->i_ino)) {
+ case ISPECIAL:
+ if (inode->i_ino == IROOT) {
+ inode->i_op = &usbdevfs_root_inode_operations;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ return;
+ }
+ if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
+ return;
+ spec = &special[inode->i_ino-(IROOT+1)];
+ inode->i_op = spec->iops;
+ return;
+
+ case IDEVICE:
+ return;
+
+ case IBUS:
+ return;
+
+ default:
+ return;
+ }
+}
+
+static void usbdevfs_put_inode(struct inode *inode)
+{
+}
+
+static void usbdevfs_put_super(struct super_block *sb)
+{
+ list_del(&sb->u.usbdevfs_sb.slist);
+ INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
+ while (!list_empty(&sb->u.usbdevfs_sb.ilist))
+ free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
+ MOD_DEC_USE_COUNT;
+}
+
+static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = USBDEVICE_SUPER_MAGIC;
+ tmp.f_bsize = PAGE_SIZE/sizeof(long); /* ??? */
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static struct super_operations usbdevfs_sops = {
+ usbdevfs_read_inode,
+ NULL,
+ usbdevfs_put_inode,
+ NULL,
+ NULL,
+ usbdevfs_put_super,
+ NULL,
+ usbdevfs_statfs,
+ NULL
+};
+
+struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+{
+ struct inode *root_inode, *inode;
+ struct list_head *blist;
+ struct usb_bus *bus;
+ unsigned int i;
+ uid_t devuid = 0, busuid = 0, listuid = 0;
+ gid_t devgid = 0, busgid = 0, listgid = 0;
+ umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
+ char *curopt = NULL, *value;
+
+ /* parse options */
+ if (data)
+ curopt = strtok(data, ",");
+ for (; curopt; curopt = strtok(NULL, ",")) {
+ if ((value = strchr(curopt, '=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(curopt, "devuid")) {
+ if (!value || !value[0])
+ goto opterr;
+ devuid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "devgid")) {
+ if (!value || !value[0])
+ goto opterr;
+ devgid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "devmode")) {
+ if (!value || !value[0])
+ goto opterr;
+ devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "busuid")) {
+ if (!value || !value[0])
+ goto opterr;
+ busuid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "busgid")) {
+ if (!value || !value[0])
+ goto opterr;
+ busgid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "busmode")) {
+ if (!value || !value[0])
+ goto opterr;
+ busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "listuid")) {
+ if (!value || !value[0])
+ goto opterr;
+ listuid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "listgid")) {
+ if (!value || !value[0])
+ goto opterr;
+ listgid = simple_strtoul(value, &value, 0);
+ if (*value)
+ goto opterr;
+ }
+ if (!strcmp(curopt, "listmode")) {
+ if (!value || !value[0])
+ goto opterr;
+ listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+ if (*value)
+ goto opterr;
+ }
+ }
+ /* fill superblock */
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = USBDEVICE_SUPER_MAGIC;
+ s->s_op = &usbdevfs_sops;
+ INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
+ INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
+ s->u.usbdevfs_sb.devuid = devuid;
+ s->u.usbdevfs_sb.devgid = devgid;
+ s->u.usbdevfs_sb.devmode = devmode;
+ s->u.usbdevfs_sb.busuid = busuid;
+ s->u.usbdevfs_sb.busgid = busgid;
+ s->u.usbdevfs_sb.busmode = busmode;
+ root_inode = iget(s, IROOT);
+ if (!root_inode)
+ goto out_no_root;
+ s->s_root = d_alloc_root(root_inode);
+ if (!s->s_root)
+ goto out_no_root;
+ list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
+ unlock_super(s);
+ for (i = 0; i < NRSPECIAL; i++) {
+ if (!(inode = iget(s, IROOT+1+i)))
+ continue;
+ inode->i_uid = listuid;
+ inode->i_gid = listgid;
+ inode->i_mode = listmode | S_IFREG;
+ list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
+ list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
+ }
+ lock_kernel();
+ for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
+ bus = list_entry(blist, struct usb_bus, bus_list);
+ new_bus_inode(bus, s);
+ recurse_new_dev_inode(bus->root_hub, s);
+ }
+ unlock_kernel();
+ return s;
+
+ out_no_root:
+ printk("usbdevfs_read_super: get root inode failed\n");
+ iput(root_inode);
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+
+ opterr:
+ printk(KERN_WARNING "usbdevfs: mount parameter error\n");
+ s->s_dev = 0;
+ return NULL;
+}
+
+static struct file_system_type usbdevice_fs_type = {
+ "usbdevfs",
+ 0,
+ usbdevfs_read_super,
+ NULL
+};
+
+/* --------------------------------------------------------------------- */
+
+void usbdevfs_add_bus(struct usb_bus *bus)
+{
+ struct list_head *slist;
+
+ lock_kernel();
+ for (slist = superlist.next; slist != &superlist; slist = slist->next)
+ new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+ unlock_kernel();
+ usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_bus(struct usb_bus *bus)
+{
+ lock_kernel();
+ while (!list_empty(&bus->inodes))
+ free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
+ unlock_kernel();
+ usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_add_device(struct usb_device *dev)
+{
+ struct list_head *slist;
+
+ lock_kernel();
+ for (slist = superlist.next; slist != &superlist; slist = slist->next)
+ new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+ unlock_kernel();
+ usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_device(struct usb_device *dev)
+{
+ struct dev_state *ds;
+ struct siginfo sinfo;
+
+ lock_kernel();
+ while (!list_empty(&dev->inodes))
+ free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+ while (!list_empty(&dev->filelist)) {
+ ds = list_entry(dev->filelist.next, struct dev_state, list);
+ list_del(&ds->list);
+ INIT_LIST_HEAD(&ds->list);
+ down_write(&ds->devsem);
+ ds->dev = NULL;
+ up_write(&ds->devsem);
+ if (ds->discsignr) {
+ sinfo.si_signo = SIGPIPE;
+ sinfo.si_errno = EPIPE;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = ds->disccontext;
+ send_sig_info(ds->discsignr, &sinfo, ds->disctask);
+ }
+ }
+ unlock_kernel();
+ usbdevfs_conn_disc_event();
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct proc_dir_entry *usbdir = NULL;
+
+int __init usbdevfs_init(void)
+{
+ int ret;
+
+ for (ret = 0; ret < NRSPECIAL; ret++) {
+ INIT_LIST_HEAD(&special[ret].inodes);
+ }
+ if ((ret = usb_register(&usbdevfs_driver)))
+ return ret;
+ if ((ret = register_filesystem(&usbdevice_fs_type)))
+ usb_deregister(&usbdevfs_driver);
+ /* create mount point for usbdevfs */
+ usbdir = proc_mkdir("usb", proc_bus);
+ return ret;
+}
+
+void __exit usbdevfs_cleanup(void)
+{
+ usb_deregister(&usbdevfs_driver);
+ unregister_filesystem(&usbdevice_fs_type);
+ if (usbdir)
+ remove_proc_entry("usb", proc_bus);
+}
+
+#if 0
+module_init(usbdevfs_init);
+module_exit(usbdevfs_cleanup);
+#endif
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 9c0ff47c8..9f1c94fc0 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -424,9 +424,13 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
joydev->minor = ffz(joydev_minors);
set_bit(joydev->minor, &joydev_minors);
joydev_base[joydev->minor] = joydev;
-
+
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
+ if (dev->absmax[j] == dev->absmin[j]) {
+ joydev->corr[i].type = JS_CORR_NONE;
+ continue;
+ }
joydev->corr[i].type = JS_CORR_BROKEN;
joydev->corr[i].prec = dev->absfuzz[j];
joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index f09f90845..34da92941 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -34,6 +34,7 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/kbd_kern.h>
#ifdef CONFIG_X86
@@ -43,11 +44,11 @@ static unsigned char keybdev_x86_e0s[] =
0x26, 0x25, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00,
0x23, 0x24, 0x25, 0x26, 0x27 };
-#elif CONFIG_MAC_KEYBOARD
+#elif CONFIG_ADB_KEYBOARD
static unsigned char keybdev_mac_codes[256] =
{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
- 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
+ 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
11, 45, 46, 43, 47, 44,123, 67, 55, 49, 57,122,120, 99,118, 96,
97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
@@ -57,6 +58,21 @@ static unsigned char keybdev_mac_codes[256] =
#endif
+struct input_handler keybdev_handler;
+
+void keybdev_ledfunc(unsigned int led)
+{
+ struct input_handle *handle;
+
+ for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
+
+ input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
+ input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02));
+ input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04));
+
+ }
+}
+
void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
{
if (type != EV_KEY || code > 255) return;
@@ -85,10 +101,10 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
}
} else handle_scancode(code, down);
-#elif CONFIG_MAC_KEYBOARD
+#elif CONFIG_ADB_KEYBOARD
- if (keycode < 128 && keybdev_mac_codes[code])
- handle_scancode(keybdev_mac_codes[code], down);
+ if (code < 128 && keybdev_mac_codes[code])
+ handle_scancode(keybdev_mac_codes[code] & 0x7f, down);
else
printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
@@ -96,6 +112,7 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
#error "Cannot generate rawmode keyboard for your architecture yet."
#endif
+ mark_bh(KEYBOARD_BH);
}
static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
@@ -137,6 +154,7 @@ struct input_handler keybdev_handler = {
#ifdef MODULE
void cleanup_module(void)
{
+ kbd_ledfunc = NULL;
input_unregister_handler(&keybdev_handler);
}
int init_module(void)
@@ -145,5 +163,6 @@ int __init keybdev_init(void)
#endif
{
input_register_handler(&keybdev_handler);
+ kbd_ledfunc = keybdev_ledfunc;
return 0;
}
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index b52609bf0..c10b76557 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -53,7 +53,7 @@ struct mousedev_list {
struct mousedev_list *next;
int dx, dy, dz;
unsigned char ps2[6];
- unsigned char buttons;
+ unsigned long buttons;
unsigned char ready, buffer, bufsiz;
unsigned char mode, genseq, impseq;
};
@@ -83,7 +83,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
switch (code) {
case REL_X: list->dx += value; break;
case REL_Y: list->dy -= value; break;
- case REL_WHEEL: if (list->mode) list->dz += value; break;
+ case REL_WHEEL: if (list->mode) list->dz -= value; break;
}
break;
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
index e95d66e96..30274cb85 100644
--- a/drivers/usb/ohci-hcd.c
+++ b/drivers/usb/ohci-hcd.c
@@ -47,6 +47,7 @@
#include <asm/system.h>
#undef DEBUG
+#define OHCI_USE_NPS
#include "usb.h"
#include "ohci-hcd.h"
@@ -154,8 +155,9 @@ void ep_print_int_eds (ohci_t * ohci, char * str) {
printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
ed_p = &(ohci->hcca.int_table [i]);
while (*ed_p != 0 && j--) {
- printk (" ed: %4x;", (((ed_t *) bus_to_virt (*ed_p))->hwINFO));
- ed_p = &(((ed_t *) bus_to_virt (*ed_p))->hwNextED);
+ ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
+ printk (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
}
printk ("\n");
}
@@ -174,7 +176,7 @@ static int sohci_return_urb (urb_t * urb)
{
urb_priv_t * urb_priv = urb->hcpriv;
urb_t * urbt;
- unsigned int flags;
+ unsigned long flags;
int i;
/* just to be sure */
@@ -245,7 +247,7 @@ static int sohci_submit_urb (urb_t * urb)
urb_priv_t * urb_priv;
unsigned int pipe = urb->pipe;
int i, size = 0;
- unsigned int flags;
+ unsigned long flags;
if (!urb->dev || !urb->dev->bus) return -EINVAL;
@@ -346,7 +348,7 @@ static int sohci_submit_urb (urb_t * urb)
static int sohci_unlink_urb (urb_t * urb)
{
- unsigned int flags;
+ unsigned long flags;
ohci_t * ohci;
DECLARE_WAITQUEUE (wait, current);
@@ -412,7 +414,7 @@ static int sohci_alloc_dev (struct usb_device *usb_dev)
static int sohci_free_dev (struct usb_device * usb_dev)
{
- unsigned int flags;
+ unsigned long flags;
int i, cnt = 0;
ed_t * ed;
DECLARE_WAITQUEUE (wait, current);
@@ -566,9 +568,9 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
for (i = 0; i < ep_rev (6, interval); i += inter) {
inter = 1;
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]);
- (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->int_interval >= interval);
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->hwNextED))
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->int_interval);
+ (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval);
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
+ inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
ed->hwNextED = *ed_p;
*ed_p = cpu_to_le32 (virt_to_bus (ed));
}
@@ -588,8 +590,8 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
inter = 1;
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]);
*ed_p != 0;
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->hwNextED))
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->int_interval);
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
+ inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
*ed_p = cpu_to_le32 (virt_to_bus (ed));
}
ed->ed_prev = NULL;
@@ -622,27 +624,27 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
switch (ed->type) {
case CTRL:
if (ed->ed_prev == NULL) {
- writel (le32_to_cpu (ed->hwNextED), &ohci->regs->ed_controlhead);
+ writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
}
if(ohci->ed_controltail == ed) {
ohci->ed_controltail = ed->ed_prev;
} else {
- ((ed_t *) bus_to_virt (le32_to_cpu (ed->hwNextED)))->ed_prev = ed->ed_prev;
+ ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
}
break;
case BULK:
if (ed->ed_prev == NULL) {
- writel (le32_to_cpu (ed->hwNextED), &ohci->regs->ed_bulkhead);
+ writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
}
if (ohci->ed_bulktail == ed) {
ohci->ed_bulktail = ed->ed_prev;
} else {
- ((ed_t *) bus_to_virt (le32_to_cpu (ed->hwNextED)))->ed_prev = ed->ed_prev;
+ ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
}
break;
@@ -653,9 +655,9 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
for (i = 0; i < ep_rev (6, interval); i += inter) {
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1;
(*ed_p != 0) && (*ed_p != ed->hwNextED);
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->hwNextED),
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->int_interval)) {
- if(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p))) == ed) {
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED),
+ inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {
+ if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
*ed_p = ed->hwNextED;
break;
}
@@ -670,7 +672,7 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
if (ohci->ed_isotail == ed)
ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
- ((ed_t *) bus_to_virt (le32_to_cpu (ed->hwNextED)))->ed_prev = ed->ed_prev;
+ ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
if (ed->ed_prev != NULL) {
ed->ed_prev->hwNextED = ed->hwNextED;
@@ -679,9 +681,9 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
inter = 1;
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]);
*ed_p != 0;
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->hwNextED)) {
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpu (*ed_p)))->int_interval);
- if(((ed_t *) bus_to_virt (le32_to_cpu (*ed_p))) == ed) {
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
+ inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+ if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
*ed_p = ed->hwNextED;
break;
}
@@ -800,7 +802,7 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int t
td_pt = urb_priv->td [index];
/* fill the old dummy TD */
- td = (td_t *) bus_to_virt (le32_to_cpu (urb_priv->ed->hwTailP) & 0xfffffff0);
+ td = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0);
td->ed = urb_priv->ed;
td->index = index;
td->urb = urb;
@@ -900,20 +902,20 @@ static td_t * dl_reverse_done_list (ohci_t * ohci)
td_t * td_rev = NULL;
td_t * td_list = NULL;
urb_priv_t * urb_priv = NULL;
- unsigned int flags;
+ unsigned long flags;
spin_lock_irqsave (&usb_ed_lock, flags);
- td_list_hc = le32_to_cpu (ohci->hcca.done_head) & 0xfffffff0;
+ td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
ohci->hcca.done_head = 0;
while (td_list_hc) {
td_list = (td_t *) bus_to_virt (td_list_hc);
- if (TD_CC_GET (le32_to_cpu (td_list->hwINFO))) {
+ if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
dbg(" USB-error/status: %x : %p",
- TD_CC_GET (le32_to_cpu (td_list->hwINFO)), td_list);
+ TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
td_list->ed->hwHeadP =
@@ -927,7 +929,7 @@ static td_t * dl_reverse_done_list (ohci_t * ohci)
td_list->next_dl_td = td_rev;
td_rev = td_list;
- td_list_hc = le32_to_cpu (td_list->hwNextTD) & 0xfffffff0;
+ td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
return td_list;
@@ -941,7 +943,7 @@ static td_t * dl_reverse_done_list (ohci_t * ohci)
static void dl_del_list (ohci_t * ohci, unsigned int frame)
{
- unsigned int flags;
+ unsigned long flags;
ed_t * ed;
__u32 edINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
@@ -951,16 +953,16 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
spin_lock_irqsave (&usb_ed_lock, flags);
for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
- tdTailP = bus_to_virt (le32_to_cpu (ed->hwTailP) & 0xfffffff0);
- tdHeadP = bus_to_virt (le32_to_cpu (ed->hwHeadP) & 0xfffffff0);
- edINFO = le32_to_cpu (ed->hwINFO);
+ tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+ tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+ edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP;
for (td = tdHeadP; td != tdTailP; td = td_next) {
urb_t * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv;
- td_next = bus_to_virt (le32_to_cpu (td->hwNextTD) & 0xfffffff0);
+ td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
if(++ (urb_priv->td_cnt) == urb_priv->length)
@@ -1013,16 +1015,16 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
urb_priv_t * urb_priv;
__u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
__u16 tdPSW;
- unsigned int flags;
+ unsigned long flags;
while (td_list) {
td_list_next = td_list->next_dl_td;
urb = td_list->urb;
urb_priv = urb->hcpriv;
- tdINFO = le32_to_cpu (td_list->hwINFO);
- tdBE = le32_to_cpu (td_list->hwBE);
- tdCBP = le32_to_cpu (td_list->hwCBP);
+ tdINFO = le32_to_cpup (&td_list->hwINFO);
+ tdBE = le32_to_cpup (&td_list->hwBE);
+ tdCBP = le32_to_cpup (&td_list->hwCBP);
ed = td_list->ed;
@@ -1071,8 +1073,8 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
spin_lock_irqsave (&usb_ed_lock, flags);
if (ed->state != ED_NEW) {
- edHeadP = le32_to_cpu (ed->hwHeadP) & 0xfffffff0;
- edTailP = le32_to_cpu (ed->hwTailP);
+ edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+ edTailP = le32_to_cpup (&ed->hwTailP);
if((edHeadP == edTailP) && (ed->state == ED_OPER))
ep_unlink (ohci, ed); /* unlink eds if they are not busy */
@@ -1185,9 +1187,9 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
ret = *(__u8 *) data;
for ( i = 0; i < num_ports; i++) {
- *(__u8 *) (data + i / 8) |=
+ *(__u8 *) (data + (i + 1) / 8) |=
((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
- ret += *(__u8 *) (data + i / 8);
+ ret += *(__u8 *) (data + (i + 1) / 8);
}
len = i/8 + 1;
@@ -1313,8 +1315,10 @@ static int rh_submit_urb (urb_t * urb)
case RH_CLEAR_FEATURE | RH_CLASS:
switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
case (RH_C_HUB_OVER_CURRENT):
- WR_RH_STAT(RH_PS_OCIC); OK (0);
+ WR_RH_STAT(RH_HS_OCIC); OK (0);
}
break;
@@ -1489,6 +1493,13 @@ static int hc_start (ohci_t * ohci)
writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
writel (mask, &ohci->regs->intrstatus);
+
+#ifdef OHCI_USE_NPS
+ writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+ &ohci->regs->roothub.a);
+ writel (0x10000, &ohci->regs->roothub.status);
+ mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
+#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
@@ -1516,7 +1527,7 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
struct ohci_regs * regs = ohci->regs;
int ints;
- if ((ohci->hcca.done_head != 0) && !(le32_to_cpu (ohci->hcca.done_head) & 0x01)) {
+ if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
} else {
if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
@@ -1578,7 +1589,7 @@ static ohci_t * hc_alloc_ohci (void * mem_base)
bus = usb_alloc_bus (&sohci_device_operations);
if (!bus) {
- free_pages ((unsigned int) ohci, 1);
+ free_pages ((unsigned long) ohci, 1);
return NULL;
}
@@ -1614,7 +1625,7 @@ static void hc_release_ohci (ohci_t * ohci)
/* unmap the IO address space */
iounmap (ohci->regs);
- free_pages ((unsigned int) ohci, 1);
+ free_pages ((unsigned long) ohci, 1);
}
/*-------------------------------------------------------------------------*/
@@ -1625,7 +1636,7 @@ static void hc_release_ohci (ohci_t * ohci)
static int hc_found_ohci (int irq, void * mem_base)
{
ohci_t * ohci;
- dbg("USB HC found: irq= %d membase= %x", irq, (int) mem_base);
+ dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
@@ -1655,15 +1666,15 @@ static int hc_found_ohci (int irq, void * mem_base)
static int hc_start_ohci (struct pci_dev * dev)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
- unsigned int mem_base = dev->resource[0].start;
+ unsigned long mem_base = dev->resource[0].start;
#else
- unsigned int mem_base = dev->base_address[0];
+ unsigned long mem_base = dev->base_address[0];
if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
#endif
pci_set_master (dev);
- mem_base = (unsigned int) ioremap_nocache (mem_base, 4096);
+ mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
if (!mem_base) {
err("Error mapping OHCI memory");
diff --git a/drivers/usb/ohci-hcd.h b/drivers/usb/ohci-hcd.h
index c9267f533..f3d71154f 100644
--- a/drivers/usb/ohci-hcd.h
+++ b/drivers/usb/ohci-hcd.h
@@ -314,6 +314,13 @@ struct virt_root_hub {
#define RH_PS_OCIC 0x00080000
#define RH_PS_PRSC 0x00100000
+/* Root hub status bits */
+#define RH_HS_LPS 0x00000001
+#define RH_HS_OCI 0x00000002
+#define RH_HS_DRWE 0x00008000
+#define RH_HS_LPSC 0x00010000
+#define RH_HS_OCIC 0x00020000
+#define RH_HS_CRWE 0x80000000
#define min(a,b) (((a)<(b))?(a):(b))
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index d0da393f3..c26f96132 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -11,8 +11,11 @@
* DEBUG - Debugging code.
* FIXME - Something that is broken or needs improvement.
*
- * Version History:
- * Version 1.00 - Initial version
+ * Version: 1.05
+ *
+ * Please see the file: linux/Documentation/usb/ov511.txt
+ * and the website at: http://people.delphi.com/mmcclelland/linux/
+ * for more info.
*/
/*
@@ -63,13 +66,15 @@
#define OV511_I2C_RETRIES 3
-/* Video Size 384 x 288 x 3 bytes for RGB */
-#define MAX_FRAME_SIZE (320 * 240 * 3)
+#define OV7610_AUTO_ADJUST 1
+
+/* Video Size 640 x 480 x 3 bytes for RGB */
+#define MAX_FRAME_SIZE (640 * 480 * 3)
// FIXME - Force CIF to make some apps happy for the moment. Should find a
// better way to do this.
-#define DEFAULT_WIDTH 320
-#define DEFAULT_HEIGHT 240
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
char kernel_version[] = UTS_RELEASE;
@@ -200,7 +205,9 @@ int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char val
USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, &value, 1, HZ);
- PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("reg write: 0x%02X:0x%02X", reg, value);
+#endif
return rc;
}
@@ -217,7 +224,9 @@ int ov511_reg_read(struct usb_device *dev, unsigned char reg)
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, buffer, 1, HZ);
- PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
+#if 0
+ PDEBUG("reg read: 0x%02X:0x%02X", reg, buffer[0]);
+#endif
if(rc < 0)
return rc;
@@ -229,7 +238,9 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
{
int rc, retries;
- PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("i2c write: 0x%02X:0x%02X", reg, value);
+#endif
/* Three byte write cycle */
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
@@ -309,7 +320,9 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
}
value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
- PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("i2c read: 0x%02X:0x%02X", reg, value);
+#endif
/* This is needed to make ov511_i2c_write() work */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
@@ -318,27 +331,94 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
return (value);
}
+#if 0
+static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
+{
+ int i;
+ int rc;
+ for(i=reg1; i<=regn; i++) {
+ rc = ov511_i2c_read(dev, i);
+#if 0
+ PDEBUG("OV7610[0x%X] = 0x%X", i, rc);
+#endif
+ }
+}
+
+static void ov511_dump_i2c_regs( struct usb_device *dev)
+{
+ PDEBUG("I2C REGS");
+ ov511_dump_i2c_range(dev, 0x00, 0x38);
+}
+
+static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
+{
+ int i;
+ int rc;
+ for(i=reg1; i<=regn; i++) {
+ rc = ov511_reg_read(dev, i);
+ PDEBUG("OV511[0x%X] = 0x%X", i, rc);
+ }
+}
+
+static void ov511_dump_regs( struct usb_device *dev)
+{
+ PDEBUG("CAMERA INTERFACE REGS");
+ ov511_dump_reg_range(dev, 0x10, 0x1f);
+ PDEBUG("DRAM INTERFACE REGS");
+ ov511_dump_reg_range(dev, 0x20, 0x23);
+ PDEBUG("ISO FIFO REGS");
+ ov511_dump_reg_range(dev, 0x30, 0x31);
+ PDEBUG("PIO REGS");
+ ov511_dump_reg_range(dev, 0x38, 0x39);
+ ov511_dump_reg_range(dev, 0x3e, 0x3e);
+ PDEBUG("I2C REGS");
+ ov511_dump_reg_range(dev, 0x40, 0x49);
+ PDEBUG("SYSTEM CONTROL REGS");
+ ov511_dump_reg_range(dev, 0x50, 0x53);
+ ov511_dump_reg_range(dev, 0x5e, 0x5f);
+ PDEBUG("OmniCE REGS");
+ ov511_dump_reg_range(dev, 0x70, 0x79);
+ ov511_dump_reg_range(dev, 0x80, 0x9f);
+ ov511_dump_reg_range(dev, 0xa0, 0xbf);
+
+}
+#endif
+
+int ov511_i2c_reset(struct usb_device *dev)
+{
+ int rc;
+
+ PDEBUG("Reset 7610");
+ rc = ov511_i2c_write(dev, 0x12, 0x80);
+ if (rc < 0)
+ err("i2c reset: command failed");
+
+ return rc;
+}
+
int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
- PDEBUG("Reset: type=0x%X\n", reset_type);
+ PDEBUG("Reset: type=0x%X", reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
if (rc < 0)
- printk(KERN_ERR "ov511: reset: command failed\n");
+ err("reset: command failed");
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
if (rc < 0)
- printk(KERN_ERR "ov511: reset: command failed\n");
+ err("reset: command failed");
return rc;
}
int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
{
- int alt, multiplier, err;
+ int alt, multiplier, rc;
- PDEBUG("set packet size: %d\n", size);
+#if 0
+ PDEBUG("set packet size: %d", size);
+#endif
switch (size) {
case 992:
@@ -374,21 +454,19 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
multiplier = 1; // FIXME - is this correct?
break;
default:
- printk(KERN_ERR "ov511_set_packet_size: invalid size (%d)\n",
- size);
+ err("Set packet size: invalid size (%d)", size);
return -EINVAL;
}
- err = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
- multiplier);
- if (err < 0) {
- printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n",
- err);
+ rc = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+ multiplier);
+ if (rc < 0) {
+ err("Set packet size: Set FIFO size ret %d", rc);
return -ENOMEM;
}
if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
- printk(KERN_ERR "ov511: Set packet size: set interface error\n");
+ err("Set packet size: set interface error");
return -EBUSY;
}
@@ -399,8 +477,258 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
return 0;
}
-/* How much data is left in the scratch buf? */
-#define scratch_left(x) (ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch))
+static inline int ov7610_set_picture(struct usb_ov511 *ov511,
+ struct video_picture *p)
+{
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static inline int ov7610_get_picture(struct usb_ov511 *ov511,
+ struct video_picture *p)
+{
+ int ret;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO;
+ p->colour = ret << 8;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_CNT)) < 0) return -EIO;
+ p->contrast = ret << 8;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_BRT)) < 0) return -EIO;
+ p->brightness = ret << 8;
+
+ p->hue = 0x8000;
+ p->whiteness = 105 << 8;
+ p->depth = 24;
+ p->palette = VIDEO_PALETTE_RGB24;
+
+ return 0;
+}
+
+static int ov511_mode_init_regs(struct usb_ov511 *ov511,
+ int width, int height, int mode)
+{
+ int rc = 0;
+ struct usb_device *dev = ov511->dev;
+
+#if 0
+ PDEBUG("ov511_mode_init_regs(ov511, %d, %d, %d)", width, height, mode);
+#endif
+ ov511_set_packet_size(ov511, 0);
+
+ /* Set mode consistent registers */
+ ov511_i2c_write(dev, 0x0f, 0x03);
+ ov511_i2c_write(dev, 0x10, 0xff);
+ ov511_i2c_write(dev, 0x13, 0x01);
+ ov511_i2c_write(dev, 0x16, 0x06);
+ ov511_i2c_write(dev, 0x20, 0x1c);
+ ov511_i2c_write(dev, 0x24, 0x2e); /* 10 */
+ ov511_i2c_write(dev, 0x25, 0x7c); /* 8a */
+ ov511_i2c_write(dev, 0x26, 0x70);
+ ov511_i2c_write(dev, 0x28, 0x24); /* 24 */
+ ov511_i2c_write(dev, 0x2b, 0xac);
+ ov511_i2c_write(dev, 0x2c, 0xfe);
+ ov511_i2c_write(dev, 0x2d, 0x93);
+ ov511_i2c_write(dev, 0x34, 0x8b);
+
+ if (width == 640 && height == 480) {
+ ov511_reg_write(dev, 0x12, 0x4f);
+ ov511_reg_write(dev, 0x13, 0x3d);
+ ov511_reg_write(dev, 0x14, 0x00);
+ ov511_reg_write(dev, 0x15, 0x00);
+ ov511_reg_write(dev, 0x18, 0x03);
+
+ ov511_i2c_write(dev, 0x11, 0x01);
+ ov511_i2c_write(dev, 0x12, 0x24);
+ ov511_i2c_write(dev, 0x14, 0x04);
+ ov511_i2c_write(dev, 0x35, 0x9e);
+ } else if (width == 320 && height == 240) {
+ ov511_reg_write(dev, 0x12, 0x27);
+ ov511_reg_write(dev, 0x13, 0x1f);
+ ov511_reg_write(dev, 0x14, 0x00);
+ ov511_reg_write(dev, 0x15, 0x00);
+ ov511_reg_write(dev, 0x18, 0x03);
+
+ ov511_i2c_write(dev, 0x11, 0x00);
+ ov511_i2c_write(dev, 0x12, 0x04);
+ ov511_i2c_write(dev, 0x14, 0x24);
+ ov511_i2c_write(dev, 0x35, 0x1e);
+ } else {
+ err("Unknown mode (%d, %d): %d", width, height, mode);
+ rc = -EINVAL;
+ }
+ ov511_set_packet_size(ov511, 993);
+
+ return rc;
+}
+
+
+/*************************************************************
+
+Turn a YUV4:2:0 block into an RGB block
+
+*************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+static inline void ov511_move_420_block(int y00, int y01, int y10, int y11,
+ int u, int v, int w,
+ unsigned char * pOut)
+{
+ int r = 68911 * v;
+ int g = -16915 * u + -35101 * v;
+ int b = 87097 * u;
+ y00 *= 49152;
+ y01 *= 49152;
+ y10 *= 49152;
+ y11 *= 49152;
+ *(pOut+w*3) = LIMIT(r + y10);
+ *pOut++ = LIMIT(r + y00);
+ *(pOut+w*3) = LIMIT(g + y10);
+ *pOut++ = LIMIT(g + y00);
+ *(pOut+w*3) = LIMIT(b + y10);
+ *pOut++ = LIMIT(b + y00);
+ *(pOut+w*3) = LIMIT(r + y11);
+ *pOut++ = LIMIT(r + y01);
+ *(pOut+w*3) = LIMIT(g + y11);
+ *pOut++ = LIMIT(g + y01);
+ *(pOut+w*3) = LIMIT(b + y11);
+ *pOut++ = LIMIT(b + y01);
+}
+
+/***************************************************************
+
+For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. The
+first 64 bytes of each segment are V, the next 64 are U. The V and
+U are arranged as follows:
+
+ 0 1 ... 7
+ 8 9 ... 15
+ ...
+ 56 57 ... 63
+
+The next 256 bytes are Y data and represent 4 squares of 8x8 pixels as
+follows:
+
+ 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
+ 8 9 ... 15 72 73 ... 79 200 201 ... 207
+ ... ... ...
+ 56 57 ... 63 120 121 127 248 249 ... 255
+
+If OV511_DUMPPIX is defined, _parse_data just dumps the
+incoming segments, verbatim, in order, into the frame.
+When used with vidcat -f ppm -s 640x480 this puts the data
+on the standard output and can be analyzed with the parseppm.c
+utility I wrote. That's a much faster way for figuring out how
+this data is scrambled.
+
+****************************************************************/
+#define HDIV 8
+#define WDIV (256/HDIV)
+
+static void ov511_parse_data(unsigned char * pIn0,
+ unsigned char * pOut0,
+ int iWidth,
+ int iSegment)
+
+{
+#ifndef OV511_DUMPPIX
+ int k, l, m;
+ unsigned char * pIn;
+ unsigned char * pOut, * pOut1;
+
+ int iHalf = (iSegment / (iWidth / 32)) & 1;
+ int iY = iSegment / (iWidth / WDIV);
+ int jY = iSegment - iY * (iWidth / WDIV);
+ int iOutY = (iY*HDIV*iWidth + jY*WDIV) * 3;
+ int iUV = iSegment / (iWidth / WDIV * 2);
+ int jUV = iSegment - iUV * (iWidth / WDIV * 2);
+ int iOutUV = (iUV*HDIV*2*iWidth + jUV*WDIV/2) * 3;
+
+ /* Just copy the Y's if in the first stripe */
+ if (!iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for(k=0; k<4; k++) {
+ pOut1 = pOut;
+ for(l=0; l<8; l++) {
+ for(m=0; m<8; m++) {
+ *pOut1 = *pIn++;
+ pOut1 += 3;
+ }
+ pOut1 += (iWidth - 8) * 3;
+ }
+ pOut += 8 * 3;
+ }
+ }
+
+ /* Use the first half of VUs to calculate value */
+ pIn = pIn0;
+ pOut = pOut0 + iOutUV;
+ for(l=0; l<4; l++) {
+ for(m=0; m<8; m++) {
+ int y00 = *(pOut);
+ int y01 = *(pOut+3);
+ int y10 = *(pOut+iWidth*3);
+ int y11 = *(pOut+iWidth*3+3);
+ int u = *(pIn+64) - 128;
+ int v = *pIn++ - 128;
+ ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut);
+ pOut += 6;
+ }
+ pOut += (iWidth*2 - 16) * 3;
+ }
+
+ /* Just copy the other UV rows */
+ for(l=0; l<4; l++) {
+ for(m=0; m<8; m++) {
+ *pOut++ = *(pIn + 64);
+ *pOut = *pIn++;
+ pOut += 5;
+ }
+ pOut += (iWidth*2 - 16) * 3;
+ }
+
+ /* Calculate values if it's the second half */
+ if (iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for(k=0; k<4; k++) {
+ pOut1 = pOut;
+ for(l=0; l<4; l++) {
+ for(m=0; m<4; m++) {
+ int y10 = *(pIn+8);
+ int y00 = *pIn++;
+ int y11 = *(pIn+8);
+ int y01 = *pIn++;
+ int u = *pOut1 - 128;
+ int v = *(pOut1+1) - 128;
+ ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1);
+ pOut1 += 6;
+ }
+ pOut1 += (iWidth*2 - 8) * 3;
+ pIn += 8;
+ }
+ pOut += 8 * 3;
+ }
+ }
+
+#else
+ /* Just dump pix data straight out for debug */
+ int i;
+ pOut0 += iSegment * 384;
+ for(i=0; i<384; i++) {
+ *pOut0++ = *pIn0++;
+ }
+#endif
+}
static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
{
@@ -421,13 +749,10 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
if (!n) continue;
- aPackNum[i] = n ? cdata[512] : -1;
+ aPackNum[i] = n ? cdata[992] : -1;
- if (st){
- // Macro - must be in braces!
- PDEBUG("data error: [%d] len=%d, status=%d\n",
- i, n, st);
- }
+ if (st)
+ PDEBUG("data error: [%d] len=%d, status=%d", i, n, st);
frame = &ov511->frame[ov511->curframe];
@@ -436,13 +761,18 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
(cdata[8] & 8) && (cdata[8] & 0x80)) {
- PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[512]));
- PDEBUG("Current frame = %d\n", ov511->curframe);
+#if 0
+ PDEBUG("Found Frame End!, packnum = %d", (int)(cdata[992]));
+ PDEBUG("Current frame = %d", ov511->curframe);
+#endif
if (frame->scanstate == STATE_LINES) {
if (waitqueue_active(&frame->wq)) {
- PDEBUG("About to wake up waiting processes\n");
+#if 0
+ PDEBUG("About to wake up waiting processes");
+#endif
frame->grabstate = FRAME_DONE;
+ ov511->curframe = -1;
wake_up_interruptible(&frame->wq);
}
}
@@ -452,35 +782,52 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
(cdata[8] & 8)) {
- PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[512]));
+#if 0
+ PDEBUG("ov511: Found Frame Start!, packnum = %d", (int)(cdata[992]));
+ PDEBUG("ov511: Frame Header Byte = 0x%x", (int)(cdata[8]));
+#endif
frame->scanstate = STATE_LINES;
- frame->curpix = 0;
+ frame->segment = 0;
}
/* Are we in a frame? */
- else if (frame->scanstate == STATE_LINES) {
- unsigned char *f = frame->data + 3 * frame->curpix;
- int i;
- if (frame->curpix <= 320 * 240 - 256) {
- for (i=0; i<256; i++) {
- *f++ = *cdata;
- *f++ = *cdata;
- *f++ = *cdata++;
- *f++ = *cdata;
- *f++ = *cdata;
- *f++ = *cdata++;
- }
- frame->curpix += 512;
+ if (frame->scanstate == STATE_LINES) {
+ unsigned char * pData;
+ int iPix;
+
+ /* Deal with leftover from last segment, if any */
+ if (frame->segment) {
+ pData = ov511->scratch;
+ iPix = - ov511->scratchlen;
+ memmove(pData + ov511->scratchlen, cdata, iPix+384);
} else {
- PDEBUG("Too many pixels!\n");
+ pData = &cdata[iPix = 9];
}
+
+ /* Parse the segments */
+ while(iPix <= 992 - 384 &&
+ frame->segment < frame->width * frame->height / 256) {
+ ov511_parse_data(pData, frame->data,
+ frame->width,
+ frame->segment);
+ frame->segment++;
+ iPix += 384;
+ pData = &cdata[iPix];
}
+ /* Save extra data for next time */
+ if (frame->segment < frame->width * frame->height / 256) {
+ memmove(ov511->scratch, pData, 992 - iPix);
+ ov511->scratchlen = 992 - iPix;
+ }
+ }
}
+#if 0
PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n",
aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+#endif
return totlen;
}
@@ -491,18 +838,6 @@ static void ov511_isoc_irq(struct urb *urb)
struct ov511_sbuf *sbuf;
int i;
-#if 0
- static int last_status, last_error_count, last_actual_length;
- if (last_status != urb->status ||
- last_error_count != urb->error_count ||
- last_actual_length != urb->actual_length) {
- PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
- last_status = urb->status;
- last_error_count = urb->error_count;
- last_actual_length = urb->actual_length;
- }
-#endif
-
if (!ov511->streaming) {
PDEBUG("hmmm... not streaming, but got interrupt\n");
return;
@@ -511,17 +846,10 @@ static void ov511_isoc_irq(struct urb *urb)
sbuf = &ov511->sbuf[ov511->cursbuf];
/* Copy the data received into our scratch buffer */
- len = ov511_move_data(ov511, urb);
-#if 0
- /* If we don't have a frame we're current working on, complain */
- if (ov511->scratchlen) {
- if (ov511->curframe < 0) {
- // Macro - must be in braces!!
- PDEBUG("received data, but no frame available\n");
- } else
- ov511_parse_data(ov511);
+ if (ov511->curframe >= 0) {
+ len = ov511_move_data(ov511, urb);
}
-#endif
+
for (i = 0; i < FRAMES_PER_DESC; i++) {
sbuf->urb->iso_frame_desc[i].status = 0;
sbuf->urb->iso_frame_desc[i].actual_length = 0;
@@ -544,30 +872,13 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- ov511_set_packet_size(ov511, 512);
-
-#define OV511_COLOR_BAR_TEST
-#ifdef OV511_COLOR_BAR_TEST
- {
- int rc;
- rc = ov511_i2c_read(ov511->dev, 0x12);
- rc = ov511_i2c_write(ov511->dev, 0x12, 0x3f);
- rc = ov511_i2c_read(ov511->dev, 0x12);
- rc = ov511_i2c_read(ov511->dev, 0x13);
- rc = ov511_i2c_write(ov511->dev, 0x14, 0x4);
- rc = ov511_i2c_read(ov511->dev, 0x14);
- rc = ov511_i2c_write(ov511->dev, 0x28, 0x60);
- rc = ov511_i2c_read(ov511->dev, 0x28);
- ov511_reg_write(ov511->dev, OV511_REG_CAMERA_DATA_INPUT_SELECT,
- 0);
- }
-#endif
+ ov511_set_packet_size(ov511, 993);
/* We double buffer the Iso lists */
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
- printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n");
+ err("ov511_init_isoc: usb_alloc_urb ret. NULL");
return -ENOMEM;
}
ov511->sbuf[0].urb = urb;
@@ -586,7 +897,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
- printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n");
+ err("ov511_init_isoc: usb_alloc_urb ret. NULL");
return -ENOMEM;
}
ov511->sbuf[1].urb = urb;
@@ -608,12 +919,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
err = usb_submit_urb(ov511->sbuf[0].urb);
if (err)
- printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(0) ret %d\n",
- err);
+ err("ov511_init_isoc: usb_run_isoc(0) ret %d", err);
err = usb_submit_urb(ov511->sbuf[1].urb);
if (err)
- printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n",
- err);
+ err("ov511_init_isoc: usb_run_isoc(1) ret %d\n", err);
ov511->streaming = 1;
@@ -685,7 +994,7 @@ static int ov511_open(struct video_device *dev, int flags)
int err = -EBUSY;
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_open\n");
+ PDEBUG("ov511_open");
down(&ov511->lock);
if (ov511->user)
@@ -704,8 +1013,8 @@ static int ov511_open(struct video_device *dev, int flags)
ov511->frame[0].data = ov511->fbuf;
ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE;
- PDEBUG("frame [0] @ %p\n", ov511->frame[0].data);
- PDEBUG("frame [1] @ %p\n", ov511->frame[1].data);
+ PDEBUG("frame [0] @ %p", ov511->frame[0].data);
+ PDEBUG("frame [1] @ %p", ov511->frame[1].data);
ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[0].data)
@@ -714,17 +1023,8 @@ static int ov511_open(struct video_device *dev, int flags)
if (!ov511->sbuf[1].data)
goto open_err_on1;
- PDEBUG("sbuf[0] @ %p\n", ov511->sbuf[0].data);
- PDEBUG("sbuf[1] @ %p\n", ov511->sbuf[1].data);
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- ov511->frame[0].width = DEFAULT_WIDTH;
- ov511->frame[0].height = DEFAULT_HEIGHT;
- ov511->frame[0].bytes_read = 0;
- ov511->frame[1].width = DEFAULT_WIDTH;
- ov511->frame[1].height = DEFAULT_HEIGHT;
- ov511->frame[1].bytes_read = 0;
+ PDEBUG("sbuf[0] @ %p", ov511->sbuf[0].data);
+ PDEBUG("sbuf[1] @ %p", ov511->sbuf[1].data);
err = ov511_init_isoc(ov511);
if (err)
@@ -755,7 +1055,7 @@ static void ov511_close(struct video_device *dev)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_close\n");
+ PDEBUG("ov511_close");
down(&ov511->lock);
ov511->user--;
@@ -783,12 +1083,12 @@ static long ov511_write(struct video_device *dev, const char *buf, unsigned long
}
// FIXME - Needs much work!!!
-static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
- struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
-
- PDEBUG("IOCtl: 0x%X\n", cmd);
-
+ struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
+#if 0
+ PDEBUG("IOCtl: 0x%X", cmd);
+#endif
switch (cmd) {
case VIDIOCGCAP:
{
@@ -844,14 +1144,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_picture p;
- p.colour = 0x8000; /* Damn British people :) */
- p.hue = 0x8000;
- p.brightness = 180 << 8; /* XXX */
- p.contrast = 192 << 8; /* XXX */
- p.whiteness = 105 << 8; /* XXX */
- p.depth = 24;
- p.palette = VIDEO_PALETTE_RGB24;
-
+ if (ov7610_get_picture(ov511, &p))
+ return -EIO;
+
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
@@ -863,6 +1158,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
+
+ if (ov7610_set_picture(ov511, &p))
+ return -EIO;
return 0;
}
@@ -923,9 +1221,11 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
- PDEBUG("MCAPTURE\n");
- PDEBUG("frame: %d, size: %dx%d, format: %d\n",
+#if 0
+ PDEBUG("MCAPTURE");
+ PDEBUG("frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
+#endif
if (vm.format != VIDEO_PALETTE_RGB24)
return -EINVAL;
@@ -938,8 +1238,15 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
/* Don't compress if the size changed */
if ((ov511->frame[vm.frame].width != vm.width) ||
- (ov511->frame[vm.frame].height != vm.height))
+ (ov511->frame[vm.frame].height != vm.height)) {
ov511->compress = 0;
+ ov511_mode_init_regs(ov511,
+ vm.width, vm.height, 0);
+#if 0
+ PDEBUG("ov511: Setting frame %d to (%d, %d) : %d",
+ vm.frame, vm.width, vm.height, 0);
+#endif
+ }
ov511->frame[vm.frame].width = vm.width;
ov511->frame[vm.frame].height = vm.height;
@@ -956,8 +1263,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
- PDEBUG("syncing to frame %d\n", frame);
-
+#if 0
+ PDEBUG("syncing to frame %d", frame);
+#endif
switch (ov511->frame[frame].grabstate) {
case FRAME_UNUSED:
return -EINVAL;
@@ -1029,7 +1337,7 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
int frmx = -1;
volatile struct ov511_frame *frame;
- PDEBUG("ov511_read: %ld bytes, noblock=%d\n", count, noblock);
+ PDEBUG("ov511_read: %ld bytes, noblock=%d", count, noblock);
if (!dev || !buf)
return -EFAULT;
@@ -1060,20 +1368,20 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
restart:
while (frame->grabstate == FRAME_GRABBING) {
- interruptible_sleep_on(&frame->wq);
+ interruptible_sleep_on(&ov511->frame[frmx].wq);
if (signal_pending(current))
return -EINTR;
}
if (frame->grabstate == FRAME_ERROR) {
frame->bytes_read = 0;
- printk(KERN_ERR "ov511_read: errored frame %d\n", ov511->curframe);
+ err("ov511_read: errored frame %d", ov511->curframe);
if (ov511_new_frame(ov511, frmx))
- printk(KERN_ERR "ov511_read: ov511_new_frame error\n");
+ err("ov511_read: ov511_new_frame error");
goto restart;
}
- PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", frmx,
+ PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
@@ -1084,7 +1392,7 @@ restart:
return -EFAULT;
frame->bytes_read += count;
- PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld\n",
+ PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld",
count, frame->bytes_read);
if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
@@ -1093,7 +1401,7 @@ restart:
/* Mark it as available to be used again. */
ov511->frame[frmx].grabstate = FRAME_UNUSED;
if (ov511_new_frame(ov511, frmx ? 0 : 1))
- printk(KERN_ERR "ov511_read: ov511_new_frame returned error\n");
+ err("ov511_read: ov511_new_frame returned error");
}
return count;
@@ -1105,7 +1413,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long s
unsigned long start = (unsigned long)adr;
unsigned long page, pos;
- PDEBUG("mmap: %ld (%lX) bytes\n", size, size);
+ PDEBUG("mmap: %ld (%lX) bytes", size, size);
if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
return -EINVAL;
@@ -1145,14 +1453,52 @@ static struct video_device ov511_template = {
0
};
+static int ov7610_configure(struct usb_device *dev)
+{
+ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+ OV7610_I2C_WRITE_ID) < 0)
+ return -1;
+
+ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+ OV7610_I2C_READ_ID) < 0)
+ return -1;
+
+ /* Reset the camera chip */
+ if (ov511_i2c_reset(dev) < 0)
+ return -1;
+
+#if 0
+ if(usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
+ OV511_I2C_CLOCK_PRESCALER))
+ return -1;
+#endif
+
+ if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+ return -1;
+
+ /* Dummy read to sync I2C */
+ if(ov511_i2c_read(dev, 0x00) < 0)
+ return -1;
+
+
+ if((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) != 0x7F) ||
+ (ov511_i2c_read(dev, OV7610_REG_ID_LOW) != 0xA2)) {
+ err("Failed to read OV7610 ID. You might not have an OV7610,");
+ err("or it may be not responding. Report this to");
+ err("mmcclelland@delphi.com");
+ return -1;
+ }
+
+ return 0;
+}
+
static int ov511_configure(struct usb_ov511 *ov511)
{
struct usb_device *dev = ov511->dev;
- int temprc; // DEBUG CODE
/* Set altsetting 0 */
if (usb_set_interface(dev, ov511->iface, 0) < 0) {
- printk(KERN_ERR "ov511: usb_set_interface error\n");
+ err("usb_set_interface error");
return -EBUSY;
}
@@ -1162,7 +1508,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
init_waitqueue_head(&ov511->frame[1].wq);
if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
- printk(KERN_ERR "ov511: video_register_device failed\n");
+ err("video_register_device failed");
return -EBUSY;
}
@@ -1172,7 +1518,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
/* Initialize system */
if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
- printk(KERN_ERR "ov511: enable system: command failed\n");
+ err("enable system: command failed");
goto error;
}
@@ -1180,36 +1526,31 @@ static int ov511_configure(struct usb_ov511 *ov511)
if (ov511_reset(dev, OV511_RESET_ALL) < 0)
goto error;
+ if(ov7610_configure(dev) < 0) {
+ err("failed to configure OV7610");
+ goto error;
+ }
+
/* Disable compression */
if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
- printk(KERN_ERR "ov511: disable compression: command failed\n");
+ err("disable compression: command failed");
goto error;
}
-// FIXME - error checking needed
- ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
- OV7610_I2C_WRITE_ID);
- ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
- OV7610_I2C_READ_ID);
-
-// DEBUG CODE
-// usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
-// OV511_I2C_CLOCK_PRESCALER);
-
- if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
- goto error;
-
- /* Dummy read to sync I2C */
- ov511_i2c_read(dev, 0x1C);
-
-// DEBUG - TEST CODE FOR CAMERA REG READ
- temprc = ov511_i2c_read(dev, 0x1C);
-
- temprc = ov511_i2c_read(dev, 0x1D);
-// END DEBUG CODE
-
ov511->compress = 0;
+ /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+ * (using read() instead). */
+ ov511->frame[0].width = DEFAULT_WIDTH;
+ ov511->frame[0].height = DEFAULT_HEIGHT;
+ ov511->frame[0].bytes_read = 0;
+ ov511->frame[1].width = DEFAULT_WIDTH;
+ ov511->frame[1].height = DEFAULT_HEIGHT;
+ ov511->frame[1].bytes_read = 0;
+
+ /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
+ ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0);
+
return 0;
error:
@@ -1228,7 +1569,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_ov511 *ov511;
int rc;
- PDEBUG("probing for device...\n");
+ PDEBUG("probing for device...");
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
@@ -1252,7 +1593,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
printk(KERN_INFO "ov511: USB OV511-based camera found\n");
if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ov511: couldn't kmalloc ov511 struct\n");
+ err("couldn't kmalloc ov511 struct");
return NULL;
}
@@ -1263,18 +1604,30 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
if (rc < 0) {
- printk("ov511: Unable to read camera bridge registers\n");
+ err("Unable to read camera bridge registers");
return NULL;
- } else if (rc == 3) { /* D-Link DSB-C300 */
+ }
+
+ switch(ov511->customid = rc) {
+ case 0: /* This also means that no custom ID was set */
+ printk("ov511: Camera is probably a MediaForte MV300\n");
+ break;
+ case 3:
printk("ov511: Camera is a D-Link DSB-C300\n");
- ov511->customid = 3;
- } else if (rc == 21) { /* Creative Labs WebCam 3 */
+ break;
+ case 21:
printk("ov511: Camera is a Creative Labs WebCam 3\n");
- ov511->customid = 21;
- } else {
- printk("ov511: Specific camera type (%d) not recognized\n", rc);
- printk("ov511: Please contact mmcclelland@delphi.com to request\n");
- printk("ov511: support for your camera.\n");
+ break;
+ case 100:
+ printk("ov511: Camera is a Lifeview RoboCam\n");
+ break;
+ case 102:
+ printk("ov511: Camera is a AverMedia InterCam Elite\n");
+ break;
+ default:
+ err("Specific camera type (%d) not recognized", rc);
+ err("Please contact mmcclelland@delphi.com to request");
+ err("support for your camera.");
return NULL;
}
@@ -1284,7 +1637,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
return ov511;
}
else {
- printk(KERN_ERR "ov511: Failed to configure camera\n");
+ err("Failed to configure camera");
return NULL;
}
@@ -1314,7 +1667,7 @@ static struct usb_driver ov511_driver = {
int usb_ov511_init(void)
{
- PDEBUG("usb_ov511_init()\n");
+ PDEBUG("usb_ov511_init()");
EXPORT_NO_SYMBOLS;
@@ -1336,7 +1689,7 @@ void cleanup_module(void)
{
usb_ov511_cleanup();
- PDEBUG("Module unloaded\n");
+ PDEBUG("Module unloaded");
}
#endif
diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h
index 4dc7074bb..3f41e382d 100644
--- a/drivers/usb/ov511.h
+++ b/drivers/usb/ov511.h
@@ -6,9 +6,9 @@
#define OV511_DEBUG /* Turn on debug messages */
#ifdef OV511_DEBUG
-# define PDEBUG(fmt, args...) printk("ov511: " fmt, ## args)
+# define PDEBUG(fmt, args...) printk("ov511: " fmt "\n" , ## args)
#else
-# define PDEBUG(fmt, args...) /* Nothing */
+# define PDEBUG(fmt, args...) do {} while(0)
#endif
/* Camera interface register numbers */
@@ -103,13 +103,57 @@
#define OV511_ALTERNATE_SIZE_257 6
#define OV511_ALTERNATE_SIZE_0 7
+/* ov7610 registers */
+#define OV7610_REG_GAIN 0x00
+#define OV7610_REG_BLUE 0x01
+#define OV7610_REG_RED 0x02
+#define OV7610_REG_SAT 0x03
+#define OV7610_REG_CNT 0x05
+#define OV7610_REG_BRT 0x06
+#define OV7610_REG_BLUE_BIAS 0x0C
+#define OV7610_REG_RED_BIAS 0x0D
+#define OV7610_REG_GAMMA_COEFF 0x0E
+#define OV7610_REG_WB_RANGE 0x0F
+#define OV7610_REG_EXP 0x10
+#define OV7610_REG_CLOCK 0x11
+#define OV7610_REG_COM_A 0x12
+#define OV7610_REG_COM_B 0x13
+#define OV7610_REG_COM_C 0x14
+#define OV7610_REG_COM_D 0x15
+#define OV7610_REG_FIELD_DIVIDE 0x16
+#define OV7610_REG_HWIN_START 0x17
+#define OV7610_REG_HWIN_END 0x18
+#define OV7610_REG_VWIN_START 0x19
+#define OV7610_REG_VWIN_END 0x1A
+#define OV7610_REG_PIXEL_SHIFT 0x1B
+#define OV7610_REG_ID_HIGH 0x1C
+#define OV7610_REG_ID_LOW 0x1D
+#define OV7610_REG_COM_E 0x20
+#define OV7610_REG_YOFFSET 0x21
+#define OV7610_REG_UOFFSET 0x22
+#define OV7610_REG_ECW 0x24
+#define OV7610_REG_ECB 0x25
+#define OV7610_REG_COM_F 0x26
+#define OV7610_REG_COM_G 0x27
+#define OV7610_REG_COM_H 0x28
+#define OV7610_REG_COM_I 0x29
+#define OV7610_REG_FRAMERATE_H 0x2A
+#define OV7610_REG_FRAMERATE_L 0x2B
+#define OV7610_REG_ALC 0x2C
+#define OV7610_REG_COM_J 0x2D
+#define OV7610_REG_VOFFSET 0x2E
+#define OV7610_REG_YGAMMA 0x33
+#define OV7610_REG_BIAS_ADJUST 0x34
+#define OV7610_REG_COM_L 0x35
+#define OV7610_REG_COM_K 0x38
+
#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+#define SCRATCH_BUF_SIZE 384
#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC 512 /* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC 993 /* FIXME - Shouldn't be hardcoded */
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -166,6 +210,7 @@ struct ov511_frame {
int curline; /* Line of frame we're working on */
int curpix;
+ int segment; /* Segment from the incoming data */
long scanlength; /* uncompressed, raw data length of frame */
long bytes_read; /* amount of scanlength that has been read from *data */
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 6fb7df722..370ed6dd6 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -1,481 +1,450 @@
-/* Driver for USB Printers
- *
- * Copyright 1999 Michael Gee (michael@linuxspecific.com)
- * Copyright 1999 Pavel Machek (pavel@suse.cz)
+/*
+ * printer.c Version 0.3
+ *
+ * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
+ *
+ * USB Printer Device Class driver for USB printers and printer cables
+ *
+ * Sponsored by SuSE
+ *
+ * ChangeLog:
+ * v0.1 - thorough cleaning, URBification, almost a rewrite
+ * v0.2 - some more cleanups
+ * v0.3 - cleaner again, waitqueue fixes
+ */
+
+/*
+ * 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.
*
- * Distribute under GPL version 2 or later.
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 <linux/lp.h>
-#include <linux/spinlock.h>
+
+#define DEBUG
#include "usb.h"
-/* Define IEEE_DEVICE_ID if you want to see the IEEE-1284 Device ID string.
- * This may include the printer's serial number.
- * An example from an HP 970C DeskJet printer is (this is one long string,
- * with the serial number changed):
-MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ: ;
+#define USBLP_BUF_SIZE 8192
+
+/*
+ * USB Printer Requests
*/
-#define IEEE_DEVICE_ID
-#define NAK_TIMEOUT (HZ) /* stall wait for printer */
-#define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT) /* should not take 1 minute a page! */
+#define USBLP_REQ_GET_ID 0x00
+#define USBLP_REQ_GET_STATUS 0x01
+#define USBLP_REQ_RESET 0x02
+
+#define USBLP_MINORS 16
+#define USBLP_MINOR_BASE 0
+
+#define USBLP_WRITE_TIMEOUT (60*HZ) /* 60 seconds */
+
+struct usblp {
+ struct usb_device *dev; /* USB device */
+ struct urb readurb, writeurb; /* The urbs */
+ wait_queue_head_t wait; /* Zzzzz ... */
+ int readcount; /* Counter for reads */
+ int ifnum; /* Interface number */
+ int minor; /* minor number of device */
+ unsigned char used; /* True if open */
+ unsigned char bidir; /* interface is bidirectional */
+};
-#define BIG_BUF_SIZE 8192
-#define SUBCLASS_PRINTERS 1
-#define PROTOCOL_UNIDIRECTIONAL 1
-#define PROTOCOL_BIDIRECTIONAL 2
+static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
/*
- * USB Printer Requests
+ * Functions for usblp control messages.
*/
-#define USB_PRINTER_REQ_GET_DEVICE_ID 0
-#define USB_PRINTER_REQ_GET_PORT_STATUS 1
-#define USB_PRINTER_REQ_SOFT_RESET 2
-
-#define MAX_PRINTERS 8
-
-struct pp_usb_data {
- struct usb_device *pusb_dev;
- __u8 isopen; /* True if open */
- __u8 noinput; /* True if no input stream */
- __u8 minor; /* minor number of device */
- __u8 status; /* last status from device */
- int maxin, maxout; /* max transfer size in and out */
- char *obuf; /* transfer buffer (out only) */
- wait_queue_head_t wait_q; /* for timeouts */
- unsigned int last_error; /* save for checking */
- int bulk_in_ep; /* Bulk IN endpoint */
- int bulk_out_ep; /* Bulk OUT endpoint */
- int bulk_in_index; /* endpoint[bulk_in_index] */
- int bulk_out_index; /* endpoint[bulk_out_index] */
-};
-static struct pp_usb_data *minor_data[MAX_PRINTERS];
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, void *buf, int len)
+{
+ int retval = usb_control_msg(usblp->dev,
+ dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
+ request, USB_TYPE_CLASS | dir | recip, 0, usblp->ifnum, buf, len, HZ * 5);
+ dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d len: %#x result: %d", request, !!dir, recip, len, retval);
+ return retval < 0 ? retval : 0;
+}
-#define PPDATA(x) ((struct pp_usb_data *)(x))
+#define usblp_read_status(usblp, status)\
+ usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, status, 1)
+#define usblp_get_id(usblp, id, maxlen)\
+ usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, id, maxlen)
+#define usblp_reset(usblp)\
+ usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, NULL, 0)
-static unsigned char printer_read_status(struct pp_usb_data *p)
+/*
+ * URB callback.
+ */
+
+static void usblp_bulk(struct urb *urb)
{
- __u8 status;
- int err;
- struct usb_device *dev = p->pusb_dev;
-
- err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
- USB_PRINTER_REQ_GET_PORT_STATUS,
- USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
- 0, 0, &status, sizeof(status), HZ);
- if (err < 0) {
- printk(KERN_ERR "usblp%d: read_status control_msg error = %d\n",
- p->minor, err);
- return 0;
- }
- return status;
+ struct usblp *usblp = urb->context;
+
+ if (!usblp || !usblp->dev || !usblp->used)
+ return;
+
+ if (urb->status)
+ warn("nonzero read bulk status received: %d", urb->status);
+
+ wake_up_interruptible(&usblp->wait);
}
-static int printer_check_status(struct pp_usb_data *p)
+/*
+ * Get and print printer errors.
+ */
+
+static int usblp_check_status(struct usblp *usblp)
{
- unsigned int last = p->last_error;
- unsigned char status = printer_read_status(p);
-
- if (status & LP_PERRORP)
- /* No error. */
- last = 0;
- else if ((status & LP_POUTPA)) {
- if (last != LP_POUTPA) {
- last = LP_POUTPA;
- printk(KERN_INFO "usblp%d out of paper (%x)\n", p->minor, status);
+ unsigned char status;
+
+ if (usblp_read_status(usblp, &status)) {
+ err("failed reading usblp status");
+ return -EIO;
+ }
+
+ if (status & LP_PERRORP) {
+
+ if (status & LP_POUTPA) {
+ printk(KERN_INFO "usblp%d: out of paper", usblp->minor);
+ return -ENOSPC;
}
- } else if (!(status & LP_PSELECD)) {
- if (last != LP_PSELECD) {
- last = LP_PSELECD;
- printk(KERN_INFO "usblp%d off-line (%x)\n", p->minor, status);
+ if (~status & LP_PSELECD) {
+ printk(KERN_INFO "usblp%d: off-line", usblp->minor);
+ return -EIO;
}
- } else {
- if (last != LP_PERRORP) {
- last = LP_PERRORP;
- printk(KERN_INFO "usblp%d on fire (%x)\n", p->minor, status);
+ if (~status & LP_PERRORP) {
+ printk(KERN_INFO "usblp%d: on fire", usblp->minor);
+ return -EIO;
}
}
- p->last_error = last;
- return status;
+ return 0;
}
-static void printer_reset(struct pp_usb_data *p)
-{
- struct usb_device *dev = p->pusb_dev;
- int err;
-
- err = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
- USB_PRINTER_REQ_SOFT_RESET,
- USB_TYPE_CLASS | USB_RECIP_OTHER,
- 0, 0, NULL, 0, HZ);
- if (err < 0)
- printk(KERN_ERR "usblp%d: reset control_msg error = %d\n",
- p->minor, err);
-}
+/*
+ * File op functions.
+ */
-static int open_printer(struct inode *inode, struct file *file)
+static int usblp_open(struct inode *inode, struct file *file)
{
- struct pp_usb_data *p;
+ int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
+ struct usblp *usblp;
+ int retval;
- if (MINOR(inode->i_rdev) >= MAX_PRINTERS ||
- !minor_data[MINOR(inode->i_rdev)]) {
+ if (minor < 0 || minor >= USBLP_MINORS)
return -ENODEV;
- }
- p = minor_data[MINOR(inode->i_rdev)];
- p->minor = MINOR(inode->i_rdev);
+ usblp = usblp_table[minor];
- if (p->isopen++) {
- printk(KERN_ERR "usblp%d: printer is already open\n",
- p->minor);
- return -EBUSY;
- }
- if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) {
- p->isopen = 0;
- printk(KERN_ERR "usblp%d: cannot allocate memory\n",
- p->minor);
- return -ENOMEM;
- }
+ if (!usblp || !usblp->dev)
+ return -ENODEV;
- printer_check_status(p);
+ if (usblp->used)
+ return -EBUSY;
- file->private_data = p;
-// printer_reset(p);
- init_waitqueue_head(&p->wait_q);
+ if ((retval = usblp_check_status(usblp)))
+ return retval;
MOD_INC_USE_COUNT;
+ usblp->used = 1;
+ file->private_data = usblp;
+
+ usblp->writeurb.transfer_buffer_length = 0;
+ usblp->writeurb.status = 0;
+ usblp->readcount = 0;
+
+ usb_submit_urb(&usblp->readurb);
return 0;
}
-static int close_printer(struct inode *inode, struct file *file)
+static int usblp_release(struct inode *inode, struct file *file)
{
- struct pp_usb_data *p = file->private_data;
-
- free_page((unsigned long)p->obuf);
- p->isopen = 0;
- file->private_data = NULL;
- /* free the resources if the printer is no longer around */
- if (!p->pusb_dev) {
- minor_data[p->minor] = NULL;
- kfree(p);
- }
+ struct usblp *usblp = file->private_data;
+
MOD_DEC_USE_COUNT;
+ usblp->used = 0;
+
+ if (usblp->dev) {
+ usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(&usblp->writeurb);
+ return 0;
+ }
+
+ usblp_table[usblp->minor] = NULL;
+ kfree(usblp);
+
return 0;
}
-static ssize_t write_printer(struct file *file,
- const char *buffer, size_t count, loff_t *ppos)
+static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
- struct pp_usb_data *p = file->private_data;
- unsigned long copy_size;
- unsigned long bytes_written = 0;
- unsigned long partial;
- int result = USB_ST_NOERROR;
- int maxretry;
-
- do {
- char *obuf = p->obuf;
- unsigned long thistime;
-
- thistime = copy_size = (count > p->maxout) ? p->maxout : count;
- if (copy_from_user(p->obuf, buffer, copy_size))
- return -EFAULT;
- maxretry = MAX_RETRY_COUNT;
-
- while (thistime) {
- if (!p->pusb_dev)
- return -ENODEV;
- if (signal_pending(current)) {
- return bytes_written ? bytes_written : -EINTR;
- }
- result = usb_bulk_msg(p->pusb_dev,
- usb_sndbulkpipe(p->pusb_dev, p->bulk_out_ep),
- obuf, thistime, &partial, HZ*20);
- if (partial) {
- obuf += partial;
- thistime -= partial;
- maxretry = MAX_RETRY_COUNT;
- }
- if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */
- if (!maxretry--)
- return -ETIME;
- interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT);
- continue;
- } else if (!result && !partial) {
- break;
+ struct usblp *usblp = file->private_data;
+ poll_wait(file, &usblp->wait, wait);
+ return (usblp->readurb.status == -EINPROGRESS ? 0 : POLLIN | POLLRDNORM)
+ | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
+}
+
+static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct usblp *usblp = file->private_data;
+ int retval, timeout, writecount = 0;
+
+ while (writecount < count) {
+
+ if (usblp->writeurb.status == -EINPROGRESS) {
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ timeout = USBLP_WRITE_TIMEOUT;
+ while (timeout && usblp->writeurb.status == -EINPROGRESS) {
+
+ if (signal_pending(current))
+ return writecount ? writecount : -EINTR;
+
+ timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
}
- };
- if (result) {
- /* whoops - let's reset and fail the request */
-// printk("Whoops - %x\n", result);
- printer_reset(p);
- interruptible_sleep_on_timeout(&p->wait_q, 5*HZ); /* let reset do its stuff */
+ }
+
+ if (usblp->writeurb.status == -EINPROGRESS) {
+ usb_unlink_urb(&usblp->writeurb);
+ printk(KERN_ERR "usblp%d: timed out\n", usblp->minor);
return -EIO;
}
- bytes_written += copy_size;
- count -= copy_size;
- buffer += copy_size;
- } while ( count > 0 );
- return bytes_written ? bytes_written : -EIO;
+ if (!usblp->dev)
+ return -ENODEV;
+
+ if (!usblp->writeurb.status)
+ writecount += usblp->writeurb.transfer_buffer_length;
+ else {
+ if (!(retval = usblp_check_status(usblp))) {
+ printk(KERN_ERR "usblp%d: error %d writing to printer\n",
+ usblp->minor, usblp->writeurb.status);
+ return -EIO;
+ }
+
+ return retval;
+ }
+
+ if (writecount == count)
+ continue;
+
+ usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+ (count - writecount) : USBLP_BUF_SIZE;
+
+ if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
+ usblp->writeurb.transfer_buffer_length)) return -EFAULT;
+
+ usb_submit_urb(&usblp->writeurb);
+ }
+
+ return count;
}
-static ssize_t read_printer(struct file *file,
- char *buffer, size_t count, loff_t *ppos)
+static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- struct pp_usb_data *p = file->private_data;
- int read_count = 0;
- int this_read;
- char buf[64];
- unsigned long partial;
- int result;
-
- if (p->noinput)
+ struct usblp *usblp = file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (!usblp->bidir)
return -EINVAL;
- while (count) {
- if (signal_pending(current)) {
- return read_count ? read_count : -EINTR;
- }
- if (!p->pusb_dev)
- return -ENODEV;
+ if (usblp->readurb.status == -EINPROGRESS) {
- this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
- result = usb_bulk_msg(p->pusb_dev,
- usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep),
- buf, this_read, &partial, HZ*20);
- if (result < 0)
- printk(KERN_ERR "usblp%d read_printer bulk_msg error = %d\n",
- p->minor, result);
-
- /* unlike writes, we don't retry a NAK, just stop now */
- if (!result & partial)
- count = this_read = partial;
- else if (result)
- return -EIO;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
- if (this_read) {
- if (copy_to_user(buffer, buf, this_read))
- return -EFAULT;
- count -= this_read;
- read_count += this_read;
- buffer += this_read;
+ while (usblp->readurb.status == -EINPROGRESS) {
+ if (signal_pending(current))
+ return -EINTR;
+ interruptible_sleep_on(&usblp->wait);
}
}
- return read_count;
+ if (!usblp->dev)
+ return -ENODEV;
+
+ if (usblp->readurb.status) {
+ printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+ usblp->minor, usblp->readurb.status);
+ usb_submit_urb(&usblp->readurb);
+ return -EIO;
+ }
+
+ count = count < usblp->readurb.actual_length - usblp->readcount ?
+ count : usblp->readurb.actual_length - usblp->readcount;
+
+ if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
+ return -EFAULT;
+
+ if ((usblp->readcount += count) == usblp->readurb.actual_length)
+ usb_submit_urb(&usblp->readurb);
+
+ return count;
}
-static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
- struct pp_usb_data *pp;
- int i;
- __u8 status;
-
- /*
- * FIXME - this will not cope with combined printer/scanners
- */
- if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER &&
- dev->descriptor.bDeviceClass != 0) ||
- dev->descriptor.bNumConfigurations != 1 ||
- dev->actconfig->bNumInterfaces != 1) {
- return NULL;
- }
+ struct usb_endpoint_descriptor *epread, *epwrite;
+ struct usblp *usblp;
+ int minor, i, alts = -1, bidir = 0;
+ char *buf;
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- /* Let's be paranoid (for the moment). */
- if (interface->bInterfaceClass != USB_CLASS_PRINTER ||
- interface->bInterfaceSubClass != SUBCLASS_PRINTERS ||
- (interface->bInterfaceProtocol != PROTOCOL_BIDIRECTIONAL &&
- interface->bInterfaceProtocol != PROTOCOL_UNIDIRECTIONAL) ||
- interface->bNumEndpoints > 2) {
- return NULL;
+ for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[i];
+
+ if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
+ (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) ||
+ (interface->bInterfaceProtocol > interface->bNumEndpoints))
+ continue;
+
+ if (alts == -1)
+ alts = i;
+
+ if (!bidir && interface->bInterfaceProtocol == 2) {
+ bidir = 1;
+ alts = i;
+ }
}
- /* Does this (these) interface(s) support bulk transfers? */
- if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_BULK) {
+ if (alts == -1)
return NULL;
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[alts];
+ if (usb_set_interface(dev, ifnum, alts))
+ err("can't set desired altsetting %d on interface %d", alts, ifnum);
+
+ epwrite = interface->endpoint + 0;
+ epread = NULL;
+
+ if (bidir) {
+ epread = interface->endpoint + 1;
+ if ((epread->bEndpointAddress & 0x80) != 0x80) {
+ epwrite = interface->endpoint + 1;
+ epread = interface->endpoint + 0;
+
+ if ((epread->bEndpointAddress & 0x80) != 0x80)
+ return NULL;
+ }
}
- if ((interface->bNumEndpoints > 1) &&
- ((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_BULK)) {
+
+ if ((epwrite->bEndpointAddress & 0x80) == 0x80)
return NULL;
- }
- /*
- * Does this interface have at least one OUT endpoint
- * that we can write to: endpoint index 0 or 1?
- */
- if ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- != USB_DIR_OUT &&
- (interface->bNumEndpoints > 1 &&
- (interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- != USB_DIR_OUT)) {
- return NULL;
- }
-
- for (i=0; i<MAX_PRINTERS; i++) {
- if (!minor_data[i])
- break;
+ for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
+ if (usblp_table[minor]) {
+ err("no more free usblp devices");
+ return NULL;
}
- if (i >= MAX_PRINTERS) {
- printk(KERN_ERR "No minor table space available for new USB printer\n");
+
+ if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
+ err("out of memory");
return NULL;
}
+ memset(usblp, 0, sizeof(struct usblp));
+
+ usblp->dev = dev;
+ usblp->ifnum = ifnum;
+ usblp->minor = minor;
+ usblp->bidir = bidir;
- printk(KERN_INFO "USB printer found at address %d\n", dev->devnum);
+ init_waitqueue_head(&usblp->wait);
- if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
- printk(KERN_DEBUG "USB printer: no memory!\n");
+ if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
+ err("out of memory");
+ kfree(usblp);
return NULL;
}
- memset(pp, 0, sizeof(struct pp_usb_data));
- minor_data[i] = PPDATA(pp);
-
- pp->minor = i;
- pp->pusb_dev = dev;
- pp->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
- if (interface->bInterfaceProtocol != PROTOCOL_BIDIRECTIONAL)
- pp->noinput = 1;
-
- pp->bulk_out_index =
- ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT) ? 0 : 1;
- pp->bulk_in_index = pp->noinput ? -1 :
- (pp->bulk_out_index == 0) ? 1 : 0;
- pp->bulk_in_ep = pp->noinput ? -1 :
- interface->endpoint[pp->bulk_in_index].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- pp->bulk_out_ep =
- interface->endpoint[pp->bulk_out_index].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- if (interface->bInterfaceProtocol == PROTOCOL_BIDIRECTIONAL) {
- pp->maxin =
- interface->endpoint[pp->bulk_in_index].wMaxPacketSize;
- }
+ FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+ buf, 0, usblp_bulk, usblp);
- printk(KERN_INFO "usblp%d Summary:\n", pp->minor);
- printk(KERN_INFO "index=%d, maxout=%d, noinput=%d, maxin=%d\n",
- i, pp->maxout, pp->noinput, pp->maxin);
- printk(KERN_INFO "bulk_in_ix=%d, bulk_in_ep=%d, bulk_out_ix=%d, bulk_out_ep=%d\n",
- pp->bulk_in_index,
- pp->bulk_in_ep,
- pp->bulk_out_index,
- pp->bulk_out_ep);
-
-#ifdef IEEE_DEVICE_ID
- {
- __u8 ieee_id[64]; /* first 2 bytes are (big-endian) length */
- /* This string space may be too short. */
- int length = (ieee_id[0] << 8) + ieee_id[1]; /* high-low */
- /* This calc. or be16_to_cpu() both get
- * some weird results for <length>. */
- int err;
-
- /* Let's get the device id if possible. */
- err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
- USB_PRINTER_REQ_GET_DEVICE_ID,
- USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
- 0, 0, ieee_id,
- sizeof(ieee_id)-1, HZ);
- if (err >= 0) {
- if (ieee_id[1] < sizeof(ieee_id) - 1)
- ieee_id[ieee_id[1]+2] = '\0';
- else
- ieee_id[sizeof(ieee_id)-1] = '\0';
- printk(KERN_INFO "usblp%d Device ID length=%d [%x:%x]\n",
- pp->minor, length, ieee_id[0], ieee_id[1]);
- printk(KERN_INFO "usblp%d Device ID=%s\n",
- pp->minor, &ieee_id[2]);
- }
- else
- printk(KERN_INFO "usblp%d: error = %d reading IEEE-1284 Device ID\n",
- pp->minor, err);
+ if (bidir) {
+ FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+ buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
}
-#endif
- status = printer_read_status(PPDATA(pp));
- printk(KERN_INFO "usblp%d probe status is %x: %s,%s,%s\n",
- pp->minor, status,
- (status & LP_PSELECD) ? "Selected" : "Not Selected",
- (status & LP_POUTPA) ? "No Paper" : "Paper",
- (status & LP_PERRORP) ? "No Error" : "Error");
+ printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d if %d alt %d\n",
+ minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
- return pp;
+ return usblp_table[minor] = usblp;
}
-static void printer_disconnect(struct usb_device *dev, void *ptr)
+static void usblp_disconnect(struct usb_device *dev, void *ptr)
{
- struct pp_usb_data *pp = ptr;
+ struct usblp *usblp = ptr;
- if (pp->isopen) {
- /* better let it finish - the release will do whats needed */
- pp->pusb_dev = NULL;
+ if (!usblp || !usblp->dev) {
+ err("disconnect on nonexisting interface");
return;
}
- minor_data[pp->minor] = NULL;
- kfree(pp);
+
+ usblp->dev = NULL;
+
+ usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(&usblp->writeurb);
+
+ kfree(usblp->writeurb.transfer_buffer);
+
+ if (usblp->used) return;
+
+ usblp_table[usblp->minor] = NULL;
+ kfree(usblp);
}
-static struct file_operations usb_printer_fops = {
- NULL, /* seek */
- read_printer,
- write_printer,
- NULL, /* readdir */
- NULL, /* poll - out for the moment */
- NULL, /* ioctl */
- NULL, /* mmap */
- open_printer,
- NULL, /* flush ? */
- close_printer,
- NULL,
- NULL
+static struct file_operations usblp_fops = {
+ read: usblp_read,
+ write: usblp_write,
+ open: usblp_open,
+ release: usblp_release,
+ poll: usblp_poll
};
-static struct usb_driver printer_driver = {
- "printer",
- printer_probe,
- printer_disconnect,
- { NULL, NULL },
- &usb_printer_fops,
- 0
+static struct usb_driver usblp_driver = {
+ name: "usblp",
+ probe: usblp_probe,
+ disconnect: usblp_disconnect,
+ fops: &usblp_fops,
+ minor: USBLP_MINOR_BASE
};
-int usb_printer_init(void)
+#ifdef MODULE
+void cleanup_module(void)
{
- if (usb_register(&printer_driver))
- return -1;
-
- printk(KERN_INFO "USB Printer driver registered.\n");
- return 0;
+ usb_deregister(&usblp_driver);
}
-
-#ifdef MODULE
int init_module(void)
+#else
+int usb_printer_init(void)
+#endif
{
- return usb_printer_init();
-}
+ if (usb_register(&usblp_driver))
+ return -1;
-void cleanup_module(void)
-{
- usb_deregister(&printer_driver);
+ return 0;
}
-#endif
diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c
deleted file mode 100644
index ca431d454..000000000
--- a/drivers/usb/proc_usb.c
+++ /dev/null
@@ -1,1189 +0,0 @@
-/*
- * drivers/usb/proc_usb.c
- * (C) Copyright 1999 Randy Dunlap.
- * (C) Copyright 1999 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
- * (C) Copyright 1999 Deti Fliegl (new USB architecture)
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *************************************************************
- *
- * This is a /proc/bus/usb filesystem output module for USB.
- * It creates /proc/bus/usb/drivers and /proc/bus/usb/devices.
- *
- * /proc/bus/usb/devices contains USB topology, device, config, class,
- * interface, & endpoint data.
- *
- * I considered using /proc/bus/usb/devices/device# for each device
- * as it is attached or detached, but I didn't like this for some
- * reason -- maybe it's just too deep of a directory structure.
- * I also don't like looking in multiple places to gather and view
- * the data. Having only one file for ./devices also prevents race
- * conditions that could arise if a program was reading device info
- * for devices that are being removed (unplugged). (That is, the
- * program may find a directory for devnum_12 then try to open it,
- * but it was just unplugged, so the directory is now deleted.
- * But programs would just have to be prepared for situations like
- * this in any plug-and-play environment.)
- *
- * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Converted the whole proc stuff to real
- * read methods. Now not the whole device list needs to fit
- * into one page, only the device list for one bus.
- * Added a poll method to /proc/bus/usb/devices, to wake
- * up an eventual usbd
- *
- * $Id: proc_usb.c,v 1.14 1999/12/17 10:51:41 fliegl Exp $
- */
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
-#include <linux/wait.h>
-#include <linux/poll.h>
-
-#include "usb.h"
-
-
-#define MAX_TOPO_LEVEL 6
-
-/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
-#define ALLOW_SERIAL_NUMBER
-
-static char *format_topo =
-/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
- "T: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
-
-static char *format_string_manufacturer =
-/* S: Manufacturer=xxxx */
- "S: Manufacturer=%s\n";
-
-static char *format_string_product =
-/* S: Product=xxxx */
- "S: Product=%s\n";
-
-#ifdef ALLOW_SERIAL_NUMBER
-static char *format_string_serialnumber =
-/* S: SerialNumber=xxxx */
- "S: SerialNumber=%s\n";
-#endif
-
-static char *format_bandwidth =
-/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
- "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
-
-static char *format_device1 =
-/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
- "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
-
-static char *format_device2 =
-/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
- "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
-
-static char *format_config =
-/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
- "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
-
-static char *format_iface =
-/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
- "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
-
-static char *format_endpt =
-/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
- "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
-
-
-/*
- * Need access to the driver and USB bus lists.
- * extern struct list_head usb_driver_list;
- * extern struct list_head usb_bus_list;
- * However, these will come from functions that return ptrs to each of them.
- */
-
-extern struct list_head *usb_driver_get_list (void);
-extern struct list_head *usb_bus_get_list (void);
-
-extern struct proc_dir_entry *proc_bus;
-
-static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL;
-static struct proc_dir_entry *devicesdir = NULL;
-
-static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
-static unsigned int conndiscevcnt = 0;
-
-/* this struct stores the poll state for /proc/bus/usb/devices pollers */
-struct usb_device_status {
- unsigned int lastev;
-};
-
-struct class_info {
- int class;
- char *class_name;
-};
-
-static const struct class_info clas_info[] =
-{ /* max. 5 chars. per name string */
- {USB_CLASS_PER_INTERFACE, ">ifc"},
- {USB_CLASS_AUDIO, "audio"},
- {USB_CLASS_COMM, "comm."},
- {USB_CLASS_HID, "HID"},
- {USB_CLASS_HUB, "hub"},
- {USB_CLASS_PRINTER, "print"},
- {USB_CLASS_MASS_STORAGE, "stor."},
- {USB_CLASS_DATA, "data"},
- {USB_CLASS_VENDOR_SPEC, "vend."},
- {-1, "unk."} /* leave as last */
-};
-
-/*****************************************************************/
-
-extern inline void conndiscevent(void)
-{
- wake_up(&deviceconndiscwq);
- conndiscevcnt++;
-}
-
-static const char *class_decode(const int class)
-{
- int ix;
-
- for (ix = 0; clas_info[ix].class != -1; ix++)
- if (clas_info[ix].class == class)
- break;
- return (clas_info[ix].class_name);
-}
-
-static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
-{
- char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
-
- if (start > end)
- return start;
- start += sprintf(start, format_endpt, desc->bEndpointAddress,
- (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
- desc->bmAttributes, EndpointType[desc->bmAttributes & 3],
- desc->wMaxPacketSize, desc->bInterval);
- return start;
-}
-
-static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
-{
- return usb_dump_endpoint_descriptor(start, end, endpoint);
-}
-
-static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
-{
- struct usb_interface_descriptor *desc = &iface->altsetting[setno];
-
- if (start > end)
- return start;
- start += sprintf(start, format_iface,
- desc->bInterfaceNumber,
- desc->bAlternateSetting,
- desc->bNumEndpoints,
- desc->bInterfaceClass,
- class_decode(desc->bInterfaceClass),
- desc->bInterfaceSubClass,
- desc->bInterfaceProtocol,
- iface->driver ? iface->driver->name : "(none)");
- return start;
-}
-
-static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
-{
- struct usb_interface_descriptor *desc = &iface->altsetting[setno];
- int i;
-
- start = usb_dump_interface_descriptor(start, end, iface, setno);
- for (i = 0; i < desc->bNumEndpoints; i++) {
- if (start > end)
- return start;
- start = usb_dump_endpoint(start, end, desc->endpoint + i);
- }
- return start;
-}
-
-/* TBD:
- * 0. TBDs
- * 1. marking active config and ifaces (code lists all, but should mark
- * which ones are active, if any)
- * 2. add <halted> status to each endpoint line
- */
-
-static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, const int active)
-{
- if (start > end)
- return start;
- start += sprintf(start, format_config,
- active ? '*' : ' ', /* mark active/actual/current cfg. */
- desc->bNumInterfaces,
- desc->bConfigurationValue,
- desc->bmAttributes,
- desc->MaxPower * 2);
- return start;
-}
-
-static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, const int active)
-{
- int i, j;
- struct usb_interface *interface;
-
- if (start > end)
- return start;
- if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
- return start + sprintf(start, "(null Cfg. desc.)\n");
- start = usb_dump_config_descriptor(start, end, config, active);
- for (i = 0; i < config->bNumInterfaces; i++) {
- interface = config->interface + i;
- if (!interface)
- break;
- for (j = 0; j < interface->num_altsetting; j++) {
- if (start > end)
- return start;
- start = usb_dump_interface(start, end, interface, j);
- }
- }
- return start;
-}
-
-/*
- * Dump the different USB descriptors.
- */
-static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
-{
- if (start > end)
- return start;
- start += sprintf (start, format_device1,
- desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
- desc->bDeviceClass,
- class_decode (desc->bDeviceClass),
- desc->bDeviceSubClass,
- desc->bDeviceProtocol,
- desc->bMaxPacketSize0,
- desc->bNumConfigurations);
- if (start > end)
- return start;
- start += sprintf(start, format_device2,
- desc->idVendor, desc->idProduct,
- desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
- return start;
-}
-
-/*
- * Dump the different strings that this device holds.
- */
-static char *usb_dump_device_strings (char *start, char *end, const struct usb_device *dev)
-{
- if (start > end)
- return start;
-
- if (dev->descriptor.iManufacturer) {
- char * string = usb_string ((struct usb_device *)dev,
- dev->descriptor.iManufacturer);
- if (string) {
- start += sprintf (start, format_string_manufacturer,
- string
- );
- if (start > end)
- return start;
-
- }
- }
-
- if (dev->descriptor.iProduct) {
- char * string = usb_string ((struct usb_device *)dev,
- dev->descriptor.iProduct);
- if (string) {
- start += sprintf (start, format_string_product,
- string
- );
- if (start > end)
- return start;
-
- }
- }
-
-#ifdef ALLOW_SERIAL_NUMBER
- if (dev->descriptor.iSerialNumber) {
- char * string = usb_string ((struct usb_device *)dev,
- dev->descriptor.iSerialNumber);
- if (string) {
- start += sprintf (start, format_string_serialnumber,
- string
- );
- }
- }
-#endif
-
- return start;
-}
-
-static char *usb_dump_desc(char *start, char *end, const struct usb_device *dev)
-{
- int i;
-
- if (start > end)
- return start;
-
- start = usb_dump_device_descriptor(start, end, &dev->descriptor);
-
- if (start > end)
- return start;
-
- start = usb_dump_device_strings (start, end, dev);
-
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- if (start > end)
- return start;
- start = usb_dump_config(start, end, dev->config + i,
- (dev->config + i) == dev->actconfig); /* active ? */
- }
- return start;
-}
-
-
-#ifdef PROC_EXTRA /* TBD: may want to add this code later */
-
-static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
-{
- int leng = USB_DT_HUB_NONVAR_SIZE;
- unsigned char *ptr = (unsigned char *)desc;
-
- if (start > end)
- return start;
- start += sprintf(start, "Interface:");
- while (leng) {
- start += sprintf(start, " %02x", *ptr);
- ptr++; leng--;
- }
- start += sprintf(start, "\n");
- return start;
-}
-
-#endif /* PROC_EXTRA */
-
-/*****************************************************************/
-
-static char *usb_device_dump(char *start, char *end, const struct usb_device *usbdev,
- const struct usb_bus *bus, int level, int index, int count)
-{
- int chix;
- int cnt = 0;
- int parent_devnum = 0;
-
- if (level > MAX_TOPO_LEVEL)
- return start;
- if (usbdev->parent && usbdev->parent->devnum != -1)
- parent_devnum = usbdev->parent->devnum;
- /*
- * So the root hub's parent is 0 and any device that is
- * plugged into the root hub has a parent of 0.
- */
- start += sprintf(start, format_topo, bus->busnum-1, level, parent_devnum, index, count,
- usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
- /*
- * level = topology-tier level;
- * parent_devnum = parent device number;
- * index = parent's connector number;
- * count = device count at this level
- */
- /* If this is the root hub, display the bandwidth information */
- if (level == 0)
- start += sprintf(start, format_bandwidth, bus->bandwidth_allocated,
- FRAME_TIME_MAX_USECS_ALLOC,
- (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
- bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
-
- /* show the descriptor information for this device */
- start = usb_dump_desc(start, end, usbdev);
- if (start > end)
- return start + sprintf(start, "(truncated)\n");
-
- /* Now look at all of this device's children. */
- for (chix = 0; chix < usbdev->maxchild; chix++) {
- if (start > end)
- return start;
- if (usbdev->children[chix])
- start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
- }
- return start;
-}
-
-static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
-{
- struct list_head *usb_bus_list, *buslist;
- struct usb_bus *bus;
- char *page, *end;
- ssize_t ret = 0;
- unsigned int pos, len;
-
- if (*ppos < 0)
- return -EINVAL;
- if (nbytes <= 0)
- return 0;
- if (!access_ok(VERIFY_WRITE, buf, nbytes))
- return -EFAULT;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- pos = *ppos;
- usb_bus_list = usb_bus_get_list();
- /* enumerate busses */
- for (buslist = usb_bus_list->next; buslist != usb_bus_list; buslist = buslist->next) {
- bus = list_entry(buslist, struct usb_bus, bus_list);
- end = usb_device_dump(page, page + (PAGE_SIZE - 100), bus->root_hub, bus, 0, 0, 0);
- len = end - page;
- if (len > pos) {
- len -= pos;
- if (len > nbytes)
- len = nbytes;
- if (copy_to_user(buf, page + pos, len)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- nbytes -= len;
- buf += len;
- ret += len;
- pos = 0;
- *ppos += len;
- } else
- pos -= len;
- }
- free_page((unsigned long)page);
- return ret;
-}
-
-static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct usb_device_status *st = (struct usb_device_status *)file->private_data;
- unsigned int mask = 0;
-
- if (!st) {
- st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
- if (!st)
- return POLLIN;
- /*
- * need to prevent the module from being unloaded, since
- * proc_unregister does not call the release method and
- * we would have a memory leak
- */
- st->lastev = conndiscevcnt;
- file->private_data = st;
- MOD_INC_USE_COUNT;
- mask = POLLIN;
- }
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &deviceconndiscwq, wait);
- if (st->lastev != conndiscevcnt)
- mask |= POLLIN;
- st->lastev = conndiscevcnt;
- return mask;
-}
-
-static int usb_device_open(struct inode *inode, struct file *file)
-{
- file->private_data = NULL;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static int usb_device_release(struct inode *inode, struct file *file)
-{
- if (file->private_data) {
- kfree(file->private_data);
- file->private_data = NULL;
- }
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
- * Dump usb_driver_list.
- *
- * We now walk the list of registered USB drivers.
- */
-static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
-{
- struct list_head *usb_driver_list = usb_driver_get_list();
- struct list_head *tmp = usb_driver_list->next;
- char *page, *start, *end;
- ssize_t ret = 0;
- unsigned int pos, len;
-
- if (*ppos < 0)
- return -EINVAL;
- if (nbytes <= 0)
- return 0;
- if (!access_ok(VERIFY_WRITE, buf, nbytes))
- return -EFAULT;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- start = page;
- end = page + (PAGE_SIZE - 100);
- pos = *ppos;
- for (; tmp != usb_driver_list; tmp = tmp->next) {
- struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
- start += sprintf (start, "%s\n", driver->name);
- if (start > end) {
- start += sprintf(start, "(truncated)\n");
- break;
- }
- }
- if (start == page)
- start += sprintf(start, "(none)\n");
- len = start - page;
- if (len > pos) {
- len -= pos;
- if (len > nbytes)
- len = nbytes;
- ret = len;
- if (copy_to_user(buf, page + pos, len))
- ret = -EFAULT;
- else
- *ppos += len;
- }
- free_page((unsigned long)page);
- return ret;
-}
-
-static long long usbdev_lseek(struct file * file, long long offset, int orig);
-
-static struct file_operations proc_usb_devlist_file_operations = {
- usbdev_lseek, /* lseek */
- usb_device_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- usb_device_poll, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- usb_device_open, /* open */
- NULL, /* flush */
- usb_device_release, /* release */
- NULL /* fsync */
-};
-
-static struct inode_operations proc_usb_devlist_inode_operations = {
- &proc_usb_devlist_file_operations, /* file-ops */
-};
-
-static struct file_operations proc_usb_drvlist_file_operations = {
- usbdev_lseek, /* lseek */
- usb_driver_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-static struct inode_operations proc_usb_drvlist_inode_operations = {
- &proc_usb_drvlist_file_operations, /* file-ops */
-};
-
-
-/*
- * proc entry for every device
- */
-
-static long long usbdev_lseek(struct file * file, long long offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return file->f_pos;
-
- case 1:
- file->f_pos += offset;
- return file->f_pos;
-
- case 2:
- return -EINVAL;
-
- default:
- return -EINVAL;
- }
-}
-
-static ssize_t usbdev_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip;
- struct usb_device *dev = (struct usb_device *)dp->data;
- ssize_t ret = 0;
- unsigned len;
-
- if (*ppos < 0)
- return -EINVAL;
- if (*ppos < sizeof(struct usb_device_descriptor)) {
- len = sizeof(struct usb_device_descriptor);
- if (len > nbytes)
- len = nbytes;
- copy_to_user_ret(buf, ((char *)&dev->descriptor) + *ppos, len, -EFAULT);
- *ppos += len;
- buf += len;
- nbytes -= len;
- ret += len;
- }
- return ret;
-}
-
-/* note: this is a compatibility kludge that will vanish soon. */
-#include "ezusb.h"
-
-static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- static unsigned obsolete_warn = 0;
- struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip;
- struct usb_device *dev = (struct usb_device *)dp->data;
- struct ezusb_ctrltransfer ctrl;
- struct ezusb_bulktransfer bulk;
- struct ezusb_old_ctrltransfer octrl;
- struct ezusb_old_bulktransfer obulk;
- struct ezusb_setinterface setintf;
- unsigned int len1, ep, pipe, cfg;
- unsigned long len2;
- unsigned char *tbuf;
- int i;
-
- switch (cmd) {
- case EZUSB_CONTROL:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_CONTROL ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
- if (ctrl.length > PAGE_SIZE)
- return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (ctrl.requesttype & 0x80) {
- if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
- ctrl.value, ctrl.index, tbuf, ctrl.length,
- (ctrl.timeout * HZ + 500) / 1000);
- if ((i > 0) && ctrl.length) {
- copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
- }
- } else {
- if (ctrl.length) {
- copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
- }
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
- ctrl.value, ctrl.index, tbuf, ctrl.length,
- (ctrl.timeout * HZ + 500) / 1000);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("EZUSB_CONTROL failed rqt %u rq %u len %u ret %d",
- ctrl.requesttype, ctrl.request, ctrl.length, i);
- return i;
- }
- return i;
-
- case EZUSB_BULK:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_BULK ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
- if (bulk.ep & 0x80)
- pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
- if (!usb_maxpacket(dev, pipe, !(bulk.ep & 0x80)))
- return -EINVAL;
- len1 = bulk.len;
- if (len1 > PAGE_SIZE)
- len1 = PAGE_SIZE;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (bulk.ep & 0x80) {
- if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
- if ((i > 0) && len2) {
- copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
- }
- } else {
- if (len1) {
- copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("EZUSB_BULK failed ep 0x%x len %u ret %d",
- bulk.ep, bulk.len, i);
- return i;
- }
- return len2;
-
- case EZUSB_OLD_CONTROL:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_OLD_CONTROL ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
- if (octrl.dlen > PAGE_SIZE)
- return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (octrl.requesttype & 0x80) {
- if (octrl.dlen && !access_ok(VERIFY_WRITE, octrl.data, octrl.dlen)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_internal_control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
- if ((i > 0) && octrl.dlen) {
- copy_to_user_ret(octrl.data, tbuf, octrl.dlen, -EFAULT);
- }
- } else {
- if (octrl.dlen) {
- copy_from_user_ret(tbuf, octrl.data, octrl.dlen, -EFAULT);
- }
- i = usb_internal_control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("EZUSB_OLD_CONTROL failed rqt %u rq %u len %u ret %d",
- octrl.requesttype, octrl.request, octrl.length, i);
- return i;
- }
- return i;
-
- case EZUSB_OLD_BULK:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_OLD_BULK ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
- if (obulk.ep & 0x80)
- pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
- if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
- return -EINVAL;
- len1 = obulk.len;
- if (len1 > PAGE_SIZE)
- len1 = PAGE_SIZE;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (obulk.ep & 0x80) {
- if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- if ((i > 0) && len2) {
- copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
- }
- } else {
- if (len1) {
- copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("EZUSB_OLD_BULK failed ep 0x%x len %u ret %d",
- obulk.ep, obulk.len, i);
- return i;
- }
- return len2;
-
- case EZUSB_RESETEP:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_RESETEP ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- usb_settoggle(dev, ep & 0xf, !(ep & 0x80), 0);
- return 0;
-
- case EZUSB_SETINTERFACE:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_SETINTERFACE ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT);
- if (usb_set_interface(dev, setintf.interface, setintf.altsetting))
- return -EINVAL;
- return 0;
-
- case EZUSB_SETCONFIGURATION:
- if (obsolete_warn < 20) {
- warn("process %d (%s) used obsolete EZUSB_SETCONFIGURATION ioctl",
- current->pid, current->comm);
- obsolete_warn++;
- }
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
- if (usb_set_configuration(dev, cfg) < 0)
- return -EINVAL;
- return 0;
-
- }
- return -ENOIOCTLCMD;
-}
-
-
-
-static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip;
- struct usb_device *dev = (struct usb_device *)dp->data;
- struct usb_proc_ctrltransfer ctrl;
- struct usb_proc_bulktransfer bulk;
- struct usb_proc_old_ctrltransfer octrl;
- struct usb_proc_old_bulktransfer obulk;
- struct usb_proc_setinterface setintf;
- unsigned int len1, ep, pipe, cfg;
- unsigned long len2;
- unsigned char *tbuf;
- int i;
-
- switch (cmd) {
- case USB_PROC_CONTROL:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
- if (ctrl.length > PAGE_SIZE)
- return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (ctrl.requesttype & 0x80) {
- if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request,
- ctrl.requesttype, ctrl.value, ctrl.index, tbuf,
- ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
- if ((i > 0) && ctrl.length) {
- copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
- }
- } else {
- if (ctrl.length) {
- copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
- }
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request,
- ctrl.requesttype, ctrl.value, ctrl.index, tbuf,
- ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
- }
- free_page((unsigned long)tbuf);
- if (i<0) {
- warn("USB_PROC_CONTROL failed rqt %u rq %u len %u ret %d",
- ctrl.requesttype, ctrl.request, ctrl.length, i);
- return i;
- }
- return 0;
-
- case USB_PROC_BULK:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
- if (bulk.ep & 0x80)
- pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
- if (!usb_maxpacket(dev, pipe, !(bulk.ep & 0x80)))
- return -EINVAL;
- len1 = bulk.len;
- if (len1 > PAGE_SIZE)
- len1 = PAGE_SIZE;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (bulk.ep & 0x80) {
- if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
- if (!i && len2) {
- copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
- }
- } else {
- if (len1) {
- copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
- }
- free_page((unsigned long)tbuf);
- if (i) {
- warn("USB_PROC_BULK failed ep 0x%x len %u ret %d",
- bulk.ep, bulk.len, i);
- return -ENXIO;
- }
- return len2;
-
- case USB_PROC_OLD_CONTROL:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
- if (octrl.length > PAGE_SIZE)
- return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (octrl.requesttype & 0x80) {
- if (octrl.length && !access_ok(VERIFY_WRITE, octrl.data, octrl.length)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), octrl.request,
- octrl.requesttype, octrl.value, octrl.index, tbuf,
- octrl.length, HZ);
- if ((i > 0) && octrl.length) {
- copy_to_user_ret(octrl.data, tbuf, octrl.length, -EFAULT);
- }
- } else {
- if (octrl.length) {
- copy_from_user_ret(tbuf, octrl.data, octrl.length, -EFAULT);
- }
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), octrl.request,
- octrl.requesttype, octrl.value, octrl.index, tbuf,
- octrl.length, HZ);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("USB_PROC_OLD_CONTROL failed rqt %u rq %u len %u ret %d",
- octrl.requesttype, octrl.request, octrl.length, i);
- return i;
- }
- return 0;
-
- case USB_PROC_OLD_BULK:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
- if (obulk.ep & 0x80)
- pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
- if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
- return -EINVAL;
- len1 = obulk.len;
- if (len1 > PAGE_SIZE)
- len1 = PAGE_SIZE;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if (obulk.ep & 0x80) {
- if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- if ((i > 0) && len2) {
- copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
- }
- } else {
- if (len1) {
- copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
- }
- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- }
- free_page((unsigned long)tbuf);
- if (i < 0) {
- warn("USB_PROC_OLD_BULK failed ep 0x%x len %u ret %d",
- obulk.ep, obulk.len, i);
- return i;
- }
- return len2;
-
- case USB_PROC_RESETEP:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
- if ((ep & ~0x80) >= 16)
- return -EINVAL;
- usb_settoggle(dev, ep & 0xf, !(ep & 0x80), 0);
- return 0;
-
- case USB_PROC_SETINTERFACE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT);
- if (usb_set_interface(dev, setintf.interface, setintf.altsetting))
- return -EINVAL;
- return 0;
-
- case USB_PROC_SETCONFIGURATION:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
- if (usb_set_configuration(dev, cfg) < 0)
- return -EINVAL;
- return 0;
-
- case EZUSB_CONTROL:
- case EZUSB_BULK:
- case EZUSB_OLD_CONTROL:
- case EZUSB_OLD_BULK:
- case EZUSB_RESETEP:
- case EZUSB_SETINTERFACE:
- case EZUSB_SETCONFIGURATION:
- return usbdev_ioctl_ezusbcompat(inode, file, cmd, arg);
- }
- return -ENOIOCTLCMD;
-}
-
-static struct file_operations proc_usb_device_file_operations = {
- usbdev_lseek, /* lseek */
- usbdev_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- usbdev_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-static struct inode_operations proc_usb_device_inode_operations = {
- &proc_usb_device_file_operations, /* file-ops */
-};
-
-void proc_usb_add_bus(struct usb_bus *bus)
-{
- char buf[16];
-
- bus->proc_entry = NULL;
- if (!usbdir)
- return;
- sprintf(buf, "%03d", bus->busnum);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,31)
- if (!(bus->proc_entry = create_proc_entry(buf, S_IFDIR, usbdir)))
-#else
- if (!(bus->proc_entry = proc_mkdir(buf, usbdir)))
-#endif
- return;
- bus->proc_entry->data = bus;
- conndiscevent();
-}
-
-/* devices need already be removed! */
-void proc_usb_remove_bus(struct usb_bus *bus)
-{
- if (!bus->proc_entry)
- return;
- remove_proc_entry(bus->proc_entry->name, usbdir);
- conndiscevent();
-}
-
-void proc_usb_add_device(struct usb_device *dev)
-{
- char buf[16];
-
- dev->proc_entry = NULL;
- if (!dev->bus->proc_entry)
- return;
- sprintf(buf, "%03d", dev->devnum);
- if (!(dev->proc_entry = create_proc_entry(buf, 0, dev->bus->proc_entry)))
- return;
- dev->proc_entry->ops = &proc_usb_device_inode_operations;
- dev->proc_entry->data = dev;
- conndiscevent();
-}
-
-void proc_usb_remove_device(struct usb_device *dev)
-{
- if (dev->proc_entry)
- remove_proc_entry(dev->proc_entry->name, dev->bus->proc_entry);
- conndiscevent();
-}
-
-
-void proc_usb_cleanup (void)
-{
- if (driversdir)
- remove_proc_entry("drivers", usbdir);
- if (devicesdir)
- remove_proc_entry("devices", usbdir);
- if (usbdir)
- remove_proc_entry("usb", proc_bus);
-}
-
-int proc_usb_init (void)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,31)
- usbdir = create_proc_entry("usb", S_IFDIR, proc_bus);
-#else
- usbdir = proc_mkdir("usb", proc_bus);
-#endif
- if (!usbdir) {
- err("cannot create /proc/bus/usb entry");
- return -1;
- }
-
- driversdir = create_proc_entry("drivers", 0, usbdir);
- if (!driversdir) {
- err("cannot create /proc/bus/usb/drivers entry");
- proc_usb_cleanup();
- return -1;
- }
- driversdir->ops = &proc_usb_drvlist_inode_operations;
-
- devicesdir = create_proc_entry("devices", 0, usbdir);
- if (!devicesdir) {
- err("cannot create /proc/bus/usb/devices entry");
- proc_usb_cleanup ();
- return -1;
- }
- devicesdir->ops = &proc_usb_devlist_inode_operations;
-
- return 0;
-}
-
-/* end proc_usb.c */
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index 806e15ab3..97399bc2d 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -125,7 +125,7 @@ static struct hpscan_usb_data hpscan;
MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
MODULE_DESCRIPTION("USB Scanner Driver");
-static __u16 vendor=0, product=0;
+static __u16 vendor=0x05f9, product=0xffff;
MODULE_PARM(vendor, "i");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
@@ -410,9 +410,12 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
hps->oep = endpoint[1].bEndpointAddress;
}
- ident = usb_string(dev, dev->descriptor.iProduct); /* usb_string allocates memory using kmalloc() so kfree() needs to be called afterwards when the pointer is no longer needed. */
- info("USB Scanner (%s) found at address %d", ident, dev->devnum);
- kfree(ident);
+ ident = kmalloc(256, GFP_KERNEL);
+ if (ident) {
+ usb_string(dev, dev->descriptor.iProduct, ident, 256);
+ info("USB Scanner (%s) found at address %d", ident, dev->devnum);
+ kfree(ident);
+ }
dbg("probe_scanner: using bulk endpoints - In: %x Out: %x", hps->iep, hps->oep);
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 2302d42a7..f0b30bf93 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -24,8 +24,6 @@ int usb_hub_init(void);
void usb_hub_cleanup(void);
int usb_major_init(void);
void usb_major_cleanup(void);
-int proc_usb_init(void);
-void proc_usb_cleanup(void);
/*
* USB device drivers
@@ -38,13 +36,14 @@ int usb_ov511_init(void);
int usb_dc2xx_init(void);
int usb_scanner_init(void);
int usb_printer_init(void);
-int usb_scsi_init(void);
+int usb_stor_init(void);
int usb_serial_init(void);
int dabusb_init(void);
int hid_init(void);
int input_init(void);
int usb_mouse_init(void);
int usb_kbd_init(void);
+int graphire_init(void);
/*
* HCI drivers
@@ -62,10 +61,8 @@ int ohci_hcd_init(void);
void cleanup_module(void)
{
usb_major_cleanup();
-#ifdef CONFIG_USB_PROC
- proc_usb_cleanup ();
-#endif
- usb_hub_cleanup();
+ usbdevfs_cleanup();
+ usb_hub_cleanup();
}
@@ -79,9 +76,7 @@ int usb_init(void)
#endif
{
usb_major_init();
-#ifdef CONFIG_USB_PROC
- proc_usb_init();
-#endif
+ usbdevfs_init();
usb_hub_init();
#ifndef CONFIG_USB_MODULE
@@ -110,12 +105,12 @@ int usb_init(void)
usb_dc2xx_init();
#endif
#ifdef CONFIG_USB_SCSI
- usb_scsi_init();
+ usb_stor_init();
#endif
#ifdef CONFIG_USB_DABUSB
dabusb_init();
#endif
-#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_MOUSE) || defined(CONFIG_USB_KBD)
+#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_MOUSE) || defined(CONFIG_USB_KBD) || defined(CONFIG_USB_GRAPHIRE)
input_init();
#endif
#ifdef CONFIG_USB_HID
@@ -127,6 +122,9 @@ int usb_init(void)
#ifdef CONFIG_USB_KBD
usb_kbd_init();
#endif
+#ifdef CONFIG_USB_GRAPHIRE
+ graphire_init();
+#endif
#ifdef CONFIG_USB_UHCI
uhci_init();
#endif
diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c
index b321fdff3..2cca35151 100644
--- a/drivers/usb/usb-debug.c
+++ b/drivers/usb/usb-debug.c
@@ -6,6 +6,7 @@
*/
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#define DEBUG
@@ -131,24 +132,6 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)
printk(" iInterface = %02x\n", desc->iInterface);
}
-void usb_show_hid_descriptor(struct usb_hid_descriptor * desc)
-{
- int i;
-
- printk(" HID:\n");
- printk(" HID version %x.%02x\n", desc->bcdHID >> 8, desc->bcdHID & 0xff);
- printk(" bLength = %4d\n", desc->bLength);
- printk(" bDescriptorType = %02x\n", desc->bDescriptorType);
- printk(" bCountryCode = %02x\n", desc->bCountryCode);
- printk(" bNumDescriptors = %02x\n", desc->bNumDescriptors);
-
- for (i=0; i<desc->bNumDescriptors; i++) {
- printk(" %d:\n", i);
- printk(" bDescriptorType = %02x\n", desc->desc[i].bDescriptorType);
- printk(" wDescriptorLength = %04x\n", desc->desc[i].wDescriptorLength);
- }
-}
-
void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
{
char *LengthCommentString = (desc->bLength ==
@@ -175,9 +158,12 @@ void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
void usb_show_string(struct usb_device *dev, char *id, int index)
{
- char *p = usb_string(dev, index);
+ char *buf;
- if (p != 0)
- printk(KERN_INFO "%s: %s\n", id, p);
+ if (!(buf = kmalloc(256, GFP_KERNEL)))
+ return;
+ if (usb_string(dev, index, buf, 256) > 0)
+ printk(KERN_INFO "%s: %s\n", id, buf);
+ kfree(buf);
}
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c
index 0cb3bdcba..8826bc522 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/usb-serial.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * (C) Copyright (C) 1999
+ * (C) Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,8 +12,42 @@
* This driver was originally based on the ACM driver by Armin Fuerst (which was
* based on a driver by Brad Keryan)
*
- * See README.serial for more information on using this driver.
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (01/19/2000) gkh
+ * Removed lots of cruft that was around from the old (pre urb) driver
+ * interface.
+ * Made the serial_table dynamic. This should save lots of memory when
+ * the number of minor nodes goes up to 256.
+ * Added initial support for devices that have more than one port.
+ * Added more debugging comments for the Visor, and added a needed
+ * set_configuration call.
+ *
+ * (01/17/2000) gkh
+ * Fixed the WhiteHEAT firmware (my processing tool had a bug)
+ * and added new debug loader firmware for it.
+ * Removed the put_char function as it isn't really needed.
+ * Added visor startup commands as found by the Win98 dump.
+ *
+ * (01/13/2000) gkh
+ * Fixed the vendor id for the generic driver to the one I meant it to be.
+ *
+ * (01/12/2000) gkh
+ * Forget the version numbering...that's pretty useless...
+ * Made the driver able to be compiled so that the user can select which
+ * converter they want to use. This allows people who only want the Visor
+ * support to not pay the memory size price of the WhiteHEAT.
+ * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+ * grabbed the root hub. Not good.
+ *
+ * version 0.4.0 (01/10/2000) gkh
+ * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+ * device. Added startup function to allow firmware to be downloaded to
+ * a device if it needs to be.
+ * Added firmware download logic to the WhiteHEAT device.
+ * Started to add #defines to split up the different drivers for potential
+ * configuration option.
+ *
* version 0.3.1 (12/30/99) gkh
* Fixed problems with urb for bulk out.
* Added initial support for multiple sets of endpoints. This enables
@@ -63,6 +97,7 @@
*
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -77,21 +112,31 @@
#include <linux/module.h>
#include <linux/spinlock.h>
-#undef DEBUG
+#define DEBUG
#include "usb.h"
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+#include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */
+#endif
+
/* Module information */
MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
MODULE_DESCRIPTION("USB Serial Driver");
-static __u16 vendor = 0;
-static __u16 product = 0;
+#ifdef CONFIG_USB_SERIAL_GENERIC
+static __u16 vendor = 0x05f9;
+static __u16 product = 0xffff;
MODULE_PARM(vendor, "i");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
MODULE_PARM(product, "i");
MODULE_PARM_DESC(product, "User specified USB idProduct");
+#endif
+
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
/* USB Serial devices vendor ids and device ids that this driver supports */
@@ -106,12 +151,36 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
#define HANDSPRING_VISOR_ID 0x0100
-#define SERIAL_MAJOR 188 /* Nice legal number now */
-#define NUM_PORTS 16 /* Actually we are allowed 255, but this is good for now */
+#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
+#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
+#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+
+struct usb_serial {
+ struct usb_device * dev;
+ struct usb_serial_device_type * type;
+ void * irq_handle;
+ unsigned int irqpipe;
+ struct tty_struct * tty; /* the coresponding tty for this device */
+ unsigned char minor;
+ unsigned char num_ports; /* the number of ports this device has */
+ char active[MAX_NUM_PORTS]; /* someone has this device open */
+
+ char num_interrupt_in; /* number of interrupt in endpoints we have */
+ __u8 interrupt_in_interval[MAX_NUM_PORTS];
+ unsigned char * interrupt_in_buffer[MAX_NUM_PORTS];
+ struct urb control_urb[MAX_NUM_PORTS];
+
+ char num_bulk_in; /* number of bulk in endpoints we have */
+ unsigned char * bulk_in_buffer[MAX_NUM_PORTS];
+ struct urb read_urb[MAX_NUM_PORTS];
+
+ char num_bulk_out; /* number of bulk out endpoints we have */
+ unsigned char * bulk_out_buffer[MAX_NUM_PORTS];
+ int bulk_out_size[MAX_NUM_PORTS];
+ struct urb write_urb[MAX_NUM_PORTS];
+};
#define MUST_HAVE_NOT 0x01
@@ -127,7 +196,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
static int serial_open (struct tty_struct *tty, struct file * filp);
static void serial_close (struct tty_struct *tty, struct file * filp);
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
-static void serial_put_char (struct tty_struct *tty, unsigned char ch);
static int serial_write_room (struct tty_struct *tty);
static int serial_chars_in_buffer (struct tty_struct *tty);
static void serial_throttle (struct tty_struct * tty);
@@ -145,15 +213,15 @@ struct usb_serial_device_type {
char num_interrupt_in;
char num_bulk_in;
char num_bulk_out;
+ char num_ports; /* number of serial ports this device has */
/* function call to make before accepting driver */
- void (*startup) (void);
+ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
/* serial function calls */
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);
- void (*put_char)(struct tty_struct *tty, unsigned char ch);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
void (*throttle)(struct tty_struct * tty);
@@ -162,13 +230,14 @@ struct usb_serial_device_type {
/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
+/* need to always compile these in, as some of the other devices use these functions as their own. */
static int generic_serial_open (struct tty_struct *tty, struct file *filp);
static void generic_serial_close (struct tty_struct *tty, struct file *filp);
static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
-static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch);
static int generic_write_room (struct tty_struct *tty);
static int generic_chars_in_buffer (struct tty_struct *tty);
+#ifdef CONFIG_USB_SERIAL_GENERIC
/* All of the device info needed for the Generic Serial Converter */
static struct usb_serial_device_type generic_device = {
name: "Generic",
@@ -180,19 +249,22 @@ static struct usb_serial_device_type generic_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
open: generic_serial_open,
close: generic_serial_close,
write: generic_serial_write,
- put_char: generic_serial_put_char,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
};
+#endif
-
+#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM)
/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */
static int etek_serial_open (struct tty_struct *tty, struct file *filp);
static void etek_serial_close (struct tty_struct *tty, struct file *filp);
+#endif
+#ifdef CONFIG_USB_SERIAL_BELKIN
/* All of the device info needed for the Belkin Serial Converter */
static __u16 belkin_vendor_id = BELKIN_VENDOR_ID;
static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER;
@@ -206,14 +278,17 @@ static struct usb_serial_device_type belkin_device = {
num_interrupt_in: 1,
num_bulk_in: 1,
num_bulk_out: 1,
+ num_ports: 1,
open: etek_serial_open,
close: etek_serial_close,
write: generic_serial_write,
- put_char: generic_serial_put_char,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
};
+#endif
+
+#ifdef CONFIG_USB_SERIAL_PERACOM
/* All of the device info needed for the Peracom Serial Converter */
static __u16 peracom_vendor_id = PERACOM_VENDOR_ID;
static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER;
@@ -224,23 +299,26 @@ static struct usb_serial_device_type peracom_device = {
needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_ports: 1,
num_interrupt_in: 1,
num_bulk_in: 1,
num_bulk_out: 1,
open: etek_serial_open,
close: etek_serial_close,
write: generic_serial_write,
- put_char: generic_serial_put_char,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
};
+#endif
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp);
static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp);
static void whiteheat_throttle (struct tty_struct *tty);
static void whiteheat_unthrottle (struct tty_struct *tty);
+static int whiteheat_startup (struct usb_serial *serial);
/* All of the device info needed for the Connect Tech WhiteHEAT */
static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
@@ -256,6 +334,7 @@ static struct usb_serial_device_type whiteheat_fake_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ startup: whiteheat_startup
};
static struct usb_serial_device_type whiteheat_device = {
name: "Connect Tech - WhiteHEAT",
@@ -267,22 +346,25 @@ static struct usb_serial_device_type whiteheat_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ num_ports: 4,
open: whiteheat_serial_open,
close: whiteheat_serial_close,
write: generic_serial_write,
- put_char: generic_serial_put_char,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle
};
+#endif
+#ifdef CONFIG_USB_SERIAL_VISOR
/* function prototypes for a handspring visor */
static int visor_serial_open (struct tty_struct *tty, struct file *filp);
static void visor_serial_close (struct tty_struct *tty, struct file *filp);
static void visor_throttle (struct tty_struct *tty);
static void visor_unthrottle (struct tty_struct *tty);
+static int visor_startup (struct usb_serial *serial);
/* All of the device info needed for the Handspring Visor */
static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
@@ -297,72 +379,42 @@ static struct usb_serial_device_type handspring_device = {
num_interrupt_in: 0,
num_bulk_in: 2,
num_bulk_out: 2,
+ num_ports: 2,
open: visor_serial_open,
close: visor_serial_close,
write: generic_serial_write,
- put_char: generic_serial_put_char,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
throttle: visor_throttle,
- unthrottle: visor_unthrottle
+ unthrottle: visor_unthrottle,
+ startup: visor_startup
};
-
+#endif
/* To add support for another serial converter, create a usb_serial_device_type
structure for that device, and add it to this list, making sure that the last
entry is NULL. */
static struct usb_serial_device_type *usb_serial_devices[] = {
+#ifdef CONFIG_USB_SERIAL_GENERIC
&generic_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
&whiteheat_fake_device,
&whiteheat_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_BELKIN
&belkin_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_PERACOM
&peracom_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_VISOR
&handspring_device,
+#endif
NULL
};
-#define MAX_ENDPOINTS 8
-
-struct usb_serial_state {
- struct usb_device * dev;
- struct usb_serial_device_type * type;
- void * irq_handle;
- unsigned int irqpipe;
- struct tty_struct * tty; /* the coresponding tty for this device */
- unsigned char number;
- char present;
- char active;
-
- char num_interrupt_in; /* number of interrupt in endpoints we have */
- char interrupt_in_inuse; /* if the interrupt in endpoint is in use */
- __u8 interrupt_in_endpoint[MAX_ENDPOINTS];
- __u8 interrupt_in_interval[MAX_ENDPOINTS];
- __u16 interrupt_in_size[MAX_ENDPOINTS]; /* the size of the interrupt in endpoint */
- unsigned int interrupt_in_pipe[MAX_ENDPOINTS];
- unsigned char * interrupt_in_buffer[MAX_ENDPOINTS];
- void * interrupt_in_transfer[MAX_ENDPOINTS];
- struct urb control_urb;
-
- char num_bulk_in; /* number of bulk in endpoints we have */
- __u8 bulk_in_endpoint[MAX_ENDPOINTS];
- __u8 bulk_in_interval[MAX_ENDPOINTS];
- __u16 bulk_in_size[MAX_ENDPOINTS]; /* the size of the bulk in endpoint */
- unsigned int bulk_in_pipe[MAX_ENDPOINTS];
- unsigned char * bulk_in_buffer[MAX_ENDPOINTS];
- void * bulk_in_transfer[MAX_ENDPOINTS];
- struct urb read_urb;
-
- char num_bulk_out; /* number of bulk out endpoints we have */
- __u8 bulk_out_endpoint[MAX_ENDPOINTS];
- __u8 bulk_out_interval[MAX_ENDPOINTS];
- __u16 bulk_out_size[MAX_ENDPOINTS]; /* the size of the bulk out endpoint */
- unsigned int bulk_out_pipe[MAX_ENDPOINTS];
- unsigned char * bulk_out_buffer[MAX_ENDPOINTS];
- void * bulk_out_transfer[MAX_ENDPOINTS];
- struct urb write_urb;
-};
-
static struct usb_driver usb_serial_driver = {
"serial",
usb_serial_probe,
@@ -371,16 +423,61 @@ static struct usb_driver usb_serial_driver = {
};
static int serial_refcount;
-static struct tty_struct * serial_tty[NUM_PORTS];
-static struct termios * serial_termios[NUM_PORTS];
-static struct termios * serial_termios_locked[NUM_PORTS];
-static struct usb_serial_state serial_state_table[NUM_PORTS];
+static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
+static struct termios * serial_termios[SERIAL_TTY_MINORS];
+static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
+static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+
+
+
+#define SERIAL_PTR_EMPTY ((void *)(-1))
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
+ int i;
+ dbg("get_serial_by_minor %d", minor);
+
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i)
+ if (serial_table[i])
+ if (serial_table[i] != SERIAL_PTR_EMPTY)
+ if (serial_table[i]->minor == minor)
+ return (serial_table[i]);
+
+ return (NULL);
+}
+
+
+static struct usb_serial *get_free_serial (int num_ports, int *minor)
+{
+ struct usb_serial *serial = NULL;
+ int i;
+
+ dbg("get_free_serial %d", num_ports);
+
+ *minor = 0;
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ if (serial_table[i])
+ continue;
+ if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
+ err("Out of memory");
+ return NULL;
+ }
+ memset(serial, 0, sizeof(struct usb_serial));
+ serial_table[i] = serial;
+ *minor = i;
+ dbg("minor base = %d", *minor);
+ for (i = *minor+1; (i < num_ports) && (i < SERIAL_TTY_MINORS); ++i)
+ serial_table[i] = SERIAL_PTR_EMPTY;
+ return (serial);
+ }
+ return (NULL);
+}
static void serial_read_bulk (struct urb *urb)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)urb->context;
+ struct usb_serial *serial = (struct usb_serial *)urb->context;
struct tty_struct *tty = serial->tty;
unsigned char *data = urb->transfer_buffer;
int i;
@@ -412,7 +509,7 @@ static void serial_read_bulk (struct urb *urb)
static void serial_write_bulk (struct urb *urb)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) urb->context;
+ struct usb_serial *serial = (struct usb_serial *) urb->context;
struct tty_struct *tty = serial->tty;
dbg("serial_write_irq");
@@ -437,12 +534,12 @@ static void serial_write_bulk (struct urb *urb)
*****************************************************************************/
static int serial_open (struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial;
+ struct usb_serial *serial;
dbg("serial_open");
- /* assign a serial object to the tty pointer */
- serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start];
+ /* get the serial object associated with this tty pointer */
+ serial = get_serial_by_minor (MINOR(tty->device));
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -469,8 +566,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
static void serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
- dbg("serial_close");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("serial_close port %d", port);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -481,11 +580,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
dbg("serial->type == NULL!");
return;
}
- if (!serial->present) {
- dbg("no device registered");
- return;
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device already open");
return;
}
@@ -499,9 +594,10 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("serial_write");
+ dbg("serial_write port %d, %d byte(s)", port, count);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -512,11 +608,7 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
dbg("serial->type == NULL!");
return (-ENODEV);
}
- if (!serial->present) {
- dbg("device not registered");
- return (-EINVAL);
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device not opened");
return (-EINVAL);
}
@@ -531,44 +623,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
}
-static void serial_put_char (struct tty_struct *tty, unsigned char ch)
-{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
-
- dbg("serial_put_char");
-
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return;
- }
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return;
- }
- if (!serial->present) {
- dbg("no device registered");
- return;
- }
- if (!serial->active) {
- dbg ("device not open");
- return;
- }
-
- /* pass on to the driver specific version of this function */
- if (serial->type->put_char) {
- serial->type->put_char(tty, ch);
- }
-
- return;
-}
-
-
static int serial_write_room (struct tty_struct *tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("serial_write_room");
+ dbg("serial_write_room port %d", port);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -579,11 +639,7 @@ static int serial_write_room (struct tty_struct *tty)
dbg("serial->type == NULL!");
return (-ENODEV);
}
- if (!serial->present) {
- dbg("no device registered");
- return (-EINVAL);
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device not open");
return (-EINVAL);
}
@@ -599,9 +655,10 @@ static int serial_write_room (struct tty_struct *tty)
static int serial_chars_in_buffer (struct tty_struct *tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("serial_chars_in_buffer");
+ dbg("serial_chars_in_buffer port %d", port);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -612,11 +669,7 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
dbg("serial->type == NULL!");
return (-ENODEV);
}
- if (!serial->present) {
- dbg("no device registered");
- return (-EINVAL);
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device not open");
return (-EINVAL);
}
@@ -632,9 +685,10 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
static void serial_throttle (struct tty_struct * tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("serial_throttle");
+ dbg("serial_throttle port %d", port);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -645,11 +699,7 @@ static void serial_throttle (struct tty_struct * tty)
dbg("serial->type == NULL!");
return;
}
- if (!serial->present) {
- dbg("no device registered");
- return;
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device not open");
return;
}
@@ -665,9 +715,10 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("serial_unthrottle");
+ dbg("serial_unthrottle port %d", port);
/* do some sanity checking that we really have a device present */
if (!serial) {
@@ -678,16 +729,11 @@ static void serial_unthrottle (struct tty_struct * tty)
dbg("serial->type == NULL!");
return;
}
- if (!serial->present) {
- dbg("no device registered");
- return;
- }
- if (!serial->active) {
+ if (!serial->active[port]) {
dbg ("device not open");
return;
}
-
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle) {
serial->type->unthrottle(tty);
@@ -697,28 +743,25 @@ static void serial_unthrottle (struct tty_struct * tty)
}
+#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM)
/*****************************************************************************
* eTek specific driver functions
*****************************************************************************/
static int etek_serial_open (struct tty_struct *tty, struct file *filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("etek_serial_open");
+ dbg("etek_serial_open port %d", port);
- if (!serial->present) {
- dbg("no device registered");
- return -EINVAL;
- }
-
- if (serial->active) {
+ if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
- serial->active = 1;
+ serial->active[port] = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&serial->read_urb))
+ if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -730,41 +773,42 @@ static int etek_serial_open (struct tty_struct *tty, struct file *filp)
static void etek_serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
- dbg("etek_serial_close");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("etek_serial_close port %d", port);
/* Need to change the control lines here */
/* FIXME */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&serial->write_urb);
- usb_unlink_urb (&serial->read_urb);
- serial->active = 0;
+ usb_unlink_urb (&serial->write_urb[port]);
+ usb_unlink_urb (&serial->read_urb[port]);
+ serial->active[port] = 0;
}
+#endif /* defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) */
+
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
*****************************************************************************/
static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("whiteheat_serial_open");
+ dbg("whiteheat_serial_open port %d", port);
- if (!serial->present) {
- dbg("no device registered");
- return -EINVAL;
- }
-
- if (serial->active) {
+ if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
- serial->active = 1;
+ serial->active[port] = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&serial->read_urb))
+ if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -776,23 +820,28 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
- dbg("whiteheat_serial_close");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("whiteheat_serial_close port %d", port);
/* Need to change the control lines here */
/* FIXME */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&serial->write_urb);
- usb_unlink_urb (&serial->read_urb);
- serial->active = 0;
+ usb_unlink_urb (&serial->write_urb[port]);
+ usb_unlink_urb (&serial->read_urb[port]);
+ serial->active[port] = 0;
}
static void whiteheat_throttle (struct tty_struct * tty)
{
- dbg("whiteheat_throttle");
-
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("whiteheat_throttle port %d", port);
+
/* Change the control signals */
/* FIXME!!! */
@@ -802,8 +851,11 @@ static void whiteheat_throttle (struct tty_struct * tty)
static void whiteheat_unthrottle (struct tty_struct * tty)
{
- dbg("whiteheat_unthrottle");
-
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("whiteheat_unthrottle port %d", port);
+
/* Change the control signals */
/* FIXME!!! */
@@ -811,28 +863,131 @@ static void whiteheat_unthrottle (struct tty_struct * tty)
}
+static int whiteheat_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
+{
+ int result;
+ unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL);
+
+// dbg("whiteheat_writememory %x, %d", address, length);
+
+ if (!transfer_buffer) {
+ err("whiteheat_writememory: kmalloc(%d) failed.\n", length);
+ return -ENOMEM;
+ }
+ memcpy (transfer_buffer, data, length);
+ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+ kfree (transfer_buffer);
+ return result;
+}
+
+/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
+#define CPUCS_REG 0x7F92
+
+static int whiteheat_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+{
+ int response;
+ dbg("whiteheat_set_reset: %d", reset_bit);
+ response = whiteheat_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
+ if (response < 0) {
+ err("whiteheat_set_reset %d failed", reset_bit);
+ }
+ return (response);
+}
+
+
+/* steps to download the firmware to the WhiteHEAT device:
+ - hold the reset (by writing to the reset bit of the CPUCS register)
+ - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
+ - release the reset (by writing to the CPUCS register)
+ - download the WH.HEX file for all addresses greater than 0x1b3f using
+ VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
+ - hold the reset
+ - download the WH.HEX file for all addresses less than 0x1b40 using
+ VENDOR_REQUEST_ANCHOR_LOAD
+ - release the reset
+ - device renumerated itself and comes up as new device id with all
+ firmware download completed.
+*/
+static int whiteheat_startup (struct usb_serial *serial)
+{
+ int response;
+ const struct whiteheat_hex_record *record;
+
+ dbg("whiteheat_startup");
+
+ response = whiteheat_set_reset (serial, 1);
+
+ record = &whiteheat_loader[0];
+ while (record->address != 0xffff) {
+ response = whiteheat_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("whiteheat_writememory failed for loader (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = whiteheat_set_reset (serial, 0);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ ++record;
+ }
+ while (record->address != 0xffff) {
+ response = whiteheat_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("whiteheat_writememory failed for first firmware step (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = whiteheat_set_reset (serial, 1);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ response = whiteheat_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)\n",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = whiteheat_set_reset (serial, 0);
+
+ /* we want this device to fail to have a driver assigned to it. */
+ return (1);
+}
+#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
+
+
+#ifdef CONFIG_USB_SERIAL_VISOR
/******************************************************************************
* Handspring Visor specific driver functions
******************************************************************************/
static int visor_serial_open (struct tty_struct *tty, struct file *filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
- dbg("visor_serial_open");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- if (!serial->present) {
- dbg("no device registered");
- return -EINVAL;
- }
+ dbg("visor_serial_open port %d", port);
- if (serial->active) {
+ if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
- serial->active = 1;
+ serial->active[port] = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&serial->read_urb))
+ if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
return (0);
@@ -840,66 +995,146 @@ static int visor_serial_open (struct tty_struct *tty, struct file *filp)
static void visor_serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("USB: visor_serial_close");
+ dbg("visor_serial_close port %d", port);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&serial->write_urb);
- usb_unlink_urb (&serial->read_urb);
- serial->active = 0;
+ usb_unlink_urb (&serial->write_urb[port]);
+ usb_unlink_urb (&serial->read_urb[port]);
+ serial->active[port] = 0;
}
static void visor_throttle (struct tty_struct * tty)
{
-/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("visor_throttle");
+ dbg("visor_throttle port %d", port);
- /* Change the control signals */
- /* FIXME!!! */
+ usb_unlink_urb (&serial->read_urb[port]);
return;
}
+
static void visor_unthrottle (struct tty_struct * tty)
{
-/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("visor_unthrottle");
+ dbg("visor_unthrottle port %d", port);
- /* Change the control signals */
- /* FIXME!!! */
+ if (usb_unlink_urb (&serial->read_urb[port]))
+ dbg("usb_submit_urb(read bulk) failed");
return;
}
+/*
+ Here's the raw dump of the vendor specific command data that the Visor sends on Win98
+______________________________________________________________________
+SETUP(0xB4) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA0(0xC3) DATA(C2 03 00 00 00 00 12 00 ) CRC16(0xB0BB)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+IN(0x96) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA1(0xD2) DATA(02 00 00 01 02 02 ) CRC16(0xF4E6)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+OUT(0x87) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA1(0xD2) DATA() CRC16(0x0000)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+SETUP(0xB4) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA0(0xC3) DATA(C2 01 00 00 05 00 02 00 ) CRC16(0xC488)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+IN(0x96) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA1(0xD2) DATA(01 00 ) CRC16(0xFFFB)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+OUT(0x87) ADDR(0x02) ENDP(0x0) CRC5(0x15)
+______________________________________________________________________
+DATA1(0xD2) DATA() CRC16(0x0000)
+______________________________________________________________________
+ACK(0x4B)
+______________________________________________________________________
+*/
+
+static int visor_startup (struct usb_serial *serial)
+{
+ /* send out two unknown commands that I found by looking at a Win98 trace */
+ int response;
+ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+ err("visor_startup: kmalloc(%d) failed.\n", 256);
+ return -ENOMEM;
+ }
+
+ dbg("visor_startup");
+
+ dbg("visor_setup: Set config to 1");
+ usb_set_configuration (serial->dev, 1);
+
+ response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x03, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ if (response < 0) {
+ err("visor_startup: error getting first vendor specific message");
+ } else {
+ dbg("visor_startup: First vendor specific message successful");
+ }
+
+ response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x01, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+ if (response < 0) {
+ err("visor_startup: error getting second vendor specific message");
+ } else {
+ dbg("visor_startup: Second vendor specific message successful");
+ }
+
+ kfree (transfer_buffer);
+
+ /* continue on with initialization */
+ return (0);
+}
+
+
+#endif /* CONFIG_USB_SERIAL_VISOR*/
+
+
/*****************************************************************************
* generic devices specific driver functions
*****************************************************************************/
static int generic_serial_open (struct tty_struct *tty, struct file *filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("generic_serial_open");
+ dbg("generic_serial_open port %d", port);
- if (!serial->present) {
- dbg("no device registered");
- return -EINVAL;
- }
-
- if (serial->active) {
+ if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
- serial->active = 1;
+ serial->active[port] = 1;
/* if we have a bulk interrupt, start reading from it */
if (serial->num_bulk_in) {
/*Start reading from the device*/
- if (usb_submit_urb(&serial->read_urb))
+ if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
}
@@ -909,26 +1144,29 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp)
static void generic_serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
- dbg("generic_serial_close");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("generic_serial_close port %d", port);
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out) {
- usb_unlink_urb (&serial->write_urb);
+ usb_unlink_urb (&serial->write_urb[port]);
}
if (serial->num_bulk_in) {
- usb_unlink_urb (&serial->read_urb);
+ usb_unlink_urb (&serial->read_urb[port]);
}
- serial->active = 0;
+ serial->active[port] = 0;
}
static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
-
- dbg("generic_serial_write");
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+
+ dbg("generic_serial_write port %d", port);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -937,24 +1175,24 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (serial->write_urb.status == -EINPROGRESS) {
+ if (serial->write_urb[port].status == -EINPROGRESS) {
dbg ("already writing");
return (0);
}
- count = (count > serial->bulk_out_size[0]) ? serial->bulk_out_size[0] : count;
+ count = (count > serial->bulk_out_size[port]) ? serial->bulk_out_size[port] : count;
if (from_user) {
- copy_from_user(serial->write_urb.transfer_buffer, buf, count);
+ copy_from_user(serial->write_urb[port].transfer_buffer, buf, count);
}
else {
- memcpy (serial->write_urb.transfer_buffer, buf, count);
+ memcpy (serial->write_urb[port].transfer_buffer, buf, count);
}
/* send the data out the bulk port */
- serial->write_urb.transfer_buffer_length = count;
+ serial->write_urb[port].transfer_buffer_length = count;
- if (usb_submit_urb(&serial->write_urb))
+ if (usb_submit_urb(&serial->write_urb[port]))
dbg("usb_submit_urb(write bulk) failed");
return (count);
@@ -965,39 +1203,19 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
}
-static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch)
-{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
-
- dbg("generic_serial_put_char");
-
- /* if we have a bulk out endpoint, then shove a character out it */
- if (serial->num_bulk_out) {
- /* send the single character out the bulk port */
- memcpy (serial->write_urb.transfer_buffer, &ch, 1);
- serial->write_urb.transfer_buffer_length = 1;
-
- if (usb_submit_urb(&serial->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
-
- }
-
- return;
-}
-
-
static int generic_write_room (struct tty_struct *tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
int room;
- dbg("generic_write_room");
+ dbg("generic_write_room port %d", port);
if (serial->num_bulk_out) {
- if (serial->write_urb.status == -EINPROGRESS)
+ if (serial->write_urb[port].status == -EINPROGRESS)
room = 0;
else
- room = serial->bulk_out_size[0];
+ room = serial->bulk_out_size[port];
dbg("generic_write_room returns %d", room);
return (room);
}
@@ -1008,13 +1226,14 @@ static int generic_write_room (struct tty_struct *tty)
static int generic_chars_in_buffer (struct tty_struct *tty)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+ struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
- dbg("generic_chars_in_buffer");
+ dbg("generic_chars_in_buffer port %d", port);
if (serial->num_bulk_out) {
- if (serial->write_urb.status == -EINPROGRESS) {
- return (serial->bulk_out_size[0]);
+ if (serial->write_urb[port].status == -EINPROGRESS) {
+ return (serial->bulk_out_size[port]);
}
}
@@ -1022,29 +1241,18 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
-static int Get_Free_Serial (void)
-{
- int i;
-
- for (i=0; i < NUM_PORTS; ++i) {
- if (!serial_state_table[i].present)
- return (i);
- }
- return (-1);
-}
-
-
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
- struct usb_serial_state *serial = NULL;
+ struct usb_serial *serial = NULL;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
- struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_ENDPOINTS];
- struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_ENDPOINTS];
- struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_ENDPOINTS];
+ struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_device_type *type;
int device_num;
- int serial_num;
+ int minor;
+ int buffer_size;
int i;
char interrupt_pipe;
char bulk_in_pipe;
@@ -1109,83 +1317,69 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
/* found all that we need */
info("%s converter detected", type->name);
- if (0>(serial_num = Get_Free_Serial())) {
- dbg("Too many devices connected");
+ serial = get_free_serial (type->num_ports, &minor);
+ if (serial == NULL) {
+ err("No more free serial devices");
return NULL;
}
- serial = &serial_state_table[serial_num];
-
- memset(serial, 0, sizeof(struct usb_serial_state));
serial->dev = dev;
serial->type = type;
- serial->number = serial_num;
+ serial->minor = minor;
+ serial->num_ports = type->num_ports;
serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
+ /* if this device type has a startup function, call it */
+ if (type->startup) {
+ if (type->startup (serial))
+ return NULL;
+ }
+
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
- serial->bulk_in_endpoint[i] = bulk_in_endpoint[i]->bEndpointAddress;
- serial->bulk_in_size[i] = bulk_in_endpoint[i]->wMaxPacketSize;
- serial->bulk_in_interval[i] = bulk_in_endpoint[i]->bInterval;
- serial->bulk_in_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[i]);
- serial->bulk_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL);
+ buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
+ serial->bulk_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL);
if (!serial->bulk_in_buffer[i]) {
err("Couldn't allocate bulk_in_buffer");
goto probe_error;
}
+ FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ serial->bulk_in_buffer[i], buffer_size, serial_read_bulk, serial);
}
- if (num_bulk_in)
- FILL_BULK_URB(&serial->read_urb, dev, usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[0]),
- serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_read_bulk, serial);
for (i = 0; i < num_bulk_out; ++i) {
- serial->bulk_out_endpoint[i] = bulk_out_endpoint[i]->bEndpointAddress;
serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize;
- serial->bulk_out_interval[i] = bulk_out_endpoint[i]->bInterval;
- serial->bulk_out_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint[i]);
serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL);
if (!serial->bulk_out_buffer[i]) {
err("Couldn't allocate bulk_out_buffer");
goto probe_error;
}
+ FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial_write_bulk, serial);
}
- if (num_bulk_out)
- FILL_BULK_URB(&serial->write_urb, dev, usb_sndbulkpipe (dev, serial->bulk_in_endpoint[0]),
- serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_write_bulk, serial);
+#if 0 /* use this code when WhiteHEAT is up and running */
for (i = 0; i < num_interrupt_in; ++i) {
- serial->interrupt_in_inuse = 0;
- serial->interrupt_in_endpoint[i] = interrupt_in_endpoint[i]->bEndpointAddress;
- serial->interrupt_in_size[i] = interrupt_in_endpoint[i]->wMaxPacketSize;
- serial->interrupt_in_interval[i] = interrupt_in_endpoint[i]->bInterval;
- /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */
- serial->interrupt_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL);
+ buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+ serial->interrupt_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL);
if (!serial->interrupt_in_buffer[i]) {
err("Couldn't allocate interrupt_in_buffer");
goto probe_error;
}
+ FILL_INT_URB(&serial->control_urb[i], dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
+ serial->interrupt_in_buffer[i], buffer_size, serial_control_irq,
+ serial, interrupt_in_endpoint[i]->bInterval);
}
+#endif
- #if 0
- /* set up an interrupt for out bulk in pipe */
- /* ask for a bulk read */
- serial->bulk_in_inuse = 1;
- serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
-
- /* set up our interrupt to be the time for the bulk in read */
- ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle);
- if (ret) {
- info("failed usb_request_irq (0x%x)", ret);
- goto probe_error;
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
}
- #endif
- serial->present = 1;
MOD_INC_USE_COUNT;
- info("%s converter now attached to ttyUSB%d", type->name, serial_num);
return serial;
} else {
info("descriptors matched, but endpoints did not");
@@ -1214,19 +1408,16 @@ probe_error:
static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_serial_state *serial = (struct usb_serial_state *) ptr;
+ struct usb_serial *serial = (struct usb_serial *) ptr;
int i;
if (serial) {
- if (!serial->present) {
- /* something strange is going on */
- dbg("disconnect but not present?");
- return;
- }
-
/* need to stop any transfers...*/
- usb_unlink_urb (&serial->write_urb);
- usb_unlink_urb (&serial->read_urb);
+ for (i = 0; i < serial->num_ports; ++i) {
+ usb_unlink_urb (&serial->write_urb[i]);
+ usb_unlink_urb (&serial->read_urb[i]);
+ serial->active[i] = 0;
+ }
/* free up any memory that we allocated */
for (i = 0; i < serial->num_bulk_in; ++i)
@@ -1239,17 +1430,18 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
if (serial->interrupt_in_buffer[i])
kfree (serial->interrupt_in_buffer[i]);
- serial->present = 0;
- serial->active = 0;
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+ }
- info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->number);
+ serial_table[serial->minor] = NULL;
+ kfree (serial);
} else {
info("device disconnected");
}
MOD_DEC_USE_COUNT;
-
}
@@ -1257,9 +1449,9 @@ static struct tty_driver serial_tty_driver = {
magic: TTY_DRIVER_MAGIC,
driver_name: "usb",
name: "ttyUSB",
- major: SERIAL_MAJOR,
+ major: SERIAL_TTY_MAJOR,
minor_start: 0,
- num: NUM_PORTS,
+ num: SERIAL_TTY_MINORS,
type: TTY_DRIVER_TYPE_SERIAL,
subtype: SERIAL_TYPE_NORMAL,
flags: TTY_DRIVER_REAL_RAW,
@@ -1273,7 +1465,7 @@ static struct tty_driver serial_tty_driver = {
open: serial_open,
close: serial_close,
write: serial_write,
- put_char: serial_put_char,
+ put_char: NULL,
flush_chars: NULL,
write_room: serial_write_room,
ioctl: NULL,
@@ -1298,8 +1490,8 @@ int usb_serial_init(void)
int i;
/* Initalize our global data */
- for (i = 0; i < NUM_PORTS; ++i) {
- memset(&serial_state_table[i], 0x00, sizeof(struct usb_serial_state));
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ serial_table[i] = NULL;
}
/* register the tty driver */
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 2c75fb86b..6b02641a9 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -39,8 +39,8 @@ static void usb_check_support(struct usb_device *);
/*
* We have a per-interface "registered driver" list.
*/
-static LIST_HEAD(usb_driver_list);
-static LIST_HEAD(usb_bus_list);
+LIST_HEAD(usb_driver_list);
+LIST_HEAD(usb_bus_list);
static struct usb_busmap busmap;
@@ -240,6 +240,7 @@ struct usb_bus *usb_alloc_bus(struct usb_operations *op)
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD(&bus->bus_list);
+ INIT_LIST_HEAD(&bus->inodes);
return bus;
}
@@ -263,11 +264,11 @@ void usb_register_bus(struct usb_bus *bus)
} else
warn("too many buses");
- proc_usb_add_bus(bus);
-
/* Add it to the list of buses */
list_add(&bus->bus_list, &usb_bus_list);
+ usbdevfs_add_bus(bus);
+
info("new USB bus registered, assigned bus number %d", bus->busnum);
}
@@ -282,7 +283,7 @@ void usb_deregister_bus(struct usb_bus *bus)
*/
list_del(&bus->bus_list);
- proc_usb_remove_bus(bus);
+ usbdevfs_remove_bus(bus);
clear_bit(bus->busnum, busmap.busmap);
}
@@ -443,6 +444,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
dev->bus = bus;
dev->parent = parent;
atomic_set(&dev->refcnt, 1);
+ INIT_LIST_HEAD(&dev->inodes);
+ INIT_LIST_HEAD(&dev->filelist);
dev->bus->op->allocate(dev);
@@ -559,9 +562,10 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, unsigned long* rval)
return status;
}
- if (urb->status == -EINPROGRESS)
- status=schedule_timeout(timeout); // ZZzzzz....
- else
+ if (urb->status == -EINPROGRESS) {
+ while (timeout && urb->status == -EINPROGRESS)
+ status = timeout = schedule_timeout(timeout);
+ } else
status = 1;
remove_wait_queue(&wqh, &wait);
@@ -646,8 +650,6 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
{
urb_t *urb;
- DECLARE_WAITQUEUE(wait, current);
- DECLARE_WAIT_QUEUE_HEAD(wqh);
api_wrapper_data *awd;
if (!(urb=usb_alloc_urb(0)))
@@ -1154,11 +1156,6 @@ void usb_destroy_configuration(struct usb_device *dev)
kfree(cf->interface);
}
kfree(dev->config);
-
- if (dev->string) {
- kfree(dev->string);
- dev->string = 0;
- }
}
void usb_init_root_hub(struct usb_device *dev)
@@ -1229,7 +1226,7 @@ void usb_disconnect(struct usb_device **pdev)
}
/* remove /proc/bus/usb entry */
- proc_usb_remove_device(dev);
+ usbdevfs_remove_device(dev);
/* Free up the device itself, including its device number */
if (dev->devnum > 0)
@@ -1290,7 +1287,7 @@ int usb_get_class_descriptor(struct usb_device *dev, unsigned char type,
unsigned char id, unsigned char index, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_DESCRIPTOR, USB_RT_INTERFACE | USB_DIR_IN,
+ USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
(type << 8) + id, index, buf, size, HZ * GET_TIMEOUT);
}
@@ -1326,7 +1323,7 @@ int usb_get_protocol(struct usb_device *dev)
int ret;
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_PROTOCOL, USB_DIR_IN | USB_RT_HIDD,
+ USB_REQ_GET_PROTOCOL, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, 1, &type, 1, HZ * GET_TIMEOUT)) < 0)
return ret;
@@ -1336,13 +1333,15 @@ int usb_get_protocol(struct usb_device *dev)
int usb_set_protocol(struct usb_device *dev, int protocol)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_PROTOCOL, USB_RT_HIDD, protocol, 1, NULL, 0, HZ * SET_TIMEOUT);
+ USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ protocol, 1, NULL, 0, HZ * SET_TIMEOUT);
}
int usb_set_idle(struct usb_device *dev, int duration, int report_id)
{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_IDLE,
- USB_RT_HIDD, (duration << 8) | report_id, 1, NULL, 0, HZ * SET_TIMEOUT);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (duration << 8) | report_id, 1, NULL, 0, HZ * SET_TIMEOUT);
}
static void usb_set_maxpacket(struct usb_device *dev)
@@ -1385,14 +1384,14 @@ int usb_clear_halt(struct usb_device *dev, int endp)
*/
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RT_ENDPOINT, 0, endp, NULL, 0, HZ * SET_TIMEOUT);
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, HZ * SET_TIMEOUT);
/* don't clear if failed */
if (result < 0)
return result;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_ENDPOINT, 0, endp,
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
&status, sizeof(status), HZ * SET_TIMEOUT);
if (result < 0)
return result;
@@ -1426,7 +1425,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
}
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_INTERFACE, USB_RT_INTERFACE, alternate,
+ USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
interface, NULL, 0, HZ * 5)) < 0)
return ret;
@@ -1466,14 +1465,14 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_REPORT, USB_DIR_IN | USB_RT_HIDD,
+ USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, index, buf, size, HZ * GET_TIMEOUT);
}
int usb_set_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_REPORT, USB_RT_HIDD,
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, index, buf, size, HZ);
}
@@ -1491,6 +1490,11 @@ int usb_get_configuration(struct usb_device *dev)
return -1;
}
+ if (dev->descriptor.bNumConfigurations < 1) {
+ warn("not enough configurations");
+ return -1;
+ }
+
dev->config = (struct usb_config_descriptor *)
kmalloc(dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor), GFP_KERNEL);
@@ -1547,54 +1551,45 @@ int usb_get_configuration(struct usb_device *dev)
return result;
}
-char *usb_string(struct usb_device *dev, int index)
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
- int i, len, ret;
- char *ptr;
- union {
- unsigned char buffer[256];
- struct usb_string_descriptor desc;
- } u;
-
- if (index <= 0)
- return 0;
- if (dev->string)
- kfree (dev->string);
-
- if (dev->string_langid == 0) {
- /* read string descriptor 0 */
- ret = usb_get_string(dev, 0, 0, u.buffer, 4);
- if (ret >= 0 && u.desc.bLength >= 4)
- dev->string_langid = le16_to_cpup(&u.desc.wData[0]);
- else
- err("error getting string");
- dev->string_langid |= 0x10000; /* so it's non-zero */
- }
+ unsigned char *tbuf;
+ int err;
+ unsigned int u, idx;
- if (usb_get_string(dev, dev->string_langid, index, u.buffer, 4) < 0 ||
- ((ret = usb_get_string(dev, dev->string_langid, index, u.buffer,
- u.desc.bLength)) < 0)) {
- err("error retrieving string");
- return NULL;
- }
-
- if (ret > 0) ret /= 2; /* going from 16-bit chars to 8-bit */
- len = u.desc.bLength / 2; /* includes terminating null */
- /* after removing bLength & bDescType */
- if (ret < len) len = ret; /* use min of (ret, len) */
-
- ptr = kmalloc(len, GFP_KERNEL);
- if (!ptr) {
- err("couldn't allocate memory for string");
- return NULL;
+ if (size <= 0 || !buf)
+ return -EINVAL;
+ buf[0] = 0;
+ tbuf = kmalloc(256, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+ /*
+ * is this two step process necessary? can't we just
+ * ask for a maximum length string and then take the length
+ * that was returned?
+ */
+ err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
+ if (err < 0)
+ goto errout;
+ err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]);
+ if (err < 0)
+ goto errout;
+ size--;
+ for (idx = 0, u = 2; u < tbuf[0]; u += 2) {
+ if (idx >= size)
+ break;
+ if (tbuf[u+1]) {
+ buf[idx++] = '?'; /* non ASCII character */
+ continue;
+ }
+ buf[idx++] = tbuf[u];
}
+ buf[idx] = 0;
+ err = idx;
- for (i = 0; i < len - 1; ++i)
- ptr[i] = le16_to_cpup(&u.desc.wData[i]);
- ptr[i] = 0;
-
- dev->string = ptr;
- return ptr;
+ errout:
+ kfree(tbuf);
+ return err;
}
/*
@@ -1606,10 +1601,10 @@ char *usb_string(struct usb_device *dev, int index)
*/
int usb_new_device(struct usb_device *dev)
{
+ unsigned char *buf;
int addr, err;
- info("USB new device connect, assigned device number %d",
- dev->devnum);
+ info("USB new device connect, assigned device number %d", dev->devnum);
dev->maxpacketsize = 0; /* Default to 8 byte max packet size */
dev->epmaxpacketin [0] = 8;
@@ -1657,8 +1652,7 @@ int usb_new_device(struct usb_device *dev)
return 1;
}
- err=usb_get_configuration(dev);
-
+ err = usb_get_configuration(dev);
if (err < 0) {
err("unable to get configuration (error=%d)", err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
@@ -1674,13 +1668,28 @@ int usb_new_device(struct usb_device *dev)
err("failed to set default configuration");
return -1;
}
+ /* get langid for strings */
+ buf = kmalloc(256, GFP_KERNEL);
+ if (!buf) {
+ err("out of memory\n");
+ } else {
+ err = usb_get_string(dev, 0, 0, buf, 4);
+ if (err < 0) {
+ err("error getting string descriptor 0 (error=%d)\n", err);
+ } else if (buf[0] < 4) {
+ err("string descriptpr 0 too short\n");
+ } else
+ dev->string_langid = buf[2] | (buf[3]<< 8);
+ kfree(buf);
+ info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid);
+ }
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
usb_show_string(dev, "Product", dev->descriptor.iProduct);
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
/* now that the basic setup is over, add a /proc/bus/usb entry */
- proc_usb_add_device(dev);
+ usbdevfs_add_device(dev);
/* find drivers willing to handle this device */
usb_find_drivers(dev);
@@ -1771,6 +1780,7 @@ EXPORT_SYMBOL(usb_set_address);
EXPORT_SYMBOL(usb_get_descriptor);
EXPORT_SYMBOL(usb_get_class_descriptor);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
+EXPORT_SYMBOL(usb_get_device_descriptor);
EXPORT_SYMBOL(usb_get_string);
EXPORT_SYMBOL(usb_string);
EXPORT_SYMBOL(usb_get_protocol);
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index 15bf6a664..c6f52047b 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -21,6 +21,28 @@
#define USB_CLASS_VENDOR_SPEC 0xff
/*
+ * USB types
+ */
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+/*
+ * USB recipients
+ */
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * USB directions
+ */
+#define USB_DIR_OUT 0
+#define USB_DIR_IN 0x80
+
+/*
* Descriptor types
*/
#define USB_DT_DEVICE 0x01
@@ -29,10 +51,10 @@
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
-#define USB_DT_HUB 0x29
-#define USB_DT_HID 0x21
-#define USB_DT_REPORT 0x22
-#define USB_DT_PHYSICAL 0x23
+#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
+#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
+#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
+#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
/*
* Descriptor sizes per descriptor type
@@ -46,11 +68,8 @@
#define USB_DT_HID_SIZE 9
/*
- * USB Request Type and Endpoint Directions
+ * Endpoints
*/
-#define USB_DIR_OUT 0
-#define USB_DIR_IN 0x80
-
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
@@ -72,9 +91,7 @@
*/
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
-/* 0x02 is reserved */
#define USB_REQ_SET_FEATURE 0x03
-/* 0x04 is reserved */
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
@@ -85,7 +102,7 @@
#define USB_REQ_SYNCH_FRAME 0x0C
/*
- * HIDD requests
+ * HID requests
*/
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
@@ -94,79 +111,6 @@
#define USB_REQ_SET_IDLE 0x0A
#define USB_REQ_SET_PROTOCOL 0x0B
-#define USB_TYPE_STANDARD (0x00 << 5)
-#define USB_TYPE_CLASS (0x01 << 5)
-#define USB_TYPE_VENDOR (0x02 << 5)
-#define USB_TYPE_RESERVED (0x03 << 5)
-
-#define USB_RECIP_DEVICE 0x00
-#define USB_RECIP_INTERFACE 0x01
-#define USB_RECIP_ENDPOINT 0x02
-#define USB_RECIP_OTHER 0x03
-
-#define USB_HID_RPT_INPUT 0x01
-#define USB_HID_RPT_OUTPUT 0x02
-#define USB_HID_RPT_FEATURE 0x03
-
-/*
- * Request target types.
- */
-#define USB_RT_DEVICE 0x00
-#define USB_RT_INTERFACE 0x01
-#define USB_RT_ENDPOINT 0x02
-
-#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
-#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
-
-#define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-
-/* /proc/bus/usb/xxx/yyy ioctl codes */
-
-struct usb_proc_ctrltransfer {
- __u8 requesttype;
- __u8 request;
- __u16 value;
- __u16 index;
- __u16 length;
- __u32 timeout; /* in milliseconds */
- void *data;
-};
-
-struct usb_proc_bulktransfer {
- unsigned int ep;
- unsigned int len;
- unsigned int timeout; /* in milliseconds */
- void *data;
-};
-
-struct usb_proc_old_ctrltransfer {
- __u8 requesttype;
- __u8 request;
- __u16 value;
- __u16 index;
- __u16 length;
- /* pointer to data */
- void *data;
-};
-
-struct usb_proc_old_bulktransfer {
- unsigned int ep;
- unsigned int len;
- void *data;
-};
-
-struct usb_proc_setinterface {
- unsigned int interface;
- unsigned int altsetting;
-};
-
-#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer)
-#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer)
-#define USB_PROC_OLD_CONTROL _IOWR('U', 0, struct usb_proc_old_ctrltransfer)
-#define USB_PROC_OLD_BULK _IOWR('U', 2, struct usb_proc_old_bulktransfer)
-#define USB_PROC_RESETEP _IOR('U', 3, unsigned int)
-#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface)
-#define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int)
#ifdef __KERNEL__
@@ -227,9 +171,10 @@ typedef struct {
__u16 length;
} devrequest __attribute__ ((packed));
-/* USB-status codes:
+/*
+ * USB-status codes:
* USB_ST* maps to -E* and should go away in the future
-*/
+ */
#define USB_ST_NOERROR 0
#define USB_ST_CRC (-EILSEQ)
@@ -318,22 +263,6 @@ struct usb_endpoint_descriptor {
int extralen;
} __attribute__ ((packed));
-/* HID descriptor */
-struct usb_hid_class_descriptor {
- __u8 bDescriptorType;
- __u16 wDescriptorLength;
-} __attribute__ ((packed));
-
-struct usb_hid_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u16 bcdHID;
- __u8 bCountryCode;
- __u8 bNumDescriptors;
-
- struct usb_hid_class_descriptor desc[1];
-} __attribute__ ((packed));
-
/* Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
@@ -548,8 +477,8 @@ struct usb_bus {
int bandwidth_int_reqs; /* number of Interrupt requesters */
int bandwidth_isoc_reqs; /* number of Isoc. requesters */
- /* procfs entry */
- struct proc_dir_entry *proc_entry;
+ /* usbdevfs inode list */
+ struct list_head inodes;
};
#define USB_MAXCHILDREN (8) /* This is arbitrary */
@@ -574,13 +503,13 @@ struct usb_device {
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
- char *string; /* pointer to the last string read from the device */
int string_langid; /* language ID for strings */
void *hcpriv; /* Host Controller private data */
- /* procfs entry */
- struct proc_dir_entry *proc_entry;
+ /* usbdevfs inode list */
+ struct list_head inodes;
+ struct list_head filelist;
/*
* Child devices - these can be either new devices
@@ -746,7 +675,7 @@ int usb_get_report(struct usb_device *dev, unsigned char type,
unsigned char id, unsigned char index, void *buf, int size);
int usb_set_report(struct usb_device *dev, unsigned char type,
unsigned char id, unsigned char index, void *buf, int size);
-char *usb_string(struct usb_device *dev, int index);
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
int usb_clear_halt(struct usb_device *dev, int endp);
#define usb_get_extra_descriptor(ifpoint,type,ptr)\
@@ -778,36 +707,56 @@ int usb_clear_halt(struct usb_device *dev, int endp);
void usb_show_device_descriptor(struct usb_device_descriptor *);
void usb_show_config_descriptor(struct usb_config_descriptor *);
void usb_show_interface_descriptor(struct usb_interface_descriptor *);
-void usb_show_hid_descriptor(struct usb_hid_descriptor * desc);
void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
void usb_show_device(struct usb_device *);
void usb_show_string(struct usb_device *dev, char *id, int index);
#ifdef DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n", ## arg)
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
#else
-#define dbg(format, arg...)
+#define dbg(format, arg...) do {} while (0)
#endif
-#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n", ## arg)
-#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n", ## arg)
-#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n", ## arg)
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
/*
- * procfs stuff
+ * bus and driver list
*/
-#ifdef CONFIG_USB_PROC
-void proc_usb_add_bus(struct usb_bus *bus);
-void proc_usb_remove_bus(struct usb_bus *bus);
-void proc_usb_add_device(struct usb_device *dev);
-void proc_usb_remove_device(struct usb_device *dev);
-#else
-extern inline void proc_usb_add_bus(struct usb_bus *bus) {}
-extern inline void proc_usb_remove_bus(struct usb_bus *bus) {}
-extern inline void proc_usb_add_device(struct usb_device *dev) {}
-extern inline void proc_usb_remove_device(struct usb_device *dev) {}
-#endif
+extern struct list_head usb_driver_list;
+extern struct list_head usb_bus_list;
+
+/*
+ * USB device fs stuff
+ */
+
+#ifdef CONFIG_USB_DEVICEFS
+
+/*
+ * these are expected to be called from the USB core/hub thread
+ * with the kernel lock held
+ */
+extern void usbdevfs_add_bus(struct usb_bus *bus);
+extern void usbdevfs_remove_bus(struct usb_bus *bus);
+extern void usbdevfs_add_device(struct usb_device *dev);
+extern void usbdevfs_remove_device(struct usb_device *dev);
+
+extern int usbdevfs_init(void);
+extern void usbdevfs_cleanup(void);
+
+#else /* CONFIG_USB_DEVICEFS */
+
+extern inline void usbdevfs_add_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_add_device(struct usb_device *dev) {}
+extern inline void usbdevfs_remove_device(struct usb_device *dev) {}
+
+extern inline int usbdevfs_init(void) { return 0; }
+extern inline void usbdevfs_cleanup(void) { }
+
+#endif /* CONFIG_USB_DEVICEFS */
#endif /* __KERNEL__ */
diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c
index e1713ed12..885cdac77 100644
--- a/drivers/usb/usb_scsi.c
+++ b/drivers/usb/usb_scsi.c
@@ -288,7 +288,7 @@ static int pop_CB_reset(struct us_data *us)
cmd[0] = SEND_DIAGNOSTIC;
cmd[1] = 4;
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
+ US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, cmd, sizeof(cmd), HZ*5);
/* long wait for reset */
@@ -346,7 +346,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
} /* switch */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
+ US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum,
cmd, us->fixedlength, HZ*5);
US_DEBUGP("First usb_control_msg returns %d\n", result);
@@ -367,7 +367,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RT_INTERFACE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum,
cmd, us->fixedlength, HZ*5);
US_DEBUGP("Next usb_control_msg returns %d\n", result);
@@ -378,7 +378,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
}
} else { /* !US_FL_FIXED_COMMAND */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
+ US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum,
srb->cmnd, srb->cmd_len, HZ*5);
}
@@ -411,7 +411,7 @@ static int pop_CB_status(Scsi_Cmnd *srb)
while (retry--) {
result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0),
USB_REQ_GET_STATUS, USB_DIR_IN |
- USB_TYPE_STANDARD | USB_RT_DEVICE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE,
0, us->ifnum, status, sizeof(status), HZ*5);
if (result != USB_ST_TIMEOUT)
break;
@@ -517,7 +517,7 @@ static int pop_Bulk_reset(struct us_data *us)
int result;
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_BULK_RESET, USB_TYPE_CLASS | USB_RT_INTERFACE,
+ US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
US_BULK_RESET_HARD, us->ifnum,
NULL, 0, HZ*5);
if (result)
@@ -770,24 +770,24 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
SPRINTF ("Host scsi%d: usb-scsi\n", hostno);
/* print product and vendor strings */
- if (!us->pusb_dev) {
+ tmp_ptr = kmalloc(256, GFP_KERNEL);
+ if (!us->pusb_dev || !tmp_ptr) {
SPRINTF("Vendor: Unknown Vendor\n");
SPRINTF("Product: Unknown Product\n");
} else {
SPRINTF("Vendor: ");
- tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer);
- if (!tmp_ptr)
- SPRINTF("Unknown Vendor\n");
- else
+ if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
SPRINTF("%s\n", tmp_ptr);
+ else
+ SPRINTF("Unknown Vendor\n");
SPRINTF("Product: ");
- tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct);
- if (!tmp_ptr)
- SPRINTF("Unknown Vendor\n");
- else
+ if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
SPRINTF("%s\n", tmp_ptr);
+ else
+ SPRINTF("Unknown Vendor\n");
}
+ kfree(tmp_ptr);
SPRINTF("Protocol: ");
switch (us->protocol) {
@@ -1196,9 +1196,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
int i;
- char *mf; /* manufacturer */
- char *prod; /* product */
- char *serial; /* serial number */
+ char mf[32]; /* manufacturer */
+ char prod[32]; /* product */
+ char serial[32]; /* serial number */
struct us_data *ss = NULL;
unsigned int flags = 0;
GUID(guid); /* Global Unique Identifier */
@@ -1211,9 +1211,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* clear the GUID and fetch the strings */
GUID_CLEAR(guid);
- mf = usb_string(dev, dev->descriptor.iManufacturer);
- prod = usb_string(dev, dev->descriptor.iProduct);
- serial = usb_string(dev, dev->descriptor.iSerialNumber);
+ usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
+ usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
+ usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
/* let's examine the device now */
@@ -1234,12 +1234,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("USB Mass Storage device detected\n");
/* Create a GUID for this device */
- if (dev->descriptor.iSerialNumber &&
- usb_string(dev, dev->descriptor.iSerialNumber) ) {
+ if (dev->descriptor.iSerialNumber && serial[0]) {
/* If we have a serial number, and it's a non-NULL string */
make_guid(guid, dev->descriptor.idVendor,
dev->descriptor.idProduct,
- usb_string(dev, dev->descriptor.iSerialNumber));
+ serial);
} else {
/* We don't have a serial number, so we use 0 */
make_guid(guid, dev->descriptor.idVendor,
diff --git a/drivers/usb/usbdevice_fs.h b/drivers/usb/usbdevice_fs.h
new file mode 100644
index 000000000..a4bd5d154
--- /dev/null
+++ b/drivers/usb/usbdevice_fs.h
@@ -0,0 +1,168 @@
+/*****************************************************************************/
+
+/*
+ * usbdevice_fs.h -- USB device file system.
+ *
+ * Copyright (C) 2000
+ * Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ * History:
+ * 0.1 04.01.2000 Created
+ *
+ * $Id: usbdevice_fs.h,v 1.1 2000/01/06 18:40:41 tom Exp $
+ */
+
+/*****************************************************************************/
+
+#ifndef _LINUX_USBDEVICE_FS_H
+#define _LINUX_USBDEVICE_FS_H
+
+/* --------------------------------------------------------------------- */
+
+#define USBDEVICE_SUPER_MAGIC 0x9fa2
+
+/* usbdevfs ioctl codes */
+
+struct usbdevfs_ctrltransfer {
+ __u8 requesttype;
+ __u8 request;
+ __u16 value;
+ __u16 index;
+ __u16 length;
+ __u32 timeout; /* in milliseconds */
+ void *data;
+};
+
+struct usbdevfs_bulktransfer {
+ unsigned int ep;
+ unsigned int len;
+ unsigned int timeout; /* in milliseconds */
+ void *data;
+};
+
+struct usbdevfs_setinterface {
+ unsigned int interface;
+ unsigned int altsetting;
+};
+
+struct usbdevfs_disconnectsignal {
+ unsigned int signr;
+ void *context;
+};
+
+#define USBDEVFS_URB_DISABLE_SPD 1
+#define USBDEVFS_URB_ISO_ASAP 2
+
+#define USBDEVFS_URB_TYPE_ISO 0
+#define USBDEVFS_URB_TYPE_INTERRUPT 1
+#define USBDEVFS_URB_TYPE_CONTROL 2
+#define USBDEVFS_URB_TYPE_BULK 3
+
+struct usbdevfs_iso_packet_desc {
+ unsigned int length;
+ unsigned int actual_length;
+ unsigned int status;
+};
+
+struct usbdevfs_urb {
+ unsigned char type;
+ unsigned char endpoint;
+ int status;
+ unsigned int flags;
+ void *buffer;
+ int buffer_length;
+ int actual_length;
+ int start_frame;
+ int number_of_packets;
+ int error_count;
+ unsigned int signr; /* signal to be sent on error, -1 if none should be sent */
+ void *usercontext;
+ struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)
+#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface)
+#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
+#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_DISCARDURB _IO('U', 11)
+#define USBDEVFS_REAPURB _IOW('U', 12, void *)
+#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)
+#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
+#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
+
+/* --------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+/*
+ * inode number macros
+ */
+#define ITYPE(x) ((x)&(0xf<<28))
+#define ISPECIAL (0<<28)
+#define IBUS (1<<28)
+#define IDEVICE (2<<28)
+#define IBUSNR(x) (((x)>>8)&0xff)
+#define IDEVNR(x) ((x)&0xff)
+
+#define IROOT 1
+
+/*
+ * sigh. rwsemaphores do not (yet) work from modules
+ */
+
+#define rw_semaphore semaphore
+#define init_rwsem init_MUTEX
+#define down_read down
+#define down_write down
+#define up_read up
+#define up_write up
+
+
+struct dev_state {
+ struct list_head list; /* state list */
+ struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */
+ struct usb_device *dev;
+ struct file *file;
+ spinlock_t lock; /* protects the async urb lists */
+ struct list_head async_pending;
+ struct list_head async_completed;
+ wait_queue_head_t wait; /* wake up if a request completed */
+ unsigned int discsignr;
+ struct task_struct *disctask;
+ void *disccontext;
+ unsigned long ifclaimed;
+};
+
+/* internal methods & data */
+extern struct usb_driver usbdevfs_driver;
+extern struct file_operations usbdevfs_drivers_fops;
+extern struct file_operations usbdevfs_devices_fops;
+extern struct inode_operations usbdevfs_device_inode_operations;
+extern void usbdevfs_conn_disc_event(void);
+
+
+#endif /* __KERNEL__ */
+
+/* --------------------------------------------------------------------- */
+#endif /* _LINUX_USBDEVICE_FS_H */
diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
index c85ac5fec..26de45a38 100644
--- a/drivers/usb/usbkbd.c
+++ b/drivers/usb/usbkbd.c
@@ -99,19 +99,28 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i
if (type != EV_LED) return -1;
+ if (kbd->led.status == -EINPROGRESS) {
+ warn("had to kill led urb");
+ usb_unlink_urb(&kbd->led);
+ }
+
kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
-
- usb_submit_urb(&kbd->led);
- return -1;
+
+ if (usb_submit_urb(&kbd->led)) {
+ err("usb_submit_urb(leds) failed");
+ return -1;
+ }
+
+ return 0;
}
static void usb_kbd_led(struct urb *urb)
{
if (urb->status)
- printk(KERN_DEBUG "nonzero control status received: %d\n", urb->status);
+ warn("led urb status %d received", urb->status);
}
static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
@@ -148,12 +157,6 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
kbd->dev.private = kbd;
kbd->dev.event = usb_kbd_event;
- kbd->dr.requesttype = USB_RT_HIDD;
- kbd->dr.request = USB_REQ_SET_REPORT;
- kbd->dr.value = 0x200;
- kbd->dr.index = 1;
- kbd->dr.length = 1;
-
{
int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
@@ -162,7 +165,13 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
usb_kbd_irq, kbd, endpoint->bInterval);
}
- FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, endpoint->bEndpointAddress),
+ kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kbd->dr.request = USB_REQ_SET_REPORT;
+ kbd->dr.value = 0x200;
+ kbd->dr.index = interface->bInterfaceNumber;
+ kbd->dr.length = 1;
+
+ FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
if (usb_submit_urb(&kbd->irq)) {
diff --git a/drivers/usb/whiteheat.h b/drivers/usb/whiteheat.h
new file mode 100644
index 000000000..d7053e337
--- /dev/null
+++ b/drivers/usb/whiteheat.h
@@ -0,0 +1,1542 @@
+/*****************************************************************************
+ *
+ * whiteheat.h -- ConnectTech WhiteHEAT Firmware.
+ *
+ * Copyright (C) 2000 ConnectTech Inc (http://www.connecttech.com/)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * (01/16/2000) gkh
+ * Fixed my intel hex processing tool, so now the firmware actually
+ * matches the original file (this was causing a few problems...)
+ *
+ * (01/15/2000) gkh
+ * Added debug loader firmware if DEBUG is #defined:
+ * Port 1 LED flashes when the vend_ax program is running
+ * Port 2 LED flashes when any SETUP command arrives
+ * Port 3 LED flashes when any valid VENDOR request occurs
+ * Port 4 LED flashes when the EXTERNAL RAM DOWNLOAD request occurs
+ *
+ * version 1.0 (01/09/2000) gkh
+ * Original firmware from ConnectTech massaged a little to be program
+ * readable.
+ *
+ *****************************************************************************/
+
+#define whiteheat_DATE "20000106"
+
+struct whiteheat_hex_record {
+ __u16 address;
+ __u8 data_size;
+ __u8 data[16];
+};
+
+static const struct whiteheat_hex_record whiteheat_firmware[] = {
+{ 0x0000, 3, {0x02, 0x91, 0xc9} },
+{ 0x0003, 3, {0x02, 0x13, 0x12} },
+{ 0x000b, 3, {0x02, 0x0a, 0x8d} },
+{ 0x0033, 3, {0x02, 0x07, 0x84} },
+{ 0x0043, 3, {0x02, 0x09, 0x00} },
+{ 0x0053, 3, {0x02, 0x0f, 0x6e} },
+{ 0x005b, 3, {0x02, 0x11, 0xb9} },
+{ 0x0300, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x03, 0x14, 0x70, 0x03, 0x02, 0x04, 0x77, 0x24} },
+{ 0x0310, 16, {0xfe, 0x70, 0x03, 0x02, 0x04, 0xca, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x03, 0xf4, 0x14, 0x70, 0x03} },
+{ 0x0320, 16, {0x02, 0x03, 0xe2, 0x14, 0x70, 0x03, 0x02, 0x03, 0xca, 0x14, 0x70, 0x03, 0x02, 0x03, 0xd9, 0x24} },
+{ 0x0330, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
+{ 0x0340, 16, {0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x0350, 16, {0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x58, 0xea, 0x49, 0x60, 0x0d} },
+{ 0x0360, 16, {0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
+{ 0x0370, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08, 0xa9, 0xea} },
+{ 0x0380, 16, {0x49, 0x60, 0x33, 0x12, 0x9a, 0x48, 0xf5, 0x5e, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x5e, 0xd3} },
+{ 0x0390, 16, {0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x5e, 0x40} },
+{ 0x03a0, 16, {0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x5e, 0x12, 0x1b, 0x0c, 0x90, 0x7f, 0xb5} },
+{ 0x03b0, 16, {0xe5, 0x5e, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20} },
+{ 0x03c0, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
+{ 0x03d0, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
+{ 0x03e0, 16, {0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
+{ 0x03f0, 16, {0xa8, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
+{ 0x0400, 16, {0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
+{ 0x0410, 16, {0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
+{ 0x0420, 16, {0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0xe4} },
+{ 0x0430, 16, {0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90} },
+{ 0x0440, 16, {0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x0450, 16, {0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
+{ 0x0460, 16, {0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
+{ 0x0470, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
+{ 0x0480, 16, {0x02, 0x60, 0x03, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
+{ 0x0490, 16, {0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x04a0, 16, {0x70, 0x1f, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54} },
+{ 0x04b0, 16, {0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x80} },
+{ 0x04c0, 16, {0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe} },
+{ 0x04d0, 16, {0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80} },
+{ 0x04e0, 16, {0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20} },
+{ 0x04f0, 16, {0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
+{ 0x0500, 16, {0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10} },
+{ 0x0510, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x0520, 7, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0527, 1, {0x22} },
+{ 0x0528, 16, {0x75, 0x5a, 0xff, 0x75, 0x59, 0xff, 0x75, 0x58, 0x0f, 0x75, 0x57, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
+{ 0x0538, 16, {0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
+{ 0x0548, 16, {0x01, 0x5b, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
+{ 0x0558, 16, {0x0a, 0xfa, 0xe4, 0x90, 0x02, 0x4d, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x0568, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
+{ 0x0578, 16, {0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
+{ 0x0588, 16, {0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x0598, 16, {0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
+{ 0x05a8, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
+{ 0x05b8, 16, {0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x05c8, 16, {0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
+{ 0x05d8, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
+{ 0x05e8, 16, {0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
+{ 0x05f8, 16, {0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
+{ 0x0608, 16, {0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x62, 0x10, 0x75, 0x63, 0x02, 0x75} },
+{ 0x0618, 16, {0x64, 0x12, 0x75, 0x65, 0xac, 0x12, 0x8e, 0x35, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0xb2, 0x90, 0x01} },
+{ 0x0628, 16, {0x0d, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82} },
+{ 0x0638, 16, {0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
+{ 0x0648, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
+{ 0x0658, 16, {0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
+{ 0x0668, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x5d, 0xe5, 0x5d, 0xae, 0x5c, 0x70, 0x02, 0x05, 0x5c} },
+{ 0x0678, 16, {0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
+{ 0x0688, 16, {0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9b, 0xfb, 0x7e, 0x01} },
+{ 0x0698, 16, {0x7f, 0x18, 0x12, 0x84, 0x61, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x06a8, 16, {0xa3, 0xe0, 0xff, 0x75, 0x62, 0x0a, 0x75, 0x63, 0x06, 0x75, 0x64, 0x12, 0x75, 0x65, 0xb8, 0x12} },
+{ 0x06b8, 16, {0x8e, 0x35, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
+{ 0x06c8, 16, {0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
+{ 0x06d8, 16, {0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xa7, 0x75, 0x56, 0x50} },
+{ 0x06e8, 16, {0x75, 0x55, 0x6d, 0x75, 0x54, 0x33, 0x75, 0x53, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
+{ 0x06f8, 16, {0x7d, 0xff, 0x7c, 0xff, 0x78, 0x53, 0x12, 0x9b, 0xe4, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
+{ 0x0708, 16, {0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x00, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x08, 0xfb, 0x50} },
+{ 0x0718, 16, {0x06, 0x12, 0x0a, 0x00, 0x12, 0x09, 0xf4, 0xc2, 0x06, 0x12, 0x90, 0x58, 0x12, 0x98, 0x7d, 0xe4} },
+{ 0x0728, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0x5b} },
+{ 0x0738, 16, {0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
+{ 0x0748, 16, {0x80, 0x02, 0x7e, 0x00, 0x8e, 0x5b, 0x80, 0x03, 0x75, 0x5b, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
+{ 0x0758, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x5b, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
+{ 0x0768, 16, {0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x90, 0x02} },
+{ 0x0778, 11, {0x4d, 0xe0, 0x64, 0x0f, 0x70, 0x8b, 0x12, 0x93, 0x50, 0x80, 0x86} },
+{ 0x0783, 1, {0x22} },
+{ 0x0784, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x0788, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0798, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x08, 0x92, 0x90, 0x7f} },
+{ 0x07a8, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff} },
+{ 0x07b8, 16, {0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
+{ 0x07c8, 16, {0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x07d8, 16, {0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
+{ 0x07e8, 16, {0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
+{ 0x07f8, 7, {0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x22} },
+{ 0x07ff, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
+{ 0x080f, 16, {0x08, 0x92, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92} },
+{ 0x081f, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f} },
+{ 0x082f, 16, {0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x083f, 16, {0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
+{ 0x084f, 12, {0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x12, 0x0a, 0x00, 0x22} },
+{ 0x085b, 16, {0x90, 0x11, 0xef, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
+{ 0x086b, 16, {0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
+{ 0x087b, 16, {0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x07, 0x88, 0x75, 0x82, 0xef} },
+{ 0x088b, 7, {0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
+{ 0x0892, 16, {0x8e, 0x6d, 0x8f, 0x6e, 0xe5, 0x6e, 0x15, 0x6e, 0xae, 0x6d, 0x70, 0x02, 0x15, 0x6d, 0x4e, 0x60} },
+{ 0x08a2, 7, {0x05, 0x12, 0x08, 0xea, 0x80, 0xee, 0x22} },
+{ 0x08a9, 2, {0x8f, 0x5f} },
+{ 0x08ab, 16, {0xe4, 0xf5, 0x60, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x6a, 0xab, 0x61, 0xaa, 0x62} },
+{ 0x08bb, 16, {0xa9, 0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x03, 0x1d, 0xaf, 0x60, 0x05, 0x60, 0xef} },
+{ 0x08cb, 16, {0xb5, 0x5f, 0x01, 0x22, 0x12, 0x9a, 0x48, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x08db, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x08e9, 1, {0x22} },
+{ 0x08ea, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x08fa, 1, {0x22} },
+{ 0x08fb, 5, {0x12, 0x07, 0xff, 0xd3, 0x22} },
+{ 0x0900, 16, {0x02, 0x0b, 0x17, 0x00, 0x02, 0x0b, 0x4a, 0x00, 0x02, 0x0b, 0x2f, 0x00, 0x02, 0x0b, 0x89, 0x00} },
+{ 0x0910, 16, {0x02, 0x0b, 0x73, 0x00, 0x02, 0x09, 0xf9, 0x00, 0x02, 0x09, 0xfa, 0x00, 0x02, 0x09, 0xfb, 0x00} },
+{ 0x0920, 16, {0x02, 0x0b, 0xa4, 0x00, 0x02, 0x0c, 0x78, 0x00, 0x02, 0x0b, 0xd9, 0x00, 0x02, 0x0c, 0xc5, 0x00} },
+{ 0x0930, 16, {0x02, 0x0c, 0x0e, 0x00, 0x02, 0x0d, 0x12, 0x00, 0x02, 0x0c, 0x43, 0x00, 0x02, 0x0d, 0x5f, 0x00} },
+{ 0x0940, 16, {0x02, 0x09, 0xfc, 0x00, 0x02, 0x09, 0xfe, 0x00, 0x02, 0x09, 0xfd, 0x00, 0x02, 0x09, 0xff, 0x00} },
+{ 0x0950, 8, {0x02, 0x0d, 0xac, 0x00, 0x02, 0x0d, 0xc2, 0x00} },
+{ 0x0958, 16, {0xe4, 0xfe, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x12, 0xab, 0x61, 0xaa, 0x62, 0xa9} },
+{ 0x0968, 16, {0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0978, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9a, 0xba, 0x85, 0xf0, 0x5f, 0xf5, 0x60, 0x62, 0x5f} },
+{ 0x0988, 16, {0xe5, 0x5f, 0x62, 0x60, 0xe5, 0x60, 0x62, 0x5f, 0x29, 0xfd, 0xe5, 0x5f, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0998, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x09a6, 1, {0x22} },
+{ 0x09a7, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
+{ 0x09b7, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x09c7, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x09cc, 16, {0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
+{ 0x09dc, 16, {0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
+{ 0x09ec, 7, {0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
+{ 0x09f3, 1, {0x22} },
+{ 0x09f4, 5, {0x12, 0x07, 0x88, 0xd3, 0x22} },
+{ 0x09f9, 1, {0x32} },
+{ 0x09fa, 1, {0x32} },
+{ 0x09fb, 1, {0x32} },
+{ 0x09fc, 1, {0x32} },
+{ 0x09fd, 1, {0x32} },
+{ 0x09fe, 1, {0x32} },
+{ 0x09ff, 1, {0x32} },
+{ 0x0a00, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x0a7d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0a8d, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
+{ 0x0a9d, 1, {0x07} },
+{ 0x0a9e, 16, {0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
+{ 0x0aae, 16, {0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
+{ 0x0abe, 16, {0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x02, 0x9e} },
+{ 0x0ace, 16, {0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
+{ 0x0ade, 13, {0x01, 0x5f, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x34, 0xff, 0xf0} },
+{ 0x0aeb, 15, {0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0afa, 16, {0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x0f, 0x72, 0x12, 0x08, 0x5b} },
+{ 0x0b0a, 13, {0x12, 0x0e, 0x0f, 0x12, 0x8f, 0x06, 0x12, 0x11, 0x9c, 0x12, 0x09, 0xcc, 0x22} },
+{ 0x0b17, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0b27, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0b2f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0b3f, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0b4a, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x0b5a, 16, {0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
+{ 0x0b6a, 9, {0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0b73, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0b83, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0b89, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0b99, 11, {0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ba4, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x02, 0xf0, 0xe5} },
+{ 0x0bb4, 16, {0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20, 0x04, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x0bc4, 16, {0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
+{ 0x0bd4, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bd9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xe5} },
+{ 0x0be9, 16, {0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20, 0x0c, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x0bf9, 16, {0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
+{ 0x0c09, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c0e, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xe5} },
+{ 0x0c1e, 16, {0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20, 0x14, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x0c2e, 16, {0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
+{ 0x0c3e, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c43, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x10, 0xf0, 0xe5} },
+{ 0x0c53, 16, {0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20, 0x1c, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x0c63, 16, {0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
+{ 0x0c73, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c78, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0c88, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20, 0xe0, 0x06, 0x90, 0x7f, 0xc7} },
+{ 0x0c98, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0x90, 0x02, 0x96, 0xf0} },
+{ 0x0ca8, 16, {0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
+{ 0x0cb8, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0cc5, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0cd5, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20, 0xe1, 0x06, 0x90, 0x7f, 0xc9} },
+{ 0x0ce5, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0x90, 0x02, 0x97, 0xf0} },
+{ 0x0cf5, 16, {0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
+{ 0x0d05, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d12, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0d22, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20, 0xe2, 0x06, 0x90, 0x7f, 0xcb} },
+{ 0x0d32, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x90, 0x02, 0x98, 0xf0} },
+{ 0x0d42, 16, {0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
+{ 0x0d52, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d5f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0d6f, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20, 0xe3, 0x06, 0x90, 0x7f, 0xcd} },
+{ 0x0d7f, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x90, 0x02, 0x99, 0xf0} },
+{ 0x0d8f, 16, {0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
+{ 0x0d9f, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dac, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
+{ 0x0dbc, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dc2, 16, {0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0} },
+{ 0x0dd2, 16, {0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x53, 0x91, 0xef} },
+{ 0x0de2, 16, {0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8c, 0xfb, 0x90, 0x7f, 0xd3} },
+{ 0x0df2, 16, {0xe4, 0xf0, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01} },
+{ 0x0e02, 13, {0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32} },
+{ 0x0e0f, 16, {0x90, 0x01, 0x20, 0x12, 0x9c, 0x07, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
+{ 0x0e1f, 16, {0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x0e2f, 16, {0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50} },
+{ 0x0e3f, 16, {0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x84, 0xf4, 0x90, 0x01, 0x1e, 0xe0} },
+{ 0x0e4f, 16, {0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
+{ 0x0e5f, 16, {0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0x96, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4} },
+{ 0x0e6f, 16, {0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xdc, 0xe4} },
+{ 0x0e7f, 16, {0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
+{ 0x0e8f, 16, {0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02} },
+{ 0x0e9f, 16, {0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x82, 0xea, 0x90, 0x01, 0x1e} },
+{ 0x0eaf, 16, {0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
+{ 0x0ebf, 16, {0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54} },
+{ 0x0ecf, 16, {0xf0, 0xfe, 0x74, 0x63, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xee, 0xf0, 0x74, 0x36} },
+{ 0x0edf, 16, {0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c, 0x2f, 0xf8, 0xe4, 0xf6} },
+{ 0x0eef, 16, {0x74, 0x9a, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
+{ 0x0eff, 16, {0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0x5e, 0x60, 0x5e} },
+{ 0x0f0f, 16, {0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0xe7, 0x74} },
+{ 0x0f1f, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x5e, 0x60, 0x38, 0x90, 0x01} },
+{ 0x0f2f, 1, {0x1e} },
+{ 0x0f30, 16, {0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
+{ 0x0f40, 16, {0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
+{ 0x0f50, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x0f60, 14, {0x7d, 0x06, 0x12, 0x82, 0x60, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xa7, 0x22} },
+{ 0x0f6e, 4, {0x53, 0x91, 0xbf, 0x32} },
+{ 0x0f72, 16, {0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0xfd, 0x8b, 0x60, 0x75} },
+{ 0x0f82, 16, {0x61, 0x12, 0x75, 0x62, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x5e} },
+{ 0x0f92, 16, {0xf5, 0x5f, 0x90, 0x02, 0x4c, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
+{ 0x0fa2, 16, {0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x0fb2, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
+{ 0x0fc2, 16, {0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0x38, 0xab, 0x60, 0xaa, 0x61, 0xa9, 0x62} },
+{ 0x0fd2, 16, {0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0x27, 0x90, 0x00, 0x03} },
+{ 0x0fe2, 16, {0x12, 0x9a, 0x61, 0x64, 0x01, 0x60, 0x03, 0x02, 0x10, 0xae, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61} },
+{ 0x0ff2, 16, {0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x10, 0x88, 0xec, 0xc3, 0x94, 0x10} },
+{ 0x1002, 16, {0x40, 0x03, 0x02, 0x10, 0x88, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x5f, 0xae, 0x5e, 0x78, 0x02, 0xce} },
+{ 0x1012, 16, {0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x1022, 16, {0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
+{ 0x1032, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0x4c, 0xe0} },
+{ 0x1042, 16, {0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x5f, 0xae, 0x5e, 0x78} },
+{ 0x1052, 16, {0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x1062, 16, {0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
+{ 0x1072, 16, {0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
+{ 0x1082, 16, {0x4c, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0x25} },
+{ 0x1092, 16, {0x5f, 0xf5, 0x5f, 0xe4, 0x35, 0x5e, 0xf5, 0x5e, 0x90, 0x00, 0x05, 0x12, 0x9a, 0x61, 0xfe, 0xe4} },
+{ 0x10a2, 16, {0x25, 0x5f, 0xf5, 0x5f, 0xee, 0x35, 0x5e, 0xf5, 0x5e, 0x02, 0x11, 0x2a, 0xab, 0x60, 0xaa, 0x61} },
+{ 0x10b2, 16, {0xa9, 0x62, 0x90, 0x00, 0x03, 0x12, 0x9a, 0x61, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
+{ 0x10c2, 16, {0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
+{ 0x10d2, 16, {0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
+{ 0x10e2, 16, {0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
+{ 0x10f2, 16, {0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x1102, 16, {0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
+{ 0x1112, 16, {0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
+{ 0x1122, 16, {0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35} },
+{ 0x1132, 16, {0x61, 0xf5, 0x61, 0x02, 0x0f, 0xc3, 0x20, 0x03, 0x0d, 0x90, 0x02, 0x4c, 0xe0, 0x60, 0x07, 0x90} },
+{ 0x1142, 8, {0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
+{ 0x114a, 1, {0x22} },
+{ 0x114b, 2, {0xae, 0x07} },
+{ 0x114d, 16, {0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x115d, 16, {0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
+{ 0x116d, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
+{ 0x117d, 16, {0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
+{ 0x118d, 14, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
+{ 0x119b, 1, {0x22} },
+{ 0x119c, 16, {0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x7f, 0x05} },
+{ 0x11ac, 13, {0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x22} },
+{ 0x11b9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
+{ 0x11c9, 15, {0x53, 0x91, 0x7f, 0x90, 0x01, 0x62, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x11d8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
+{ 0x11e8, 7, {0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
+{ 0x11ef, 3, {0x00, 0x02, 0x28} },
+{ 0x1200, 16, {0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
+{ 0x1210, 16, {0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
+{ 0x1220, 16, {0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
+{ 0x1230, 16, {0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1240, 16, {0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1250, 16, {0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02} },
+{ 0x1260, 16, {0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x24, 0x03} },
+{ 0x1270, 16, {0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00} },
+{ 0x1280, 16, {0x54, 0x00, 0x65, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x1290, 16, {0x2e, 0x00, 0x18, 0x03, 0x57, 0x00, 0x68, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x48, 0x00} },
+{ 0x12a0, 16, {0x45, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x1a, 0x03, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12b0, 16, {0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12c0, 16, {0x58, 0x00, 0x58, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x12d0, 16, {0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x12e0, 16, {0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x12f0, 16, {0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x1300, 16, {0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x1310, 2, {0x00, 0x00} },
+{ 0x1312, 16, {0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0xc0, 0xd0} },
+{ 0x1322, 16, {0x75, 0x86, 0x00, 0x75, 0xd0, 0x18, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0xf0, 0x70, 0x11} },
+{ 0x1332, 16, {0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0} },
+{ 0x1342, 16, {0x32, 0x75, 0x86, 0x00, 0x10, 0xf0, 0x0b, 0x10, 0xf1, 0x12, 0x10, 0xf2, 0x19, 0x10, 0xf3, 0x20} },
+{ 0x1352, 16, {0x80, 0xd4, 0xe5, 0x27, 0x70, 0x03, 0x75, 0x27, 0x14, 0x02, 0x13, 0x7c, 0xe5, 0x28, 0x70, 0x03} },
+{ 0x1362, 16, {0x75, 0x28, 0x14, 0x02, 0x15, 0x0d, 0xe5, 0x29, 0x70, 0x03, 0x75, 0x29, 0x14, 0x02, 0x16, 0x9e} },
+{ 0x1372, 16, {0xe5, 0x2a, 0x70, 0x03, 0x75, 0x2a, 0x14, 0x02, 0x18, 0x2f, 0x90, 0x20, 0x02, 0xe0, 0x54, 0x3f} },
+{ 0x1382, 16, {0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02, 0x13} },
+{ 0x1392, 16, {0x43, 0x02, 0x14, 0x65, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x36, 0x02, 0x13, 0x43} },
+{ 0x13a2, 16, {0x43, 0x82, 0x04, 0xe0, 0x43, 0x2c, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x05} },
+{ 0x13b2, 16, {0xe0, 0x42, 0x32, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1, 0x02} },
+{ 0x13c2, 16, {0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x13d2, 16, {0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x00, 0xf0, 0x90, 0x20} },
+{ 0x13e2, 16, {0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86} },
+{ 0x13f2, 16, {0x90, 0x7e, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f} },
+{ 0x1402, 16, {0xe5, 0xe5, 0x3c, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1412, 16, {0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90} },
+{ 0x1422, 16, {0x7f, 0xb7, 0xed, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f, 0x40} },
+{ 0x1432, 16, {0x90, 0x7e, 0x80, 0x05, 0x86, 0x90, 0x20, 0x00, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d, 0x84} },
+{ 0x1442, 16, {0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef, 0x05} },
+{ 0x1452, 16, {0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb7, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x1462, 16, {0x02, 0x13, 0x43, 0x53, 0x2c, 0xfa, 0xe5, 0x22, 0x60, 0x08, 0x75, 0x22, 0x00, 0xd2, 0xe7, 0xfe} },
+{ 0x1472, 16, {0x80, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x14, 0xff, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1482, 16, {0x00, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1492, 16, {0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7e, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x14a2, 16, {0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0, 0x05} },
+{ 0x14b2, 16, {0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03, 0x03} },
+{ 0x14c2, 16, {0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x14d2, 16, {0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x22, 0x90, 0x7f} },
+{ 0x14e2, 16, {0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde, 0xfd} },
+{ 0x14f2, 16, {0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90, 0x20, 0x01} },
+{ 0x1502, 16, {0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20, 0x0a, 0xe0, 0x54} },
+{ 0x1512, 16, {0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02} },
+{ 0x1522, 16, {0x13, 0x43, 0x02, 0x15, 0xf6, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x37, 0x02, 0x13} },
+{ 0x1532, 16, {0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2d, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82} },
+{ 0x1542, 16, {0x05, 0xe0, 0x42, 0x33, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1} },
+{ 0x1552, 16, {0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04} },
+{ 0x1562, 16, {0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x01, 0xf0, 0x90} },
+{ 0x1572, 16, {0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05} },
+{ 0x1582, 16, {0x86, 0x90, 0x7e, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90} },
+{ 0x1592, 16, {0x7f, 0xe5, 0xe5, 0x3d, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x15a2, 16, {0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x15b2, 16, {0x90, 0x7f, 0xb9, 0xed, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f} },
+{ 0x15c2, 16, {0x40, 0x90, 0x7e, 0x00, 0x05, 0x86, 0x90, 0x20, 0x08, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d} },
+{ 0x15d2, 16, {0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef} },
+{ 0x15e2, 16, {0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb9, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe} },
+{ 0x15f2, 16, {0xf0, 0x02, 0x13, 0x43, 0x53, 0x2d, 0xfa, 0xe5, 0x23, 0x60, 0x08, 0x75, 0x23, 0x00, 0xd2, 0xe7} },
+{ 0x1602, 16, {0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x16, 0x90, 0x90, 0x20, 0x50} },
+{ 0x1612, 16, {0x74, 0x01, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x1622, 16, {0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0xc0, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x1632, 16, {0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0} },
+{ 0x1642, 16, {0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03} },
+{ 0x1652, 16, {0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x1662, 16, {0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x23, 0x90} },
+{ 0x1672, 16, {0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde} },
+{ 0x1682, 14, {0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x1690, 16, {0x90, 0x20, 0x09, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20} },
+{ 0x16a0, 16, {0x12, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14} },
+{ 0x16b0, 16, {0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x17, 0x87, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5} },
+{ 0x16c0, 16, {0x38, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2e, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82} },
+{ 0x16d0, 16, {0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x34, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13} },
+{ 0x16e0, 16, {0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x53, 0x82, 0xf8} },
+{ 0x16f0, 16, {0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1700, 16, {0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1710, 16, {0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x1720, 16, {0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3e, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1730, 16, {0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58} },
+{ 0x1740, 16, {0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbb, 0xed, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfe, 0xf0, 0x02} },
+{ 0x1750, 16, {0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x80, 0x05, 0x86, 0x90, 0x20, 0x10, 0xe5, 0x84, 0xfe, 0x24} },
+{ 0x1760, 16, {0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05} },
+{ 0x1770, 16, {0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbb, 0xf0, 0x05, 0x86, 0xa3} },
+{ 0x1780, 16, {0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2e, 0xfa, 0xe5, 0x24, 0x60, 0x08, 0x75, 0x24} },
+{ 0x1790, 16, {0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x18, 0x21} },
+{ 0x17a0, 16, {0x90, 0x20, 0x50, 0x74, 0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0} },
+{ 0x17b0, 16, {0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0} },
+{ 0x17c0, 16, {0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0} },
+{ 0x17d0, 16, {0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60} },
+{ 0x17e0, 16, {0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0} },
+{ 0x17f0, 16, {0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11} },
+{ 0x1800, 16, {0x8b, 0x24, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80} },
+{ 0x1810, 16, {0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00} },
+{ 0x1820, 16, {0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x02, 0x13, 0x43, 0x90} },
+{ 0x1830, 16, {0x20, 0x1a, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5} },
+{ 0x1840, 16, {0x14, 0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x19, 0x18, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x1850, 16, {0xf5, 0x39, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2f, 0x01, 0x02, 0x13, 0x43, 0x53} },
+{ 0x1860, 16, {0x82, 0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x35, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02} },
+{ 0x1870, 16, {0x13, 0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x53, 0x82} },
+{ 0x1880, 16, {0xf8, 0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50} },
+{ 0x1890, 16, {0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x18a0, 16, {0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x18b0, 16, {0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3f, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0} },
+{ 0x18c0, 16, {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20} },
+{ 0x18d0, 16, {0x58, 0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbd, 0xed, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x18e0, 16, {0x02, 0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x00, 0x05, 0x86, 0x90, 0x20, 0x18, 0xe5, 0x84, 0xfe} },
+{ 0x18f0, 16, {0x24, 0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3} },
+{ 0x1900, 16, {0x05, 0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbd, 0xf0, 0x05, 0x86} },
+{ 0x1910, 16, {0xa3, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2f, 0xfa, 0xe5, 0x25, 0x60, 0x08, 0x75} },
+{ 0x1920, 16, {0x25, 0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x19} },
+{ 0x1930, 16, {0xb2, 0x90, 0x20, 0x50, 0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2} },
+{ 0x1940, 16, {0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7c, 0xc0, 0x05, 0x86, 0xe5, 0x85} },
+{ 0x1950, 16, {0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86} },
+{ 0x1960, 16, {0xe0, 0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78} },
+{ 0x1970, 16, {0x60, 0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0} },
+{ 0x1980, 16, {0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70} },
+{ 0x1990, 16, {0x11, 0x8b, 0x25, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x19a0, 16, {0x80, 0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74} },
+{ 0x19b0, 16, {0x00, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x02, 0x13, 0x43} },
+{ 0x19c0, 1, {0x32} },
+{ 0x19c1, 4, {0xad, 0x07, 0xac, 0x06} },
+{ 0x19c5, 16, {0x79, 0x06, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x19d5, 16, {0x4a, 0x70, 0x03, 0x02, 0x1b, 0x09, 0xe9, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x1a, 0xdb, 0x90} },
+{ 0x19e5, 16, {0x19, 0xeb, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x1a, 0xb9, 0x02, 0x1a, 0x71, 0x02, 0x1a, 0x5a, 0x02} },
+{ 0x19f5, 16, {0x1a, 0x40, 0x02, 0x1a, 0x2f, 0x02, 0x1a, 0x1a, 0x02, 0x1a, 0x00, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a05, 16, {0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6} },
+{ 0x1a15, 16, {0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x19, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x0a} },
+{ 0x1a25, 16, {0xa3, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x02, 0x1a, 0xdb, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x1a35, 16, {0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a45, 16, {0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
+{ 0x1a55, 16, {0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a65, 16, {0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x69, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
+{ 0x1a75, 16, {0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
+{ 0x1a85, 16, {0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x1a95, 16, {0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x1aa5, 16, {0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
+{ 0x1ab5, 16, {0x9a, 0x8e, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
+{ 0x1ac5, 16, {0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
+{ 0x1ad5, 16, {0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x69, 0x30, 0xe0, 0xf7, 0x30} },
+{ 0x1ae5, 16, {0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
+{ 0x1af5, 16, {0x19, 0xc7, 0xe5, 0x69, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
+{ 0x1b05, 6, {0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
+{ 0x1b0b, 1, {0x22} },
+{ 0x1b0c, 16, {0x8e, 0x5f, 0x8f, 0x60, 0x8c, 0x61, 0x8d, 0x62, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x60} },
+{ 0x1b1c, 16, {0xe5, 0x60, 0xae, 0x5f, 0x70, 0x02, 0x05, 0x5f, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
+{ 0x1b2c, 16, {0x62, 0xe5, 0x62, 0xac, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x1b3c, 3, {0x80, 0xd6, 0x22} },
+{ 0x8000, 4, {0x8e, 0x69, 0x8f, 0x6a} },
+{ 0x8004, 16, {0x75, 0x6b, 0x03, 0xe5, 0x6a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x8014, 16, {0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x6b, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
+{ 0x8024, 16, {0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8034, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8044, 16, {0x80, 0x6c, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
+{ 0x8054, 16, {0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x6b, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3} },
+{ 0x8064, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x6a, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x8074, 16, {0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5} },
+{ 0x8084, 16, {0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x6a, 0x24} },
+{ 0x8094, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9a, 0x8e, 0x85} },
+{ 0x80a4, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0x8e, 0x90, 0x7f} },
+{ 0x80b4, 16, {0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
+{ 0x80c4, 16, {0x22, 0xe5, 0x6c, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
+{ 0x80d4, 16, {0xe5, 0x6b, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x80e4, 16, {0x80, 0xf0, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
+{ 0x80f4, 16, {0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
+{ 0x8104, 12, {0x6b, 0x03, 0x02, 0x80, 0x07, 0x15, 0x6b, 0x02, 0x80, 0x07, 0x7f, 0x08} },
+{ 0x8110, 1, {0x22} },
+{ 0x8111, 2, {0xac, 0x07} },
+{ 0x8113, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8123, 16, {0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x8133, 16, {0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0xd4, 0x80, 0xf8, 0x90, 0x7f} },
+{ 0x8143, 16, {0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xdc, 0x20, 0xe1, 0x09, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8153, 16, {0xf9, 0x22, 0xed, 0x30, 0xe2, 0x0c, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8163, 16, {0xfa, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7b, 0x1e} },
+{ 0x8173, 16, {0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6} },
+{ 0x8183, 16, {0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0x86, 0x80, 0xf8, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x8193, 16, {0xfd, 0x20, 0xe0, 0xdc, 0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x19, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x81a3, 16, {0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03} },
+{ 0x81b3, 16, {0x02, 0x81, 0x13, 0x80, 0xf5, 0x90, 0x7f, 0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xd9, 0x30, 0xe2, 0x09} },
+{ 0x81c3, 16, {0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x81d3, 12, {0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
+{ 0x81df, 1, {0x22} },
+{ 0x81e0, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
+{ 0x81f0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf9, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0} },
+{ 0x8200, 16, {0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83} },
+{ 0x8210, 16, {0xa3, 0xf0, 0xed, 0x60, 0x29, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33} },
+{ 0x8220, 16, {0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4, 0xef, 0x55, 0x3b, 0x60, 0x0a, 0x8b, 0x82, 0x8a, 0x83} },
+{ 0x8230, 16, {0xa3, 0x74, 0x01, 0xf0, 0x80, 0x08, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0x74, 0xad, 0xf0, 0x8b, 0x82} },
+{ 0x8240, 16, {0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54} },
+{ 0x8250, 15, {0xef, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe9, 0xf0} },
+{ 0x825f, 1, {0x22} },
+{ 0x8260, 4, {0x8f, 0x68, 0x8d, 0x69} },
+{ 0x8264, 16, {0xe4, 0xf5, 0x6a, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x8274, 16, {0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x8284, 16, {0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x50} },
+{ 0x8294, 16, {0x3c, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x82a4, 16, {0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
+{ 0x82b4, 16, {0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75, 0x6a, 0x40, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76} },
+{ 0x82c4, 16, {0x10, 0x80, 0x0a, 0x75, 0x6a, 0x80, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76, 0x38, 0xe5, 0x6a, 0x45} },
+{ 0x82d4, 16, {0x69, 0x44, 0x01, 0xff, 0xe5, 0x68, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x82e4, 5, {0x20, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x82e9, 1, {0x22} },
+{ 0x82ea, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x82fa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xf5, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5} },
+{ 0x830a, 16, {0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82} },
+{ 0x831a, 16, {0x60, 0xaf, 0x5f, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3} },
+{ 0x832a, 16, {0xe0, 0x20, 0xe0, 0x28, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x61} },
+{ 0x833a, 16, {0xf5, 0x83, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83} },
+{ 0x834a, 16, {0xe0, 0xf5, 0x60, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x80, 0xcc, 0x74, 0x96, 0x25, 0x5f} },
+{ 0x835a, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x5f, 0x25, 0xe0, 0xff, 0xc3, 0x74} },
+{ 0x836a, 16, {0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82} },
+{ 0x837a, 16, {0xfe, 0xe5, 0x5f, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0} },
+{ 0x838a, 16, {0xa3, 0xef, 0xf0, 0xaf, 0x5f, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc} },
+{ 0x839a, 4, {0x42, 0x30, 0x7f, 0x00} },
+{ 0x839e, 1, {0x22} },
+{ 0x839f, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x47, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x83af, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x49, 0x8f, 0x4a, 0x74, 0x96, 0x25, 0x47, 0xf5, 0x82, 0xe4} },
+{ 0x83bf, 16, {0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x4a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5} },
+{ 0x83cf, 16, {0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf, 0x47, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0xaf, 0x47, 0x7d, 0x06} },
+{ 0x83df, 16, {0x12, 0x82, 0x60, 0xe5, 0x4a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5, 0x83, 0xe0, 0x30} },
+{ 0x83ef, 16, {0xe0, 0x0b, 0x85, 0x4a, 0x82, 0x85, 0x49, 0x83, 0xe0, 0xf5, 0x48, 0x80, 0xe6, 0xaf, 0x47, 0x74} },
+{ 0x83ff, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x47, 0x25} },
+{ 0x840f, 13, {0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xff} },
+{ 0x841c, 1, {0x22} },
+{ 0x841d, 4, {0x8e, 0x47, 0x8f, 0x48} },
+{ 0x8421, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x49, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
+{ 0x8431, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x48, 0x82, 0x8e, 0x83, 0xa3} },
+{ 0x8441, 16, {0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x49, 0x7d, 0x02, 0x12, 0x82, 0x60, 0x85, 0x48, 0x82, 0x85, 0x47} },
+{ 0x8451, 15, {0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x49, 0x7d, 0x04, 0x12, 0x82, 0x60, 0x7f, 0x00} },
+{ 0x8460, 1, {0x22} },
+{ 0x8461, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
+{ 0x8471, 16, {0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8481, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
+{ 0x8491, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
+{ 0x84a1, 16, {0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
+{ 0x84b1, 16, {0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
+{ 0x84c1, 16, {0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
+{ 0x84d1, 16, {0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x84e1, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
+{ 0x84f1, 3, {0x83, 0xf0, 0x22} },
+{ 0x84f4, 4, {0x8e, 0x5f, 0x8f, 0x60} },
+{ 0x84f8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x8508, 16, {0x1f, 0xad, 0x82, 0xf5, 0x66, 0x8d, 0x67, 0xaa, 0x5f, 0xa9, 0x60, 0x7b, 0x01, 0xc0, 0x03, 0xc0} },
+{ 0x8518, 16, {0x01, 0xef, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x92, 0xf9, 0x74, 0x02, 0x35, 0xf0, 0xa8, 0x01, 0xfc} },
+{ 0x8528, 16, {0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9a, 0x1f, 0x85, 0x60, 0x82} },
+{ 0x8538, 16, {0x85, 0x5f, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0x7f} },
+{ 0x8548, 16, {0x00, 0x7e, 0x08, 0x7d, 0x07, 0x7c, 0x00, 0x12, 0x9b, 0x2e, 0x8f, 0x64, 0x8e, 0x63, 0x8d, 0x62} },
+{ 0x8558, 16, {0x8c, 0x61, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x70, 0x09} },
+{ 0x8568, 16, {0x75, 0x64, 0x01, 0xf5, 0x63, 0xf5, 0x62, 0xf5, 0x61, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0x00, 0x7c} },
+{ 0x8578, 16, {0x00, 0xab, 0x64, 0xaa, 0x63, 0xa9, 0x62, 0xa8, 0x61, 0xd3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75} },
+{ 0x8588, 16, {0x64, 0xff, 0x75, 0x63, 0xff, 0x75, 0x62, 0x00, 0x75, 0x61, 0x00, 0x85, 0x67, 0x82, 0x85, 0x66} },
+{ 0x8598, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xe5, 0x64} },
+{ 0x85a8, 16, {0xf0, 0xaf, 0x64, 0xae, 0x63, 0xad, 0x62, 0xac, 0x61, 0x78, 0x08, 0x12, 0x9b, 0xd1, 0x85, 0x67} },
+{ 0x85b8, 16, {0x82, 0x85, 0x66, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x85c8, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x65, 0xe5, 0x60, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x5f} },
+{ 0x85d8, 16, {0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x65, 0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05} },
+{ 0x85e8, 16, {0x43, 0x65, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03, 0x43, 0x65, 0x02, 0xe5, 0x60, 0x24, 0x0b} },
+{ 0x85f8, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe3, 0x03, 0x43, 0x65, 0x80, 0xef} },
+{ 0x8608, 16, {0x30, 0xe7, 0x12, 0x43, 0x65, 0x40, 0xe5, 0x67, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
+{ 0x8618, 16, {0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x60, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83} },
+{ 0x8628, 16, {0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x27, 0x85, 0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14} },
+{ 0x8638, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x67} },
+{ 0x8648, 16, {0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x17, 0x85} },
+{ 0x8658, 16, {0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x8668, 16, {0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x3b, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0x74} },
+{ 0x8678, 16, {0xbf, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x65, 0xf0, 0xe5} },
+{ 0x8688, 16, {0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x04} },
+{ 0x8698, 16, {0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4} },
+{ 0x86a8, 16, {0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
+{ 0x86b8, 16, {0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x86c8, 16, {0xe5, 0x67, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24} },
+{ 0x86d8, 16, {0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x07, 0xf5, 0x82} },
+{ 0x86e8, 16, {0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x86f8, 16, {0xe4, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x60, 0x82, 0x85, 0x5f} },
+{ 0x8708, 16, {0x83, 0xe0, 0x14, 0xff, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x75, 0x65, 0x08, 0xe5, 0x60, 0x24, 0x0c} },
+{ 0x8718, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43, 0x65, 0x10, 0xe5, 0x67, 0x24} },
+{ 0x8728, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x45, 0x65, 0xf0, 0xe5, 0x60} },
+{ 0x8738, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x14, 0xff, 0x25, 0xe0, 0x25, 0xe0} },
+{ 0x8748, 16, {0xff, 0xe5, 0x60, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xfb, 0x4f} },
+{ 0x8758, 16, {0xf5, 0x65, 0xe5, 0x60, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xd0} },
+{ 0x8768, 16, {0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a, 0x70, 0x12, 0x43, 0x65, 0x18} },
+{ 0x8778, 16, {0x80, 0x0d, 0x43, 0x65, 0x08, 0x80, 0x08, 0x43, 0x65, 0x38, 0x80, 0x03, 0x43, 0x65, 0x28, 0x85} },
+{ 0x8788, 13, {0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x65, 0xf0, 0x7f, 0x00} },
+{ 0x8795, 1, {0x22} },
+{ 0x8796, 4, {0x8e, 0x47, 0x8f, 0x48} },
+{ 0x879a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x4a, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x87aa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4d, 0x8f, 0x4e, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01} },
+{ 0x87ba, 16, {0xf5, 0x4c, 0xe4, 0x3e, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x08, 0xf0, 0xe5, 0x4a, 0x04} },
+{ 0x87ca, 16, {0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xf0, 0xa3, 0xe4, 0xf0, 0xe5, 0x4e, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x87da, 16, {0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xf0, 0xe5} },
+{ 0x87ea, 16, {0x4e, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x85, 0x4c, 0x82} },
+{ 0x87fa, 16, {0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xa3, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x2b} },
+{ 0x880a, 16, {0xf8, 0xe6, 0xff, 0xe5, 0x4c, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x881a, 16, {0xaf, 0x4a, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x49, 0x7f} },
+{ 0x882a, 16, {0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x49, 0x5f, 0xff} },
+{ 0x883a, 16, {0xe5, 0x4c, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x884a, 5, {0x74, 0x07, 0xf0, 0x7f, 0x00} },
+{ 0x884f, 1, {0x22} },
+{ 0x8850, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8860, 16, {0xaf, 0x82, 0xf5, 0x47, 0x8f, 0x48, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e} },
+{ 0x8870, 16, {0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0a, 0xf0, 0xe5, 0x48, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x8880, 16, {0x47, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x90, 0x7f, 0xc3, 0x74, 0x02, 0xf0, 0x7f} },
+{ 0x8890, 1, {0x00} },
+{ 0x8891, 1, {0x22} },
+{ 0x8892, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x88a2, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x88b2, 16, {0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x88c2, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
+{ 0x88cd, 1, {0x22} },
+{ 0x88ce, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x88de, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x88ee, 16, {0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x88fe, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
+{ 0x8909, 1, {0x22} },
+{ 0x890a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x891a, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x892a, 16, {0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
+{ 0x893a, 7, {0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
+{ 0x8941, 1, {0x22} },
+{ 0x8942, 4, {0x8e, 0x47, 0x8f, 0x48} },
+{ 0x8946, 16, {0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x8956, 16, {0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
+{ 0x8966, 16, {0x49, 0x7e, 0x75, 0x4a, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x49, 0x7e, 0x75, 0x4a} },
+{ 0x8976, 16, {0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x80, 0x80, 0x0a, 0x7e} },
+{ 0x8986, 16, {0x7d, 0x7f, 0x00, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x00, 0xe5, 0x4b, 0x70, 0x20, 0x85, 0x4a, 0x82} },
+{ 0x8996, 16, {0x85, 0x49, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x89a6, 16, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x3a, 0xe5, 0x48, 0x24} },
+{ 0x89b6, 16, {0x02, 0xff, 0xe4, 0x35, 0x47, 0xfe, 0xe5, 0x4b, 0x60, 0x10, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x85} },
+{ 0x89c6, 16, {0x4a, 0x82, 0x85, 0x49, 0x83, 0xf0, 0x15, 0x4b, 0x80, 0xec, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
+{ 0x89d6, 16, {0xa3, 0xe0, 0xff, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24, 0xb5, 0xf5, 0x82} },
+{ 0x89e6, 9, {0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
+{ 0x89ef, 1, {0x22} },
+{ 0x89f0, 16, {0xef, 0x24, 0x01, 0xf5, 0x48, 0xe4, 0x3e, 0xf5, 0x47, 0x7c, 0x7b, 0x7d, 0x80, 0x7e, 0x7b, 0x7f} },
+{ 0x8a00, 16, {0x80, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x07, 0xf0, 0xef, 0x24, 0x01, 0xff, 0xe4, 0x3e, 0x90, 0x01} },
+{ 0x8a10, 16, {0x31, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xfe} },
+{ 0x8a20, 16, {0xa3, 0xe0, 0x8e, 0x49, 0xf5, 0x4a, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x60} },
+{ 0x8a30, 16, {0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8a, 0xdd, 0x24, 0x14, 0x60, 0x03} },
+{ 0x8a40, 16, {0x02, 0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3} },
+{ 0x8a50, 16, {0xe4, 0x9f, 0xf5, 0x4c, 0x74, 0x01, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b} },
+{ 0x8a60, 16, {0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5} },
+{ 0x8a70, 16, {0x49, 0x95, 0x4b, 0x50, 0x03, 0x02, 0x8b, 0x30, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85} },
+{ 0x8a80, 16, {0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x02} },
+{ 0x8a90, 16, {0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x74} },
+{ 0x8aa0, 16, {0x30, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b, 0x94} },
+{ 0x8ab0, 16, {0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5, 0x49} },
+{ 0x8ac0, 16, {0x95, 0x4b, 0x40, 0x6c, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3} },
+{ 0x8ad0, 16, {0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x80, 0x53, 0x85, 0x48, 0x82} },
+{ 0x8ae0, 16, {0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e} },
+{ 0x8af0, 16, {0xf5, 0x4b, 0x45, 0x4c, 0x70, 0x07, 0xf5, 0x4b, 0x75, 0x4c, 0x40, 0x80, 0x11, 0xd3, 0xe5, 0x4c} },
+{ 0x8b00, 16, {0x94, 0x40, 0xe5, 0x4b, 0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5} },
+{ 0x8b10, 16, {0x4a, 0x95, 0x4c, 0xe5, 0x49, 0x95, 0x4b, 0x40, 0x17, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82} },
+{ 0x8b20, 16, {0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a} },
+{ 0x8b30, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8b, 0xf0, 0x24, 0xf9} },
+{ 0x8b40, 16, {0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x40, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x84} },
+{ 0x8b50, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
+{ 0x8b60, 16, {0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a} },
+{ 0x8b70, 16, {0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xe0} },
+{ 0x8b80, 16, {0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a} },
+{ 0x8b90, 16, {0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
+{ 0x8ba0, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8c} },
+{ 0x8bb0, 16, {0x84, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2d} },
+{ 0x8bc0, 16, {0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02} },
+{ 0x8bd0, 16, {0x8c, 0x84, 0x90, 0x01, 0x2d, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
+{ 0x8be0, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
+{ 0x8bf0, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
+{ 0x8c00, 16, {0x94, 0x00, 0x50, 0x03, 0x02, 0x8c, 0x84, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
+{ 0x8c10, 16, {0x90, 0x01, 0x2e, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e} },
+{ 0x8c20, 16, {0x60, 0x62, 0x90, 0x01, 0x2e, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
+{ 0x8c30, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
+{ 0x8c40, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x2f, 0xcf, 0xf0} },
+{ 0x8c50, 16, {0xa3, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x60, 0x24} },
+{ 0x8c60, 16, {0x90, 0x01, 0x2f, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
+{ 0x8c70, 16, {0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x8c80, 16, {0xef, 0xf0, 0x80, 0xcf, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xa3, 0xe0} },
+{ 0x8c90, 6, {0x90, 0x7f, 0xc3, 0xf0, 0x7f, 0x00} },
+{ 0x8c96, 1, {0x22} },
+{ 0x8c97, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e, 0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74} },
+{ 0x8ca7, 16, {0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f, 0x8d, 0x82, 0x8c, 0x83} },
+{ 0x8cb7, 16, {0xf0, 0x90, 0x11, 0xf0, 0xe4, 0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xf0, 0x90, 0x11, 0xf1, 0xe4} },
+{ 0x8cc7, 16, {0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xf0, 0xe4, 0x90, 0x01, 0x33, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x8cd7, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xed, 0x24, 0x03, 0xfe, 0xe4, 0x3c, 0xa3} },
+{ 0x8ce7, 16, {0xf0, 0xa3, 0xce, 0xf0, 0x7e, 0x01, 0x7f, 0x33, 0x12, 0x19, 0xc1, 0x90, 0x7f, 0xc3, 0x74, 0x14} },
+{ 0x8cf7, 3, {0xf0, 0x7f, 0x00} },
+{ 0x8cfa, 1, {0x22} },
+{ 0x8cfb, 4, {0x8e, 0x40, 0x8f, 0x41} },
+{ 0x8cff, 16, {0x85, 0x40, 0x43, 0x85, 0x41, 0x44, 0x85, 0x44, 0x82, 0x85, 0x43, 0x83, 0xe0, 0x14, 0xb4, 0x0f} },
+{ 0x8d0f, 16, {0x00, 0x40, 0x03, 0x02, 0x8e, 0x32, 0x90, 0x8d, 0x1c, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8d, 0x49} },
+{ 0x8d1f, 16, {0x02, 0x8d, 0x5a, 0x02, 0x8d, 0x6b, 0x02, 0x8d, 0x8e, 0x02, 0x8d, 0x9f, 0x02, 0x8d, 0xb0, 0x02} },
+{ 0x8d2f, 16, {0x8d, 0xc0, 0x02, 0x8d, 0xcb, 0x02, 0x8d, 0xdb, 0x02, 0x8d, 0xeb, 0x02, 0x8d, 0xfb, 0x02, 0x8e} },
+{ 0x8d3f, 16, {0x02, 0x02, 0x8e, 0x32, 0x02, 0x8e, 0x12, 0x02, 0x8e, 0x22, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4} },
+{ 0x8d4f, 16, {0x35, 0x43, 0xfe, 0x12, 0x82, 0xea, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01, 0xff} },
+{ 0x8d5f, 16, {0xe4, 0x35, 0x43, 0xfe, 0x12, 0x83, 0x9f, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01} },
+{ 0x8d6f, 16, {0xf5, 0x46, 0xe4, 0x35, 0x43, 0xf5, 0x45, 0xe5, 0x46, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x45, 0xfe} },
+{ 0x8d7f, 16, {0x12, 0x84, 0x61, 0xaf, 0x46, 0xae, 0x45, 0x12, 0x84, 0xf4, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5} },
+{ 0x8d8f, 16, {0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x92, 0x8f, 0x42, 0x02, 0x8e, 0x32} },
+{ 0x8d9f, 16, {0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0xce, 0x8f, 0x42, 0x02, 0x8e} },
+{ 0x8daf, 16, {0x32, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x0a, 0x8f, 0x42, 0x80} },
+{ 0x8dbf, 16, {0x72, 0xaf, 0x41, 0xae, 0x40, 0x12, 0x89, 0xf0, 0x8f, 0x42, 0x80, 0x67, 0xe5, 0x44, 0x24, 0x01} },
+{ 0x8dcf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x87, 0x96, 0x8f, 0x42, 0x80, 0x57, 0xe5, 0x44, 0x24, 0x01} },
+{ 0x8ddf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x84, 0x1d, 0x8f, 0x42, 0x80, 0x47, 0xe5, 0x44, 0x24, 0x01} },
+{ 0x8def, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x50, 0x8f, 0x42, 0x80, 0x37, 0x12, 0x8c, 0x97, 0x8f} },
+{ 0x8dff, 16, {0x42, 0x80, 0x30, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x11, 0xd8, 0x8f} },
+{ 0x8e0f, 16, {0x42, 0x80, 0x20, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x42, 0x8f} },
+{ 0x8e1f, 16, {0x42, 0x80, 0x10, 0xaf, 0x41, 0xae, 0x40, 0x7c, 0x02, 0x7d, 0x4d, 0x7b, 0x40, 0x12, 0x1b, 0x0c} },
+{ 0x8e2f, 5, {0xe4, 0xf5, 0x42, 0xaf, 0x42} },
+{ 0x8e34, 1, {0x22} },
+{ 0x8e35, 8, {0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e} },
+{ 0x8e3d, 16, {0x75, 0x68, 0x01, 0x75, 0x69, 0x3b, 0xe4, 0xf5, 0x67, 0xaf, 0x63, 0x15, 0x63, 0xef, 0x70, 0x03} },
+{ 0x8e4d, 16, {0x02, 0x8e, 0xd3, 0xaf, 0x62, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x61} },
+{ 0x8e5d, 16, {0xae, 0x60, 0xad, 0x5f, 0xac, 0x5e, 0x12, 0x9b, 0x2e, 0xaf, 0x03, 0x8f, 0x66, 0xaf, 0x61, 0xae} },
+{ 0x8e6d, 16, {0x60, 0xad, 0x5f, 0xac, 0x5e, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x62, 0xe4} },
+{ 0x8e7d, 16, {0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
+{ 0x8e8d, 16, {0x12, 0x9b, 0x2e, 0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e, 0xe5, 0x66, 0x24, 0x30, 0xf5} },
+{ 0x8e9d, 16, {0x66, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x66, 0xf5, 0x66, 0x05, 0x69, 0xe5, 0x69} },
+{ 0x8ead, 16, {0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x69, 0xe5} },
+{ 0x8ebd, 16, {0x69, 0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x66, 0xf0, 0x05} },
+{ 0x8ecd, 16, {0x67, 0x05, 0x67, 0x02, 0x8e, 0x46, 0xe5, 0x69, 0x15, 0x69, 0x70, 0x02, 0x15, 0x68, 0xaf, 0x67} },
+{ 0x8edd, 16, {0x15, 0x67, 0xef, 0x60, 0x23, 0xe5, 0x69, 0x15, 0x69, 0xae, 0x68, 0x70, 0x02, 0x15, 0x68, 0xf5} },
+{ 0x8eed, 16, {0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x65, 0xe5, 0x65, 0xac, 0x64, 0x70, 0x02, 0x05, 0x64, 0x14} },
+{ 0x8efd, 8, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
+{ 0x8f05, 1, {0x22} },
+{ 0x8f06, 16, {0xe4, 0x90, 0x01, 0x67, 0xf0, 0x7e, 0x01, 0x7f, 0x68, 0x90, 0x01, 0x5c, 0xee, 0xf0, 0xa3, 0xef} },
+{ 0x8f16, 10, {0xf0, 0x90, 0x01, 0x60, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x8f20, 16, {0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0x67, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
+{ 0x8f30, 16, {0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
+{ 0x8f40, 16, {0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0x60, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x8f50, 16, {0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x8f60, 16, {0xeb, 0xf0, 0x90, 0x01, 0x60, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x8f70, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x60, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
+{ 0x8f80, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x8f90, 1, {0x22} },
+{ 0x8f91, 16, {0x90, 0x01, 0x67, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0x5c, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x8fa1, 16, {0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
+{ 0x8fb1, 16, {0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
+{ 0x8fc1, 16, {0x9a, 0x1f, 0x90, 0x01, 0x5c, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x8fd1, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x5c, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
+{ 0x8fe1, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x8ff1, 1, {0x22} },
+{ 0x8ff2, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x63, 0x7b, 0x75, 0x64} },
+{ 0x9002, 16, {0x80, 0xe5, 0x64, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x63, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x65, 0xf5} },
+{ 0x9012, 16, {0x66, 0x89, 0x67, 0xfe, 0x12, 0x8f, 0x91, 0xef, 0x60, 0x3b, 0xab, 0x65, 0xaa, 0x66, 0xa9, 0x67} },
+{ 0x9022, 16, {0x12, 0x9a, 0x48, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
+{ 0x9032, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
+{ 0x9042, 16, {0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x9052, 5, {0x74, 0x04, 0xf0, 0xd2, 0xaf} },
+{ 0x9057, 1, {0x22} },
+{ 0x9058, 16, {0x12, 0x8f, 0xf2, 0xe4, 0xf5, 0x5e, 0x74, 0x36, 0x25, 0x5e, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x5f} },
+{ 0x9068, 16, {0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x5f, 0xff, 0xc4} },
+{ 0x9078, 16, {0x54, 0x0f, 0xf5, 0x60, 0x60, 0x22, 0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
+{ 0x9088, 16, {0x83, 0xe5, 0x5f, 0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0xe5, 0x5f, 0x45, 0x60, 0xfb, 0x12, 0x8f, 0x20} },
+{ 0x9098, 16, {0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40} },
+{ 0x90a8, 16, {0xb5, 0x12, 0x8f, 0xf2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8} },
+{ 0x90b8, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x5e} },
+{ 0x90c8, 16, {0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
+{ 0x90d8, 16, {0x16, 0xaf, 0x5e, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2} },
+{ 0x90e8, 16, {0x80, 0xef, 0xe5, 0x5f, 0xf4, 0x52, 0x3a, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
+{ 0x90f8, 16, {0x90, 0x02, 0x9e, 0xe0, 0x60, 0x03, 0x02, 0x91, 0xc5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
+{ 0x9108, 16, {0x11, 0x8e, 0x61, 0x8f, 0x62, 0xc3, 0xe5, 0x61, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
+{ 0x9118, 16, {0x5b, 0xe0, 0x65, 0x62, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8, 0x07} },
+{ 0x9128, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01, 0x5b, 0xe0, 0x55, 0x5f, 0x60} },
+{ 0x9138, 16, {0x14, 0xaf, 0x5e, 0x7d, 0x08, 0xe5, 0x5f, 0x55, 0x62, 0xfb, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05} },
+{ 0x9148, 16, {0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
+{ 0x9158, 16, {0x5b, 0xe5, 0x62, 0xf0, 0xe4, 0xf5, 0x5e, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x5e, 0xf8, 0xe6, 0xf5} },
+{ 0x9168, 16, {0x5f, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x5f, 0x1e, 0xe5, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x02} },
+{ 0x9178, 16, {0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
+{ 0x9188, 16, {0x5e, 0xf8, 0xe6, 0xf5, 0x5f, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x9198, 16, {0xe0, 0x65, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x04, 0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70} },
+{ 0x91a8, 16, {0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x91b8, 16, {0x83, 0xe5, 0x5f, 0xf0, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x8f, 0xf2} },
+{ 0x91c8, 1, {0x22} },
+{ 0x91c9, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x6e, 0x02, 0x92, 0x10} },
+{ 0x91d5, 16, {0x02, 0x05, 0x28, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x91e5, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x91f5, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x9205, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x92, 0x55, 0xe4, 0x7e} },
+{ 0x9215, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x9225, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x9235, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x9245, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x9255, 16, {0x60, 0x24, 0x02, 0x28, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
+{ 0x9265, 16, {0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
+{ 0x9275, 8, {0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
+{ 0x927d, 1, {0x00} },
+{ 0x927e, 11, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
+{ 0x9289, 16, {0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
+{ 0x9299, 16, {0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
+{ 0x92a9, 16, {0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xb5, 0x1e} },
+{ 0x92b9, 10, {0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0x62, 0xee, 0xf0} },
+{ 0x92c3, 9, {0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x92cc, 2, {0xa9, 0x03} },
+{ 0x92ce, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
+{ 0x92de, 16, {0x6c, 0x45, 0x6d, 0xf5, 0x6e, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
+{ 0x92ee, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
+{ 0x92fe, 16, {0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x6e, 0xeb} },
+{ 0x930e, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x6e, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
+{ 0x931e, 16, {0x05, 0x22, 0xe5, 0x6c, 0x5c, 0xfe, 0xe5, 0x6d, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
+{ 0x932e, 16, {0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
+{ 0x933e, 16, {0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x6c, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x6d, 0x22, 0x7f} },
+{ 0x934e, 1, {0x00} },
+{ 0x934f, 1, {0x22} },
+{ 0x9350, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xf5, 0x66, 0xe4, 0x3e, 0xf5, 0x65, 0x75, 0x63, 0x02} },
+{ 0x9360, 16, {0x75, 0x64, 0x4e, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0f, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
+{ 0x9370, 16, {0xe0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0xa3, 0xe0} },
+{ 0x9380, 16, {0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xf0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3} },
+{ 0x9390, 16, {0x74, 0xff, 0xf0, 0xe5, 0x66, 0x24, 0x03, 0xf5, 0x68, 0xe4, 0x35, 0x65, 0xf5, 0x67, 0x85, 0x64} },
+{ 0x93a0, 16, {0x82, 0x85, 0x63, 0x83, 0xe0, 0x14, 0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x98, 0x43, 0x90, 0x93} },
+{ 0x93b0, 16, {0xb5, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x93, 0xd6, 0x02, 0x94, 0x7c, 0x02, 0x95, 0xba, 0x02, 0x95} },
+{ 0x93c0, 16, {0xda, 0x02, 0x95, 0xda, 0x02, 0x96, 0x7f, 0x02, 0x96, 0xbd, 0x02, 0x96, 0xe4, 0x02, 0x97, 0xa6} },
+{ 0x93d0, 16, {0x02, 0x97, 0xda, 0x02, 0x98, 0x0b, 0xe4, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
+{ 0x93e0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xe4, 0xff, 0xe4, 0xfe} },
+{ 0x93f0, 16, {0xef, 0x60, 0x10, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5} },
+{ 0x9400, 16, {0x5f, 0x80, 0x0d, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x5f} },
+{ 0x9410, 16, {0xe5, 0x62, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe5, 0x5f, 0xf0, 0xe0, 0xf5} },
+{ 0x9420, 16, {0x60, 0x65, 0x5f, 0x60, 0x3d, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5} },
+{ 0x9430, 16, {0x5e, 0x04, 0xfd, 0x05, 0x68, 0xe5, 0x68, 0xaa, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82} },
+{ 0x9440, 16, {0x8a, 0x83, 0xed, 0xf0, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
+{ 0x9450, 16, {0x82, 0x8c, 0x83, 0xe5, 0x5f, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02} },
+{ 0x9460, 16, {0x98, 0x4e, 0x0e, 0xee, 0x64, 0x24, 0x70, 0x88, 0x0f, 0xef, 0x64, 0x02, 0x70, 0x80, 0x05, 0x5e} },
+{ 0x9470, 16, {0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03, 0x02, 0x93, 0xd9, 0x02, 0x98, 0x4e, 0x7e, 0x20, 0x7f, 0x00} },
+{ 0x9480, 16, {0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
+{ 0x9490, 16, {0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5} },
+{ 0x94a0, 16, {0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04, 0x74, 0x92, 0xf0, 0xa3, 0x74, 0x7e, 0xf0} },
+{ 0x94b0, 16, {0xe4, 0xf5, 0x60, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xf5, 0x5e, 0xaf} },
+{ 0x94c0, 16, {0x5e, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01} },
+{ 0x94d0, 16, {0x62, 0xf0, 0x90, 0x01, 0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
+{ 0x94e0, 16, {0x83, 0xa3, 0x74, 0x02, 0xf0, 0x90, 0x01, 0x62, 0xe0, 0x65, 0x5f, 0x70, 0x39, 0x90, 0x01, 0x5e} },
+{ 0x94f0, 16, {0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xee, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0} },
+{ 0x9500, 16, {0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
+{ 0x9510, 16, {0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
+{ 0x9520, 16, {0x01, 0x62, 0xf0, 0x75, 0x60, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xff, 0x60, 0x3c, 0x85, 0x66, 0x82} },
+{ 0x9530, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xfe, 0x05, 0x68, 0xe5, 0x68, 0xac} },
+{ 0x9540, 16, {0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x68, 0xe5, 0x68} },
+{ 0x9550, 16, {0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82} },
+{ 0x9560, 16, {0x85, 0x67, 0x83, 0xe5, 0x5f, 0xf0, 0x75, 0x60, 0xff, 0xe5, 0x60, 0x70, 0x16, 0x74, 0x08, 0x25} },
+{ 0x9570, 16, {0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03} },
+{ 0x9580, 16, {0x02, 0x94, 0xbf, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e} },
+{ 0x9590, 16, {0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4} },
+{ 0x95a0, 16, {0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04} },
+{ 0x95b0, 16, {0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12, 0xf0, 0x02, 0x98, 0x4e, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
+{ 0x95c0, 16, {0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90} },
+{ 0x95d0, 16, {0x02, 0x95, 0xf0, 0x90, 0x01, 0x62, 0xf0, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0x74, 0x03, 0xf0} },
+{ 0x95e0, 16, {0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0} },
+{ 0x95f0, 16, {0xb5, 0x07, 0x1e, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x85, 0x66, 0x82} },
+{ 0x9600, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xf5} },
+{ 0x9610, 16, {0x60, 0xe5, 0x60, 0x60, 0x03, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0x74, 0x96, 0xf0} },
+{ 0x9620, 16, {0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3} },
+{ 0x9630, 16, {0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0} },
+{ 0x9640, 16, {0x55, 0x60, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x5f, 0x85, 0x64, 0x82, 0x85} },
+{ 0x9650, 16, {0x63, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x5f, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00} },
+{ 0x9660, 16, {0x8f, 0x5f, 0xe5, 0x5f, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3} },
+{ 0x9670, 16, {0xa3, 0xe4, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x7e} },
+{ 0x9680, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
+{ 0x9690, 16, {0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x96a0, 16, {0x62, 0x82, 0x85, 0x61, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
+{ 0x96b0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x98, 0x4e, 0xc2, 0x04, 0x7e} },
+{ 0x96c0, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
+{ 0x96d0, 16, {0x35, 0x61, 0xf5, 0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81} },
+{ 0x96e0, 16, {0xe0, 0x02, 0x98, 0x4e, 0xe4, 0xf5, 0x60, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
+{ 0x96f0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xfe, 0xe4, 0xfd, 0x12} },
+{ 0x9700, 16, {0x81, 0xe0, 0xe5, 0x62, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe0, 0x54, 0xfc} },
+{ 0x9710, 16, {0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc} },
+{ 0x9720, 16, {0x8f, 0x60, 0xe5, 0x60, 0x70, 0x11, 0xaf, 0x5e, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x6c, 0x10, 0x75} },
+{ 0x9730, 16, {0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf, 0x5e, 0x7d, 0x01, 0xfb} },
+{ 0x9740, 16, {0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf} },
+{ 0x9750, 16, {0x5e, 0x7d, 0x02, 0xfb, 0x75, 0x6c, 0x10, 0x75, 0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xaf} },
+{ 0x9760, 16, {0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0xe5, 0x60, 0x60, 0x2b, 0x85, 0x66, 0x82, 0x85} },
+{ 0x9770, 16, {0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67} },
+{ 0x9780, 16, {0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67} },
+{ 0x9790, 16, {0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x50, 0x03} },
+{ 0x97a0, 16, {0x02, 0x96, 0xe9, 0x02, 0x98, 0x4e, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x97b0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x98, 0xf0, 0xa3, 0x74, 0x6d, 0xf0, 0x7e} },
+{ 0x97c0, 16, {0x02, 0x7f, 0xd3, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66} },
+{ 0x97d0, 16, {0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x74, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3} },
+{ 0x97e0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x67, 0xf0, 0xa3} },
+{ 0x97f0, 16, {0xe5, 0x68, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x4f, 0x85} },
+{ 0x9800, 16, {0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x43, 0xe4, 0x90, 0x02, 0xd3, 0xf0} },
+{ 0x9810, 16, {0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x64, 0x24, 0x02} },
+{ 0x9820, 16, {0x90, 0x02, 0xda, 0xf0, 0xe4, 0x35, 0x63, 0x90, 0x02, 0xd9, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12} },
+{ 0x9830, 16, {0x80, 0x00, 0xef, 0x64, 0x08, 0x60, 0x17, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4} },
+{ 0x9840, 16, {0xf0, 0x80, 0x0b, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0x74, 0x01, 0xf0, 0x90, 0x01} },
+{ 0x9850, 16, {0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
+{ 0x9860, 12, {0xf6, 0x90, 0x7f, 0xc3, 0x74, 0x24, 0xf0, 0xe4, 0x90, 0x02, 0x4d, 0xf0} },
+{ 0x986c, 1, {0x22} },
+{ 0x986d, 16, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
+{ 0x987d, 16, {0xe4, 0xfd, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x05, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce} },
+{ 0x988d, 16, {0xd8, 0xf9, 0xff, 0xe5, 0x3b, 0xfb, 0xe4, 0xef, 0x5b, 0x70, 0x03, 0x02, 0x99, 0x45, 0xed, 0x75} },
+{ 0x989d, 16, {0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xfe, 0xf5, 0x83, 0xe5} },
+{ 0x98ad, 16, {0x82, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x60} },
+{ 0x98bd, 16, {0x03, 0x02, 0x99, 0x45, 0xef, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0xfc, 0x74} },
+{ 0x98cd, 16, {0x36, 0x2d, 0xf8, 0xec, 0xf6, 0x30, 0xe5, 0x70, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02} },
+{ 0x98dd, 16, {0xf5, 0x83, 0xe0, 0x60, 0x63, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x98ed, 16, {0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8f, 0x82} },
+{ 0x98fd, 16, {0x8e, 0x83, 0xf0, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0} },
+{ 0x990d, 16, {0x70, 0x36, 0xed, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x991d, 16, {0xed, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82} },
+{ 0x992d, 16, {0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x993d, 16, {0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x0d, 0xed, 0x64, 0x04, 0x60, 0x03, 0x02, 0x98} },
+{ 0x994d, 1, {0x7f} },
+{ 0x994e, 1, {0x22} },
+{ 0x994f, 16, {0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
+{ 0x995f, 16, {0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
+{ 0x996f, 16, {0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
+{ 0x997f, 16, {0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
+{ 0x998f, 16, {0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
+{ 0x999f, 16, {0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
+{ 0x99af, 16, {0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
+{ 0x99bf, 16, {0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
+{ 0x99cf, 16, {0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
+{ 0x99df, 16, {0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
+{ 0x99ef, 16, {0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
+{ 0x99ff, 16, {0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
+{ 0x9a0f, 16, {0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
+{ 0x9a1f, 16, {0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
+{ 0x9a2f, 16, {0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
+{ 0x9a3f, 9, {0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x99, 0x9f, 0x73} },
+{ 0x9a48, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x9a58, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9a61, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x9a71, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x9a81, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9a8e, 16, {0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
+{ 0x9a9e, 6, {0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
+{ 0x9aa4, 16, {0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
+{ 0x9ab4, 6, {0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
+{ 0x9aba, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x9aca, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x9ada, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x9aea, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x9af2, 16, {0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
+{ 0x9b02, 16, {0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
+{ 0x9b12, 16, {0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
+{ 0x9b22, 16, {0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
+{ 0x9b32, 16, {0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
+{ 0x9b42, 16, {0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
+{ 0x9b52, 16, {0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
+{ 0x9b62, 16, {0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
+{ 0x9b72, 16, {0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
+{ 0x9b82, 16, {0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
+{ 0x9b92, 16, {0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
+{ 0x9ba2, 16, {0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
+{ 0x9bb2, 14, {0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
+{ 0x9bc0, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x9bd0, 1, {0x22} },
+{ 0x9bd1, 16, {0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
+{ 0x9be1, 3, {0xd8, 0xf1, 0x22} },
+{ 0x9be4, 16, {0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
+{ 0x9bf4, 7, {0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
+{ 0x9bfb, 12, {0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9c07, 16, {0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0x12} },
+{ 0x9c17, 16, {0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
+{ 0x9c27, 16, {0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
+{ 0x9c37, 1, {0x22} },
+{ 0xffff, 0, {0x00} }
+};
+
+#ifdef DEBUG
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000, 3, {0x02, 0x09, 0x8d} },
+{ 0x0033, 3, {0x02, 0x0e, 0x70} },
+{ 0x0043, 3, {0x02, 0x0b, 0x00} },
+{ 0x004b, 3, {0x02, 0x05, 0xb3} },
+{ 0x0100, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110, 16, {0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120, 16, {0x7c, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130, 16, {0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140, 16, {0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150, 16, {0x02, 0x03, 0x7c, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160, 16, {0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x7c, 0x12} },
+{ 0x0170, 16, {0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180, 16, {0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190, 16, {0x7c, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0, 16, {0x03, 0x12, 0x0d, 0xd5, 0xd2, 0x06, 0x12, 0x0d, 0x0d, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0, 16, {0x75, 0x29, 0x00, 0xf5, 0x2a, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x29, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0, 16, {0x75, 0x2b, 0x00, 0xf5, 0x2c, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2b, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0, 16, {0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c} },
+{ 0x01f0, 16, {0xc3, 0xe5, 0x2c, 0x94, 0x40, 0xe5, 0x2b, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2b, 0x2d, 0x85, 0x2c} },
+{ 0x0200, 16, {0x2e, 0x80, 0x06, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210, 16, {0x34, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x5c} },
+{ 0x0220, 16, {0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5, 0x31, 0x35, 0x29, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230, 16, {0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70} },
+{ 0x0240, 16, {0x02, 0x05, 0x31, 0x80, 0xd0, 0xe4, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5} },
+{ 0x0250, 16, {0x31, 0x95, 0x2d, 0x50, 0x18, 0x74, 0x00, 0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260, 16, {0x74, 0xcd, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80, 0xdd, 0xaf, 0x2a, 0xae} },
+{ 0x0270, 16, {0x29, 0xad, 0x2e, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280, 16, {0x2e, 0xf0, 0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5} },
+{ 0x0290, 16, {0x2c, 0x95, 0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0, 16, {0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3, 0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50} },
+{ 0x02b0, 16, {0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0, 16, {0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0, 16, {0x03, 0x02, 0x03, 0x7c, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c, 0xe4, 0x90, 0x7f} },
+{ 0x02e0, 16, {0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3} },
+{ 0x02f0, 16, {0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300, 16, {0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2d, 0x00, 0xf5} },
+{ 0x0310, 16, {0x2e, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x38, 0x90, 0x20, 0x6b, 0xf0, 0xf5, 0x31, 0xf5} },
+{ 0x0320, 16, {0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x32} },
+{ 0x0330, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5} },
+{ 0x0340, 16, {0x31, 0x35, 0x29, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80} },
+{ 0x0350, 16, {0xd0, 0xaf, 0x2a, 0xae, 0x29, 0xad, 0x2e, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x80} },
+{ 0x0360, 16, {0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5, 0x2c, 0x95} },
+{ 0x0370, 13, {0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x02, 0x02, 0xd4, 0xc3} },
+{ 0x037d, 1, {0x22} },
+{ 0x037e, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x56, 0x14, 0x70, 0x03, 0x02, 0x04, 0xd2, 0x24} },
+{ 0x038e, 16, {0xfe, 0x70, 0x03, 0x02, 0x05, 0x46, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x50, 0x14, 0x70, 0x03} },
+{ 0x039e, 16, {0x02, 0x04, 0x4a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3e, 0x14, 0x70, 0x03, 0x02, 0x04, 0x44, 0x24} },
+{ 0x03ae, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x9a, 0x12, 0x0e, 0x7b, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f} },
+{ 0x03be, 16, {0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ce, 16, {0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03de, 16, {0xff, 0x12, 0x0b, 0x58, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ee, 16, {0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90} },
+{ 0x03fe, 16, {0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0c} },
+{ 0x040e, 16, {0x3f, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041e, 16, {0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042e, 16, {0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab} },
+{ 0x043e, 16, {0x12, 0x0e, 0x52, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x60, 0x02, 0x05, 0xab, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044e, 16, {0x05, 0xab, 0x12, 0x08, 0xf1, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7d, 0x40, 0x03, 0x02, 0x05, 0xab} },
+{ 0x045e, 16, {0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046e, 16, {0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047e, 16, {0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048e, 16, {0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049e, 16, {0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04ae, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04be, 16, {0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ce, 16, {0xf0, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7f, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04de, 16, {0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ee, 16, {0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fe, 16, {0xab, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050e, 16, {0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051e, 16, {0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052e, 16, {0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x6e, 0x90} },
+{ 0x053e, 16, {0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x65, 0x12, 0x0e, 0x81, 0x50, 0x60, 0x90, 0x7f, 0xe8} },
+{ 0x054e, 16, {0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x54, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055e, 16, {0xd2, 0x00, 0x80, 0x49, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x40, 0x90, 0x7f, 0xea} },
+{ 0x056e, 16, {0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057e, 16, {0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058e, 16, {0xf0, 0x80, 0x1a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xe4, 0x90, 0x20, 0x6a} },
+{ 0x059e, 16, {0xf0, 0x12, 0x01, 0x00, 0x50, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4} },
+{ 0x05ae, 4, {0xe0, 0x44, 0x02, 0xf0} },
+{ 0x05b2, 1, {0x22} },
+{ 0x05b3, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05c3, 16, {0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05d3, 16, {0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x7f, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05e3, 16, {0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x7f, 0xaf, 0x0d, 0xef} },
+{ 0x05f3, 16, {0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x0603, 16, {0x06, 0x7f, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x0613, 16, {0x00, 0x12, 0x07, 0x85, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x0623, 16, {0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x0633, 16, {0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x0643, 16, {0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x0653, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x0663, 16, {0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x05, 0x0c} },
+{ 0x0673, 16, {0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x0683, 16, {0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x0693, 10, {0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x069d, 16, {0xc2, 0x04, 0xd2, 0x05, 0xe4, 0xf5, 0x25, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12} },
+{ 0x06ad, 16, {0x0e, 0x74, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
+{ 0x06bd, 16, {0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90} },
+{ 0x06cd, 16, {0x7f, 0x93, 0x74, 0x30, 0xf0, 0x12, 0x0a, 0x19, 0x75, 0x24, 0x48, 0x75, 0x23, 0x92, 0x75, 0x22} },
+{ 0x06dd, 16, {0x00, 0x75, 0x21, 0x00, 0xe4, 0xff, 0xfe, 0x7e, 0x05, 0x90, 0x20, 0x68, 0x74, 0x01, 0xf0, 0xa3} },
+{ 0x06ed, 16, {0xde, 0xfc, 0x7e, 0x00, 0x7f, 0x05, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae} },
+{ 0x06fd, 16, {0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x68, 0x30, 0x01, 0x0a, 0xe4, 0x90, 0x20, 0x69} },
+{ 0x070d, 16, {0xf0, 0x12, 0x03, 0x7e, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x77, 0x50, 0x13, 0x12, 0x09} },
+{ 0x071d, 16, {0x00, 0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x8b, 0x12, 0x0e} },
+{ 0x072d, 16, {0x79, 0xc2, 0x03, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0xff, 0x7c, 0xff, 0x78, 0x21, 0x12, 0x08, 0x1d} },
+{ 0x073d, 16, {0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x08, 0x0c, 0x70, 0x1b, 0x75, 0x24} },
+{ 0x074d, 16, {0x48, 0x75, 0x23, 0x92, 0xf5, 0x22, 0xf5, 0x21, 0x63, 0x25, 0xff, 0x90, 0x20, 0x68, 0xe5, 0x25} },
+{ 0x075d, 14, {0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0x12, 0x08, 0xff, 0x80, 0x9b} },
+{ 0x076b, 1, {0x22} },
+{ 0x076c, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x077c, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0785, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0795, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x07a5, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x07b2, 16, {0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x07c2, 16, {0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x07d2, 2, {0xf2, 0x22} },
+{ 0x07d4, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x07e4, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x07f4, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x0804, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x080c, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x081c, 1, {0x22} },
+{ 0x081d, 16, {0x08, 0x08, 0x08, 0xe6, 0x2f, 0xff, 0xf6, 0x18, 0xe6, 0x3e, 0xfe, 0xf6, 0x18, 0xe6, 0x3d, 0xfd} },
+{ 0x082d, 7, {0xf6, 0x18, 0xe6, 0x3c, 0xfc, 0xf6, 0x22} },
+{ 0x0834, 4, {0x8c, 0x34, 0x8d, 0x35} },
+{ 0x0838, 16, {0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95} },
+{ 0x0848, 16, {0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x69, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5} },
+{ 0x0858, 16, {0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0868, 16, {0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0878, 16, {0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5} },
+{ 0x0888, 16, {0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60, 0x02, 0xc3, 0x22, 0xad} },
+{ 0x0898, 16, {0x37, 0xe5, 0x37, 0x2f, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xed, 0xf0, 0xfc, 0xac, 0x05} },
+{ 0x08a8, 16, {0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x37, 0xe5, 0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0x8c} },
+{ 0x08b8, 16, {0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95, 0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x27} },
+{ 0x08c8, 16, {0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe0, 0x65, 0x37, 0x60, 0x02, 0xc3} },
+{ 0x08d8, 16, {0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5} },
+{ 0x08e8, 8, {0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0xce, 0xd3} },
+{ 0x08f0, 1, {0x22} },
+{ 0x08f1, 14, {0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x08ff, 1, {0x22} },
+{ 0x0900, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x3a, 0x02, 0x09, 0xd4} },
+{ 0x0999, 16, {0x02, 0x06, 0x9d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0e, 0x2d, 0xe4, 0x7e} },
+{ 0x09d9, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xd5, 0x90, 0x7f} },
+{ 0x0a39, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49, 16, {0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59, 16, {0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69, 16, {0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79, 16, {0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x22} },
+{ 0x0a89, 16, {0x75, 0x33, 0x01, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99, 16, {0x7d, 0x00, 0x7c, 0x01, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9, 16, {0x0e, 0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9, 16, {0x00, 0x7c, 0x80, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e} },
+{ 0x0ac9, 16, {0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9, 16, {0x7c, 0x5b, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e, 0x18} },
+{ 0x0ae9, 13, {0xe5, 0x33, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0e, 0x18, 0xe5, 0x33, 0x24, 0xff} },
+{ 0x0af6, 1, {0x22} },
+{ 0x0af7, 8, {0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff, 1, {0x32} },
+{ 0x0b00, 16, {0x02, 0x0d, 0xa5, 0x00, 0x02, 0x0d, 0xec, 0x00, 0x02, 0x0d, 0x70, 0x00, 0x02, 0x0d, 0xbd, 0x00} },
+{ 0x0b10, 16, {0x02, 0x0e, 0x02, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x83, 0x00, 0x02, 0x0e, 0x84, 0x00} },
+{ 0x0b20, 16, {0x02, 0x0e, 0x85, 0x00, 0x02, 0x0e, 0x86, 0x00, 0x02, 0x0e, 0x87, 0x00, 0x02, 0x0e, 0x88, 0x00} },
+{ 0x0b30, 16, {0x02, 0x0e, 0x89, 0x00, 0x02, 0x0e, 0x8a, 0x00, 0x02, 0x0e, 0x8b, 0x00, 0x02, 0x0e, 0x8c, 0x00} },
+{ 0x0b40, 16, {0x02, 0x0e, 0x8d, 0x00, 0x02, 0x0e, 0x8e, 0x00, 0x02, 0x0e, 0x8f, 0x00, 0x02, 0x0e, 0x90, 0x00} },
+{ 0x0b50, 8, {0x02, 0x0e, 0x91, 0x00, 0x02, 0x0e, 0x92, 0x00} },
+{ 0x0b58, 16, {0xe4, 0xfe, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x12, 0xab, 0x2b, 0xaa, 0x2c, 0xa9} },
+{ 0x0b68, 16, {0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x07, 0xd4, 0x85, 0xf0, 0x29, 0xf5, 0x2a, 0x62, 0x29} },
+{ 0x0b88, 16, {0xe5, 0x29, 0x62, 0x2a, 0xe5, 0x2a, 0x62, 0x29, 0x29, 0xfd, 0xe5, 0x29, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98, 14, {0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6, 1, {0x22} },
+{ 0x0ba7, 6, {0xab, 0x07, 0xaa, 0x06, 0xac, 0x05} },
+{ 0x0bad, 16, {0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82} },
+{ 0x0bbd, 16, {0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05, 0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82} },
+{ 0x0bcd, 16, {0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d, 0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x0bdd, 16, {0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x10, 0x12, 0x0d, 0x51, 0x7f} },
+{ 0x0bed, 6, {0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5} },
+{ 0x0bf3, 1, {0x22} },
+{ 0x0bf4, 10, {0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0bfe, 16, {0xe4, 0xfd, 0xf5, 0x38, 0xe5, 0x11, 0x60, 0x12, 0xe5, 0x33, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24} },
+{ 0x0c0e, 16, {0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x34, 0xae, 0x05, 0x0d, 0x74} },
+{ 0x0c1e, 16, {0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xe5, 0x34, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0c2e, 16, {0x7b, 0x13, 0x12, 0x0d, 0x51, 0xaf, 0x0f, 0xad, 0x35, 0xab, 0x37, 0xaa, 0x36, 0x12, 0x0d, 0x32} },
+{ 0x0c3e, 1, {0x22} },
+{ 0x0c3f, 2, {0x8f, 0x29} },
+{ 0x0c41, 16, {0xe4, 0xf5, 0x2a, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x32, 0xab, 0x2b, 0xaa, 0x2c} },
+{ 0x0c51, 16, {0xa9, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0xb4, 0x03, 0x1d, 0xaf, 0x2a, 0x05, 0x2a, 0xef} },
+{ 0x0c61, 16, {0xb5, 0x29, 0x01, 0x22, 0x12, 0x07, 0x6c, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0c71, 14, {0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0c7f, 1, {0x22} },
+{ 0x0c80, 10, {0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0c8a, 16, {0xe4, 0xf5, 0x38, 0xe5, 0x38, 0xc3, 0x95, 0x35, 0x50, 0x20, 0x05, 0x34, 0xe5, 0x34, 0xae, 0x33} },
+{ 0x0c9a, 16, {0x70, 0x02, 0x05, 0x33, 0x14, 0xff, 0xe5, 0x37, 0x25, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x36, 0xf5} },
+{ 0x0caa, 10, {0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7, 0x05, 0x38, 0x80, 0xd9} },
+{ 0x0cb4, 1, {0x22} },
+{ 0x0cb5, 16, {0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cc5, 16, {0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0cd5, 13, {0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ce2, 16, {0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cf2, 16, {0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0d02, 11, {0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0d0d, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0d1d, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0d2d, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0d32, 16, {0x12, 0x0c, 0xb5, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d42, 15, {0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d51, 16, {0x12, 0x0c, 0xe2, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d61, 15, {0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d70, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d80, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d8b, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d9b, 10, {0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0da5, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0db5, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dbd, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0dcd, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd5, 16, {0x8e, 0x39, 0x8f, 0x3a, 0xe5, 0x3a, 0x15, 0x3a, 0xae, 0x39, 0x70, 0x02, 0x15, 0x39, 0x4e, 0x60} },
+{ 0x0de5, 7, {0x05, 0x12, 0x0e, 0x41, 0x80, 0xee, 0x22} },
+{ 0x0dec, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dfc, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e02, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0e12, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e18, 16, {0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0e28, 5, {0xfa, 0x12, 0x0d, 0x51, 0x22} },
+{ 0x0e2d, 16, {0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0e3d, 3, {0xa1, 0x86, 0x8e} },
+{ 0x0e40, 1, {0x00} },
+{ 0x0e41, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e51, 1, {0x22} },
+{ 0x0e52, 14, {0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e60, 8, {0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e68, 8, {0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e70, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x0e74, 3, {0xd2, 0x00, 0x22} },
+{ 0x0e77, 2, {0xd3, 0x22} },
+{ 0x0e79, 2, {0xd3, 0x22} },
+{ 0x0e7b, 2, {0xd3, 0x22} },
+{ 0x0e7d, 2, {0xd3, 0x22} },
+{ 0x0e7f, 2, {0xd3, 0x22} },
+{ 0x0e81, 2, {0xd3, 0x22} },
+{ 0x0e83, 1, {0x32} },
+{ 0x0e84, 1, {0x32} },
+{ 0x0e85, 1, {0x32} },
+{ 0x0e86, 1, {0x32} },
+{ 0x0e87, 1, {0x32} },
+{ 0x0e88, 1, {0x32} },
+{ 0x0e89, 1, {0x32} },
+{ 0x0e8a, 1, {0x32} },
+{ 0x0e8b, 1, {0x32} },
+{ 0x0e8c, 1, {0x32} },
+{ 0x0e8d, 1, {0x32} },
+{ 0x0e8e, 1, {0x32} },
+{ 0x0e8f, 1, {0x32} },
+{ 0x0e90, 1, {0x32} },
+{ 0x0e91, 1, {0x32} },
+{ 0x0e92, 1, {0x32} },
+{ 0x1100, 16, {0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110, 16, {0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120, 16, {0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130, 16, {0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140, 16, {0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150, 16, {0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160, 16, {0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170, 16, {0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180, 16, {0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190, 16, {0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0, 16, {0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0, 16, {0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0, 16, {0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0, 2, {0x00, 0x00} },
+{ 0xffff, 0, {0x00} }
+};
+
+#else
+
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000, 3, {0x02, 0x09, 0x8d} },
+{ 0x0033, 3, {0x02, 0x08, 0xfb} },
+{ 0x0043, 3, {0x02, 0x0b, 0x00} },
+{ 0x004b, 3, {0x02, 0x05, 0xaa} },
+{ 0x0100, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110, 16, {0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120, 16, {0x78, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130, 16, {0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140, 16, {0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150, 16, {0x02, 0x03, 0x78, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160, 16, {0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x78, 0x12} },
+{ 0x0170, 16, {0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180, 16, {0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190, 16, {0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x78, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0, 16, {0x03, 0x12, 0x0d, 0x94, 0xd2, 0x06, 0x12, 0x0c, 0xcc, 0x02, 0x03, 0x78, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0, 16, {0x75, 0x28, 0x00, 0xf5, 0x29, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x28, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0, 16, {0x75, 0x2a, 0x00, 0xf5, 0x2b, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2a, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0, 16, {0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78} },
+{ 0x01f0, 16, {0xc3, 0xe5, 0x2b, 0x94, 0x40, 0xe5, 0x2a, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2a, 0x2c, 0x85, 0x2b} },
+{ 0x0200, 16, {0x2d, 0x80, 0x06, 0x75, 0x2c, 0x00, 0x75, 0x2d, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210, 16, {0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x5c} },
+{ 0x0220, 16, {0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230, 16, {0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70} },
+{ 0x0240, 16, {0x02, 0x05, 0x30, 0x80, 0xd0, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5} },
+{ 0x0250, 16, {0x30, 0x95, 0x2c, 0x50, 0x18, 0x74, 0x00, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260, 16, {0x74, 0xcd, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xdd, 0xaf, 0x29, 0xae} },
+{ 0x0270, 16, {0x28, 0xad, 0x2d, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280, 16, {0x2d, 0xf0, 0xe5, 0x2d, 0x25, 0x29, 0xf5, 0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5} },
+{ 0x0290, 16, {0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a, 0x95, 0x2c, 0xf5, 0x2a, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0, 16, {0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3, 0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50} },
+{ 0x02b0, 16, {0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0, 16, {0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0, 16, {0x03, 0x02, 0x03, 0x78, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78, 0xe4, 0x90, 0x7f} },
+{ 0x02e0, 16, {0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3} },
+{ 0x02f0, 16, {0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300, 16, {0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2c, 0x00, 0xf5} },
+{ 0x0310, 16, {0x2d, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31} },
+{ 0x0320, 16, {0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0330, 1, {0x7e} },
+{ 0x0331, 16, {0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83} },
+{ 0x0341, 16, {0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xd0, 0xaf, 0x29, 0xae, 0x28} },
+{ 0x0351, 16, {0xad, 0x2d, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x3f, 0xe5, 0x2d, 0x25, 0x29, 0xf5} },
+{ 0x0361, 16, {0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a} },
+{ 0x0371, 9, {0x95, 0x2c, 0xf5, 0x2a, 0x02, 0x02, 0xd4, 0xc3, 0x22} },
+{ 0x037a, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0xce, 0x24} },
+{ 0x038a, 16, {0xfe, 0x70, 0x03, 0x02, 0x05, 0x42, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x4c, 0x14, 0x70, 0x03} },
+{ 0x039a, 16, {0x02, 0x04, 0x46, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x40, 0x24} },
+{ 0x03aa, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x96, 0x12, 0x0e, 0x44, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f} },
+{ 0x03ba, 16, {0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ca, 16, {0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03da, 16, {0xff, 0x12, 0x0b, 0x58, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ea, 16, {0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90} },
+{ 0x03fa, 16, {0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08} },
+{ 0x040a, 16, {0xba, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041a, 16, {0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042a, 16, {0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2} },
+{ 0x043a, 16, {0x12, 0x0e, 0x1f, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x2d, 0x02, 0x05, 0xa2, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044a, 16, {0x05, 0xa2, 0x12, 0x0e, 0x11, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x46, 0x40, 0x03, 0x02, 0x05, 0xa2} },
+{ 0x045a, 16, {0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046a, 16, {0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047a, 16, {0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048a, 16, {0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049a, 16, {0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04aa, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04ba, 16, {0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ca, 16, {0xf0, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x48, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04da, 16, {0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ea, 16, {0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fa, 16, {0xa2, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050a, 16, {0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051a, 16, {0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052a, 16, {0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x69, 0x90} },
+{ 0x053a, 16, {0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x60, 0x12, 0x0e, 0x4a, 0x50, 0x5b, 0x90, 0x7f, 0xe8} },
+{ 0x054a, 16, {0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055a, 16, {0xd2, 0x00, 0x80, 0x44, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x3b, 0x90, 0x7f, 0xea} },
+{ 0x056a, 16, {0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057a, 16, {0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058a, 16, {0xf0, 0x80, 0x15, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0c, 0x12, 0x01, 0x00, 0x50} },
+{ 0x059a, 16, {0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22} },
+{ 0x05aa, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05ba, 16, {0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05ca, 16, {0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x76, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05da, 16, {0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x76, 0xaf, 0x0d, 0xef} },
+{ 0x05ea, 16, {0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x05fa, 16, {0x06, 0x76, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x060a, 16, {0x00, 0x12, 0x08, 0x22, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x061a, 16, {0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x062a, 16, {0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x063a, 16, {0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x064a, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x065a, 16, {0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x05, 0x0c} },
+{ 0x066a, 16, {0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x067a, 16, {0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x068a, 10, {0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0694, 16, {0x8c, 0x33, 0x8d, 0x34, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x36} },
+{ 0x06a4, 16, {0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35, 0x95, 0x33, 0x50, 0x69, 0xef, 0x25, 0x36, 0xf5, 0x82} },
+{ 0x06b4, 16, {0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06c4, 16, {0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06d4, 16, {0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22} },
+{ 0x06e4, 16, {0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60} },
+{ 0x06f4, 16, {0x02, 0xc3, 0x22, 0xad, 0x36, 0xe5, 0x36, 0x2f, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xed} },
+{ 0x0704, 16, {0xf0, 0xfc, 0xac, 0x05, 0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02} },
+{ 0x0714, 16, {0x05, 0x35, 0x80, 0x8c, 0xe4, 0xf5, 0x35, 0xf5, 0x36, 0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35} },
+{ 0x0724, 16, {0x95, 0x33, 0x50, 0x27, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe0, 0x65} },
+{ 0x0734, 16, {0x36, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4} },
+{ 0x0744, 13, {0xf0, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02, 0x05, 0x35, 0x80, 0xce, 0xd3, 0x22} },
+{ 0x0751, 16, {0xc2, 0x04, 0xd2, 0x05, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12, 0x0e, 0x3d, 0xd2} },
+{ 0x0761, 16, {0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f} },
+{ 0x0771, 16, {0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x7f, 0x93, 0x74} },
+{ 0x0781, 16, {0x30, 0xf0, 0x12, 0x0a, 0x19, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0} },
+{ 0x0791, 16, {0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x35, 0x20, 0x01, 0x42, 0x75, 0x24, 0x00, 0x75, 0x23} },
+{ 0x07a1, 16, {0x00, 0x75, 0x22, 0x00, 0x75, 0x21, 0x00, 0x7f, 0x48, 0x7e, 0x92, 0x7d, 0x00, 0x7c, 0x00, 0xab} },
+{ 0x07b1, 16, {0x24, 0xaa, 0x23, 0xa9, 0x22, 0xa8, 0x21, 0xc3, 0x12, 0x08, 0xa9, 0x50, 0xdb, 0x20, 0x01, 0xd8} },
+{ 0x07c1, 16, {0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xe5, 0x24, 0x24, 0x01, 0xf5, 0x24, 0xea, 0x35, 0x23, 0xf5} },
+{ 0x07d1, 16, {0x23, 0xe9, 0x35, 0x22, 0xf5, 0x22, 0xe8, 0x35, 0x21, 0xf5, 0x21, 0x80, 0xca, 0x30, 0x01, 0x05} },
+{ 0x07e1, 16, {0x12, 0x03, 0x7a, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x40, 0x50, 0x13, 0x12, 0x09, 0x00} },
+{ 0x07f1, 16, {0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x4a, 0x12, 0x0e, 0x42} },
+{ 0x0801, 8, {0xc2, 0x03, 0x12, 0x08, 0xff, 0x80, 0xd6, 0x22} },
+{ 0x0809, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0819, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0822, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0832, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0842, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x084f, 16, {0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x085f, 16, {0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x086f, 2, {0xf2, 0x22} },
+{ 0x0871, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x0881, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x0891, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x08a1, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x08a9, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x08b9, 1, {0x22} },
+{ 0x08ba, 2, {0x8f, 0x28} },
+{ 0x08bc, 16, {0xe4, 0xf5, 0x29, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x32, 0xab, 0x2a, 0xaa, 0x2b} },
+{ 0x08cc, 16, {0xa9, 0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0xb4, 0x03, 0x1d, 0xaf, 0x29, 0x05, 0x29, 0xef} },
+{ 0x08dc, 16, {0xb5, 0x28, 0x01, 0x22, 0x12, 0x08, 0x09, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x08ec, 14, {0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x08fa, 1, {0x22} },
+{ 0x08fb, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x08ff, 1, {0x22} },
+{ 0x0900, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x39, 0x02, 0x09, 0xd4} },
+{ 0x0999, 16, {0x02, 0x07, 0x51, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0xec, 0xe4, 0x7e} },
+{ 0x09d9, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0x94, 0x90, 0x7f} },
+{ 0x0a39, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49, 16, {0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59, 16, {0x7e, 0x00, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69, 16, {0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79, 16, {0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0a89, 16, {0x75, 0x32, 0x01, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99, 16, {0x7d, 0x00, 0x7c, 0x01, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9, 16, {0x0d, 0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9, 16, {0x00, 0x7c, 0x80, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d} },
+{ 0x0ac9, 16, {0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9, 16, {0x7c, 0x5b, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d, 0xd7} },
+{ 0x0ae9, 14, {0xe5, 0x32, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0d, 0xd7, 0xe5, 0x32, 0x24, 0xff, 0x22} },
+{ 0x0af7, 8, {0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff, 1, {0x32} },
+{ 0x0b00, 16, {0x02, 0x0d, 0x64, 0x00, 0x02, 0x0d, 0xab, 0x00, 0x02, 0x0d, 0x2f, 0x00, 0x02, 0x0d, 0x7c, 0x00} },
+{ 0x0b10, 16, {0x02, 0x0d, 0xc1, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x4c, 0x00, 0x02, 0x0e, 0x4d, 0x00} },
+{ 0x0b20, 16, {0x02, 0x0e, 0x4e, 0x00, 0x02, 0x0e, 0x4f, 0x00, 0x02, 0x0e, 0x50, 0x00, 0x02, 0x0e, 0x51, 0x00} },
+{ 0x0b30, 16, {0x02, 0x0e, 0x52, 0x00, 0x02, 0x0e, 0x53, 0x00, 0x02, 0x0e, 0x54, 0x00, 0x02, 0x0e, 0x55, 0x00} },
+{ 0x0b40, 16, {0x02, 0x0e, 0x56, 0x00, 0x02, 0x0e, 0x57, 0x00, 0x02, 0x0e, 0x58, 0x00, 0x02, 0x0e, 0x59, 0x00} },
+{ 0x0b50, 8, {0x02, 0x0e, 0x5a, 0x00, 0x02, 0x0e, 0x5b, 0x00} },
+{ 0x0b58, 16, {0xe4, 0xfe, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x12, 0xab, 0x2a, 0xaa, 0x2b, 0xa9} },
+{ 0x0b68, 16, {0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x08, 0x71, 0x85, 0xf0, 0x28, 0xf5, 0x29, 0x62, 0x28} },
+{ 0x0b88, 16, {0xe5, 0x28, 0x62, 0x29, 0xe5, 0x29, 0x62, 0x28, 0x29, 0xfd, 0xe5, 0x28, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98, 14, {0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6, 1, {0x22} },
+{ 0x0ba7, 16, {0xab, 0x07, 0xaa, 0x06, 0xac, 0x05, 0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05} },
+{ 0x0bb7, 16, {0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05} },
+{ 0x0bc7, 16, {0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d} },
+{ 0x0bd7, 16, {0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0be7, 13, {0x7b, 0x10, 0x12, 0x0d, 0x10, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0bf4, 16, {0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xfd, 0xf5, 0x37, 0xe5, 0x11} },
+{ 0x0c04, 16, {0x60, 0x12, 0xe5, 0x32, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f} },
+{ 0x0c14, 16, {0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x33, 0xae, 0x05, 0x0d, 0x74, 0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0c24, 16, {0x0f, 0xf5, 0x83, 0xe5, 0x33, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x13, 0x12, 0x0d, 0x10, 0xaf} },
+{ 0x0c34, 11, {0x0f, 0xad, 0x34, 0xab, 0x36, 0xaa, 0x35, 0x12, 0x0c, 0xf1, 0x22} },
+{ 0x0c3f, 16, {0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0xc3} },
+{ 0x0c4f, 16, {0x95, 0x34, 0x50, 0x20, 0x05, 0x33, 0xe5, 0x33, 0xae, 0x32, 0x70, 0x02, 0x05, 0x32, 0x14, 0xff} },
+{ 0x0c5f, 16, {0xe5, 0x36, 0x25, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x35, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7} },
+{ 0x0c6f, 5, {0x05, 0x37, 0x80, 0xd9, 0x22} },
+{ 0x0c74, 16, {0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0c84, 16, {0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0c94, 13, {0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ca1, 16, {0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cb1, 16, {0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0cc1, 11, {0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ccc, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0cdc, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0cec, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0cf1, 16, {0x12, 0x0c, 0x74, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d01, 15, {0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d10, 16, {0x12, 0x0c, 0xa1, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d20, 15, {0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d2f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d3f, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d4a, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d5a, 10, {0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0d64, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0d74, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7c, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0d8c, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d94, 16, {0x8e, 0x38, 0x8f, 0x39, 0xe5, 0x39, 0x15, 0x39, 0xae, 0x38, 0x70, 0x02, 0x15, 0x38, 0x4e, 0x60} },
+{ 0x0da4, 7, {0x05, 0x12, 0x0e, 0x00, 0x80, 0xee, 0x22} },
+{ 0x0dab, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dbb, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dc1, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0dd1, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd7, 16, {0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0de7, 5, {0xfa, 0x12, 0x0d, 0x10, 0x22} },
+{ 0x0dec, 16, {0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0dfc, 3, {0xa1, 0x86, 0x8e} },
+{ 0x0dff, 1, {0x00} },
+{ 0x0e00, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e10, 1, {0x22} },
+{ 0x0e11, 14, {0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e1f, 14, {0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e2d, 8, {0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e35, 8, {0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e3d, 3, {0xd2, 0x00, 0x22} },
+{ 0x0e40, 2, {0xd3, 0x22} },
+{ 0x0e42, 2, {0xd3, 0x22} },
+{ 0x0e44, 2, {0xd3, 0x22} },
+{ 0x0e46, 2, {0xd3, 0x22} },
+{ 0x0e48, 2, {0xd3, 0x22} },
+{ 0x0e4a, 2, {0xd3, 0x22} },
+{ 0x0e4c, 1, {0x32} },
+{ 0x0e4d, 1, {0x32} },
+{ 0x0e4e, 1, {0x32} },
+{ 0x0e4f, 1, {0x32} },
+{ 0x0e50, 1, {0x32} },
+{ 0x0e51, 1, {0x32} },
+{ 0x0e52, 1, {0x32} },
+{ 0x0e53, 1, {0x32} },
+{ 0x0e54, 1, {0x32} },
+{ 0x0e55, 1, {0x32} },
+{ 0x0e56, 1, {0x32} },
+{ 0x0e57, 1, {0x32} },
+{ 0x0e58, 1, {0x32} },
+{ 0x0e59, 1, {0x32} },
+{ 0x0e5a, 1, {0x32} },
+{ 0x0e5b, 1, {0x32} },
+{ 0x1100, 16, {0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110, 16, {0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120, 16, {0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130, 16, {0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140, 16, {0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150, 16, {0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160, 16, {0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170, 16, {0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180, 16, {0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190, 16, {0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0, 16, {0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0, 16, {0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0, 16, {0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0, 2, {0x00, 0x00} },
+{ 0xffff, 0, {0x00} }
+};
+#endif
diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c
new file mode 100644
index 000000000..b8fef7891
--- /dev/null
+++ b/drivers/usb/wmforce.c
@@ -0,0 +1,165 @@
+/*
+ * wmforce.c Version 0.1
+ *
+ * Copyright (c) 1999 Vojtech Pavlik
+ *
+ * USB Logitech WingMan Force tablet support
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include "usb.h"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
+
+struct wmforce {
+ signed char data[8];
+ struct input_dev dev;
+ struct urb irq;
+};
+
+static struct {
+ __s32 x;
+ __s32 y;
+} wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static void wmforce_irq(struct urb *urb)
+{
+ struct wmforce *wmforce = urb->context;
+ unsigned char *data = wmforce->data;
+ struct input_dev *dev = &wmforce->dev;
+
+ if (urb->status) return;
+
+ if (data[0] != 1) {
+ if (data[0] != 2)
+ warn("received unknown report #%d", data[0]);
+ return;
+ }
+
+ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[2] << 8) | data[1]));
+ input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[4] << 8) | data[3]));
+ input_report_abs(dev, ABS_THROTTLE, data[5]);
+ input_report_abs(dev, ABS_HAT0X, wmforce_hat_to_axis[data[7] >> 4].x);
+ input_report_abs(dev, ABS_HAT0Y, wmforce_hat_to_axis[data[7] >> 4].y);
+
+ input_report_key(dev, BTN_TRIGGER, !!(data[6] & 0x01));
+ input_report_key(dev, BTN_TOP, !!(data[6] & 0x02));
+ input_report_key(dev, BTN_THUMB, !!(data[6] & 0x04));
+ input_report_key(dev, BTN_TOP2, !!(data[6] & 0x08));
+ input_report_key(dev, BTN_BASE, !!(data[6] & 0x10));
+ input_report_key(dev, BTN_BASE2, !!(data[6] & 0x20));
+ input_report_key(dev, BTN_BASE3, !!(data[6] & 0x40));
+ input_report_key(dev, BTN_BASE4, !!(data[6] & 0x80));
+ input_report_key(dev, BTN_BASE5, !!(data[7] & 0x01));
+}
+
+static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_endpoint_descriptor *endpoint;
+ struct wmforce *wmforce;
+ int i;
+
+ if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
+ dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
+ return NULL;
+
+ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+ if (!(wmforce = kmalloc(sizeof(struct wmforce), GFP_KERNEL))) return NULL;
+ memset(wmforce, 0, sizeof(struct wmforce));
+
+ wmforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ wmforce->dev.keybit[LONG(BTN_JOYSTICK)] = BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
+ BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
+ wmforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
+
+ for (i = ABS_X; i <= ABS_Y; i++) {
+ wmforce->dev.absmax[i] = 1920;
+ wmforce->dev.absmin[i] = -1920;
+ wmforce->dev.absfuzz[i] = 0;
+ wmforce->dev.absflat[i] = 128;
+ }
+
+ wmforce->dev.absmax[ABS_THROTTLE] = 0;
+ wmforce->dev.absmin[ABS_THROTTLE] = 255;
+ wmforce->dev.absfuzz[ABS_THROTTLE] = 0;
+ wmforce->dev.absflat[ABS_THROTTLE] = 0;
+
+ for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
+ wmforce->dev.absmax[i] = 1;
+ wmforce->dev.absmin[i] = -1;
+ wmforce->dev.absfuzz[i] = 0;
+ wmforce->dev.absflat[i] = 0;
+ }
+
+ FILL_INT_URB(&wmforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wmforce->data, 8, wmforce_irq, wmforce, endpoint->bInterval);
+
+ if (usb_submit_urb(&wmforce->irq)) {
+ kfree(wmforce);
+ return NULL;
+ }
+
+ input_register_device(&wmforce->dev);
+
+ printk(KERN_INFO "input%d: Logitech WingMan Force USB\n", wmforce->dev.number);
+
+ return wmforce;
+}
+
+static void wmforce_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct wmforce *wmforce = ptr;
+ usb_unlink_urb(&wmforce->irq);
+ input_unregister_device(&wmforce->dev);
+ kfree(wmforce);
+}
+
+static struct usb_driver wmforce_driver = {
+ name: "wmforce",
+ probe: wmforce_probe,
+ disconnect: wmforce_disconnect,
+};
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ usb_deregister(&wmforce_driver);
+}
+
+int init_module(void)
+#else
+int wmforce_init(void)
+#endif
+{
+ usb_register(&wmforce_driver);
+ return 0;
+}
diff --git a/drivers/video/aty128.h b/drivers/video/aty128.h
index cdc15e04f..7b6342e6a 100644
--- a/drivers/video/aty128.h
+++ b/drivers/video/aty128.h
@@ -3,65 +3,33 @@
* Register definitions for ATI Rage128 boards
*
* Anthony Tong <atong@uiuc.edu>, 1999
+ * Brad Douglas <brad@neruo.com>, 2000
*/
#ifndef REG_RAGE128_H
#define REG_RAGE128_H
-#define MM_INDEX 0x0000
-#define MM_DATA 0x0004
#define CLOCK_CNTL_INDEX 0x0008
#define CLOCK_CNTL_DATA 0x000c
#define BIOS_0_SCRATCH 0x0010
-#define BIOS_1_SCRATCH 0x0014
-#define BIOS_2_SCRATCH 0x0018
-#define BIOS_3_SCRATCH 0x001c
#define BUS_CNTL 0x0030
-#define BUS_CNTL1 0x0034
-#define MEM_VGA_WP_SEL 0x0038
-#define MEM_VGA_RP_SEL 0x003c
#define GEN_INT_CNTL 0x0040
-#define GEN_INT_STATUS 0x0044
#define CRTC_GEN_CNTL 0x0050
#define CRTC_EXT_CNTL 0x0054
#define DAC_CNTL 0x0058
-#define CRTC_STATUS 0x005c
-#define GPIO_MONID 0x0068
#define I2C_CNTL_1 0x0094
#define PALETTE_INDEX 0x00b0
#define PALETTE_DATA 0x00b4
#define CONFIG_CNTL 0x00e0
-#define CONFIG_XSTRAP 0x00e4
-#define CONFIG_BONDS 0x00e8
#define GEN_RESET_CNTL 0x00f0
-#define GEN_STATUS 0x00f4
#define CONFIG_MEMSIZE 0x00f8
-#define CONFIG_APER_0_BASE 0x0100
-#define CONFIG_APER_1_BASE 0x0104
-#define CONFIG_APER_SIZE 0x0108
-#define CONFIG_REG_1_BASE 0x010c
-#define CONFIG_REG_APER_SIZE 0x0110
-#define CONFIG_MEMSIZE_EMBEDDED 0x0114
-#define TEST_DEBUG_CNTL 0x0120
-#define TEST_DEBUG_MUX 0x0124
-#define HW_DEBUG 0x0128
-#define TEST_DEBUG_OUT 0x012c
-#define HOST_PATH_CNTL 0x0130
-#define SW_SEMAPHORE 0x013c
#define MEM_CNTL 0x0140
-#define EXT_MEM_CNTL 0x0144
-#define MEM_ADDR_CONFIG 0x0148
-#define MEM_INTF_CNTL 0x014c
-#define MEM_STR_CNTL 0x0150
-#define MEM_INIT_LAT_TIMER 0x0154
-#define MEM_SDRAM_MODE_REG 0x0158
#define AGP_BASE 0x0170
#define AGP_CNTL 0x0174
#define AGP_APER_OFFSET 0x0178
#define PCI_GART_PAGE 0x017c
#define PC_NGUI_MODE 0x0180
#define PC_NGUI_CTLSTAT 0x0184
-#define VIDEOMUX_CNTL 0x0190
#define MPP_TB_CONFIG 0x01C0
#define MPP_GP_CONFIG 0x01C8
#define VIPH_CONTROL 0x01D0
@@ -69,72 +37,17 @@
#define CRTC_H_SYNC_STRT_WID 0x0204
#define CRTC_V_TOTAL_DISP 0x0208
#define CRTC_V_SYNC_STRT_WID 0x020c
-#define CRTC_VLINE_CRNT_VLINE 0x0210
-#define CRTC_CRNT_FRAME 0x0214
-#define CRTC_GUI_TRIG_VLINE 0x0218
-#define CRTC_DEBUG 0x021c
#define CRTC_OFFSET 0x0224
#define CRTC_OFFSET_CNTL 0x0228
#define CRTC_PITCH 0x022c
#define OVR_CLR 0x0230
#define OVR_WID_LEFT_RIGHT 0x0234
#define OVR_WID_TOP_BOTTOM 0x0238
-#define SNAPSHOT_VH_COUNTS 0x0240
-#define SNAPSHOT_F_COUNT 0x0244
-#define N_VIF_COUNT 0x0248
-#define SNAPSHOT_VIF_COUNT 0x024c
-#define CUR_OFFSET 0x0260
-#define CUR_HORZ_VERT_POSN 0x0264
-#define CUR_HORZ_VERT_OFF 0x0268
-#define CUR_CLR0 0x026c
-#define CUR_CLR1 0x0270
-#define DAC_CRC_SIG 0x02cc
#define DDA_CONFIG 0x02e0
#define DDA_ON_OFF 0x02e4
#define VGA_DDA_CONFIG 0x02e8
#define VGA_DDA_ON_OFF 0x02ec
-#define OV0_Y_X_START 0x0400
-#define OV0_Y_X_END 0x0404
-#define OV0_EXCLUSIVE_HORZ 0x0408
-#define OV0_EXCLUSIVE_VERT 0x040c
-#define OV0_REG_LOAD_CNTL 0x0410
#define OV0_SCALE_CNTL 0x0420
-#define OV0_V_INC 0x0424
-#define OV0_P1_V_ACCUM_INIT 0x0428
-#define OV0_P23_V_ACCUM_INIT 0x042c
-#define OV0_P1_BLANK_LINES_AT_TOP 0x0430
-#define OV0_P23_BLANK_LINES_AT_TOP 0x0434
-#define OV0_VID_BUF0_BASE_ADRS 0x0440
-#define OV0_VID_BUF1_BASE_ADRS 0x0444
-#define OV0_VID_BUF2_BASE_ADRS 0x0448
-#define OV0_VID_BUF3_BASE_ADRS 0x044c
-#define OV0_VID_BUF4_BASE_ADRS 0x0450
-#define OV0_VID_BUF5_BASE_ADRS 0x0454
-#define OV0_VID_BUF_PITCH0_VALUE 0x0460
-#define OV0_VID_BUF_PITCH1_VALUE 0x0464
-#define OV0_OCTWORDS_PER_LINE_M1 0x046c
-#define OV0_AUTO_FLIP_CNTRL 0x0470
-#define OV0_DEINTERLACE_PATTERN 0x0474
-#define OV0_H_INC 0x0480
-#define OV0_STEP_BY 0x0484
-#define OV0_P1_H_ACCUM_INIT 0x0488
-#define OV0_P23_H_ACCUM_INIT 0x048c
-#define OV0_P1_X_START_END 0x0494
-#define OV0_P2_X_START_END 0x0498
-#define OV0_P3_X_START_END 0x049c
-#define OV0_FILTER_CNTL 0x04a0
-#define OV0_FOUR_TAP_COEF_0 0x04b0
-#define OV0_FOUR_TAP_COEF_1 0x04b4
-#define OV0_FOUR_TAP_COEF_2 0x04b8
-#define OV0_FOUR_TAP_COEF_3 0x04bc
-#define OV0_FOUR_TAP_COEF_4 0x04c0
-#define OV0_COLOR_CNTL 0x04e0
-#define OV0_VIDEO_KEY_CLR 0x04e4
-#define OV0_VIDEO_KEY_MASK 0x04e8
-#define OV0_GRAPHICS_KEY_CLR 0x04ec
-#define OV0_GRAPHICS_KEY_MASK 0x04f0
-#define OV0_KEY_CNTL 0x04f4
-#define OV0_TEST 0x04f8
#define SUBPIC_CNTL 0x0540
#define PM4_BUFFER_OFFSET 0x0700
#define PM4_BUFFER_CNTL 0x0704
@@ -152,9 +65,7 @@
#define PM4_IW_INDOFF 0x0738
#define PM4_IW_INDSIZE 0x073c
#define PM4_FPU_FPX0 0x0740
-#define CRC_CMDFIFO_ADDR 0x0740
#define PM4_FPU_FPY0 0x0744
-#define CRC_CMDFIFO_DOUT 0x0744
#define PM4_FPU_FPX1 0x0748
#define PM4_FPU_FPY1 0x074c
#define PM4_FPU_FPX2 0x0750
@@ -189,77 +100,8 @@
#define PM4_BUFFER_DATAH 0x07f4
#define PM4_BUFFER_DATAL 0x07f8
#define PM4_MICRO_CNTL 0x07fc
-#define VID_BUFFER_CONTROL 0x0900
-#define CAP_INT_CNTL 0x0908
-#define CAP_INT_STATUS 0x090c
-#define CAP0_BUF0_OFFSET 0x0920
-#define CAP0_BUF1_OFFSET 0x0924
-#define CAP0_BUF0_EVEN_OFFSET 0x0928
-#define CAP0_BUF1_EVEN_OFFSET 0x092c
-#define CAP0_BUF_PITCH 0x0930
-#define CAP0_V_WINDOW 0x0934
-#define CAP0_H_WINDOW 0x0938
-#define CAP0_VBI_ODD_OFFSET 0x093c
-#define CAP0_VBI_EVEN_OFFSET 0x0940
-#define CAP0_VBI_V_WINDOW 0x0944
-#define CAP0_VBI_H_WINDOW 0x0948
-#define CAP0_PORT_MODE_CNTL 0x094c
#define CAP0_TRIG_CNTL 0x0950
-#define CAP0_DEBUG 0x0954
-#define CAP0_CONFIG 0x0958
-#define CAP0_ANC_ODD_OFFSET 0x095c
-#define CAP0_ANC_EVEN_OFFSET 0x0960
-#define CAP0_ANC_H_WINDOW 0x0964
-#define CAP0_VIDEO_SYNC_TEST 0x0968
-#define CAP0_ONESHOT_BUF_OFFSET 0x096c
-#define CAP0_BUF_STATUS 0x0970
-#define CAP0_DWNSC_XRATIO 0x0978
-#define CAP0_XSHARPNESS 0x097c
-#define CAP1_BUF0_OFFSET 0x0990
-#define CAP1_BUF1_OFFSET 0x0994
-#define CAP1_BUF0_EVEN_OFFSET 0x0998
-#define CAP1_BUF1_EVEN_OFFSET 0x099c
-#define CAP1_BUF_PITCH 0x09a0
-#define CAP1_V_WINDOW 0x09a4
-#define CAP1_H_WINDOW 0x09a8
-#define CAP1_VBI_ODD_OFFSET 0x09ac
-#define CAP1_VBI_EVEN_OFFSET 0x09b0
-#define CAP1_VBI_V_WINDOW 0x09b4
-#define CAP1_VBI_H_WINDOW 0x09b8
-#define CAP1_PORT_MODE_CNTL 0x09bc
#define CAP1_TRIG_CNTL 0x09c0
-#define CAP1_DEBUG 0x09c4
-#define CAP1_CONFIG 0x09c8
-#define CAP1_ANC_ODD_OFFSET 0x09cc
-#define CAP1_ANC_EVEN_OFFSET 0x09d0
-#define CAP1_ANC_H_WINDOW 0x09d4
-#define CAP1_VIDEO_SYNC_TEST 0x09d8
-#define CAP1_ONESHOT_BUF_OFFSET 0x09dc
-#define CAP1_BUF_STATUS 0x09e0
-#define CAP1_DWNSC_XRATIO 0x09e8
-#define CAP1_XSHARPNESS 0x09ec
-#define BM_FRAME_BUF_OFFSET 0x0a00
-#define BM_SYSTEM_MEM_ADDR 0x0a04
-#define BM_COMMAND 0x0a08
-#define BM_STATUS 0x0a0c
-#define BM_QUEUE_STATUS 0x0a10
-#define BM_QUEUE_FREE_STATUS 0x0A14
-#define BM_CHUNK_0_VAL 0x0a18
-#define BM_CHUNK_1_VAL 0x0a1C
-#define BM_VIP0_BUF 0x0A20
-#define BM_VIP0_ACTIVE 0x0A24
-#define BM_VIP1_BUF 0x0A30
-#define BM_VIP1_ACTIVE 0x0A34
-#define BM_VIP2_BUF 0x0A40
-#define BM_VIP2_ACTIVE 0x0A44
-#define BM_VIP3_BUF 0x0A50
-#define BM_VIP3_ACTIVE 0x0A54
-#define BM_VIDCAP_BUF0 0x0a60
-#define BM_VIDCAP_BUF1 0x0a64
-#define BM_VIDCAP_BUF2 0x0a68
-#define BM_VIDCAP_ACTIVE 0x0a6c
-#define BM_GUI 0x0a80
-#define SURFACE_DELAY 0x0b00
/******************************************************************************
* GUI Block Memory Mapped Registers *
@@ -286,70 +128,6 @@
#define BRUSH_Y_X 0x1474
#define DP_BRUSH_BKGD_CLR 0x1478
#define DP_BRUSH_FRGD_CLR 0x147c
-#define BRUSH_DATA0 0x1480
-#define BRUSH_DATA1 0x1484
-#define BRUSH_DATA2 0x1488
-#define BRUSH_DATA3 0x148c
-#define BRUSH_DATA4 0x1490
-#define BRUSH_DATA5 0x1494
-#define BRUSH_DATA6 0x1498
-#define BRUSH_DATA7 0x149c
-#define BRUSH_DATA8 0x14a0
-#define BRUSH_DATA9 0x14a4
-#define BRUSH_DATA10 0x14a8
-#define BRUSH_DATA11 0x14ac
-#define BRUSH_DATA12 0x14b0
-#define BRUSH_DATA13 0x14b4
-#define BRUSH_DATA14 0x14b8
-#define BRUSH_DATA15 0x14bc
-#define BRUSH_DATA16 0x14c0
-#define BRUSH_DATA17 0x14c4
-#define BRUSH_DATA18 0x14c8
-#define BRUSH_DATA19 0x14cc
-#define BRUSH_DATA20 0x14d0
-#define BRUSH_DATA21 0x14d4
-#define BRUSH_DATA22 0x14d8
-#define BRUSH_DATA23 0x14dc
-#define BRUSH_DATA24 0x14e0
-#define BRUSH_DATA25 0x14e4
-#define BRUSH_DATA26 0x14e8
-#define BRUSH_DATA27 0x14ec
-#define BRUSH_DATA28 0x14f0
-#define BRUSH_DATA29 0x14f4
-#define BRUSH_DATA30 0x14f8
-#define BRUSH_DATA31 0x14fc
-#define BRUSH_DATA32 0x1500
-#define BRUSH_DATA33 0x1504
-#define BRUSH_DATA34 0x1508
-#define BRUSH_DATA35 0x150c
-#define BRUSH_DATA36 0x1510
-#define BRUSH_DATA37 0x1514
-#define BRUSH_DATA38 0x1518
-#define BRUSH_DATA39 0x151c
-#define BRUSH_DATA40 0x1520
-#define BRUSH_DATA41 0x1524
-#define BRUSH_DATA42 0x1528
-#define BRUSH_DATA43 0x152c
-#define BRUSH_DATA44 0x1530
-#define BRUSH_DATA45 0x1534
-#define BRUSH_DATA46 0x1538
-#define BRUSH_DATA47 0x153c
-#define BRUSH_DATA48 0x1540
-#define BRUSH_DATA49 0x1544
-#define BRUSH_DATA50 0x1548
-#define BRUSH_DATA51 0x154c
-#define BRUSH_DATA52 0x1550
-#define BRUSH_DATA53 0x1554
-#define BRUSH_DATA54 0x1558
-#define BRUSH_DATA55 0x155c
-#define BRUSH_DATA56 0x1560
-#define BRUSH_DATA57 0x1564
-#define BRUSH_DATA58 0x1568
-#define BRUSH_DATA59 0x156c
-#define BRUSH_DATA60 0x1570
-#define BRUSH_DATA61 0x1574
-#define BRUSH_DATA62 0x1578
-#define BRUSH_DATA63 0x157c
#define DST_WIDTH_X 0x1588
#define DST_HEIGHT_WIDTH_8 0x158c
#define SRC_X_Y 0x1590
@@ -368,22 +146,6 @@
#define CLR_CMP_MASK 0x15cc
#define DP_SRC_FRGD_CLR 0x15d8
#define DP_SRC_BKGD_CLR 0x15dc
-#define GUI_SCRATCH_REG0 0x15e0
-#define GUI_SCRATCH_REG1 0x15e4
-#define GUI_SCRATCH_REG2 0x15e8
-#define GUI_SCRATCH_REG3 0x15ec
-#define GUI_SCRATCH_REG4 0x15f0
-#define GUI_SCRATCH_REG5 0x15f4
-#define LEAD_BRES_ERR 0x1600
-#define LEAD_BRES_INC 0x1604
-#define LEAD_BRES_DEC 0x1608
-#define TRAIL_BRES_ERR 0x160c
-#define TRAIL_BRES_INC 0x1610
-#define TRAIL_BRES_DEC 0x1614
-#define TRAIL_X 0x1618
-#define LEAD_BRES_LNTH 0x161c
-#define TRAIL_X_SUB 0x1620
-#define LEAD_BRES_LNTH_SUB 0x1624
#define DST_BRES_ERR 0x1628
#define DST_BRES_INC 0x162c
#define DST_BRES_DEC 0x1630
@@ -395,19 +157,6 @@
#define SC_BOTTOM 0x164c
#define SRC_SC_RIGHT 0x1654
#define SRC_SC_BOTTOM 0x165c
-#define AUX_SC_CNTL 0x1660
-#define AUX1_SC_LEFT 0x1664
-#define AUX1_SC_RIGHT 0x1668
-#define AUX1_SC_TOP 0x166c
-#define AUX1_SC_BOTTOM 0x1670
-#define AUX2_SC_LEFT 0x1674
-#define AUX2_SC_RIGHT 0x1678
-#define AUX2_SC_TOP 0x167c
-#define AUX2_SC_BOTTOM 0x1680
-#define AUX3_SC_LEFT 0x1684
-#define AUX3_SC_RIGHT 0x1688
-#define AUX3_SC_TOP 0x168c
-#define AUX3_SC_BOTTOM 0x1690
#define GUI_DEBUG0 0x16a0
#define GUI_DEBUG1 0x16a4
#define GUI_TIMEOUT 0x16b0
@@ -437,20 +186,6 @@
#define DP_T12_CNTL 0x178c
#define DST_BRES_T1_LNTH 0x1790
#define DST_BRES_T2_LNTH 0x1794
-#define HOST_DATA0 0x17c0
-#define HOST_DATA1 0x17c4
-#define HOST_DATA2 0x17c8
-#define HOST_DATA3 0x17cc
-#define HOST_DATA4 0x17d0
-#define HOST_DATA5 0x17d4
-#define HOST_DATA6 0x17d8
-#define HOST_DATA7 0x17dc
-#define HOST_DATA_LAST 0x17e0
-#define SECONDARY_SCALE_PITCH 0x1980
-#define SECONDARY_SCALE_X_INC 0x1984
-#define SECONDARY_SCALE_Y_INC 0x1988
-#define SECONDARY_SCALE_HACC 0x198c
-#define SECONDARY_SCALE_VACC 0x1990
#define SCALE_SRC_HEIGHT_WIDTH 0x1994
#define SCALE_OFFSET_0 0x1998
#define SCALE_PITCH 0x199c
@@ -528,6 +263,7 @@
/* DAC_CNTL bit constants */
#define DAC_8BIT_EN 0x00000100
+#define DAC_MASK 0xFF000000
/* GEN_RESET_CNTL bit constants */
#define SOFT_RESET_GUI 0x00000001
@@ -545,6 +281,15 @@
#define BUS_MASTER_DIS 0x00000040
#define PM4_BUFFER_CNTL_NONPM4 0x00000000
+/* DP_DATATYPE bit constants */
+#define DST_8BPP 0x00000002
+#define DST_15BPP 0x00000003
+#define DST_16BPP 0x00000004
+#define DST_24BPP 0x00000005
+#define DST_32BPP 0x00000006
+
+#define BRUSH_SOLIDCOLOR 0x00000d00
+
/* DP_GUI_MASTER_CNTL bit constants */
#define GMC_SRC_PITCH_OFFSET_DEFAULT 0x00000000
#define GMC_DST_PITCH_OFFSET_DEFAULT 0x00000000
@@ -562,7 +307,7 @@
/* DP_GUI_MASTER_CNTL ROP3 named constants */
#define ROP3_PATCOPY 0x00f00000
-#define ROP3_SRCCOPY 0x00cc0000 // S
+#define ROP3_SRCCOPY 0x00cc0000
#define SRC_DSTCOLOR 0x00030000
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index cf83c755e..07d2789ce 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -4805,98 +4805,6 @@ aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
}
#endif /* CONFIG_PMAC_PBOOK */
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- struct fb_info_aty *info;
- unsigned int pm;
-
- for (info = first_display; info != NULL; info = info->next) {
- struct fb_fix_screeninfo fix;
- int nb;
-
- atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
- nb = fb_display[fg_console].var.yres * fix.line_length;
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- /* Stop accel engine (stop bus mastering) */
- if (info->current_par.accel_flags & FB_ACCELF_TEXT)
- reset_engine(info);
-#if 1
- /* Backup fb content */
- info->save_framebuffer = vmalloc(nb);
- if (info->save_framebuffer)
- memcpy(info->save_framebuffer,
- (void *)info->frame_buffer, nb);
-#endif
- /* Blank display and LCD */
- atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
-
- /* Set chip to "suspend" mode. Note: There's an HW bug in the
- chip which prevents proper resync on wakeup with automatic
- power management, we handle suspend manually using the
- following (weird) sequence described by ATI. Note2:
- We could enable this for all Rage LT Pro chip ids */
- if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~(PWR_BLON | AUTO_PWR_UP);
- pm |= SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
- mdelay(500);
- }
- break;
- case PBOOK_WAKE:
- /* Wakeup chip */
- if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= (PWR_BLON | AUTO_PWR_UP);
- pm &= ~SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- } while ((pm & PWR_MGT_STATUS_MASK) != 0);
- mdelay(500);
- }
-#if 1
- /* Restore fb content */
- if (info->save_framebuffer) {
- memcpy((void *)info->frame_buffer,
- info->save_framebuffer, nb);
- vfree(info->save_framebuffer);
- info->save_framebuffer = 0;
- }
-#endif
- /* Restore display */
- atyfb_set_par(&info->current_par, info);
- atyfbcon_blank(0, (struct fb_info *)info);
- break;
- }
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
#ifdef MODULE
int __init init_module(void)
{
diff --git a/drivers/video/dummycon.c b/drivers/video/dummycon.c
index 05b2b73ea..9b54b6a76 100644
--- a/drivers/video/dummycon.c
+++ b/drivers/video/dummycon.c
@@ -25,7 +25,7 @@
#define DUMMY_ROWS 25
#endif
-static const char *__init dummycon_startup(void)
+static const char *dummycon_startup(void)
{
return "dummy device";
}