diff options
Diffstat (limited to 'drivers')
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, ®s->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 |