diff options
Diffstat (limited to 'drivers')
37 files changed, 1702 insertions, 1593 deletions
diff --git a/drivers/block/block_ioctl.c b/drivers/block/block_ioctl.c index e206157da22d..60b2fb3c0c64 100644 --- a/drivers/block/block_ioctl.c +++ b/drivers/block/block_ioctl.c @@ -27,6 +27,7 @@ #include <linux/smp_lock.h> #include <linux/module.h> #include <linux/blk.h> +#include <linux/completion.h> #include <linux/cdrom.h> diff --git a/drivers/ide/Config.help b/drivers/ide/Config.help index e8bc233729fd..248d80742c20 100644 --- a/drivers/ide/Config.help +++ b/drivers/ide/Config.help @@ -352,19 +352,10 @@ CONFIG_WDC_ALI15X3 SAY N! CONFIG_BLK_DEV_AMD74XX - This driver ensures (U)DMA support for the AMD756/760 Viper - chipsets. - - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. - Please read the comments at the top of <file:drivers/ide/amd74xx.c>. - - If unsure, say N. - -CONFIG_AMD74XX_OVERRIDE - This option auto-forces the ata66 flag. - This effect can be also invoked by calling "idex=ata66" - If unsure, say N. + This driver adds explicit support for AMD-7xx and AMD-8111 chips + and also for the nVidia nForce chip. This allows the kernel to + change PIO, DMA and UDMA speeds and to configure the chip to + optimum performance. CONFIG_BLK_DEV_CMD64X Say Y here if you have an IDE controller which uses any of these @@ -435,28 +426,10 @@ CONFIG_BLK_DEV_SVWKS chipsets. CONFIG_BLK_DEV_PIIX - This driver adds PIO mode setting and tuning for all PIIX IDE - controllers by Intel. Since the BIOS can sometimes improperly tune - PIO 0-4 mode settings, this allows dynamic tuning of the chipset - via the standard end-user tool 'hdparm'. - - Please read the comments at the top of <file:drivers/ide/piix.c>. - - If you say Y here, you should also say Y to "PIIXn Tuning support", - below. - - If unsure, say N. - -CONFIG_PIIX_TUNING - This driver extension adds DMA mode setting and tuning for all PIIX - IDE controllers by Intel. Since the BIOS can sometimes improperly - set up the device/adapter combination and speed limits, it has - become a necessity to back/forward speed devices as needed. - - Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode - 2 if the BIOS can not perform this task at initialization. - - If unsure, say N. + This driver adds explicit support for Intel PIIX and ICH chips + and also for the Efar Victory66 (slc90e66) chip. This allows + the kernel to change PIO, DMA and UDMA speeds and to configure + the chip to optimum performance. CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 @@ -513,19 +486,6 @@ CONFIG_BLK_DEV_SIS5513 Please read the comments at the top of <file:drivers/ide/sis5513.c>. -CONFIG_BLK_DEV_SLC90E66 - This driver ensures (U)DMA support for Victroy66 SouthBridges for - SMsC with Intel NorthBridges. This is an Ultra66 based chipset. - The nice thing about it is that you can mix Ultra/DMA/PIO devices - and it will handle timing cycles. Since this is an improved - look-a-like to the PIIX4 it should be a nice addition. - - If you say Y here, you need to say Y to "Use DMA by default when - available" as well. - - Please read the comments at the top of - <file:drivers/ide/slc90e66.c>. - CONFIG_BLK_DEV_SL82C105 If you have a Winbond SL82c105 IDE controller, say Y here to enable special configuration for this chip. This is common on various CHRP @@ -538,20 +498,9 @@ CONFIG_BLK_DEV_TRM290 Please read the comments at the top of <file:drivers/ide/trm290.c>. CONFIG_BLK_DEV_VIA82CXXX - This allows you to configure your chipset for a better use while - running PIO/(U)DMA, it will allow you to enable efficiently the - second channel dma usage, as it may not be set by BIOS. It will try - to set fifo configuration at its best. It will allow you to get - information from /proc/ide/via provided you enabled "/proc file - system" support. - - Please read the comments at the top of - <file:drivers/ide/via82cxxx.c>. - - If you say Y here, then say Y to "Use DMA by default when available" - as well. - - If unsure, say N. + This driver adds explicit support for VIA BusMastering IDE chips. + This allows the kernel to change PIO, DMA and UDMA speeds and to + configure the chip to optimum performance. CONFIG_BLK_DEV_IDE_RAPIDE Say Y here if you want to support the Yellowstone RapIDE controller diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in index ffbc8697a02e..342d76d0073d 100644 --- a/drivers/ide/Config.in +++ b/drivers/ide/Config.in @@ -53,18 +53,14 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 - dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP + dep_bool ' AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP dep_bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI - if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then - dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO - fi + dep_bool ' Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then dep_mbool ' IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO @@ -77,9 +73,8 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_bool ' Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX dep_bool ' ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 - dep_bool ' SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' VIA chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -167,32 +162,6 @@ else define_bool CONFIG_DMA_NONPCI n fi -if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ - "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \ - "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ - "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \ - "$CONFIG_BLK_DEV_CMD640" = "y" -o \ - "$CONFIG_BLK_DEV_CMD64X" = "y" -o \ - "$CONFIG_BLK_DEV_CS5530" = "y" -o \ - "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ - "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ - "$CONFIG_BLK_DEV_HPT366" = "y" -o \ - "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ - "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ - "$CONFIG_BLK_DEV_SVWKS" = "y" -o \ - "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ - "$CONFIG_BLK_DEV_PIIX" = "y" -o \ - "$CONFIG_BLK_DEV_IT8172" = "y" -o \ - "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ - "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \ - "$CONFIG_BLK_DEV_SL82C105" = "y" -o \ - "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \ - "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then - define_bool CONFIG_BLK_DEV_IDE_MODES y -else - define_bool CONFIG_BLK_DEV_IDE_MODES n -fi - dep_tristate 'Support for IDE Raid controllers' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL dep_tristate ' Support Promise software RAID (Fasttrak(tm))' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID dep_tristate ' Highpoint 370 software RAID' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index b72a5bedd157..3142a91f6f01 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -60,7 +60,6 @@ ide-obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o ide-obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o ide-obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o -ide-obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o ide-obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o ide-obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o ide-obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c index df0532a881c6..c1c036e36fb4 100644 --- a/drivers/ide/amd74xx.c +++ b/drivers/ide/amd74xx.c @@ -1,5 +1,5 @@ /* - * $Id: amd74xx.c,v 2.7 2002/09/01 17:37:00 vojtech Exp $ + * $Id: amd74xx.c,v 2.8 2002/03/14 11:52:20 vojtech Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik * @@ -46,13 +46,13 @@ #include "ata-timing.h" -#define AMD_IDE_ENABLE 0x40 -#define AMD_IDE_CONFIG 0x41 -#define AMD_CABLE_DETECT 0x42 -#define AMD_DRIVE_TIMING 0x48 -#define AMD_8BIT_TIMING 0x4e -#define AMD_ADDRESS_SETUP 0x4c -#define AMD_UDMA_TIMING 0x50 +#define AMD_IDE_ENABLE (0x00 + amd_config->base) +#define AMD_IDE_CONFIG (0x01 + amd_config->base) +#define AMD_CABLE_DETECT (0x02 + amd_config->base) +#define AMD_DRIVE_TIMING (0x08 + amd_config->base) +#define AMD_8BIT_TIMING (0x0e + amd_config->base) +#define AMD_ADDRESS_SETUP (0x0c + amd_config->base) +#define AMD_UDMA_TIMING (0x10 + amd_config->base) #define AMD_UDMA 0x07 #define AMD_UDMA_33 0x01 @@ -66,18 +66,19 @@ */ static struct amd_ide_chip { - char *name; unsigned short id; unsigned char rev; + unsigned int base; unsigned char flags; } amd_ide_chips[] = { - { "8111", PCI_DEVICE_ID_AMD_8111_IDE, 0x00, AMD_UDMA_100 }, - { "768 Opus", PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, AMD_UDMA_100 }, - { "766 Viper", PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, AMD_UDMA_100 | AMD_BAD_FIFO }, - { "756/c4+ Viper", PCI_DEVICE_ID_AMD_VIPER_7409, 0x07, AMD_UDMA_66 }, - { "756 Viper", PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, AMD_UDMA_66 | AMD_BAD_SWDMA }, - { "755 Cobra", PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, AMD_UDMA_33 | AMD_BAD_SWDMA }, - { NULL } + { PCI_DEVICE_ID_AMD_8111_IDE, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-8111 */ + { PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-768 Opus */ + { PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO }, /* AMD-766 Viper */ + { PCI_DEVICE_ID_AMD_VIPER_7409, 0x07, 0x40, AMD_UDMA_66 }, /* AMD-756/c4+ Viper */ + { PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_BAD_SWDMA }, /* AMD-756 Viper */ + { PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA }, /* AMD-755 Cobra */ + { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 }, /* nVidia nForce */ + { 0 } }; static struct amd_ide_chip *amd_config; @@ -119,8 +120,8 @@ static int amd_get_info(char *buffer, char **addr, off_t offset, int count) amd_print("----------AMD BusMastering IDE Configuration----------------"); - amd_print("Driver Version: 2.7"); - amd_print("South Bridge: AMD-%s", amd_config->name); + amd_print("Driver Version: 2.8"); + amd_print("South Bridge: %s", bmide_dev->name); pci_read_config_byte(dev, PCI_REVISION_ID, &t); amd_print("Revision: IDE %#x", t); @@ -389,8 +390,8 @@ unsigned int __init pci_init_amd74xx(struct pci_dev *dev, const char *name) */ pci_read_config_byte(dev, PCI_REVISION_ID, &t); - printk(KERN_INFO "AMD_IDE: AMD-%s (rev %02x) IDE %s controller on pci%s\n", - amd_config->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name); + printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n", + dev->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name); /* * Register /proc/ide/amd74xx entry diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index f218a1916a17..5f598354bd6a 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -106,40 +106,51 @@ static int lba_capacity_is_ok (struct hd_driveid *id) return 0; /* lba_capacity value may be bad */ } -static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); -static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); -static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block); +static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block); /* - * do_rw_disk() issues READ and WRITE commands to a disk, - * using LBA if supported, or CHS otherwise, to address sectors. - * It also takes care of issuing special DRIVE_CMDs. + * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS + * otherwise, to address sectors. It also takes care of issuing special + * DRIVE_CMDs. */ -static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) { - if (drive->blocked) - panic("ide: Request while drive blocked? You don't like your data intact?"); + /* + * Wait until all request have bin finished. + */ + + while (drive->blocked) { + yield(); + // panic("ide: Request while drive blocked?"); + } + if (!(rq->flags & REQ_CMD)) { - blk_dump_rq_flags(rq, "do_rw_disk, bad command"); + blk_dump_rq_flags(rq, "idedisk_do_request - bad command"); ide_end_request(drive, 0); return ide_stopped; } if (IS_PDC4030_DRIVE) { extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long); + return promise_rw_disk(drive, rq, block); } - if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) /* 48-bit LBA */ - return lba_48_rw_disk(drive, rq, block); - if (drive->select.b.lba) /* 28-bit LBA */ - return lba_28_rw_disk(drive, rq, block); + /* 48-bit LBA */ + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) + return lba48_do_request(drive, rq, block); + + /* 28-bit LBA */ + if (drive->select.b.lba) + return lba28_do_request(drive, rq, block); - /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */ - return chs_rw_disk(drive, rq, block); + /* 28-bit CHS */ + return chs_do_request(drive, rq, block); } -static task_ioreg_t get_command (ide_drive_t *drive, int cmd) +static task_ioreg_t get_command(ide_drive_t *drive, int cmd) { int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; @@ -147,23 +158,25 @@ static task_ioreg_t get_command (ide_drive_t *drive, int cmd) lba48bit = drive->addressing; #endif - if ((cmd == READ) && (drive->using_dma)) - return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA; - else if ((cmd == READ) && (drive->mult_count)) - return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD; - else if (cmd == READ) - return (lba48bit) ? WIN_READ_EXT : WIN_READ; - else if ((cmd == WRITE) && (drive->using_dma)) - return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; - else if ((cmd == WRITE) && (drive->mult_count)) - return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; - else if (cmd == WRITE) - return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE; - else - return WIN_NOP; + if (cmd == READ) { + if (drive->using_dma) + return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA; + else if (drive->mult_count) + return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD; + else + return (lba48bit) ? WIN_READ_EXT : WIN_READ; + } else if (cmd == WRITE) { + if (drive->using_dma) + return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + else if (drive->mult_count) + return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; + else + return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE; + } + return WIN_NOP; } -static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; @@ -203,19 +216,15 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = NULL; - rq->special = (ide_task_t *)&args; + ide_cmd_type_parser(&args); + args.rq = rq; + args.block = block; + rq->special = &args; return do_rw_taskfile(drive, &args); } -static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; @@ -250,14 +259,10 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = NULL; - rq->special = (ide_task_t *)&args; + ide_cmd_type_parser(&args); + args.rq = rq; + args.block = block; + rq->special = &args; return do_rw_taskfile(drive, &args); } @@ -268,7 +273,7 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u * 1073741822 == 549756 MB or 48bit addressing fake drive */ -static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block) +static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; @@ -314,13 +319,10 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = (ide_task_t *)&args; + ide_cmd_type_parser(&args); + args.rq = rq; + args.block = block; + rq->special = &args; return do_rw_taskfile(drive, &args); } @@ -637,9 +639,9 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive) taskfile.high_cylinder = drive->cyl>>8; taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF; if (!IS_PDC4030_DRIVE) { - taskfile.sector_count = drive->sect; - taskfile.command = WIN_SPECIFY; - handler = ide_handler_parser(&taskfile, &hobfile); + taskfile.sector_count = drive->sect; + taskfile.command = WIN_SPECIFY; + handler = set_geometry_intr;; } do_taskfile(drive, &taskfile, &hobfile, handler); } else if (s->b.recalibrate) { @@ -651,7 +653,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive) memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.sector_count = drive->sect; taskfile.command = WIN_RESTORE; - do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + do_taskfile(drive, &taskfile, &hobfile, recal_intr); } } else if (s->b.set_multmode) { s->b.set_multmode = 0; @@ -1089,7 +1091,7 @@ static struct ata_operations idedisk_driver = { owner: THIS_MODULE, cleanup: idedisk_cleanup, standby: idedisk_standby, - do_request: do_rw_disk, + do_request: idedisk_do_request, end_request: NULL, ioctl: NULL, open: idedisk_open, @@ -1127,7 +1129,7 @@ int idedisk_init (void) { ide_drive_t *drive; int failed = 0; - + MOD_INC_USE_COUNT; while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", NULL, failed++)) != NULL) { if (ide_register_subdriver (drive, &idedisk_driver)) { diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index a1f65de568f5..d8c32aca8a7b 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -119,6 +119,7 @@ extern void ide_init_pdc202xx(ide_hwif_t *); extern unsigned int pci_init_piix(struct pci_dev *); extern unsigned int ata66_piix(ide_hwif_t *); extern void ide_init_piix(ide_hwif_t *); +extern void ide_dmacapable_piix(ide_hwif_t *, unsigned long); #endif #ifdef CONFIG_BLK_DEV_IT8172 @@ -142,12 +143,6 @@ extern unsigned int ata66_sis5513(ide_hwif_t *); extern void ide_init_sis5513(ide_hwif_t *); #endif -#ifdef CONFIG_BLK_DEV_SLC90E66 -extern unsigned int pci_init_slc90e66(struct pci_dev *); -extern unsigned int ata66_slc90e66(ide_hwif_t *); -extern void ide_init_slc90e66(ide_hwif_t *); -#endif - #ifdef CONFIG_BLK_DEV_SL82C105 extern unsigned int pci_init_sl82c105(struct pci_dev *); extern void dma_init_sl82c105(ide_hwif_t *, unsigned long); @@ -197,19 +192,18 @@ typedef struct ide_pci_device_s { static ide_pci_device_t pci_chipsets[] __initdata = { #ifdef CONFIG_BLK_DEV_PIIX - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, NULL, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, NULL, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, NULL, NULL, ide_init_piix, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0, ATA_F_NODMA }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, ATA_F_NOADMA }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, #endif #ifdef CONFIG_BLK_DEV_VIA82CXXX {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA }, @@ -289,13 +283,11 @@ static ide_pci_device_t pci_chipsets[] __initdata = { {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x50,0x01,0x01}, {0x50,0x02,0x02}}, ON_BOARD, 0, 0 }, #endif #ifdef CONFIG_BLK_DEV_PDC_ADMA {PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, pci_init_pdcadma, ata66_pdcadma, ide_init_pdcadma, ide_dmacapable_pdcadma, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_NODMA }, #endif -#ifdef CONFIG_BLK_DEV_SLC90E66 - {PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_slc90e66, ata66_slc90e66, ide_init_slc90e66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, -#endif #ifdef CONFIG_BLK_DEV_SVWKS {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, @@ -311,6 +303,7 @@ static ide_pci_device_t pci_chipsets[] __initdata = { {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, NULL, NULL, NULL, NULL, {{0x6D,0x80,0x80}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_NODMA }, {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 0891bcc1e2c4..83f517e2ae5c 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -118,10 +118,6 @@ int (*svwks_display_info)(char *, char **, off_t, int) = NULL; extern byte sis_proc; int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ -#ifdef CONFIG_BLK_DEV_SLC90E66 -extern byte slc90e66_proc; -int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL; -#endif /* CONFIG_BLK_DEV_SLC90E66 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; int (*via_display_info)(char *, char **, off_t, int) = NULL; @@ -593,10 +589,6 @@ void proc_ide_create(void) if ((sis_display_info) && (sis_proc)) create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info); #endif /* CONFIG_BLK_DEV_SIS5513 */ -#ifdef CONFIG_BLK_DEV_SLC90E66 - if ((slc90e66_display_info) && (slc90e66_proc)) - create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info); -#endif /* CONFIG_BLK_DEV_SLC90E66 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX if ((via_display_info) && (via_proc)) create_proc_info_entry("via", 0, proc_ide_root, via_display_info); @@ -653,10 +645,6 @@ void proc_ide_destroy(void) if ((sis_display_info) && (sis_proc)) remove_proc_entry("ide/sis", 0); #endif /* CONFIG_BLK_DEV_SIS5513 */ -#ifdef CONFIG_BLK_DEV_SLC90E66 - if ((slc90e66_display_info) && (slc90e66_proc)) - remove_proc_entry("ide/slc90e66",0); -#endif /* CONFIG_BLK_DEV_SLC90E66 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX if ((via_display_info) && (via_proc)) remove_proc_entry("ide/via",0); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 138d5e7fdae7..29ccab91a897 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -38,6 +38,8 @@ #define DTF(x...) #endif +#define SUPPORT_VLB_SYNC 1 + /* * for now, taskfile requests are special :/ */ @@ -56,7 +58,7 @@ static inline void ide_unmap_rq(struct request *rq, char *to, bio_kunmap_irq(to, flags); } -static void ata_bswap_data (void *buffer, int wcount) +static void bswap_data (void *buffer, int wcount) { u16 *p = buffer; @@ -74,18 +76,20 @@ static void ata_bswap_data (void *buffer, int wcount) * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */ -static inline void task_vlb_sync(ide_ioreg_t port) +static inline void task_vlb_sync(ide_drive_t *drive) { - IN_BYTE (port); - IN_BYTE (port); - IN_BYTE (port); + ide_ioreg_t port = IDE_NSECTOR_REG; + + IN_BYTE(port); + IN_BYTE(port); + IN_BYTE(port); } #endif /* * This is used for most PIO data transfers *from* the IDE interface */ -void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void ata_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount) { byte io_32bit; @@ -107,7 +111,7 @@ void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) unsigned long flags; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - task_vlb_sync(IDE_NSECTOR_REG); + task_vlb_sync(drive); insl(IDE_DATA_REG, buffer, wcount); __restore_flags(flags); /* local CPU only */ } else @@ -130,7 +134,7 @@ void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) /* * This is used for most PIO data transfers *to* the IDE interface */ -void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount) { byte io_32bit; @@ -147,7 +151,7 @@ void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) unsigned long flags; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - task_vlb_sync(IDE_NSECTOR_REG); + task_vlb_sync(drive); outsl(IDE_DATA_REG, buffer, wcount); __restore_flags(flags); /* local CPU only */ } else @@ -188,7 +192,7 @@ void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; } -#endif /* CONFIG_ATARI */ +#endif ata_input_data (drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); @@ -208,25 +212,25 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; } -#endif /* CONFIG_ATARI */ +#endif ata_output_data (drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) - outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); + outsw(IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); } -void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void taskfile_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount) { ata_input_data(drive, buffer, wcount); if (drive->bswap) - ata_bswap_data(buffer, wcount); + bswap_data(buffer, wcount); } -void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void taskfile_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount) { if (drive->bswap) { - ata_bswap_data(buffer, wcount); + bswap_data(buffer, wcount); ata_output_data(drive, buffer, wcount); - ata_bswap_data(buffer, wcount); + bswap_data(buffer, wcount); } else { ata_output_data(drive, buffer, wcount); } @@ -235,7 +239,7 @@ void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount /* * Needed for PCI irq sharing */ -int drive_is_ready (ide_drive_t *drive) +int drive_is_ready(ide_drive_t *drive) { byte stat = 0; if (drive->waiting_for_dma) @@ -255,7 +259,7 @@ int drive_is_ready (ide_drive_t *drive) if (IDE_CONTROL_REG) stat = GET_ALTSTAT(); else -#endif /* CONFIG_IDEPCI_SHARE_IRQ */ +#endif stat = GET_STAT(); /* Note: this may clear a pending IRQ!! */ if (stat & BUSY_STAT) @@ -291,7 +295,7 @@ static ide_startstop_t bio_mulout_intr(ide_drive_t *drive); * Called directly from execute_drive_cmd for the first bunch of sectors, * afterwards only by the ISR */ -static ide_startstop_t task_mulout_intr (ide_drive_t *drive) +static ide_startstop_t task_mulout_intr(ide_drive_t *drive) { unsigned int msect, nsect; byte stat = GET_STAT(); @@ -314,6 +318,7 @@ static ide_startstop_t task_mulout_intr (ide_drive_t *drive) * necessary */ ide_end_request(drive, 1); + return ide_stopped; } @@ -341,13 +346,14 @@ static ide_startstop_t task_mulout_intr (ide_drive_t *drive) ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; + /* Are we sure that this as all been already transfered? */ rq->current_nr_sectors -= nsect; if (hwgroup->handler == NULL) ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); return ide_started; } -ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task) { task_struct_t *taskfile = (task_struct_t *) task->tfRegister; hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; @@ -399,7 +405,9 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) return ide_started; } -void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler) +void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, + struct hd_drive_hob_hdr *hobfile, + ide_handler_t *handler) { struct hd_driveid *id = drive->id; byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; @@ -440,10 +448,6 @@ void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct } /* - * Handler for special commands without a data phase from ide-disk - */ - -/* * This is invoked on completion of a WIN_SETMULT cmd. */ ide_startstop_t set_multmode_intr (ide_drive_t *drive) @@ -463,7 +467,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive) /* * This is invoked on completion of a WIN_SPECIFY cmd. */ -static ide_startstop_t set_geometry_intr (ide_drive_t *drive) +ide_startstop_t set_geometry_intr (ide_drive_t *drive) { byte stat; @@ -480,7 +484,7 @@ static ide_startstop_t set_geometry_intr (ide_drive_t *drive) /* * This is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ -static ide_startstop_t recal_intr (ide_drive_t *drive) +ide_startstop_t recal_intr(ide_drive_t *drive) { byte stat = GET_STAT(); @@ -713,37 +717,6 @@ static ide_startstop_t bio_mulout_intr (ide_drive_t *drive) return ide_started; } -/* Called by internal to feature out type of command being called */ -ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) -{ - switch(taskfile->command) { - /* IDE_DRIVE_TASK_RAW_WRITE */ - /* IDE_DRIVE_TASK_OUT */ - case WIN_WRITE: - case WIN_WRITE_EXT: - case WIN_WRITE_VERIFY: - case WIN_WRITE_BUFFER: - case CFA_WRITE_SECT_WO_ERASE: - case WIN_DOWNLOAD_MICROCODE: - return &pre_task_out_intr; - case CFA_WRITE_MULTI_WO_ERASE: - case WIN_MULTWRITE: - case WIN_MULTWRITE_EXT: - return &pre_bio_out_intr; - case WIN_SMART: - if (taskfile->feature == SMART_WRITE_LOG_SECTOR) - return &pre_task_out_intr; - case WIN_WRITEDMA: - case WIN_WRITEDMA_QUEUED: - case WIN_WRITEDMA_EXT: - case WIN_WRITEDMA_QUEUED_EXT: - /* IDE_DRIVE_TASK_OUT */ - default: - break; - } - return(NULL); -} - /* * Handler for command with Read Multiple */ @@ -798,154 +771,85 @@ static ide_startstop_t task_mulin_intr(ide_drive_t *drive) return ide_started; } -/* Called by internal to feature out type of command being called */ -ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) -{ - switch(taskfile->command) { - case WIN_IDENTIFY: - case WIN_PIDENTIFY: - case CFA_TRANSLATE_SECTOR: - case WIN_READ_BUFFER: - case WIN_READ: - case WIN_READ_EXT: - return &task_in_intr; - case WIN_SECURITY_DISABLE: - case WIN_SECURITY_ERASE_UNIT: - case WIN_SECURITY_SET_PASS: - case WIN_SECURITY_UNLOCK: - case WIN_DOWNLOAD_MICROCODE: - case CFA_WRITE_SECT_WO_ERASE: - case WIN_WRITE_BUFFER: - case WIN_WRITE_VERIFY: - case WIN_WRITE: - case WIN_WRITE_EXT: - return &task_out_intr; - case WIN_MULTREAD: - case WIN_MULTREAD_EXT: - return &task_mulin_intr; - case CFA_WRITE_MULTI_WO_ERASE: - case WIN_MULTWRITE: - case WIN_MULTWRITE_EXT: - return &bio_mulout_intr; - case WIN_SMART: - switch(taskfile->feature) { - case SMART_READ_VALUES: - case SMART_READ_THRESHOLDS: - case SMART_READ_LOG_SECTOR: - return &task_in_intr; - case SMART_WRITE_LOG_SECTOR: - return &task_out_intr; - default: - return &task_no_data_intr; - } - case CFA_REQ_EXT_ERROR_CODE: - case CFA_ERASE_SECTORS: - case WIN_VERIFY: - case WIN_VERIFY_EXT: - case WIN_SEEK: - return &task_no_data_intr; - case WIN_SPECIFY: - return &set_geometry_intr; - case WIN_RESTORE: - return &recal_intr; - case WIN_DIAGNOSE: - case WIN_FLUSH_CACHE: - case WIN_FLUSH_CACHE_EXT: - case WIN_STANDBYNOW1: - case WIN_STANDBYNOW2: - case WIN_SLEEPNOW1: - case WIN_SLEEPNOW2: - case WIN_SETIDLE1: - case WIN_CHECKPOWERMODE1: - case WIN_CHECKPOWERMODE2: - case WIN_GETMEDIASTATUS: - case WIN_MEDIAEJECT: - return &task_no_data_intr; - case WIN_SETMULT: - return &set_multmode_intr; - case WIN_READ_NATIVE_MAX: - case WIN_SET_MAX: - case WIN_READ_NATIVE_MAX_EXT: - case WIN_SET_MAX_EXT: - case WIN_SECURITY_ERASE_PREPARE: - case WIN_SECURITY_FREEZE_LOCK: - case WIN_DOORLOCK: - case WIN_DOORUNLOCK: - case WIN_SETFEATURES: - return &task_no_data_intr; - case DISABLE_SEAGATE: - case EXABYTE_ENABLE_NEST: - return &task_no_data_intr; -#ifdef CONFIG_BLK_DEV_IDEDMA - case WIN_READDMA: - case WIN_IDENTIFY_DMA: - case WIN_READDMA_QUEUED: - case WIN_READDMA_EXT: - case WIN_READDMA_QUEUED_EXT: - case WIN_WRITEDMA: - case WIN_WRITEDMA_QUEUED: - case WIN_WRITEDMA_EXT: - case WIN_WRITEDMA_QUEUED_EXT: -#endif - case WIN_FORMAT: - case WIN_INIT: - case WIN_DEVICE_RESET: - case WIN_QUEUED_SERVICE: - case WIN_PACKETCMD: - default: - return NULL; - } -} - /* Called by ioctl to feature out type of command being called */ -int ide_cmd_type_parser (ide_task_t *args) +void ide_cmd_type_parser(ide_task_t *args) { struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister; - struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister; - args->prehandler = ide_pre_handler_parser(taskfile, hobfile); - args->handler = ide_handler_parser(taskfile, hobfile); + args->prehandler = NULL; + args->handler = NULL; switch(args->tfRegister[IDE_COMMAND_OFFSET]) { case WIN_IDENTIFY: case WIN_PIDENTIFY: - return IDE_DRIVE_TASK_IN; + args->handler = task_in_intr; + args->command_type = IDE_DRIVE_TASK_IN; + return; + case CFA_TRANSLATE_SECTOR: case WIN_READ: case WIN_READ_EXT: case WIN_READ_BUFFER: - return IDE_DRIVE_TASK_IN; + args->handler = task_in_intr; + args->command_type = IDE_DRIVE_TASK_IN; + return; + case WIN_WRITE: case WIN_WRITE_EXT: case WIN_WRITE_VERIFY: case WIN_WRITE_BUFFER: case CFA_WRITE_SECT_WO_ERASE: case WIN_DOWNLOAD_MICROCODE: - return IDE_DRIVE_TASK_RAW_WRITE; + args->prehandler = pre_task_out_intr; + args->handler = task_out_intr; + args->command_type = IDE_DRIVE_TASK_RAW_WRITE; + return; + case WIN_MULTREAD: case WIN_MULTREAD_EXT: - return IDE_DRIVE_TASK_IN; + args->handler = task_mulin_intr; + args->command_type = IDE_DRIVE_TASK_IN; + return; + case CFA_WRITE_MULTI_WO_ERASE: case WIN_MULTWRITE: case WIN_MULTWRITE_EXT: - return IDE_DRIVE_TASK_RAW_WRITE; + args->prehandler = pre_bio_out_intr; + args->handler = bio_mulout_intr; + args->command_type = IDE_DRIVE_TASK_RAW_WRITE; + return; + case WIN_SECURITY_DISABLE: case WIN_SECURITY_ERASE_UNIT: case WIN_SECURITY_SET_PASS: case WIN_SECURITY_UNLOCK: - return IDE_DRIVE_TASK_OUT; + args->handler = task_out_intr; + args->command_type = IDE_DRIVE_TASK_OUT; + return; + case WIN_SMART: + if (taskfile->feature == SMART_WRITE_LOG_SECTOR) + args->prehandler = pre_task_out_intr; args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; switch(args->tfRegister[IDE_FEATURE_OFFSET]) { case SMART_READ_VALUES: case SMART_READ_THRESHOLDS: case SMART_READ_LOG_SECTOR: - return IDE_DRIVE_TASK_IN; + args->handler = task_in_intr; + args->command_type = IDE_DRIVE_TASK_IN; + return; + case SMART_WRITE_LOG_SECTOR: - return IDE_DRIVE_TASK_OUT; + args->handler = task_out_intr; + args->command_type = IDE_DRIVE_TASK_OUT; + return; + default: - return IDE_DRIVE_TASK_NO_DATA; + args->handler = task_no_data_intr; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + } #ifdef CONFIG_BLK_DEV_IDEDMA case WIN_READDMA: @@ -953,17 +857,23 @@ int ide_cmd_type_parser (ide_task_t *args) case WIN_READDMA_QUEUED: case WIN_READDMA_EXT: case WIN_READDMA_QUEUED_EXT: - return IDE_DRIVE_TASK_IN; + args->command_type = IDE_DRIVE_TASK_IN; + return; + case WIN_WRITEDMA: case WIN_WRITEDMA_QUEUED: case WIN_WRITEDMA_EXT: case WIN_WRITEDMA_QUEUED_EXT: - return IDE_DRIVE_TASK_RAW_WRITE; + args->command_type = IDE_DRIVE_TASK_RAW_WRITE; + return; + #endif case WIN_SETFEATURES: + args->handler = task_no_data_intr; switch(args->tfRegister[IDE_FEATURE_OFFSET]) { case SETFEATURES_XFER: - return IDE_DRIVE_TASK_SET_XFER; + args->command_type = IDE_DRIVE_TASK_SET_XFER; + return; case SETFEATURES_DIS_DEFECT: case SETFEATURES_EN_APM: case SETFEATURES_DIS_MSN: @@ -980,16 +890,20 @@ int ide_cmd_type_parser (ide_task_t *args) case SETFEATURES_DIS_RI: case SETFEATURES_DIS_SI: default: - return IDE_DRIVE_TASK_NO_DATA; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; } - case WIN_NOP: - case CFA_REQ_EXT_ERROR_CODE: - case CFA_ERASE_SECTORS: - case WIN_VERIFY: - case WIN_VERIFY_EXT: - case WIN_SEEK: + case WIN_SPECIFY: + args->handler = set_geometry_intr; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + case WIN_RESTORE: + args->handler = recal_intr; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + case WIN_DIAGNOSE: case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: @@ -998,29 +912,48 @@ int ide_cmd_type_parser (ide_task_t *args) case WIN_SLEEPNOW1: case WIN_SLEEPNOW2: case WIN_SETIDLE1: - case DISABLE_SEAGATE: case WIN_CHECKPOWERMODE1: case WIN_CHECKPOWERMODE2: case WIN_GETMEDIASTATUS: case WIN_MEDIAEJECT: - case WIN_SETMULT: + case CFA_REQ_EXT_ERROR_CODE: + case CFA_ERASE_SECTORS: + case WIN_VERIFY: + case WIN_VERIFY_EXT: + case WIN_SEEK: case WIN_READ_NATIVE_MAX: case WIN_SET_MAX: case WIN_READ_NATIVE_MAX_EXT: case WIN_SET_MAX_EXT: case WIN_SECURITY_ERASE_PREPARE: case WIN_SECURITY_FREEZE_LOCK: - case EXABYTE_ENABLE_NEST: case WIN_DOORLOCK: case WIN_DOORUNLOCK: - return IDE_DRIVE_TASK_NO_DATA; + case DISABLE_SEAGATE: + case EXABYTE_ENABLE_NEST: + + args->handler = task_no_data_intr; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + + case WIN_SETMULT: + args->handler = set_multmode_intr; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + + case WIN_NOP: + + args->command_type = IDE_DRIVE_TASK_NO_DATA; + return; + case WIN_FORMAT: case WIN_INIT: case WIN_DEVICE_RESET: case WIN_QUEUED_SERVICE: case WIN_PACKETCMD: default: - return IDE_DRIVE_TASK_INVALID; + args->command_type = IDE_DRIVE_TASK_INVALID; + return; } } @@ -1067,7 +1000,7 @@ int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, st ide_init_drive_taskfile(&rq); /* This is kept for internal use only !!! */ - args.command_type = ide_cmd_type_parser (&args); + ide_cmd_type_parser(&args); if (args.command_type != IDE_DRIVE_TASK_NO_DATA) rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count; @@ -1232,14 +1165,13 @@ EXPORT_SYMBOL(taskfile_output_data); EXPORT_SYMBOL(do_rw_taskfile); EXPORT_SYMBOL(do_taskfile); +EXPORT_SYMBOL(recal_intr); +EXPORT_SYMBOL(set_geometry_intr); EXPORT_SYMBOL(set_multmode_intr); - EXPORT_SYMBOL(task_no_data_intr); EXPORT_SYMBOL(ide_wait_taskfile); EXPORT_SYMBOL(ide_raw_taskfile); -EXPORT_SYMBOL(ide_pre_handler_parser); -EXPORT_SYMBOL(ide_handler_parser); EXPORT_SYMBOL(ide_cmd_type_parser); EXPORT_SYMBOL(ide_cmd_ioctl); EXPORT_SYMBOL(ide_task_ioctl); diff --git a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c index 16758e96f042..04e6ad2871bd 100644 --- a/drivers/ide/pdc4030.c +++ b/drivers/ide/pdc4030.c @@ -654,14 +654,14 @@ ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigne memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); + ide_cmd_type_parser(&args); + /* We don't use the generic inerrupt handlers here? */ args.prehandler = NULL; args.handler = NULL; - args.posthandler = NULL; - args.rq = (struct request *) rq; + args.rq = rq; args.block = block; rq->special = NULL; - rq->special = (ide_task_t *)&args; + rq->special = &args; return do_pdc4030_io(drive, &args); } diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index de7f2e74d32e..384ea0b2380a 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -1,499 +1,578 @@ /* - * linux/drivers/ide/piix.c Version 0.32 June 9, 2000 + * $Id: piix.c,v 1.2 2002/03/13 22:50:43 vojtech Exp $ * - * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * May be copied or modified under the terms of the GNU General Public License + * Copyright (c) 2000-2002 Vojtech Pavlik * - * PIO mode setting function for Intel chipsets. - * For use instead of BIOS settings. + * Based on the work of: + * Andrzej Krzysztofowicz + * Andre Hedrick * - * 40-41 - * 42-43 - * - * 41 - * 43 - * - * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0); - * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2); - * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3); - * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4); - * - * sitre = word40 & 0x4000; primary - * sitre = word42 & 0x4000; secondary - * - * 44 8421|8421 hdd|hdb - * - * 48 8421 hdd|hdc|hdb|hda udma enabled - * - * 0001 hda - * 0010 hdb - * 0100 hdc - * 1000 hdd - * - * 4a 84|21 hdb|hda - * 4b 84|21 hdd|hdc + * Thanks to Daniela Egbert for advice on PIIX bugs. + */ + +/* + * Intel PIIX/ICH and Efar Victory66 IDE driver for Linux. * - * ata-33/82371AB - * ata-33/82371EB - * ata-33/82801AB ata-66/82801AA - * 00|00 udma 0 00|00 reserved - * 01|01 udma 1 01|01 udma 3 - * 10|10 udma 2 10|10 udma 4 - * 11|11 reserved 11|11 reserved + * UDMA66 and higher modes are autoenabled only in case the BIOS has detected a + * 80 wire cable. To ignore the BIOS data and assume the cable is present, use + * 'ide0=ata66' or 'ide1=ata66' on the kernel command line. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * 54 8421|8421 ata66 drive|ata66 enable + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include <linux/config.h> -#include <linux/types.h> #include <linux/kernel.h> #include <linux/ioport.h> +#include <linux/blkdev.h> #include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> #include <linux/init.h> - +#include <linux/ide.h> #include <asm/io.h> #include "ata-timing.h" -#define PIIX_DEBUG_DRIVE_INFO 0 +#define PIIX_IDETIM0 0x40 +#define PIIX_IDETIM1 0x42 +#define PIIX_SIDETIM 0x44 +#define PIIX_IDESTAT 0x47 +#define PIIX_UDMACTL 0x48 +#define PIIX_UDMATIM 0x4a +#define PIIX_IDECFG 0x54 + +#define PIIX_UDMA 0x07 +#define PIIX_UDMA_NONE 0x00 +#define PIIX_UDMA_33 0x01 +#define PIIX_UDMA_66 0x02 +#define PIIX_UDMA_V66 0x03 +#define PIIX_UDMA_100 0x04 +#define PIIX_NO_SITRE 0x08 /* Chip doesn't have separate slave timing */ +#define PIIX_PINGPONG 0x10 /* Enable ping-pong buffers */ +#define PIIX_VICTORY 0x20 /* Efar Victory66 has a different UDMA setup */ +#define PIIX_CHECK_REV 0x40 /* May be a buggy revision of PIIX */ +#define PIIX_NODMA 0x80 /* Don't do DMA with this chip */ + +/* + * Intel IDE chips + */ + +static struct piix_ide_chip { + unsigned short id; + unsigned char flags; +} piix_ide_chips[] = { + { PCI_DEVICE_ID_INTEL_82801CA_11, PIIX_UDMA_100 | PIIX_PINGPONG }, /* Intel 82801CA ICH3 */ + { PCI_DEVICE_ID_INTEL_82801CA_10, PIIX_UDMA_100 | PIIX_PINGPONG }, /* Intel 82801CAM ICH3-M */ + { PCI_DEVICE_ID_INTEL_82801BA_9, PIIX_UDMA_100 | PIIX_PINGPONG }, /* Intel 82801BA ICH2 */ + { PCI_DEVICE_ID_INTEL_82801BA_8, PIIX_UDMA_100 | PIIX_PINGPONG }, /* Intel 82801BAM ICH2-M */ + { PCI_DEVICE_ID_INTEL_82801AB_1, PIIX_UDMA_33 | PIIX_PINGPONG }, /* Intel 82801AB ICH0 */ + { PCI_DEVICE_ID_INTEL_82801AA_1, PIIX_UDMA_66 | PIIX_PINGPONG }, /* Intel 82801AA ICH */ + { PCI_DEVICE_ID_INTEL_82372FB_1, PIIX_UDMA_66 }, /* Intel 82372FB PIIX5 */ + { PCI_DEVICE_ID_INTEL_82443MX_1, PIIX_UDMA_33 }, /* Intel 82443MX MPIIX4 */ + { PCI_DEVICE_ID_INTEL_82371AB, PIIX_UDMA_33 }, /* Intel 82371AB/EB PIIX4/4E */ + { PCI_DEVICE_ID_INTEL_82371SB_1, PIIX_UDMA_NONE }, /* Intel 82371SB PIIX3 */ + { PCI_DEVICE_ID_INTEL_82371FB_1, PIIX_UDMA_NONE | PIIX_NO_SITRE | PIIX_CHECK_REV }, /* Intel 82371FB PIIX */ + { PCI_DEVICE_ID_EFAR_SLC90E66_1, PIIX_UDMA_V66 | PIIX_VICTORY }, /* Efar Victory66 */ + { 0 } +}; + +static struct piix_ide_chip *piix_config; +static unsigned char piix_enabled; +static unsigned int piix_80w; +static unsigned int piix_clock; + +static char *piix_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA66", "UDMA100" }; + +/* + * PIIX/ICH /proc entry. + */ -#define DISPLAY_PIIX_TIMINGS +#ifdef CONFIG_PROC_FS -#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) #include <linux/stat.h> #include <linux/proc_fs.h> -static int piix_get_info(char *, char **, off_t, int); -extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +byte piix_proc; +int piix_base; static struct pci_dev *bmide_dev; +extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */ + +#define piix_print(format, arg...) p += sprintf(p, format "\n" , ## arg) +#define piix_print_drive(name, format, arg...)\ + p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n"); -static int piix_get_info (char *buffer, char **addr, off_t offset, int count) +static int piix_get_info(char *buffer, char **addr, off_t offset, int count) { + int speed[4], cycle[4], active[4], recover[4], dmaen[4], uen[4], udma[4], umul; + struct pci_dev *dev = bmide_dev; + unsigned int i, u; + unsigned short c, d, e; + unsigned char t; char *p = buffer; - u32 bibma = pci_resource_start(bmide_dev, 4); - u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; - u8 c0 = 0, c1 = 0; - u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0; - - if (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371MX) { - p += sprintf(p, "\n Intel MPIIX Chipset.\n"); - return p-buffer; /* => must be less than 4k! */ - } - pci_read_config_word(bmide_dev, 0x40, ®40); - pci_read_config_word(bmide_dev, 0x42, ®42); - pci_read_config_byte(bmide_dev, 0x44, ®44); - pci_read_config_byte(bmide_dev, 0x48, ®48); - pci_read_config_byte(bmide_dev, 0x4a, ®4a); - pci_read_config_byte(bmide_dev, 0x4b, ®4b); - pci_read_config_byte(bmide_dev, 0x54, ®54); - pci_read_config_byte(bmide_dev, 0x55, ®55); - - psitre = (reg40 & 0x4000) ? 1 : 0; - ssitre = (reg42 & 0x4000) ? 1 : 0; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); - - p += sprintf(p, "\n %s Chipset.\n", bmide_dev->name); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", - (reg48&0x01) ? "yes" : "no ", - (reg48&0x02) ? "yes" : "no ", - (reg48&0x04) ? "yes" : "no ", - (reg48&0x08) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", - ((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" : - ((reg54&0x11) && (reg4a&0x02)) ? "4" : - ((reg54&0x11) && (reg4a&0x01)) ? "3" : - (reg4a&0x02) ? "2" : - (reg4a&0x01) ? "1" : - (reg4a&0x00) ? "0" : "X", - ((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" : - ((reg54&0x22) && (reg4a&0x20)) ? "4" : - ((reg54&0x22) && (reg4a&0x10)) ? "3" : - (reg4a&0x20) ? "2" : - (reg4a&0x10) ? "1" : - (reg4a&0x00) ? "0" : "X", - ((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" : - ((reg54&0x44) && (reg4b&0x02)) ? "4" : - ((reg54&0x44) && (reg4b&0x01)) ? "3" : - (reg4b&0x02) ? "2" : - (reg4b&0x01) ? "1" : - (reg4b&0x00) ? "0" : "X", - ((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" : - ((reg54&0x88) && (reg4b&0x20)) ? "4" : - ((reg54&0x88) && (reg4b&0x10)) ? "3" : - (reg4b&0x20) ? "2" : - (reg4b&0x10) ? "1" : - (reg4b&0x00) ? "0" : "X"); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); + piix_print("----------PIIX BusMastering IDE Configuration---------------"); -/* - * FIXME.... Add configuration junk data....blah blah...... - */ + piix_print("Driver Version: 1.2"); + piix_print("South Bridge: %s", bmide_dev->name); - return p-buffer; /* => must be less than 4k! */ -} -#endif /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */ + pci_read_config_byte(dev, PCI_REVISION_ID, &t); + piix_print("Revision: IDE %#x", t); + piix_print("Highest DMA rate: %s", piix_config->flags & PIIX_NODMA ? "No DMA" + : piix_dma[piix_config->flags & PIIX_UDMA]); -/* - * Used to set Fifo configuration via kernel command line: - */ + piix_print("BM-DMA base: %#x", piix_base); + piix_print("PCI clock: %d.%dMHz", piix_clock / 1000, piix_clock / 100 % 10); -byte piix_proc = 0; + piix_print("-----------------------Primary IDE-------Secondary IDE------"); -extern char *ide_xfer_verbose (byte xfer_rate); + pci_read_config_word(dev, PIIX_IDETIM0, &d); + pci_read_config_word(dev, PIIX_IDETIM1, &e); + piix_print("Enabled: %10s%20s", (d & 0x8000) ? "yes" : "no", (e & 0x8000) ? "yes" : "no"); -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) -/* - * - */ -static byte piix_dma_2_pio (byte xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; + c = inb(piix_base + 0x02) | (inb(piix_base + 0x0a) << 8); + piix_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no"); + + piix_print("Cable Type: %10s%20s", (piix_80w & 1) ? "80w" : "40w", (piix_80w & 2) ? "80w" : "40w"); + + if (!piix_clock) + return p - buffer; + + piix_print("-------------------drive0----drive1----drive2----drive3-----"); + + piix_print_drive("Prefetch+Post: ", "%10s", (((i & 2) ? d : e) & (1 << (2 + ((i & 1) << 2)))) ? "yes" : "no"); + + for (i = 0; i < 4; i++) { + + pci_read_config_word(dev, PIIX_IDETIM0 + (i & 2), &d); + if (~piix_config->flags & PIIX_NO_SITRE) + pci_read_config_byte(dev, PIIX_SIDETIM, &t); + + umul = 4; + udma[i] = uen[i] = 0; + active[i] = 12; + recover[i] = 18; + + switch (i & 1) { + case 1: if (~d & 0x10) break; + if ((~piix_config->flags & PIIX_NO_SITRE) && (d & 0x4000)) { + active[i] = 5 - ((t >> (((i & 2) << 1) + 2)) & 3); + recover[i] = 4 - ((t >> (((i & 2) << 1) + 0)) & 3); + break; + } + + case 0: if (~d & 0x01) break; + active[i] = 5 - ((d >> 12) & 3); + recover[i] = 4 - ((d >> 8) & 3); + } + + dmaen[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)); + cycle[i] = 1000000 / piix_clock * (active[i] + recover[i]); + speed[i] = 2 * piix_clock / (active[i] + recover[i]); + + if (!(piix_config->flags & PIIX_UDMA)) + continue; + + pci_read_config_byte(dev, PIIX_UDMACTL, &t); + uen[i] = (t & (1 << i)) ? dmaen[i] : 0; + + if (!uen[i]) + continue; + + pci_read_config_word(dev, PIIX_UDMATIM, &e); + pci_read_config_dword(dev, PIIX_IDECFG, &u); + + if (~piix_config->flags & PIIX_VICTORY) { + if ((piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 && (u & (1 << i))) umul = 2; + if ((piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 && (u & ((1 << i) + 12))) umul = 1; + udma[i] = (4 - ((e >> (i << 2)) & 3)) * umul; + } else udma[i] = (8 - ((e >> (i << 2)) & 7)) * 2; + + speed[i] = 8 * piix_clock / udma[i]; + cycle[i] = 250000 * udma[i] / piix_clock; } + + piix_print_drive("Transfer Mode: ", "%10s", dmaen[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO"); + + piix_print_drive("Address Setup: ", "%8dns", (1000000 / piix_clock) * 3); + piix_print_drive("Cmd Active: ", "%8dns", (1000000 / piix_clock) * 12); + piix_print_drive("Cmd Recovery: ", "%8dns", (1000000 / piix_clock) * 18); + piix_print_drive("Data Active: ", "%8dns", (1000000 / piix_clock) * active[i]); + piix_print_drive("Data Recovery: ", "%8dns", (1000000 / piix_clock) * recover[i]); + piix_print_drive("Cycle Time: ", "%8dns", cycle[i]); + piix_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10); + + return p - buffer; /* hoping it is less than 4K... */ } -#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ + +#endif /* - * Based on settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). + * piix_set_speed() writes timing values to the chipset registers */ -static void piix_tune_drive (ide_drive_t *drive, byte pio) -{ - unsigned long flags; - u16 master_data; - u8 slave_data; - int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = HWIF(drive)->index ? 0x42 : 0x40; - int slave_port = 0x44; - /* ISP RTC */ - byte timings[][2] = { { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - if (pio == 255) - pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; - else - pio = min_t(byte, pio, 4); - - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); - if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; - pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); - slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) - << (HWIF(drive)->index ? 4 : 0)); - } else { - master_data = master_data & 0xccf8; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | - (timings[pio][1] << 8); - } - save_flags(flags); - cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); - restore_flags(flags); -} -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) -static int piix_tune_chipset (ide_drive_t *drive, byte speed) +static void piix_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing, int umul) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - byte maslave = hwif->channel ? 0x42 : 0x40; - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int v_flag = 0x01 << drive->dn; - int w_flag = 0x10 << drive->dn; - int u_speed = 0; - int err = 0; - int sitre; - short reg4042, reg44, reg48, reg4a, reg54; - byte reg55; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_word(dev, 0x54, ®54); - pci_read_config_byte(dev, 0x55, ®55); - - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; - default: return -1; + unsigned short t; + unsigned char u; + unsigned int c; + + pci_read_config_word(dev, PIIX_IDETIM0 + (dn & 2), &t); + + switch (dn & 1) { + + case 1: + if (timing->cycle > 9) { + t &= ~0x30; + break; + } + + if (~piix_config->flags & PIIX_NO_SITRE) { + pci_read_config_byte(dev, PIIX_SIDETIM, &u); + u &= ~(0xf << ((dn & 2) << 1)); + t |= 0x30; + u |= (4 - FIT(timing->recover, 1, 4)) << ((dn & 2) << 1); + u |= (5 - FIT(timing->active, 2, 5)) << (((dn & 2) << 1) + 2); + pci_write_config_byte(dev, PIIX_SIDETIM, u); + break; + } + + case 0: + if ((~dn & 1) && timing->cycle > 9) { + t &= ~0x03; + break; + } + + t &= 0xccff; + t |= 0x03 << ((dn & 1) << 2); + t |= (4 - FIT(timing->recover, 1, 4)) << 8; + t |= (5 - FIT(timing->active, 2, 5)) << 12; } - if (speed >= XFER_UDMA_0) { - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag); + pci_write_config_word(dev, PIIX_IDETIM0 + (dn & 2), t); + + if (!(piix_config->flags & PIIX_UDMA)) return; + + pci_read_config_byte(dev, PIIX_UDMACTL, &u); + u &= ~(1 << dn); + + if (timing->udma) { + + u |= 1 << dn; + + pci_read_config_word(dev, PIIX_UDMATIM, &t); + + if (piix_config->flags & PIIX_VICTORY) { + t &= ~(0x07 << (dn << 2)); + t |= (8 - FIT(timing->udma, 2, 8)) << (dn << 2); } else { - pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); - } - if (!(reg4a & u_speed)) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); + t &= ~(0x03 << (dn << 2)); + t |= (4 - FIT(timing->udma, 2, 4)) << (dn << 2); } - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) { - pci_write_config_word(dev, 0x54, reg54|v_flag); + + pci_write_config_word(dev, PIIX_UDMATIM, t); + + if ((piix_config->flags & PIIX_UDMA) > PIIX_UDMA_33 + && ~piix_config->flags & PIIX_VICTORY) { + + pci_read_config_dword(dev, PIIX_IDECFG, &c); + + if ((piix_config->flags & PIIX_UDMA) > PIIX_UDMA_66) + c &= ~(1 << (dn + 12)); + c &= ~(1 << dn); + + switch (umul) { + case 2: c |= 1 << dn; break; + case 4: c |= 1 << (dn + 12); break; } - } else { - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + + pci_write_config_dword(dev, PIIX_IDECFG, c); } } - if (speed < XFER_UDMA_0) { - if (reg48 & u_flag) - pci_write_config_word(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & v_flag) - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); - if (reg55 & w_flag) - pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); + + pci_write_config_byte(dev, PIIX_UDMACTL, u); +} + +/* + * piix_set_drive() computes timing values configures the drive and + * the chipset to a desired transfer mode. It also can be called + * by upper layers. + */ + +static int piix_set_drive(ide_drive_t *drive, unsigned char speed) +{ + ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); + struct ata_timing t, p; + int err, T, UT, umul; + + if (speed != XFER_PIO_SLOW && speed != drive->current_speed) + if ((err = ide_config_drive_speed(drive, speed))) + return err; + + umul = min((speed > XFER_UDMA_4) ? 4 : ((speed > XFER_UDMA_2) ? 2 : 1), + piix_config->flags & PIIX_UDMA); + + if (piix_config->flags & PIIX_VICTORY) + umul = 2; + + T = 1000000000 / piix_clock; + UT = T / umul; + + ata_timing_compute(drive, speed, &t, T, UT); + + if ((piix_config->flags & PIIX_NO_SITRE) && peer->present) { + ata_timing_compute(peer, peer->current_speed, &p, T, UT); + if (t.cycle <= 9 && p.cycle <= 9) + ata_timing_merge(&p, &t, &t, IDE_TIMING_ALL); } - piix_tune_drive(drive, piix_dma_2_pio(speed)); + piix_set_speed(HWIF(drive)->pci_dev, drive->dn, &t, umul); -#if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* PIIX_DEBUG_DRIVE_INFO */ - if (!drive->init_speed) + if (!drive->init_speed) drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); drive->current_speed = speed; - return err; + + return 0; } -static int piix_config_drive_for_dma (ide_drive_t *drive) +/* + * piix_tune_drive() is a callback from upper layers for + * PIO-only tuning. + */ + +static void piix_tune_drive(ide_drive_t *drive, unsigned char pio) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - byte speed; - - byte udma_66 = eighty_ninty_three(drive); - int ultra100 = ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) || - (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) || - (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10)) ? 1 : 0; - int ultra66 = ((ultra100) || - (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; - int ultra = ((ultra66) || - (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || - (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) || - (dev->device == PCI_DEVICE_ID_INTEL_82451NX) || - (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - - speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA - | (ultra ? XFER_UDMA : 0) | ((udma_66 & ultra66) ? XFER_UDMA_66 : 0) - | ((udma_66 & ultra100) ? XFER_UDMA_100 : 0)); - - (void) piix_tune_chipset(drive, speed); - - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + if (!((piix_enabled >> HWIF(drive)->channel) & 1)) + return; + + if (pio == 255) { + piix_set_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO)); + return; + } + + piix_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); } -static void config_chipset_for_pio (ide_drive_t *drive) +#ifdef CONFIG_BLK_DEV_IDEDMA + +/* + * piix_dmaproc() is a callback from upper layers that can do + * a lot, but we use it for DMA/PIO tuning only, delegating everything + * else to the default ide_dmaproc(). + */ + +int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - piix_tune_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0); + + if (func == ide_dma_check) { + + short w80 = HWIF(drive)->udma_four; + + short speed = ata_timing_mode(drive, + XFER_PIO | XFER_EPIO | + (piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA | + (piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) | + (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) | + (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0)))); + + piix_set_drive(drive, speed); + + func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO) + ? ide_dma_on : ide_dma_off_quietly; + + } + + return ide_dmaproc(func, drive); } -static int config_drive_xfer_rate (ide_drive_t *drive) +#endif /* CONFIG_BLK_DEV_IDEDMA */ + +/* + * The initialization callback. Here we determine the IDE chip type + * and initialize its drive independent registers. + */ + +unsigned int __init pci_init_piix(struct pci_dev *dev, const char *name) { - struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; - - if (id && (id->capability & 1) && HWIF(drive)->autodma) { - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; - goto fast_ata_pio; - } - dma_func = ide_dma_off_quietly; - if (id->field_valid & 4) { - if (id->dma_ultra & 0x003F) { - /* Force if Capable UltraDMA */ - dma_func = piix_config_drive_for_dma(drive); - if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x007)) { - /* Force if Capable regular DMA modes */ - dma_func = piix_config_drive_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; + unsigned int u; + unsigned short w; + unsigned char t; + int i; + +/* + * Find out which Intel IDE this is. + */ + + for (piix_config = piix_ide_chips; piix_config->id != 0; ++piix_config) + if (dev->device == piix_config->id) + break; + + if (!piix_config->id) { + printk(KERN_WARNING "PIIX: Unknown PIIX/ICH chip %#x, contact Vojtech Pavlik <vojtech@ucw.cz>\n", dev->device); + return -ENODEV; + } + +/* + * Check for possibly broken DMA configs. + */ + + { + struct pci_dev *orion = NULL; + + if (piix_config->flags & PIIX_CHECK_REV) { + pci_read_config_byte(dev, PCI_REVISION_ID, &t); + if (t < 2) { + printk(KERN_INFO "PIIX: Found buggy old PIIX rev %#x, disabling DMA\n", t); + piix_config->flags |= PIIX_NODMA; } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { - if (id->eide_dma_time > 150) { - goto no_dma_set; + } + + if ((orion = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, NULL))) { + pci_read_config_byte(orion, PCI_REVISION_ID, &t); + if (t < 4) { + printk(KERN_INFO "PIIX: Found buggy 82454GX Orion bridge rev %#x, disabling DMA\n", t); + piix_config->flags |= PIIX_NODMA; } - /* Consult the list of known "good" drives */ - dma_func = piix_config_drive_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; - } else { - goto fast_ata_pio; } - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - dma_func = ide_dma_off_quietly; -no_dma_set: - config_chipset_for_pio(drive); } - return HWIF(drive)->dmaproc(dma_func, drive); -} -static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -{ - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - default : +/* + * Check 80-wire cable presence. + */ + + switch (piix_config->flags & PIIX_UDMA) { + + case PIIX_UDMA_66: + case PIIX_UDMA_100: + pci_read_config_dword(dev, PIIX_IDECFG, &u); + piix_80w = ((u & 0x30) ? 1 : 0) | ((u & 0xc0) ? 2 : 0); + break; + + case PIIX_UDMA_V66: + pci_read_config_byte(dev, PIIX_IDESTAT, &t); + piix_80w = ((t & 2) ? 1 : 0) | ((t & 1) ? 2 : 0); break; } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive); -} -#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ -unsigned int __init pci_init_piix(struct pci_dev *dev) -{ -#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) +/* + * Enable ping-pong buffers where applicable. + */ + + if (piix_config->flags & PIIX_PINGPONG) { + pci_read_config_dword(dev, PIIX_IDECFG, &u); + u |= 0x400; + pci_write_config_dword(dev, PIIX_IDECFG, u); + } + +/* + * Detect enabled interfaces, enable slave separate timing if possible. + */ + + for (i = 0; i < 2; i++) { + pci_read_config_word(dev, PIIX_IDETIM0 + (i << 1), &w); + piix_enabled |= (w & 0x8000) ? (1 << i) : 0; + w &= 0x8c00; + if (~piix_config->flags & PIIX_NO_SITRE) w |= 0x4000; + w |= 0x44; + pci_write_config_word(dev, PIIX_IDETIM0 + (i << 1), w); + } + +/* + * Determine the system bus clock. + */ + + piix_clock = system_bus_speed * 1000; + + switch (piix_clock) { + case 33000: piix_clock = 33333; break; + case 37000: piix_clock = 37500; break; + case 41000: piix_clock = 41666; break; + } + + if (piix_clock < 20000 || piix_clock > 50000) { + printk(KERN_WARNING "PIIX: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", piix_clock); + printk(KERN_WARNING "PIIX: Use ide0=ata66 if you want to assume 80-wire cable\n"); + piix_clock = 33333; + } + +/* + * Print the boot message. + */ + + printk(KERN_INFO "PIIX: %s %s controller on pci%s\n", + dev->name, piix_dma[piix_config->flags & PIIX_UDMA], dev->slot_name); + +/* + * Register /proc/ide/piix entry + */ + +#ifdef CONFIG_PROC_FS if (!piix_proc) { - piix_proc = 1; + piix_base = pci_resource_start(dev, 4); bmide_dev = dev; piix_display_info = &piix_get_info; + piix_proc = 1; } -#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ +#endif + return 0; } -/* - * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards. - * It does not specify device detection, but channel!!! - * You determine later if bit 13 of word93 is set... - */ -unsigned int __init ata66_piix (ide_hwif_t *hwif) +unsigned int __init ata66_piix(ide_hwif_t *hwif) { - byte reg54h = 0, reg55h = 0, ata66 = 0; - byte mask = hwif->channel ? 0xc0 : 0x30; - - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - - ata66 = (reg54h & mask) ? 1 : 0; - - return ata66; + return ((piix_enabled & piix_80w) >> hwif->channel) & 1; } -void __init ide_init_piix (ide_hwif_t *hwif) +void __init ide_init_piix(ide_hwif_t *hwif) { -#ifndef CONFIG_IA64 - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; -#endif /* CONFIG_IA64 */ + int i; - if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) { - /* This is a painful system best to let it self tune for now */ - return; + hwif->tuneproc = &piix_tune_drive; + hwif->speedproc = &piix_set_drive; + hwif->autodma = 0; + + for (i = 0; i < 2; i++) { + hwif->drives[i].io_32bit = 1; + hwif->drives[i].unmask = 1; + hwif->drives[i].autotune = 1; + hwif->drives[i].dn = hwif->channel * 2 + i; } - hwif->tuneproc = &piix_tune_drive; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) { + hwif->highmem = 1; + hwif->dmaproc = &piix_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ +} - if (!hwif->dma_base) - return; +/* + * We allow the BM-DMA driver only work on enabled interfaces, + * and only if DMA is safe with the chip and bridge. + */ - hwif->highmem = 1; -#ifndef CONFIG_BLK_DEV_IDEDMA - hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ -#ifdef CONFIG_PIIX_TUNING - if (!noautodma) - hwif->autodma = 1; - hwif->dmaproc = &piix_dmaproc; - hwif->speedproc = &piix_tune_chipset; -#endif /* CONFIG_PIIX_TUNING */ -#endif /* !CONFIG_BLK_DEV_IDEDMA */ +void __init ide_dmacapable_piix(ide_hwif_t *hwif, unsigned long dmabase) +{ + if (((piix_enabled >> hwif->channel) & 1) + && !(piix_config->flags & PIIX_NODMA)) + ide_setup_dma(hwif, dmabase, 8); } diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c deleted file mode 100644 index 95159248e95f..000000000000 --- a/drivers/ide/slc90e66.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * linux/drivers/ide/slc90e66.c Version 0.10 October 4, 2000 - * - * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> - * May be copied or modified under the terms of the GNU General Public License - * - * 00:07.1 IDE interface: EFAR Microsystems: - * Unknown device 9130 (prog-if 8a [Master SecP PriP]) - * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- - * VGASnoop- ParErr- Stepping- SERR- FastB2B- - * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium - * >TAbort- <TAbort- <MAbort- >SERR- <PERR- - * Latency: 64 - * Interrupt: pin A routed to IRQ 255 - * Region 4: I/O ports at 1050 - * - * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00 - * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00 - * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00 - * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00 - * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * - * This a look-a-like variation of the ICH0 PIIX4 Ultra-66, - * but this keeps the ISA-Bridge and slots alive. - * - */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/io.h> - -#include "ata-timing.h" - -#define SLC90E66_DEBUG_DRIVE_INFO 0 - -#define DISPLAY_SLC90E66_TIMINGS - -#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static int slc90e66_get_info(char *, char **, off_t, int); -extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -static struct pci_dev *bmide_dev; - -static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - u32 bibma = pci_resource_start(bmide_dev, 4); - u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; - u8 c0 = 0, c1 = 0; - u8 reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0; - - pci_read_config_word(bmide_dev, 0x40, ®40); - pci_read_config_word(bmide_dev, 0x42, ®42); - pci_read_config_byte(bmide_dev, 0x44, ®44); - pci_read_config_byte(bmide_dev, 0x47, ®47); - pci_read_config_byte(bmide_dev, 0x48, ®48); - pci_read_config_byte(bmide_dev, 0x4a, ®4a); - pci_read_config_byte(bmide_dev, 0x4b, ®4b); - - psitre = (reg40 & 0x4000) ? 1 : 0; - ssitre = (reg42 & 0x4000) ? 1 : 0; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ -#ifdef __mips__ /* only for mips? */ - c0 = inb_p(bibma + 0x02); - c1 = inb_p(bibma + 0x0a); -#else - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); -#endif - - p += sprintf(p, " SLC90E66 Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", - (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", - (c1&0x40) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", - (reg48&0x01) ? "yes" : "no ", - (reg48&0x02) ? "yes" : "no ", - (reg48&0x04) ? "yes" : "no ", - (reg48&0x08) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", - ((reg4a&0x04)==0x04) ? "4" : - ((reg4a&0x03)==0x03) ? "3" : - (reg4a&0x02) ? "2" : - (reg4a&0x01) ? "1" : - (reg4a&0x00) ? "0" : "X", - ((reg4a&0x40)==0x40) ? "4" : - ((reg4a&0x30)==0x30) ? "3" : - (reg4a&0x20) ? "2" : - (reg4a&0x10) ? "1" : - (reg4a&0x00) ? "0" : "X", - ((reg4b&0x04)==0x04) ? "4" : - ((reg4b&0x03)==0x03) ? "3" : - (reg4b&0x02) ? "2" : - (reg4b&0x01) ? "1" : - (reg4b&0x00) ? "0" : "X", - ((reg4b&0x40)==0x40) ? "4" : - ((reg4b&0x30)==0x30) ? "3" : - (reg4b&0x20) ? "2" : - (reg4b&0x10) ? "1" : - (reg4b&0x00) ? "0" : "X"); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - -/* - * FIXME.... Add configuration junk data....blah blah...... - */ - - return p-buffer; /* => must be less than 4k! */ -} -#endif /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */ - -/* - * Used to set Fifo configuration via kernel command line: - */ - -byte slc90e66_proc = 0; - -extern char *ide_xfer_verbose (byte xfer_rate); - -#ifdef CONFIG_BLK_DEV_IDEDMA -/* - * - */ -static byte slc90e66_dma_2_pio (byte xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} -#endif /* CONFIG_BLK_DEV_IDEDMA */ - -/* - * Based on settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). - */ -static void slc90e66_tune_drive (ide_drive_t *drive, byte pio) -{ - unsigned long flags; - u16 master_data; - byte slave_data; - int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = HWIF(drive)->index ? 0x42 : 0x40; - int slave_port = 0x44; - /* ISP RTC */ - byte timings[][2] = { { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - if (pio == 255) - pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; - else - pio = min_t(byte, pio, 4); - - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); - if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; - pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); - slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1] - << (HWIF(drive)->index ? 4 : 0))); - } else { - master_data = master_data & 0xccf8; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | - (timings[pio][1] << 8); - } - save_flags(flags); - cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); - restore_flags(flags); -} - -#ifdef CONFIG_BLK_DEV_IDEDMA -static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - byte maslave = hwif->channel ? 0x42 : 0x40; - int a_speed = 7 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int u_speed = 0; - int err = 0; - int sitre; - short reg4042, reg44, reg48, reg4a; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - - switch(speed) { - case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break; - case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break; - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; -#if 0 /* allow PIO modes */ - default: return -1; -#endif - } - - if (speed >= XFER_UDMA_0) { - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); - if ((reg4a & u_speed) != u_speed) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_read_config_word(dev, 0x4a, ®4a); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } - } - if (speed < XFER_UDMA_0) { - if (reg48 & u_flag) - pci_write_config_word(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - } - - slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed)); - -#if SLC90E66_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* SLC90E66_DEBUG_DRIVE_INFO */ - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; -} - -static int slc90e66_config_drive_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - int ultra = 1; - byte speed = 0; - byte udma_66 = eighty_ninty_three(drive); - -#if 1 /* allow PIO modes */ - if (!HWIF(drive)->autodma) { - speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); - (void) slc90e66_tune_chipset(drive, speed); - return ((int) ide_dma_off_quietly); - } -#endif - - speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA - | (ultra ? XFER_UDMA : 0) | ((ultra && udma_66) ? XFER_UDMA_66 : 0)); - - (void) slc90e66_tune_chipset(drive, speed); - - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); -} - -static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -{ - switch (func) { - case ide_dma_check: - return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive); - default : - break; - } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive); -} -#endif /* CONFIG_BLK_DEV_IDEDMA */ - -unsigned int __init pci_init_slc90e66(struct pci_dev *dev) -{ -#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) - if (!slc90e66_proc) { - slc90e66_proc = 1; - bmide_dev = dev; - slc90e66_display_info = &slc90e66_get_info; - } -#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */ - return 0; -} - -unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif) -{ -#if 1 - byte reg47 = 0, ata66 = 0; - byte mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ - - pci_read_config_byte(hwif->pci_dev, 0x47, ®47); - - ata66 = (reg47 & mask) ? 0 : 1; /* bit[0(1)]: 0:80, 1:40 */ -#else - byte ata66 = 0; -#endif - return ata66; -} - -void __init ide_init_slc90e66 (ide_hwif_t *hwif) -{ - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; - - hwif->tuneproc = &slc90e66_tune_drive; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - - if (!hwif->dma_base) - return; - - hwif->autodma = 0; - hwif->highmem = 1; -#ifdef CONFIG_BLK_DEV_IDEDMA - if (!noautodma) - hwif->autodma = 1; - hwif->dmaproc = &slc90e66_dmaproc; - hwif->speedproc = &slc90e66_tune_chipset; -#endif /* !CONFIG_BLK_DEV_IDEDMA */ -} diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 890ca713c999..a8fa051737f8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1710,7 +1710,6 @@ struct pci_pool { /* the pool */ spinlock_t lock; size_t blocks_per_page; size_t size; - int flags; struct pci_dev *dev; size_t allocation; char name [32]; @@ -1727,8 +1726,6 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_POISON_BYTE 0xa7 -// #define CONFIG_PCIPOOL_DEBUG - /** * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma. @@ -1737,7 +1734,7 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ * @size: size of the blocks in this pool. * @align: alignment requirement for blocks; must be a power of two * @allocation: returned blocks won't cross this boundary (or zero) - * @flags: SLAB_* flags (not all are supported). + * @mem_flags: SLAB_* flags. * * Returns a pci allocation pool with the requested characteristics, or * null if one can't be created. Given one of these pools, pci_pool_alloc() @@ -1753,7 +1750,7 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ */ struct pci_pool * pci_pool_create (const char *name, struct pci_dev *pdev, - size_t size, size_t align, size_t allocation, int flags) + size_t size, size_t align, size_t allocation, int mem_flags) { struct pci_pool *retval; @@ -1777,13 +1774,9 @@ pci_pool_create (const char *name, struct pci_dev *pdev, } else if (allocation < size) return 0; - if (!(retval = kmalloc (sizeof *retval, flags))) + if (!(retval = kmalloc (sizeof *retval, mem_flags))) return retval; -#ifdef CONFIG_PCIPOOL_DEBUG - flags |= SLAB_POISON; -#endif - strncpy (retval->name, name, sizeof retval->name); retval->name [sizeof retval->name - 1] = 0; @@ -1791,17 +1784,10 @@ pci_pool_create (const char *name, struct pci_dev *pdev, INIT_LIST_HEAD (&retval->page_list); spin_lock_init (&retval->lock); retval->size = size; - retval->flags = flags; retval->allocation = allocation; retval->blocks_per_page = allocation / size; init_waitqueue_head (&retval->waitq); -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n", - pdev ? pdev->slot_name : NULL, retval->name, size, - retval->blocks_per_page, allocation); -#endif - return retval; } @@ -1824,8 +1810,9 @@ pool_alloc_page (struct pci_pool *pool, int mem_flags) &page->dma); if (page->vaddr) { memset (page->bitmap, 0xff, mapsize); // bit set == free - if (pool->flags & SLAB_POISON) - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif list_add (&page->page_list, &pool->page_list); } else { kfree (page); @@ -1851,8 +1838,9 @@ pool_free_page (struct pci_pool *pool, struct pci_page *page) { dma_addr_t dma = page->dma; - if (pool->flags & SLAB_POISON) - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma); list_del (&page->page_list); kfree (page); @@ -1871,12 +1859,6 @@ pci_pool_destroy (struct pci_pool *pool) { unsigned long flags; -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool destroy %s/%s\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name); -#endif - spin_lock_irqsave (&pool->lock, flags); while (!list_empty (&pool->page_list)) { struct pci_page *page; @@ -2010,30 +1992,27 @@ pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma) pool->name, vaddr, (unsigned long) dma); return; } -#ifdef CONFIG_PCIPOOL_DEBUG - if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (unsigned long) dma); - return; - } -#endif block = dma - page->dma; block /= pool->size; map = block / BITS_PER_LONG; block %= BITS_PER_LONG; -#ifdef CONFIG_PCIPOOL_DEBUG +#ifdef CONFIG_DEBUG_SLAB + if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { + printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", + pool->dev ? pool->dev->slot_name : NULL, + pool->name, vaddr, (unsigned long) dma); + return; + } if (page->bitmap [map] & (1UL << block)) { printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", pool->dev ? pool->dev->slot_name : NULL, pool->name, dma); return; } + memset (vaddr, POOL_POISON_BYTE, pool->size); #endif - if (pool->flags & SLAB_POISON) - memset (vaddr, POOL_POISON_BYTE, pool->size); spin_lock_irqsave (&pool->lock, flags); set_bit (block, &page->bitmap [map]); diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 9c67a2796b87..29a97f2b8138 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -526,8 +526,10 @@ 2040 79c974 7006 AMD-751 [Irongate] System Controller 7007 AMD-751 [Irongate] AGP Bridge - 700e AMD-760 [Irongate] System Controller - 700f AMD-760 [Irongate] AGP Bridge + 700c AMD-760 MP [IGD4-2P] System Controller + 700d AMD-760 MP [IGD4-2P] AGP Bridge + 700e AMD-760 [IGD4-1P] System Controller + 700f AMD-760 [IGD4-1P] AGP Bridge 7400 AMD-755 [Cobra] ISA 7401 AMD-755 [Cobra] IDE 7403 AMD-755 [Cobra] ACPI @@ -540,11 +542,21 @@ 7411 AMD-765 [Viper] IDE 7413 AMD-765 [Viper] ACPI 7414 AMD-765 [Viper] USB - 7440 AMD-768 [??] ISA - 7441 AMD-768 [??] IDE - 7443 AMD-768 [??] ACPI - 7448 AMD-768 [??] PCI - 7449 AMD-768 [??] USB + 7440 AMD-768 [Opus] ISA + 7441 AMD-768 [Opus] IDE + 7443 AMD-768 [Opus] ACPI + 7448 AMD-768 [Opus] PCI + 7449 AMD-768 [Opus] USB + 7454 AMD-8151 System Controller + 7455 AMD-8151 AGP Bridge + 7460 AMD-8111 PCI + 7461 AMD-8111 USB + 7462 AMD-8111 Ethernet + 7468 AMD-8111 LPC + 7469 AMD-8111 IDE + 746a AMD-8111 SMBus 2.0 + 746b AMD-8111 ACPI + 746d AMD-8111 AC97 Audio 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -1055,11 +1067,11 @@ 1052 ?Young Micro Systems 1053 Young Micro Systems 1054 Hitachi, Ltd -1055 EFAR Microsystems - 9130 EIDE Controller - 9460 PCI to ISA Bridge - 9462 USB Universal Host Controller [OHCI] - 9463 Power Management Controller [Bridge] +1055 Efar Microsystems + 9130 slc90e66 [Victory66] IDE + 9460 slc90e66 [Victory66] ISA + 9462 slc90e66 [Victory66] USB + 9463 slc90e66 [Victory66] ACPI 1056 ICL # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this. 1057 Motorola @@ -1925,6 +1937,7 @@ 0151 NV15 DDR (GeForce2 GTS) 0152 NV15 Bladerunner (GeForce2 Ultra) 0153 NV15 GL (Quadro2 Pro) + 01bc nForce IDE 0200 NV20 (GeForce3) 0203 Quadro DCC 10df Emulex Corporation @@ -5066,6 +5079,8 @@ 244c 82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M) 244e 82820 820 (Camino 2) Chipset PCI 2485 AC'97 Audio Controller + 248a 82801CAM ICH3-M IDE + 248b 82801CA ICH3 IDE 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset 2501 82820 820 (Camino) Chipset Host Bridge (MCH) @@ -5118,10 +5133,10 @@ 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) - 7600 82372FB PCI to ISA Bridge - 7601 82372FB PIIX4 IDE - 7602 82372FB [PCI-to-USB UHCI] - 7603 82372FB System Management Bus Controller + 7600 82372FB PIIX5 ISA + 7601 82372FB PIIX5 IDE + 7602 82372FB PIIX5 USB + 7603 82372FB PIIX5 SMBus 7800 i740 1092 0100 Stealth II G460 8086 0100 Intel740 Graphics Accelerator diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c index 2b23cf559079..d81324484ff8 100644 --- a/drivers/pnp/isapnp.c +++ b/drivers/pnp/isapnp.c @@ -2273,6 +2273,39 @@ EXPORT_SYMBOL(isapnp_resource_change); EXPORT_SYMBOL(isapnp_register_driver); EXPORT_SYMBOL(isapnp_unregister_driver); +static struct device_driver isapnp_device_driver = {}; + +static inline int isapnp_init_device_tree(void) +{ + struct pci_bus *card; + struct pci_dev *parent = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); + + isapnp_for_each_card(card) { + struct list_head *devlist; + + card->dev = isapnp_alloc(sizeof(*card->dev)); + if (!card->dev) + break; + snprintf(card->dev->name, sizeof(card->dev->name), "%s", card->name); + sprintf(card->dev->bus_id, "isapnp%d", card->number); + card->dev->parent = parent ? &parent->dev : NULL; + card->dev->driver = &isapnp_device_driver; + device_register(card->dev); + + for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) { + struct pci_dev *dev = pci_dev_b(devlist); + + snprintf(dev->dev.name, sizeof(dev->dev.name), "%s", dev->name); + sprintf(dev->dev.bus_id, "%d", dev->devfn); + dev->dev.parent = card->dev; + dev->dev.driver = &isapnp_device_driver; + device_register(&dev->dev); + } + } + + return 0; +} + int __init isapnp_init(void) { int cards; @@ -2351,6 +2384,9 @@ int __init isapnp_init(void) } else { printk(KERN_INFO "isapnp: No Plug & Play card found\n"); } + + isapnp_init_device_tree(); + #ifdef CONFIG_PROC_FS isapnp_proc_init(); #endif @@ -2361,10 +2397,28 @@ subsys_initcall(isapnp_init); #ifdef MODULE +static inline void isapnp_cleanup_device_tree(void) +{ + struct pci_bus *card; + + isapnp_for_each_card(card) { + struct list_head *devlist; + + for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) { + struct pci_dev *dev = pci_dev_b(devlist); + + put_device(&dev->dev); + } + put_device(card->dev); + } +} + void cleanup_module(void) { - if (isapnp_detected) + if (isapnp_detected) { + isapnp_cleanup_device_tree(); isapnp_free_all_resources(); + } } #else diff --git a/drivers/usb/Config.help b/drivers/usb/Config.help index f76202f07b7a..28a88d96a72c 100644 --- a/drivers/usb/Config.help +++ b/drivers/usb/Config.help @@ -382,6 +382,7 @@ CONFIG_USB_KAWETH CONFIG_USB_CATC Say Y if you want to use one of the following 10Mbps USB Ethernet device based on the EL1210A chip. Supported devices are: + Belkin F5U011 Belkin F5U111 CATC NetMate CATC NetMate II diff --git a/drivers/usb/catc.c b/drivers/usb/catc.c index 3bea97a3c04e..37a300d9e2d0 100644 --- a/drivers/usb/catc.c +++ b/drivers/usb/catc.c @@ -7,6 +7,9 @@ * * Based on the work of * Donald Becker + * + * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002 + * - adds support for Belkin F5U011 */ /* @@ -70,6 +73,7 @@ MODULE_LICENSE("GPL"); #define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */ #define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */ #define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */ +#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */ /* * Control requests. @@ -80,6 +84,7 @@ enum control_requests { GetMac = 0xf2, Reset = 0xf4, SetMac = 0xf5, + SetRxMode = 0xf5, /* F5U011 only */ WriteROM = 0xf8, SetReg = 0xfa, GetReg = 0xfb, @@ -127,6 +132,7 @@ enum rx_filter_bits { RxForceOK = 0x04, RxMultiCast = 0x08, RxPromisc = 0x10, + AltRxPromisc = 0x20, /* F5U011 uses different bit */ }; enum led_values { @@ -137,6 +143,12 @@ enum led_values { LEDLink = 0x08, }; +enum link_status { + LinkNoChange = 0, + LinkGood = 1, + LinkBad = 2 +}; + /* * The catc struct. */ @@ -180,6 +192,10 @@ struct catc { } ctrl_queue[CTRL_QUEUE]; struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb; + + u8 is_f5u011; /* Set if device is an F5U011 */ + u8 rxmode[2]; /* Used for F5U011 */ + atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */ }; /* @@ -193,6 +209,10 @@ struct catc { #define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size) #define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size) +#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2) +#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL) +#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL) + #define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL) #define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb) #define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL) @@ -206,9 +226,12 @@ static void catc_rx_done(struct urb *urb) struct catc *catc = urb->context; u8 *pkt_start = urb->transfer_buffer; struct sk_buff *skb; - int pkt_len; + int pkt_len, pkt_offset = 0; - clear_bit(RX_RUNNING, &catc->flags); + if (!catc->is_f5u011) { + clear_bit(RX_RUNNING, &catc->flags); + pkt_offset = 2; + } if (urb->status) { dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); @@ -216,19 +239,22 @@ static void catc_rx_done(struct urb *urb) } do { - pkt_len = le16_to_cpup((u16*)pkt_start); - - if (pkt_len > urb->actual_length) { - catc->stats.rx_length_errors++; - catc->stats.rx_errors++; - break; + if(!catc->is_f5u011) { + pkt_len = le16_to_cpup((u16*)pkt_start); + if (pkt_len > urb->actual_length) { + catc->stats.rx_length_errors++; + catc->stats.rx_errors++; + break; + } + } else { + pkt_len = urb->actual_length; } if (!(skb = dev_alloc_skb(pkt_len))) return; skb->dev = catc->netdev; - eth_copy_and_sum(skb, pkt_start + 2, pkt_len, 0); + eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, catc->netdev); @@ -237,11 +263,28 @@ static void catc_rx_done(struct urb *urb) catc->stats.rx_packets++; catc->stats.rx_bytes += pkt_len; + /* F5U011 only does one packet per RX */ + if (catc->is_f5u011) + break; pkt_start += (((pkt_len + 1) >> 6) + 1) << 6; } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); catc->netdev->last_rx = jiffies; + + if (catc->is_f5u011) { + if (atomic_read(&catc->recq_sz)) { + int status; + atomic_dec(&catc->recq_sz); + dbg("getting extra packet"); + urb->dev = catc->usbdev; + if ((status = usb_submit_urb(urb, GFP_KERNEL)) < 0) { + dbg("submit(rx_urb) status %d", status); + } + } else { + clear_bit(RX_RUNNING, &catc->flags); + } + } } static void catc_irq_done(struct urb *urb) @@ -249,29 +292,48 @@ static void catc_irq_done(struct urb *urb) struct catc *catc = urb->context; u8 *data = urb->transfer_buffer; int status; + unsigned int hasdata = 0, linksts = LinkNoChange; + + if (!catc->is_f5u011) { + hasdata = data[1] & 0x80; + if (data[1] & 0x40) + linksts = LinkGood; + else if (data[1] & 0x20) + linksts = LinkBad; + } else { + hasdata = (unsigned int)(be16_to_cpup((u16*)data) & 0x0fff); + if (data[0] == 0x90) + linksts = LinkGood; + else if (data[0] == 0xA0) + linksts = LinkBad; + } if (urb->status) { dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); return; } - if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) { - catc->rx_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) { - err("submit(rx_urb) status %d", status); - return; - } - } - - if (data[1] & 0x40) { + if (linksts == LinkGood) { netif_carrier_on(catc->netdev); dbg("link ok"); } - if (data[1] & 0x20) { + if (linksts == LinkBad) { netif_carrier_off(catc->netdev); dbg("link bad"); } + + if (hasdata) { + if (test_and_set_bit(RX_RUNNING, &catc->flags)) { + if (catc->is_f5u011) + atomic_inc(&catc->recq_sz); + } else { + catc->rx_urb->dev = catc->usbdev; + if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) { + err("submit(rx_urb) status %d", status); + } + } + } } /* @@ -282,6 +344,9 @@ static void catc_tx_run(struct catc *catc) { int status; + if (catc->is_f5u011) + catc->tx_ptr = (catc->tx_ptr + 63) & ~63; + catc->tx_urb->transfer_buffer_length = catc->tx_ptr; catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx]; catc->tx_urb->dev = catc->usbdev; @@ -338,14 +403,15 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; - *((u16*)tx_buf) = cpu_to_le16((u16)skb->len); + *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); memcpy(tx_buf + 2, skb->data, skb->len); catc->tx_ptr += skb->len + 2; if (!test_and_set_bit(TX_RUNNING, &catc->flags)) catc_tx_run(catc); - if (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))) + if ((catc->is_f5u011 && catc->tx_ptr) + || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) netif_stop_queue(netdev); spin_unlock_irqrestore(&catc->tx_lock, flags); @@ -554,17 +620,32 @@ static void catc_set_multicast_list(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { memset(catc->multicast, 0xff, 64); - rx |= RxPromisc; + rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; } - if (netdev->flags & IFF_ALLMULTI) + if (netdev->flags & IFF_ALLMULTI) { memset(catc->multicast, 0xff, 64); - - for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) - catc_multicast(mc->dmi_addr, catc->multicast); - - catc_set_reg_async(catc, RxUnit, rx); - catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); + } else { + for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { + u32 crc = ether_crc_le(6, mc->dmi_addr); + if (!catc->is_f5u011) { + catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); + } else { + catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); + } + } + } + if (!catc->is_f5u011) { + catc_set_reg_async(catc, RxUnit, rx); + catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); + } else { + f5u011_mchash_async(catc, catc->multicast); + if (catc->rxmode[0] != rx) { + catc->rxmode[0] = rx; + dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]); + f5u011_rxmode_async(catc, catc->rxmode); + } + } } /* @@ -591,6 +672,29 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) return -EFAULT; return 0; } + + /* get settings */ + case ETHTOOL_GSET: + if (catc->is_f5u011) { + struct ethtool_cmd ecmd = { ETHTOOL_GSET, + SUPPORTED_10baseT_Half | SUPPORTED_TP, + ADVERTISED_10baseT_Half | ADVERTISED_TP, + SPEED_10, + DUPLEX_HALF, + PORT_TP, + 0, + XCVR_INTERNAL, + AUTONEG_DISABLE, + 1, + 1 + }; + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } else { + return -EOPNOTSUPP; + } + /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; @@ -632,7 +736,8 @@ static int catc_open(struct net_device *netdev) netif_start_queue(netdev); - mod_timer(&catc->timer, jiffies + STATS_UPDATE); + if (!catc->is_f5u011) + mod_timer(&catc->timer, jiffies + STATS_UPDATE); return 0; } @@ -643,7 +748,8 @@ static int catc_stop(struct net_device *netdev) netif_stop_queue(netdev); - del_timer_sync(&catc->timer); + if (!catc->is_f5u011) + del_timer_sync(&catc->timer); usb_unlink_urb(catc->rx_urb); usb_unlink_urb(catc->tx_urb); @@ -662,7 +768,7 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str struct net_device *netdev; struct catc *catc; u8 broadcast[6]; - int i; + int i, pktsz; if (usb_set_interface(usbdev, ifnum, 1)) { err("Can't set altsetting 1."); @@ -670,9 +776,16 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str } catc = kmalloc(sizeof(struct catc), GFP_KERNEL); + if (!catc) + return NULL; + memset(catc, 0, sizeof(struct catc)); netdev = init_etherdev(0, 0); + if (!netdev) { + kfree(catc); + return NULL; + } netdev->open = catc_open; netdev->hard_start_xmit = catc_hard_start_xmit; @@ -701,9 +814,26 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { err("No free urbs available."); + if (catc->ctrl_urb) usb_free_urb(catc->ctrl_urb); + if (catc->tx_urb) usb_free_urb(catc->tx_urb); + if (catc->rx_urb) usb_free_urb(catc->rx_urb); + if (catc->irq_urb) usb_free_urb(catc->irq_urb); + kfree(netdev); + kfree(catc); return NULL; } + /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ + if (usbdev->descriptor.idVendor == 0x0423 && usbdev->descriptor.idProduct == 0xa && + catc->usbdev->descriptor.bcdDevice == 0x0130 ) { + dbg("Testing for f5u011"); + catc->is_f5u011 = 1; + atomic_set(&catc->recq_sz, 0); + pktsz = RX_PKT_SZ; + } else { + pktsz = RX_MAX_BURST * (PKT_SZ + 2); + } + FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), NULL, NULL, 0, catc_ctrl_done, catc); @@ -711,20 +841,21 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str NULL, 0, catc_tx_done, catc); FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), - catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc); + catc->rx_buf, pktsz, catc_rx_done, catc); FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), catc->irq_buf, 2, catc_irq_done, catc, 1); - dbg("Checking memory size\n"); - - i = 0x12345678; - catc_write_mem(catc, 0x7a80, &i, 4); - i = 0x87654321; - catc_write_mem(catc, 0xfa80, &i, 4); - catc_read_mem(catc, 0x7a80, &i, 4); + if (!catc->is_f5u011) { + dbg("Checking memory size\n"); - switch (i) { + i = 0x12345678; + catc_write_mem(catc, 0x7a80, &i, 4); + i = 0x87654321; + catc_write_mem(catc, 0xfa80, &i, 4); + catc_read_mem(catc, 0x7a80, &i, 4); + + switch (i) { case 0x12345678: catc_set_reg(catc, TxBufCount, 8); catc_set_reg(catc, RxBufCount, 32); @@ -737,44 +868,52 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str catc_set_reg(catc, RxBufCount, 16); dbg("32k Memory\n"); break; + } + + dbg("Getting MAC from SEEROM."); + + catc_get_mac(catc, netdev->dev_addr); + + dbg("Setting MAC into registers."); + + for (i = 0; i < 6; i++) + catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); + + dbg("Filling the multicast list."); + + memset(broadcast, 0xff, 6); + catc_multicast(broadcast, catc->multicast); + catc_multicast(netdev->dev_addr, catc->multicast); + catc_write_mem(catc, 0xfa80, catc->multicast, 64); + + dbg("Clearing error counters."); + + for (i = 0; i < 8; i++) + catc_set_reg(catc, EthStats + i, 0); + catc->last_stats = jiffies; + + dbg("Enabling."); + + catc_set_reg(catc, MaxBurst, RX_MAX_BURST); + catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); + catc_set_reg(catc, LEDCtrl, LEDLink); + catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); + } else { + dbg("Performing reset\n"); + catc_reset(catc); + catc_get_mac(catc, netdev->dev_addr); + + dbg("Setting RX Mode"); + catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; + catc->rxmode[1] = 0; + f5u011_rxmode(catc, catc->rxmode); } - - dbg("Getting MAC from SEEROM."); - - catc_get_mac(catc, netdev->dev_addr); - - dbg("Setting MAC into registers."); - - for (i = 0; i < 6; i++) - catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); - - dbg("Filling the multicast list."); - - memset(broadcast, 0xff, 8); - catc_multicast(broadcast, catc->multicast); - catc_multicast(netdev->dev_addr, catc->multicast); - catc_write_mem(catc, 0xfa80, catc->multicast, 64); - - dbg("Clearing error counters."); - - for (i = 0; i < 8; i++) - catc_set_reg(catc, EthStats + i, 0); - catc->last_stats = jiffies; - - dbg("Enabling."); - - catc_set_reg(catc, MaxBurst, RX_MAX_BURST); - catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); - catc_set_reg(catc, LEDCtrl, LEDLink); - catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); - dbg("Init done."); - - printk(KERN_INFO "%s: CATC EL1210A NetMate USB Ethernet at usb%d:%d.%d, ", - netdev->name, usbdev->bus->busnum, usbdev->devnum, ifnum); + printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ", + netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", + usbdev->bus->busnum, usbdev->devnum, ifnum); for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); printk("%2.2x.\n", netdev->dev_addr[i]); - return catc; } @@ -795,7 +934,7 @@ static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr) */ static struct usb_device_id catc_id_table [] = { - { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate */ + { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ { } diff --git a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c index 5b3f0c64273e..0bb17425bc39 100644 --- a/drivers/usb/hid-core.c +++ b/drivers/usb/hid-core.c @@ -110,10 +110,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned)); - report->field[report->maxfield++] = field; + report->field[report->maxfield] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (unsigned *)(field->usage + usages); field->report = report; + field->index = report->maxfield++; return field; } @@ -741,8 +742,20 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value); #ifdef CONFIG_USB_HIDDEV - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_hid_event(hid, usage->hid, value); + if (hid->claimed & HID_CLAIMED_HIDDEV) { + struct hiddev_usage_ref uref; + unsigned type = field->report_type; + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = field->report->id; + uref.field_index = field->index; + uref.usage_index = (usage - field->usage); + uref.usage_code = usage->hid; + uref.value = value; + hiddev_hid_event(hid, &uref); + } #endif } @@ -839,6 +852,21 @@ static int hid_input_report(int type, struct urb *urb) return -1; } +#ifdef CONFIG_USB_HIDDEV + /* Notify listeners that a report has been received */ + if (hid->claimed & HID_CLAIMED_HIDDEV) { + struct hiddev_usage_ref uref; + memset(&uref, 0, sizeof(uref)); + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = report->id; + uref.field_index = HID_FIELD_INDEX_NONE; + hiddev_hid_event(hid, &uref); + } +#endif + size = ((report->size - 1) >> 3) + 1; if (len < size) { @@ -1096,6 +1124,9 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign int head; unsigned long flags; + if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) + return; + if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&hid->outlock, flags); @@ -1238,18 +1269,27 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_POWERMATE 0x0410 #define USB_DEVICE_ID_SOUNDKNOB 0x04AA +#define USB_VENDOR_ID_ATEN 0x0557 +#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 +#define USB_DEVICE_ID_ATEN_CS124U 0x2202 +#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; + unsigned quirks; } hid_blacklist[] = { - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { 0, 0 } }; @@ -1258,13 +1298,17 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; struct hid_device *hid; - unsigned rsize = 0; + unsigned quirks = 0, rsize = 0; char *buf; int n; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; + (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) + quirks = hid_blacklist[n].quirks; + + if (quirks & HID_QUIRK_IGNORE) + return NULL; if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { @@ -1302,6 +1346,8 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) } } + hid->quirks = quirks; + for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h index 77a656f2bcc9..ed72dc6acfd1 100644 --- a/drivers/usb/hid.h +++ b/drivers/usb/hid.h @@ -203,6 +203,8 @@ struct hid_item { #define HID_QUIRK_INVERT 0x01 #define HID_QUIRK_NOTOUCH 0x02 +#define HID_QUIRK_IGNORE 0x04 +#define HID_QUIRK_NOGET 0x08 /* * This is the global enviroment of the parser. This information is @@ -276,6 +278,7 @@ struct hid_field { __s32 unit_exponent; unsigned unit; struct hid_report *report; /* associated report */ + unsigned index; /* index into report->field[] */ }; #define HID_MAX_FIELDS 64 diff --git a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c index 886a30825a92..5d4029259899 100644 --- a/drivers/usb/hiddev.c +++ b/drivers/usb/hiddev.c @@ -50,9 +50,10 @@ struct hiddev { }; struct hiddev_list { - struct hiddev_event buffer[HIDDEV_BUFFER_SIZE]; + struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; int head; int tail; + unsigned flags; struct fasync_struct *fasync; struct hiddev *hiddev; struct hiddev_list *next; @@ -146,17 +147,19 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) * This is where hid.c calls into hiddev to pass an event that occurred over * the interrupt pipe */ -void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) +void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) { struct hiddev *hiddev = hid->hiddev; struct hiddev_list *list = hiddev->list; while (list) { - list->buffer[list->head].hid = usage; - list->buffer[list->head].value = value; - list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1); - - kill_fasync(&list->fasync, SIGIO, POLL_IN); + if (uref->field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + list->buffer[list->head] = *uref; + list->head = (list->head + 1) & + (HIDDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + } list = list->next; } @@ -257,43 +260,67 @@ static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, { DECLARE_WAITQUEUE(wait, current); struct hiddev_list *list = file->private_data; + int event_size; int retval = 0; - if (list->head == list->tail) { - - add_wait_queue(&list->hiddev->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); + event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? + sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); - while (list->head == list->tail) { + if (count < event_size) return 0; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - if (!list->hiddev->exist) { - retval = -EIO; - break; + while (retval == 0) { + if (list->head == list->tail) { + add_wait_queue(&list->hiddev->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + if (!list->hiddev->exist) { + retval = -EIO; + break; + } + + schedule(); } - schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->hiddev->wait, &wait); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&list->hiddev->wait, &wait); - } - - if (retval) - return retval; + if (retval) + return retval; + + + while (list->head != list->tail && + retval + event_size <= count) { + if ((list->flags & HIDDEV_FLAG_UREF) == 0) { + if (list->buffer[list->tail].field_index != + HID_FIELD_INDEX_NONE) { + struct hiddev_event event; + event.hid = list->buffer[list->tail].usage_code; + event.value = list->buffer[list->tail].value; + if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) + return -EFAULT; + retval += sizeof(struct hiddev_event); + } + } else { + if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) + return -EFAULT; + retval += sizeof(struct hiddev_usage_ref); + } + } + list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); + } - while (list->head != list->tail && retval + sizeof(struct hiddev_event) <= count) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct hiddev_event))) return -EFAULT; - list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); - retval += sizeof(struct hiddev_event); } return retval; @@ -358,6 +385,25 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); } + case HIDIOCGFLAG: + return put_user(list->flags, (int *) arg); + + case HIDIOCSFLAG: + { + int newflags; + if (get_user(newflags, (int *) arg)) + return -EFAULT; + + if ((newflags & ~HIDDEV_FLAGS) != 0 || + ((newflags & HIDDEV_FLAG_REPORT) != 0 && + (newflags & HIDDEV_FLAG_UREF) == 0)) + return -EINVAL; + + list->flags = newflags; + + return 0; + } + case HIDIOCGSTRING: { int idx, len; diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 6025a0176103..00ea80dfca00 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -1,10 +1,12 @@ /* - * printer.c Version 0.8 + * printer.c Version 0.12 * * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> * Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com> * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> + # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> + # Copyright (c) 2001 David Paschal <paschal@rcsis.com> * * USB Printer Device Class driver for USB printers and printer cables * @@ -17,10 +19,12 @@ * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support * v0.6 - never time out - * v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) + * v0.7 - fixed bulk-IN read and poll (David Paschal) * v0.8 - add devfs support * v0.9 - fix unplug-while-open paths * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) + * v0.11 - add proto_bias option (Pete Zaitcev) + * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) */ /* @@ -55,16 +59,36 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.10" -#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap" +#define DRIVER_VERSION "v0.12" +#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" #define DRIVER_DESC "USB Printer Device Class driver" #define USBLP_BUF_SIZE 8192 #define DEVICE_ID_SIZE 1024 -#define IOCNR_GET_DEVICE_ID 1 -#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */ +/* ioctls: */ #define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ +#define IOCNR_GET_DEVICE_ID 1 +#define IOCNR_GET_PROTOCOLS 2 +#define IOCNR_SET_PROTOCOL 3 +#define IOCNR_HP_SET_CHANNEL 4 +#define IOCNR_GET_BUS_ADDRESS 5 +#define IOCNR_GET_VID_PID 6 +/* Get device_id string: */ +#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) +/* The following ioctls were added for http://hpoj.sourceforge.net: */ +/* Get two-int array: + * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), + * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ +#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) +/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ +#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) +/* Set channel number (HP Vendor-specific command): */ +#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) +/* Get two-int array: [0]=bus number, [1]=device address: */ +#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) +/* Get two-int array: [0]=vendor ID, [1]=product ID: */ +#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) /* * A DEVICE_ID string may include the printer's serial number. @@ -78,26 +102,40 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H * USB Printer Requests */ -#define USBLP_REQ_GET_ID 0x00 -#define USBLP_REQ_GET_STATUS 0x01 -#define USBLP_REQ_RESET 0x02 +#define USBLP_REQ_GET_ID 0x00 +#define USBLP_REQ_GET_STATUS 0x01 +#define USBLP_REQ_RESET 0x02 +#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 #define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */ +#define USBLP_FIRST_PROTOCOL 1 +#define USBLP_LAST_PROTOCOL 3 +#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) + struct usblp { struct usb_device *dev; /* USB device */ devfs_handle_t devfs; /* devfs device */ struct semaphore sem; /* locks this struct, especially "dev" */ + char *buf; /* writeurb->transfer_buffer */ struct urb *readurb, *writeurb; /* The urbs */ wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ int ifnum; /* Interface number */ + /* Alternate-setting numbers and endpoints for each protocol + * (7/1/{index=1,2,3}) that the device supports: */ + struct { + int alt_setting; + struct usb_endpoint_descriptor *epwrite; + struct usb_endpoint_descriptor *epread; + } protocol[USBLP_MAX_PROTOCOLS]; + int current_protocol; int minor; /* minor number of device */ int wcomplete; /* writing is completed */ - int rcomplete; /* reading is completed */ + int rcomplete; /* reading is completed */ unsigned int quirks; /* quirks flags */ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ @@ -105,6 +143,35 @@ struct usblp { /* first 2 bytes are (big-endian) length */ }; +#ifdef DEBUG +static void usblp_dump(struct usblp *usblp) { + int p; + + dbg("usblp=0x%p", usblp); + dbg("dev=0x%p", usblp->dev); + dbg("devfs=0x%p", usblp->devfs); + dbg("buf=0x%p", usblp->buf); + dbg("readcount=%d", usblp->readcount); + dbg("ifnum=%d", usblp->ifnum); + for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { + dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); + dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); + dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); + } + dbg("current_protocol=%d", usblp->current_protocol); + dbg("minor=%d", usblp->minor); + dbg("wcomplete=%d", usblp->wcomplete); + dbg("rcomplete=%d", usblp->rcomplete); + dbg("quirks=%d", usblp->quirks); + dbg("used=%d", usblp->used); + dbg("bidir=%d", usblp->bidir); + dbg("device_id_string=\"%s\"", + usblp->device_id_string ? + usblp->device_id_string + 2 : + (unsigned char *)"(null)"); +} +#endif + extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ static struct usblp *usblp_table[USBLP_MINORS]; @@ -126,29 +193,45 @@ static struct quirk_printer_struct quirk_printers[] = { { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ + { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ { 0, 0 } }; +static int usblp_select_alts(struct usblp *usblp); +static int usblp_set_protocol(struct usblp *usblp, int protocol); +static int usblp_cache_device_id_string(struct usblp *usblp); + + /* * Functions for usblp control messages. */ -static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len) +static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) { int retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5); + request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", request, !!dir, recip, value, len, retval); return retval < 0 ? retval : 0; } #define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) #define usblp_get_id(usblp, config, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) #define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + +#define usblp_hp_channel_change_request(usblp, channel, buffer) \ + usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) + +/* + * See the description for usblp_select_alts() below for the usage + * explanation. Look into your /proc/bus/usb/devices and dmesg in + * case of any trouble. + */ +static int proto_bias = -1; /* * URB callback. @@ -276,7 +359,7 @@ static void usblp_cleanup (struct usblp *usblp) { devfs_unregister (usblp->devfs); usblp_table [usblp->minor] = NULL; - info ("usblp%d: removed", usblp->minor); + info("usblp%d: removed", usblp->minor); kfree (usblp->writeurb->transfer_buffer); kfree (usblp->device_id_string); @@ -285,6 +368,13 @@ static void usblp_cleanup (struct usblp *usblp) kfree (usblp); } +static void usblp_unlink_urbs(struct usblp *usblp) +{ + usb_unlink_urb(usblp->writeurb); + if (usblp->bidir) + usb_unlink_urb(usblp->readurb); +} + static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; @@ -293,9 +383,7 @@ static int usblp_release(struct inode *inode, struct file *file) lock_kernel(); usblp->used = 0; if (usblp->dev) { - if (usblp->bidir) - usb_unlink_urb(usblp->readurb); - usb_unlink_urb(usblp->writeurb); + usblp_unlink_urbs(usblp); up(&usblp->sem); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); @@ -315,8 +403,9 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct usblp *usblp = file->private_data; - int length, err; - unsigned char status; + int length, err, i; + unsigned char status, newChannel; + int twoints[2]; int retval = 0; down (&usblp->sem); @@ -335,32 +424,128 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, goto done; } - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + length = usblp_cache_device_id_string(usblp); + if (length < 0) { + retval = length; + goto done; + } + if (length > _IOC_SIZE(cmd)) + length = _IOC_SIZE(cmd); /* truncate */ + + if (copy_to_user((unsigned char *) arg, + usblp->device_id_string, + (unsigned long) length)) { + retval = -EFAULT; + goto done; + } + + break; + + case IOCNR_GET_PROTOCOLS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->current_protocol; + twoints[1] = 0; + for (i = USBLP_FIRST_PROTOCOL; + i <= USBLP_LAST_PROTOCOL; i++) { + if (usblp->protocol[i].alt_setting >= 0) + twoints[1] |= (1<<i); + } + + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { + retval = -EFAULT; + goto done; + } + + break; + + case IOCNR_SET_PROTOCOL: + if (_IOC_DIR(cmd) != _IOC_WRITE) { + retval = -EINVAL; + goto done; + } + +#ifdef DEBUG + if (arg == -10) { + usblp_dump(usblp); + break; + } +#endif + + usblp_unlink_urbs(usblp); + retval = usblp_set_protocol(usblp, arg); + if (retval < 0) { + usblp_set_protocol(usblp, + usblp->current_protocol); + } + break; + + case IOCNR_HP_SET_CHANNEL: + if (_IOC_DIR(cmd) != _IOC_WRITE || + usblp->dev->descriptor.idVendor != 0x03F0 || + usblp->quirks & USBLP_QUIRK_BIDIR) { + retval = -EINVAL; + goto done; + } + + err = usblp_hp_channel_change_request(usblp, + arg, &newChannel); if (err < 0) { - dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string", + err("usblp%d: error = %d setting " + "HP channel", usblp->minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; retval = -EIO; goto done; } - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; + dbg("usblp%d requested/got HP channel %ld/%d", + usblp->minor, arg, newChannel); + break; - dbg ("usblp%d Device ID string [%d/max %d]='%s'", - usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + case IOCNR_GET_BUS_ADDRESS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } - if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + twoints[0] = usblp->dev->bus->busnum; + twoints[1] = usblp->dev->devnum; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { + retval = -EFAULT; + goto done; + } - if (copy_to_user((unsigned char *) arg, - usblp->device_id_string, (unsigned long) length)) { + dbg("usblp%d is bus=%d, device=%d", + usblp->minor, twoints[0], twoints[1]); + break; + + case IOCNR_GET_VID_PID: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->dev->descriptor.idVendor; + twoints[1] = usblp->dev->descriptor.idProduct; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { retval = -EFAULT; goto done; } + dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", + usblp->minor, twoints[0], twoints[1]); break; default: @@ -593,155 +778,268 @@ static struct file_operations usblp_fops = { static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *epread, *epwrite; - struct usblp *usblp; - int minor, i, bidir = 0, quirks; - int alts = dev->actconfig->interface[ifnum].act_altsetting; - int length, err; - char *buf; + struct usblp *usblp = 0; + int protocol; char name[6]; - /* If a bidirectional interface exists, use it. */ - for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { - - interface = &dev->actconfig->interface[ifnum].altsetting[i]; - - if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 || - interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 || - (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) - continue; - - if (interface->bInterfaceProtocol > 1) { - bidir = 1; - alts = i; - break; - } - } - - interface = &dev->actconfig->interface[ifnum].altsetting[alts]; - if (usb_set_interface(dev, ifnum, alts)) - err("can't set desired altsetting %d on interface %d", alts, ifnum); - - epwrite = interface->endpoint + 0; - epread = bidir ? interface->endpoint + 1 : NULL; - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) { - if (interface->bNumEndpoints == 1) - return NULL; - epwrite = interface->endpoint + 1; - epread = bidir ? interface->endpoint + 0 : NULL; - } - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) - return NULL; - - if (bidir && (epread->bEndpointAddress & 0x80) != 0x80) - return NULL; - - for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++); - if (usblp_table[minor]) { - err("no more free usblp devices"); - return NULL; - } - + /* Malloc and start initializing usblp structure so we can use it + * directly. */ if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) { - err("out of memory"); - return NULL; + err("out of memory for usblp"); + goto abort; } memset(usblp, 0, sizeof(struct usblp)); - init_MUTEX (&usblp->sem); - - /* lookup quirks for this printer */ - quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); - - if (bidir && (quirks & USBLP_QUIRK_BIDIR)) { - bidir = 0; - epread = NULL; - info ("Disabling reads from problem bidirectional printer on usblp%d", - minor); - } - usblp->dev = dev; + init_MUTEX (&usblp->sem); + init_waitqueue_head(&usblp->wait); usblp->ifnum = ifnum; - usblp->minor = minor; - usblp->bidir = bidir; - usblp->quirks = quirks; - init_waitqueue_head(&usblp->wait); + /* Look for a free usblp_table entry. */ + while (usblp_table[usblp->minor]) { + usblp->minor++; + if (usblp->minor >= USBLP_MINORS) { + err("no more free usblp devices"); + goto abort; + } + } usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { err("out of memory"); - kfree(usblp); - return NULL; + goto abort; } usblp->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->readurb) { err("out of memory"); - usb_free_urb(usblp->writeurb); - kfree(usblp); - return NULL; + goto abort; } - if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) { - err("out of memory"); - usb_free_urb(usblp->writeurb); - usb_free_urb(usblp->readurb); - kfree(usblp); - return NULL; + /* Malloc device ID string buffer to the largest expected length, + * since we can re-query it on an ioctl and a dynamic string + * could change in length. */ + if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { + err("out of memory for device_id_string"); + goto abort; } - if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { - err("out of memory"); - usb_free_urb(usblp->writeurb); - usb_free_urb(usblp->readurb); - kfree(usblp); - kfree(buf); - return NULL; + /* Malloc write/read buffers in one chunk. We somewhat wastefully + * malloc both regardless of bidirectionality, because the + * alternate setting can be changed later via an ioctl. */ + if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) { + err("out of memory for buf"); + goto abort; } - FILL_BULK_URB(usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf, 0, usblp_bulk_write, usblp); + /* Lookup quirks for this printer. */ + usblp->quirks = usblp_quirks( + dev->descriptor.idVendor, + dev->descriptor.idProduct); + + /* Analyze and pick initial alternate settings and endpoints. */ + protocol = usblp_select_alts(usblp); + if (protocol < 0) { + dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", + dev->descriptor.idVendor, + dev->descriptor.idProduct); + goto abort; + } - if (bidir) - FILL_BULK_URB(usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp); + /* Setup the selected alternate setting and endpoints. */ + if (usblp_set_protocol(usblp, protocol) < 0) + goto abort; - /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */ - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); - if (err >= 0) { - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; - dbg ("usblp%d Device ID string [%d]=%s", - minor, length, &usblp->device_id_string[2]); - } - else { - err ("usblp%d: error = %d reading IEEE-1284 Device ID string", - minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - } + /* Retrieve and store the device ID string. */ + usblp_cache_device_id_string(usblp); #ifdef DEBUG usblp_check_status(usblp, 0); #endif - sprintf(name, "lp%d", minor); - - /* if we have devfs, create with perms=660 */ + /* If we have devfs, create with perms=660. */ + sprintf(name, "lp%d", usblp->minor); usblp->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, - USBLP_MINOR_BASE + minor, + USBLP_MINOR_BASE + usblp->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &usblp_fops, NULL); - info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", - minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); + info("usblp%d: USB %sdirectional printer dev %d " + "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X", + usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum, + usblp->protocol[usblp->current_protocol].alt_setting, + usblp->current_protocol, usblp->dev->descriptor.idVendor, + usblp->dev->descriptor.idProduct); - return usblp_table[minor] = usblp; + return usblp_table[usblp->minor] = usblp; + +abort: + if (usblp) { + usb_free_urb(usblp->writeurb); + usb_free_urb(usblp->readurb); + if (usblp->buf) kfree(usblp->buf); + if (usblp->device_id_string) kfree(usblp->device_id_string); + kfree(usblp); + } + return NULL; +} + +/* + * We are a "new" style driver with usb_device_id table, + * but our requirements are too intricate for simple match to handle. + * + * The "proto_bias" option may be used to specify the preferred protocol + * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device + * supports the preferred protocol, then we bind to it. + * + * The best interface for us is 7/1/2, because it is compatible + * with a stream of characters. If we find it, we bind to it. + * + * Note that the people from hpoj.sourceforge.net need to be able to + * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. + * + * Failing 7/1/2, we look for 7/1/3, even though it's probably not + * stream-compatible, because this matches the behaviour of the old code. + * + * If nothing else, we bind to 7/1/1 - the unidirectional interface. + */ +static int usblp_select_alts(struct usblp *usblp) +{ + struct usb_interface *if_alt; + struct usb_interface_descriptor *ifd; + struct usb_endpoint_descriptor *epd, *epwrite, *epread; + int p, i, e; + + if_alt = &usblp->dev->actconfig->interface[usblp->ifnum]; + + for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) + usblp->protocol[p].alt_setting = -1; + + /* Find out what we have. */ + for (i = 0; i < if_alt->num_altsetting; i++) { + ifd = &if_alt->altsetting[i]; + + if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1) + continue; + + if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL || + ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL) + continue; + + /* Look for bulk OUT and IN endpoints. */ + epwrite = epread = 0; + for (e = 0; e < ifd->bNumEndpoints; e++) { + epd = &ifd->endpoint[e]; + + if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!= + USB_ENDPOINT_XFER_BULK) + continue; + + if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) { + if (!epwrite) epwrite=epd; + + } else { + if (!epread) epread=epd; + } + } + + /* Ignore buggy hardware without the right endpoints. */ + if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread)) + continue; + + /* Turn off reads for 7/1/1 (unidirectional) interfaces + * and buggy bidirectional printers. */ + if (ifd->bInterfaceProtocol == 1) { + epread = NULL; + } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { + info("Disabling reads from problem bidirectional " + "printer on usblp%d", usblp->minor); + epread = NULL; + } + + usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i; + usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite; + usblp->protocol[ifd->bInterfaceProtocol].epread = epread; + } + + /* If our requested protocol is supported, then use it. */ + if (proto_bias >= USBLP_FIRST_PROTOCOL && + proto_bias <= USBLP_LAST_PROTOCOL && + usblp->protocol[proto_bias].alt_setting != -1) + return proto_bias; + + /* Ordering is important here. */ + if (usblp->protocol[2].alt_setting != -1) return 2; + if (usblp->protocol[1].alt_setting != -1) return 1; + if (usblp->protocol[3].alt_setting != -1) return 3; + + /* If nothing is available, then don't bind to this device. */ + return -1; +} + +static int usblp_set_protocol(struct usblp *usblp, int protocol) +{ + int r, alts; + + if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) + return -EINVAL; + + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) return -EINVAL; + r = usb_set_interface(usblp->dev, usblp->ifnum, alts); + if (r < 0) { + err("can't set desired altsetting %d on interface %d", + alts, usblp->ifnum); + return r; + } + + FILL_BULK_URB(usblp->writeurb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[protocol].epwrite->bEndpointAddress), + usblp->buf, 0, + usblp_bulk_write, usblp); + + usblp->bidir = (usblp->protocol[protocol].epread != 0); + if (usblp->bidir) + FILL_BULK_URB(usblp->readurb, usblp->dev, + usb_rcvbulkpipe(usblp->dev, + usblp->protocol[protocol].epread->bEndpointAddress), + usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, + usblp_bulk_read, usblp); + + usblp->current_protocol = protocol; + dbg("usblp%d set protocol %d", usblp->minor, protocol); + return 0; +} + +/* Retrieves and caches device ID string. + * Returns length, including length bytes but not null terminator. + * On error, returns a negative errno value. */ +static int usblp_cache_device_id_string(struct usblp *usblp) +{ + int err, length; + + err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + if (err < 0) { + dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", + usblp->minor, err); + usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; + return -EIO; + } + + /* First two bytes are length in big-endian. + * They count themselves, and we copy them into + * the user's buffer. */ + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; + if (length < 2) + length = 2; + else if (length >= DEVICE_ID_SIZE) + length = DEVICE_ID_SIZE - 1; + usblp->device_id_string[length] = '\0'; + + dbg("usblp%d Device ID string [len=%d]=\"%s\"", + usblp->minor, length, &usblp->device_id_string[2]); + + return length; } static void usblp_disconnect(struct usb_device *dev, void *ptr) @@ -757,9 +1055,7 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) lock_kernel(); usblp->dev = NULL; - usb_unlink_urb(usblp->writeurb); - if (usblp->bidir) - usb_unlink_urb(usblp->readurb); + usblp_unlink_urbs(usblp); if (!usblp->used) usblp_cleanup (usblp); @@ -794,7 +1090,7 @@ static int __init usblp_init(void) { if (usb_register(&usblp_driver)) return -1; - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_VERSION ": " DRIVER_DESC); return 0; } @@ -808,5 +1104,6 @@ module_exit(usblp_exit); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_PARM(proto_bias, "i"); +MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index f185987c6541..812726b110fa 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -262,7 +262,7 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); /* Throw away data. No better idea what to do with it. */ @@ -331,7 +331,7 @@ static void cyberjack_read_int_callback( struct urb *urb ) if( !old_rdtodo ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if( result ) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); @@ -387,7 +387,7 @@ static void cyberjack_read_bulk_callback (struct urb *urb) /* Continue to read if we have still urbs to do. */ if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); @@ -440,7 +440,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb) port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); /* Throw away data. No better idea what to do with it. */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 621af4d63ebc..a03c9b4a9a1d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -676,7 +676,7 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co oob_port->write_urb->transfer_buffer_length = len; oob_port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) { oob_priv->dp_write_urb_in_use = 1; count -= len; buf += len; @@ -764,7 +764,7 @@ count ); } port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; count -= len; @@ -841,7 +841,7 @@ port_priv->dp_port_num, modem_signals ); oob_port->write_urb->transfer_buffer_length = 8; oob_port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) { oob_priv->dp_write_urb_in_use = 1; port_priv->dp_modem_signals = (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) @@ -962,7 +962,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); /* restart read chain */ if( priv->dp_throttle_restart ) { port->read_urb->dev = port->serial->dev; - ret = usb_submit_urb( port->read_urb, GFP_KERNEL ); + ret = usb_submit_urb( port->read_urb, GFP_ATOMIC ); } /* turn throttle off */ @@ -1323,7 +1323,7 @@ priv->dp_port_num, count, from_user, in_interrupt() ); /* copy in new data */ memcpy( data, from_user ? user_buf : buf, new_len ); - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; ret = new_len; priv->dp_out_buf_len = 0; @@ -1399,7 +1399,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf, priv->dp_out_buf_len ); - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; } @@ -1837,7 +1837,7 @@ dbg( "digi_read_bulk_callback: TOP" ); /* continue read */ urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(urb, GFP_KERNEL)) != 0 ) { + if( (ret=usb_submit_urb(urb, GFP_ATOMIC)) != 0 ) { err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d", ret, priv->dp_port_num ); } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 3a636d7a4740..fa390d5c32cc 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -256,7 +256,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig } if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { err(__FUNCTION__" no more kernel memory..."); goto exit; @@ -288,7 +288,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig urb->transfer_flags |= USB_QUEUE_BULK; /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); bytes_sent = status; @@ -441,7 +441,7 @@ static void empeg_read_bulk_callback (struct urb *urb) port->read_urb->transfer_flags |= USB_QUEUE_BULK; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); @@ -466,7 +466,7 @@ static void empeg_unthrottle (struct usb_serial_port *port) port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 911d3ac53f94..fc07f8f67835 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -469,7 +469,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, port->write_urb->transfer_buffer, count, ftdi_sio_write_bulk_callback, port); - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); return 0; @@ -631,7 +631,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_sio_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 60194ede19d8..393fbafd21e2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -790,7 +790,7 @@ static void edge_interrupt_callback (struct urb *urb) /* we have pending bytes on the bulk in pipe, send a request */ edge_serial->read_urb->dev = edge_serial->serial->dev; - result = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL); + result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result); } @@ -867,7 +867,7 @@ static void edge_bulk_in_callback (struct urb *urb) /* there is, so resubmit our urb */ edge_serial->read_urb->dev = edge_serial->serial->dev; - status = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL); + status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (status) { err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status); } @@ -1435,7 +1435,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge /* build the data header for the buffer and port that we are about to send out */ count = fifo->count; - buffer = kmalloc (count+2, GFP_KERNEL); + buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { err(__FUNCTION__" - no more kernel memory..."); edge_port->write_in_progress = FALSE; @@ -1474,7 +1474,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge urb->transfer_flags |= USB_QUEUE_BULK; urb->dev = edge_serial->serial->dev; - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); @@ -2431,7 +2431,7 @@ static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u dbg(__FUNCTION__" - %d, %d", command, param); - buffer = kmalloc (10, GFP_KERNEL); + buffer = kmalloc (10, GFP_ATOMIC); if (!buffer) { err(__FUNCTION__" - kmalloc(%d) failed.\n", 10); return -ENOMEM; @@ -2467,7 +2467,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); /* Allocate our next urb */ - urb = usb_alloc_urb (0, GFP_KERNEL); + urb = usb_alloc_urb (0, GFP_ATOMIC); if (!urb) return -ENOMEM; @@ -2482,7 +2482,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer urb->transfer_flags |= USB_QUEUE_BULK; edge_port->commandPending = TRUE; - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ @@ -2532,7 +2532,7 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa } // Alloc memory for the string of commands. - cmdBuffer = kmalloc (0x100, GFP_KERNEL); + cmdBuffer = kmalloc (0x100, GFP_ATOMIC); if (!cmdBuffer) { err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100); return -ENOMEM; @@ -2618,7 +2618,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue); // Alloc memory for the string of commands. - cmdBuffer = kmalloc (0x10, GFP_KERNEL); + cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { return -ENOMEM; } diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c839920d236a..c3e9c8791fa9 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -297,7 +297,7 @@ static void ipaq_read_bulk_callback(struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ipaq_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -412,7 +412,7 @@ static int ipaq_write_flush(struct usb_serial_port *port) usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback, port); - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); } diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index f44ae514529a..5a8f68918b67 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -405,7 +405,7 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned = USB_QUEUE_BULK | USB_ZERO_PACKET; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else @@ -515,7 +515,7 @@ static void ir_read_bulk_callback (struct urb *urb) port->read_urb->transfer_flags = USB_QUEUE_BULK; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err("%s - failed resubmitting read urb, error %d", diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index d8d8a2e83bb2..2879204149e1 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -378,7 +378,7 @@ static int keyspan_write(struct usb_serial_port *port, int from_user, this_urb->transfer_flags &= ~USB_ASYNC_UNLINK; this_urb->dev = port->serial->dev; - if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) { dbg("usb_submit_urb(write bulk) failed (%d)\n", err); } p_priv->tx_start_time[flip] = jiffies; @@ -436,7 +436,7 @@ static void usa26_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } return; @@ -535,7 +535,7 @@ static void usa26_instat_callback(struct urb *urb) exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -586,7 +586,7 @@ static void usa28_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } @@ -671,7 +671,7 @@ static void usa28_instat_callback(struct urb *urb) exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -764,7 +764,7 @@ exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -819,7 +819,7 @@ static void usa49_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index ae37c1ff9b86..54b09b26e43c 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -292,7 +292,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port) /* just restart the receive interrupt URB */ dbg("keyspan_pda_rx_unthrottle port %d", port->number); port->interrupt_in_urb->dev = port->serial->dev; - if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) + if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC)) dbg(" usb_submit_urb(read urb) failed"); return; } @@ -584,7 +584,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, priv->tx_room -= count; port->write_urb->dev = port->serial->dev; - rc = usb_submit_urb(port->write_urb, GFP_KERNEL); + rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (rc) { dbg(" usb_submit_urb(write bulk) failed"); goto exit; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 3aa9c40e2c61..5b0e1b944dcb 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -519,7 +519,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, } if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { err(__FUNCTION__ " - no more kernel memory..."); goto exit; @@ -555,7 +555,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, /* send the data out the bulk port */ - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); @@ -721,7 +721,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer_length, klsi_105_read_bulk_callback, port); - rc = usb_submit_urb(port->read_urb, GFP_KERNEL); + rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (rc) err(__FUNCTION__ " - failed resubmitting read urb, error %d", rc); @@ -1019,7 +1019,7 @@ static void klsi_105_unthrottle (struct usb_serial_port *port) dbg(__FUNCTION__ " - port %d", port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 1151d0d2170a..125c4a647ab3 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -470,7 +470,7 @@ static int mct_u232_write (struct usb_serial_port *port, int from_user, port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 2eb34c553790..457984644e9b 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -265,7 +265,7 @@ static void omninet_read_bulk_callback (struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), urb->transfer_buffer, urb->transfer_buffer_length, omninet_read_bulk_callback, port); - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); @@ -316,7 +316,7 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns wport->write_urb->transfer_buffer_length = 64; wport->write_urb->dev = serial->dev; - result = usb_submit_urb(wport->write_urb, GFP_KERNEL); + result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 57dedd00441c..23adb9024f46 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -195,7 +195,7 @@ static int pl2303_write (struct usb_serial_port *port, int from_user, const uns port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else @@ -643,7 +643,7 @@ static void pl2303_read_bulk_callback (struct urb *urb) dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb"); urb->status = 0; urb->dev = serial->dev; - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -668,7 +668,7 @@ static void pl2303_read_bulk_callback (struct urb *urb) /* Schedule the next read _if_ we are still open */ if (port->open_count) { urb->dev = serial->dev; - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } @@ -697,7 +697,7 @@ static void pl2303_write_bulk_callback (struct urb *urb) dbg (__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); port->write_urb->transfer_buffer_length = 1; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting write urb, error %d", result); diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 4746b8107f45..6271ade640d6 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -899,7 +899,7 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns generic_write_bulk_callback), port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else @@ -989,7 +989,7 @@ static void generic_read_bulk_callback (struct urb *urb) ((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_read_bulk_callback), port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 2ac4489b92d8..29415d2e2fb1 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -344,13 +344,13 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig dbg(__FUNCTION__ " - port %d", port->number); - buffer = kmalloc (count, GFP_KERNEL); + buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { err ("out of memory"); return -ENOMEM; } - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { err ("no more free urbs"); kfree (buffer); @@ -377,7 +377,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig urb->transfer_flags |= USB_QUEUE_BULK; /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); count = status; @@ -491,7 +491,7 @@ static void visor_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, visor_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -512,7 +512,7 @@ static void visor_unthrottle (struct usb_serial_port *port) dbg(__FUNCTION__ " - port %d", port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 4485b3d26936..3a1dcf663a3a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -240,7 +240,7 @@ static void command_port_read_callback (struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, command_port_read_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) dbg(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } |
