summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-07-05 23:09:37 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-07-05 23:09:37 +0000
commitaba344fdfed81b2c03d6114c54cfd73a486aa10b (patch)
treed032d8430bf1234c3ecc6f6330d6de6e887e5963 /drivers
parent40c138bfc6d37dbff5339f84575db1e3cec6e34e (diff)
Merge with Linux 2.3.9.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ap1000/ringbuf.c7
-rw-r--r--drivers/block/Config.in7
-rw-r--r--drivers/block/genhd.c31
-rw-r--r--drivers/block/icside.c1
-rw-r--r--drivers/block/ide-disk.c7
-rw-r--r--drivers/block/ide-floppy.c7
-rw-r--r--drivers/block/ide-pci.c4
-rw-r--r--drivers/block/ide-pmac.c4
-rw-r--r--drivers/block/ide-probe.c4
-rw-r--r--drivers/block/ide-proc.c98
-rw-r--r--drivers/block/ide-tape.c56
-rw-r--r--drivers/block/ide.c37
-rw-r--r--drivers/block/ll_rw_blk.c29
-rw-r--r--drivers/block/pdc4030.c87
-rw-r--r--drivers/block/raid1.c2
-rw-r--r--drivers/block/raid5.c35
-rw-r--r--drivers/block/rd.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape-proc.c5
-rw-r--r--drivers/char/pc_keyb.c2
-rw-r--r--drivers/char/serial.c9
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/char/tpqic02.c2
-rw-r--r--drivers/char/tty_io.c10
-rw-r--r--drivers/i2o/i2o_config.c1
-rw-r--r--drivers/i2o/i2o_core.c1
-rw-r--r--drivers/i2o/i2o_lan.c1
-rw-r--r--drivers/i2o/i2o_pci.c1
-rw-r--r--drivers/i2o/i2o_proc.c1
-rw-r--r--drivers/net/cycx_drv.c1
-rw-r--r--drivers/net/depca.c6
-rw-r--r--drivers/net/irda/irtty.c1
-rw-r--r--drivers/net/yellowfin.c3
-rw-r--r--drivers/pci/proc.c7
-rw-r--r--drivers/sbus/char/aurora.c1
-rw-r--r--drivers/scsi/aic7xxx_proc.c2
-rw-r--r--drivers/scsi/sd.c2
-rw-r--r--drivers/scsi/st.c2
-rw-r--r--drivers/sgi/char/sgiserial.c1
-rw-r--r--drivers/sgi/char/usema.c2
-rw-r--r--drivers/sound/cmpci.c1
-rw-r--r--drivers/sound/sb_ess.c1
-rw-r--r--drivers/usb/README.ohci39
-rw-r--r--drivers/usb/acm.c1
-rw-r--r--drivers/usb/audio.c1
-rw-r--r--drivers/usb/cpia.c1
-rw-r--r--drivers/usb/hub.c1
-rw-r--r--drivers/usb/mouse.c1
-rw-r--r--drivers/usb/ohci-debug.c24
-rw-r--r--drivers/usb/ohci.c575
-rw-r--r--drivers/usb/ohci.h24
-rw-r--r--drivers/usb/printer.c19
-rw-r--r--drivers/usb/uhci.c15
-rw-r--r--drivers/usb/usb.c6
-rw-r--r--drivers/usb/usb.h10
-rw-r--r--drivers/usb/usb_scsi.c1
-rw-r--r--drivers/usb/usb_scsi.h2
-rw-r--r--drivers/video/sbusfb.c24
-rw-r--r--drivers/zorro/proc.c7
58 files changed, 906 insertions, 328 deletions
diff --git a/drivers/ap1000/ringbuf.c b/drivers/ap1000/ringbuf.c
index ebce30e83..69682437e 100644
--- a/drivers/ap1000/ringbuf.c
+++ b/drivers/ap1000/ringbuf.c
@@ -318,9 +318,12 @@ struct inode_operations proc_ringbuf_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index a9b9a000f..0e73f0c65 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -75,7 +75,7 @@ else
if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
- bool ' Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
+ bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
fi
fi
fi
@@ -93,6 +93,11 @@ else
"$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
"$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
define_bool CONFIG_BLK_DEV_IDEDMA y
+ if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
+ "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
+ "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
+ define_bool CONFIG_IDEDMA_AUTO y
+ fi
fi
bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index f52489d76..4197ad92a 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -221,11 +221,6 @@ static void extended_partition(struct gendisk *hd, kdev_t dev)
return;
if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
return;
- /*
- * This block is from a device that we're about to stomp on.
- * So make sure nobody thinks this block is usable.
- */
- bh->b_state = 0;
if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
goto done;
@@ -285,10 +280,12 @@ static void extended_partition(struct gendisk *hd, kdev_t dev)
hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
this_sector = first_sector + START_SECT(p) * sector_size;
dev = MKDEV(hd->major, current_minor);
- brelse(bh);
+
+ /* Use bforget(), as we have changed the disk geometry */
+ bforget(bh);
}
done:
- brelse(bh);
+ bforget(bh);
}
#ifdef CONFIG_SOLARIS_X86_PARTITION
@@ -386,7 +383,6 @@ static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev,
if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
return;
- bh->b_state = 0;
l = (struct bsd_disklabel *) (bh->b_data+512);
if (l->d_magic != BSD_DISKMAGIC) {
brelse(bh);
@@ -402,7 +398,9 @@ static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev,
if (p->p_fstype != BSD_FS_UNUSED)
check_and_add_bsd_partition(hd, p, dev);
}
- brelse(bh);
+
+ /* Use bforget(), as we have changed the disk setup */
+ bforget(bh);
}
#endif
@@ -421,7 +419,6 @@ static void unixware_partition(struct gendisk *hd, kdev_t dev)
if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))
return;
- bh->b_state = 0;
l = (struct unixware_disklabel *) (bh->b_data+512);
if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
@@ -441,7 +438,8 @@ static void unixware_partition(struct gendisk *hd, kdev_t dev)
}
p++;
}
- brelse(bh);
+ /* Use bforget, as we have changed the disk setup */
+ bforget(bh);
printk(" >");
}
#endif
@@ -469,15 +467,12 @@ read_mbr:
return -1;
}
data = bh->b_data;
- /* In some cases we modify the geometry */
- /* of the drive (below), so ensure that */
- /* nobody else tries to re-use this data. */
- bh->b_state = 0;
#ifdef CONFIG_BLK_DEV_IDE
check_table:
#endif
+ /* Use bforget(), because we have potentially changed the disk geometry */
if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
- brelse(bh);
+ bforget(bh);
return 0;
}
p = (struct partition *) (0x1be + data);
@@ -515,7 +510,7 @@ check_table:
* adjustments to fool fdisk/LILO and partition check.
*/
if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
- brelse(bh);
+ bforget(bh);
goto read_mbr; /* start over with new MBR */
}
} else if (sig <= 0x1ae &&
@@ -627,7 +622,7 @@ check_table:
}
}
printk("\n");
- brelse(bh);
+ bforget(bh);
return 1;
}
diff --git a/drivers/block/icside.c b/drivers/block/icside.c
index 299bce7a6..0d29761ee 100644
--- a/drivers/block/icside.c
+++ b/drivers/block/icside.c
@@ -10,6 +10,7 @@
* 22-May-1999 RMK Added support for V6 DMA
*/
+#include <linux/config.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/ioport.h>
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 5d8548d96..fee5297f1 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -856,11 +856,16 @@ void cleanup_module (void)
ide_drive_t *drive;
int failed = 0;
- while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL)
+ while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
if (idedisk_cleanup (drive)) {
printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
failed++;
}
+ /* We must remove proc entries defined in this module.
+ Otherwise we oops while accessing these entries */
+ if (drive->proc)
+ ide_remove_proc_entries(drive->proc, idedisk_proc);
+ }
ide_unregister_module(&idedisk_module);
}
#endif /* MODULE */
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index 78aa7fe29..49ccb66ce 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1630,11 +1630,16 @@ void cleanup_module (void)
ide_drive_t *drive;
int failed = 0;
- while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL)
+ while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
if (idefloppy_cleanup (drive)) {
printk ("%s: cleanup_module() called while still busy\n", drive->name);
failed++;
}
+ /* We must remove proc entries defined in this module.
+ Otherwise we oops while accessing these entries */
+ if (drive->proc)
+ ide_remove_proc_entries(drive->proc, idefloppy_proc);
+ }
ide_unregister_module(&idefloppy_module);
}
#endif /* MODULE */
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
index d1d906ecb..8b4c5fe2c 100644
--- a/drivers/block/ide-pci.c
+++ b/drivers/block/ide-pci.c
@@ -29,6 +29,7 @@
#define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1})
#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1})
#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561})
#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
#define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
@@ -190,6 +191,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_VP_IDE, "VP_IDE", NULL, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 },
{DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 },
{DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 },
@@ -548,6 +550,8 @@ __initfunc(void ide_scan_pcibus (void))
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, 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",
diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c
index 4e38b4f64..52c658311 100644
--- a/drivers/block/ide-pmac.c
+++ b/drivers/block/ide-pmac.c
@@ -218,9 +218,9 @@ pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
}
hwif->dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_PMAC_IDEDMA_AUTO
+#ifdef CONFIG_IDEDMA_PMAC_AUTO
hwif->autodma = 1;
-#endif
+#endif /* CONFIG_IDEDMA_PMAC_AUTO */
}
/*
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 9fc293b18..3b5d24744 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -845,7 +845,9 @@ int init_module (void)
for (index = 0; index < MAX_HWIFS; ++index)
ide_unregister(index);
- return ideprobe_init();
+ ideprobe_init();
+ create_proc_ide_interfaces();
+ return 0;
}
void cleanup_module (void)
diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c
index f985980b1..623ac9268 100644
--- a/drivers/block/ide-proc.c
+++ b/drivers/block/ide-proc.c
@@ -112,6 +112,8 @@ static int xx_xx_parse_error (const char *data, unsigned long len, const char *m
return -EINVAL;
}
+static struct proc_dir_entry * proc_ide_root = NULL;
+
static int proc_ide_write_config
(struct file *file, const char *buffer, unsigned long count, void *data)
{
@@ -384,7 +386,7 @@ static int proc_ide_read_identify
ide_drive_t *drive = (ide_drive_t *)data;
int len = 0, i = 0;
- if (!proc_ide_get_identify(drive, page)) {
+ if (drive && !proc_ide_get_identify(drive, page)) {
unsigned short *val = ((unsigned short *)page) + 2;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
@@ -394,6 +396,8 @@ static int proc_ide_read_identify
} while (i < (SECTOR_WORDS * 2));
len = out - page;
}
+ else
+ len = sprintf(page, "\n");
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
@@ -525,8 +529,8 @@ int proc_ide_read_geometry
char *out = page;
int len;
- out += sprintf(out,"physical %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
- out += sprintf(out,"logical %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ out += sprintf(out,"physical %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
+ out += sprintf(out,"logical %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
len = out - page;
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
@@ -634,21 +638,30 @@ static int proc_ide_readlink(struct proc_dir_entry *de, char *page)
return sprintf(page, "ide%d/%s", n, de->name);
}
-static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root)
+static void create_proc_ide_drives(ide_hwif_t *hwif)
{
int d;
struct proc_dir_entry *ent;
+ struct proc_dir_entry *parent = hwif->proc;
for (d = 0; d < MAX_DRIVES; d++) {
ide_drive_t *drive = &hwif->drives[d];
+ ide_driver_t *driver = drive->driver;
if (!drive->present)
continue;
- drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
if (drive->proc)
- ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+ continue;
- ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root);
+ drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+ if (drive->proc) {
+ ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+ if (driver) {
+ ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ ide_add_proc_entries(drive->proc, driver->proc, drive);
+ }
+ }
+ ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, proc_ide_root);
if (!ent) return;
ent->data = drive;
ent->readlink_proc = proc_ide_readlink;
@@ -656,6 +669,25 @@ static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *par
}
}
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+ int d;
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+ ide_driver_t *driver = drive->driver;
+
+ if (!drive->proc)
+ continue;
+ if (driver)
+ ide_remove_proc_entries(drive->proc, driver->proc);
+ ide_remove_proc_entries(drive->proc, generic_drive_entries);
+ remove_proc_entry(drive->name, proc_ide_root);
+ remove_proc_entry(drive->name, hwif->proc);
+ drive->proc = NULL;
+ }
+}
+
static ide_proc_entry_t hwif_entries[] = {
{ "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
{ "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config },
@@ -664,42 +696,67 @@ static ide_proc_entry_t hwif_entries[] = {
{ NULL, 0, NULL, NULL }
};
-static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+void create_proc_ide_interfaces(void)
{
int h;
- struct proc_dir_entry *hwif_ent;
for (h = 0; h < MAX_HWIFS; h++) {
ide_hwif_t *hwif = &ide_hwifs[h];
+ int exist = (hwif->proc != NULL);
if (!hwif->present)
continue;
- hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
- if (!hwif_ent) return;
- ide_add_proc_entries(hwif_ent, hwif_entries, hwif);
- create_proc_ide_drives(hwif, hwif_ent, parent);
+ if (!exist)
+ hwif->proc = create_proc_entry(hwif->name, S_IFDIR, proc_ide_root);
+ if (!hwif->proc)
+ return;
+ if (!exist)
+ ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
+ create_proc_ide_drives(hwif);
+ }
+}
+
+static void destroy_proc_ide_interfaces(void)
+{
+ int h;
+
+ for (h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+ int exist = (hwif->proc != NULL);
+
+#if 0
+ if (!hwif->present)
+ continue;
+#endif
+ if (exist) {
+ destroy_proc_ide_drives(hwif);
+ ide_remove_proc_entries(hwif->proc, hwif_entries);
+ remove_proc_entry(hwif->name, proc_ide_root);
+ hwif->proc = NULL;
+ } else
+ continue;
}
}
void proc_ide_create(void)
{
- struct proc_dir_entry *root, *ent;
- root = create_proc_entry("ide", S_IFDIR, 0);
- if (!root) return;
- create_proc_ide_interfaces(root);
+ struct proc_dir_entry *ent;
+ proc_ide_root = create_proc_entry("ide", S_IFDIR, 0);
+ if (!proc_ide_root) return;
+ create_proc_ide_interfaces();
- ent = create_proc_entry("drivers", 0, root);
+ ent = create_proc_entry("drivers", 0, proc_ide_root);
if (!ent) return;
ent->read_proc = proc_ide_read_drivers;
#ifdef CONFIG_BLK_DEV_VIA82C586
if (via_display_info) {
- ent = create_proc_entry("via", 0, root);
+ ent = create_proc_entry("via", 0, proc_ide_root);
ent->get_info = via_display_info;
}
#endif /* CONFIG_BLK_DEV_VIA82C586 */
#ifdef CONFIG_BLK_DEV_ALI15X3
if (ali_display_info) {
- ent = create_proc_entry("ali", 0, root);
+ ent = create_proc_entry("ali", 0, proc_ide_root);
ent->get_info = ali_display_info;
}
#endif /* CONFIG_BLK_DEV_ALI15X3 */
@@ -720,5 +777,6 @@ void proc_ide_destroy(void)
remove_proc_entry("ide/ali",0);
#endif /* CONFIG_BLK_DEV_ALI15X3 */
remove_proc_entry("ide/drivers", 0);
+ destroy_proc_ide_interfaces();
remove_proc_entry("ide", 0);
}
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 1382eb3ab..74c89cff0 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1073,13 +1073,13 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- count = IDE_MIN (bh->b_size - bh->b_count, bcount);
- atapi_input_bytes (drive, bh->b_data + bh->b_count, count);
- bcount -= count; bh->b_count += count;
- if (bh->b_count == bh->b_size) {
+ count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
+ atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+ bcount -= count; atomic_add(count, &bh->b_count);
+ if (atomic_read(&bh->b_count) == bh->b_size) {
bh = bh->b_reqnext;
if (bh)
- bh->b_count = 0;
+ atomic_set(&bh->b_count, 0);
}
}
pc->bh = bh;
@@ -1104,7 +1104,7 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
pc->bh = bh = bh->b_reqnext;
if (bh) {
pc->b_data = bh->b_data;
- pc->b_count = bh->b_count;
+ pc->b_count = atomic_read(&bh->b_count);
}
}
}
@@ -1126,8 +1126,8 @@ static void idetape_update_buffers (idetape_pc_t *pc)
}
#endif /* IDETAPE_DEBUG_BUGS */
count = IDE_MIN (bh->b_size, bcount);
- bh->b_count = count;
- if (bh->b_count == bh->b_size)
+ atomic_set(&bh->b_count, count);
+ if (atomic_read(&bh->b_count) == bh->b_size)
bh = bh->b_reqnext;
bcount -= count;
}
@@ -1351,13 +1351,13 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- count = IDE_MIN (bh->b_size - bh->b_count, n);
- copy_from_user (bh->b_data + bh->b_count, buf, count);
- n -= count; bh->b_count += count; buf += count;
- if (bh->b_count == bh->b_size) {
+ count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
+ copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+ n -= count; atomic_add(count, &bh->b_count); buf += count;
+ if (atomic_read(&bh->b_count) == bh->b_size) {
bh = bh->b_reqnext;
if (bh)
- bh->b_count = 0;
+ atomic_set(&bh->b_count, 0);
}
}
tape->bh = bh;
@@ -1382,7 +1382,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape
tape->bh = bh = bh->b_reqnext;
if (bh) {
tape->b_data = bh->b_data;
- tape->b_count = bh->b_count;
+ tape->b_count = atomic_read(&bh->b_count);
}
}
}
@@ -1394,10 +1394,10 @@ static void idetape_init_merge_stage (idetape_tape_t *tape)
tape->bh = bh;
if (tape->chrdev_direction == idetape_direction_write)
- bh->b_count = 0;
+ atomic_set(&bh->b_count, 0);
else {
tape->b_data = bh->b_data;
- tape->b_count = bh->b_count;
+ tape->b_count = atomic_read(&bh->b_count);
}
}
@@ -2131,7 +2131,7 @@ static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, uns
pc->c[1] = 1;
pc->callback = &idetape_rw_callback;
pc->bh = bh;
- bh->b_count = 0;
+ atomic_set(&bh->b_count, 0);
pc->buffer = NULL;
pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
if (pc->request_transfer == tape->stage_size)
@@ -2158,7 +2158,7 @@ static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, un
set_bit (PC_WRITING, &pc->flags);
pc->bh = bh;
pc->b_data = bh->b_data;
- pc->b_count = bh->b_count;
+ pc->b_count = atomic_read(&bh->b_count);
pc->buffer = NULL;
pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
if (pc->request_transfer == tape->stage_size)
@@ -2587,9 +2587,9 @@ static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
bcount -= count;
blocks = count / tape->tape_block_size;
while (count) {
- bh->b_count = IDE_MIN (count, bh->b_size);
- memset (bh->b_data, 0, bh->b_count);
- count -= bh->b_count;
+ atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
+ memset (bh->b_data, 0, atomic_read(&bh->b_count));
+ count -= atomic_read(&bh->b_count);
bh = bh->b_reqnext;
}
idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
@@ -2616,8 +2616,8 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
if (tape->merge_stage_size % tape->tape_block_size) {
blocks++;
i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
- memset (tape->bh->b_data + tape->bh->b_count, 0, i);
- tape->bh->b_count += i;
+ memset (tape->bh->b_data + atomic_read(&tape->bh->b_count), 0, i);
+ atomic_add(i, &tape->bh->b_count);
}
(void) idetape_add_chrdev_write_request (drive, blocks);
tape->merge_stage_size = 0;
@@ -3814,8 +3814,14 @@ void cleanup_module (void)
for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
drive = idetape_chrdevs[minor].drive;
- if (drive != NULL && idetape_cleanup (drive))
- printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+ if (drive) {
+ if (idetape_cleanup (drive))
+ printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+ /* We must remove proc entries defined in this module.
+ Otherwise we oops while accessing these entries */
+ if (drive->proc)
+ ide_remove_proc_entries(drive->proc, idetape_proc);
+ }
}
ide_unregister_module(&idetape_module);
}
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 2d6eebd24..17b10593d 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1748,6 +1748,13 @@ abort:
return 1;
}
+#ifdef CONFIG_PROC_FS
+ide_proc_entry_t generic_subdriver_entries[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+ { NULL, 0, NULL, NULL }
+};
+#endif
+
void ide_unregister (unsigned int index)
{
struct gendisk *gd, **gdp;
@@ -1757,6 +1764,7 @@ void ide_unregister (unsigned int index)
int irq_count = 0, unit, i;
unsigned long flags;
unsigned int p, minor;
+ ide_hwif_t old_hwif;
if (index >= MAX_HWIFS)
return;
@@ -1793,6 +1801,9 @@ void ide_unregister (unsigned int index)
invalidate_buffers (devp);
}
}
+#ifdef CONFIG_PROC_FS
+ destroy_proc_ide_drives(hwif);
+#endif
}
cli();
hwgroup = hwif->hwgroup;
@@ -1875,7 +1886,21 @@ void ide_unregister (unsigned int index)
kfree(gd->part);
kfree(gd);
}
+ old_hwif = *hwif;
init_hwif_data (index); /* restore hwif data to pristine status */
+ hwif->hwgroup = old_hwif.hwgroup;
+ hwif->tuneproc = old_hwif.tuneproc;
+ hwif->dmaproc = old_hwif.dmaproc;
+ hwif->dma_base = old_hwif.dma_base;
+ hwif->dma_extra = old_hwif.dma_extra;
+ hwif->config_data = old_hwif.config_data;
+ hwif->select_data = old_hwif.select_data;
+ hwif->irq = old_hwif.irq;
+ hwif->major = old_hwif.major;
+ hwif->proc = old_hwif.proc;
+ hwif->chipset = old_hwif.chipset;
+ hwif->pci_dev = old_hwif.pci_dev;
+ hwif->pci_devid = old_hwif.pci_devid;
abort:
restore_flags(flags); /* all CPUs */
}
@@ -1950,6 +1975,9 @@ found:
if (!initializing) {
ide_init_module(IDE_PROBE_MODULE);
+#ifdef CONFIG_PROC_FS
+ create_proc_ide_interfaces();
+#endif
ide_init_module(IDE_DRIVER_MODULE);
}
@@ -1966,7 +1994,6 @@ found:
int ide_register (int arg1, int arg2, int irq)
{
hw_regs_t hw;
-
ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
hw.irq = irq;
return ide_register_hw(&hw, NULL);
@@ -3239,13 +3266,6 @@ search:
return NULL;
}
-#ifdef CONFIG_PROC_FS
-static ide_proc_entry_t generic_subdriver_entries[] = {
- { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
- { NULL, 0, NULL, NULL }
-};
-#endif
-
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
{
unsigned long flags;
@@ -3401,6 +3421,7 @@ EXPORT_SYMBOL(ide_stall_queue);
EXPORT_SYMBOL(ide_add_proc_entries);
EXPORT_SYMBOL(ide_remove_proc_entries);
EXPORT_SYMBOL(proc_ide_read_geometry);
+EXPORT_SYMBOL(create_proc_ide_interfaces);
#endif
EXPORT_SYMBOL(ide_add_setting);
EXPORT_SYMBOL(ide_remove_setting);
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 185591b3a..02df81f77 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -17,6 +17,7 @@
#include <linux/locks.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -322,8 +323,6 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
spin_lock_irqsave(&io_request_lock,flags);
current_request = get_queue(req->rq_dev);
- if (req->bh)
- mark_buffer_clean(req->bh);
if (!(tmp = *current_request)) {
*current_request = req;
if (dev->current_request != &dev->plug)
@@ -385,12 +384,17 @@ void make_request(int major,int rw, struct buffer_head * bh)
count = bh->b_size >> 9;
sector = bh->b_rsector;
- /* Uhhuh.. Nasty dead-lock possible here.. */
- if (buffer_locked(bh))
- return;
- /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
+ /* We'd better have a real physical mapping! */
+ if (!buffer_mapped(bh))
+ BUG();
+
+ /* It had better not be a new buffer by the time we see it */
+ if (buffer_new(bh))
+ BUG();
- lock_buffer(bh);
+ /* Only one thread can actually submit the I/O. */
+ if (test_and_set_bit(BH_Lock, &bh->b_state))
+ return;
if (blk_size[major]) {
unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
@@ -425,9 +429,11 @@ void make_request(int major,int rw, struct buffer_head * bh)
rw_ahead = 1;
rw = WRITE; /* drop into WRITE */
case WRITE:
- if (!buffer_dirty(bh)) /* Hmmph! Nothing to write */
- goto end_io;
- /* We don't allow the write-requests to fill up the
+ if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
+ goto end_io; /* Hmmph! Nothing to write */
+ refile_buffer(bh);
+ /*
+ * We don't allow the write-requests to fill up the
* queue completely: we want some room for reads,
* as they take precedence. The last third of the
* requests are only for reads.
@@ -528,7 +534,6 @@ void make_request(int major,int rw, struct buffer_head * bh)
} else
continue;
- mark_buffer_clean(bh);
spin_unlock_irqrestore(&io_request_lock,flags);
return;
@@ -605,7 +610,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
for (i = 0; i < nr; i++) {
if (bh[i]->b_size != correct_size) {
printk(KERN_NOTICE "ll_rw_block: device %s: "
- "only %d-char blocks implemented (%lu)\n",
+ "only %d-char blocks implemented (%u)\n",
kdevname(bh[0]->b_dev),
correct_size, bh[i]->b_size);
goto sorry;
diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c
index 92c7082c6..84fbb4856 100644
--- a/drivers/block/pdc4030.c
+++ b/drivers/block/pdc4030.c
@@ -1,5 +1,5 @@
/* -*- linux-c -*-
- * linux/drivers/block/pdc4030.c Version 0.11 May 17, 1999
+ * linux/drivers/block/pdc4030.c Version 0.90 May 27, 1999
*
* Copyright (C) 1995-1999 Linus Torvalds & authors (see below)
*/
@@ -35,6 +35,8 @@
* Version 0.10 Updated for 2.1 series of kernels
* Version 0.11 Updated for 2.3 series of kernels
* Autodetection code added.
+ *
+ * Version 0.90 Transition to BETA code. No lost/unexpected interrupts
*/
/*
@@ -68,8 +70,8 @@
* because I still don't understand what the card is doing with interrupts.
*/
-#undef DEBUG_READ
-#undef DEBUG_WRITE
+#define DEBUG_READ
+#define DEBUG_WRITE
#include <linux/types.h>
#include <linux/kernel.h>
@@ -100,7 +102,8 @@ static void promise_selectproc (ide_drive_t *drive)
/*
* pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification.
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
*/
int pdc4030_cmd(ide_drive_t *drive, byte cmd)
{
@@ -358,11 +361,11 @@ read_next:
if (stat & DRQ_STAT)
goto read_again;
if (stat & BUSY_STAT) {
+ ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
#ifdef DEBUG_READ
printk(KERN_DEBUG "%s: promise_read: waiting for"
"interrupt\n", drive->name);
#endif
- ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
return;
}
printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
@@ -372,37 +375,39 @@ read_next:
}
/*
- * promise_finish_write()
- * called at the end of all writes
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
*/
-static void promise_finish_write(ide_drive_t *drive)
+static void promise_complete_pollfunc(ide_drive_t *drive)
{
- struct request *rq = HWGROUP(drive)->rq;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ struct request *rq = hwgroup->rq;
int i;
- for (i = rq->nr_sectors; i > 0; ) {
- i -= rq->current_nr_sectors;
- ide_end_request(1, HWGROUP(drive));
- }
-}
-
-/*
- * promise_write_intr()
- * This interrupt is called after the particularly odd polling for completion
- * of the write request, once all the data has been sent.
- */
-static void promise_write_intr(ide_drive_t *drive)
-{
- byte stat;
-
- if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
- ide_error(drive, "promise_write_intr", stat);
+ if (GET_STAT() & BUSY_STAT) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ ide_set_handler(drive, &promise_complete_pollfunc, 1);
+ return; /* continue polling... */
+ }
+ hwgroup->poll_timeout = 0;
+ printk(KERN_ERR "%s: completion timeout - still busy!\n",
+ drive->name);
+ ide_error(drive, "busy timeout", GET_STAT());
+ return;
}
+ hwgroup->poll_timeout = 0;
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
#endif
- promise_finish_write(drive);
+ for (i = rq->nr_sectors; i > 0; ) {
+ i -= rq->current_nr_sectors;
+ ide_end_request(1, hwgroup);
+ }
}
/*
@@ -410,22 +415,29 @@ static void promise_write_intr(ide_drive_t *drive)
*/
static void promise_write_pollfunc (ide_drive_t *drive)
{
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
- if (time_before(jiffies, HWGROUP(drive)->poll_timeout)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
ide_set_handler (drive, &promise_write_pollfunc, 1);
return; /* continue polling... */
}
+ hwgroup->poll_timeout = 0;
printk(KERN_ERR "%s: write timed-out!\n",drive->name);
ide_error (drive, "write timeout", GET_STAT());
return;
}
+ /*
+ * Now write out last 4 sectors and poll for not BUSY
+ */
ide_multwrite(drive, 4);
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ ide_set_handler(drive, &promise_complete_pollfunc, 1);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
drive->name, GET_STAT());
#endif
- ide_set_handler(drive, &promise_write_intr, WAIT_CMD);
return;
}
@@ -433,8 +445,8 @@ static void promise_write_pollfunc (ide_drive_t *drive)
* promise_write() transfers a block of one or more sectors of data to a
* drive as part of a disk write operation. All but 4 sectors are transfered
* in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transfered. The interrupt generated on
- * writes occurs after this process, which is why I got it wrong for so long!
+ * before the final 4 sectors are transfered. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
*/
static void promise_write (ide_drive_t *drive)
{
@@ -446,18 +458,27 @@ static void promise_write (ide_drive_t *drive)
"buffer=0x%08x\n", drive->name, rq->sector,
rq->sector + rq->nr_sectors - 1, (unsigned int)rq->buffer);
#endif
+
+ /*
+ * If there are more than 4 sectors to transfer, do n-4 then go into
+ * the polling strategy as defined above.
+ */
if (rq->nr_sectors > 4) {
ide_multwrite(drive, rq->nr_sectors - 4);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler (drive, &promise_write_pollfunc, 1);
- return;
} else {
+ /*
+ * There are 4 or fewer sectors to transfer, do them all in one go
+ * and wait for NOT BUSY.
+ */
ide_multwrite(drive, rq->nr_sectors);
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ ide_set_handler(drive, &promise_complete_pollfunc, 1);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
"status = %02x\n", drive->name, GET_STAT());
#endif
- promise_finish_write(drive);
}
}
diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c
index 890584dcd..7efb78400 100644
--- a/drivers/block/raid1.c
+++ b/drivers/block/raid1.c
@@ -310,7 +310,7 @@ raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh)
mirror_bh [i]->b_rdev = raid_conf->mirrors [i].dev;
mirror_bh [i]->b_rsector = bh->b_rsector;
mirror_bh [i]->b_state = (1<<BH_Req) | (1<<BH_Dirty);
- mirror_bh [i]->b_count = 1;
+ atomic_set(&mirror_bh [i]->b_count, 1);
mirror_bh [i]->b_size = bh->b_size;
mirror_bh [i]->b_data = bh->b_data;
mirror_bh [i]->b_list = BUF_LOCKED;
diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c
index 3c5701b3e..3e60f92ce 100644
--- a/drivers/block/raid5.c
+++ b/drivers/block/raid5.c
@@ -586,13 +586,15 @@ static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, i
b_data = ((volatile struct buffer_head *) bh)->b_data;
memset (bh, 0, sizeof (struct buffer_head));
- init_buffer(bh, dev, block, raid5_end_request, sh);
+ init_buffer(bh, raid5_end_request, sh);
+ bh->b_dev = dev;
+ bh->b_blocknr = block;
((volatile struct buffer_head *) bh)->b_data = b_data;
bh->b_rdev = raid_conf->disks[i].dev;
bh->b_rsector = sh->sector;
- bh->b_state = (1 << BH_Req);
+ bh->b_state = (1 << BH_Req) | (1 << BH_Mapped);
bh->b_size = sh->size;
bh->b_list = BUF_LOCKED;
}
@@ -1030,19 +1032,24 @@ static void handle_stripe(struct stripe_head *sh)
if (sh->bh_new[i])
continue;
block = (int) compute_blocknr(sh, i);
- bh = find_buffer(MKDEV(MD_MAJOR, minor), block, sh->size);
- if (bh && bh->b_count == 0 && buffer_dirty(bh) && !buffer_locked(bh)) {
- PRINTK(("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block));
- add_stripe_bh(sh, bh, i, WRITE);
- sh->new[i] = 0;
- nr++; nr_write++;
- if (sh->bh_old[i]) {
- nr_cache_overwrite++;
- nr_cache_other--;
- } else if (!operational[i]) {
- nr_failed_overwrite++;
- nr_failed_other--;
+ bh = get_hash_table(MKDEV(MD_MAJOR, minor), block, sh->size);
+ if (bh) {
+ if (atomic_read(&bh->b_count) == 1 &&
+ buffer_dirty(bh) &&
+ !buffer_locked(bh)) {
+ PRINTK(("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block));
+ add_stripe_bh(sh, bh, i, WRITE);
+ sh->new[i] = 0;
+ nr++; nr_write++;
+ if (sh->bh_old[i]) {
+ nr_cache_overwrite++;
+ nr_cache_other--;
+ } else if (!operational[i]) {
+ nr_failed_overwrite++;
+ nr_failed_other--;
+ }
}
+ atomic_dec(&bh->b_count);
}
}
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 81ce11c49..6c2768b27 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -173,7 +173,7 @@ repeat:
if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 0, len);
- else
+ else
set_bit(BH_Protected, &CURRENT->bh->b_state);
end_request(1);
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c
index ee21d92d4..ef91ff6c9 100644
--- a/drivers/char/ftape/lowlevel/ftape-proc.c
+++ b/drivers/char/ftape/lowlevel/ftape-proc.c
@@ -112,11 +112,14 @@ static struct inode_operations ftape_proc_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* revalidate */
};
/*
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index bf3d1f41d..8c4b85eec 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -782,7 +782,7 @@ static void aux_write_ack(int val)
spin_lock_irqsave(&kbd_controller_lock, flags);
kb_wait();
- kbd_write_cmd(KBD_CCMD_WRITE_MOUSE);
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
kb_wait();
kbd_write_output(val);
/* we expect an ACK in response. */
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 4a3d6e00e..ded6b227e 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -105,7 +105,8 @@
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+#define IRQ_T(state) \
+ ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
#define SERIAL_INLINE
@@ -1025,7 +1026,7 @@ static int startup(struct async_struct * info)
} else
handler = rs_interrupt_single;
- retval = request_irq(state->irq, handler, IRQ_T(info),
+ retval = request_irq(state->irq, handler, IRQ_T(state),
"serial", NULL);
if (retval) {
if (capable(CAP_SYS_ADMIN)) {
@@ -1190,7 +1191,7 @@ static void shutdown(struct async_struct * info)
if (IRQ_ports[state->irq]) {
free_irq(state->irq, NULL);
retval = request_irq(state->irq, rs_interrupt_single,
- IRQ_T(info), "serial", NULL);
+ IRQ_T(state), "serial", NULL);
if (retval)
printk("serial shutdown: request_irq: error %d"
@@ -2039,7 +2040,7 @@ static int set_multiport_struct(struct async_struct * info,
else
handler = rs_interrupt;
- retval = request_irq(state->irq, handler, IRQ_T(info),
+ retval = request_irq(state->irq, handler, IRQ_T(state),
"serial", NULL);
if (retval) {
printk("Couldn't reallocate serial interrupt "
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 5a4ad1c6f..574f1b1e9 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -155,7 +155,7 @@ static void all_files_read_only(void) /* Kill write permissions of all files
struct file *file;
for (file = inuse_filps; file; file = file->f_next)
- if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
+ if (file->f_dentry && atomic_read(&file->f_count) && S_ISREG(file->f_dentry->d_inode->i_mode))
file->f_mode &= ~2;
}
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 67b8f3a71..edcf6f2f3 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2216,7 +2216,7 @@ static int qic02_tape_open_no_use_count(struct inode * inode, struct file * filp
}
/* Only one at a time from here on... */
- if (filp->f_count>1) /* filp->f_count==1 for the first open() */
+ if (atomic_read(&filp->f_count)>1) /* filp->f_count==1 for the first open() */
{
return -EBUSY;
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index df5a8efc7..3951b5422 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -628,10 +628,12 @@ static ssize_t tty_read(struct file * file, char * buf, size_t count,
return -ERESTARTSYS;
}
#endif
+ lock_kernel();
if (tty->ldisc.read)
i = (tty->ldisc.read)(tty,file,buf,count);
else
i = -EIO;
+ unlock_kernel();
if (i > 0)
inode->i_atime = CURRENT_TIME;
return i;
@@ -658,7 +660,9 @@ static inline ssize_t do_tty_write(
unsigned long size = PAGE_SIZE*2;
if (size > count)
size = count;
+ lock_kernel();
ret = write(tty, file, buf, size);
+ unlock_kernel();
if (ret <= 0)
break;
written += ret;
@@ -2034,11 +2038,7 @@ long __init console_init(long kmem_start, long kmem_end)
memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
tty_std_termios.c_iflag = ICRNL | IXON;
tty_std_termios.c_oflag = OPOST | ONLCR;
-#if CONFIG_COBALT_SERIAL
- tty_std_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL;
-#else
tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
-#endif
tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
@@ -2131,10 +2131,8 @@ __initfunc(int tty_init(void))
if (tty_register_driver(&dev_console_driver))
panic("Couldn't register /dev/tty0 driver\n");
-#ifndef CONFIG_COBALT_MICRO_SERVER
kbd_init();
#endif
-#endif
#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
espserial_init();
#endif
diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c
index c3c644883..8fd93bff9 100644
--- a/drivers/i2o/i2o_config.c
+++ b/drivers/i2o/i2o_config.c
@@ -14,7 +14,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c
index 3a3f1fe94..7945c7961 100644
--- a/drivers/i2o/i2o_core.c
+++ b/drivers/i2o/i2o_core.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/i2o/i2o_lan.c b/drivers/i2o/i2o_lan.c
index 1ebbe0b49..f15b7476e 100644
--- a/drivers/i2o/i2o_lan.c
+++ b/drivers/i2o/i2o_lan.c
@@ -25,6 +25,7 @@
* - code/test for other LAN classes
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/netdevice.h>
diff --git a/drivers/i2o/i2o_pci.c b/drivers/i2o/i2o_pci.c
index 596d9f953..196d58c85 100644
--- a/drivers/i2o/i2o_pci.c
+++ b/drivers/i2o/i2o_pci.c
@@ -12,7 +12,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c
index ce38b3914..cdadc9cdc 100644
--- a/drivers/i2o/i2o_proc.c
+++ b/drivers/i2o/i2o_proc.c
@@ -38,7 +38,6 @@
#define FMT_U64_HEX "0x%08x%08x"
#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/i2o.h>
diff --git a/drivers/net/cycx_drv.c b/drivers/net/cycx_drv.c
index e75552e48..7f803c63d 100644
--- a/drivers/net/cycx_drv.c
+++ b/drivers/net/cycx_drv.c
@@ -39,7 +39,6 @@
* Aug 8, 1998 Arnaldo Initial version.
*/
-#include <linux/config.h>
#ifdef MODULE
#ifdef MODVERSIONS
#include <linux/modversions.h>
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index c3701e230..68250ade1 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -221,11 +221,13 @@
by <tymm@computer.org>
0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
0.5 14-Nov-98 Re-spin for 2.1.x kernels.
+ 0.51 27-Jun-99 Correct received packet length for CRC from
+ report by <worm@dkik.dk>
=========================================================================
*/
-static const char *version = "depca.c:v0.5 1998/11/14 davies@maniac.ultranet.com\n";
+static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -947,7 +949,7 @@ depca_rx(struct device *dev)
if (status & R_CRC) lp->stats.rx_crc_errors++;
if (status & R_BUFF) lp->stats.rx_fifo_errors++;
} else {
- short len, pkt_len = readw(&lp->rx_ring[entry].msg_length);
+ short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+2);
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index ad8d2dc0e..751d98ec7 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -24,7 +24,6 @@
*
********************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 410121e2e..8d5b232ec 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -76,6 +76,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <linux/pci.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
+#include <asm/unaligned.h>
#include <asm/io.h>
#include <linux/netdevice.h>
@@ -1054,7 +1055,7 @@ static int yellowfin_rx(struct device *dev)
u16 desc_status = desc->status;
int data_size = desc->request_cnt - desc->result_cnt;
u8 *buf_addr = bus_to_virt(desc->addr);
- s16 frame_status = *(s16*)&(buf_addr[data_size - 2]); /* ?Alpha safe on 885? */
+ s16 frame_status = get_unaligned((s16*)(buf_addr+data_size-2));
if (yellowfin_debug > 4)
printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index d1a78fe53..3a7ef777c 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -222,11 +222,14 @@ static struct inode_operations proc_bus_pci_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
int
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 607b0f230..fde6f7649 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -45,7 +45,6 @@
#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>
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index 3314514f4..a986c5e80 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -29,6 +29,8 @@
* $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
+#include <linux/config.h>
+
#define BLS (&aic7xxx_buffer[size])
#define HDRB \
" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+"
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index e89eeecb7..22ab35f63 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -945,7 +945,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
printk("maxsg = %x, counted = %d this_count = %d\n",
max_sg, counted, this_count);
while(bh){
- printk("[%p %lx] ", bh->b_data, bh->b_size);
+ printk("[%p %x] ", bh->b_data, bh->b_size);
bh = bh->b_reqnext;
}
if(SCpnt->use_sg < 16)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a5a825de6..dc702848d 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -890,7 +890,7 @@ scsi_tape_flush(struct file * filp)
kdev_t devt = inode->i_rdev;
int dev;
- if (filp->f_count > 1)
+ if (atomic_read(&filp->f_count) > 1)
return 0;
dev = TAPE_NR(devt);
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index aaa9e7e46..4178891ce 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -408,7 +408,6 @@ static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs
show_state();
return;
} else if (ch == 2) {
- show_buffers();
return;
}
/* It is a 'keyboard interrupt' ;-) */
diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c
index ad273206f..e91a94456 100644
--- a/drivers/sgi/char/usema.c
+++ b/drivers/sgi/char/usema.c
@@ -54,7 +54,7 @@ sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
return newfd;
current->files->fd [newfd] = usema->filp;
- usema->filp->f_count++;
+ atomic_inc(&usema->filp->f_count);
/* Is that it? */
printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
return newfd;
diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c
index f4befd5a3..c6f4f45c6 100644
--- a/drivers/sound/cmpci.c
+++ b/drivers/sound/cmpci.c
@@ -62,6 +62,7 @@
/*****************************************************************************/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c
index c6eb5c8d5..3f55b74cf 100644
--- a/drivers/sound/sb_ess.c
+++ b/drivers/sound/sb_ess.c
@@ -183,6 +183,7 @@
* ES1946 yes This is a PCI chip; not handled by this driver
*/
+#include <linux/config.h>
#include <linux/delay.h>
#include "sound_config.h"
diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci
index faa650b8d..921d9a9a3 100644
--- a/drivers/usb/README.ohci
+++ b/drivers/usb/README.ohci
@@ -1,3 +1,21 @@
+[This is the readme for ohci.c, ohci-debug.c and ohci.h]
+
+June 23, 1999 00:31:20 PST
+
+I now have bulk support in a reasonably working state. The only
+device I have tested it with at the moment is my Epson Stylus 740
+printer. I can print both small and large files.
+
+I have included code to support transfers of large amounts of data in
+either control or bulk transfers. Check out the build_td_chain() and
+add_td_chain_to_ed() functions.
+
+TODO:
+
+~ Get Michael Gee's mass storage driver working with my donated
+ YE-Data floppy drive over OHCI.
+~ Drool on the Epson printer because its the new toy around the house.
+
June 08, 1999 01:23:34
Paul Mackerras went through the OHCI (& USB code) to fix most of the
@@ -12,12 +30,6 @@ that occurred after removing a device.
TODO:
-~ Add the concept of a td_group to lump TDs associated with a single
- data transfer request from the higher layers. This will be needed
- for bulk and all larger transfers that will span multiple TDs but
- which need to allocate/free them as a group as things happen. I
- am thinking about create_td_group and free_td_group functions...
-~ Add bulk transfer support.
~ Add Isochronous transfer support. These have their own special
format TDs to allow for several DMA data pointers. Kinda neat, but
likely harder to use through a generic interface in practice.
@@ -32,7 +44,7 @@ KNOWN BUGS:
called using the "IRQ handle" that should be returned by
usb_request_irq().
-May 09, 1999 16:25:58
+May 09, 1999 16:25:58 PST
Cool, things are working "well" now. (I'm not getting oops's from the
OHCI code anyways.. ;). I can attach a usb hub and mouse in any
@@ -43,18 +55,5 @@ acknowledged because /proc/interrupts usb-ohci goes up accordingly with
mouse movements/events. That means the TD at least returns some data
and requeues itself.
-Device attach/detach from the root hub is not working well. Currently
-every interrupt checks for root hub status changes and frame number
-overflow interrupts are enabled. This means you shouldn't have to
-wait more than 32-33 seconds for the change to occur, less if there is
-other activity. (due to checking in the WDH caused interrupts)
-My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
-with the RHSC interrupt so it has been disabled. The ohci_timer
-should be polling but it not currently working, I haven't had time to
-look into that problem.
-
-However, when I tried telling X to use /dev/psaux for the mouse my
-machine locked up...
-
- greg@electricrain.com
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 10c837d5a..d5acef82f 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -26,7 +26,6 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/spinlock.h>
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 9743ec89e..abbb73c4f 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -3,7 +3,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/sched.h>
-#include <linux/config.h>
#include <linux/module.h>
#include "usb.h"
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
index 2402d3425..ba89884a4 100644
--- a/drivers/usb/cpia.c
+++ b/drivers/usb/cpia.c
@@ -17,7 +17,6 @@
#include <linux/videodev.h>
#include <linux/vmalloc.h>
#include <linux/wrapper.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/spinlock.h>
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 0a1ec1f01..20ff10427 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -10,7 +10,6 @@
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/spinlock.h>
diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c
index a79c10a07..7ebb03be4 100644
--- a/drivers/usb/mouse.c
+++ b/drivers/usb/mouse.c
@@ -33,7 +33,6 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/spinlock.h>
diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c
index 263f32c91..56b9fff0a 100644
--- a/drivers/usb/ohci-debug.c
+++ b/drivers/usb/ohci-debug.c
@@ -124,7 +124,9 @@ void show_ohci_td(struct ohci_td *td)
td_cc_accessed(*td) ? "" : "Not ",
td_active(*td) ? "" : "Not ");
- printk(KERN_DEBUG " %s\n", td_allocated(*td) ? "Allocated" : "Free");
+ printk(KERN_DEBUG " %s%s\n",
+ td_allocated(*td) ? "Allocated" : "Free",
+ td_dummy(*td) ? " DUMMY" : "");
printk(KERN_DEBUG " cur_buf = 0x%x\n", le32_to_cpup(&td->cur_buf));
printk(KERN_DEBUG " next_td = 0x%x\n", le32_to_cpup(&td->next_td));
@@ -141,6 +143,26 @@ void show_ohci_td(struct ohci_td *td)
} /* show_ohci_td() */
+void show_ohci_td_chain(struct ohci_td *td)
+{
+ struct ohci_td *cur_td;
+ if (td == NULL) return;
+
+ printk(KERN_DEBUG "+++ OHCI TD Chain %lx: +++\n", virt_to_bus(td));
+
+ cur_td = td;
+ for (;;) {
+ show_ohci_td(cur_td);
+ if (!cur_td->next_td) break;
+ cur_td = bus_to_virt(le32_to_cpup(&cur_td->next_td));
+ /* we can't trust -anything- we find inside of a dummy TD */
+ if (td_dummy(*cur_td)) break;
+ }
+
+ printk(KERN_DEBUG "--- End TD Chain %lx: ---\n", virt_to_bus(td));
+} /* show_ohci_td_chain () */
+
+
void show_ohci_device(struct ohci_device *dev)
{
int idx;
diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c
index 48191e11b..261306949 100644
--- a/drivers/usb/ohci.c
+++ b/drivers/usb/ohci.c
@@ -2,19 +2,14 @@
* Open Host Controller Interface driver for USB.
*
* (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ * Significant code from the following individuals has also been used:
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> [ohci-hcd.c]
+ * (C) Copyright 1999 Linus Torvalds [uhci.c]
*
* This is the "other" host controller interface for USB. You will
* find this on many non-Intel based motherboards, and of course the
- * Mac. As Linus hacked his UHCI driver together first, I modeled
- * this after his.. (it should be obvious)
- *
- * From the programming standpoint the OHCI interface seems a little
- * prettier and potentially less CPU intensive. This remains to be
- * proven. In reality, I don't believe it'll make one darn bit of
- * difference. USB v1.1 is a slow bus by today's standards.
- *
- * OHCI hardware takes care of most of the scheduling of different
- * transfer types with the correct prioritization for us.
+ * Mac. As Linus hacked his UHCI driver together first, I originally
+ * modeled this after his.. (it should be obvious)
*
* To get started in USB, I used the "Universal Serial Bus System
* Architecture" book by Mindshare, Inc. It was a reasonable introduction
@@ -76,6 +71,7 @@ static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
#define FIELDS_OF_TD(t) le32_to_cpup(&t->info), le32_to_cpup(&t->cur_buf), \
le32_to_cpup(&t->next_td), le32_to_cpup(&t->buf_end)
+#ifdef OHCI_DEBUG
static const char *cc_names[16] = {
"no error",
"CRC error",
@@ -94,6 +90,7 @@ static const char *cc_names[16] = {
"not accessed (14)",
"not accessed"
};
+#endif
/*
* Add a chain of TDs to the end of the TD list on a given ED.
@@ -152,6 +149,36 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
} /* ohci_add_td_to_ed() */
+/*
+ * Add a whole chain of TDs to an ED using the above function.
+ * The same restrictions apply.
+ *
+ * XXX This function is being removed in the future! XXX
+ */
+static struct ohci_td *ohci_add_td_chain_to_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+ struct ohci_td *cur_td;
+ if (!td)
+ return NULL;
+
+ /* Find the last TD in this chain, storing its pointer in cur_td */
+ cur_td = td;
+ for (;;) {
+ __u32 next_td = cur_td->next_td;
+
+ /* advance to the next td, exit if there isn't one */
+ if (!next_td)
+ break;
+ cur_td = bus_to_virt(le32_to_cpup(&next_td));
+ }
+
+ return td = ohci_add_td_to_ed(td, cur_td, ed);
+} /* ohci_add_td_chain_to_ed() */
+
+
+/* .......... */
+
+
inline void ohci_start_control(struct ohci *ohci)
{
/* tell the HC to start processing the control list */
@@ -474,7 +501,7 @@ void ohci_remove_device(struct ohci *ohci, int devnum)
}
/*
- * Remove a TD from the given EDs TD list.
+ * Remove a TD from the given EDs TD list. The TD is freed as well.
*/
static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
{
@@ -484,11 +511,11 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
if ((td == NULL) || (ed == NULL))
return;
- spin_lock_irqsave(&ohci_edtd_lock, flags);
-
if (ed_head_td(ed) == 0)
return;
+ spin_lock_irqsave(&ohci_edtd_lock, flags);
+
/* set the "skip me bit" in this ED */
ed->status |= cpu_to_le32(OHCI_ED_SKIP);
@@ -569,6 +596,10 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
/*
* Get a pointer (virtual) to an available TD from the given device's
* pool. Return NULL if none are left.
+ *
+ * NOTE: This function does not allocate and attach the dummy_td.
+ * That is done in ohci_fill_ed(). FIXME: it should probably be moved
+ * into here.
*/
static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
{
@@ -593,6 +624,11 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
} /* ohci_get_free_ed() */
+/*
+ * Free an OHCI ED and all of the TDs on its list. It is assumed that
+ * this ED is not active. You should call ohci_wait_for_ed_safe()
+ * beforehand if you can't guarantee that.
+ */
void ohci_free_ed(struct ohci_ed *ed)
{
if (!ed)
@@ -692,6 +728,140 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
} /* ohci_fill_ed() */
+/*
+ * Create a chain of Normal TDs to be used for a large data transfer
+ * (bulk or control).
+ *
+ * Returns the head TD in the chain.
+ */
+struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigned int len, int dir, __u32 toggle, int round, int auto_free, void* dev_id, usb_device_irq handler, __u32 next_td)
+{
+ struct ohci_td *head, *cur_td;
+ __u32 bus_data_start, bus_data_end;
+ unsigned short max_page0_len;
+
+ if (!data || (len == 0))
+ return NULL;
+
+ /* Setup the first TD, leaving buf_end = 0 */
+ head = ohci_get_free_td(dev);
+ if (head == NULL) {
+ printk(KERN_ERR "usb-ohci: out of TDs\n");
+ return NULL;
+ }
+
+ ohci_fill_new_td(head,
+ td_set_dir_out(dir),
+ toggle & OHCI_TD_DT,
+ (round ? OHCI_TD_ROUND : 0),
+ data, 0,
+ dev_id, handler);
+ if (!auto_free)
+ noauto_free_td(head);
+
+ cur_td = head;
+
+ /* AFICT, that the OHCI controller takes care of the innards of
+ * bulk & control data transfers by sending zero length
+ * packets as necessary if the transfer falls on an even packet
+ * size boundary, we don't need a special TD for that. */
+
+ while (len > 0) {
+ bus_data_start = virt_to_bus(data);
+ bus_data_end = virt_to_bus(data+(len-1));
+
+ /* check the 4096 byte alignment of the start of the data */
+ max_page0_len = 0x1000 - (bus_data_start & 0xfff);
+
+ /* check if the remaining data occupies more than two pages */
+ if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) {
+ struct ohci_td *new_td;
+
+ /* Point this TD to data up through the end of
+ * the second page */
+ cur_td->buf_end = bus_data_start +
+ (max_page0_len + 0xfff);
+
+ /* adjust the data pointer & remaining length */
+ data += (max_page0_len + 0x1000);
+ len -= (max_page0_len + 0x1000);
+
+ /* TODO lookup effect of rounding bit on
+ * individual TDs vs. whole TD chain transfers;
+ * disable cur_td's rounding bit here if needed. */
+
+ /* mark that this is not the last TD... */
+ clear_td_endofchain(cur_td);
+
+ /* allocate another td */
+ new_td = ohci_get_free_td(dev);
+ if (new_td == NULL) {
+ printk(KERN_ERR "usb-ohci: out of TDs\n");
+ /* FIXME: free any allocated TDs */
+ return NULL;
+ }
+
+ ohci_fill_new_td(new_td,
+ td_set_dir_out(dir),
+ TOGGLE_AUTO, /* toggle Data0/1 via the ED */
+ round ? OHCI_TD_ROUND : 0,
+ data, 0,
+ dev_id, handler);
+ if (!auto_free)
+ noauto_free_td(new_td);
+
+ /* Link the new TD to the chain & advance */
+ cur_td->next_td = virt_to_bus(new_td);
+ cur_td = new_td;
+ } else {
+ /* Last TD in this chain, normal buf_end is fine */
+ cur_td->buf_end = bus_data_end;
+
+ set_td_endofchain(cur_td);
+
+ len = 0;
+ break;
+ }
+ } /* while */
+
+ /* link the given next_td to the end of this chain */
+ cur_td->next_td = next_td;
+
+ return head;
+} /* ohci_build_td_chain() */
+
+
+/*
+ * Compute the number of bytes that have been transferred on a given
+ * TD. Do not call this on TDs that are active on the host
+ * controller.
+ */
+static __u16 ohci_td_bytes_done(struct ohci_td *td)
+{
+ __u16 result;
+ __u32 bus_data_start, bus_data_end;
+
+ bus_data_start = virt_to_bus(td->data);
+ if (!td->data || !bus_data_start)
+ return 0;
+
+ /* if cur_buf is 0, all data has been transferred */
+ bus_data_end = td->cur_buf ? td->cur_buf : td->buf_end;
+
+ /* is it on the same page? */
+ if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
+ result = bus_data_end - bus_data_start + 1;
+ } else {
+ /* compute the amount transferred on the first page */
+ result = 0x1000 - (bus_data_start & 0xfff);
+ /* add the amount done in the second page */
+ result += (bus_data_end & 0xfff) + 1;
+ }
+
+ return result;
+} /* ohci_td_bytes_done() */
+
+
/**********************************
* OHCI interrupt list operations *
**********************************/
@@ -762,6 +932,10 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
/* Assimilate the new ED into the collective */
ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+ /* FIXME: return a request handle that can be used by the
+ * caller to cancel this request. Be sure its guaranteed not
+ * to be re-used until the caller is guaranteed to know that
+ * the transfer has ended or been cancelled */
return 0;
} /* ohci_request_irq() */
@@ -794,8 +968,7 @@ static int ohci_control_completed(int stats, void *buffer, int len, void *dev_id
* Send or receive a control message on a "pipe"
*
* The cmd parameter is a pointer to the 8 byte setup command to be
- * sent. FIXME: This is a devrequest in usb.h. The function
- * should be updated to accept a devrequest* instead of void*..
+ * sent.
*
* A control message contains:
* - The command itself
@@ -811,7 +984,6 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
struct ohci_ed *control_ed = ohci_get_free_ed(dev);
struct ohci_td *setup_td, *data_td, *status_td;
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
int completion_status = -1;
devrequest our_cmd;
@@ -861,57 +1033,17 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
OHCI_TD_IOC_OFF,
&our_cmd, 8, /* cmd is always 8 bytes long */
- NULL, NULL);
+ &completion_status, NULL);
- /* allocate the next TD */
- data_td = ohci_get_free_td(dev);
- if (!data_td) {
- printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
+ /* Allocate a TD for the control xfer status */
+ status_td = ohci_get_free_td(dev);
+ if (!status_td) {
+ printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
ohci_free_td(setup_td);
ohci_free_ed(control_ed);
return -1;
}
- /* link to the next TD */
- setup_td->next_td = cpu_to_le32(virt_to_bus(data_td));
-
- if (len > 0) {
-
- /* build the Control DATA TD, it starts with a DATA1. */
- ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
- TOGGLE_DATA1,
- OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
- data, len,
- NULL, NULL);
-
- /*
- * TODO: Normal TDs can transfer up to 8192 bytes on OHCI.
- * However, for that to happen, the data must -start-
- * on a nice 4kb page. We need to check for data
- * sizes > 4096 and, if they cross more than two 4096
- * byte pages of memory one or more additional TDs
- * will need to be created. (repeat doing this in a
- * loop until all of the DATA is on a TD)
- *
- * Control transfers are -highly unlikely- to need to
- * transfer this much data.. but who knows.. sadistic
- * hardware is sure to exist.
- */
-
- status_td = ohci_get_free_td(dev); /* TODO check for NULL */
- if (!status_td) {
- printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
- ohci_free_td(setup_td);
- ohci_free_td(data_td);
- ohci_free_ed(control_ed);
- return -1;
- }
-
- data_td->next_td = cpu_to_le32(virt_to_bus(status_td));
- } else {
- status_td = data_td; /* no data_td, use it for status */
- }
-
/* The control status packet always uses a DATA1
* Give "dev_id" the address of completion_status so that the
* TDs status can be passed back to us from the IRQ. */
@@ -923,27 +1055,44 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
&completion_status, ohci_control_completed);
status_td->next_td = 0; /* end of TDs */
+ /* If there is data to transfer, create the chain of data TDs
+ * followed by the status TD. */
+ if (len > 0) {
+ data_td = ohci_build_td_chain( dev, data, len,
+ usb_pipeout(pipe), TOGGLE_DATA1,
+ 1 /* round */, 1 /* autofree */,
+ &completion_status, NULL /* no handler here */,
+ virt_to_bus(status_td) );
+ if (!data_td) {
+ printk(KERN_ERR "usb-ohci: couldn't allocate control data TDs for dev %p\n", dev);
+ ohci_free_td(setup_td);
+ ohci_free_td(status_td);
+ ohci_free_ed(control_ed);
+ return -1;
+ }
+
+ /* link the to the data & status TDs */
+ setup_td->next_td = virt_to_bus(data_td);
+ } else {
+ /* no data TDs, link to the status TD */
+ setup_td->next_td = virt_to_bus(status_td);
+ }
+
/*
- * Add the chain of 2-3 control TDs to the control ED's TD list
+ * Add the control TDs to the control ED (setup_td is the first)
*/
- spin_lock_irqsave(&ohci_edtd_lock, flags);
- setup_td = ohci_add_td_to_ed(setup_td, status_td, control_ed);
- spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+ setup_td = ohci_add_td_chain_to_ed(setup_td, control_ed);
+ control_ed->status &= ~OHCI_ED_SKIP;
+ ohci_unhalt_ed(control_ed);
#ifdef OHCI_DEBUG
if (MegaDebug) {
/* complete transaction debugging output (before) */
printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
show_ohci_ed(control_ed);
- printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
- show_ohci_td(setup_td);
- if (data_td != status_td) {
- printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
- show_ohci_td(data_td);
- }
- printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
- show_ohci_td(status_td);
- printk(KERN_DEBUG " Controller Status:\n");
+ printk(KERN_DEBUG " Control TD chain:\n");
+ show_ohci_td_chain(setup_td);
+ printk(KERN_DEBUG " OHCI Controller Status:\n");
show_ohci_status(dev->ohci);
}
#endif
@@ -966,19 +1115,15 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
/* complete transaction debugging output (after) */
printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
show_ohci_ed(control_ed);
- printk(KERN_DEBUG " *after* Setup TD %lx:\n", virt_to_bus(setup_td));
- show_ohci_td(setup_td);
- if (data_td != status_td) {
- printk(KERN_DEBUG " *after* Data TD %lx:\n", virt_to_bus(data_td));
- show_ohci_td(data_td);
- }
- printk(KERN_DEBUG " *after* Status TD %lx:\n", virt_to_bus(status_td));
- show_ohci_td(status_td);
- printk(KERN_DEBUG " *after* Controller Status:\n");
+ printk(KERN_DEBUG " *after* Control TD chain:\n");
+ show_ohci_td_chain(setup_td);
+ printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
show_ohci_status(dev->ohci);
}
#endif
+ /* no TD cleanup, the TDs were auto-freed as they finished */
+
/* remove the control ED from the HC */
ohci_remove_control_ed(dev->ohci, control_ed);
ohci_free_ed(control_ed); /* return it to the pool */
@@ -1008,6 +1153,219 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
} /* ohci_control_msg() */
+/**********************************************************************
+ * Bulk transfer processing
+ **********************************************************************/
+
+/*
+ * Internal state for an ohci_bulk_request
+ */
+struct ohci_bulk_request_state {
+ struct usb_device *usb_dev;
+ unsigned int pipe; /* usb "pipe" */
+ void *data; /* ptr to data */
+ int length; /* length to transfer */
+ int _bytes_done; /* bytes transferred so far */
+ unsigned long *bytes_transferred_p; /* where to increment */
+ void *dev_id; /* pass to the completion handler */
+ usb_device_irq completion; /* completion handler */
+};
+
+/*
+ * this handles the individual TDs of a (possibly) larger bulk
+ * request. It keeps track of the total bytes transferred, calls the
+ * final completion handler, etc.
+ */
+static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
+{
+ struct ohci_bulk_request_state *req;
+
+ req = (struct ohci_bulk_request_state *) dev_id;
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req);
+#endif
+
+ /* only count TDs that were completed successfully */
+ if (stats == USB_ST_NOERROR)
+ req->_bytes_done += len;
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_bulk_td_handler %d bytes done\n", req->_bytes_done);
+#endif
+
+ /* call the real completion handler when done or on an error */
+ if ((stats != USB_ST_NOERROR) ||
+ (req->_bytes_done >= req->length && req->completion != NULL)) {
+ *req->bytes_transferred_p += req->_bytes_done;
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "usb-ohci: bulk request %p ending after %d bytes\n", req, req->_bytes_done);
+#endif
+ req->completion(stats, buffer, req->_bytes_done, req->dev_id);
+ }
+
+ return 0; /* do not re-queue the TD */
+} /* ohci_bulk_td_handler() */
+
+
+/*
+ * Request to send or receive bulk data. The completion() function
+ * will be called when the transfer has completed or been aborted due
+ * to an error.
+ *
+ * bytes_transferred_p is a pointer to an integer that will be
+ * -incremented- by the number of bytes that have been successfully
+ * transferred. The interrupt handler will update it after each
+ * internal TD completes successfully.
+ *
+ * This function can NOT be called from an interrupt (?)
+ * (TODO: verify & fix this if needed).
+ *
+ * Returns: a pointer to the ED being used for this request. At the
+ * moment, removing & freeing it is the responsibilty of the caller.
+ */
+static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_request)
+{
+ /* local names for the readonly fields */
+ struct usb_device *usb_dev = bulk_request->usb_dev;
+ unsigned int pipe = bulk_request->pipe;
+ void *data = bulk_request->data;
+ int len = bulk_request->length;
+
+ struct ohci_device *dev = usb_to_ohci(usb_dev);
+ struct ohci_ed *bulk_ed;
+ struct ohci_td *head_td;
+ unsigned long flags;
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len);
+#endif
+
+ bulk_ed = ohci_get_free_ed(dev);
+ if (!bulk_ed) {
+ printk("usb-ohci: couldn't get ED for dev %p\n", dev);
+ return NULL;
+ }
+
+ /* allocate & fill in the TDs for this request */
+ head_td = ohci_build_td_chain(dev, data, len, usb_pipeout(pipe),
+ TOGGLE_AUTO,
+ 0 /* round not required */, 1 /* autofree */,
+ bulk_request, /* dev_id: the bulk_request */
+ ohci_bulk_td_handler,
+ 0 /* no additional TDs */);
+ if (!head_td) {
+ printk("usb-ohci: couldn't get TDs for dev %p\n", dev);
+ ohci_free_ed(bulk_ed);
+ return NULL;
+ }
+
+ /* Set the max packet size, device speed, endpoint number, usb
+ * device number (function address), and type of TD. */
+ ohci_fill_ed(dev, bulk_ed,
+ usb_maxpacket(usb_dev, pipe),
+ usb_pipeslow(pipe),
+ usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */);
+
+ /* initialize the internal counter */
+ bulk_request->_bytes_done = 0;
+
+ /*
+ * Add the TDs to the ED
+ */
+ spin_lock_irqsave(&ohci_edtd_lock, flags);
+ bulk_ed->status |= OHCI_ED_SKIP;
+ head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed);
+ bulk_ed->status &= ~OHCI_ED_SKIP;
+ ohci_unhalt_ed(bulk_ed);
+ spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+
+
+#ifdef OHCI_DEBUG
+/* if (MegaDebug) { */
+ /* complete transaction debugging output (before) */
+ printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed));
+ show_ohci_ed(bulk_ed);
+ printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td));
+ show_ohci_td_chain(head_td);
+/* } */
+#endif
+
+ /* Give the ED to the HC */
+ ohci_add_bulk_ed(dev->ohci, bulk_ed);
+
+ return bulk_ed;
+} /* ohci_request_bulk() */
+
+
+static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
+
+
+static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id)
+{
+ if (dev_id != NULL) {
+ int *completion_status = (int *)dev_id;
+ *completion_status = stats;
+ }
+
+ wake_up(&bulk_wakeup);
+ return 0; /* don't requeue the TD */
+} /* ohci_bulk_msg_completed() */
+
+
+static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int completion_status = USB_ST_INTERNALERROR;
+ struct ohci_bulk_request_state req;
+ struct ohci_ed *req_ed;
+
+ /* ....... */
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
+#endif
+
+ req.usb_dev = usb_dev;
+ req.pipe = pipe;
+ req.data = data;
+ req.length = len;
+ req.bytes_transferred_p = bytes_transferred_p;
+ req.dev_id = &completion_status;
+ req.completion = ohci_bulk_msg_completed;
+
+ /*
+ * Start the transaction..
+ */
+ current->state = TASK_UNINTERRUPTIBLE;
+ add_wait_queue(&bulk_wakeup, &wait);
+
+ req_ed = ohci_request_bulk(&req);
+
+ /* FIXME this should to wait for a caller specified time... */
+ schedule_timeout(HZ*5);
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_bulk_msg request completed or timed out w/ status %x\n", completion_status);
+#endif
+
+ remove_wait_queue(&bulk_wakeup, &wait);
+
+ /* remove the ED from the HC */
+ ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+ ohci_free_ed(req_ed); /* return it to the pool */
+
+#ifdef OHCI_DEBUG
+ printk(KERN_DEBUG "ohci_bulk_msg done.\n");
+#endif
+
+ return completion_status;
+} /* ohci_bulk_msg() */
+
+
+/* .......... */
+
+
/*
* Allocate a new USB device to be attached to an OHCI controller
*/
@@ -1079,8 +1437,6 @@ static int ohci_usb_deallocate(struct usb_device *usb_dev)
return 0;
}
-/* FIXME! */
-#define ohci_bulk_msg NULL
/*
* functions for the generic USB driver
@@ -1404,6 +1760,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
{
struct ohci_td *td; /* used for walking the list */
+ /* um... isn't this dangerous to do in an interrupt handler? -greg */
spin_lock(&ohci_edtd_lock);
/* create the FIFO ordered donelist */
@@ -1416,18 +1773,12 @@ static void ohci_reap_donelist(struct ohci *ohci)
if (td_dummy(*td))
printk(KERN_ERR "yikes! reaping a dummy TD\n");
- /* FIXME: munge td->info into a future standard status format */
-
- if (cc != 0 && ohci_ed_halted(td->ed) && td->completed == 0) {
+ if (cc != 0 && ohci_ed_halted(td->ed) && !td_endofchain(*td)) {
/*
* There was an error on this TD and the ED
* is halted, and this was not the last TD
* of the transaction, so there will be TDs
* to clean off the ED.
- * (We assume that a TD with a non-NULL completed
- * field is the last one of a transaction.
- * Ultimately we should have a flag in the TD
- * to say that it is the last one.)
*/
struct ohci_ed *ed = td->ed;
struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed));
@@ -1437,17 +1788,27 @@ static void ohci_reap_donelist(struct ohci *ohci)
td = ntd = bus_to_virt(ed_head_td(ed));
while (td != tail_td) {
ntd = bus_to_virt(le32_to_cpup(&td->next_td));
- if (td->completed != 0)
- break;
- ohci_free_td(td);
+
+ /* only deal with TDs from this ED,
+ * the host controller could have
+ * processed other endpoints at the
+ * same time as this one.. */
+ if (td->ed == ed) {
+ if (td_endofchain(*td))
+ break;
+
+ /* FIXME: unlink this TD from the
+ * reverse donelist! */
+ ohci_free_td(td);
+ }
+
td = ntd;
}
/* Set the ED head past the ones we cleaned
off, and clear the halted flag */
set_ed_head_td(ed, virt_to_bus(ntd));
ohci_unhalt_ed(ed);
- /* If we didn't find a TD with a completion
- routine, give up */
+ /* If we didn't find an endofchain TD, give up */
if (td == tail_td) {
td = next_td;
continue;
@@ -1456,7 +1817,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
/* Check if TD should be re-queued */
if ((td->completed != NULL) &&
- (td->completed(cc, td->data, -1 /* XXX */, td->dev_id))) {
+ (td->completed(cc, td->data, ohci_td_bytes_done(td), td->dev_id))) {
/* Mark the TD as active again:
* Set the not accessed condition code
* Reset the Error count
@@ -1473,7 +1834,8 @@ static void ohci_reap_donelist(struct ohci *ohci)
ohci_add_td_to_ed(td, td, td->ed);
} else {
/* return it to the pool of free TDs */
- ohci_free_td(td);
+ if (can_auto_free(*td))
+ ohci_free_td(td);
}
td = next_td;
@@ -1516,6 +1878,13 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
/* Disable HC interrupts */ /* why? - paulus */
writel(OHCI_INTR_MIE, &regs->intrdisable);
+#if 0
+ /* Only do this for SERIOUS debugging, be sure kern.debug logs
+ * are not going to the console as this can cause your
+ * machine to lock up if so... -greg */
+ show_ohci_status(ohci);
+#endif
+
/* Process the done list */
if (context & OHCI_INTR_WDH) {
/* See which TD's completed.. */
@@ -1856,9 +2225,11 @@ static int ohci_control_thread(void * __ohci)
show_ohci_status(ohci);
} else if (signr == SIGUSR2) {
/* toggle mega TD/ED debugging output */
+#ifdef OHCI_DEBUG
MegaDebug = !MegaDebug;
printk(KERN_DEBUG "usb-ohci: Mega debugging %sabled.\n",
MegaDebug ? "en" : "dis");
+#endif
} else {
/* unknown signal, exit the thread */
break;
@@ -2084,9 +2455,6 @@ int ohci_init(void)
} /* ohci_init */
-/* vim:sw=8
- */
-
#ifdef MODULE
/*
* Clean up when unloading the module
@@ -2103,4 +2471,5 @@ int init_module(void){
}
#endif //MODULE
-
+/* vim:sw=8
+ */
diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h
index 2fdc3583d..88b08750f 100644
--- a/drivers/usb/ohci.h
+++ b/drivers/usb/ohci.h
@@ -38,10 +38,12 @@ struct ohci_td {
void *data; /* virt. address of the the buffer */
usb_device_irq completed; /* Completion handler routine */
int hcd_flags; /* Flags for the HCD: */
- /* bit0 = boolean: Is this TD allocated? */
- /* bit1 = boolean: Is this a dummy (end of list) TD? */
+ /* bit0: Is this TD allocated? */
+ /* bit1: Is this a dummy (end of list) TD? */
+ /* bit2: do NOT automatically free this TD on completion */
+ /* bit3: this is NOT the last TD in a contiguious TD chain
+ * on the indicated ED. (0 means it is the last) */
- /* User or Device class driver specific fields */
void *dev_id; /* user defined pointer passed to irq handler */
} __attribute((aligned(16)));
@@ -54,6 +56,7 @@ struct ohci_td {
#define td_set_dir_out(d) ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
#define OHCI_TD_IOC_DELAY (7 << 21) /* frame delay allowed before int. */
#define OHCI_TD_IOC_OFF (OHCI_TD_IOC_DELAY) /* no interrupt on complete */
+#define td_set_ioc_delay(frames) (((frames) & 7) << 21)
#define OHCI_TD_DT (3 << 24) /* data toggle bits */
#define TOGGLE_AUTO (0 << 24) /* automatic (from the ED) */
#define TOGGLE_DATA0 (2 << 24) /* force Data0 */
@@ -82,6 +85,19 @@ struct ohci_td {
#define make_dumb_td(td) ((td)->hcd_flags |= 2)
#define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2)
+#define td_endofchain(td) (!((td).hcd_flags & (1 << 3)))
+#define set_td_endofchain(td) ((td)->hcd_flags &= ~(1 << 3))
+#define clear_td_endofchain(td) ((td)->hcd_flags |= (1 << 3))
+
+/*
+ * These control if the IRQ will call ohci_free_td after taking the TDs
+ * off of the donelist (assuming the completion function does not ask
+ * for the TD to be requeued).
+ */
+#define can_auto_free(td) (!((td).hcd_flags & 4))
+#define noauto_free_td(td) ((td)->hcd_flags |= 4)
+#define auto_free_td(td) ((td)->hcd_flags &= ~(__u32)4)
+
/*
* The endpoint descriptors also requires 16-byte alignment
@@ -369,6 +385,7 @@ struct ohci {
int irq;
struct ohci_regs *regs; /* OHCI controller's memory */
struct usb_bus *bus;
+ struct ohci_device *root_hub; /* Root hub & controller */
struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */
};
@@ -380,6 +397,7 @@ struct ohci {
/* Debugging code [ohci-debug.c] */
void show_ohci_ed(struct ohci_ed *ed);
void show_ohci_td(struct ohci_td *td);
+void show_ohci_td_chain(struct ohci_td *td);
void show_ohci_status(struct ohci *ohci);
void show_ohci_device(struct ohci_device *dev);
void show_ohci_hcca(struct ohci_hcca *hcca);
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 88723c6ff..157d58898 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -25,7 +25,7 @@
#define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT) /* should not take 1 minute a page! */
#ifndef USB_PRINTER_MAJOR
-#define USB_PRINTER_MAJOR 0
+#define USB_PRINTER_MAJOR 63
#endif
static int mymajor = USB_PRINTER_MAJOR;
@@ -166,6 +166,7 @@ static ssize_t write_printer(struct file * file,
do {
char *obuf = p->obuf;
unsigned long thistime;
+ partial = 0;
thistime = copy_size = (count > p->maxout) ? p->maxout : count;
if (copy_from_user(p->obuf, buffer, copy_size))
@@ -179,16 +180,19 @@ static ssize_t write_printer(struct file * file,
}
result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
usb_sndbulkpipe(p->pusb_dev, 1), obuf, thistime, &partial);
+ 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) {
- obuf += partial;
- thistime -= partial;
- } else
+ } else if (!result && !partial) {
break;
+ }
};
if (result) {
/* whoops - let's reset and fail the request */
@@ -255,7 +259,8 @@ static int printer_probe(struct usb_device *dev)
/*
* FIXME - this will not cope with combined printer/scanners
*/
- if (dev->descriptor.bDeviceClass != 7 ||
+ if ((dev->descriptor.bDeviceClass != 7 &&
+ dev->descriptor.bDeviceClass != 0) ||
dev->descriptor.bNumConfigurations != 1 ||
dev->config[0].bNumInterfaces != 1) {
return -1;
@@ -408,6 +413,6 @@ void cleanup_module(void)
unsigned int offset;
usb_deregister(&printer_driver);
- unregister_chrdev(mymajor, "usblplp");
+ unregister_chrdev(mymajor, "usblp");
}
#endif
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index c03ce5adf..48233703c 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -20,6 +20,7 @@
/* 4/4/1999 added data toggle for interrupt pipes -keryan */
/* 5/16/1999 added global toggles for bulk and control */
+/* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */
#include <linux/config.h>
#include <linux/module.h>
@@ -105,7 +106,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
if (uhci_debug) {
printk("Set toggle from %x rval %d\n", (unsigned int)tmp, rval ? *rval : 0);
}
- usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), (tmp->info >> 19) & 1);
+ usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
break;
} else {
if(rval)
@@ -372,7 +373,7 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
td->link = 1;
td->status = status; /* In */
- td->info = destination | (7 << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe)) << 19); /* 8 bytes of data */
+ td->info = destination | (7 << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* 8 bytes of data */
td->buffer = virt_to_bus(dev->data);
td->first = td;
td->qh = interrupt_qh;
@@ -991,7 +992,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
td->status = status; /* Status */
td->info = destination | ((pktsze-1) << 21) |
- (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe)) << 19); /* pktsze bytes of data */
+ (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
td->first = first;
@@ -1006,7 +1007,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
}
/* Alternate Data0/1 (start with Data0) */
- usb_dotoggle(usb_dev, usb_pipeendpoint(pipe));
+ usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
}
td->link = 1; /* Terminate */
td->status |= (1 << 24); /* IOC */
@@ -1267,9 +1268,9 @@ static void uhci_interrupt_notify(struct uhci *uhci)
if (!(td->status & (1 << 25))) {
struct uhci_qh *interrupt_qh = td->qh;
- usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
+ usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
td->info &= ~(1 << 19); /* clear data toggle */
- td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info)) << 19; /* toggle between data0 and data1 */
+ td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
/* Remove then readd? Is that necessary */
@@ -1280,7 +1281,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
struct uhci_qh *interrupt_qh = td->qh;
/* marked for removal */
td->inuse &= ~2;
- usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
+ usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
uhci_qh_deallocate(interrupt_qh);
uhci_td_deallocate(td);
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index b291c04c6..bbce88b64 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -36,7 +36,6 @@
* 6 wLength 2 Count Bytes for data
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
@@ -773,7 +772,7 @@ int usb_clear_halt(struct usb_device *dev, int endp)
/* toggle is reset on clear */
- usb_settoggle(dev, endp & 0x0f, 0);
+ usb_settoggle(dev, endp & 0x0f, ((endp >> 7) & 1) ^ 1, 0);
return 0;
}
@@ -823,7 +822,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
return -1;
dev->actconfig = cp;
- dev->toggle = 0;
+ dev->toggle[0] = 0;
+ dev->toggle[1] = 0;
usb_set_maxpacket(dev);
return 0;
}
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index a6bf78e4a..5c36dad34 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -276,7 +276,7 @@ struct usb_device {
int devnum; /* Device number on USB bus */
int slow; /* Slow device? */
int maxpacketsize; /* Maximum packet size */
- int toggle; /* one bit for each endpoint */
+ int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
int halted; /* endpoint halts */
struct usb_config_descriptor *actconfig;/* the active configuration */
int epmaxpacket[16]; /* endpoint specific maximums */
@@ -362,7 +362,7 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipedata(pipe) (((pipe) >> 19) & 1)
-#define usb_pipeout(pipe) (((pipe) & 0x80) == 0)
+#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
#define usb_pipeslow(pipe) (((pipe) >> 26) & 1)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
@@ -374,9 +374,9 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
/* The D0/D1 toggle bits */
-#define usb_gettoggle(dev, ep) (((dev)->toggle >> ep) & 1)
-#define usb_dotoggle(dev, ep) ((dev)->toggle ^= (1 << ep))
-#define usb_settoggle(dev, ep, bit) ((dev)->toggle = ((dev)->toggle & ~(1 << ep)) | ((bit) << ep))
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
+#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep))
+#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep))
/* Endpoint halt */
#define usb_endpoint_halt(dev, ep) ((dev)->halted |= (1 << (ep)))
diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c
index 1a3e16b25..5701d2671 100644
--- a/drivers/usb/usb_scsi.c
+++ b/drivers/usb/usb_scsi.c
@@ -25,6 +25,7 @@
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/usb/usb_scsi.h b/drivers/usb/usb_scsi.h
index 58367d852..3e6386f4f 100644
--- a/drivers/usb/usb_scsi.h
+++ b/drivers/usb/usb_scsi.h
@@ -11,6 +11,8 @@
*
*/
+#include <linux/config.h>
+
#define USB_SCSI "usbscsi: "
extern int usbscsi_debug;
diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c
index ce2c89eb7..7e17bf1d6 100644
--- a/drivers/video/sbusfb.c
+++ b/drivers/video/sbusfb.c
@@ -364,9 +364,29 @@ static int sbusfb_get_var(struct fb_var_screeninfo *var, int con,
*/
static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *info)
{
- return -EINVAL;
+ struct display *display;
+ int activate = var->activate;
+
+ if(con >= 0)
+ display = &fb_display[con];
+ else
+ display = info->disp;
+
+ /* simple check for equality until fully implemented -E */
+ if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ if (display->var.xres != var->xres ||
+ display->var.yres != var->yres ||
+ display->var.xres_virtual != var->xres_virtual ||
+ display->var.yres_virtual != var->yres_virtual ||
+ display->var.bits_per_pixel != var->bits_per_pixel ||
+ display->var.accel_flags != var->accel_flags) {
+ return -EINVAL;
+ }
+ }
+ return 0;
+
}
/*
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index b208392a9..9d9f0242d 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -89,11 +89,14 @@ static struct inode_operations proc_bus_zorro_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
int