diff options
Diffstat (limited to 'drivers')
262 files changed, 11686 insertions, 6851 deletions
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 81b248429703..fd1c4ba63367 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -192,18 +192,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) arg.type = ACPI_TYPE_INTEGER; arg.integer.value = sleep_state; - /* Run the _PTS and _GTS methods */ + /* Run the _PTS method */ status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { return_ACPI_STATUS(status); } - status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - return_ACPI_STATUS(status); - } - /* Setup the argument to _SST */ switch (sleep_state) { @@ -234,10 +229,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) "While executing method _SST")); } - /* Disable/Clear all GPEs */ - - status = acpi_hw_disable_all_gpes(); - return_ACPI_STATUS(status); } @@ -262,6 +253,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) struct acpi_bit_register_info *sleep_type_reg_info; struct acpi_bit_register_info *sleep_enable_reg_info; u32 in_value; + struct acpi_object_list arg_list; + union acpi_object arg; acpi_status status; ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); @@ -307,6 +300,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) return_ACPI_STATUS(status); } + /* Execute the _GTS method */ + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = sleep_state; + + status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + return_ACPI_STATUS(status); + } + /* Get current value of PM1A control */ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); @@ -473,17 +478,18 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) /******************************************************************************* * - * FUNCTION: acpi_leave_sleep_state + * FUNCTION: acpi_leave_sleep_state_prep * - * PARAMETERS: sleep_state - Which sleep state we just exited + * PARAMETERS: sleep_state - Which sleep state we are exiting * * RETURN: Status * - * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep - * Called with interrupts ENABLED. + * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a + * sleep. + * Called with interrupts DISABLED. * ******************************************************************************/ -acpi_status acpi_leave_sleep_state(u8 sleep_state) +acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) { struct acpi_object_list arg_list; union acpi_object arg; @@ -493,7 +499,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) u32 PM1Acontrol; u32 PM1Bcontrol; - ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); + ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); /* * Set SLP_TYPE and SLP_EN to state S0. @@ -540,6 +546,41 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) } } + /* Execute the _BFS method */ + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = sleep_state; + + status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS")); + } + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_leave_sleep_state + * + * PARAMETERS: sleep_state - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ +acpi_status acpi_leave_sleep_state(u8 sleep_state) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); + /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; @@ -558,12 +599,6 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) ACPI_EXCEPTION((AE_INFO, status, "During Method _SST")); } - arg.integer.value = sleep_state; - status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS")); - } - /* * GPEs must be enabled before _WAK is called as GPEs * might get fired there diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2c0b6630f8ba..485de1347075 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -26,9 +26,24 @@ u8 sleep_states[ACPI_S_STATE_COUNT]; #ifdef CONFIG_PM_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; +static bool acpi_sleep_finish_wake_up; + +/* + * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we + * allow the user to request that behavior by using the 'acpi_new_pts_ordering' + * kernel command line option that causes the following variable to be set. + */ +static bool new_pts_ordering; + +static int __init acpi_new_pts_ordering(char *str) +{ + new_pts_ordering = true; + return 1; +} +__setup("acpi_new_pts_ordering", acpi_new_pts_ordering); #endif -int acpi_sleep_prepare(u32 acpi_state) +static int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP /* do we have a wakeup address for S2 and S3? */ @@ -44,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state) ACPI_FLUSH_CPU_CACHE(); acpi_enable_wakeup_device_prep(acpi_state); #endif + printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", + acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -63,17 +80,25 @@ static u32 acpi_suspend_states[] = { static int init_8259A_after_S1; /** - * acpi_pm_set_target - Set the target system sleep state to the state + * acpi_pm_begin - Set the target system sleep state to the state * associated with given @pm_state, if supported. */ -static int acpi_pm_set_target(suspend_state_t pm_state) +static int acpi_pm_begin(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; if (sleep_states[acpi_state]) { acpi_target_sleep_state = acpi_state; + if (new_pts_ordering) + return 0; + + error = acpi_sleep_prepare(acpi_state); + if (error) + acpi_target_sleep_state = ACPI_STATE_S0; + else + acpi_sleep_finish_wake_up = true; } else { printk(KERN_ERR "ACPI does not support this state: %d\n", pm_state); @@ -91,12 +116,17 @@ static int acpi_pm_set_target(suspend_state_t pm_state) static int acpi_pm_prepare(void) { - int error = acpi_sleep_prepare(acpi_target_sleep_state); + if (new_pts_ordering) { + int error = acpi_sleep_prepare(acpi_target_sleep_state); - if (error) - acpi_target_sleep_state = ACPI_STATE_S0; + if (error) { + acpi_target_sleep_state = ACPI_STATE_S0; + return error; + } + acpi_sleep_finish_wake_up = true; + } - return error; + return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; } /** @@ -120,10 +150,8 @@ static int acpi_pm_enter(suspend_state_t pm_state) if (acpi_state == ACPI_STATE_S3) { int error = acpi_save_state_mem(); - if (error) { - acpi_target_sleep_state = ACPI_STATE_S0; + if (error) return error; - } } local_irq_save(flags); @@ -139,6 +167,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) break; } + /* Reprogram control registers and execute _BFS */ + acpi_leave_sleep_state_prep(acpi_state); + /* ACPI 3.0 specs (P62) says that it's the responsabilty * of the OSPM to clear the status bit [ implying that the * POWER_BUTTON event should not reach userspace ] @@ -146,6 +177,13 @@ static int acpi_pm_enter(suspend_state_t pm_state) if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) acpi_clear_event(ACPI_EVENT_POWER_BUTTON); + /* + * Disable and clear GPE status before interrupt is enabled. Some GPEs + * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. + * acpi_leave_sleep_state will reenable specific GPEs later + */ + acpi_hw_disable_all_gpes(); + local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -157,7 +195,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) } /** - * acpi_pm_finish - Finish up suspend sequence. + * acpi_pm_finish - Instruct the platform to leave a sleep state. * * This is called after we wake back up (or if entering the sleep state * failed). @@ -174,6 +212,7 @@ static void acpi_pm_finish(void) acpi_set_firmware_waking_vector((acpi_physical_address) 0); acpi_target_sleep_state = ACPI_STATE_S0; + acpi_sleep_finish_wake_up = false; #ifdef CONFIG_X86 if (init_8259A_after_S1) { @@ -183,6 +222,20 @@ static void acpi_pm_finish(void) #endif } +/** + * acpi_pm_end - Finish up suspend sequence. + */ + +static void acpi_pm_end(void) +{ + /* + * This is necessary in case acpi_pm_finish() is not called directly + * during a failing transition to a sleep state. + */ + if (acpi_sleep_finish_wake_up) + acpi_pm_finish(); +} + static int acpi_pm_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -201,10 +254,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) static struct platform_suspend_ops acpi_pm_ops = { .valid = acpi_pm_state_valid, - .set_target = acpi_pm_set_target, + .begin = acpi_pm_begin, .prepare = acpi_pm_prepare, .enter = acpi_pm_enter, .finish = acpi_pm_finish, + .end = acpi_pm_end, }; /* @@ -229,15 +283,36 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION -static int acpi_hibernation_start(void) +static int acpi_hibernation_begin(void) { + int error; + acpi_target_sleep_state = ACPI_STATE_S4; - return 0; + if (new_pts_ordering) + return 0; + + error = acpi_sleep_prepare(ACPI_STATE_S4); + if (error) + acpi_target_sleep_state = ACPI_STATE_S0; + else + acpi_sleep_finish_wake_up = true; + + return error; } static int acpi_hibernation_prepare(void) { - return acpi_sleep_prepare(ACPI_STATE_S4); + if (new_pts_ordering) { + int error = acpi_sleep_prepare(ACPI_STATE_S4); + + if (error) { + acpi_target_sleep_state = ACPI_STATE_S0; + return error; + } + acpi_sleep_finish_wake_up = true; + } + + return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; } static int acpi_hibernation_enter(void) @@ -251,6 +326,8 @@ static int acpi_hibernation_enter(void) acpi_enable_wakeup_device(ACPI_STATE_S4); /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); + /* Reprogram control registers and execute _BFS */ + acpi_leave_sleep_state_prep(ACPI_STATE_S4); local_irq_restore(flags); return ACPI_SUCCESS(status) ? 0 : -EFAULT; @@ -263,15 +340,12 @@ static void acpi_hibernation_leave(void) * enable it here. */ acpi_enable(); + /* Reprogram control registers and execute _BFS */ + acpi_leave_sleep_state_prep(ACPI_STATE_S4); } static void acpi_hibernation_finish(void) { - /* - * If ACPI is not enabled by the BIOS and the boot kernel, we need to - * enable it here. - */ - acpi_enable(); acpi_disable_wakeup_device(ACPI_STATE_S4); acpi_leave_sleep_state(ACPI_STATE_S4); @@ -279,6 +353,17 @@ static void acpi_hibernation_finish(void) acpi_set_firmware_waking_vector((acpi_physical_address) 0); acpi_target_sleep_state = ACPI_STATE_S0; + acpi_sleep_finish_wake_up = false; +} + +static void acpi_hibernation_end(void) +{ + /* + * This is necessary in case acpi_hibernation_finish() is not called + * directly during a failing transition to the sleep state. + */ + if (acpi_sleep_finish_wake_up) + acpi_hibernation_finish(); } static int acpi_hibernation_pre_restore(void) @@ -296,7 +381,8 @@ static void acpi_hibernation_restore_cleanup(void) } static struct platform_hibernation_ops acpi_hibernation_ops = { - .start = acpi_hibernation_start, + .begin = acpi_hibernation_begin, + .end = acpi_hibernation_end, .pre_snapshot = acpi_hibernation_prepare, .finish = acpi_hibernation_finish, .prepare = acpi_hibernation_prepare, @@ -403,6 +489,7 @@ static void acpi_power_off_prepare(void) { /* Prepare to power off the system */ acpi_sleep_prepare(ACPI_STATE_S5); + acpi_hw_disable_all_gpes(); } static void acpi_power_off(void) diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index a2ea125ae2d0..cfaf8f5b0a14 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state); extern void acpi_enable_wakeup_device_prep(u8 sleep_state); extern void acpi_enable_wakeup_device(u8 sleep_state); extern void acpi_disable_wakeup_device(u8 sleep_state); - -extern int acpi_sleep_prepare(u32 acpi_state); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ae19c9b30d15..ba8f7f4dfa11 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -69,7 +69,7 @@ config ATA_PIIX config SATA_MV tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + depends on EXPERIMENTAL help This option enables support for the Marvell Serial ATA family. Currently supports 88SX[56]0[48][01] chips. diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6f089b899a1a..27c8d56111c2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -475,6 +475,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ + { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ + { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index a65c8ae5c461..47892e6f5ded 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -267,6 +267,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller IDE (Tolapai) */ { 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; @@ -1068,7 +1076,7 @@ static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val) iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); } -u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) +static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) { u32 val = 0; int i, mi; diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index a32e3c44a606..7f87f105c2f6 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -299,7 +299,7 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev) */ n6 = num_clocks_min(t6min, fsclk); if (mode >= 0 && mode <= 4 && n6 >= 1) { - pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); + dev_dbg(adev->link->ap->dev, "set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); /* calculate the timing values for register transfers. */ while (mode > 0 && pio_fsclk[mode] > fsclk) mode--; @@ -376,7 +376,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev) mode = adev->dma_mode - XFER_UDMA_0; if (mode >= 0 && mode <= 5) { - pr_debug("set udmamode: mode=%d\n", mode); + dev_dbg(adev->link->ap->dev, "set udmamode: mode=%d\n", mode); /* the most restrictive timing value is t6 and tc, * the DIOW - data hold. If one SCLK pulse is longer * than this minimum value then register @@ -433,7 +433,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev) mode = adev->dma_mode - XFER_MW_DMA_0; if (mode >= 0 && mode <= 2) { - pr_debug("set mdmamode: mode=%d\n", mode); + dev_dbg(adev->link->ap->dev, "set mdmamode: mode=%d\n", mode); /* the most restrictive timing value is tf, the DMACK to * read data released. If one SCLK pulse is longer than * this maximum value then the MDMA mode @@ -697,7 +697,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal); write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam); write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah); - pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X " + dev_dbg(ap->dev, "hob: feat 0x%X nsect 0x%X, lba 0x%X " "0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -711,7 +711,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) write_atapi_register(base, ATA_REG_LBAL, tf->lbal); write_atapi_register(base, ATA_REG_LBAM, tf->lbam); write_atapi_register(base, ATA_REG_LBAH, tf->lbah); - pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + dev_dbg(ap->dev, "feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, tf->lbal, @@ -721,7 +721,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) if (tf->flags & ATA_TFLAG_DEVICE) { write_atapi_register(base, ATA_REG_DEVICE, tf->device); - pr_debug("device 0x%X\n", tf->device); + dev_dbg(ap->dev, "device 0x%X\n", tf->device); } ata_wait_idle(ap); @@ -782,7 +782,7 @@ static void bfin_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command); write_atapi_register(base, ATA_REG_CMD, tf->command); ata_pause(ap); @@ -834,7 +834,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) struct scatterlist *sg; unsigned int si; - pr_debug("in atapi dma setup\n"); + dev_dbg(qc->ap->dev, "in atapi dma setup\n"); /* Program the ATA_CTRL register with dir */ if (qc->tf.flags & ATA_TFLAG_WRITE) { /* fill the ATAPI DMA controller */ @@ -870,7 +870,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) struct scatterlist *sg; unsigned int si; - pr_debug("in atapi dma start\n"); + dev_dbg(qc->ap->dev, "in atapi dma start\n"); if (!(ap->udma_mask || ap->mwdma_mask)) return; @@ -888,7 +888,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) sg_dma_address(sg) + sg_dma_len(sg)); } enable_dma(CH_ATAPI_TX); - pr_debug("enable udma write\n"); + dev_dbg(qc->ap->dev, "enable udma write\n"); /* Send ATA DMA write command */ bfin_exec_command(ap, &qc->tf); @@ -898,7 +898,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) | XFER_DIR)); } else { enable_dma(CH_ATAPI_RX); - pr_debug("enable udma read\n"); + dev_dbg(qc->ap->dev, "enable udma read\n"); /* Send ATA DMA read command */ bfin_exec_command(ap, &qc->tf); @@ -936,7 +936,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc) struct scatterlist *sg; unsigned int si; - pr_debug("in atapi dma stop\n"); + dev_dbg(qc->ap->dev, "in atapi dma stop\n"); if (!(ap->udma_mask || ap->mwdma_mask)) return; @@ -1147,15 +1147,15 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; unsigned short int_status = ATAPI_GET_INT_STATUS(base); - if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) { + if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) host_stat |= ATA_DMA_ACTIVE; - } - if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) { + if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT| + ATAPI_DEV_INT)) host_stat |= ATA_DMA_INTR; - } - if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) { - host_stat |= ATA_DMA_ERR; - } + if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) + host_stat |= ATA_DMA_ERR|ATA_DMA_INTR; + + dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat); return host_stat; } @@ -1213,8 +1213,7 @@ static void bfin_irq_clear(struct ata_port *ap) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - pr_debug("in atapi irq clear\n"); - + dev_dbg(ap->dev, "in atapi irq clear\n"); ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT); @@ -1232,7 +1231,7 @@ static unsigned char bfin_irq_on(struct ata_port *ap) void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; u8 tmp; - pr_debug("in atapi irq on\n"); + dev_dbg(ap->dev, "in atapi irq on\n"); ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; @@ -1255,7 +1254,7 @@ static void bfin_bmdma_freeze(struct ata_port *ap) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - pr_debug("in atapi dma freeze\n"); + dev_dbg(ap->dev, "in atapi dma freeze\n"); ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; @@ -1328,7 +1327,7 @@ static void bfin_error_handler(struct ata_port *ap) static void bfin_port_stop(struct ata_port *ap) { - pr_debug("in atapi port stop\n"); + dev_dbg(ap->dev, "in atapi port stop\n"); if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { free_dma(CH_ATAPI_RX); free_dma(CH_ATAPI_TX); @@ -1337,7 +1336,7 @@ static void bfin_port_stop(struct ata_port *ap) static int bfin_port_start(struct ata_port *ap) { - pr_debug("in atapi port start\n"); + dev_dbg(ap->dev, "in atapi port start\n"); if (!(ap->udma_mask || ap->mwdma_mask)) return 0; @@ -1373,10 +1372,6 @@ static struct scsi_host_template bfin_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, -#ifdef CONFIG_PM - .resume = ata_scsi_device_resume, - .suspend = ata_scsi_device_suspend, -#endif }; static const struct ata_port_operations bfin_pata_ops = { diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index d4590f546c49..7ed279b0a12e 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -229,7 +229,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi return -ENOMEM; /* Perform set up for DMA */ - if (pci_enable_device_bars(pdev, 1<<2)) { + if (pci_enable_device_io(pdev)) { printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n"); return -ENODEV; } diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 1388cef52c07..81ef207f8265 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -26,7 +26,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_sl82c105" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.3.3" enum { /* @@ -206,6 +206,34 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc) sl82c105_set_piomode(ap, qc->dev); } +/** + * sl82c105_qc_defer - implement serialization + * @qc: command + * + * We must issue one command per host not per channel because + * of the reset bug. + * + * Q: is the scsi host lock sufficient ? + */ + +static int sl82c105_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_host *host = qc->ap->host; + struct ata_port *alt = host->ports[1 ^ qc->ap->port_no]; + int rc; + + /* First apply the usual rules */ + rc = ata_std_qc_defer(qc); + if (rc != 0) + return rc; + + /* Now apply serialization rules. Only allow a command if the + other channel state machine is idle */ + if (alt && alt->qc_active) + return ATA_DEFER_PORT; + return 0; +} + static struct scsi_host_template sl82c105_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -245,6 +273,7 @@ static struct ata_port_operations sl82c105_port_ops = { .bmdma_stop = sl82c105_bmdma_stop, .bmdma_status = ata_bmdma_status, + .qc_defer = sl82c105_qc_defer, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -312,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id }; /* for now use only the first port */ const struct ata_port_info *ppi[] = { &info_early, - &ata_dummy_port_info }; + NULL }; u32 val; int rev; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 7e72463a90eb..3c1b5c9027db 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -29,7 +29,13 @@ I distinctly remember a couple workarounds (one related to PCI-X) are still needed. - 4) Add NCQ support (easy to intermediate, once new-EH support appears) + 2) Improve/fix IRQ and error handling sequences. + + 3) ATAPI support (Marvell claims the 60xx/70xx chips can do it). + + 4) Think about TCQ support here, and for libata in general + with controllers that suppport it via host-queuing hardware + (a software-only implementation could be a nightmare). 5) Investigate problems with PCI Message Signalled Interrupts (MSI). @@ -53,8 +59,6 @@ Target mode, for those without docs, is the ability to directly connect two SATA controllers. - 13) Verify that 7042 is fully supported. I only have a 6042. - */ @@ -73,7 +77,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_mv" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.20" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -107,14 +111,12 @@ enum { /* CRQB needs alignment on a 1KB boundary. Size == 1KB * CRPB needs alignment on a 256B boundary. Size == 256B - * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B */ MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH), MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH), - MV_MAX_SG_CT = 176, + MV_MAX_SG_CT = 256, MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), - MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), MV_PORTS_PER_HC = 4, /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ @@ -125,6 +127,9 @@ enum { /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ + /* SoC integrated controllers, no PCI interface */ + MV_FLAG_SOC = (1 << 28), + MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, @@ -170,7 +175,7 @@ enum { PCIE_IRQ_CAUSE_OFS = 0x1900, PCIE_IRQ_MASK_OFS = 0x1910, - PCIE_UNMASK_ALL_IRQS = 0x70a, /* assorted bits */ + PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */ HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, HC_MAIN_IRQ_MASK_OFS = 0x1d64, @@ -210,6 +215,7 @@ enum { /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ SATA_ACTIVE_OFS = 0x350, + SATA_FIS_IRQ_CAUSE_OFS = 0x364, PHY_MODE3 = 0x310, PHY_MODE4 = 0x314, PHY_MODE2 = 0x330, @@ -222,11 +228,11 @@ enum { /* Port registers */ EDMA_CFG_OFS = 0, - EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */ - EDMA_CFG_NCQ = (1 << 5), - EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ - EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ - EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ + EDMA_CFG_Q_DEPTH = 0x1f, /* max device queue depth */ + EDMA_CFG_NCQ = (1 << 5), /* for R/W FPDMA queued */ + EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ + EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ + EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ EDMA_ERR_IRQ_CAUSE_OFS = 0x8, EDMA_ERR_IRQ_MASK_OFS = 0xc, @@ -244,14 +250,33 @@ enum { EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */ EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */ EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */ + EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */ - EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15), + EDMA_ERR_LNK_CTRL_RX_0 = (1 << 13), /* transient: CRC err */ + EDMA_ERR_LNK_CTRL_RX_1 = (1 << 14), /* transient: FIFO err */ + EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15), /* fatal: caught SYNC */ + EDMA_ERR_LNK_CTRL_RX_3 = (1 << 16), /* transient: FIS rx err */ + EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */ + EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */ + EDMA_ERR_LNK_CTRL_TX_0 = (1 << 21), /* transient: CRC err */ + EDMA_ERR_LNK_CTRL_TX_1 = (1 << 22), /* transient: FIFO err */ + EDMA_ERR_LNK_CTRL_TX_2 = (1 << 23), /* transient: caught SYNC */ + EDMA_ERR_LNK_CTRL_TX_3 = (1 << 24), /* transient: caught DMAT */ + EDMA_ERR_LNK_CTRL_TX_4 = (1 << 25), /* transient: FIS collision */ + EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */ + EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */ EDMA_ERR_OVERRUN_5 = (1 << 5), EDMA_ERR_UNDERRUN_5 = (1 << 6), + + EDMA_ERR_IRQ_TRANSIENT = EDMA_ERR_LNK_CTRL_RX_0 | + EDMA_ERR_LNK_CTRL_RX_1 | + EDMA_ERR_LNK_CTRL_RX_3 | + EDMA_ERR_LNK_CTRL_TX, + EDMA_EH_FREEZE = EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | EDMA_ERR_DEV_DCON | @@ -311,12 +336,14 @@ enum { /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ + MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */ MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */ }; #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I) #define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II) #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) +#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC)) enum { /* DMA boundary 0xffff is required by the s/g splitting @@ -379,8 +406,8 @@ struct mv_port_priv { dma_addr_t crqb_dma; struct mv_crpb *crpb; dma_addr_t crpb_dma; - struct mv_sg *sg_tbl; - dma_addr_t sg_tbl_dma; + struct mv_sg *sg_tbl[MV_MAX_Q_DEPTH]; + dma_addr_t sg_tbl_dma[MV_MAX_Q_DEPTH]; unsigned int req_idx; unsigned int resp_idx; @@ -400,6 +427,14 @@ struct mv_host_priv { u32 irq_cause_ofs; u32 irq_mask_ofs; u32 unmask_all_irqs; + /* + * These consistent DMA memory pools give us guaranteed + * alignment for hardware-accessed data structures, + * and less memory waste in accomplishing the alignment. + */ + struct dma_pool *crqb_pool; + struct dma_pool *crpb_pool; + struct dma_pool *sg_tbl_pool; }; struct mv_hw_ops { @@ -411,7 +446,7 @@ struct mv_hw_ops { int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int n_hc); void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio); - void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); + void (*reset_bus)(struct ata_host *host, void __iomem *mmio); }; static void mv_irq_clear(struct ata_port *ap); @@ -425,10 +460,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc); static void mv_qc_prep_iie(struct ata_queued_cmd *qc); static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); static void mv_error_handler(struct ata_port *ap); -static void mv_post_int_cmd(struct ata_queued_cmd *qc); static void mv_eh_freeze(struct ata_port *ap); static void mv_eh_thaw(struct ata_port *ap); -static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void mv6_dev_config(struct ata_device *dev); static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port); @@ -438,7 +472,7 @@ static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int n_hc); static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); -static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio); +static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio); static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port); @@ -448,10 +482,17 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int n_hc); static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); -static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio); +static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio); static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port_no); +static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv, + void __iomem *port_mmio, int want_ncq); +static int __mv_stop_dma(struct ata_port *ap); +/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below + * because we have to allow room for worst case splitting of + * PRDs for 64K boundaries in mv_fill_sg(). + */ static struct scsi_host_template mv5_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -475,7 +516,8 @@ static struct scsi_host_template mv6_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, + .change_queue_depth = ata_scsi_change_queue_depth, + .can_queue = MV_MAX_Q_DEPTH - 1, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = MV_MAX_SG_CT / 2, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, @@ -505,7 +547,6 @@ static const struct ata_port_operations mv5_ops = { .irq_on = ata_irq_on, .error_handler = mv_error_handler, - .post_internal_cmd = mv_post_int_cmd, .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, @@ -517,6 +558,7 @@ static const struct ata_port_operations mv5_ops = { }; static const struct ata_port_operations mv6_ops = { + .dev_config = mv6_dev_config, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -533,9 +575,9 @@ static const struct ata_port_operations mv6_ops = { .irq_on = ata_irq_on, .error_handler = mv_error_handler, - .post_internal_cmd = mv_post_int_cmd, .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, + .qc_defer = ata_std_qc_defer, .scr_read = mv_scr_read, .scr_write = mv_scr_write, @@ -561,9 +603,9 @@ static const struct ata_port_operations mv_iie_ops = { .irq_on = ata_irq_on, .error_handler = mv_error_handler, - .post_internal_cmd = mv_post_int_cmd, .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, + .qc_defer = ata_std_qc_defer, .scr_read = mv_scr_read, .scr_write = mv_scr_write, @@ -592,26 +634,29 @@ static const struct ata_port_info mv_port_info[] = { .port_ops = &mv5_ops, }, { /* chip_604x */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS, + .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | + ATA_FLAG_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv6_ops, }, { /* chip_608x */ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | - MV_FLAG_DUAL_HC, + ATA_FLAG_NCQ | MV_FLAG_DUAL_HC, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv6_ops, }, { /* chip_6042 */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS, + .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | + ATA_FLAG_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, }, { /* chip_7042 */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS, + .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | + ATA_FLAG_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, @@ -648,13 +693,6 @@ static const struct pci_device_id mv_pci_tbl[] = { { } /* terminate list */ }; -static struct pci_driver mv_pci_driver = { - .name = DRV_NAME, - .id_table = mv_pci_tbl, - .probe = mv_init_one, - .remove = ata_pci_remove_one, -}; - static const struct mv_hw_ops mv5xxx_ops = { .phy_errata = mv5_phy_errata, .enable_leds = mv5_enable_leds, @@ -674,45 +712,6 @@ static const struct mv_hw_ops mv6xxx_ops = { }; /* - * module options - */ -static int msi; /* Use PCI msi; either zero (off, default) or non-zero */ - - -/* move to PCI layer or libata core? */ -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} - -/* * Functions */ @@ -815,19 +814,46 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio, * LOCKING: * Inherited from caller. */ -static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv, - struct mv_port_priv *pp) +static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio, + struct mv_port_priv *pp, u8 protocol) { + int want_ncq = (protocol == ATA_PROT_NCQ); + + if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { + int using_ncq = ((pp->pp_flags & MV_PP_FLAG_NCQ_EN) != 0); + if (want_ncq != using_ncq) + __mv_stop_dma(ap); + } if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) { + struct mv_host_priv *hpriv = ap->host->private_data; + int hard_port = mv_hardport_from_port(ap->port_no); + void __iomem *hc_mmio = mv_hc_base_from_port( + ap->host->iomap[MV_PRIMARY_BAR], hard_port); + u32 hc_irq_cause, ipending; + /* clear EDMA event indicators, if any */ - writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS); + writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + + /* clear EDMA interrupt indicator, if any */ + hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); + ipending = (DEV_IRQ << hard_port) | + (CRPB_DMA_DONE << hard_port); + if (hc_irq_cause & ipending) { + writelfl(hc_irq_cause & ~ipending, + hc_mmio + HC_IRQ_CAUSE_OFS); + } + + mv_edma_cfg(pp, hpriv, port_mmio, want_ncq); + + /* clear FIS IRQ Cause */ + writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS); - mv_set_edma_ptrs(base, hpriv, pp); + mv_set_edma_ptrs(port_mmio, hpriv, pp); - writelfl(EDMA_EN, base + EDMA_CMD_OFS); + writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS); pp->pp_flags |= MV_PP_FLAG_EDMA_EN; } - WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS))); + WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS))); } /** @@ -1003,38 +1029,76 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) return -EINVAL; } -static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv, - void __iomem *port_mmio) +static void mv6_dev_config(struct ata_device *adev) { - u32 cfg = readl(port_mmio + EDMA_CFG_OFS); + /* + * We don't have hob_nsect when doing NCQ commands on Gen-II. + * See mv_qc_prep() for more info. + */ + if (adev->flags & ATA_DFLAG_NCQ) + if (adev->max_sectors > ATA_MAX_SECTORS) + adev->max_sectors = ATA_MAX_SECTORS; +} + +static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv, + void __iomem *port_mmio, int want_ncq) +{ + u32 cfg; /* set up non-NCQ EDMA configuration */ - cfg &= ~(1 << 9); /* disable eQue */ + cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */ - if (IS_GEN_I(hpriv)) { - cfg &= ~0x1f; /* clear queue depth */ + if (IS_GEN_I(hpriv)) cfg |= (1 << 8); /* enab config burst size mask */ - } - else if (IS_GEN_II(hpriv)) { - cfg &= ~0x1f; /* clear queue depth */ + else if (IS_GEN_II(hpriv)) cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN; - cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */ - } else if (IS_GEN_IIE(hpriv)) { cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */ cfg |= (1 << 22); /* enab 4-entry host queue cache */ - cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */ cfg |= (1 << 18); /* enab early completion */ cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */ - cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */ - cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */ } + if (want_ncq) { + cfg |= EDMA_CFG_NCQ; + pp->pp_flags |= MV_PP_FLAG_NCQ_EN; + } else + pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN; + writelfl(cfg, port_mmio + EDMA_CFG_OFS); } +static void mv_port_free_dma_mem(struct ata_port *ap) +{ + struct mv_host_priv *hpriv = ap->host->private_data; + struct mv_port_priv *pp = ap->private_data; + int tag; + + if (pp->crqb) { + dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma); + pp->crqb = NULL; + } + if (pp->crpb) { + dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma); + pp->crpb = NULL; + } + /* + * For GEN_I, there's no NCQ, so we have only a single sg_tbl. + * For later hardware, we have one unique sg_tbl per NCQ tag. + */ + for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) { + if (pp->sg_tbl[tag]) { + if (tag == 0 || !IS_GEN_I(hpriv)) + dma_pool_free(hpriv->sg_tbl_pool, + pp->sg_tbl[tag], + pp->sg_tbl_dma[tag]); + pp->sg_tbl[tag] = NULL; + } + } +} + /** * mv_port_start - Port specific init/start routine. * @ap: ATA channel to manipulate @@ -1051,51 +1115,47 @@ static int mv_port_start(struct ata_port *ap) struct mv_host_priv *hpriv = ap->host->private_data; struct mv_port_priv *pp; void __iomem *port_mmio = mv_ap_base(ap); - void *mem; - dma_addr_t mem_dma; unsigned long flags; - int rc; + int tag, rc; pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; - - mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, - GFP_KERNEL); - if (!mem) - return -ENOMEM; - memset(mem, 0, MV_PORT_PRIV_DMA_SZ); + ap->private_data = pp; rc = ata_pad_alloc(ap, dev); if (rc) return rc; - /* First item in chunk of DMA memory: - * 32-slot command request table (CRQB), 32 bytes each in size - */ - pp->crqb = mem; - pp->crqb_dma = mem_dma; - mem += MV_CRQB_Q_SZ; - mem_dma += MV_CRQB_Q_SZ; + pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma); + if (!pp->crqb) + return -ENOMEM; + memset(pp->crqb, 0, MV_CRQB_Q_SZ); - /* Second item: - * 32-slot command response table (CRPB), 8 bytes each in size - */ - pp->crpb = mem; - pp->crpb_dma = mem_dma; - mem += MV_CRPB_Q_SZ; - mem_dma += MV_CRPB_Q_SZ; + pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma); + if (!pp->crpb) + goto out_port_free_dma_mem; + memset(pp->crpb, 0, MV_CRPB_Q_SZ); - /* Third item: - * Table of scatter-gather descriptors (ePRD), 16 bytes each + /* + * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl. + * For later hardware, we need one unique sg_tbl per NCQ tag. */ - pp->sg_tbl = mem; - pp->sg_tbl_dma = mem_dma; + for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) { + if (tag == 0 || !IS_GEN_I(hpriv)) { + pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool, + GFP_KERNEL, &pp->sg_tbl_dma[tag]); + if (!pp->sg_tbl[tag]) + goto out_port_free_dma_mem; + } else { + pp->sg_tbl[tag] = pp->sg_tbl[0]; + pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0]; + } + } spin_lock_irqsave(&ap->host->lock, flags); - mv_edma_cfg(ap, hpriv, port_mmio); - + mv_edma_cfg(pp, hpriv, port_mmio, 0); mv_set_edma_ptrs(port_mmio, hpriv, pp); spin_unlock_irqrestore(&ap->host->lock, flags); @@ -1104,8 +1164,11 @@ static int mv_port_start(struct ata_port *ap) * we'll be unable to send non-data, PIO, etc due to restricted access * to shadow regs. */ - ap->private_data = pp; return 0; + +out_port_free_dma_mem: + mv_port_free_dma_mem(ap); + return -ENOMEM; } /** @@ -1120,6 +1183,7 @@ static int mv_port_start(struct ata_port *ap) static void mv_port_stop(struct ata_port *ap) { mv_stop_dma(ap); + mv_port_free_dma_mem(ap); } /** @@ -1138,7 +1202,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) struct mv_sg *mv_sg, *last_sg = NULL; unsigned int si; - mv_sg = pp->sg_tbl; + mv_sg = pp->sg_tbl[qc->tag]; for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); @@ -1194,7 +1258,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) u16 flags = 0; unsigned in_index; - if (qc->tf.protocol != ATA_PROT_DMA) + if ((qc->tf.protocol != ATA_PROT_DMA) && + (qc->tf.protocol != ATA_PROT_NCQ)) return; /* Fill in command request block @@ -1203,15 +1268,14 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) flags |= CRQB_FLAG_READ; WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); flags |= qc->tag << CRQB_TAG_SHIFT; - flags |= qc->tag << CRQB_IOID_SHIFT; /* 50xx appears to ignore this*/ /* get current queue index from software */ in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK; pp->crqb[in_index].sg_addr = - cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); + cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff); pp->crqb[in_index].sg_addr_hi = - cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); + cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16); pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags); cw = &pp->crqb[in_index].ata_cmd[0]; @@ -1231,13 +1295,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) case ATA_CMD_WRITE_FUA_EXT: mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0); break; -#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ case ATA_CMD_FPDMA_READ: case ATA_CMD_FPDMA_WRITE: mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); break; -#endif /* FIXME: remove this line when NCQ added */ default: /* The only other commands EDMA supports in non-queued and * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none @@ -1286,7 +1348,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) unsigned in_index; u32 flags = 0; - if (qc->tf.protocol != ATA_PROT_DMA) + if ((qc->tf.protocol != ATA_PROT_DMA) && + (qc->tf.protocol != ATA_PROT_NCQ)) return; /* Fill in Gen IIE command request block @@ -1296,15 +1359,14 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); flags |= qc->tag << CRQB_TAG_SHIFT; - flags |= qc->tag << CRQB_IOID_SHIFT; /* "I/O Id" is -really- - what we use as our tag */ + flags |= qc->tag << CRQB_HOSTQ_SHIFT; /* get current queue index from software */ in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK; crqb = (struct mv_crqb_iie *) &pp->crqb[in_index]; - crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); - crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); + crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff); + crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16); crqb->flags = cpu_to_le32(flags); tf = &qc->tf; @@ -1351,10 +1413,10 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; void __iomem *port_mmio = mv_ap_base(ap); struct mv_port_priv *pp = ap->private_data; - struct mv_host_priv *hpriv = ap->host->private_data; u32 in_index; - if (qc->tf.protocol != ATA_PROT_DMA) { + if ((qc->tf.protocol != ATA_PROT_DMA) && + (qc->tf.protocol != ATA_PROT_NCQ)) { /* We're about to send a non-EDMA capable command to the * port. Turn off EDMA so there won't be problems accessing * shadow block, etc registers. @@ -1363,13 +1425,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } - mv_start_dma(port_mmio, hpriv, pp); - - in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK; - - /* until we do queuing, the queue should be empty at this point */ - WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) - >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); + mv_start_dma(ap, port_mmio, pp, qc->tf.protocol); pp->req_idx++; @@ -1437,6 +1493,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ? "dev disconnect" : "dev connect"); + action |= ATA_EH_HARDRESET; } if (IS_GEN_I(hpriv)) { @@ -1465,7 +1522,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) } /* Clear EDMA now that SERR cleanup done */ - writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); if (!err_mask) { err_mask = AC_ERR_OTHER; @@ -1538,23 +1595,17 @@ static void mv_intr_edma(struct ata_port *ap) * support for queueing. this works transparently for * queued and non-queued modes. */ - else if (IS_GEN_II(hpriv)) - tag = (le16_to_cpu(pp->crpb[out_index].id) - >> CRPB_IOID_SHIFT_6) & 0x3f; - - else /* IS_GEN_IIE */ - tag = (le16_to_cpu(pp->crpb[out_index].id) - >> CRPB_IOID_SHIFT_7) & 0x3f; + else + tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f; qc = ata_qc_from_tag(ap, tag); - /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS - * bits (WARNING: might not necessarily be associated - * with this command), which -should- be clear - * if all is well + /* For non-NCQ mode, the lower 8 bits of status + * are from EDMA_ERR_IRQ_CAUSE_OFS, + * which should be zero if all went well. */ status = le16_to_cpu(pp->crpb[out_index].flags); - if (unlikely(status & 0xff)) { + if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) { mv_err_intr(ap, qc); return; } @@ -1715,20 +1766,21 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; unsigned int hc, handled = 0, n_hcs; void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; - u32 irq_stat; + u32 irq_stat, irq_mask; + spin_lock(&host->lock); irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); + irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS); /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault */ - if (!irq_stat || (0xffffffffU == irq_stat)) - return IRQ_NONE; + if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat)) + goto out_unlock; n_hcs = mv_get_hc_count(host->ports[0]->flags); - spin_lock(&host->lock); - if (unlikely(irq_stat & PCI_ERR)) { + if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) { mv_pci_error(host, mmio); handled = 1; goto out_unlock; /* skip all other HC irq handling */ @@ -1799,8 +1851,9 @@ static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) return -EINVAL; } -static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) +static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio) { + struct pci_dev *pdev = to_pci_dev(host->dev); int early_5080; early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0); @@ -1811,7 +1864,7 @@ static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); } - mv_reset_pci_bus(pdev, mmio); + mv_reset_pci_bus(host, mmio); } static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) @@ -1935,9 +1988,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, #undef ZERO #define ZERO(reg) writel(0, mmio + (reg)) -static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) +static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio) { - struct ata_host *host = dev_get_drvdata(&pdev->dev); struct mv_host_priv *hpriv = host->private_data; u32 tmp; @@ -2329,11 +2381,6 @@ static void mv_error_handler(struct ata_port *ap) mv_hardreset, mv_postreset); } -static void mv_post_int_cmd(struct ata_queued_cmd *qc) -{ - mv_stop_dma(qc->ap); -} - static void mv_eh_freeze(struct ata_port *ap) { void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; @@ -2427,8 +2474,8 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); - /* unmask all EDMA error interrupts */ - writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); + /* unmask all non-transient EDMA error interrupts */ + writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS); VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", readl(port_mmio + EDMA_CFG_OFS), @@ -2586,7 +2633,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) static int mv_init_host(struct ata_host *host, unsigned int board_idx) { int rc = 0, n_hc, port, hc; - struct pci_dev *pdev = to_pci_dev(host->dev); void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv = host->private_data; @@ -2607,7 +2653,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) goto done; hpriv->ops->reset_flash(hpriv, mmio); - hpriv->ops->reset_bus(pdev, mmio); + hpriv->ops->reset_bus(host, mmio); hpriv->ops->enable_leds(hpriv, mmio); for (port = 0; port < host->n_ports; port++) { @@ -2630,8 +2676,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) mv_port_init(&ap->ioaddr, port_mmio); +#ifdef CONFIG_PCI ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); +#endif } for (hc = 0; hc < n_hc; hc++) { @@ -2668,6 +2716,55 @@ done: return rc; } +#ifdef CONFIG_PCI +static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +static struct pci_driver mv_pci_driver = { + .name = DRV_NAME, + .id_table = mv_pci_tbl, + .probe = mv_init_one, + .remove = ata_pci_remove_one, +}; + +/* + * module options + */ +static int msi; /* Use PCI msi; either zero (off, default) or non-zero */ + + +/* move to PCI layer or libata core? */ +static int pci_go_64(struct pci_dev *pdev) +{ + int rc; + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { + rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); + return rc; + } + } + } else { + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + return rc; + } + } + + return rc; +} + /** * mv_print_info - Dump key info to kernel log for perusal. * @host: ATA host to print info about @@ -2710,6 +2807,26 @@ static void mv_print_info(struct ata_host *host) scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); } +static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev) +{ + hpriv->crqb_pool = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ, + MV_CRQB_Q_SZ, 0); + if (!hpriv->crqb_pool) + return -ENOMEM; + + hpriv->crpb_pool = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ, + MV_CRPB_Q_SZ, 0); + if (!hpriv->crpb_pool) + return -ENOMEM; + + hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ, + MV_SG_TBL_SZ, 0); + if (!hpriv->sg_tbl_pool) + return -ENOMEM; + + return 0; +} + /** * mv_init_one - handle a positive probe of a Marvell host * @pdev: PCI device found @@ -2755,6 +2872,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + rc = mv_create_dma_pools(hpriv, &pdev->dev); + if (rc) + return rc; + /* initialize adapter */ rc = mv_init_host(host, board_idx); if (rc) @@ -2772,15 +2893,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED, IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht); } +#endif static int __init mv_init(void) { - return pci_register_driver(&mv_pci_driver); + int rc = -ENODEV; +#ifdef CONFIG_PCI + rc = pci_register_driver(&mv_pci_driver); +#endif + return rc; } static void __exit mv_exit(void) { +#ifdef CONFIG_PCI pci_unregister_driver(&mv_pci_driver); +#endif } MODULE_AUTHOR("Brett Russ"); @@ -2789,8 +2917,10 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, mv_pci_tbl); MODULE_VERSION(DRV_VERSION); +#ifdef CONFIG_PCI module_param(msi, int, 0444); MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)"); +#endif module_init(mv_init); module_exit(mv_exit); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index a0f98fdab7a0..bfe92a43cf89 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1011,14 +1011,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) } if (status & (NV_ADMA_STAT_DONE | - NV_ADMA_STAT_CPBERR)) { - u32 check_commands; + NV_ADMA_STAT_CPBERR | + NV_ADMA_STAT_CMD_COMPLETE)) { + u32 check_commands = notifier_clears[i]; int pos, error = 0; - if (ata_tag_valid(ap->link.active_tag)) - check_commands = 1 << ap->link.active_tag; - else - check_commands = ap->link.sactive; + if (status & NV_ADMA_STAT_CPBERR) { + /* Check all active commands */ + if (ata_tag_valid(ap->link.active_tag)) + check_commands = 1 << + ap->link.active_tag; + else + check_commands = ap-> + link.sactive; + } /** Check CPBs for completed commands */ while ((pos = ffs(check_commands)) && !error) { diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index de28dfd3b96c..911208b89259 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o -obj-$(CONFIG_PM_TRACE) += trace.o +obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG diff --git a/drivers/block/ub.c b/drivers/block/ub.c index c6179d6ac6e4..a70c1c29a7aa 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -922,11 +922,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - /* Fill what we shouldn't be filling, because usb-storage did so. */ - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ ub_complete(&sc->work_done); @@ -1313,9 +1308,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg), sg->length, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ @@ -1356,9 +1348,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->recv_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ @@ -1473,9 +1462,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { ub_complete(&sc->work_done); @@ -1953,9 +1939,6 @@ static int ub_sync_reset(struct ub_dev *sc) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { printk(KERN_WARNING @@ -2007,9 +1990,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe, (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) goto err_submit; @@ -2077,9 +2057,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { printk(KERN_WARNING diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index af0561053167..47e5b40510cb 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2787,12 +2787,6 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi, return -ENOSYS; } -static inline -int msf_to_lba(char m, char s, char f) -{ - return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; -} - /* * Required when we need to use READ_10 to issue other than 2048 block * reads diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index d222012c1b0c..bacded0eefab 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -73,6 +73,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf) * @tsk with @loginuid. @buf->mutex must be locked. */ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, + unsigned int sessionid, struct tty_audit_buf *buf) { struct audit_buffer *ab; @@ -85,9 +86,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, if (ab) { char name[sizeof(tsk->comm)]; - audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d " - "minor=%d comm=", tsk->pid, tsk->uid, - loginuid, buf->major, buf->minor); + audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u " + "major=%d minor=%d comm=", tsk->pid, tsk->uid, + loginuid, sessionid, buf->major, buf->minor); get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); @@ -105,8 +106,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, */ static void tty_audit_buf_push_current(struct tty_audit_buf *buf) { - tty_audit_buf_push(current, audit_get_loginuid(current->audit_context), - buf); + uid_t auid = audit_get_loginuid(current); + unsigned int sessionid = audit_get_sessionid(current); + tty_audit_buf_push(current, auid, sessionid, buf); } /** @@ -152,6 +154,11 @@ void tty_audit_fork(struct signal_struct *sig) void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) { struct tty_audit_buf *buf; + /* FIXME I think this is correct. Check against netlink once that is + * I really need to read this code more closely. But that's for + * another patch. + */ + unsigned int sessionid = audit_get_sessionid(tsk); spin_lock_irq(&tsk->sighand->siglock); buf = tsk->signal->tty_audit_buf; @@ -162,7 +169,7 @@ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) return; mutex_lock(&buf->mutex); - tty_audit_buf_push(tsk, loginuid, buf); + tty_audit_buf_push(tsk, loginuid, sessionid, buf); mutex_unlock(&buf->mutex); tty_audit_buf_put(buf); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index e6c4a2b762ec..f5e7a70da831 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -492,7 +492,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, iface->pdev = pdev; iface->bar = bar; - rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar); + rc = pci_enable_device_io(iface->pdev); if (rc) goto errout_free; diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 64df55e20ab5..e42a465f5717 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -206,6 +206,15 @@ config BLK_DEV_IDECD To compile this driver as a module, choose M here: the module will be called ide-cd. +config BLK_DEV_IDECD_VERBOSE_ERRORS + bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED + depends on BLK_DEV_IDECD + default y + help + Turn this on to have the driver print out the meanings of the + ATAPI error codes. This will use up additional 8kB of kernel-space + memory, though. + config BLK_DEV_IDETAPE tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -617,8 +626,8 @@ config BLK_DEV_SC1200 tristate "National SCx200 chipset support" select BLK_DEV_IDEDMA_PCI help - This driver adds support for the built in IDE on the National - SCx200 series of embedded x86 "Geode" systems + This driver adds support for the on-board IDE controller on the + National SCx200 series of embedded x86 "Geode" systems. config BLK_DEV_PIIX tristate "Intel PIIXn chipsets support" @@ -793,22 +802,22 @@ config BLK_DEV_CELLEB depends on PPC_CELLEB select BLK_DEV_IDEDMA_PCI help - This driver provides support for the built-in IDE controller on + This driver provides support for the on-board IDE controller on Toshiba Cell Reference Board. If unsure, say Y. endif config BLK_DEV_IDE_PMAC - tristate "Builtin PowerMac IDE support" + tristate "PowerMac on-board IDE support" depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y help - This driver provides support for the built-in IDE controller on + This driver provides support for the on-board IDE controller on most of the recent Apple Power Macintoshes and PowerBooks. If unsure, say Y. config BLK_DEV_IDE_PMAC_ATA100FIRST - bool "Probe internal ATA/100 (Kauai) first" + bool "Probe on-board ATA/100 (Kauai) first" depends on BLK_DEV_IDE_PMAC help This option will cause the ATA/100 controller found in UniNorth2 @@ -823,7 +832,7 @@ config BLK_DEV_IDEDMA_PMAC depends on BLK_DEV_IDE_PMAC select BLK_DEV_IDEDMA_PCI help - This option allows the driver for the built-in IDE controller on + This option allows the driver for the on-board IDE controller on Power Macintoshes and PowerBooks to use DMA (direct memory access) to transfer data to and from memory. Saying Y is safe and improves performance. @@ -934,7 +943,7 @@ config BLK_DEV_GAYLE help This is the IDE driver for the Amiga Gayle IDE interface. It supports both the `A1200 style' and `A4000 style' of the Gayle IDE interface, - This includes builtin IDE interfaces on some Amiga models (A600, + This includes on-board IDE interfaces on some Amiga models (A600, A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion bus (M-Tech E-Matrix 530 expansion card). Say Y if you have an Amiga with a Gayle IDE interface and want to use @@ -948,10 +957,10 @@ config BLK_DEV_IDEDOUBLER depends on BLK_DEV_GAYLE && EXPERIMENTAL ---help--- This driver provides support for the so-called `IDE doublers' (made - by various manufacturers, e.g. Eyetech) that can be connected to the - builtin IDE interface of some Amiga models. Using such an IDE - doubler, you can connect up to four instead of two IDE devices on - the Amiga's builtin IDE interface. + by various manufacturers, e.g. Eyetech) that can be connected to + the on-board IDE interface of some Amiga models. Using such an IDE + doubler, you can connect up to four instead of two IDE devices to + the Amiga's on-board IDE interface. Note that the normal Amiga Gayle IDE driver may not work correctly if you have an IDE doubler and don't enable this driver! @@ -963,9 +972,9 @@ config BLK_DEV_BUDDHA tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)" depends on ZORRO && EXPERIMENTAL help - This is the IDE driver for the IDE interfaces on the Buddha, - Catweasel and X-Surf expansion boards. It supports up to two interfaces - on the Buddha, three on the Catweasel and two on the X-Surf. + This is the IDE driver for the IDE interfaces on the Buddha, Catweasel + and X-Surf expansion boards. It supports up to two interfaces on the + Buddha, three on the Catweasel and two on the X-Surf. Say Y if you have a Buddha or Catweasel expansion board and want to use IDE devices (hard disks, CD-ROM drives, etc.) that are connected @@ -975,23 +984,23 @@ config BLK_DEV_FALCON_IDE tristate "Falcon IDE interface support" depends on ATARI help - This is the IDE driver for the builtin IDE interface on the Atari + This is the IDE driver for the on-board IDE interface on the Atari Falcon. Say Y if you have a Falcon and want to use IDE devices (hard - disks, CD-ROM drives, etc.) that are connected to the builtin IDE + disks, CD-ROM drives, etc.) that are connected to the on-board IDE interface. config BLK_DEV_MAC_IDE tristate "Macintosh Quadra/Powerbook IDE interface support" depends on MAC help - This is the IDE driver for the builtin IDE interface on some m68k + This is the IDE driver for the on-board IDE interface on some m68k Macintosh models. It supports both the `Quadra style' (used in Quadra/ Centris 630 and Performa 588 models) and `Powerbook style' (used in the Powerbook 150 and 190 models) IDE interface. Say Y if you have such an Macintosh model and want to use IDE devices (hard disks, CD-ROM drives, etc.) that are connected to the - builtin IDE interface. + on-board IDE interface. config BLK_DEV_Q40IDE tristate "Q40/Q60 IDE interface support" @@ -1062,8 +1071,8 @@ config BLK_DEV_ALI14XX boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster I/O speeds to be set as well. See the files - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for - more info. + <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> + for more info. config BLK_DEV_DTC2278 tristate "DTC-2278 support" @@ -1088,8 +1097,8 @@ config BLK_DEV_QD65XX help This driver is enabled at runtime using the "qd65xx.probe" kernel boot parameter. It permits faster I/O speeds to be set. See the - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for - more info. + <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> + for more info. config BLK_DEV_UMC8672 tristate "UMC-8672 support" diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 0d2da89d15cf..a4a4323be911 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -40,8 +40,10 @@ obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o obj-$(CONFIG_IDE_H8300) += h8300/ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o +ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o + obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o -obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o +obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index 45bf9c825f2b..037300fa284c 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -1,5 +1,4 @@ -/* linux/drivers/ide/arm/bast-ide.c - * +/* * Copyright (c) 2003-2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 8a5c7205b77c..8d2cc47a362e 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/arm/icside.c - * * Copyright (c) 1996-2004 Russell King. * * Please note that this platform does not support 32-bit IDE IO. @@ -71,8 +69,6 @@ struct icside_state { void __iomem *irq_port; void __iomem *ioc_base; unsigned int type; - /* parent device... until the IDE core gets one of its own */ - struct device *dev; ide_hwif_t *hwif[2]; }; @@ -206,23 +202,6 @@ static void icside_maskproc(ide_drive_t *drive, int mask) * interfaces use the same IRQ, which should guarantee this. */ -static void icside_build_sglist(ide_drive_t *drive, struct request *rq) -{ - ide_hwif_t *hwif = drive->hwif; - struct icside_state *state = hwif->hwif_data; - struct scatterlist *sg = hwif->sg_table; - - ide_map_sg(drive, rq); - - if (rq_data_dir(rq) == READ) - hwif->sg_dma_direction = DMA_FROM_DEVICE; - else - hwif->sg_dma_direction = DMA_TO_DEVICE; - - hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents, - hwif->sg_dma_direction); -} - /* * Configure the IOMD to give the appropriate timings for the transfer * mode being requested. We take the advice of the ATA standards, and @@ -294,33 +273,32 @@ static void icside_dma_host_set(ide_drive_t *drive, int on) static int icside_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct icside_state *state = hwif->hwif_data; + struct expansion_card *ec = ECARD_DEV(hwif->dev); drive->waiting_for_dma = 0; - disable_dma(ECARD_DEV(state->dev)->dma); + disable_dma(ec->dma); /* Teardown mappings after DMA has completed. */ - dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); + ide_destroy_dmatable(drive); - return get_dma_residue(ECARD_DEV(state->dev)->dma) != 0; + return get_dma_residue(ec->dma) != 0; } static void icside_dma_start(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct icside_state *state = hwif->hwif_data; + struct expansion_card *ec = ECARD_DEV(hwif->dev); /* We can not enable DMA on both channels simultaneously. */ - BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma)); - enable_dma(ECARD_DEV(state->dev)->dma); + BUG_ON(dma_channel_active(ec->dma)); + enable_dma(ec->dma); } static int icside_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct icside_state *state = hwif->hwif_data; + struct expansion_card *ec = ECARD_DEV(hwif->dev); struct request *rq = hwif->hwgroup->rq; unsigned int dma_mode; @@ -332,9 +310,9 @@ static int icside_dma_setup(ide_drive_t *drive) /* * We can not enable DMA on both channels. */ - BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma)); + BUG_ON(dma_channel_active(ec->dma)); - icside_build_sglist(drive, rq); + hwif->sg_nents = ide_build_sglist(drive, rq); /* * Ensure that we have the right interrupt routed. @@ -349,14 +327,14 @@ static int icside_dma_setup(ide_drive_t *drive) /* * Select the correct timing for this drive. */ - set_dma_speed(ECARD_DEV(state->dev)->dma, drive->drive_data); + set_dma_speed(ec->dma, drive->drive_data); /* * Tell the DMA engine about the SG table and * data direction. */ - set_dma_sg(ECARD_DEV(state->dev)->dma, hwif->sg_table, hwif->sg_nents); - set_dma_mode(ECARD_DEV(state->dev)->dma, dma_mode); + set_dma_sg(ec->dma, hwif->sg_table, hwif->sg_nents); + set_dma_mode(ec->dma, dma_mode); drive->waiting_for_dma = 1; @@ -444,6 +422,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e hwif->noprobe = 0; hwif->chipset = ide_acorn; hwif->gendev.parent = &ec->dev; + hwif->dev = &ec->dev; } return hwif; @@ -591,7 +570,6 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id) } state->type = ICS_TYPE_NOTYPE; - state->dev = &ec->dev; idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); if (idmem) { diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index e6b56d1d48f4..c8b6581e624e 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/arm/rapide.c - * * Copyright (c) 1996-2002 Russell King. */ @@ -78,8 +76,8 @@ static void __devexit rapide_remove(struct expansion_card *ec) ecard_set_drvdata(ec, NULL); - /* there must be a better way */ - ide_unregister(hwif - ide_hwifs); + ide_unregister(hwif->index); + ecard_release_resources(ec); } diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 8c3294c4d23e..0640a38ff127 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -1,5 +1,4 @@ -/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $ - * +/* * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. * Copyright (c) 2000-2005 Axis Communications AB diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index 4f6d0191cf6c..02432958dfe1 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -1,5 +1,4 @@ /* - * drivers/ide/h8300/ide-h8300.c * H8/300 generic IDE interface */ diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index e888fc35b27c..68bc61844780 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -1,5 +1,4 @@ /* - * ide-acpi.c * Provides ACPI support for IDE drives. * * Copyright (C) 2005 Intel Corp. diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index bee05a3f52ae..23074e84472e 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1,14 +1,14 @@ /* - * linux/drivers/ide/ide-cd.c + * ATAPI CD-ROM driver. * - * Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov> - * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> - * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * ATAPI CD-ROM driver. To be used with ide.c. * See Documentation/cdrom/ide-cd for usage information. * * Suggestions are welcome. Patches that work are more welcome though. ;-) @@ -19,287 +19,11 @@ * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf * - * Drives that deviate from these standards will be accommodated as much - * as possible via compile time or command-line options. Since I only have - * a few drives, you generally need to send me patches... - * - * ---------------------------------- - * TO DO LIST: - * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on - * boot - * - * ---------------------------------- - * 1.00 Oct 31, 1994 -- Initial version. - * 1.01 Nov 2, 1994 -- Fixed problem with starting request in - * cdrom_check_status. - * 1.03 Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks) - * (from mlord) -- minor changes to cdrom_setup() - * -- renamed ide_dev_s to ide_drive_t, enable irq on command - * 2.00 Nov 27, 1994 -- Generalize packet command interface; - * add audio ioctls. - * 2.01 Dec 3, 1994 -- Rework packet command interface to handle devices - * which send an interrupt when ready for a command. - * 2.02 Dec 11, 1994 -- Cache the TOC in the driver. - * Don't use SCMD_PLAYAUDIO_TI; it's not included - * in the current version of ATAPI. - * Try to use LBA instead of track or MSF addressing - * when possible. - * Don't wait for READY_STAT. - * 2.03 Jan 10, 1995 -- Rewrite block read routines to handle block sizes - * other than 2k and to move multiple sectors in a - * single transaction. - * 2.04 Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives. - * Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for - * help in figuring this out. Ditto for Acer and - * Aztech drives, which seem to have the same problem. - * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml - * 2.05 Jun 8, 1995 -- Don't attempt to retry after an illegal request - * or data protect error. - * Use HWIF and DEV_HWIF macros as in ide.c. - * Always try to do a request_sense after - * a failed command. - * Include an option to give textual descriptions - * of ATAPI errors. - * Fix a bug in handling the sector cache which - * showed up if the drive returned data in 512 byte - * blocks (like Pioneer drives). Thanks to - * Richard Hirst <srh@gpt.co.uk> for diagnosing this. - * Properly supply the page number field in the - * MODE_SELECT command. - * PLAYAUDIO12 is broken on the Aztech; work around it. - * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c - * (my apologies to Scott, but now ide-cd.c is independent) - * 3.00 Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl. - * Implement CDROMREADAUDIO ioctl (UNTESTED). - * Use input_ide_data() and output_ide_data(). - * Add door locking. - * Fix usage count leak in cdrom_open, which happened - * when a read-write mount was attempted. - * Try to load the disk on open. - * Implement CDROMEJECT_SW ioctl (off by default). - * Read total cdrom capacity during open. - * Rearrange logic in cdrom_decode_status. Issue - * request sense commands for failed packet commands - * from here instead of from cdrom_queue_packet_command. - * Fix a race condition in retrieving error information. - * Suppress printing normal unit attention errors and - * some drive not ready errors. - * Implement CDROMVOLREAD ioctl. - * Implement CDROMREADMODE1/2 ioctls. - * Fix race condition in setting up interrupt handlers - * when the `serialize' option is used. - * 3.01 Sep 2, 1995 -- Fix ordering of reenabling interrupts in - * cdrom_queue_request. - * Another try at using ide_[input,output]_data. - * 3.02 Sep 16, 1995 -- Stick total disk capacity in partition table as well. - * Make VERBOSE_IDE_CD_ERRORS dump failed command again. - * Dump out more information for ILLEGAL REQUEST errs. - * Fix handling of errors occurring before the - * packet command is transferred. - * Fix transfers with odd bytelengths. - * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'. - * `DCI-2S10' drives are broken too. - * 3.04 Nov 20, 1995 -- So are Vertos drives. - * 3.05 Dec 1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c - * 3.06 Dec 16, 1995 -- Add support needed for partitions. - * More workarounds for Vertos bugs (based on patches - * from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>). - * Try to eliminate byteorder assumptions. - * Use atapi_cdrom_subchnl struct definition. - * Add STANDARD_ATAPI compilation option. - * 3.07 Jan 29, 1996 -- More twiddling for broken drives: Sony 55D, - * Vertos 300. - * Add NO_DOOR_LOCKING configuration option. - * Handle drive_cmd requests w/NULL args (for hdparm -t). - * Work around sporadic Sony55e audio play problem. - * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix - * problem with "hde=cdrom" with no drive present. -ml - * 3.08 Mar 6, 1996 -- More Vertos workarounds. - * 3.09 Apr 5, 1996 -- Add CDROMCLOSETRAY ioctl. - * Switch to using MSF addressing for audio commands. - * Reformat to match kernel tabbing style. - * Add CDROM_GET_UPC ioctl. - * 3.10 Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI. - * 3.11 Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko@colossus.escape.de> - * to remove redundant verify_area calls. - * 3.12 May 7, 1996 -- Rudimentary changer support. Based on patches - * from Gerhard Zuber <zuber@berlin.snafu.de>. - * Let open succeed even if there's no loaded disc. - * 3.13 May 19, 1996 -- Fixes for changer code. - * 3.14 May 29, 1996 -- Add work-around for Vertos 600. - * (From Hennus Bergman <hennus@sky.ow.nl>.) - * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers - * from Ben Galliart <bgallia@luc.edu> with - * special help from Jeff Lightfoot - * <jeffml@pobox.com> - * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification - * 3.16 Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl. - * 3.17 Sep 17, 1996 -- Tweak audio reads for some drives. - * Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC. - * 3.18 Oct 31, 1996 -- Added module and DMA support. - * - * - * 4.00 Nov 5, 1996 -- New ide-cd maintainer, - * Erik B. Andersen <andersee@debian.org> - * -- Newer Creative drives don't always set the error - * register correctly. Make sure we see media changes - * regardless. - * -- Integrate with generic cdrom driver. - * -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on - * a patch from Ciro Cattuto <>. - * -- Call set_device_ro. - * -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE - * ioctls, based on patch by Erik Andersen - * -- Add some probes of drive capability during setup. - * - * 4.01 Nov 11, 1996 -- Split into ide-cd.c and ide-cd.h - * -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE - * ioctls in favor of a generalized approach - * using the generic cdrom driver. - * -- Fully integrated with the 2.1.X kernel. - * -- Other stuff that I forgot (lots of changes) - * - * 4.02 Dec 01, 1996 -- Applied patch from Gadi Oxman <gadio@netvision.net.il> - * to fix the drive door locking problems. - * - * 4.03 Dec 04, 1996 -- Added DSC overlap support. - * 4.04 Dec 29, 1996 -- Added CDROMREADRAW ioclt based on patch - * by Ales Makarov (xmakarov@sun.felk.cvut.cz) - * - * 4.05 Nov 20, 1997 -- Modified to print more drive info on init - * Minor other changes - * Fix errors on CDROMSTOP (If you have a "Dolphin", - * you must define IHAVEADOLPHIN) - * Added identifier so new Sanyo CD-changer works - * Better detection if door locking isn't supported - * - * 4.06 Dec 17, 1997 -- fixed endless "tray open" messages -ml - * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open" - * 4.08 Dec 18, 1997 -- spew less noise when tray is empty - * -- fix speed display for ACER 24X, 18X - * 4.09 Jan 04, 1998 -- fix handling of the last block so we return - * an end of file instead of an I/O error (Gadi) - * 4.10 Jan 24, 1998 -- fixed a bug so now changers can change to a new - * slot when there is no disc in the current slot. - * -- Fixed a memory leak where info->changer_info was - * malloc'ed but never free'd when closing the device. - * -- Cleaned up the global namespace a bit by making more - * functions static that should already have been. - * 4.11 Mar 12, 1998 -- Added support for the CDROM_SELECT_SPEED ioctl - * based on a patch for 2.0.33 by Jelle Foks - * <jelle@scintilla.utwente.nl>, a patch for 2.0.33 - * by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI - * version, and my own efforts. -erik - * -- Fixed a stupid bug which egcs was kind enough to - * inform me of where "Illegal mode for this track" - * was never returned due to a comparison on data - * types of limited range. - * 4.12 Mar 29, 1998 -- Fixed bug in CDROM_SELECT_SPEED so write speed is - * now set ionly for CD-R and CD-RW drives. I had - * removed this support because it produced errors. - * It produced errors _only_ for non-writers. duh. - * 4.13 May 05, 1998 -- Suppress useless "in progress of becoming ready" - * messages, since this is not an error. - * -- Change error messages to be const - * -- Remove a "\t" which looks ugly in the syslogs - * 4.14 July 17, 1998 -- Change to pointing to .ps version of ATAPI spec - * since the .pdf version doesn't seem to work... - * -- Updated the TODO list to something more current. - * - * 4.15 Aug 25, 1998 -- Updated ide-cd.h to respect mechine endianess, - * patch thanks to "Eddie C. Dost" <ecd@skynet.be> - * - * 4.50 Oct 19, 1998 -- New maintainers! - * Jens Axboe <axboe@image.dk> - * Chris Zwilling <chris@cloudnet.com> - * - * 4.51 Dec 23, 1998 -- Jens Axboe <axboe@image.dk> - * - ide_cdrom_reset enabled since the ide subsystem - * handles resets fine now. <axboe@image.dk> - * - Transfer size fix for Samsung CD-ROMs, thanks to - * "Ville Hallik" <ville.hallik@mail.ee>. - * - other minor stuff. - * - * 4.52 Jan 19, 1999 -- Jens Axboe <axboe@image.dk> - * - Detect DVD-ROM/RAM drives - * - * 4.53 Feb 22, 1999 - Include other model Samsung and one Goldstar - * drive in transfer size limit. - * - Fix the I/O error when doing eject without a medium - * loaded on some drives. - * - CDROMREADMODE2 is now implemented through - * CDROMREADRAW, since many drives don't support - * MODE2 (even though ATAPI 2.6 says they must). - * - Added ignore parameter to ide-cd (as a module), eg - * insmod ide-cd ignore='hda hdb' - * Useful when using ide-cd in conjunction with - * ide-scsi. TODO: non-modular way of doing the - * same. - * - * 4.54 Aug 5, 1999 - Support for MMC2 class commands through the generic - * packet interface to cdrom.c. - * - Unified audio ioctl support, most of it. - * - cleaned up various deprecated verify_area(). - * - Added ide_cdrom_packet() as the interface for - * the Uniform generic_packet(). - * - bunch of other stuff, will fill in logs later. - * - report 1 slot for non-changers, like the other - * cd-rom drivers. don't report select disc for - * non-changers as well. - * - mask out audio playing, if the device can't do it. - * - * 4.55 Sep 1, 1999 - Eliminated the rest of the audio ioctls, except - * for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers - * use this independently of the actual audio handling. - * They will disappear later when I get the time to - * do it cleanly. - * - Minimize the TOC reading - only do it when we - * know a media change has occurred. - * - Moved all the CDROMREADx ioctls to the Uniform layer. - * - Heiko Eißfeldt <heiko@colossus.escape.de> supplied - * some fixes for CDI. - * - CD-ROM leaving door locked fix from Andries - * Brouwer <Andries.Brouwer@cwi.nl> - * - Erik Andersen <andersen@xmission.com> unified - * commands across the various drivers and how - * sense errors are handled. - * - * 4.56 Sep 12, 1999 - Removed changer support - it is now in the - * Uniform layer. - * - Added partition based multisession handling. - * - Mode sense and mode select moved to the - * Uniform layer. - * - Fixed a problem with WPI CDS-32X drive - it - * failed the capabilities - * - * 4.57 Apr 7, 2000 - Fixed sense reporting. - * - Fixed possible oops in ide_cdrom_get_last_session() - * - Fix locking mania and make ide_cdrom_reset relock - * - Stop spewing errors to log when magicdev polls with - * TEST_UNIT_READY on some drives. - * - Various fixes from Tobias Ringstrom: - * tray if it was locked prior to the reset. - * - cdrom_read_capacity returns one frame too little. - * - Fix real capacity reporting. - * - * 4.58 May 1, 2000 - Clean up ACER50 stuff. - * - Fix small problem with ide_cdrom_capacity - * - * 4.59 Aug 11, 2000 - Fix changer problem in cdrom_read_toc, we weren't - * correctly sensing a disc change. - * - Rearranged some code - * - Use extended sense on drives that support it for - * correctly reporting tray status -- from - * Michael D Johnson <johnsom@orst.edu> - * 4.60 Dec 17, 2003 - Add mt rainier support - * - Bump timeout for packet commands, matches sr - * - Odd stuff - * 4.61 Jan 22, 2004 - support hardware sector sizes other than 2kB, - * Pascal Schmidt <der.eremit@email.de> - * - *************************************************************************/ - -#define IDECD_VERSION "4.61" + * For historical changelog please see: + * Documentation/ide/ChangeLog.ide-cd.1994-2004 + */ + +#define IDECD_VERSION "5.00" #include <linux/module.h> #include <linux/types.h> @@ -313,6 +37,7 @@ #include <linux/ide.h> #include <linux/completion.h> #include <linux/mutex.h> +#include <linux/bcd.h> #include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */ @@ -360,11 +85,11 @@ static void ide_cd_put(struct cdrom_info *cd) buffers. */ static void cdrom_saw_media_change (ide_drive_t *drive) { - struct cdrom_info *info = drive->driver_data; - - CDROM_STATE_FLAGS (drive)->media_changed = 1; - CDROM_STATE_FLAGS (drive)->toc_valid = 0; - info->nsectors_buffered = 0; + struct cdrom_info *cd = drive->driver_data; + + cd->cd_flags |= IDE_CD_FLAG_MEDIA_CHANGED; + cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID; + cd->nsectors_buffered = 0; } static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, @@ -465,134 +190,14 @@ void cdrom_analyze_sense_data(ide_drive_t *drive, } } } -#if VERBOSE_IDE_CD_ERRORS - { - int i; - const char *s = "bad sense key!"; - char buf[80]; - - printk ("ATAPI device %s:\n", drive->name); - if (sense->error_code==0x70) - printk(" Error: "); - else if (sense->error_code==0x71) - printk(" Deferred Error: "); - else if (sense->error_code == 0x7f) - printk(" Vendor-specific Error: "); - else - printk(" Unknown Error Type: "); - - if (sense->sense_key < ARRAY_SIZE(sense_key_texts)) - s = sense_key_texts[sense->sense_key]; - - printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); - - if (sense->asc == 0x40) { - sprintf(buf, "Diagnostic failure on component 0x%02x", - sense->ascq); - s = buf; - } else { - int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts); - unsigned long key = (sense->sense_key << 16); - key |= (sense->asc << 8); - if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) - key |= sense->ascq; - s = NULL; - - while (hi > lo) { - mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key || - sense_data_texts[mid].asc_ascq == (0xff0000|key)) { - s = sense_data_texts[mid].text; - break; - } - else if (sense_data_texts[mid].asc_ascq > key) - hi = mid; - else - lo = mid+1; - } - } - - if (s == NULL) { - if (sense->asc > 0x80) - s = "(vendor-specific error)"; - else - s = "(reserved error code)"; - } - - printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", - s, sense->asc, sense->ascq); - - if (failed_command != NULL) { - - int lo=0, mid, hi= ARRAY_SIZE(packet_command_texts); - s = NULL; - - while (hi > lo) { - mid = (lo + hi) / 2; - if (packet_command_texts[mid].packet_command == - failed_command->cmd[0]) { - s = packet_command_texts[mid].text; - break; - } - if (packet_command_texts[mid].packet_command > - failed_command->cmd[0]) - hi = mid; - else - lo = mid+1; - } - - printk (KERN_ERR " The failed \"%s\" packet command was: \n \"", s); - for (i=0; i<sizeof (failed_command->cmd); i++) - printk ("%02x ", failed_command->cmd[i]); - printk ("\"\n"); - } - - /* The SKSV bit specifies validity of the sense_key_specific - * in the next two commands. It is bit 7 of the first byte. - * In the case of NOT_READY, if SKSV is set the drive can - * give us nice ETA readings. - */ - if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { - int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; - printk(KERN_ERR " Command is %02d%% complete\n", progress / 0xffff); - - } - - if (sense->sense_key == ILLEGAL_REQUEST && - (sense->sks[0] & 0x80) != 0) { - printk(KERN_ERR " Error in %s byte %d", - (sense->sks[0] & 0x40) != 0 ? - "command packet" : "command data", - (sense->sks[1] << 8) + sense->sks[2]); - - if ((sense->sks[0] & 0x40) != 0) - printk (" bit %d", sense->sks[0] & 0x07); - printk ("\n"); - } - } - -#else /* not VERBOSE_IDE_CD_ERRORS */ - - /* Suppress printing unit attention and `in progress of becoming ready' - errors when we're not being verbose. */ - - if (sense->sense_key == UNIT_ATTENTION || - (sense->sense_key == NOT_READY && (sense->asc == 4 || - sense->asc == 0x3a))) - return; - - printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", - drive->name, - sense->error_code, sense->sense_key, - sense->asc, sense->ascq); -#endif /* not VERBOSE_IDE_CD_ERRORS */ + ide_cd_log_error(drive->name, failed_command, sense); } /* * Initialize a ide-cd packet command request */ -static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq) +void ide_cd_init_rq(ide_drive_t *drive, struct request *rq) { struct cdrom_info *cd = drive->driver_data; @@ -611,7 +216,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, sense = &info->sense_data; /* stuff the sense request in front of our current request */ - cdrom_prepare_request(drive, rq); + ide_cd_init_rq(drive, rq); rq->data = sense; rq->cmd[0] = GPCMD_REQUEST_SENSE; @@ -718,7 +323,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { /* All other functions, except for READ. */ - unsigned long flags; /* * if we have an error, pass back CHECK_CONDITION as the @@ -756,15 +360,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) * remove failed request completely and end it when the * request sense has completed */ - if (stat & ERR_STAT) { - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - - cdrom_queue_request_sense(drive, rq->sense, rq); - } else - cdrom_end_request(drive, 0); + goto end_request; } else if (blk_fs_request(rq)) { int do_end_request = 0; @@ -844,23 +440,15 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) sense data. We need this in order to perform end of media processing */ - if (do_end_request) { - if (stat & ERR_STAT) { - unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); + if (do_end_request) + goto end_request; - cdrom_queue_request_sense(drive, rq->sense, rq); - } else - cdrom_end_request(drive, 0); - } else { - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if (stat & ERR_STAT) - cdrom_queue_request_sense(drive, NULL, NULL); - } + /* + * If we got a CHECK_CONDITION status, + * queue a request sense command. + */ + if (stat & ERR_STAT) + cdrom_queue_request_sense(drive, NULL, NULL); } else { blk_dump_rq_flags(rq, "ide-cd: bad rq"); cdrom_end_request(drive, 0); @@ -868,6 +456,21 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) /* Retry, or handle the next request. */ return 1; + +end_request: + if (stat & ERR_STAT) { + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); + + cdrom_queue_request_sense(drive, rq->sense, rq); + } else + cdrom_end_request(drive, 0); + + return 1; } static int cdrom_timer_expiry(ide_drive_t *drive) @@ -924,8 +527,8 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, /* Set up the controller registers. */ ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL | IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma); - - if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + + if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) { /* waiting for CDB interrupt, not DMA yet. */ if (info->dma) drive->waiting_for_dma = 0; @@ -951,10 +554,6 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, by cdrom_start_packet_command. HANDLER is the interrupt handler to call when the command completes or there's data ready. */ -/* - * changed 5 parameters to 3 for dvd-ram - * struct packet_command *pc; now packet_command_t *pc; - */ #define ATAPI_MIN_CDB_BYTES 12 static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, struct request *rq, @@ -965,7 +564,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; - if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) { + if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) { /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ @@ -1005,6 +604,27 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, * Block read functions. */ +typedef void (xfer_func_t)(ide_drive_t *, void *, u32); + +static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len) +{ + while (len > 0) { + int dum = 0; + xf(drive, &dum, sizeof(dum)); + len -= sizeof(dum); + } +} + +static void ide_cd_drain_data(ide_drive_t *drive, int nsects) +{ + while (nsects > 0) { + static char dum[SECTOR_SIZE]; + + drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum)); + nsects--; + } +} + /* * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector * buffer. Once the first sector is added, any subsequent sectors are @@ -1043,11 +663,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector, } /* Throw away any remaining data. */ - while (sectors_to_transfer > 0) { - static char dum[SECTOR_SIZE]; - HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum)); - --sectors_to_transfer; - } + ide_cd_drain_data(drive, sectors_to_transfer); } /* @@ -1056,23 +672,25 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector, * ok; nonzero if the request has been terminated. */ static -int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason) +int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw) { - if (ireason == 2) + /* + * ireason == 0: the drive wants to receive data from us + * ireason == 2: the drive is expecting to transfer data to us + */ + if (ireason == (!rw << 1)) return 0; - else if (ireason == 0) { - /* Whoops... The drive is expecting to receive data from us! */ + else if (ireason == (rw << 1)) { + ide_hwif_t *hwif = drive->hwif; + xfer_func_t *xf; + + /* Whoops... */ printk(KERN_ERR "%s: %s: wrong transfer direction!\n", drive->name, __FUNCTION__); - /* Throw some data at the drive so it doesn't hang - and quit this request. */ - while (len > 0) { - int dum = 0; - HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum)); - len -= sizeof (dum); - } - } else if (ireason == 1) { + xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes; + ide_cd_pad_transfer(drive, xf, len); + } else if (rw == 0 && ireason == 1) { /* Some drives (ASUS) seem to tell us that status * info is available. just get it and ignore. */ @@ -1089,137 +707,28 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason) } /* - * Interrupt routine. Called when a read request has completed. + * Assume that the drive will always provide data in multiples of at least + * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */ -static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) +static int ide_cd_check_transfer_size(ide_drive_t *drive, int len) { - int stat; - int ireason, len, sectors_to_transfer, nskip; - struct cdrom_info *info = drive->driver_data; - u8 lowcyl = 0, highcyl = 0; - int dma = info->dma, dma_error = 0; - - struct request *rq = HWGROUP(drive)->rq; - - /* - * handle dma case - */ - if (dma) { - info->dma = 0; - dma_error = HWIF(drive)->ide_dma_end(drive); - if (dma_error) { - printk(KERN_ERR "%s: DMA read error\n", drive->name); - ide_dma_off(drive); - } - } - - if (cdrom_decode_status(drive, 0, &stat)) - return ide_stopped; - - if (dma) { - if (!dma_error) { - ide_end_request(drive, 1, rq->nr_sectors); - return ide_stopped; - } else - return ide_error(drive, "dma error", stat); - } - - /* Read the interrupt reason and the transfer length. */ - ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; - lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); - highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); - - len = lowcyl + (256 * highcyl); - - /* If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) { - /* If we're not done filling the current buffer, complain. - Otherwise, complete the command normally. */ - if (rq->current_nr_sectors > 0) { - printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n", - drive->name, rq->current_nr_sectors); - rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, 0); - } else - cdrom_end_request(drive, 1); - return ide_stopped; - } - - /* Check that the drive is expecting to do the same thing we are. */ - if (cdrom_read_check_ireason (drive, len, ireason)) - return ide_stopped; - - /* Assume that the drive will always provide data in multiples - of at least SECTOR_SIZE, as it gets hairy to keep track - of the transfers otherwise. */ - if ((len % SECTOR_SIZE) != 0) { - printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n", - drive->name, len); - if (CDROM_CONFIG_FLAGS(drive)->limit_nframes) - printk (KERN_ERR " This drive is not supported by this version of the driver\n"); - else { - printk (KERN_ERR " Trying to limit transfer sizes\n"); - CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; - } - cdrom_end_request(drive, 0); - return ide_stopped; - } - - /* The number of sectors we need to read from the drive. */ - sectors_to_transfer = len / SECTOR_SIZE; - - /* First, figure out if we need to bit-bucket - any of the leading sectors. */ - nskip = min_t(int, rq->current_nr_sectors - bio_cur_sectors(rq->bio), sectors_to_transfer); - - while (nskip > 0) { - /* We need to throw away a sector. */ - static char dum[SECTOR_SIZE]; - HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum)); - - --rq->current_nr_sectors; - --nskip; - --sectors_to_transfer; - } + struct cdrom_info *cd = drive->driver_data; - /* Now loop while we still have data to read from the drive. */ - while (sectors_to_transfer > 0) { - int this_transfer; + if ((len % SECTOR_SIZE) == 0) + return 0; - /* If we've filled the present buffer but there's another - chained buffer after it, move on. */ - if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request(drive, 1); + printk(KERN_ERR "%s: %s: Bad transfer size %d\n", + drive->name, __FUNCTION__, len); - /* If the buffers are full, cache the rest of the data in our - internal buffer. */ - if (rq->current_nr_sectors == 0) { - cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); - sectors_to_transfer = 0; - } else { - /* Transfer data to the buffers. - Figure out how many sectors we can transfer - to the current buffer. */ - this_transfer = min_t(int, sectors_to_transfer, - rq->current_nr_sectors); - - /* Read this_transfer sectors - into the current buffer. */ - while (this_transfer > 0) { - HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE); - rq->buffer += SECTOR_SIZE; - --rq->nr_sectors; - --rq->current_nr_sectors; - ++rq->sector; - --this_transfer; - --sectors_to_transfer; - } - } + if (cd->cd_flags & IDE_CD_FLAG_LIMIT_NFRAMES) + printk(KERN_ERR " This drive is not supported by " + "this version of the driver\n"); + else { + printk(KERN_ERR " Trying to limit transfer sizes\n"); + cd->cd_flags |= IDE_CD_FLAG_LIMIT_NFRAMES; } - /* Done moving data! Wait for another interrupt. */ - ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL); - return ide_started; + return 1; } /* @@ -1281,48 +790,58 @@ static int cdrom_read_from_buffer (ide_drive_t *drive) return 0; } +static ide_startstop_t cdrom_newpc_intr(ide_drive_t *); + /* - * Routine to send a read packet command to the drive. - * This is usually called directly from cdrom_start_read. + * Routine to send a read/write packet command to the drive. + * This is usually called directly from cdrom_start_{read,write}(). * However, for drq_interrupt devices, it is called from an interrupt * when the drive is ready to accept the command. */ -static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive) +static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; - unsigned short sectors_per_frame; - int nskip; - sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS; + if (rq_data_dir(rq) == READ) { + unsigned short sectors_per_frame = + queue_hardsect_size(drive->queue) >> SECTOR_BITS; + int nskip = rq->sector & (sectors_per_frame - 1); - /* If the requested sector doesn't start on a cdrom block boundary, - we must adjust the start of the transfer so that it does, - and remember to skip the first few sectors. - If the CURRENT_NR_SECTORS field is larger than the size - of the buffer, it will mean that we're to skip a number - of sectors equal to the amount by which CURRENT_NR_SECTORS - is larger than the buffer size. */ - nskip = rq->sector & (sectors_per_frame - 1); - if (nskip > 0) { - /* Sanity check... */ - if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) && - (rq->sector & (sectors_per_frame - 1))) { - printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n", - drive->name, rq->current_nr_sectors); - cdrom_end_request(drive, 0); - return ide_stopped; + /* + * If the requested sector doesn't start on a frame boundary, + * we must adjust the start of the transfer so that it does, + * and remember to skip the first few sectors. + * + * If the rq->current_nr_sectors field is larger than the size + * of the buffer, it will mean that we're to skip a number of + * sectors equal to the amount by which rq->current_nr_sectors + * is larger than the buffer size. + */ + if (nskip > 0) { + /* Sanity check... */ + if (rq->current_nr_sectors != + bio_cur_sectors(rq->bio)) { + printk(KERN_ERR "%s: %s: buffer botch (%u)\n", + drive->name, __FUNCTION__, + rq->current_nr_sectors); + cdrom_end_request(drive, 0); + return ide_stopped; + } + rq->current_nr_sectors += nskip; } - rq->current_nr_sectors += nskip; } - +#if 0 + else + /* the immediate bit */ + rq->cmd[1] = 1 << 3; +#endif /* Set up the command */ rq->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr); + return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr); } - #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ #define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */ @@ -1335,7 +854,8 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) if (cdrom_decode_status(drive, 0, &stat)) return ide_stopped; - CDROM_CONFIG_FLAGS(drive)->seeking = 1; + + info->cd_flags |= IDE_CD_FLAG_SEEKING; if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) { if (--retry == 0) { @@ -1391,184 +911,25 @@ static void restore_request (struct request *rq) rq->q->prep_rq_fn(rq->q, rq); } -/* - * Start a read request from the CD-ROM. - */ -static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) -{ - struct cdrom_info *info = drive->driver_data; - struct request *rq = HWGROUP(drive)->rq; - unsigned short sectors_per_frame; - - sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS; - - /* We may be retrying this request after an error. Fix up - any weirdness which might be present in the request packet. */ - restore_request(rq); - - /* Satisfy whatever we can of this request from our cached sector. */ - if (cdrom_read_from_buffer(drive)) - return ide_stopped; - - /* Clear the local sector buffer. */ - info->nsectors_buffered = 0; - - /* use dma, if possible. */ - info->dma = drive->using_dma; - if ((rq->sector & (sectors_per_frame - 1)) || - (rq->nr_sectors & (sectors_per_frame - 1))) - info->dma = 0; - - /* Start sending the read request to the drive. */ - return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); -} - /**************************************************************************** * Execute all other packet commands. */ -/* Interrupt routine for packet command completion. */ -static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) +static void ide_cd_request_sense_fixup(struct request *rq) { - int ireason, len, thislen; - struct request *rq = HWGROUP(drive)->rq; - u8 lowcyl = 0, highcyl = 0; - int stat; - - /* Check for errors. */ - if (cdrom_decode_status(drive, 0, &stat)) - return ide_stopped; - - /* Read the interrupt reason and the transfer length. */ - ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; - lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); - highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); - - len = lowcyl + (256 * highcyl); - - /* If DRQ is clear, the command has completed. - Complain if we still have data left to transfer. */ - if ((stat & DRQ_STAT) == 0) { - /* Some of the trailing request sense fields are optional, and - some drives don't send them. Sigh. */ - if (rq->cmd[0] == GPCMD_REQUEST_SENSE && - rq->data_len > 0 && - rq->data_len <= 5) { - while (rq->data_len > 0) { - *(unsigned char *)rq->data++ = 0; - --rq->data_len; - } - } - - if (rq->data_len == 0) - cdrom_end_request(drive, 1); - else { - /* Comment this out, because this always happens - right after a reset occurs, and it is annoying to - always print expected stuff. */ - /* - printk ("%s: cdrom_pc_intr: data underrun %d\n", - drive->name, pc->buflen); - */ - rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, 0); - } - return ide_stopped; - } - - /* Figure out how much data to transfer. */ - thislen = rq->data_len; - if (thislen > len) thislen = len; - - /* The drive wants to be written to. */ - if (ireason == 0) { - if (!rq->data) { - blk_dump_rq_flags(rq, "cdrom_pc_intr, write"); - goto confused; - } - /* Transfer the data. */ - HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen); - - /* If we haven't moved enough data to satisfy the drive, - add some padding. */ - while (len > thislen) { - int dum = 0; - HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum)); - len -= sizeof(dum); - } - - /* Keep count of how much data we've moved. */ - rq->data += thislen; - rq->data_len -= thislen; - } - - /* Same drill for reading. */ - else if (ireason == 2) { - if (!rq->data) { - blk_dump_rq_flags(rq, "cdrom_pc_intr, read"); - goto confused; - } - /* Transfer the data. */ - HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen); - - /* If we haven't moved enough data to satisfy the drive, - add some padding. */ - while (len > thislen) { - int dum = 0; - HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum)); - len -= sizeof(dum); + /* + * Some of the trailing request sense fields are optional, + * and some drives don't send them. Sigh. + */ + if (rq->cmd[0] == GPCMD_REQUEST_SENSE && + rq->data_len > 0 && rq->data_len <= 5) + while (rq->data_len > 0) { + *(u8 *)rq->data++ = 0; + --rq->data_len; } - - /* Keep count of how much data we've moved. */ - rq->data += thislen; - rq->data_len -= thislen; - - if (blk_sense_request(rq)) - rq->sense_len += thislen; - } else { -confused: - printk (KERN_ERR "%s: cdrom_pc_intr: The drive " - "appears confused (ireason = 0x%02x). " - "Trying to recover by ending request.\n", - drive->name, ireason); - rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, 0); - return ide_stopped; - } - - /* Now we wait for another interrupt. */ - ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry); - return ide_started; } -static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - - if (!rq->timeout) - rq->timeout = ATAPI_WAIT_PC; - - /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr); -} - - -static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive) -{ - int len; - struct request *rq = HWGROUP(drive)->rq; - struct cdrom_info *info = drive->driver_data; - - info->dma = 0; - rq->cmd_flags &= ~REQ_FAILED; - len = rq->data_len; - - /* Start sending the command to the drive. */ - return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation); -} - - -static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) +int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq) { struct request_sense sense; int retries = 10; @@ -1617,37 +978,6 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) } /* - * Write handling - */ -static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason) -{ - /* Two notes about IDE interrupt reason here - 0 means that - * the drive wants to receive data from us, 2 means that - * the drive is expecting to transfer data to us. - */ - if (ireason == 0) - return 0; - else if (ireason == 2) { - /* Whoops... The drive wants to send data. */ - printk(KERN_ERR "%s: %s: wrong transfer direction!\n", - drive->name, __FUNCTION__); - - while (len > 0) { - int dum = 0; - HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum)); - len -= sizeof(dum); - } - } else { - /* Drive wants a command packet, or invalid ireason... */ - printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n", - drive->name, __FUNCTION__, ireason); - } - - cdrom_end_request(drive, 0); - return 1; -} - -/* * Called from blk_end_request_callback() after the data of the request * is completed and before the request is completed. * By returning value '1', blk_end_request_callback() returns immediately @@ -1658,29 +988,27 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq) return 1; } -typedef void (xfer_func_t)(ide_drive_t *, void *, u32); - -/* - * best way to deal with dma that is not sector aligned right now... note - * that in this path we are not using ->data or ->buffer at all. this irs - * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the - * future. - */ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; - int dma_error, dma, stat, ireason, len, thislen; - u8 lowcyl, highcyl; xfer_func_t *xferfunc; - unsigned long flags; + ide_expiry_t *expiry = NULL; + int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0; + int write = (rq_data_dir(rq) == WRITE) ? 1 : 0; + unsigned int timeout; + u8 lowcyl, highcyl; /* Check for errors. */ - dma_error = 0; dma = info->dma; if (dma) { info->dma = 0; dma_error = HWIF(drive)->ide_dma_end(drive); + if (dma_error) { + printk(KERN_ERR "%s: DMA %s error\n", drive->name, + write ? "write" : "read"); + ide_dma_off(drive); + } } if (cdrom_decode_status(drive, 0, &stat)) @@ -1690,19 +1018,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) * using dma, transfer is complete now */ if (dma) { - if (dma_error) { - printk(KERN_ERR "ide-cd: dma error\n"); - ide_dma_off(drive); + if (dma_error) return ide_error(drive, "dma error", stat); + if (blk_fs_request(rq)) { + ide_end_request(drive, 1, rq->nr_sectors); + return ide_stopped; } - - spin_lock_irqsave(&ide_lock, flags); - if (__blk_end_request(rq, 0, rq->data_len)) - BUG(); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - - return ide_stopped; + goto end_request; } /* @@ -1713,7 +1035,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); len = lowcyl + (256 * highcyl); - thislen = rq->data_len; + + thislen = blk_fs_request(rq) ? len : rq->data_len; if (thislen > len) thislen = len; @@ -1721,53 +1044,111 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) * If DRQ is clear, the command has completed. */ if ((stat & DRQ_STAT) == 0) { - spin_lock_irqsave(&ide_lock, flags); - if (__blk_end_request(rq, 0, rq->data_len)) - BUG(); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - - return ide_stopped; + if (blk_fs_request(rq)) { + /* + * If we're not done reading/writing, complain. + * Otherwise, complete the command normally. + */ + uptodate = 1; + if (rq->current_nr_sectors > 0) { + printk(KERN_ERR "%s: %s: data underrun " + "(%d blocks)\n", + drive->name, __FUNCTION__, + rq->current_nr_sectors); + if (!write) + rq->cmd_flags |= REQ_FAILED; + uptodate = 0; + } + cdrom_end_request(drive, uptodate); + return ide_stopped; + } else if (!blk_pc_request(rq)) { + ide_cd_request_sense_fixup(rq); + /* Complain if we still have data left to transfer. */ + uptodate = rq->data_len ? 0 : 1; + } + goto end_request; } /* * check which way to transfer data */ - if (rq_data_dir(rq) == WRITE) { - /* - * write to drive - */ - if (cdrom_write_check_ireason(drive, len, ireason)) + if (blk_fs_request(rq) || blk_pc_request(rq)) { + if (ide_cd_check_ireason(drive, len, ireason, write)) return ide_stopped; - xferfunc = HWIF(drive)->atapi_output_bytes; - } else { - /* - * read from drive - */ - if (cdrom_read_check_ireason(drive, len, ireason)) - return ide_stopped; + if (blk_fs_request(rq) && write == 0) { + int nskip; + if (ide_cd_check_transfer_size(drive, len)) { + cdrom_end_request(drive, 0); + return ide_stopped; + } + + /* + * First, figure out if we need to bit-bucket + * any of the leading sectors. + */ + nskip = min_t(int, rq->current_nr_sectors + - bio_cur_sectors(rq->bio), + thislen >> 9); + if (nskip > 0) { + ide_cd_drain_data(drive, nskip); + rq->current_nr_sectors -= nskip; + thislen -= (nskip << 9); + } + } + } + + if (ireason == 0) { + write = 1; + xferfunc = HWIF(drive)->atapi_output_bytes; + } else if (ireason == 2 || (ireason == 1 && + (blk_fs_request(rq) || blk_pc_request(rq)))) { + write = 0; xferfunc = HWIF(drive)->atapi_input_bytes; + } else { + printk(KERN_ERR "%s: %s: The drive " + "appears confused (ireason = 0x%02x). " + "Trying to recover by ending request.\n", + drive->name, __FUNCTION__, ireason); + goto end_request; } /* * transfer data */ while (thislen > 0) { - int blen = blen = rq->data_len; - char *ptr = rq->data; + u8 *ptr = blk_fs_request(rq) ? NULL : rq->data; + int blen = rq->data_len; /* * bio backed? */ if (rq->bio) { - ptr = bio_data(rq->bio); - blen = bio_iovec(rq->bio)->bv_len; + if (blk_fs_request(rq)) { + ptr = rq->buffer; + blen = rq->current_nr_sectors << 9; + } else { + ptr = bio_data(rq->bio); + blen = bio_iovec(rq->bio)->bv_len; + } } if (!ptr) { - printk(KERN_ERR "%s: confused, missing data\n", drive->name); + if (blk_fs_request(rq) && !write) + /* + * If the buffers are full, cache the rest + * of the data in our internal buffer. + */ + cdrom_buffer_sectors(drive, rq->sector, + thislen >> 9); + else { + printk(KERN_ERR "%s: confused, missing data\n", + drive->name); + blk_dump_rq_flags(rq, rq_data_dir(rq) + ? "cdrom_newpc_intr, write" + : "cdrom_newpc_intr, read"); + } break; } @@ -1778,185 +1159,117 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) thislen -= blen; len -= blen; - rq->data_len -= blen; - if (rq->bio) + if (blk_fs_request(rq)) { + rq->buffer += blen; + rq->nr_sectors -= (blen >> 9); + rq->current_nr_sectors -= (blen >> 9); + rq->sector += (blen >> 9); + + if (rq->current_nr_sectors == 0 && rq->nr_sectors) + cdrom_end_request(drive, 1); + } else { + rq->data_len -= blen; + /* * The request can't be completed until DRQ is cleared. * So complete the data, but don't complete the request * using the dummy function for the callback feature * of blk_end_request_callback(). */ - blk_end_request_callback(rq, 0, blen, + if (rq->bio) + blk_end_request_callback(rq, 0, blen, cdrom_newpc_intr_dummy_cb); - else - rq->data += blen; - } - - /* - * pad, if necessary - */ - if (len > 0) { - while (len > 0) { - int pad = 0; - - xferfunc(drive, &pad, sizeof(pad)); - len -= sizeof(pad); - } - } - - BUG_ON(HWGROUP(drive)->handler != NULL); - - ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL); - return ide_started; -} - -static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) -{ - int stat, ireason, len, sectors_to_transfer, uptodate; - struct cdrom_info *info = drive->driver_data; - int dma_error = 0, dma = info->dma; - u8 lowcyl = 0, highcyl = 0; - - struct request *rq = HWGROUP(drive)->rq; - - /* Check for errors. */ - if (dma) { - info->dma = 0; - dma_error = HWIF(drive)->ide_dma_end(drive); - if (dma_error) { - printk(KERN_ERR "%s: DMA write error\n", drive->name); - ide_dma_off(drive); + else + rq->data += blen; } } - if (cdrom_decode_status(drive, 0, &stat)) - return ide_stopped; + if (write && blk_sense_request(rq)) + rq->sense_len += thislen; /* - * using dma, transfer is complete now + * pad, if necessary */ - if (dma) { - if (dma_error) - return ide_error(drive, "dma error", stat); + if (!blk_fs_request(rq) && len > 0) + ide_cd_pad_transfer(drive, xferfunc, len); - ide_end_request(drive, 1, rq->nr_sectors); - return ide_stopped; + if (blk_pc_request(rq)) { + timeout = rq->timeout; + } else { + timeout = ATAPI_WAIT_PC; + if (!blk_fs_request(rq)) + expiry = cdrom_timer_expiry; } - /* Read the interrupt reason and the transfer length. */ - ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; - lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); - highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); + ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry); + return ide_started; - len = lowcyl + (256 * highcyl); +end_request: + if (blk_pc_request(rq)) { + unsigned long flags; - /* If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) { - /* If we're not done writing, complain. - * Otherwise, complete the command normally. - */ - uptodate = 1; - if (rq->current_nr_sectors > 0) { - printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n", - drive->name, __FUNCTION__, - rq->current_nr_sectors); - uptodate = 0; - } + spin_lock_irqsave(&ide_lock, flags); + if (__blk_end_request(rq, 0, rq->data_len)) + BUG(); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); + } else { + if (!uptodate) + rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, uptodate); - return ide_stopped; } + return ide_stopped; +} - /* Check that the drive is expecting to do the same thing we are. */ - if (cdrom_write_check_ireason(drive, len, ireason)) - return ide_stopped; - - sectors_to_transfer = len / SECTOR_SIZE; - - /* - * now loop and write out the data - */ - while (sectors_to_transfer > 0) { - int this_transfer; - - if (!rq->current_nr_sectors) { - printk(KERN_ERR "%s: %s: confused, missing data\n", - drive->name, __FUNCTION__); - break; - } +static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) +{ + struct cdrom_info *cd = drive->driver_data; + int write = rq_data_dir(rq) == WRITE; + unsigned short sectors_per_frame = + queue_hardsect_size(drive->queue) >> SECTOR_BITS; + if (write) { /* - * Figure out how many sectors we can transfer + * disk has become write protected */ - this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors); - - while (this_transfer > 0) { - HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE); - rq->buffer += SECTOR_SIZE; - --rq->nr_sectors; - --rq->current_nr_sectors; - ++rq->sector; - --this_transfer; - --sectors_to_transfer; + if (cd->disk->policy) { + cdrom_end_request(drive, 0); + return ide_stopped; } - + } else { /* - * current buffer complete, move on + * We may be retrying this request after an error. Fix up any + * weirdness which might be present in the request packet. */ - if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request(drive, 1); - } - - /* re-arm handler */ - ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL); - return ide_started; -} - -static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; + restore_request(rq); -#if 0 /* the immediate bit */ - rq->cmd[1] = 1 << 3; -#endif - rq->timeout = ATAPI_WAIT_PC; - - return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr); -} - -static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) -{ - struct cdrom_info *info = drive->driver_data; - struct gendisk *g = info->disk; - unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS; + /* Satisfy whatever we can of this request from our cache. */ + if (cdrom_read_from_buffer(drive)) + return ide_stopped; + } /* - * writes *must* be hardware frame aligned + * use DMA, if possible / writes *must* be hardware frame aligned */ if ((rq->nr_sectors & (sectors_per_frame - 1)) || (rq->sector & (sectors_per_frame - 1))) { - cdrom_end_request(drive, 0); - return ide_stopped; - } - - /* - * disk has become write protected - */ - if (g->policy) { - cdrom_end_request(drive, 0); - return ide_stopped; - } - - info->nsectors_buffered = 0; + if (write) { + cdrom_end_request(drive, 0); + return ide_stopped; + } + cd->dma = 0; + } else + cd->dma = drive->using_dma; - /* use dma, if possible. we don't need to check more, since we - * know that the transfer is always (at least!) frame aligned */ - info->dma = drive->using_dma ? 1 : 0; + /* Clear the local sector buffer. */ + cd->nsectors_buffered = 0; - info->devinfo.media_written = 1; + if (write) + cd->devinfo.media_written = 1; - /* Start sending the write request to the drive. */ - return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); + /* Start sending the read/write request to the drive. */ + return cdrom_start_packet_command(drive, 32768, cdrom_start_rw_cont); } static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive) @@ -1973,7 +1286,10 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) { struct cdrom_info *info = drive->driver_data; - rq->cmd_flags |= REQ_QUIET; + if (blk_pc_request(rq)) + rq->cmd_flags |= REQ_QUIET; + else + rq->cmd_flags &= ~REQ_FAILED; info->dma = 0; @@ -2010,7 +1326,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) struct cdrom_info *info = drive->driver_data; if (blk_fs_request(rq)) { - if (CDROM_CONFIG_FLAGS(drive)->seeking) { + if (info->cd_flags & IDE_CD_FLAG_SEEKING) { unsigned long elapsed = jiffies - info->start_seek; int stat = HWIF(drive)->INB(IDE_STATUS_REG); @@ -2021,22 +1337,16 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) } printk (KERN_ERR "%s: DSC timeout\n", drive->name); } - CDROM_CONFIG_FLAGS(drive)->seeking = 0; + info->cd_flags &= ~IDE_CD_FLAG_SEEKING; } if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) { action = cdrom_start_seek(drive, block); - } else { - if (rq_data_dir(rq) == READ) - action = cdrom_start_read(drive, block); - else - action = cdrom_start_write(drive, rq); - } + } else + action = cdrom_start_rw(drive, rq); info->last_block = block; return action; - } else if (rq->cmd_type == REQ_TYPE_SENSE || + } else if (blk_sense_request(rq) || blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { - return cdrom_do_packet_command(drive); - } else if (blk_pc_request(rq)) { return cdrom_do_block_pc(drive, rq); } else if (blk_special_request(rq)) { /* @@ -2063,141 +1373,33 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) * can also be NULL, in which case no sense information is returned. */ -#if ! STANDARD_ATAPI -static inline -int bin2bcd (int x) -{ - return (x%10) | ((x/10) << 4); -} - - -static inline -int bcd2bin (int x) -{ - return (x >> 4) * 10 + (x & 0x0f); -} - static void msf_from_bcd (struct atapi_msf *msf) { - msf->minute = bcd2bin (msf->minute); - msf->second = bcd2bin (msf->second); - msf->frame = bcd2bin (msf->frame); -} - -#endif /* not STANDARD_ATAPI */ - - -static inline -void lba_to_msf (int lba, byte *m, byte *s, byte *f) -{ - lba += CD_MSF_OFFSET; - lba &= 0xffffff; /* negative lbas use only 24 bits */ - *m = lba / (CD_SECS * CD_FRAMES); - lba %= (CD_SECS * CD_FRAMES); - *s = lba / CD_FRAMES; - *f = lba % CD_FRAMES; -} - - -static inline -int msf_to_lba (byte m, byte s, byte f) -{ - return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; + msf->minute = BCD2BIN(msf->minute); + msf->second = BCD2BIN(msf->second); + msf->frame = BCD2BIN(msf->frame); } -static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) +int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) { struct request req; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; - cdrom_prepare_request(drive, &req); + ide_cd_init_rq(drive, &req); req.sense = sense; req.cmd[0] = GPCMD_TEST_UNIT_READY; req.cmd_flags |= REQ_QUIET; -#if ! STANDARD_ATAPI - /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to - switch CDs instead of supporting the LOAD_UNLOAD opcode */ - + /* + * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to + * switch CDs instead of supporting the LOAD_UNLOAD opcode. + */ req.cmd[7] = cdi->sanyo_slot % 3; -#endif /* not STANDARD_ATAPI */ - - return cdrom_queue_packet_command(drive, &req); -} - - -/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ -static int -cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense) -{ - struct request_sense my_sense; - struct request req; - int stat; - - if (sense == NULL) - sense = &my_sense; - - /* If the drive cannot lock the door, just pretend. */ - if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) { - stat = 0; - } else { - cdrom_prepare_request(drive, &req); - req.sense = sense; - req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; - req.cmd[4] = lockflag ? 1 : 0; - stat = cdrom_queue_packet_command(drive, &req); - } - - /* If we got an illegal field error, the drive - probably cannot lock the door. */ - if (stat != 0 && - sense->sense_key == ILLEGAL_REQUEST && - (sense->asc == 0x24 || sense->asc == 0x20)) { - printk (KERN_ERR "%s: door locking not supported\n", - drive->name); - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; - stat = 0; - } - - /* no medium, that's alright. */ - if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) - stat = 0; - - if (stat == 0) - CDROM_STATE_FLAGS(drive)->door_locked = lockflag; - - return stat; -} - -/* Eject the disk if EJECTFLAG is 0. - If EJECTFLAG is 1, try to reload the disk. */ -static int cdrom_eject(ide_drive_t *drive, int ejectflag, - struct request_sense *sense) -{ - struct request req; - char loej = 0x02; - - if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) - return -EDRIVE_CANT_DO_THIS; - - /* reload fails on some drives, if the tray is locked */ - if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) - return 0; - - cdrom_prepare_request(drive, &req); - - /* only tell drive to close tray if open, if it can do that */ - if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray) - loej = 0; - - req.sense = sense; - req.cmd[0] = GPCMD_START_STOP_UNIT; - req.cmd[4] = loej | (ejectflag != 0); - return cdrom_queue_packet_command(drive, &req); + return ide_cd_queue_pc(drive, &req); } static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, @@ -2212,7 +1414,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, int stat; struct request req; - cdrom_prepare_request(drive, &req); + ide_cd_init_rq(drive, &req); req.sense = sense; req.cmd[0] = GPCMD_READ_CDVD_CAPACITY; @@ -2220,7 +1422,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, req.data_len = sizeof(capbuf); req.cmd_flags |= REQ_QUIET; - stat = cdrom_queue_packet_command(drive, &req); + stat = ide_cd_queue_pc(drive, &req); if (stat == 0) { *capacity = 1 + be32_to_cpu(capbuf.lba); *sectors_per_frame = @@ -2236,7 +1438,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, { struct request req; - cdrom_prepare_request(drive, &req); + ide_cd_init_rq(drive, &req); req.sense = sense; req.data = buf; @@ -2251,12 +1453,11 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, if (msf_flag) req.cmd[1] = 2; - return cdrom_queue_packet_command(drive, &req); + return ide_cd_queue_pc(drive, &req); } - /* Try to read the entire TOC for the disk into our internal buffer. */ -static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) +int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; @@ -2283,7 +1484,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) If it is, just return. */ (void) cdrom_check_status(drive, sense); - if (CDROM_STATE_FLAGS(drive)->toc_valid) + if (info->cd_flags & IDE_CD_FLAG_TOC_VALID) return 0; /* Try to get the total cdrom capacity and sector size. */ @@ -2305,12 +1506,10 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) if (stat) return stat; -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) { - toc->hdr.first_track = bcd2bin(toc->hdr.first_track); - toc->hdr.last_track = bcd2bin(toc->hdr.last_track); + if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) { + toc->hdr.first_track = BCD2BIN(toc->hdr.first_track); + toc->hdr.last_track = BCD2BIN(toc->hdr.last_track); } -#endif /* not STANDARD_ATAPI */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (ntracks <= 0) @@ -2342,16 +1541,13 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) (ntracks + 1) * sizeof(struct atapi_toc_entry), sense); - if (stat) { + if (stat) return stat; - } -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) { - toc->hdr.first_track = bin2bcd(CDROM_LEADOUT); - toc->hdr.last_track = bin2bcd(CDROM_LEADOUT); - } else -#endif /* not STANDARD_ATAPI */ - { + + if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) { + toc->hdr.first_track = (u8)BIN2BCD(CDROM_LEADOUT); + toc->hdr.last_track = (u8)BIN2BCD(CDROM_LEADOUT); + } else { toc->hdr.first_track = CDROM_LEADOUT; toc->hdr.last_track = CDROM_LEADOUT; } @@ -2362,21 +1558,17 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) toc->hdr.toc_length = ntohs (toc->hdr.toc_length); -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) { - toc->hdr.first_track = bcd2bin(toc->hdr.first_track); - toc->hdr.last_track = bcd2bin(toc->hdr.last_track); + if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) { + toc->hdr.first_track = BCD2BIN(toc->hdr.first_track); + toc->hdr.last_track = BCD2BIN(toc->hdr.last_track); } -#endif /* not STANDARD_ATAPI */ - for (i=0; i<=ntracks; i++) { -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) { - if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) - toc->ent[i].track = bcd2bin(toc->ent[i].track); + for (i = 0; i <= ntracks; i++) { + if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) { + if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) + toc->ent[i].track = BCD2BIN(toc->ent[i].track); msf_from_bcd(&toc->ent[i].addr.msf); } -#endif /* not STANDARD_ATAPI */ toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute, toc->ent[i].addr.msf.second, toc->ent[i].addr.msf.frame); @@ -2396,8 +1588,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */ } -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) { + if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) { /* Re-read multisession information using MSF format */ stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, sizeof(ms_tmp), sense); @@ -2409,7 +1600,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) ms_tmp.ent.addr.msf.second, ms_tmp.ent.addr.msf.frame); } -#endif /* not STANDARD_ATAPI */ toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); @@ -2422,278 +1612,22 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) } /* Remember that we've read this stuff. */ - CDROM_STATE_FLAGS(drive)->toc_valid = 1; + info->cd_flags |= IDE_CD_FLAG_TOC_VALID; return 0; } - -static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, - int buflen, struct request_sense *sense) -{ - struct request req; - - cdrom_prepare_request(drive, &req); - - req.sense = sense; - req.data = buf; - req.data_len = buflen; - req.cmd[0] = GPCMD_READ_SUBCHANNEL; - req.cmd[1] = 2; /* MSF addressing */ - req.cmd[2] = 0x40; /* request subQ data */ - req.cmd[3] = format; - req.cmd[7] = (buflen >> 8); - req.cmd[8] = (buflen & 0xff); - return cdrom_queue_packet_command(drive, &req); -} - -/* ATAPI cdrom drives are free to select the speed you request or any slower - rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int cdrom_select_speed(ide_drive_t *drive, int speed, - struct request_sense *sense) -{ - struct request req; - cdrom_prepare_request(drive, &req); - - req.sense = sense; - if (speed == 0) - speed = 0xffff; /* set to max */ - else - speed *= 177; /* Nx to kbytes/s */ - - req.cmd[0] = GPCMD_SET_SPEED; - /* Read Drive speed in kbytes/second MSB */ - req.cmd[2] = (speed >> 8) & 0xff; - /* Read Drive speed in kbytes/second LSB */ - req.cmd[3] = speed & 0xff; - if (CDROM_CONFIG_FLAGS(drive)->cd_r || - CDROM_CONFIG_FLAGS(drive)->cd_rw || - CDROM_CONFIG_FLAGS(drive)->dvd_r) { - /* Write Drive speed in kbytes/second MSB */ - req.cmd[4] = (speed >> 8) & 0xff; - /* Write Drive speed in kbytes/second LSB */ - req.cmd[5] = speed & 0xff; - } - - return cdrom_queue_packet_command(drive, &req); -} - -static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end) -{ - struct request_sense sense; - struct request req; - - cdrom_prepare_request(drive, &req); - - req.sense = &sense; - req.cmd[0] = GPCMD_PLAY_AUDIO_MSF; - lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]); - lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]); - - return cdrom_queue_packet_command(drive, &req); -} - -static int cdrom_get_toc_entry(ide_drive_t *drive, int track, - struct atapi_toc_entry **ent) -{ - struct cdrom_info *info = drive->driver_data; - struct atapi_toc *toc = info->toc; - int ntracks; - - /* - * don't serve cached data, if the toc isn't valid - */ - if (!CDROM_STATE_FLAGS(drive)->toc_valid) - return -EINVAL; - - /* Check validity of requested track number. */ - ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; - if (track == CDROM_LEADOUT) - *ent = &toc->ent[ntracks]; - else if (track < toc->hdr.first_track || - track > toc->hdr.last_track) - return -EINVAL; - else - *ent = &toc->ent[track - toc->hdr.first_track]; - - return 0; -} - -/* the generic packet interface to cdrom.c */ -static int ide_cdrom_packet(struct cdrom_device_info *cdi, - struct packet_command *cgc) -{ - struct request req; - ide_drive_t *drive = cdi->handle; - - if (cgc->timeout <= 0) - cgc->timeout = ATAPI_WAIT_PC; - - /* here we queue the commands from the uniform CD-ROM - layer. the packet must be complete, as we do not - touch it at all. */ - cdrom_prepare_request(drive, &req); - memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE); - if (cgc->sense) - memset(cgc->sense, 0, sizeof(struct request_sense)); - req.data = cgc->buffer; - req.data_len = cgc->buflen; - req.timeout = cgc->timeout; - - if (cgc->quiet) - req.cmd_flags |= REQ_QUIET; - - req.sense = cgc->sense; - cgc->stat = cdrom_queue_packet_command(drive, &req); - if (!cgc->stat) - cgc->buflen -= req.data_len; - return cgc->stat; -} - -static -int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, - unsigned int cmd, void *arg) - -{ - ide_drive_t *drive = cdi->handle; - struct cdrom_info *info = drive->driver_data; - int stat; - - switch (cmd) { - /* - * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since - * atapi doesn't support it - */ - case CDROMPLAYTRKIND: { - unsigned long lba_start, lba_end; - struct cdrom_ti *ti = arg; - struct atapi_toc_entry *first_toc, *last_toc; - - stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc); - if (stat) - return stat; - - stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc); - if (stat) - return stat; - - if (ti->cdti_trk1 != CDROM_LEADOUT) - ++last_toc; - lba_start = first_toc->addr.lba; - lba_end = last_toc->addr.lba; - - if (lba_end <= lba_start) - return -EINVAL; - - return cdrom_play_audio(drive, lba_start, lba_end); - } - - case CDROMREADTOCHDR: { - struct cdrom_tochdr *tochdr = arg; - struct atapi_toc *toc; - - /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc(drive, NULL); - if (stat) - return stat; - - toc = info->toc; - tochdr->cdth_trk0 = toc->hdr.first_track; - tochdr->cdth_trk1 = toc->hdr.last_track; - - return 0; - } - - case CDROMREADTOCENTRY: { - struct cdrom_tocentry *tocentry = arg; - struct atapi_toc_entry *toce; - - stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce); - if (stat) - return stat; - - tocentry->cdte_ctrl = toce->control; - tocentry->cdte_adr = toce->adr; - if (tocentry->cdte_format == CDROM_MSF) { - lba_to_msf (toce->addr.lba, - &tocentry->cdte_addr.msf.minute, - &tocentry->cdte_addr.msf.second, - &tocentry->cdte_addr.msf.frame); - } else - tocentry->cdte_addr.lba = toce->addr.lba; - - return 0; - } - - default: - return -EINVAL; - } -} - -static -int ide_cdrom_reset (struct cdrom_device_info *cdi) -{ - ide_drive_t *drive = cdi->handle; - struct request_sense sense; - struct request req; - int ret; - - cdrom_prepare_request(drive, &req); - req.cmd_type = REQ_TYPE_SPECIAL; - req.cmd_flags = REQ_QUIET; - ret = ide_do_drive_cmd(drive, &req, ide_wait); - - /* - * A reset will unlock the door. If it was previously locked, - * lock it again. - */ - if (CDROM_STATE_FLAGS(drive)->door_locked) - (void) cdrom_lockdoor(drive, 1, &sense); - - return ret; -} - - -static -int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) -{ - ide_drive_t *drive = cdi->handle; - struct request_sense sense; - - if (position) { - int stat = cdrom_lockdoor(drive, 0, &sense); - if (stat) - return stat; - } - - return cdrom_eject(drive, !position, &sense); -} - -static -int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) -{ - ide_drive_t *drive = cdi->handle; - return cdrom_lockdoor(drive, lock, NULL); -} - -static -int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap) +int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf) { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; struct packet_command cgc; - int stat, attempts = 3, size = sizeof(*cap); + int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE; - /* - * ACER50 (and others?) require the full spec length mode sense - * page capabilities size, but older drives break. - */ - if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") || - !strcmp(drive->id->model, "WPI CDS-32X"))) - size -= sizeof(cap->pad); + if ((info->cd_flags & IDE_CD_FLAG_FULL_CAPS_PAGE) == 0) + size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE; - init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN); + init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN); do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); if (!stat) @@ -2702,177 +1636,33 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag return stat; } -static -void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page *cap) -{ - /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ - if (!drive->id->model[0] && - !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS(drive)->current_speed = - (le16_to_cpu(cap->curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS(drive)->max_speed = - (le16_to_cpu(cap->maxspeed) + (176/2)) / 176; - } else { - CDROM_STATE_FLAGS(drive)->current_speed = - (be16_to_cpu(cap->curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS(drive)->max_speed = - (be16_to_cpu(cap->maxspeed) + (176/2)) / 176; - } -} - -static -int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) -{ - ide_drive_t *drive = cdi->handle; - struct request_sense sense; - struct atapi_capabilities_page cap; - int stat; - - if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0) - return stat; - - if (!ide_cdrom_get_capabilities(drive, &cap)) { - ide_cdrom_update_speed(drive, &cap); - cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed; - } - return 0; -} - -/* - * add logic to try GET_EVENT command first to check for media and tray - * status. this should be supported by newer cd-r/w and all DVD etc - * drives - */ -static -int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) -{ - ide_drive_t *drive = cdi->handle; - struct media_event_desc med; - struct request_sense sense; - int stat; - - if (slot_nr != CDSL_CURRENT) - return -EINVAL; - - stat = cdrom_check_status(drive, &sense); - if (!stat || sense.sense_key == UNIT_ATTENTION) - return CDS_DISC_OK; - - if (!cdrom_get_media_event(cdi, &med)) { - if (med.media_present) - return CDS_DISC_OK; - else if (med.door_open) - return CDS_TRAY_OPEN; - else - return CDS_NO_DISC; - } - - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) - return CDS_DISC_OK; - - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - } - return CDS_DRIVE_NOT_READY; -} - -static -int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, - struct cdrom_multisession *ms_info) +void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf) { - struct atapi_toc *toc; - ide_drive_t *drive = cdi->handle; - struct cdrom_info *info = drive->driver_data; - struct request_sense sense; - int ret; - - if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL) - if ((ret = cdrom_read_toc(drive, &sense))) - return ret; - - toc = info->toc; - ms_info->addr.lba = toc->last_session_lba; - ms_info->xa_flag = toc->xa_flag; - - return 0; -} - -static -int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, - struct cdrom_mcn *mcn_info) -{ - int stat; - char mcnbuf[24]; - ide_drive_t *drive = cdi->handle; - -/* get MCN */ - if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL))) - return stat; - - memcpy (mcn_info->medium_catalog_number, mcnbuf+9, - sizeof (mcn_info->medium_catalog_number)-1); - mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1] - = '\0'; - - return 0; -} - - + struct cdrom_info *cd = drive->driver_data; + u16 curspeed, maxspeed; -/**************************************************************************** - * Other driver requests (open, close, check media change). - */ + curspeed = *(u16 *)&buf[8 + 14]; + maxspeed = *(u16 *)&buf[8 + 8]; -static -int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, - int slot_nr) -{ - ide_drive_t *drive = cdi->handle; - int retval; - - if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status(drive, NULL); - retval = CDROM_STATE_FLAGS(drive)->media_changed; - CDROM_STATE_FLAGS(drive)->media_changed = 0; - return retval; + if (cd->cd_flags & IDE_CD_FLAG_LE_SPEED_FIELDS) { + curspeed = le16_to_cpu(curspeed); + maxspeed = le16_to_cpu(maxspeed); } else { - return -EINVAL; + curspeed = be16_to_cpu(curspeed); + maxspeed = be16_to_cpu(maxspeed); } -} - -static -int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose) -{ - return 0; + cd->current_speed = (curspeed + (176/2)) / 176; + cd->max_speed = (maxspeed + (176/2)) / 176; } -/* - * Close down the device. Invalidate all cached blocks. - */ - -static -void ide_cdrom_release_real (struct cdrom_device_info *cdi) -{ - ide_drive_t *drive = cdi->handle; - - if (!cdi->use_count) - CDROM_STATE_FLAGS(drive)->toc_valid = 0; -} +#define IDE_CD_CAPABILITIES \ + (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \ + CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \ + CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \ + CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \ + CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM) - - -/**************************************************************************** - * Device initialization. - */ static struct cdrom_device_ops ide_cdrom_dops = { .open = ide_cdrom_open_real, .release = ide_cdrom_release_real, @@ -2885,14 +1675,7 @@ static struct cdrom_device_ops ide_cdrom_dops = { .get_mcn = ide_cdrom_get_mcn, .reset = ide_cdrom_reset, .audio_ioctl = ide_cdrom_audio_ioctl, - .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | - CDC_SELECT_SPEED | CDC_SELECT_DISC | - CDC_MULTI_SESSION | CDC_MCN | - CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | - CDC_DRIVE_STATUS | CDC_CD_R | - CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM | - CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW | - CDC_MRW_W | CDC_RAM, + .capability = IDE_CD_CAPABILITIES, .generic_packet = ide_cdrom_packet, }; @@ -2902,35 +1685,12 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) struct cdrom_device_info *devinfo = &info->devinfo; devinfo->ops = &ide_cdrom_dops; - devinfo->mask = 0; - devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed; + devinfo->speed = info->current_speed; devinfo->capacity = nslots; devinfo->handle = drive; strcpy(devinfo->name, drive->name); - - /* set capability mask to match the probe. */ - if (!CDROM_CONFIG_FLAGS(drive)->cd_r) - devinfo->mask |= CDC_CD_R; - if (!CDROM_CONFIG_FLAGS(drive)->cd_rw) - devinfo->mask |= CDC_CD_RW; - if (!CDROM_CONFIG_FLAGS(drive)->dvd) - devinfo->mask |= CDC_DVD; - if (!CDROM_CONFIG_FLAGS(drive)->dvd_r) - devinfo->mask |= CDC_DVD_R; - if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram) - devinfo->mask |= CDC_DVD_RAM; - if (!CDROM_CONFIG_FLAGS(drive)->is_changer) - devinfo->mask |= CDC_SELECT_DISC; - if (!CDROM_CONFIG_FLAGS(drive)->audio_play) - devinfo->mask |= CDC_PLAY_AUDIO; - if (!CDROM_CONFIG_FLAGS(drive)->close_tray) - devinfo->mask |= CDC_CLOSE_TRAY; - if (!CDROM_CONFIG_FLAGS(drive)->mo_drive) - devinfo->mask |= CDC_MO_DRIVE; - if (!CDROM_CONFIG_FLAGS(drive)->ram) - devinfo->mask |= CDC_RAM; - - if (CDROM_CONFIG_FLAGS(drive)->no_speed_select) + + if (info->cd_flags & IDE_CD_FLAG_NO_SPEED_SELECT) devinfo->mask |= CDC_SELECT_SPEED; devinfo->disk = info->disk; @@ -2940,22 +1700,25 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi = &info->devinfo; - struct atapi_capabilities_page cap; + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; + mechtype_t mechtype; int nslots = 1; + cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | + CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO | + CDC_MO_DRIVE | CDC_RAM); + if (drive->media == ide_optical) { - CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; - CDROM_CONFIG_FLAGS(drive)->ram = 1; + cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM); printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name); return nslots; } - if (CDROM_CONFIG_FLAGS(drive)->nec260 || - !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) { - CDROM_CONFIG_FLAGS(drive)->no_eject = 0; - CDROM_CONFIG_FLAGS(drive)->audio_play = 1; + if (cd->cd_flags & IDE_CD_FLAG_PRE_ATAPI12) { + cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT; + cdi->mask &= ~CDC_PLAY_AUDIO; return nslots; } @@ -2969,83 +1732,66 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) cdi->handle = drive; cdi->ops = &ide_cdrom_dops; - if (ide_cdrom_get_capabilities(drive, &cap)) + if (ide_cdrom_get_capabilities(drive, buf)) return 0; - if (cap.lock == 0) - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; - if (cap.eject) - CDROM_CONFIG_FLAGS(drive)->no_eject = 0; - if (cap.cd_r_write) - CDROM_CONFIG_FLAGS(drive)->cd_r = 1; - if (cap.cd_rw_write) { - CDROM_CONFIG_FLAGS(drive)->cd_rw = 1; - CDROM_CONFIG_FLAGS(drive)->ram = 1; - } - if (cap.test_write) - CDROM_CONFIG_FLAGS(drive)->test_write = 1; - if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) - CDROM_CONFIG_FLAGS(drive)->dvd = 1; - if (cap.dvd_ram_write) { - CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1; - CDROM_CONFIG_FLAGS(drive)->ram = 1; - } - if (cap.dvd_r_write) - CDROM_CONFIG_FLAGS(drive)->dvd_r = 1; - if (cap.audio_play) - CDROM_CONFIG_FLAGS(drive)->audio_play = 1; - if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) - CDROM_CONFIG_FLAGS(drive)->close_tray = 0; - - /* Some drives used by Apple don't advertise audio play - * but they do support reading TOC & audio datas - */ - if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 || - strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 || - strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 || - strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0) - CDROM_CONFIG_FLAGS(drive)->audio_play = 1; + if ((buf[8 + 6] & 0x01) == 0) + cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK; + if (buf[8 + 6] & 0x08) + cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT; + if (buf[8 + 3] & 0x01) + cdi->mask &= ~CDC_CD_R; + if (buf[8 + 3] & 0x02) + cdi->mask &= ~(CDC_CD_RW | CDC_RAM); + if (buf[8 + 2] & 0x38) + cdi->mask &= ~CDC_DVD; + if (buf[8 + 3] & 0x20) + cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM); + if (buf[8 + 3] & 0x10) + cdi->mask &= ~CDC_DVD_R; + if ((buf[8 + 4] & 0x01) || (cd->cd_flags & IDE_CD_FLAG_PLAY_AUDIO_OK)) + cdi->mask &= ~CDC_PLAY_AUDIO; + + mechtype = buf[8 + 6] >> 5; + if (mechtype == mechtype_caddy || mechtype == mechtype_popup) + cdi->mask |= CDC_CLOSE_TRAY; -#if ! STANDARD_ATAPI if (cdi->sanyo_slot > 0) { - CDROM_CONFIG_FLAGS(drive)->is_changer = 1; + cdi->mask &= ~CDC_SELECT_DISC; nslots = 3; + } else if (mechtype == mechtype_individual_changer || + mechtype == mechtype_cartridge_changer) { + nslots = cdrom_number_of_slots(cdi); + if (nslots > 1) + cdi->mask &= ~CDC_SELECT_DISC; } - else -#endif /* not STANDARD_ATAPI */ - if (cap.mechtype == mechtype_individual_changer || - cap.mechtype == mechtype_cartridge_changer) { - if ((nslots = cdrom_number_of_slots(cdi)) > 1) { - CDROM_CONFIG_FLAGS(drive)->is_changer = 1; - CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1; - } - } + ide_cdrom_update_speed(drive, buf); - ide_cdrom_update_speed(drive, &cap); - /* don't print speed if the drive reported 0. - */ printk(KERN_INFO "%s: ATAPI", drive->name); - if (CDROM_CONFIG_FLAGS(drive)->max_speed) - printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); - printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); - if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram) - printk(" DVD%s%s", - (CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : ""); + /* don't print speed if the drive reported 0 */ + if (cd->max_speed) + printk(KERN_CONT " %dX", cd->max_speed); - if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) - printk(" CD%s%s", - (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : ""); + printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM"); - if (CDROM_CONFIG_FLAGS(drive)->is_changer) - printk(" changer w/%d slots", nslots); - else - printk(" drive"); + if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0) + printk(KERN_CONT " DVD%s%s", + (cdi->mask & CDC_DVD_R) ? "" : "-R", + (cdi->mask & CDC_DVD_RAM) ? "" : "-RAM"); - printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(cap.buffer_size)); + if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0) + printk(KERN_CONT " CD%s%s", + (cdi->mask & CDC_CD_R) ? "" : "-R", + (cdi->mask & CDC_CD_RW) ? "" : "/RW"); + + if ((cdi->mask & CDC_SELECT_DISC) == 0) + printk(KERN_CONT " changer w/%d slots", nslots); + else + printk(KERN_CONT " drive"); + + printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(*(u16 *)&buf[8 + 12])); return nslots; } @@ -3138,11 +1884,74 @@ static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq) return 0; } +struct cd_list_entry { + const char *id_model; + const char *id_firmware; + unsigned int cd_flags; +}; + +static const struct cd_list_entry ide_cd_quirks_list[] = { + /* Limit transfer size per interrupt. */ + { "SAMSUNG CD-ROM SCR-2430", NULL, IDE_CD_FLAG_LIMIT_NFRAMES }, + { "SAMSUNG CD-ROM SCR-2432", NULL, IDE_CD_FLAG_LIMIT_NFRAMES }, + /* SCR-3231 doesn't support the SET_CD_SPEED command. */ + { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_CD_FLAG_NO_SPEED_SELECT }, + /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */ + { "NEC CD-ROM DRIVE:260", "1.01", IDE_CD_FLAG_TOCADDR_AS_BCD | + IDE_CD_FLAG_PRE_ATAPI12, }, + /* Vertos 300, some versions of this drive like to talk BCD. */ + { "V003S0DS", NULL, IDE_CD_FLAG_VERTOS_300_SSD, }, + /* Vertos 600 ESD. */ + { "V006E0DS", NULL, IDE_CD_FLAG_VERTOS_600_ESD, }, + /* + * Sanyo 3 CD changer uses a non-standard command for CD changing + * (by default standard ATAPI support for CD changers is used). + */ + { "CD-ROM CDR-C3 G", NULL, IDE_CD_FLAG_SANYO_3CD }, + { "CD-ROM CDR-C3G", NULL, IDE_CD_FLAG_SANYO_3CD }, + { "CD-ROM CDR_C36", NULL, IDE_CD_FLAG_SANYO_3CD }, + /* Stingray 8X CD-ROM. */ + { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_CD_FLAG_PRE_ATAPI12}, + /* + * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length + * mode sense page capabilities size, but older drives break. + */ + { "ATAPI CD ROM DRIVE 50X MAX", NULL, IDE_CD_FLAG_FULL_CAPS_PAGE }, + { "WPI CDS-32X", NULL, IDE_CD_FLAG_FULL_CAPS_PAGE }, + /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */ + { "", "241N", IDE_CD_FLAG_LE_SPEED_FIELDS }, + /* + * Some drives used by Apple don't advertise audio play + * but they do support reading TOC & audio datas. + */ + { "MATSHITADVD-ROM SR-8187", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8186", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8176", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8174", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK }, + { NULL, NULL, 0 } +}; + +static unsigned int ide_cd_flags(struct hd_driveid *id) +{ + const struct cd_list_entry *cle = ide_cd_quirks_list; + + while (cle->id_model) { + if (strcmp(cle->id_model, id->model) == 0 && + (cle->id_firmware == NULL || + strstr(id->fw_rev, cle->id_firmware))) + return cle->cd_flags; + cle++; + } + + return 0; +} + static int ide_cdrom_setup (ide_drive_t *drive) { - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi = &info->devinfo; + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + struct hd_driveid *id = drive->id; int nslots; blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn); @@ -3153,101 +1962,21 @@ int ide_cdrom_setup (ide_drive_t *drive) drive->special.all = 0; - CDROM_STATE_FLAGS(drive)->media_changed = 1; - CDROM_STATE_FLAGS(drive)->toc_valid = 0; - CDROM_STATE_FLAGS(drive)->door_locked = 0; + cd->cd_flags = IDE_CD_FLAG_MEDIA_CHANGED | IDE_CD_FLAG_NO_EJECT | + ide_cd_flags(id); -#if NO_DOOR_LOCKING - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; -#else - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0; -#endif + if ((id->config & 0x0060) == 0x20) + cd->cd_flags |= IDE_CD_FLAG_DRQ_INTERRUPT; - CDROM_CONFIG_FLAGS(drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20); - CDROM_CONFIG_FLAGS(drive)->is_changer = 0; - CDROM_CONFIG_FLAGS(drive)->cd_r = 0; - CDROM_CONFIG_FLAGS(drive)->cd_rw = 0; - CDROM_CONFIG_FLAGS(drive)->test_write = 0; - CDROM_CONFIG_FLAGS(drive)->dvd = 0; - CDROM_CONFIG_FLAGS(drive)->dvd_r = 0; - CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0; - CDROM_CONFIG_FLAGS(drive)->no_eject = 1; - CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0; - CDROM_CONFIG_FLAGS(drive)->audio_play = 0; - CDROM_CONFIG_FLAGS(drive)->close_tray = 1; - - /* limit transfer size per interrupt. */ - CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0; - /* a testament to the nice quality of Samsung drives... */ - if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430")) - CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; - else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432")) - CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; - /* the 3231 model does not support the SET_CD_SPEED command */ - else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231")) - CDROM_CONFIG_FLAGS(drive)->no_speed_select = 1; - -#if ! STANDARD_ATAPI - /* by default Sanyo 3 CD changer support is turned off and - ATAPI Rev 2.2+ standard support for CD changers is used */ - cdi->sanyo_slot = 0; - - CDROM_CONFIG_FLAGS(drive)->nec260 = 0; - CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0; - CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0; - CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0; - CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0; - - if (strcmp (drive->id->model, "V003S0DS") == 0 && - drive->id->fw_rev[4] == '1' && - drive->id->fw_rev[6] <= '2') { - /* Vertos 300. - Some versions of this drive like to talk BCD. */ - CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1; - } - - else if (strcmp (drive->id->model, "V006E0DS") == 0 && - drive->id->fw_rev[4] == '1' && - drive->id->fw_rev[6] <= '2') { - /* Vertos 600 ESD. */ - CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1; - } - else if (strcmp(drive->id->model, "NEC CD-ROM DRIVE:260") == 0 && - strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */ - /* Old NEC260 (not R). - This drive was released before the 1.2 version - of the spec. */ - CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->nec260 = 1; - } - else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 && - strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */ - /* Wearnes */ - CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1; - CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1; - } - /* Sanyo 3 CD changer uses a non-standard command - for CD changing */ - else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) || - (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) || - (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) { - /* uses CD in slot 0 when value is set to 3 */ - cdi->sanyo_slot = 3; - } -#endif /* not STANDARD_ATAPI */ - - info->toc = NULL; - info->buffer = NULL; - info->sector_buffered = 0; - info->nsectors_buffered = 0; - info->changer_info = NULL; - info->last_block = 0; - info->start_seek = 0; + if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_300_SSD) && + id->fw_rev[4] == '1' && id->fw_rev[6] <= '2') + cd->cd_flags |= (IDE_CD_FLAG_TOCTRACKS_AS_BCD | + IDE_CD_FLAG_TOCADDR_AS_BCD); + else if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_600_ESD) && + id->fw_rev[4] == '1' && id->fw_rev[6] <= '2') + cd->cd_flags |= IDE_CD_FLAG_TOCTRACKS_AS_BCD; + else if (cd->cd_flags & IDE_CD_FLAG_SANYO_3CD) + cdi->sanyo_slot = 3; /* 3 => use CD in slot 0 */ nslots = ide_cdrom_probe_capabilities (drive); @@ -3262,7 +1991,7 @@ int ide_cdrom_setup (ide_drive_t *drive) if (ide_cdrom_register(drive, nslots)) { printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); - info->devinfo.handle = NULL; + cd->devinfo.handle = NULL; return 1; } ide_cdrom_add_settings(drive); @@ -3302,7 +2031,6 @@ static void ide_cd_release(struct kref *kref) kfree(info->buffer); kfree(info->toc); - kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) printk(KERN_ERR "%s: %s failed to unregister device from the cdrom " "driver.\n", __FUNCTION__, drive->name); @@ -3458,7 +2186,9 @@ static int idecd_revalidate_disk(struct gendisk *disk) { struct cdrom_info *info = ide_cd_g(disk); struct request_sense sense; - cdrom_read_toc(info->drive, &sense); + + ide_cd_read_toc(info->drive, &sense); + return 0; } @@ -3533,7 +2263,7 @@ static int ide_cd_probe(ide_drive_t *drive) goto failed; } - cdrom_read_toc(drive, &sense); + ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; add_disk(g); @@ -3556,6 +2286,7 @@ static int __init ide_cdrom_init(void) } MODULE_ALIAS("ide:*m-cdrom*"); +MODULE_ALIAS("ide-cd"); module_init(ide_cdrom_init); module_exit(ide_cdrom_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index 1b302fe2724d..22e3751a681e 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide_cd.h - * * Copyright (C) 1996-98 Erik Andersen * Copyright (C) 1998-2000 Jens Axboe */ @@ -10,31 +8,6 @@ #include <linux/cdrom.h> #include <asm/byteorder.h> -/* Turn this on to have the driver print out the meanings of the - ATAPI error codes. This will use up additional kernel-space - memory, though. */ - -#ifndef VERBOSE_IDE_CD_ERRORS -#define VERBOSE_IDE_CD_ERRORS 1 -#endif - - -/* Turning this on will remove code to work around various nonstandard - ATAPI implementations. If you know your drive follows the standard, - this will give you a slightly smaller kernel. */ - -#ifndef STANDARD_ATAPI -#define STANDARD_ATAPI 0 -#endif - - -/* Turning this on will disable the door-locking functionality. - This is apparently needed for supermount. */ - -#ifndef NO_DOOR_LOCKING -#define NO_DOOR_LOCKING 0 -#endif - /* * typical timeout for packet command */ @@ -49,68 +22,47 @@ #endif #define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS) #define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) -#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -#define SECTORS_MAX (131072 >> SECTOR_BITS) - -#define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE) - -/* special command codes for strategy routine. */ -#define PACKET_COMMAND 4315 -#define REQUEST_SENSE_COMMAND 4316 -#define RESET_DRIVE_COMMAND 4317 - - -/* Configuration flags. These describe the capabilities of the drive. - They generally do not change after initialization, unless we learn - more about the drive from stuff failing. */ -struct ide_cd_config_flags { - __u8 drq_interrupt : 1; /* Device sends an interrupt when ready - for a packet command. */ - __u8 no_doorlock : 1; /* Drive cannot lock the door. */ - __u8 no_eject : 1; /* Drive cannot eject the disc. */ - __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ - __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */ - __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */ - __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */ - __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */ - __u8 is_changer : 1; /* Drive is a changer. */ - __u8 cd_r : 1; /* Drive can write to CD-R media . */ - __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ - __u8 dvd : 1; /* Drive is a DVD-ROM */ - __u8 dvd_r : 1; /* Drive can write DVD-R */ - __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ - __u8 ram : 1; /* generic WRITE (dvd-ram/mrw) */ - __u8 test_write : 1; /* Drive can fake writes */ - __u8 supp_disc_present : 1; /* Changer can report exact contents - of slots. */ - __u8 limit_nframes : 1; /* Drive does not provide data in - multiples of SECTOR_SIZE when more - than one interrupt is needed. */ - __u8 seeking : 1; /* Seeking in progress */ - __u8 audio_play : 1; /* can do audio related commands */ - __u8 close_tray : 1; /* can close the tray */ - __u8 writing : 1; /* pseudo write in progress */ - __u8 mo_drive : 1; /* drive is an MO device */ - __u8 no_speed_select : 1; /* SET_CD_SPEED command is unsupported. */ - __u8 reserved : 1; - byte max_speed; /* Max speed of the drive */ -}; -#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) - -/* State flags. These give information about the current state of the - drive, and will change during normal operation. */ -struct ide_cd_state_flags { - __u8 media_changed : 1; /* Driver has noticed a media change. */ - __u8 toc_valid : 1; /* Saved TOC information is current. */ - __u8 door_locked : 1; /* We think that the drive door is locked. */ - __u8 writing : 1; /* the drive is currently writing */ - __u8 reserved : 4; - byte current_speed; /* Current speed of the drive */ +/* Capabilities Page size including 8 bytes of Mode Page Header */ +#define ATAPI_CAPABILITIES_PAGE_SIZE (8 + 20) +#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE 4 + +enum { + /* Device sends an interrupt when ready for a packet command. */ + IDE_CD_FLAG_DRQ_INTERRUPT = (1 << 0), + /* Drive cannot lock the door. */ + IDE_CD_FLAG_NO_DOORLOCK = (1 << 1), + /* Drive cannot eject the disc. */ + IDE_CD_FLAG_NO_EJECT = (1 << 2), + /* Drive is a pre ATAPI 1.2 drive. */ + IDE_CD_FLAG_PRE_ATAPI12 = (1 << 3), + /* TOC addresses are in BCD. */ + IDE_CD_FLAG_TOCADDR_AS_BCD = (1 << 4), + /* TOC track numbers are in BCD. */ + IDE_CD_FLAG_TOCTRACKS_AS_BCD = (1 << 5), + /* + * Drive does not provide data in multiples of SECTOR_SIZE + * when more than one interrupt is needed. + */ + IDE_CD_FLAG_LIMIT_NFRAMES = (1 << 6), + /* Seeking in progress. */ + IDE_CD_FLAG_SEEKING = (1 << 7), + /* Driver has noticed a media change. */ + IDE_CD_FLAG_MEDIA_CHANGED = (1 << 8), + /* Saved TOC information is current. */ + IDE_CD_FLAG_TOC_VALID = (1 << 9), + /* We think that the drive door is locked. */ + IDE_CD_FLAG_DOOR_LOCKED = (1 << 10), + /* SET_CD_SPEED command is unsupported. */ + IDE_CD_FLAG_NO_SPEED_SELECT = (1 << 11), + IDE_CD_FLAG_VERTOS_300_SSD = (1 << 12), + IDE_CD_FLAG_VERTOS_600_ESD = (1 << 13), + IDE_CD_FLAG_SANYO_3CD = (1 << 14), + IDE_CD_FLAG_FULL_CAPS_PAGE = (1 << 15), + IDE_CD_FLAG_PLAY_AUDIO_OK = (1 << 16), + IDE_CD_FLAG_LE_SPEED_FIELDS = (1 << 17), }; -#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) - /* Structure of a MSF cdrom address. */ struct atapi_msf { byte reserved; @@ -155,310 +107,6 @@ struct atapi_toc { /* One extra for the leadout. */ }; - -/* This structure is annoyingly close to, but not identical with, - the cdrom_subchnl structure from cdrom.h. */ -struct atapi_cdrom_subchnl { - u_char acdsc_reserved; - u_char acdsc_audiostatus; - u_short acdsc_length; - u_char acdsc_format; - -#if defined(__BIG_ENDIAN_BITFIELD) - u_char acdsc_ctrl: 4; - u_char acdsc_adr: 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - u_char acdsc_adr: 4; - u_char acdsc_ctrl: 4; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u_char acdsc_trk; - u_char acdsc_ind; - union { - struct atapi_msf msf; - int lba; - } acdsc_absaddr; - union { - struct atapi_msf msf; - int lba; - } acdsc_reladdr; -}; - - - -/* This should probably go into cdrom.h along with the other - * generic stuff now in the Mt. Fuji spec. - */ -struct atapi_capabilities_page { - struct mode_page_header header; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 parameters_saveable : 1; - __u8 reserved1 : 1; - __u8 page_code : 6; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 page_code : 6; - __u8 reserved1 : 1; - __u8 parameters_saveable : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - - byte page_length; - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved2 : 2; - /* Drive supports reading of DVD-RAM discs */ - __u8 dvd_ram_read : 1; - /* Drive supports reading of DVD-R discs */ - __u8 dvd_r_read : 1; - /* Drive supports reading of DVD-ROM discs */ - __u8 dvd_rom : 1; - /* Drive supports reading CD-R discs with addressing method 2 */ - __u8 method2 : 1; /* reserved in 1.2 */ - /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */ - __u8 cd_rw_read : 1; /* reserved in 1.2 */ - /* Drive supports read from CD-R discs (orange book, part II) */ - __u8 cd_r_read : 1; /* reserved in 1.2 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - /* Drive supports read from CD-R discs (orange book, part II) */ - __u8 cd_r_read : 1; /* reserved in 1.2 */ - /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */ - __u8 cd_rw_read : 1; /* reserved in 1.2 */ - /* Drive supports reading CD-R discs with addressing method 2 */ - __u8 method2 : 1; - /* Drive supports reading of DVD-ROM discs */ - __u8 dvd_rom : 1; - /* Drive supports reading of DVD-R discs */ - __u8 dvd_r_read : 1; - /* Drive supports reading of DVD-RAM discs */ - __u8 dvd_ram_read : 1; - __u8 reserved2 : 2; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved3 : 2; - /* Drive can write DVD-RAM discs */ - __u8 dvd_ram_write : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; - __u8 reserved3a : 1; - /* Drive can fake writes */ - __u8 test_write : 1; - /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ - __u8 cd_rw_write : 1; /* reserved in 1.2 */ - /* Drive supports write to CD-R discs (orange book, part II) */ - __u8 cd_r_write : 1; /* reserved in 1.2 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - /* Drive can write to CD-R discs (orange book, part II) */ - __u8 cd_r_write : 1; /* reserved in 1.2 */ - /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ - __u8 cd_rw_write : 1; /* reserved in 1.2 */ - /* Drive can fake writes */ - __u8 test_write : 1; - __u8 reserved3a : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; - /* Drive can write DVD-RAM discs */ - __u8 dvd_ram_write : 1; - __u8 reserved3 : 2; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved4 : 1; - /* Drive can read multisession discs. */ - __u8 multisession : 1; - /* Drive can read mode 2, form 2 data. */ - __u8 mode2_form2 : 1; - /* Drive can read mode 2, form 1 (XA) data. */ - __u8 mode2_form1 : 1; - /* Drive supports digital output on port 2. */ - __u8 digport2 : 1; - /* Drive supports digital output on port 1. */ - __u8 digport1 : 1; - /* Drive can deliver a composite audio/video data stream. */ - __u8 composite : 1; - /* Drive supports audio play operations. */ - __u8 audio_play : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - /* Drive supports audio play operations. */ - __u8 audio_play : 1; - /* Drive can deliver a composite audio/video data stream. */ - __u8 composite : 1; - /* Drive supports digital output on port 1. */ - __u8 digport1 : 1; - /* Drive supports digital output on port 2. */ - __u8 digport2 : 1; - /* Drive can read mode 2, form 1 (XA) data. */ - __u8 mode2_form1 : 1; - /* Drive can read mode 2, form 2 data. */ - __u8 mode2_form2 : 1; - /* Drive can read multisession discs. */ - __u8 multisession : 1; - __u8 reserved4 : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved5 : 1; - /* Drive can return Media Catalog Number (UPC) info. */ - __u8 upc : 1; - /* Drive can return International Standard Recording Code info. */ - __u8 isrc : 1; - /* Drive supports C2 error pointers. */ - __u8 c2_pointers : 1; - /* R-W data will be returned deinterleaved and error corrected. */ - __u8 rw_corr : 1; - /* Subchannel reads can return combined R-W information. */ - __u8 rw_supported : 1; - /* Drive can continue a read cdda operation from a loss of streaming.*/ - __u8 cdda_accurate : 1; - /* Drive can read Red Book audio data. */ - __u8 cdda : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - /* Drive can read Red Book audio data. */ - __u8 cdda : 1; - /* Drive can continue a read cdda operation from a loss of streaming.*/ - __u8 cdda_accurate : 1; - /* Subchannel reads can return combined R-W information. */ - __u8 rw_supported : 1; - /* R-W data will be returned deinterleaved and error corrected. */ - __u8 rw_corr : 1; - /* Drive supports C2 error pointers. */ - __u8 c2_pointers : 1; - /* Drive can return International Standard Recording Code info. */ - __u8 isrc : 1; - /* Drive can return Media Catalog Number (UPC) info. */ - __u8 upc : 1; - __u8 reserved5 : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - /* Drive mechanism types. */ - mechtype_t mechtype : 3; - __u8 reserved6 : 1; - /* Drive can eject a disc or changer cartridge. */ - __u8 eject : 1; - /* State of prevent/allow jumper. */ - __u8 prevent_jumper : 1; - /* Present state of door lock. */ - __u8 lock_state : 1; - /* Drive can lock the door. */ - __u8 lock : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - - /* Drive can lock the door. */ - __u8 lock : 1; - /* Present state of door lock. */ - __u8 lock_state : 1; - /* State of prevent/allow jumper. */ - __u8 prevent_jumper : 1; - /* Drive can eject a disc or changer cartridge. */ - __u8 eject : 1; - __u8 reserved6 : 1; - /* Drive mechanism types. */ - mechtype_t mechtype : 3; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved7 : 4; - /* Drive supports software slot selection. */ - __u8 sss : 1; /* reserved in 1.2 */ - /* Changer can report exact contents of slots. */ - __u8 disc_present : 1; /* reserved in 1.2 */ - /* Audio for each channel can be muted independently. */ - __u8 separate_mute : 1; - /* Audio level for each channel can be controlled independently. */ - __u8 separate_volume : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - - /* Audio level for each channel can be controlled independently. */ - __u8 separate_volume : 1; - /* Audio for each channel can be muted independently. */ - __u8 separate_mute : 1; - /* Changer can report exact contents of slots. */ - __u8 disc_present : 1; /* reserved in 1.2 */ - /* Drive supports software slot selection. */ - __u8 sss : 1; /* reserved in 1.2 */ - __u8 reserved7 : 4; -#else -#error "Please fix <asm/byteorder.h>" -#endif - - /* Note: the following four fields are returned in big-endian form. */ - /* Maximum speed (in kB/s). */ - unsigned short maxspeed; - /* Number of discrete volume levels. */ - unsigned short n_vol_levels; - /* Size of cache in drive, in kB. */ - unsigned short buffer_size; - /* Current speed (in kB/s). */ - unsigned short curspeed; - char pad[4]; -}; - - -struct atapi_mechstat_header { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 fault : 1; - __u8 changer_state : 2; - __u8 curslot : 5; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 curslot : 5; - __u8 changer_state : 2; - __u8 fault : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 mech_state : 3; - __u8 door_open : 1; - __u8 reserved1 : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved1 : 4; - __u8 door_open : 1; - __u8 mech_state : 3; -#else -#error "Please fix <asm/byteorder.h>" -#endif - - byte curlba[3]; - byte nslots; - __u16 slot_tablelen; -}; - - -struct atapi_slot { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 disc_present : 1; - __u8 reserved1 : 6; - __u8 change : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 change : 1; - __u8 reserved1 : 6; - __u8 disc_present : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - - byte reserved2[3]; -}; - -struct atapi_changer_info { - struct atapi_mechstat_header hdr; - struct atapi_slot slots[0]; -}; - /* Extra per-device info for cdrom drives. */ struct cdrom_info { ide_drive_t *drive; @@ -483,11 +131,11 @@ struct cdrom_info { int dma; unsigned long last_block; unsigned long start_seek; - /* Buffer to hold mechanism status and changer slot table. */ - struct atapi_changer_info *changer_info; - struct ide_cd_config_flags config_flags; - struct ide_cd_state_flags state_flags; + unsigned int cd_flags; + + u8 max_speed; /* Max speed of the drive. */ + u8 current_speed; /* Current speed of the drive. */ /* Per-device info needed by cdrom.c generic driver. */ struct cdrom_device_info devinfo; @@ -495,250 +143,30 @@ struct cdrom_info { unsigned long write_timeout; }; -/**************************************************************************** - * Descriptions of ATAPI error codes. - */ - -/* This stuff should be in cdrom.h, since it is now generic... */ - -/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define BLANK_CHECK 0x08 -#define ABORTED_COMMAND 0x0b -#define MISCOMPARE 0x0e - - - -/* This stuff should be in cdrom.h, since it is now generic... */ -#if VERBOSE_IDE_CD_ERRORS - - /* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const struct { - unsigned short packet_command; - const char * const text; -} packet_command_texts[] = { - { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, - { GPCMD_REQUEST_SENSE, "Request Sense" }, - { GPCMD_FORMAT_UNIT, "Format Unit" }, - { GPCMD_INQUIRY, "Inquiry" }, - { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, - { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, - { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, - { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, - { GPCMD_READ_10, "Read 10" }, - { GPCMD_WRITE_10, "Write 10" }, - { GPCMD_SEEK, "Seek" }, - { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, - { GPCMD_VERIFY_10, "Verify 10" }, - { GPCMD_FLUSH_CACHE, "Flush Cache" }, - { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, - { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, - { GPCMD_READ_HEADER, "Read Header" }, - { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, - { GPCMD_GET_CONFIGURATION, "Get Configuration" }, - { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, - { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, - { GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" }, - { GPCMD_PAUSE_RESUME, "Pause/Resume" }, - { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, - { GPCMD_READ_DISC_INFO, "Read Disc Info" }, - { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, - { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, - { GPCMD_SEND_OPC, "Send OPC" }, - { GPCMD_MODE_SELECT_10, "Mode Select 10" }, - { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, - { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, - { GPCMD_CLOSE_TRACK, "Close Track" }, - { GPCMD_BLANK, "Blank" }, - { GPCMD_SEND_EVENT, "Send Event" }, - { GPCMD_SEND_KEY, "Send Key" }, - { GPCMD_REPORT_KEY, "Report Key" }, - { GPCMD_LOAD_UNLOAD, "Load/Unload" }, - { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, - { GPCMD_READ_12, "Read 12" }, - { GPCMD_GET_PERFORMANCE, "Get Performance" }, - { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, - { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, - { GPCMD_SET_STREAMING, "Set Streaming" }, - { GPCMD_READ_CD_MSF, "Read CD MSF" }, - { GPCMD_SCAN, "Scan" }, - { GPCMD_SET_SPEED, "Set Speed" }, - { GPCMD_PLAY_CD, "Play CD" }, - { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, - { GPCMD_READ_CD, "Read CD" }, -}; - - - -/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const char * const sense_key_texts[16] = { - "No sense data", - "Recovered error", - "Not ready", - "Medium error", - "Hardware error", - "Illegal request", - "Unit attention", - "Data protect", - "Blank check", - "(reserved)", - "(reserved)", - "Aborted command", - "(reserved)", - "(reserved)", - "Miscompare", - "(reserved)", -}; - -/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const struct { - unsigned long asc_ascq; - const char * const text; -} sense_data_texts[] = { - { 0x000000, "No additional sense information" }, - { 0x000011, "Play operation in progress" }, - { 0x000012, "Play operation paused" }, - { 0x000013, "Play operation successfully completed" }, - { 0x000014, "Play operation stopped due to error" }, - { 0x000015, "No current audio status to return" }, - { 0x010c0a, "Write error - padding blocks added" }, - { 0x011700, "Recovered data with no error correction applied" }, - { 0x011701, "Recovered data with retries" }, - { 0x011702, "Recovered data with positive head offset" }, - { 0x011703, "Recovered data with negative head offset" }, - { 0x011704, "Recovered data with retries and/or CIRC applied" }, - { 0x011705, "Recovered data using previous sector ID" }, - { 0x011800, "Recovered data with error correction applied" }, - { 0x011801, "Recovered data with error correction and retries applied"}, - { 0x011802, "Recovered data - the data was auto-reallocated" }, - { 0x011803, "Recovered data with CIRC" }, - { 0x011804, "Recovered data with L-EC" }, - { 0x015d00, - "Failure prediction threshold exceeded - Predicted logical unit failure" }, - { 0x015d01, - "Failure prediction threshold exceeded - Predicted media failure" }, - { 0x015dff, "Failure prediction threshold exceeded - False" }, - { 0x017301, "Power calibration area almost full" }, - { 0x020400, "Logical unit not ready - cause not reportable" }, - /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ - { 0x020401, - "Logical unit not ready - in progress [sic] of becoming ready" }, - { 0x020402, "Logical unit not ready - initializing command required" }, - { 0x020403, "Logical unit not ready - manual intervention required" }, - { 0x020404, "Logical unit not ready - format in progress" }, - { 0x020407, "Logical unit not ready - operation in progress" }, - { 0x020408, "Logical unit not ready - long write in progress" }, - { 0x020600, "No reference position found (media may be upside down)" }, - { 0x023000, "Incompatible medium installed" }, - { 0x023a00, "Medium not present" }, - { 0x025300, "Media load or eject failed" }, - { 0x025700, "Unable to recover table of contents" }, - { 0x030300, "Peripheral device write fault" }, - { 0x030301, "No write current" }, - { 0x030302, "Excessive write errors" }, - { 0x030c00, "Write error" }, - { 0x030c01, "Write error - Recovered with auto reallocation" }, - { 0x030c02, "Write error - auto reallocation failed" }, - { 0x030c03, "Write error - recommend reassignment" }, - { 0x030c04, "Compression check miscompare error" }, - { 0x030c05, "Data expansion occurred during compress" }, - { 0x030c06, "Block not compressible" }, - { 0x030c07, "Write error - recovery needed" }, - { 0x030c08, "Write error - recovery failed" }, - { 0x030c09, "Write error - loss of streaming" }, - { 0x031100, "Unrecovered read error" }, - { 0x031106, "CIRC unrecovered error" }, - { 0x033101, "Format command failed" }, - { 0x033200, "No defect spare location available" }, - { 0x033201, "Defect list update failure" }, - { 0x035100, "Erase failure" }, - { 0x037200, "Session fixation error" }, - { 0x037201, "Session fixation error writin lead-in" }, - { 0x037202, "Session fixation error writin lead-out" }, - { 0x037300, "CD control error" }, - { 0x037302, "Power calibration area is full" }, - { 0x037303, "Power calibration area error" }, - { 0x037304, "Program memory area / RMA update failure" }, - { 0x037305, "Program memory area / RMA is full" }, - { 0x037306, "Program memory area / RMA is (almost) full" }, - - { 0x040200, "No seek complete" }, - { 0x040300, "Write fault" }, - { 0x040900, "Track following error" }, - { 0x040901, "Tracking servo failure" }, - { 0x040902, "Focus servo failure" }, - { 0x040903, "Spindle servo failure" }, - { 0x041500, "Random positioning error" }, - { 0x041501, "Mechanical positioning or changer error" }, - { 0x041502, "Positioning error detected by read of medium" }, - { 0x043c00, "Mechanical positioning or changer error" }, - { 0x044000, "Diagnostic failure on component (ASCQ)" }, - { 0x044400, "Internal CD/DVD logical unit failure" }, - { 0x04b600, "Media load mechanism failed" }, - { 0x051a00, "Parameter list length error" }, - { 0x052000, "Invalid command operation code" }, - { 0x052100, "Logical block address out of range" }, - { 0x052102, "Invalid address for write" }, - { 0x052400, "Invalid field in command packet" }, - { 0x052600, "Invalid field in parameter list" }, - { 0x052601, "Parameter not supported" }, - { 0x052602, "Parameter value invalid" }, - { 0x052700, "Write protected media" }, - { 0x052c00, "Command sequence error" }, - { 0x052c03, "Current program area is not empty" }, - { 0x052c04, "Current program area is empty" }, - { 0x053001, "Cannot read medium - unknown format" }, - { 0x053002, "Cannot read medium - incompatible format" }, - { 0x053900, "Saving parameters not supported" }, - { 0x054e00, "Overlapped commands attempted" }, - { 0x055302, "Medium removal prevented" }, - { 0x055500, "System resource failure" }, - { 0x056300, "End of user area encountered on this track" }, - { 0x056400, "Illegal mode for this track or incompatible medium" }, - { 0x056f00, "Copy protection key exchange failure - Authentication failure" }, - { 0x056f01, "Copy protection key exchange failure - Key not present" }, - { 0x056f02, "Copy protection key exchange failure - Key not established" }, - { 0x056f03, "Read of scrambled sector without authentication" }, - { 0x056f04, "Media region code is mismatched to logical unit" }, - { 0x056f05, "Drive region must be permanent / region reset count error" }, - { 0x057203, "Session fixation error - incomplete track in session" }, - { 0x057204, "Empty or partially written reserved track" }, - { 0x057205, "No more RZONE reservations are allowed" }, - { 0x05bf00, "Loss of streaming" }, - { 0x062800, "Not ready to ready transition, medium may have changed" }, - { 0x062900, "Power on, reset or hardware reset occurred" }, - { 0x062a00, "Parameters changed" }, - { 0x062a01, "Mode parameters changed" }, - { 0x062e00, "Insufficient time for operation" }, - { 0x063f00, "Logical unit operating conditions have changed" }, - { 0x063f01, "Microcode has been changed" }, - { 0x065a00, "Operator request or state change input (unspecified)" }, - { 0x065a01, "Operator medium removal request" }, - { 0x0bb900, "Play operation aborted" }, - - /* Here we use 0xff for the key (not a valid key) to signify - * that these can have _any_ key value associated with them... */ - { 0xff0401, "Logical unit is in process of becoming ready" }, - { 0xff0400, "Logical unit not ready, cause not reportable" }, - { 0xff0402, "Logical unit not ready, initializing command required" }, - { 0xff0403, "Logical unit not ready, manual intervention required" }, - { 0xff0500, "Logical unit does not respond to selection" }, - { 0xff0800, "Logical unit communication failure" }, - { 0xff0802, "Logical unit communication parity error" }, - { 0xff0801, "Logical unit communication time-out" }, - { 0xff2500, "Logical unit not supported" }, - { 0xff4c00, "Logical unit failed self-configuration" }, - { 0xff3e00, "Logical unit has not self-configured yet" }, -}; -#endif - +/* ide-cd_verbose.c */ +void ide_cd_log_error(const char *, struct request *, struct request_sense *); + +/* ide-cd.c functions used by ide-cd_ioctl.c */ +void ide_cd_init_rq(ide_drive_t *, struct request *); +int ide_cd_queue_pc(ide_drive_t *, struct request *); +int ide_cd_read_toc(ide_drive_t *, struct request_sense *); +int ide_cdrom_get_capabilities(ide_drive_t *, u8 *); +void ide_cdrom_update_speed(ide_drive_t *, u8 *); +int cdrom_check_status(ide_drive_t *, struct request_sense *); + +/* ide-cd_ioctl.c */ +int ide_cdrom_open_real(struct cdrom_device_info *, int); +void ide_cdrom_release_real(struct cdrom_device_info *); +int ide_cdrom_drive_status(struct cdrom_device_info *, int); +int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int); +int ide_cdrom_tray_move(struct cdrom_device_info *, int); +int ide_cdrom_lock_door(struct cdrom_device_info *, int); +int ide_cdrom_select_speed(struct cdrom_device_info *, int); +int ide_cdrom_get_last_session(struct cdrom_device_info *, + struct cdrom_multisession *); +int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); +int ide_cdrom_reset(struct cdrom_device_info *cdi); +int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); +int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *); #endif /* _IDE_CD_H */ diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c new file mode 100644 index 000000000000..b68284de4e85 --- /dev/null +++ b/drivers/ide/ide-cd_ioctl.c @@ -0,0 +1,475 @@ +/* + * cdrom.c IOCTLs handling for ide-cd driver. + * + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + */ + +#include <linux/kernel.h> +#include <linux/cdrom.h> +#include <linux/ide.h> +#include <scsi/scsi.h> + +#include "ide-cd.h" + +/**************************************************************************** + * Other driver requests (open, close, check media change). + */ +int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose) +{ + return 0; +} + +/* + * Close down the device. Invalidate all cached blocks. + */ +void ide_cdrom_release_real(struct cdrom_device_info *cdi) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + + if (!cdi->use_count) + cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID; +} + +/* + * add logic to try GET_EVENT command first to check for media and tray + * status. this should be supported by newer cd-r/w and all DVD etc + * drives + */ +int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) +{ + ide_drive_t *drive = cdi->handle; + struct media_event_desc med; + struct request_sense sense; + int stat; + + if (slot_nr != CDSL_CURRENT) + return -EINVAL; + + stat = cdrom_check_status(drive, &sense); + if (!stat || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) + return CDS_DISC_OK; + else if (med.door_open) + return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; + } + + if (sense.sense_key == NOT_READY && sense.asc == 0x04 + && sense.ascq == 0x04) + return CDS_DISC_OK; + + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (sense.sense_key == NOT_READY) { + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; + } + return CDS_DRIVE_NOT_READY; +} + +int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi, + int slot_nr) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + int retval; + + if (slot_nr == CDSL_CURRENT) { + (void) cdrom_check_status(drive, NULL); + retval = (cd->cd_flags & IDE_CD_FLAG_MEDIA_CHANGED) ? 1 : 0; + cd->cd_flags &= ~IDE_CD_FLAG_MEDIA_CHANGED; + return retval; + } else { + return -EINVAL; + } +} + +/* Eject the disk if EJECTFLAG is 0. + If EJECTFLAG is 1, try to reload the disk. */ +static +int cdrom_eject(ide_drive_t *drive, int ejectflag, + struct request_sense *sense) +{ + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + struct request req; + char loej = 0x02; + + if ((cd->cd_flags & IDE_CD_FLAG_NO_EJECT) && !ejectflag) + return -EDRIVE_CANT_DO_THIS; + + /* reload fails on some drives, if the tray is locked */ + if ((cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) && ejectflag) + return 0; + + ide_cd_init_rq(drive, &req); + + /* only tell drive to close tray if open, if it can do that */ + if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY)) + loej = 0; + + req.sense = sense; + req.cmd[0] = GPCMD_START_STOP_UNIT; + req.cmd[4] = loej | (ejectflag != 0); + + return ide_cd_queue_pc(drive, &req); +} + +/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ +static +int ide_cd_lockdoor(ide_drive_t *drive, int lockflag, + struct request_sense *sense) +{ + struct cdrom_info *cd = drive->driver_data; + struct request_sense my_sense; + struct request req; + int stat; + + if (sense == NULL) + sense = &my_sense; + + /* If the drive cannot lock the door, just pretend. */ + if (cd->cd_flags & IDE_CD_FLAG_NO_DOORLOCK) { + stat = 0; + } else { + ide_cd_init_rq(drive, &req); + req.sense = sense; + req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + req.cmd[4] = lockflag ? 1 : 0; + stat = ide_cd_queue_pc(drive, &req); + } + + /* If we got an illegal field error, the drive + probably cannot lock the door. */ + if (stat != 0 && + sense->sense_key == ILLEGAL_REQUEST && + (sense->asc == 0x24 || sense->asc == 0x20)) { + printk(KERN_ERR "%s: door locking not supported\n", + drive->name); + cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK; + stat = 0; + } + + /* no medium, that's alright. */ + if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) + stat = 0; + + if (stat == 0) { + if (lockflag) + cd->cd_flags |= IDE_CD_FLAG_DOOR_LOCKED; + else + cd->cd_flags &= ~IDE_CD_FLAG_DOOR_LOCKED; + } + + return stat; +} + +int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position) +{ + ide_drive_t *drive = cdi->handle; + struct request_sense sense; + + if (position) { + int stat = ide_cd_lockdoor(drive, 0, &sense); + + if (stat) + return stat; + } + + return cdrom_eject(drive, !position, &sense); +} + +int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock) +{ + ide_drive_t *drive = cdi->handle; + + return ide_cd_lockdoor(drive, lock, NULL); +} + +/* + * ATAPI devices are free to select the speed you request or any slower + * rate. :-( Requesting too fast a speed will _not_ produce an error. + */ +int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + struct request rq; + struct request_sense sense; + u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; + int stat; + + ide_cd_init_rq(drive, &rq); + + rq.sense = &sense; + + if (speed == 0) + speed = 0xffff; /* set to max */ + else + speed *= 177; /* Nx to kbytes/s */ + + rq.cmd[0] = GPCMD_SET_SPEED; + /* Read Drive speed in kbytes/second MSB/LSB */ + rq.cmd[2] = (speed >> 8) & 0xff; + rq.cmd[3] = speed & 0xff; + if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) != + (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) { + /* Write Drive speed in kbytes/second MSB/LSB */ + rq.cmd[4] = (speed >> 8) & 0xff; + rq.cmd[5] = speed & 0xff; + } + + stat = ide_cd_queue_pc(drive, &rq); + + if (!ide_cdrom_get_capabilities(drive, buf)) { + ide_cdrom_update_speed(drive, buf); + cdi->speed = cd->current_speed; + } + + return 0; +} + +int ide_cdrom_get_last_session(struct cdrom_device_info *cdi, + struct cdrom_multisession *ms_info) +{ + struct atapi_toc *toc; + ide_drive_t *drive = cdi->handle; + struct cdrom_info *info = drive->driver_data; + struct request_sense sense; + int ret; + + if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0 || !info->toc) { + ret = ide_cd_read_toc(drive, &sense); + if (ret) + return ret; + } + + toc = info->toc; + ms_info->addr.lba = toc->last_session_lba; + ms_info->xa_flag = toc->xa_flag; + + return 0; +} + +int ide_cdrom_get_mcn(struct cdrom_device_info *cdi, + struct cdrom_mcn *mcn_info) +{ + ide_drive_t *drive = cdi->handle; + int stat, mcnlen; + struct request rq; + char buf[24]; + + ide_cd_init_rq(drive, &rq); + + rq.data = buf; + rq.data_len = sizeof(buf); + + rq.cmd[0] = GPCMD_READ_SUBCHANNEL; + rq.cmd[1] = 2; /* MSF addressing */ + rq.cmd[2] = 0x40; /* request subQ data */ + rq.cmd[3] = 2; /* format */ + rq.cmd[8] = sizeof(buf); + + stat = ide_cd_queue_pc(drive, &rq); + if (stat) + return stat; + + mcnlen = sizeof(mcn_info->medium_catalog_number) - 1; + memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen); + mcn_info->medium_catalog_number[mcnlen] = '\0'; + + return 0; +} + +int ide_cdrom_reset(struct cdrom_device_info *cdi) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + struct request_sense sense; + struct request req; + int ret; + + ide_cd_init_rq(drive, &req); + req.cmd_type = REQ_TYPE_SPECIAL; + req.cmd_flags = REQ_QUIET; + ret = ide_do_drive_cmd(drive, &req, ide_wait); + + /* + * A reset will unlock the door. If it was previously locked, + * lock it again. + */ + if (cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) + (void)ide_cd_lockdoor(drive, 1, &sense); + + return ret; +} + +static int ide_cd_get_toc_entry(ide_drive_t *drive, int track, + struct atapi_toc_entry **ent) +{ + struct cdrom_info *info = drive->driver_data; + struct atapi_toc *toc = info->toc; + int ntracks; + + /* + * don't serve cached data, if the toc isn't valid + */ + if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0) + return -EINVAL; + + /* Check validity of requested track number. */ + ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + + if (toc->hdr.first_track == CDROM_LEADOUT) + ntracks = 0; + + if (track == CDROM_LEADOUT) + *ent = &toc->ent[ntracks]; + else if (track < toc->hdr.first_track || track > toc->hdr.last_track) + return -EINVAL; + else + *ent = &toc->ent[track - toc->hdr.first_track]; + + return 0; +} + +static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg) +{ + struct cdrom_ti *ti = arg; + struct atapi_toc_entry *first_toc, *last_toc; + unsigned long lba_start, lba_end; + int stat; + struct request rq; + struct request_sense sense; + + stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc); + if (stat) + return stat; + + stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc); + if (stat) + return stat; + + if (ti->cdti_trk1 != CDROM_LEADOUT) + ++last_toc; + lba_start = first_toc->addr.lba; + lba_end = last_toc->addr.lba; + + if (lba_end <= lba_start) + return -EINVAL; + + ide_cd_init_rq(drive, &rq); + + rq.sense = &sense; + rq.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + lba_to_msf(lba_start, &rq.cmd[3], &rq.cmd[4], &rq.cmd[5]); + lba_to_msf(lba_end - 1, &rq.cmd[6], &rq.cmd[7], &rq.cmd[8]); + + return ide_cd_queue_pc(drive, &rq); +} + +static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg) +{ + struct cdrom_info *cd = drive->driver_data; + struct cdrom_tochdr *tochdr = arg; + struct atapi_toc *toc; + int stat; + + /* Make sure our saved TOC is valid. */ + stat = ide_cd_read_toc(drive, NULL); + if (stat) + return stat; + + toc = cd->toc; + tochdr->cdth_trk0 = toc->hdr.first_track; + tochdr->cdth_trk1 = toc->hdr.last_track; + + return 0; +} + +static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg) +{ + struct cdrom_tocentry *tocentry = arg; + struct atapi_toc_entry *toce; + int stat; + + stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce); + if (stat) + return stat; + + tocentry->cdte_ctrl = toce->control; + tocentry->cdte_adr = toce->adr; + if (tocentry->cdte_format == CDROM_MSF) { + lba_to_msf(toce->addr.lba, + &tocentry->cdte_addr.msf.minute, + &tocentry->cdte_addr.msf.second, + &tocentry->cdte_addr.msf.frame); + } else + tocentry->cdte_addr.lba = toce->addr.lba; + + return 0; +} + +int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi, + unsigned int cmd, void *arg) +{ + ide_drive_t *drive = cdi->handle; + + switch (cmd) { + /* + * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since + * atapi doesn't support it + */ + case CDROMPLAYTRKIND: + return ide_cd_fake_play_trkind(drive, arg); + case CDROMREADTOCHDR: + return ide_cd_read_tochdr(drive, arg); + case CDROMREADTOCENTRY: + return ide_cd_read_tocentry(drive, arg); + default: + return -EINVAL; + } +} + +/* the generic packet interface to cdrom.c */ +int ide_cdrom_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + struct request req; + ide_drive_t *drive = cdi->handle; + + if (cgc->timeout <= 0) + cgc->timeout = ATAPI_WAIT_PC; + + /* here we queue the commands from the uniform CD-ROM + layer. the packet must be complete, as we do not + touch it at all. */ + ide_cd_init_rq(drive, &req); + memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE); + if (cgc->sense) + memset(cgc->sense, 0, sizeof(struct request_sense)); + req.data = cgc->buffer; + req.data_len = cgc->buflen; + req.timeout = cgc->timeout; + + if (cgc->quiet) + req.cmd_flags |= REQ_QUIET; + + req.sense = cgc->sense; + cgc->stat = ide_cd_queue_pc(drive, &req); + if (!cgc->stat) + cgc->buflen -= req.data_len; + return cgc->stat; +} diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c new file mode 100644 index 000000000000..6ed7ca071331 --- /dev/null +++ b/drivers/ide/ide-cd_verbose.c @@ -0,0 +1,359 @@ +/* + * Verbose error logging for ATAPI CD/DVD devices. + * + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + */ + +#include <linux/kernel.h> +#include <linux/blkdev.h> +#include <linux/cdrom.h> +#include <scsi/scsi.h> + +#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS +void ide_cd_log_error(const char *name, struct request *failed_command, + struct request_sense *sense) +{ + /* Suppress printing unit attention and `in progress of becoming ready' + errors when we're not being verbose. */ + if (sense->sense_key == UNIT_ATTENTION || + (sense->sense_key == NOT_READY && (sense->asc == 4 || + sense->asc == 0x3a))) + return; + + printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x " + "asc: 0x%02x ascq: 0x%02x\n", + name, sense->error_code, sense->sense_key, + sense->asc, sense->ascq); +} +#else +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const struct { + unsigned short packet_command; + const char * const text; +} packet_command_texts[] = { + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, + { GPCMD_REQUEST_SENSE, "Request Sense" }, + { GPCMD_FORMAT_UNIT, "Format Unit" }, + { GPCMD_INQUIRY, "Inquiry" }, + { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, + { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, + { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, + { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, + { GPCMD_READ_10, "Read 10" }, + { GPCMD_WRITE_10, "Write 10" }, + { GPCMD_SEEK, "Seek" }, + { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, + { GPCMD_VERIFY_10, "Verify 10" }, + { GPCMD_FLUSH_CACHE, "Flush Cache" }, + { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, + { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, + { GPCMD_READ_HEADER, "Read Header" }, + { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, + { GPCMD_GET_CONFIGURATION, "Get Configuration" }, + { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, + { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, + { GPCMD_GET_EVENT_STATUS_NOTIFICATION, + "Get Event Status Notification" }, + { GPCMD_PAUSE_RESUME, "Pause/Resume" }, + { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, + { GPCMD_READ_DISC_INFO, "Read Disc Info" }, + { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, + { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, + { GPCMD_SEND_OPC, "Send OPC" }, + { GPCMD_MODE_SELECT_10, "Mode Select 10" }, + { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, + { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, + { GPCMD_CLOSE_TRACK, "Close Track" }, + { GPCMD_BLANK, "Blank" }, + { GPCMD_SEND_EVENT, "Send Event" }, + { GPCMD_SEND_KEY, "Send Key" }, + { GPCMD_REPORT_KEY, "Report Key" }, + { GPCMD_LOAD_UNLOAD, "Load/Unload" }, + { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, + { GPCMD_READ_12, "Read 12" }, + { GPCMD_GET_PERFORMANCE, "Get Performance" }, + { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, + { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, + { GPCMD_SET_STREAMING, "Set Streaming" }, + { GPCMD_READ_CD_MSF, "Read CD MSF" }, + { GPCMD_SCAN, "Scan" }, + { GPCMD_SET_SPEED, "Set Speed" }, + { GPCMD_PLAY_CD, "Play CD" }, + { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, + { GPCMD_READ_CD, "Read CD" }, +}; + +/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const char * const sense_key_texts[16] = { + "No sense data", + "Recovered error", + "Not ready", + "Medium error", + "Hardware error", + "Illegal request", + "Unit attention", + "Data protect", + "Blank check", + "(reserved)", + "(reserved)", + "Aborted command", + "(reserved)", + "(reserved)", + "Miscompare", + "(reserved)", +}; + +/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const struct { + unsigned long asc_ascq; + const char * const text; +} sense_data_texts[] = { + { 0x000000, "No additional sense information" }, + { 0x000011, "Play operation in progress" }, + { 0x000012, "Play operation paused" }, + { 0x000013, "Play operation successfully completed" }, + { 0x000014, "Play operation stopped due to error" }, + { 0x000015, "No current audio status to return" }, + { 0x010c0a, "Write error - padding blocks added" }, + { 0x011700, "Recovered data with no error correction applied" }, + { 0x011701, "Recovered data with retries" }, + { 0x011702, "Recovered data with positive head offset" }, + { 0x011703, "Recovered data with negative head offset" }, + { 0x011704, "Recovered data with retries and/or CIRC applied" }, + { 0x011705, "Recovered data using previous sector ID" }, + { 0x011800, "Recovered data with error correction applied" }, + { 0x011801, "Recovered data with error correction and retries applied"}, + { 0x011802, "Recovered data - the data was auto-reallocated" }, + { 0x011803, "Recovered data with CIRC" }, + { 0x011804, "Recovered data with L-EC" }, + { 0x015d00, "Failure prediction threshold exceeded" + " - Predicted logical unit failure" }, + { 0x015d01, "Failure prediction threshold exceeded" + " - Predicted media failure" }, + { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x017301, "Power calibration area almost full" }, + { 0x020400, "Logical unit not ready - cause not reportable" }, + /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ + { 0x020401, "Logical unit not ready" + " - in progress [sic] of becoming ready" }, + { 0x020402, "Logical unit not ready - initializing command required" }, + { 0x020403, "Logical unit not ready - manual intervention required" }, + { 0x020404, "Logical unit not ready - format in progress" }, + { 0x020407, "Logical unit not ready - operation in progress" }, + { 0x020408, "Logical unit not ready - long write in progress" }, + { 0x020600, "No reference position found (media may be upside down)" }, + { 0x023000, "Incompatible medium installed" }, + { 0x023a00, "Medium not present" }, + { 0x025300, "Media load or eject failed" }, + { 0x025700, "Unable to recover table of contents" }, + { 0x030300, "Peripheral device write fault" }, + { 0x030301, "No write current" }, + { 0x030302, "Excessive write errors" }, + { 0x030c00, "Write error" }, + { 0x030c01, "Write error - Recovered with auto reallocation" }, + { 0x030c02, "Write error - auto reallocation failed" }, + { 0x030c03, "Write error - recommend reassignment" }, + { 0x030c04, "Compression check miscompare error" }, + { 0x030c05, "Data expansion occurred during compress" }, + { 0x030c06, "Block not compressible" }, + { 0x030c07, "Write error - recovery needed" }, + { 0x030c08, "Write error - recovery failed" }, + { 0x030c09, "Write error - loss of streaming" }, + { 0x031100, "Unrecovered read error" }, + { 0x031106, "CIRC unrecovered error" }, + { 0x033101, "Format command failed" }, + { 0x033200, "No defect spare location available" }, + { 0x033201, "Defect list update failure" }, + { 0x035100, "Erase failure" }, + { 0x037200, "Session fixation error" }, + { 0x037201, "Session fixation error writin lead-in" }, + { 0x037202, "Session fixation error writin lead-out" }, + { 0x037300, "CD control error" }, + { 0x037302, "Power calibration area is full" }, + { 0x037303, "Power calibration area error" }, + { 0x037304, "Program memory area / RMA update failure" }, + { 0x037305, "Program memory area / RMA is full" }, + { 0x037306, "Program memory area / RMA is (almost) full" }, + { 0x040200, "No seek complete" }, + { 0x040300, "Write fault" }, + { 0x040900, "Track following error" }, + { 0x040901, "Tracking servo failure" }, + { 0x040902, "Focus servo failure" }, + { 0x040903, "Spindle servo failure" }, + { 0x041500, "Random positioning error" }, + { 0x041501, "Mechanical positioning or changer error" }, + { 0x041502, "Positioning error detected by read of medium" }, + { 0x043c00, "Mechanical positioning or changer error" }, + { 0x044000, "Diagnostic failure on component (ASCQ)" }, + { 0x044400, "Internal CD/DVD logical unit failure" }, + { 0x04b600, "Media load mechanism failed" }, + { 0x051a00, "Parameter list length error" }, + { 0x052000, "Invalid command operation code" }, + { 0x052100, "Logical block address out of range" }, + { 0x052102, "Invalid address for write" }, + { 0x052400, "Invalid field in command packet" }, + { 0x052600, "Invalid field in parameter list" }, + { 0x052601, "Parameter not supported" }, + { 0x052602, "Parameter value invalid" }, + { 0x052700, "Write protected media" }, + { 0x052c00, "Command sequence error" }, + { 0x052c03, "Current program area is not empty" }, + { 0x052c04, "Current program area is empty" }, + { 0x053001, "Cannot read medium - unknown format" }, + { 0x053002, "Cannot read medium - incompatible format" }, + { 0x053900, "Saving parameters not supported" }, + { 0x054e00, "Overlapped commands attempted" }, + { 0x055302, "Medium removal prevented" }, + { 0x055500, "System resource failure" }, + { 0x056300, "End of user area encountered on this track" }, + { 0x056400, "Illegal mode for this track or incompatible medium" }, + { 0x056f00, "Copy protection key exchange failure" + " - Authentication failure" }, + { 0x056f01, "Copy protection key exchange failure - Key not present" }, + { 0x056f02, "Copy protection key exchange failure" + " - Key not established" }, + { 0x056f03, "Read of scrambled sector without authentication" }, + { 0x056f04, "Media region code is mismatched to logical unit" }, + { 0x056f05, "Drive region must be permanent" + " / region reset count error" }, + { 0x057203, "Session fixation error - incomplete track in session" }, + { 0x057204, "Empty or partially written reserved track" }, + { 0x057205, "No more RZONE reservations are allowed" }, + { 0x05bf00, "Loss of streaming" }, + { 0x062800, "Not ready to ready transition, medium may have changed" }, + { 0x062900, "Power on, reset or hardware reset occurred" }, + { 0x062a00, "Parameters changed" }, + { 0x062a01, "Mode parameters changed" }, + { 0x062e00, "Insufficient time for operation" }, + { 0x063f00, "Logical unit operating conditions have changed" }, + { 0x063f01, "Microcode has been changed" }, + { 0x065a00, "Operator request or state change input (unspecified)" }, + { 0x065a01, "Operator medium removal request" }, + { 0x0bb900, "Play operation aborted" }, + /* Here we use 0xff for the key (not a valid key) to signify + * that these can have _any_ key value associated with them... */ + { 0xff0401, "Logical unit is in process of becoming ready" }, + { 0xff0400, "Logical unit not ready, cause not reportable" }, + { 0xff0402, "Logical unit not ready, initializing command required" }, + { 0xff0403, "Logical unit not ready, manual intervention required" }, + { 0xff0500, "Logical unit does not respond to selection" }, + { 0xff0800, "Logical unit communication failure" }, + { 0xff0802, "Logical unit communication parity error" }, + { 0xff0801, "Logical unit communication time-out" }, + { 0xff2500, "Logical unit not supported" }, + { 0xff4c00, "Logical unit failed self-configuration" }, + { 0xff3e00, "Logical unit has not self-configured yet" }, +}; + +void ide_cd_log_error(const char *name, struct request *failed_command, + struct request_sense *sense) +{ + int i; + const char *s = "bad sense key!"; + char buf[80]; + + printk(KERN_ERR "ATAPI device %s:\n", name); + if (sense->error_code == 0x70) + printk(KERN_CONT " Error: "); + else if (sense->error_code == 0x71) + printk(" Deferred Error: "); + else if (sense->error_code == 0x7f) + printk(KERN_CONT " Vendor-specific Error: "); + else + printk(KERN_CONT " Unknown Error Type: "); + + if (sense->sense_key < ARRAY_SIZE(sense_key_texts)) + s = sense_key_texts[sense->sense_key]; + + printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key); + + if (sense->asc == 0x40) { + sprintf(buf, "Diagnostic failure on component 0x%02x", + sense->ascq); + s = buf; + } else { + int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts); + unsigned long key = (sense->sense_key << 16); + + key |= (sense->asc << 8); + if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) + key |= sense->ascq; + s = NULL; + + while (hi > lo) { + mid = (lo + hi) / 2; + if (sense_data_texts[mid].asc_ascq == key || + sense_data_texts[mid].asc_ascq == (0xff0000|key)) { + s = sense_data_texts[mid].text; + break; + } else if (sense_data_texts[mid].asc_ascq > key) + hi = mid; + else + lo = mid + 1; + } + } + + if (s == NULL) { + if (sense->asc > 0x80) + s = "(vendor-specific error)"; + else + s = "(reserved error code)"; + } + + printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", + s, sense->asc, sense->ascq); + + if (failed_command != NULL) { + int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts); + s = NULL; + + while (hi > lo) { + mid = (lo + hi) / 2; + if (packet_command_texts[mid].packet_command == + failed_command->cmd[0]) { + s = packet_command_texts[mid].text; + break; + } + if (packet_command_texts[mid].packet_command > + failed_command->cmd[0]) + hi = mid; + else + lo = mid + 1; + } + + printk(KERN_ERR " The failed \"%s\" packet command " + "was: \n \"", s); + for (i = 0; i < sizeof(failed_command->cmd); i++) + printk(KERN_CONT "%02x ", failed_command->cmd[i]); + printk(KERN_CONT "\"\n"); + } + + /* The SKSV bit specifies validity of the sense_key_specific + * in the next two commands. It is bit 7 of the first byte. + * In the case of NOT_READY, if SKSV is set the drive can + * give us nice ETA readings. + */ + if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { + int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; + + printk(KERN_ERR " Command is %02d%% complete\n", + progress / 0xffff); + } + + if (sense->sense_key == ILLEGAL_REQUEST && + (sense->sks[0] & 0x80) != 0) { + printk(KERN_ERR " Error in %s byte %d", + (sense->sks[0] & 0x40) != 0 ? + "command packet" : "command data", + (sense->sks[1] << 8) + sense->sks[2]); + + if ((sense->sks[0] & 0x40) != 0) + printk(KERN_CONT " bit %d", sense->sks[0] & 0x07); + + printk(KERN_CONT "\n"); + } +} +#endif diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 717e114ced52..3c69822507e2 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1,10 +1,9 @@ /* - * linux/drivers/ide/ide-disk.c Version 1.18 Mar 05, 2003 - * - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) - * Copyright (C) 1998-2002 Linux ATA Development - * Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2003 Red Hat <alan@redhat.com> + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1998-2002 Linux ATA Development + * Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat <alan@redhat.com> + * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz */ /* diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 5bf32038dc43..7beaf1e9be12 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -1,15 +1,13 @@ /* - * linux/drivers/ide/ide-dma.c Version 4.10 June 9, 2000 + * Copyright (C) 1995-1998 Mark Lord + * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz * - * Copyright (c) 1999-2000 Andre Hedrick <andre@linux-ide.org> * May be copied or modified under the terms of the GNU General Public License */ /* * Special Thanks to Mark for his Six years of work. - * - * Copyright (c) 1995-1998 Mark Lord - * May be copied or modified under the terms of the GNU General Public License */ /* @@ -85,6 +83,7 @@ #include <linux/ide.h> #include <linux/delay.h> #include <linux/scatterlist.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/irq.h> @@ -169,16 +168,15 @@ static int ide_dma_good_drive(ide_drive_t *drive) return ide_in_drive_list(drive->id, drive_whitelist); } -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_build_sglist - map IDE scatter gather for DMA I/O * @drive: the drive to build the DMA table for * @rq: the request holding the sg list * - * Perform the PCI mapping magic necessary to access the source or - * target buffers of a request via PCI DMA. The lower layers of the + * Perform the DMA mapping magic necessary to access the source or + * target buffers of a request via DMA. The lower layers of the * kernel provide the necessary cache management so that we can - * operate in a portable fashion + * operate in a portable fashion. */ int ide_build_sglist(ide_drive_t *drive, struct request *rq) @@ -186,20 +184,20 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq) ide_hwif_t *hwif = HWIF(drive); struct scatterlist *sg = hwif->sg_table; - BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256); - ide_map_sg(drive, rq); if (rq_data_dir(rq) == READ) - hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; + hwif->sg_dma_direction = DMA_FROM_DEVICE; else - hwif->sg_dma_direction = PCI_DMA_TODEVICE; + hwif->sg_dma_direction = DMA_TO_DEVICE; - return pci_map_sg(hwif->pci_dev, sg, hwif->sg_nents, hwif->sg_dma_direction); + return dma_map_sg(hwif->dev, sg, hwif->sg_nents, + hwif->sg_dma_direction); } EXPORT_SYMBOL_GPL(ide_build_sglist); +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_build_dmatable - build IDE DMA table * @@ -284,16 +282,17 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq) *--table |= cpu_to_le32(0x80000000); return count; } + printk(KERN_ERR "%s: empty DMA table?\n", drive->name); + use_pio_instead: - pci_unmap_sg(hwif->pci_dev, - hwif->sg_table, - hwif->sg_nents, - hwif->sg_dma_direction); + ide_destroy_dmatable(drive); + return 0; /* revert to PIO for this request */ } EXPORT_SYMBOL_GPL(ide_build_dmatable); +#endif /** * ide_destroy_dmatable - clean up DMA mapping @@ -308,15 +307,15 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable); void ide_destroy_dmatable (ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - struct scatterlist *sg = HWIF(drive)->sg_table; - int nents = HWIF(drive)->sg_nents; + ide_hwif_t *hwif = drive->hwif; - pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction); + dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents, + hwif->sg_dma_direction); } EXPORT_SYMBOL_GPL(ide_destroy_dmatable); +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * config_drive_for_dma - attempt to activate IDE DMA * @drive: the drive to place in DMA mode @@ -474,8 +473,6 @@ void ide_dma_on(ide_drive_t *drive) drive->hwif->dma_host_set(drive, 1); } -EXPORT_SYMBOL(ide_dma_on); - #ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_dma_setup - begin a DMA phase @@ -847,10 +844,10 @@ EXPORT_SYMBOL(ide_dma_timeout); static void ide_release_dma_engine(ide_hwif_t *hwif) { if (hwif->dmatable_cpu) { - pci_free_consistent(hwif->pci_dev, - PRD_ENTRIES * PRD_BYTES, - hwif->dmatable_cpu, - hwif->dmatable_dma); + struct pci_dev *pdev = to_pci_dev(hwif->dev); + + pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES, + hwif->dmatable_cpu, hwif->dmatable_dma); hwif->dmatable_cpu = NULL; } } @@ -878,7 +875,9 @@ int ide_release_dma(ide_hwif_t *hwif) static int ide_allocate_dma_engine(ide_hwif_t *hwif) { - hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, + struct pci_dev *pdev = to_pci_dev(hwif->dev); + + hwif->dmatable_cpu = pci_alloc_consistent(pdev, PRD_ENTRIES * PRD_BYTES, &hwif->dmatable_dma); @@ -891,19 +890,19 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif) return 1; } -static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports) +static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base) { printk(KERN_INFO " %s: MMIO-DMA ", hwif->name); return 0; } -static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports) +static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base) { printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx", - hwif->name, base, base + ports - 1); + hwif->name, base, base + 7); - if (!request_region(base, ports, hwif->name)) { + if (!request_region(base, 8, hwif->name)) { printk(" -- Error, ports in use.\n"); return 1; } @@ -915,7 +914,7 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port if (!request_region(hwif->extra_base, hwif->cds->extra, hwif->cds->name)) { printk(" -- Error, extra ports in use.\n"); - release_region(base, ports); + release_region(base, 8); return 1; } hwif->extra_ports = hwif->cds->extra; @@ -925,17 +924,19 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port return 0; } -static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports) +static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base) { if (hwif->mmio) - return ide_mapped_mmio_dma(hwif, base,ports); + return ide_mapped_mmio_dma(hwif, base); - return ide_iomio_dma(hwif, base, ports); + return ide_iomio_dma(hwif, base); } -void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) +void ide_setup_dma(ide_hwif_t *hwif, unsigned long base) { - if (ide_dma_iobase(hwif, base, num_ports)) + u8 dma_stat; + + if (ide_dma_iobase(hwif, base)) return; if (ide_allocate_dma_engine(hwif)) { @@ -945,16 +946,16 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) hwif->dma_base = base; - if (!(hwif->dma_command)) - hwif->dma_command = hwif->dma_base; - if (!(hwif->dma_vendor1)) - hwif->dma_vendor1 = (hwif->dma_base + 1); - if (!(hwif->dma_status)) - hwif->dma_status = (hwif->dma_base + 2); - if (!(hwif->dma_vendor3)) - hwif->dma_vendor3 = (hwif->dma_base + 3); - if (!(hwif->dma_prdtable)) - hwif->dma_prdtable = (hwif->dma_base + 4); + if (!hwif->dma_command) + hwif->dma_command = hwif->dma_base + 0; + if (!hwif->dma_vendor1) + hwif->dma_vendor1 = hwif->dma_base + 1; + if (!hwif->dma_status) + hwif->dma_status = hwif->dma_base + 2; + if (!hwif->dma_vendor3) + hwif->dma_vendor3 = hwif->dma_base + 3; + if (!hwif->dma_prdtable) + hwif->dma_prdtable = hwif->dma_base + 4; if (!hwif->dma_host_set) hwif->dma_host_set = &ide_dma_host_set; @@ -973,13 +974,10 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) if (!hwif->dma_lost_irq) hwif->dma_lost_irq = &ide_dma_lost_irq; - if (hwif->chipset != ide_trm290) { - u8 dma_stat = hwif->INB(hwif->dma_status); - printk(", BIOS settings: %s:%s, %s:%s", - hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", - hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); - } - printk("\n"); + dma_stat = hwif->INB(hwif->dma_status); + printk(KERN_CONT ", BIOS settings: %s:%s, %s:%s\n", + hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "PIO", + hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "PIO"); } EXPORT_SYMBOL_GPL(ide_setup_dma); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index ff8232ef9659..3512637ae8d4 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1,13 +1,12 @@ /* - * linux/drivers/ide/ide-floppy.c Version 0.99 Feb 24 2002 + * IDE ATAPI floppy driver. * - * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> - * Copyright (C) 2000 - 2002 Paul Bristow <paul@paulbristow.net> + * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net> + * Copyright (C) 2005 Bartlomiej Zolnierkiewicz */ /* - * IDE ATAPI floppy driver. - * * The driver currently doesn't have any fancy features, just the bare * minimum read/write support. * @@ -17,67 +16,8 @@ * Iomega Zip 100/250 * Iomega PC Card Clik!/PocketZip * - * Many thanks to Lode Leroy <Lode.Leroy@www.ibase.be>, who tested so many - * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive. - * - * Ver 0.1 Oct 17 96 Initial test version, mostly based on ide-tape.c. - * Ver 0.2 Oct 31 96 Minor changes. - * Ver 0.3 Dec 2 96 Fixed error recovery bug. - * Ver 0.4 Jan 26 97 Add support for the HDIO_GETGEO ioctl. - * Ver 0.5 Feb 21 97 Add partitions support. - * Use the minimum of the LBA and CHS capacities. - * Avoid hwgroup->rq == NULL on the last irq. - * Fix potential null dereferencing with DEBUG_LOG. - * Ver 0.8 Dec 7 97 Increase irq timeout from 10 to 50 seconds. - * Add media write-protect detection. - * Issue START command only if TEST UNIT READY fails. - * Add work-around for IOMEGA ZIP revision 21.D. - * Remove idefloppy_get_capabilities(). - * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of - * bytes requested on each interrupt to be zero. - * Thanks to <shanos@es.co.nz> for pointing this out. - * Ver 0.9.sv Jan 6 01 Sam Varshavchik <mrsam@courier-mta.com> - * Implement low level formatting. Reimplemented - * IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp - * bit. My LS-120 drive barfs on - * IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me. - * Compromise by not reporting a failure to get this - * mode page. Implemented four IOCTLs in order to - * implement formatting. IOCTls begin with 0x4600, - * 0x46 is 'F' as in Format. - * Jan 9 01 Userland option to select format verify. - * Added PC_SUPPRESS_ERROR flag - some idefloppy drives - * do not implement IDEFLOPPY_CAPABILITIES_PAGE, and - * return a sense error. Suppress error reporting in - * this particular case in order to avoid spurious - * errors in syslog. The culprit is - * idefloppy_get_capability_page(), so move it to - * idefloppy_begin_format() so that it's not used - * unless absolutely necessary. - * If drive does not support format progress indication - * monitor the dsc bit in the status register. - * Also, O_NDELAY on open will allow the device to be - * opened without a disk available. This can be used to - * open an unformatted disk, or get the device capacity. - * Ver 0.91 Dec 11 99 Added IOMEGA Clik! drive support by - * <paul@paulbristow.net> - * Ver 0.92 Oct 22 00 Paul Bristow became official maintainer for this - * driver. Included Powerbook internal zip kludge. - * Ver 0.93 Oct 24 00 Fixed bugs for Clik! drive - * no disk on insert and disk change now works - * Ver 0.94 Oct 27 00 Tidied up to remove strstr(Clik) everywhere - * Ver 0.95 Nov 7 00 Brought across to kernel 2.4 - * Ver 0.96 Jan 7 01 Actually in line with release version of 2.4.0 - * including set_bit patch from Rusty Russell - * Ver 0.97 Jul 22 01 Merge 0.91-0.96 onto 0.9.sv for ac series - * Ver 0.97.sv Aug 3 01 Backported from 2.4.7-ac3 - * Ver 0.98 Oct 26 01 Split idefloppy_transfer_pc into two pieces to - * fix a lost interrupt problem. It appears the busy - * bit was being deasserted by my IOMEGA ATAPI ZIP 100 - * drive before the drive was actually ready. - * Ver 0.98a Oct 29 01 Expose delay value so we can play. - * Ver 0.99 Feb 24 02 Remove duplicate code, modify clik! detection code - * to support new PocketZip drives + * For a historical changelog see + * Documentation/ide/ChangeLog.ide-floppy.1996-2002 */ #define IDEFLOPPY_VERSION "0.99.newide" @@ -1658,7 +1598,6 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idefloppy_id_gcw gcw; #if IDEFLOPPY_DEBUG_INFO - u16 mask,i; char buffer[80]; #endif /* IDEFLOPPY_DEBUG_INFO */ @@ -1705,55 +1644,6 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id) default: sprintf(buffer, "Reserved");break; } printk(KERN_INFO "Command Packet Size: %s\n", buffer); - printk(KERN_INFO "Model: %.40s\n",id->model); - printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev); - printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no); - printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512); - printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); - printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); - printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); - printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); - printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n"); - printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO); - printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA); - printk(KERN_INFO "Single Word DMA supported modes:\n"); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_1word & mask) - printk(KERN_INFO " Mode %d%s\n", i, - (id->dma_1word & (mask << 8)) ? " (active)" : ""); - } - printk(KERN_INFO "Multi Word DMA supported modes:\n"); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_mword & mask) - printk(KERN_INFO " Mode %d%s\n", i, - (id->dma_mword & (mask << 8)) ? " (active)" : ""); - } - if (id->field_valid & 0x0002) { - printk(KERN_INFO "Enhanced PIO Modes: %s\n", - id->eide_pio_modes & 1 ? "Mode 3":"None"); - if (id->eide_dma_min == 0) - sprintf(buffer, "Not supported"); - else - sprintf(buffer, "%d ns",id->eide_dma_min); - printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer); - if (id->eide_dma_time == 0) - sprintf(buffer, "Not supported"); - else - sprintf(buffer, "%d ns",id->eide_dma_time); - printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer); - if (id->eide_pio == 0) - sprintf(buffer, "Not supported"); - else - sprintf(buffer, "%d ns",id->eide_pio); - printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n", - buffer); - if (id->eide_pio_iordy == 0) - sprintf(buffer, "Not supported"); - else - sprintf(buffer, "%d ns",id->eide_pio_iordy); - printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer); - } else - printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n"); #endif /* IDEFLOPPY_DEBUG_INFO */ if (gcw.protocol != 2) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index e6bb9cf24e3d..4bddef0c0b96 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1487,7 +1487,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) * remove all the ifdef PCI crap */ #ifdef CONFIG_BLK_DEV_IDEPCI - if (hwif->pci_dev && !hwif->pci_dev->vendor) + if (hwif->chipset != ide_pci) #endif /* CONFIG_BLK_DEV_IDEPCI */ { /* diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index e2a7e95e1636..16b1f6e12781 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide-iops.c Version 0.37 Mar 05, 2003 - * * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> * @@ -1168,7 +1166,7 @@ EXPORT_SYMBOL(ide_do_reset); /* * ide_wait_not_busy() waits for the currently selected device on the hwif - * to report a non-busy status, see comments in probe_hwif(). + * to report a non-busy status, see comments in ide_probe_port(). */ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) { diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 9b44fbdfe41f..b42940d8bf70 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -358,8 +358,10 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) if (!PCI_DMA_BUS_IS_PHYS) { addr = BLK_BOUNCE_ANY; } else if (on && drive->media == ide_disk) { - if (HWIF(drive)->pci_dev) - addr = HWIF(drive)->pci_dev->dma_mask; + struct device *dev = drive->hwif->dev; + + if (dev && dev->dma_mask) + addr = *dev->dma_mask; } if (drive->queue) diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index cbbb0f75be92..4bda5cf2be37 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide-pnp.c - * * This file provides autodetection for ISA PnP IDE interfaces. * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface. * diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index edf650b20c67..98a8af44bf64 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ide-probe.c Version 1.11 Mar 05, 2003 - * - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz */ /* @@ -129,6 +128,10 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) drive->id_read = 1; local_irq_enable(); +#ifdef DEBUG + printk(KERN_INFO "%s: dumping identify data\n", drive->name); + ide_dump_identify((u8 *)id); +#endif ide_fix_driveid(id); #if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) @@ -610,7 +613,7 @@ static void hwif_release_dev (struct device *dev) complete(&hwif->gendev_rel_comp); } -static void hwif_register (ide_hwif_t *hwif) +static void ide_register_port(ide_hwif_t *hwif) { int ret; @@ -618,8 +621,8 @@ static void hwif_register (ide_hwif_t *hwif) strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE); hwif->gendev.driver_data = hwif; if (hwif->gendev.parent == NULL) { - if (hwif->pci_dev) - hwif->gendev.parent = &hwif->pci_dev->dev; + if (hwif->dev) + hwif->gendev.parent = hwif->dev; else /* Would like to do = &device_legacy */ hwif->gendev.parent = NULL; @@ -631,7 +634,33 @@ static void hwif_register (ide_hwif_t *hwif) __FUNCTION__, ret); } -static int wait_hwif_ready(ide_hwif_t *hwif) +/** + * ide_port_wait_ready - wait for port to become ready + * @hwif: IDE port + * + * This is needed on some PPCs and a bunch of BIOS-less embedded + * platforms. Typical cases are: + * + * - The firmware hard reset the disk before booting the kernel, + * the drive is still doing it's poweron-reset sequence, that + * can take up to 30 seconds. + * + * - The firmware does nothing (or no firmware), the device is + * still in POST state (same as above actually). + * + * - Some CD/DVD/Writer combo drives tend to drive the bus during + * their reset sequence even when they are non-selected slave + * devices, thus preventing discovery of the main HD. + * + * Doing this wait-for-non-busy should not harm any existing + * configuration and fix some issues like the above. + * + * BenH. + * + * Returns 0 on success, error code (< 0) otherwise. + */ + +static int ide_port_wait_ready(ide_hwif_t *hwif) { int unit, rc; @@ -709,36 +738,16 @@ void ide_undecoded_slave(ide_drive_t *drive1) EXPORT_SYMBOL_GPL(ide_undecoded_slave); -/* - * This routine only knows how to look for drive units 0 and 1 - * on an interface, so any setting of MAX_DRIVES > 2 won't work here. - */ -static void probe_hwif(ide_hwif_t *hwif) +static int ide_probe_port(ide_hwif_t *hwif) { unsigned long flags; unsigned int irqd; - int unit; + int unit, rc = -ENODEV; - if (hwif->noprobe) - return; + BUG_ON(hwif->present); - if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) && - (ide_hwif_request_regions(hwif))) { - u16 msgout = 0; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present) { - drive->present = 0; - printk(KERN_ERR "%s: ERROR, PORTS ALREADY IN USE\n", - drive->name); - msgout = 1; - } - } - if (!msgout) - printk(KERN_ERR "%s: ports already in use, skipping probe\n", - hwif->name); - return; - } + if (hwif->noprobe) + return -EACCES; /* * We must always disable IRQ, as probe_for_drive will assert IRQ, but @@ -750,26 +759,7 @@ static void probe_hwif(ide_hwif_t *hwif) local_irq_set(flags); - /* This is needed on some PPCs and a bunch of BIOS-less embedded - * platforms. Typical cases are: - * - * - The firmware hard reset the disk before booting the kernel, - * the drive is still doing it's poweron-reset sequence, that - * can take up to 30 seconds - * - The firmware does nothing (or no firmware), the device is - * still in POST state (same as above actually). - * - Some CD/DVD/Writer combo drives tend to drive the bus during - * their reset sequence even when they are non-selected slave - * devices, thus preventing discovery of the main HD - * - * Doing this wait-for-busy should not harm any existing configuration - * (at least things won't be worse than what current code does, that - * is blindly go & talk to the drive) and fix some issues like the - * above. - * - * BenH. - */ - if (wait_hwif_ready(hwif) == -EBUSY) + if (ide_port_wait_ready(hwif) == -EBUSY) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* @@ -779,14 +769,8 @@ static void probe_hwif(ide_hwif_t *hwif) ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); - if (drive->present && !hwif->present) { - hwif->present = 1; - if (hwif->chipset != ide_4drives || - !hwif->mate || - !hwif->mate->present) { - hwif_register(hwif); - } - } + if (drive->present) + rc = 0; } if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) { printk(KERN_WARNING "%s: reset\n", hwif->name); @@ -803,10 +787,12 @@ static void probe_hwif(ide_hwif_t *hwif) if (irqd) enable_irq(irqd); - if (!hwif->present) { - ide_hwif_release_regions(hwif); - return; - } + return rc; +} + +static void ide_port_tune_devices(ide_hwif_t *hwif) +{ + int unit; for (unit = 0; unit < MAX_DRIVES; unit++) { ide_drive_t *drive = &hwif->drives[unit]; @@ -997,21 +983,17 @@ static int init_irq (ide_hwif_t *hwif) spin_lock_irq(&ide_lock); hwif->next = hwgroup->hwif->next; hwgroup->hwif->next = hwif; + BUG_ON(hwif->next == hwif); spin_unlock_irq(&ide_lock); } else { - hwgroup = kmalloc_node(sizeof(ide_hwgroup_t), - GFP_KERNEL | __GFP_ZERO, - hwif_to_node(hwif->drives[0].hwif)); - if (!hwgroup) - goto out_up; + hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO, + hwif_to_node(hwif)); + if (hwgroup == NULL) + goto out_up; hwif->hwgroup = hwgroup; + hwgroup->hwif = hwif->next = hwif; - hwgroup->hwif = hwif->next = hwif; - hwgroup->rq = NULL; - hwgroup->handler = NULL; - hwgroup->drive = NULL; - hwgroup->busy = 0; init_timer(&hwgroup->timer); hwgroup->timer.function = &ide_timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; @@ -1079,25 +1061,7 @@ static int init_irq (ide_hwif_t *hwif) mutex_unlock(&ide_cfg_mtx); return 0; out_unlink: - spin_lock_irq(&ide_lock); - if (hwif->next == hwif) { - BUG_ON(match); - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - ide_hwif_t *g; - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Impossible. */ - printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n"); - hwgroup->hwif = g; - } - BUG_ON(hwgroup->hwif == hwif); - } - spin_unlock_irq(&ide_lock); + ide_remove_port_from_hwgroup(hwif); out_up: mutex_unlock(&ide_cfg_mtx); return 1; @@ -1246,28 +1210,21 @@ static int hwif_init(ide_hwif_t *hwif) { int old_irq; - /* Return success if no device is connected */ - if (!hwif->present) - return 1; - if (!hwif->irq) { if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: DISABLED, NO IRQ\n", hwif->name); - return (hwif->present = 0); + return 0; } } #ifdef CONFIG_BLK_DEV_HD if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) { printk("%s: CANNOT SHARE IRQ WITH OLD " "HARDDISK DRIVER (hd.c)\n", hwif->name); - return (hwif->present = 0); + return 0; } #endif /* CONFIG_BLK_DEV_HD */ - /* we set it back to 1 if all is ok below */ - hwif->present = 0; - if (register_blkdev(hwif->major, hwif->name)) return 0; @@ -1306,10 +1263,7 @@ static int hwif_init(ide_hwif_t *hwif) done: init_gendisk(hwif); - ide_acpi_init(hwif); - - hwif->present = 1; /* success */ return 1; out: @@ -1344,7 +1298,27 @@ int ide_device_add_all(u8 *idx) if (idx[i] == 0xff) continue; - probe_hwif(&ide_hwifs[idx[i]]); + hwif = &ide_hwifs[idx[i]]; + + if ((hwif->chipset != ide_4drives || !hwif->mate || + !hwif->mate->present) && ide_hwif_request_regions(hwif)) { + printk(KERN_ERR "%s: ports already in use, " + "skipping probe\n", hwif->name); + continue; + } + + if (ide_probe_port(hwif) < 0) { + ide_hwif_release_regions(hwif); + continue; + } + + hwif->present = 1; + + if (hwif->chipset != ide_4drives || !hwif->mate || + !hwif->mate->present) + ide_register_port(hwif); + + ide_port_tune_devices(hwif); } for (i = 0; i < MAX_HWIFS; i++) { @@ -1353,9 +1327,13 @@ int ide_device_add_all(u8 *idx) hwif = &ide_hwifs[idx[i]]; + if (!hwif->present) + continue; + if (hwif_init(hwif) == 0) { printk(KERN_INFO "%s: failed to initialize IDE " "interface\n", hwif->name); + hwif->present = 0; rc = -1; continue; } diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index aa663e7f46f2..00c249cba236 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide-proc.c Version 1.05 Mar 05, 2003 - * * Copyright (C) 1997-1998 Mark Lord * Copyright (C) 2003 Red Hat <alan@redhat.com> * diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c index 7ffa332d77ce..93d2e41be853 100644 --- a/drivers/ide/ide-scan-pci.c +++ b/drivers/ide/ide-scan-pci.c @@ -81,7 +81,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) * module ordering not traditionally ordered. */ -int __init ide_scan_pcibus(void) +static int __init ide_scan_pcibus(void) { struct pci_dev *dev = NULL; struct pci_driver *d; @@ -113,9 +113,4 @@ int __init ide_scan_pcibus(void) return 0; } -static int __init ide_scan_pci(void) -{ - return ide_scan_pcibus(); -} - -module_init(ide_scan_pci); +module_init(ide_scan_pcibus); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d71a584f0765..5aef63acf1e8 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ide-tape.c Version 1.19 Nov, 2003 - * - * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 1995-1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz * * $Header$ * @@ -4291,9 +4290,6 @@ static int idetape_identify_device (ide_drive_t *drive) { struct idetape_id_gcw gcw; struct hd_driveid *id = drive->id; -#if IDETAPE_DEBUG_INFO - unsigned short mask,i; -#endif /* IDETAPE_DEBUG_INFO */ if (drive->id_read == 0) return 1; @@ -4333,62 +4329,6 @@ static int idetape_identify_device (ide_drive_t *drive) case 1: printk("16 bytes\n");break; default: printk("Reserved\n");break; } - printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model); - printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev); - printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no); - printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512); - printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); - printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO); - printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA); - printk(KERN_INFO "ide-tape: Single Word DMA supported modes: "); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_1word & mask) - printk("%d ",i); - if (id->dma_1word & (mask << 8)) - printk("(active) "); - } - printk("\n"); - printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: "); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_mword & mask) - printk("%d ",i); - if (id->dma_mword & (mask << 8)) - printk("(active) "); - } - printk("\n"); - if (id->field_valid & 0x0002) { - printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n", - id->eide_pio_modes & 1 ? "Mode 3":"None"); - printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: "); - if (id->eide_dma_min == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_dma_min); - - printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: "); - if (id->eide_dma_time == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_dma_time); - - printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: "); - if (id->eide_pio == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_pio); - - printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: "); - if (id->eide_pio_iordy == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_pio_iordy); - - } else - printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); #endif /* IDETAPE_DEBUG_INFO */ /* Check that we can support this device */ @@ -4591,19 +4531,11 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) spin_lock_init(&tape->spinlock); drive->dsc_overlap = 1; -#ifdef CONFIG_BLK_DEV_IDEPCI - if (HWIF(drive)->pci_dev != NULL) { - /* - * These two ide-pci host adapters appear to need DSC overlap disabled. - * This probably needs further analysis. - */ - if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || - (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { - printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name); - drive->dsc_overlap = 0; - } + if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) { + printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", + tape->name); + drive->dsc_overlap = 0; } -#endif /* CONFIG_BLK_DEV_IDEPCI */ /* Seagate Travan drives do not support DSC overlap. */ if (strstr(drive->id->model, "Seagate STT3401")) drive->dsc_overlap = 0; diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 5eb6fa15dc4d..16a9a581d089 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -1,11 +1,9 @@ /* - * linux/drivers/ide/ide-taskfile.c Version 0.38 March 05, 2003 - * - * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org> - * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2001-2002 Klaus Smolin + * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org> + * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2001-2002 Klaus Smolin * IBM Storage Technology Division - * Copyright (C) 2003-2004 Bartlomiej Zolnierkiewicz + * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz * * The big the bad and the ugly. */ @@ -260,7 +258,7 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) return ide_stopped; } -u8 wait_drive_not_busy(ide_drive_t *drive) +static u8 wait_drive_not_busy(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); int retries; diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h index daffbb9797e1..adeda7626529 100644 --- a/drivers/ide/ide-timing.h +++ b/drivers/ide/ide-timing.h @@ -2,8 +2,6 @@ #define _IDE_TIMING_H /* - * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 97894abd9ebc..ab9ca2b5b66c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ide.c Version 7.00beta2 Mar 05 2003 - * - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyrifht (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz */ /* @@ -46,7 +45,6 @@ */ #define REVISION "Revision: 7.00alpha2" -#define VERSION "Id: ide.c 7.00a2 20020906" #define _IDE_C /* Tell ide.h it's really us */ @@ -242,22 +240,12 @@ static int ide_system_bus_speed(void) #define pci_default 0 #endif /* CONFIG_PCI */ - if (!system_bus_speed) { - if (idebus_parameter) { - /* user supplied value */ - system_bus_speed = idebus_parameter; - } else if (pci_dev_present(pci_default)) { - /* safe default value for PCI */ - system_bus_speed = 33; - } else { - /* safe default value for VESA and PCI */ - system_bus_speed = 50; - } - printk(KERN_INFO "ide: Assuming %dMHz system bus speed " - "for PIO modes%s\n", system_bus_speed, - idebus_parameter ? "" : "; override with idebus=xx"); - } - return system_bus_speed; + /* user supplied value */ + if (idebus_parameter) + return idebus_parameter; + + /* safe default value for PCI or VESA and PCI*/ + return pci_dev_present(pci_default) ? 33 : 50; } ide_hwif_t * ide_find_port(unsigned long base) @@ -405,8 +393,9 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->chipset = tmp_hwif->chipset; hwif->hold = tmp_hwif->hold; + hwif->dev = tmp_hwif->dev; + #ifdef CONFIG_BLK_DEV_IDEPCI - hwif->pci_dev = tmp_hwif->pci_dev; hwif->cds = tmp_hwif->cds; #endif @@ -472,6 +461,41 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->hwif_data = tmp_hwif->hwif_data; } +void ide_remove_port_from_hwgroup(ide_hwif_t *hwif) +{ + ide_hwgroup_t *hwgroup = hwif->hwgroup; + + spin_lock_irq(&ide_lock); + /* + * Remove us from the hwgroup, and free + * the hwgroup if we were the only member + */ + if (hwif->next == hwif) { + BUG_ON(hwgroup->hwif != hwif); + kfree(hwgroup); + } else { + /* There is another interface in hwgroup. + * Unlink us, and set hwgroup->drive and ->hwif to + * something sane. + */ + ide_hwif_t *g = hwgroup->hwif; + + while (g->next != hwif) + g = g->next; + g->next = hwif->next; + if (hwgroup->hwif == hwif) { + /* Chose a random hwif for hwgroup->hwif. + * It's guaranteed that there are no drives + * left in the hwgroup. + */ + BUG_ON(hwgroup->drive != NULL); + hwgroup->hwif = g; + } + BUG_ON(hwgroup->hwif == hwif); + } + spin_unlock_irq(&ide_lock); +} + /** * ide_unregister - free an IDE interface * @index: index of interface (will change soon to a pointer) @@ -539,43 +563,8 @@ void ide_unregister(unsigned int index) if (irq_count == 1) free_irq(hwif->irq, hwgroup); - spin_lock_irq(&ide_lock); - /* - * Note that we only release the standard ports, - * and do not even try to handle any extra ports - * allocated for weird IDE interface chipsets. - */ - ide_hwif_release_regions(hwif); - - /* - * Remove us from the hwgroup, and free - * the hwgroup if we were the only member - */ - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. - */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; - } - BUG_ON(hwgroup->hwif == hwif); - } + ide_remove_port_from_hwgroup(hwif); - /* More messed up locking ... */ - spin_unlock_irq(&ide_lock); device_unregister(&hwif->gendev); wait_for_completion(&hwif->gendev_rel_comp); @@ -601,6 +590,13 @@ void ide_unregister(unsigned int index) hwif->extra_ports = 0; } + /* + * Note that we only release the standard ports, + * and do not even try to handle any extra ports + * allocated for weird IDE interface chipsets. + */ + ide_hwif_release_regions(hwif); + /* copy original settings */ tmp_hwif = *hwif; @@ -913,7 +909,7 @@ static int set_unmaskirq(ide_drive_t *drive, int arg) int system_bus_clock (void) { - return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); + return system_bus_speed; } EXPORT_SYMBOL(system_bus_clock); @@ -1668,6 +1664,10 @@ static int __init ide_init(void) printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); system_bus_speed = ide_system_bus_speed(); + printk(KERN_INFO "ide: Assuming %dMHz system bus speed " + "for PIO modes%s\n", system_bus_speed, + idebus_parameter ? "" : "; override with idebus=xx"); + ret = bus_register(&ide_bus_type); if (ret < 0) { printk(KERN_WARNING "IDE: bus_register error: %d\n", ret); diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c index 5ec0be4cbad7..e3ea2096804a 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/legacy/ali14xx.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/ali14xx.c Version 0.03 Feb 09, 1996 - * * Copyright (C) 1996 Linus Torvalds & author (see below) */ diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 74d28e058f55..dd3d198ade47 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver + * Amiga Buddha, Catweasel and X-Surf IDE Driver * * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others * diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c index 13eee6da2806..611c9705a3ae 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/legacy/dtc2278.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/dtc2278.c Version 0.02 Feb 10, 1996 - * * Copyright (C) 1996 Linus Torvalds & author (see below) */ diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 2860956bdcb0..c9bd6bfb1f3b 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver + * Atari Falcon IDE Driver * * Created 12 Jul 1997 by Geert Uytterhoeven * @@ -66,6 +66,7 @@ static int __init falconide_init(void) { if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; + ide_hwif_t *hwif; printk(KERN_INFO "ide: Falcon IDE controller\n"); diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index 492fa047efc0..f67c51a2c84a 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver + * Amiga Gayle IDE Driver * * Created 9 Jul 1997 by Geert Uytterhoeven * diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index 8da5031a6d05..57bc15cddca0 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/ht6560b.c Version 0.07 Feb 1, 2000 - * * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index f4ea15b32969..3bd29676ef6a 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -2,8 +2,6 @@ A driver for PCMCIA IDE/ATA disk cards - ide-cs.c 1.3 2002/10/26 05:45:31 - The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 69a0fb0e564f..7c3231a21d17 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -21,13 +21,6 @@ #include <linux/platform_device.h> #include <linux/io.h> -static struct { - void __iomem *plat_ide_mapbase; - void __iomem *plat_ide_alt_mapbase; - ide_hwif_t *hwif; - int index; -} hwif_prop; - static void __devinit plat_ide_setup_ports(hw_regs_t *hw, void __iomem *base, void __iomem *ctrl, @@ -54,6 +47,7 @@ static void __devinit plat_ide_setup_ports(hw_regs_t *hw, static int __devinit plat_ide_probe(struct platform_device *pdev) { struct resource *res_base, *res_alt, *res_irq; + void __iomem *base, *alt_base; ide_hwif_t *hwif; struct pata_platform_info *pdata; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; @@ -84,27 +78,25 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) } if (mmio) { - hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev, + base = devm_ioremap(&pdev->dev, res_base->start, res_base->end - res_base->start + 1); - hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev, + alt_base = devm_ioremap(&pdev->dev, res_alt->start, res_alt->end - res_alt->start + 1); } else { - hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev, + base = devm_ioport_map(&pdev->dev, res_base->start, res_base->end - res_base->start + 1); - hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev, + alt_base = devm_ioport_map(&pdev->dev, res_alt->start, res_alt->end - res_alt->start + 1); } - hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase); + hwif = ide_find_port((unsigned long)base); if (!hwif) { ret = -ENODEV; goto out; } memset(&hw, 0, sizeof(hw)); - plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase, - hwif_prop.plat_ide_alt_mapbase, - pdata, res_irq->start); + plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start); hw.dev = &pdev->dev; ide_init_port_hw(hwif, &hw); @@ -114,9 +106,6 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) default_hwif_mmiops(hwif); } - hwif_prop.hwif = hwif; - hwif_prop.index = hwif->index; - idx[0] = hwif->index; ide_device_add(idx); @@ -133,14 +122,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev) { ide_hwif_t *hwif = pdev->dev.driver_data; - if (hwif != hwif_prop.hwif) { - dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error", - pdev->name); - } else { - ide_unregister(hwif_prop.index); - hwif_prop.index = 0; - hwif_prop.hwif = NULL; - } + ide_unregister(hwif->index); return 0; } diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index 782d4c76c0e5..c54d07ff64fe 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver + * Macintosh IDE Driver * * Copyright (C) 1998 by Michael Schmitz * diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index f5329730df99..a9c6b0609c54 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver + * Q40 I/O port IDE Driver * * (c) Richard Zidlicky * diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index 2bac4c1a6532..37534bb483a7 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/qd65xx.c Version 0.07 Sep 30, 2001 - * * Copyright (C) 1996-2001 Linus Torvalds & author (see below) */ diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h index 633a42456ef6..28dd50a15d55 100644 --- a/drivers/ide/legacy/qd65xx.h +++ b/drivers/ide/legacy/qd65xx.h @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/qd65xx.h - * * Copyright (c) 2000 Linus Torvalds & authors */ diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c index a1ae1ae6699d..26f38ce58776 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/legacy/umc8672.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/umc8672.c Version 0.05 Jul 31, 1996 - * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 2d3e5115b834..cd42b30a7a3b 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/mips/au1xxx-ide.c version 01.30.00 Aug. 02 2005 - * * BRIEF MODULE DESCRIPTION * AMD Alchemy Au1xxx IDE interface routines over the Static Bus * @@ -50,7 +48,6 @@ #include <asm/mach-au1x00/au1xxx_ide.h> #define DRV_NAME "au1200-ide" -#define DRV_VERSION "1.0" #define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>" /* enable the burstmode in the dbdma */ @@ -209,24 +206,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed) */ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - -static int auide_build_sglist(ide_drive_t *drive, struct request *rq) -{ - ide_hwif_t *hwif = drive->hwif; - _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; - struct scatterlist *sg = hwif->sg_table; - - ide_map_sg(drive, rq); - - if (rq_data_dir(rq) == READ) - hwif->sg_dma_direction = DMA_FROM_DEVICE; - else - hwif->sg_dma_direction = DMA_TO_DEVICE; - - return dma_map_sg(ahwif->dev, sg, hwif->sg_nents, - hwif->sg_dma_direction); -} - static int auide_build_dmatable(ide_drive_t *drive) { int i, iswrite, count = 0; @@ -241,8 +220,7 @@ static int auide_build_dmatable(ide_drive_t *drive) /* Save for interrupt context */ ahwif->drive = drive; - /* Build sglist */ - hwif->sg_nents = i = auide_build_sglist(drive, rq); + hwif->sg_nents = i = ide_build_sglist(drive, rq); if (!i) return 0; @@ -300,10 +278,7 @@ static int auide_build_dmatable(ide_drive_t *drive) return 1; use_pio_instead: - dma_unmap_sg(ahwif->dev, - hwif->sg_table, - hwif->sg_nents, - hwif->sg_dma_direction); + ide_destroy_dmatable(drive); return 0; /* revert to PIO for this request */ } @@ -311,11 +286,9 @@ static int auide_build_dmatable(ide_drive_t *drive) static int auide_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; if (hwif->sg_nents) { - dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); + ide_destroy_dmatable(drive); hwif->sg_nents = 0; } @@ -504,7 +477,7 @@ static int auide_ddma_init(_auide_hwif *auide) { auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, NUM_DESCRIPTORS); - hwif->dmatable_cpu = dma_alloc_coherent(auide->dev, + hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, PRD_ENTRIES * PRD_BYTES, /* 1 Page */ &hwif->dmatable_dma, GFP_KERNEL); @@ -592,9 +565,6 @@ static int au_ide_probe(struct device *dev) #endif memset(&auide_hwif, 0, sizeof(_auide_hwif)); - auide_hwif.dev = 0; - - ahwif->dev = dev; ahwif->irq = platform_get_irq(pdev, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -629,10 +599,13 @@ static int au_ide_probe(struct device *dev) memset(&hw, 0, sizeof(hw)); auide_setup_ports(&hw, ahwif); hw.irq = ahwif->irq; + hw.dev = dev; hw.chipset = ide_au1xxx; ide_init_port_hw(hwif, &hw); + hwif->dev = dev; + hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA hwif->mwdma_mask = 0x07; /* Multimode-2 DMA */ @@ -715,7 +688,7 @@ static int au_ide_remove(struct device *dev) ide_hwif_t *hwif = dev_get_drvdata(dev); _auide_hwif *ahwif = &auide_hwif; - ide_unregister(hwif - ide_hwifs); + ide_unregister(hwif->index); iounmap((void *)ahwif->regbase); diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index 7f4d1857d555..824df78c7012 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/aec62xx.c Version 0.27 Sep 16, 2007 - * * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> * @@ -90,7 +88,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr static void aec6210_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 d_conf = 0; u8 ultra = 0, ultra_conf = 0; u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; @@ -116,7 +114,7 @@ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed) static void aec6260_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = (drive->select.b.unit & 0x01); u8 tmp1 = 0, tmp2 = 0; u8 ultra = 0, drive_conf = 0, ultra_conf = 0; @@ -170,7 +168,7 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); hwif->set_pio_mode = &aec_set_pio_mode; @@ -188,7 +186,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) if (hwif->cbl != ATA_CBL_PATA40_SHORT) { u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01; - pci_read_config_byte(hwif->pci_dev, 0x49, &ata66); + pci_read_config_byte(dev, 0x49, &ata66); hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; } @@ -202,6 +200,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_NO_DSC | IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 49aa82e412b6..130cc6e784e5 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/alim15x3.c Version 0.29 Sep 16 2007 - * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer @@ -293,7 +291,7 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count) static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int s_time, a_time, c_time; u8 s_clc, a_clc, r_clc; unsigned long flags; @@ -396,7 +394,7 @@ static u8 ali_udma_filter(ide_drive_t *drive) static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 speed1 = speed; u8 unit = (drive->select.b.unit & 0x01); u8 tmpbyte = 0x00; @@ -625,7 +623,7 @@ static int ali_cable_override(struct pci_dev *pdev) static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long flags; u8 cbl = ATA_CBL_PATA40, tmpbyte; @@ -688,12 +686,13 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 ideic, inmir; s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; int irq = -1; - if (hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229) + if (dev->device == PCI_DEVICE_ID_AL_M5229) hwif->irq = hwif->channel ? 15 : 14; if (isa_dev) { @@ -745,7 +744,7 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) return; if (!hwif->channel) outb(inb(dmabase + 2) & 0x60, dmabase + 2); - ide_setup_dma(hwif, dmabase, 8); + ide_setup_dma(hwif, dmabase); } static const struct ide_port_info ali15x3_chipset __devinitdata = { @@ -775,7 +774,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev }; struct ide_port_info d = ali15x3_chipset; - u8 rev = dev->revision; + u8 rev = dev->revision, idx = id->driver_data; if (pci_dev_present(ati_rs100)) printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n"); @@ -798,6 +797,9 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev d.udma_mask = ATA_UDMA6; } + if (idx == 0) + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + #if defined(CONFIG_SPARC64) d.init_hwif = init_hwif_common_ali15x3; #endif /* CONFIG_SPARC64 */ @@ -807,7 +809,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev static const struct pci_device_id alim15x3_pci_tbl[] = { { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 }, - { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 0 }, + { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index cee51fdafcf6..8c52bc9eaa59 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -1,6 +1,4 @@ /* - * Version 2.24 - * * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 * IDE driver for Linux. * @@ -28,81 +26,46 @@ #include "ide-timing.h" -#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_CHECK_SWDMA 0x08 -#define AMD_BAD_SWDMA 0x10 -#define AMD_BAD_FIFO 0x20 -#define AMD_CHECK_SERENADE 0x40 - -/* - * AMD SouthBridge chips. - */ - -static struct amd_ide_chip { - unsigned short id; - u8 base; - u8 udma_mask; - u8 flags; -} amd_ide_chips[] = { - { PCI_DEVICE_ID_AMD_COBRA_7401, 0x40, ATA_UDMA2, AMD_BAD_SWDMA }, - { PCI_DEVICE_ID_AMD_VIPER_7409, 0x40, ATA_UDMA4, AMD_CHECK_SWDMA }, - { PCI_DEVICE_ID_AMD_VIPER_7411, 0x40, ATA_UDMA5, AMD_BAD_FIFO }, - { PCI_DEVICE_ID_AMD_OPUS_7441, 0x40, ATA_UDMA5, }, - { PCI_DEVICE_ID_AMD_8111_IDE, 0x40, ATA_UDMA6, AMD_CHECK_SERENADE }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x50, ATA_UDMA5, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE, 0x50, ATA_UDMA6, }, - { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, ATA_UDMA5, }, - { 0 } +enum { + AMD_IDE_CONFIG = 0x41, + AMD_CABLE_DETECT = 0x42, + AMD_DRIVE_TIMING = 0x48, + AMD_8BIT_TIMING = 0x4e, + AMD_ADDRESS_SETUP = 0x4c, + AMD_UDMA_TIMING = 0x50, }; -static struct amd_ide_chip *amd_config; -static const struct ide_port_info *amd_chipset; static unsigned int amd_80w; static unsigned int amd_clock; static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" }; static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 }; +static inline u8 amd_offset(struct pci_dev *dev) +{ + return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0; +} + /* * amd_set_speed() writes timing values to the chipset registers */ -static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing) +static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask, + struct ide_timing *timing) { - unsigned char t; + u8 t = 0, offset = amd_offset(dev); - pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t); + pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t); t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); - pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t); + pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t); - pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)), + pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)), ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1)); - pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn), + pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn), ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1)); - switch (amd_config->udma_mask) { + switch (udma_mask) { case ATA_UDMA2: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break; case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break; @@ -110,7 +73,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi default: return; } - pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t); + pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + (3 - dn), t); } /* @@ -120,12 +83,15 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi static void amd_set_drive(ide_drive_t *drive, const u8 speed) { - ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + ide_drive_t *peer = hwif->drives + (~drive->dn & 1); struct ide_timing t, p; int T, UT; + u8 udma_mask = hwif->ultra_mask; T = 1000000000 / amd_clock; - UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2); + UT = (udma_mask == ATA_UDMA2) ? T : (T / 2); ide_timing_compute(drive, speed, &t, T, UT); @@ -137,7 +103,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed) if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1; if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; - amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t); + amd_set_speed(dev, drive->dn, udma_mask, &t); } /* @@ -149,67 +115,68 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio) amd_set_drive(drive, XFER_PIO_0 + pio); } -/* - * The initialization callback. Here we determine the IDE chip type - * and initialize its drive independent registers. - */ +static void __devinit amd7409_cable_detect(struct pci_dev *dev, + const char *name) +{ + /* no host side cable detection */ + amd_80w = 0x03; +} -static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name) +static void __devinit amd7411_cable_detect(struct pci_dev *dev, + const char *name) { - unsigned char t; - unsigned int u; int i; + u32 u = 0; + u8 t = 0, offset = amd_offset(dev); + + pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t); + pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u); + amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { + printk(KERN_WARNING "%s: BIOS didn't set cable bits " + "correctly. Enabling workaround.\n", + name); + amd_80w |= (1 << (1 - (i >> 4))); + } +} /* - * Check for bad SWDMA. + * The initialization callback. Initialize drive independent registers. */ - if (amd_config->flags & AMD_CHECK_SWDMA) { - if (dev->revision <= 7) - amd_config->flags |= AMD_BAD_SWDMA; - } +static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, + const char *name) +{ + u8 t = 0, offset = amd_offset(dev); /* * Check 80-wire cable presence. */ - switch (amd_config->udma_mask) { - - case ATA_UDMA6: - case ATA_UDMA5: - pci_read_config_byte(dev, AMD_CABLE_DETECT, &t); - pci_read_config_dword(dev, AMD_UDMA_TIMING, &u); - amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n", - amd_chipset->name); - amd_80w |= (1 << (1 - (i >> 4))); - } - break; - - case ATA_UDMA4: - /* no host side cable detection */ - amd_80w = 0x03; - break; - } + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_COBRA_7401) + ; /* no UDMA > 2 */ + else if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) + amd7409_cable_detect(dev, name); + else + amd7411_cable_detect(dev, name); /* * Take care of prefetch & postwrite. */ - pci_read_config_byte(dev, AMD_IDE_CONFIG, &t); - pci_write_config_byte(dev, AMD_IDE_CONFIG, - (amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0)); - -/* - * Take care of incorrectly wired Serenade mainboards. - */ - - if ((amd_config->flags & AMD_CHECK_SERENADE) && - dev->subsystem_vendor == PCI_VENDOR_ID_AMD && - dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) - amd_config->udma_mask = ATA_UDMA5; + pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t); + /* + * Check for broken FIFO support. + */ + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411) + t &= 0x0f; + else + t |= 0xf0; + pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t); /* * Determine the system bus clock. @@ -225,25 +192,19 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch if (amd_clock < 20000 || amd_clock > 50000) { printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", - amd_chipset->name, amd_clock); + name, amd_clock); amd_clock = 33333; } -/* - * Print the boot message. - */ - - printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n", - amd_chipset->name, pci_name(dev), dev->revision, - amd_dma[fls(amd_config->udma_mask) - 1]); - return dev->irq; } static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + if (hwif->irq == 0) /* 0 is bogus but will do for now */ - hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel); + hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel); hwif->set_pio_mode = &amd_set_pio_mode; hwif->set_dma_mode = &amd_set_drive; @@ -251,10 +212,6 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) if (!hwif->dma_base) return; - hwif->ultra_mask = amd_config->udma_mask; - if (amd_config->flags & AMD_BAD_SWDMA) - hwif->swdma_mask = 0x00; - if (hwif->cbl != ATA_CBL_PATA40_SHORT) { if ((amd_80w >> hwif->channel) & 1) hwif->cbl = ATA_CBL_PATA80; @@ -272,7 +229,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) IDE_HFLAG_UNMASK_IRQS | \ IDE_HFLAG_BOOTABLE) -#define DECLARE_AMD_DEV(name_str) \ +#define DECLARE_AMD_DEV(name_str, swdma, udma) \ { \ .name = name_str, \ .init_chipset = init_chipset_amd74xx, \ @@ -280,11 +237,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \ .host_flags = IDE_HFLAGS_AMD, \ .pio_mask = ATA_PIO5, \ - .swdma_mask = ATA_SWDMA2, \ + .swdma_mask = swdma, \ .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ } -#define DECLARE_NV_DEV(name_str) \ +#define DECLARE_NV_DEV(name_str, udma) \ { \ .name = name_str, \ .init_chipset = init_chipset_amd74xx, \ @@ -294,45 +252,62 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) .pio_mask = ATA_PIO5, \ .swdma_mask = ATA_SWDMA2, \ .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ } static const struct ide_port_info amd74xx_chipsets[] __devinitdata = { - /* 0 */ DECLARE_AMD_DEV("AMD7401"), - /* 1 */ DECLARE_AMD_DEV("AMD7409"), - /* 2 */ DECLARE_AMD_DEV("AMD7411"), - /* 3 */ DECLARE_AMD_DEV("AMD7441"), - /* 4 */ DECLARE_AMD_DEV("AMD8111"), - - /* 5 */ DECLARE_NV_DEV("NFORCE"), - /* 6 */ DECLARE_NV_DEV("NFORCE2"), - /* 7 */ DECLARE_NV_DEV("NFORCE2-U400R"), - /* 8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"), - /* 9 */ DECLARE_NV_DEV("NFORCE3-150"), - /* 10 */ DECLARE_NV_DEV("NFORCE3-250"), - /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"), - /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), - /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), - /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), - /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), - /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), - /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), - /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"), - /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67"), - /* 20 */ DECLARE_NV_DEV("NFORCE-MCP73"), - /* 21 */ DECLARE_NV_DEV("NFORCE-MCP77"), - /* 22 */ DECLARE_AMD_DEV("AMD5536"), + /* 0 */ DECLARE_AMD_DEV("AMD7401", 0x00, ATA_UDMA2), + /* 1 */ DECLARE_AMD_DEV("AMD7409", ATA_SWDMA2, ATA_UDMA4), + /* 2 */ DECLARE_AMD_DEV("AMD7411", ATA_SWDMA2, ATA_UDMA5), + /* 3 */ DECLARE_AMD_DEV("AMD7441", ATA_SWDMA2, ATA_UDMA5), + /* 4 */ DECLARE_AMD_DEV("AMD8111", ATA_SWDMA2, ATA_UDMA6), + + /* 5 */ DECLARE_NV_DEV("NFORCE", ATA_UDMA5), + /* 6 */ DECLARE_NV_DEV("NFORCE2", ATA_UDMA6), + /* 7 */ DECLARE_NV_DEV("NFORCE2-U400R", ATA_UDMA6), + /* 8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA", ATA_UDMA6), + /* 9 */ DECLARE_NV_DEV("NFORCE3-150", ATA_UDMA6), + /* 10 */ DECLARE_NV_DEV("NFORCE3-250", ATA_UDMA6), + /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA", ATA_UDMA6), + /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2", ATA_UDMA6), + /* 13 */ DECLARE_NV_DEV("NFORCE-CK804", ATA_UDMA6), + /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04", ATA_UDMA6), + /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51", ATA_UDMA6), + /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55", ATA_UDMA6), + /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61", ATA_UDMA6), + /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65", ATA_UDMA6), + /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67", ATA_UDMA6), + /* 20 */ DECLARE_NV_DEV("NFORCE-MCP73", ATA_UDMA6), + /* 21 */ DECLARE_NV_DEV("NFORCE-MCP77", ATA_UDMA6), + + /* 22 */ DECLARE_AMD_DEV("AMD5536", ATA_SWDMA2, ATA_UDMA5), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) { - amd_chipset = amd74xx_chipsets + id->driver_data; - amd_config = amd_ide_chips + id->driver_data; - if (dev->device != amd_config->id) { - printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n", - pci_name(dev), dev->device, amd_config->id); - return -ENODEV; + struct ide_port_info d; + u8 idx = id->driver_data; + + d = amd74xx_chipsets[idx]; + + /* + * Check for bad SWDMA and incorrectly wired Serenade mainboards. + */ + if (idx == 1) { + if (dev->revision <= 7) + d.swdma_mask = 0; + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + } else if (idx == 4) { + if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD && + dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) + d.udma_mask = ATA_UDMA5; } - return ide_setup_pci_device(dev, amd_chipset); + + printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n", + d.name, pci_name(dev), dev->revision, + amd_dma[fls(d.udma_mask) - 1]); + + return ide_setup_pci_device(dev, &d); } static const struct pci_device_id amd74xx_pci_tbl[] = { diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 491871984aaa..b56274af1782 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/atiixp.c Version 0.05 Nov 9 2007 - * * Copyright (C) 2003 ATI Inc. <hyu@ati.com> * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz */ @@ -55,7 +53,7 @@ static DEFINE_SPINLOCK(atiixp_lock); static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); unsigned long flags; int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; u32 pio_timing_data; @@ -88,7 +86,7 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); unsigned long flags; int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; u32 tmp32; @@ -133,9 +131,8 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) { - u8 udma_mode = 0; - u8 ch = hwif->channel; - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); + u8 udma_mode = 0, ch = hwif->channel; hwif->set_pio_mode = &atiixp_set_pio_mode; hwif->set_dma_mode = &atiixp_set_dma_mode; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index da3565e0071f..7240c20b9593 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996 - * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index cd4eb9def151..04aa9e59670e 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/cmd64x.c Version 1.53 Dec 24, 2007 - * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Due to massive hardware bugs, UltraDMA is only supported * on the 646U2 and not on the 646U. @@ -71,7 +69,7 @@ static u8 quantize_timing(int timing, int quant) */ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); int clock_time = 1000 / system_bus_clock(); u8 cycle_count, active_count, recovery_count, drwtim; static const u8 recovery_values[] = @@ -118,7 +116,7 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int cycle_time; u8 setup_count, arttim = 0; @@ -183,7 +181,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; @@ -245,7 +243,7 @@ static int cmd648_ide_dma_end (ide_drive_t *drive) static int cmd64x_ide_dma_end (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; @@ -285,7 +283,7 @@ static int cmd648_ide_dma_test_irq (ide_drive_t *drive) static int cmd64x_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; @@ -375,7 +373,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01; switch (dev->device) { @@ -390,7 +388,7 @@ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif) static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); hwif->set_pio_mode = &cmd64x_set_pio_mode; hwif->set_dma_mode = &cmd64x_set_dma_mode; @@ -443,7 +441,9 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .init_chipset = init_chipset_cmd64x, .init_hwif = init_hwif_cmd64x, .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, - .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | + IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, .udma_mask = 0x00, /* no udma */ diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 6ec00b8d7ec1..eb68a9ad0c98 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -69,7 +69,7 @@ static struct pio_clocks cs5520_pio_clocks[]={ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); int controller = drive->dn > 1 ? 1 : 0; /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ @@ -156,8 +156,14 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic ide_setup_pci_noise(dev, d); /* We must not grab the entire device, it has 'ISA' space in its - BARS too and we will freak out other bits of the kernel */ - if (pci_enable_device_bars(dev, 1<<2)) { + * BARS too and we will freak out other bits of the kernel + * + * pci_enable_device_bars() is going away. I replaced it with + * IO only enable for now but I'll need confirmation this is + * allright for that device. If not, it will need some kind of + * quirk. --BenH. + */ + if (pci_enable_device_io(dev)) { printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); return -ENODEV; } diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index df5966b33460..765aac397ced 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/cs5530.c Version 0.77 Sep 24 2007 - * * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2000 Mark Lord <mlord@pobox.com> * Copyright (C) 2007 Bartlomiej Zolnierkiewicz diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 50b3d7791f55..66433aa53f59 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/cs5535.c - * * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * @@ -177,13 +175,15 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) */ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + hwif->set_pio_mode = &cs5535_set_pio_mode; hwif->set_dma_mode = &cs5535_set_dma_mode; if (hwif->dma_base == 0) return; - hwif->cbl = cs5535_cable_detect(hwif->pci_dev); + hwif->cbl = cs5535_cable_detect(dev); } static const struct ide_port_info cs5535_chipset __devinitdata = { diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 3ec4c659a37d..50100ac8770f 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/cy82c693.c Version 0.44 Nov 8, 2007 - * * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator * @@ -228,7 +226,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode) static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); pio_clocks_t pclk; unsigned int addrCtrl; @@ -397,8 +395,9 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) { static ide_hwif_t *primary; + struct pci_dev *dev = to_pci_dev(hwif->dev); - if (PCI_FUNC(hwif->pci_dev->devfn) == 1) + if (PCI_FUNC(dev->devfn) == 1) primary = hwif; else { hwif->mate = primary; diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 26aa492071bb..27e47fc97100 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/delkin_cb.c - * * Created 20 Oct 2004 by Mark Lord * * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter @@ -87,7 +85,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } pci_set_drvdata(dev, hwif); - hwif->pci_dev = dev; + hwif->dev = &dev->dev; drive = &hwif->drives[0]; if (drive->present) { drive->io_32bit = 1; diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 06885697ed7b..59ebe84f1053 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/generic.c Version 0.11 December 30, 2002 - * * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com> * @@ -104,7 +102,8 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = { { /* 14 */ .name = "Revolution", - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | + .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | + IDE_HFLAG_TRUST_BIOS_FOR_DMA | IDE_HFLAG_OFF_BOARD, .swdma_mask = ATA_SWDMA2, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index dfba0d13fcd3..25dbb814822d 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002 - * * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * * May be copied or modified under the terms of the GNU General Public License * * @@ -45,7 +44,7 @@ static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; u8 hi_speed, lo_speed; @@ -131,6 +130,7 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) #define IDE_HFLAGS_HPT34X \ (IDE_HFLAG_NO_ATAPI_DMA | \ + IDE_HFLAG_NO_DSC | \ IDE_HFLAG_ABUSE_SET_DMA_MODE | \ IDE_HFLAG_NO_AUTODMA) diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 12685939a813..5623cad569da 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.30 Dec 12, 2007 - * * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc @@ -626,7 +624,8 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list) static u8 hpt3xx_udma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct hpt_info *info = pci_get_drvdata(dev); u8 mask = hwif->ultra_mask; switch (info->chip_type) { @@ -665,7 +664,8 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive) static u8 hpt3xx_mdma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct hpt_info *info = pci_get_drvdata(dev); switch (info->chip_type) { case HPT372 : @@ -699,7 +699,7 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); struct hpt_info *info = pci_get_drvdata(dev); struct hpt_timings *t = info->timings; u8 itr_addr = 0x40 + (drive->dn * 4); @@ -742,7 +742,7 @@ static void hpt3xx_quirkproc(ide_drive_t *drive) static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct hpt_info *info = pci_get_drvdata(dev); if (drive->quirk_list) { @@ -774,7 +774,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask) */ static void hpt366_dma_lost_irq(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u8 mcr1 = 0, mcr3 = 0, scr1 = 0; pci_read_config_byte(dev, 0x50, &mcr1); @@ -790,18 +790,20 @@ static void hpt366_dma_lost_irq(ide_drive_t *drive) static void hpt370_clear_engine(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); - pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37); + pci_write_config_byte(dev, hwif->select_data, 0x37); udelay(10); } static void hpt370_irq_timeout(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 bfifo = 0; u8 dma_cmd; - pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); + pci_read_config_word(dev, hwif->select_data + 2, &bfifo); printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); /* get DMA command mode */ @@ -844,10 +846,11 @@ static void hpt370_dma_timeout(ide_drive_t *drive) static int hpt374_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 bfifo = 0; u8 dma_stat; - pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); + pci_read_config_word(dev, hwif->select_data + 2, &bfifo); if (bfifo & 0x1FF) { // printk("%s: %d bytes in FIFO\n", drive->name, bfifo); return 0; @@ -867,7 +870,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) static int hpt374_ide_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 mcr = 0, mcr_addr = hwif->select_data; u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; @@ -942,7 +945,7 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) static int hpt3xx_busproc(ide_drive_t *drive, int state) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 mcr_addr = hwif->select_data + 2; u8 resetmask = hwif->channel ? 0x80 : 0x40; u8 bsr2 = 0; @@ -1278,7 +1281,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct hpt_info *info = pci_get_drvdata(dev); int serialize = HPT_SERIALIZE_IO; u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; @@ -1393,7 +1396,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 masterdma = 0, slavedma = 0; u8 dma_new = 0, dma_old = 0; unsigned long flags; @@ -1413,7 +1416,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) local_irq_restore(flags); - ide_setup_dma(hwif, dmabase, 8); + ide_setup_dma(hwif, dmabase); } static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2) diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 2a0f45c4f4c4..df74e588a530 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -28,7 +28,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = 0x40; int slave_port = 0x44; @@ -85,7 +85,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = 0x40; int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; @@ -152,6 +152,7 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) static void __devinit init_hwif_it8213(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg42h = 0; hwif->set_dma_mode = &it8213_set_dma_mode; @@ -160,7 +161,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif) if (!hwif->dma_base) return; - pci_read_config_byte(hwif->pci_dev, 0x42, ®42h); + pci_read_config_byte(dev, 0x42, ®42h); if (hwif->cbl != ATA_CBL_PATA40_SHORT) hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index e610a5340fdc..938d35f35c81 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -1,7 +1,4 @@ - /* - * linux/drivers/ide/pci/it821x.c Version 0.16 Jul 3 2007 - * * Copyright (C) 2004 Red Hat <alan@redhat.com> * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * @@ -113,7 +110,8 @@ static int it8212_noraid; static void it821x_program(ide_drive_t *drive, u16 timing) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; u8 conf; @@ -123,7 +121,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing) conf = timing >> 8; else conf = timing & 0xFF; - pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf); + + pci_write_config_byte(dev, 0x54 + 4 * channel, conf); } /** @@ -137,7 +136,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing) static void it821x_program_udma(ide_drive_t *drive, u16 timing) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; int unit = drive->select.b.unit; @@ -148,11 +148,12 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing) conf = timing >> 8; else conf = timing & 0xFF; - if(itdev->timing10 == 0) - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf); + + if (itdev->timing10 == 0) + pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf); else { - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf); - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf); + pci_write_config_byte(dev, 0x56 + 4 * channel, conf); + pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf); } } @@ -167,6 +168,7 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing) static void it821x_clock_strategy(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); u8 unit = drive->select.b.unit; @@ -205,10 +207,11 @@ static void it821x_clock_strategy(ide_drive_t *drive) itdev->clock_mode = ATA_50; sel = 1; } - pci_read_config_byte(hwif->pci_dev, 0x50, &v); + + pci_read_config_byte(dev, 0x50, &v); v &= ~(1 << (1 + hwif->channel)); v |= sel << (1 + hwif->channel); - pci_write_config_byte(hwif->pci_dev, 0x50, v); + pci_write_config_byte(dev, 0x50, v); /* * Reprogram the UDMA/PIO of the pair drive for the switch @@ -282,7 +285,8 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif); int unit = drive->select.b.unit; int channel = hwif->channel; @@ -297,12 +301,12 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) itdev->udma[unit] = UDMA_OFF; /* UDMA bits off - Revision 0x10 do them in pairs */ - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); - if(itdev->timing10) + pci_read_config_byte(dev, 0x50, &conf); + if (itdev->timing10) conf |= channel ? 0x60: 0x18; else conf |= 1 << (3 + 2 * channel + unit); - pci_write_config_byte(hwif->pci_dev, 0x50, conf); + pci_write_config_byte(dev, 0x50, conf); it821x_clock_strategy(drive); /* FIXME: do we need to program this ? */ @@ -320,7 +324,8 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int unit = drive->select.b.unit; int channel = hwif->channel; @@ -337,12 +342,12 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ /* UDMA on. Again revision 0x10 must do the pair */ - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); - if(itdev->timing10) + pci_read_config_byte(dev, 0x50, &conf); + if (itdev->timing10) conf &= channel ? 0x9F: 0xE7; else conf &= ~ (1 << (3 + 2 * channel + unit)); - pci_write_config_byte(hwif->pci_dev, 0x50, conf); + pci_write_config_byte(dev, 0x50, conf); it821x_clock_strategy(drive); it821x_program_udma(drive, itdev->udma[unit]); @@ -520,6 +525,7 @@ static void __devinit it821x_quirkproc(ide_drive_t *drive) static void __devinit init_hwif_it821x(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL); u8 conf; @@ -532,7 +538,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) ide_set_hwifdata(hwif, idev); - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + pci_read_config_byte(dev, 0x50, &conf); if (conf & 1) { idev->smart = 1; hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; @@ -555,7 +561,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) * this is necessary. */ - pci_read_config_byte(hwif->pci_dev, 0x08, &conf); + pci_read_config_byte(dev, 0x08, &conf); if (conf == 0x10) { idev->timing10 = 1; hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 0083eaf89c77..8b40f6479c55 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -30,7 +30,7 @@ typedef enum { static u8 __devinit ata66_jmicron(ide_hwif_t *hwif) { - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); u32 control; u32 control5; diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index d4df4642dbb5..fc9eee9ccac3 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/ns87415.c Version 2.00 Sep. 10, 2002 - * * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com> * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be> * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> @@ -71,10 +69,9 @@ static u8 superio_ide_inb (unsigned long port) static void __devinit superio_ide_init_iops (struct hwif_s *hwif) { + struct pci_dev *pdev = to_pci_dev(hwif->dev); u32 base, dmabase; - u8 tmp; - struct pci_dev *pdev = hwif->pci_dev; - u8 port = hwif->channel; + u8 port = hwif->channel, tmp; base = pci_resource_start(pdev, port * 2) & ~3; dmabase = pci_resource_start(pdev, 4) & ~3; @@ -93,10 +90,11 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif) static void __devinit init_iops_ns87415(ide_hwif_t *hwif) { - if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + + if (PCI_SLOT(dev->devfn) == 0xE) /* Built-in - assume it's under superio. */ superio_ide_init_iops(hwif); - } } #endif @@ -110,8 +108,8 @@ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; - struct pci_dev *dev = hwif->pci_dev; unsigned long flags; local_irq_save(flags); @@ -189,7 +187,7 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive) static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int ctrl, using_inta; u8 progif; #ifdef __sparc_v9__ @@ -231,8 +229,8 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) #ifdef __sparc_v9__ /* - * XXX: Reset the device, if we don't it will not respond - * to SELECT_DRIVE() properly during first probe_hwif(). + * XXX: Reset the device, if we don't it will not respond to + * SELECT_DRIVE() properly during first ide_probe_port(). */ timeout = 10000; outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]); diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 8953d9c3926f..0ce92d323036 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/opti621.c Version 0.9 Sep 24, 2007 - * * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) */ diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 89d2363a1ebd..bb29db03540e 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -149,6 +149,7 @@ static struct udma_timing { static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; /* @@ -159,7 +160,7 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) * As we set up the PLL to output 133 MHz for UltraDMA/133 capable * chips, we must override the default register settings... */ - if (max_dma_rate(hwif->pci_dev) == 4) { + if (max_dma_rate(dev) == 4) { u8 mode = speed & 0x07; if (speed >= XFER_UDMA_0) { @@ -186,9 +187,10 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; - if (max_dma_rate(hwif->pci_dev) == 4) { + if (max_dma_rate(dev) == 4) { set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 3a1e081fe390..31a1308414a0 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/pdc202xx_old.c Version 0.52 Aug 27, 2007 - * * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2006-2007 MontaVista Software, Inc. * Copyright (C) 2007 Bartlomiej Zolnierkiewicz @@ -66,7 +64,7 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *); static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 drive_pci = 0x60 + (drive->dn << 2); u8 AP = 0, BP = 0, CP = 0; @@ -144,9 +142,10 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10); - pci_read_config_word(hwif->pci_dev, 0x50, &CIS); + pci_read_config_word(dev, 0x50, &CIS); return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; } @@ -305,12 +304,14 @@ static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + hwif->set_pio_mode = &pdc202xx_set_pio_mode; hwif->set_dma_mode = &pdc202xx_set_mode; hwif->quirkproc = &pdc202xx_quirkproc; - if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) + if (dev->device != PCI_DEVICE_ID_PROMISE_20246) hwif->resetproc = &pdc202xx_reset; if (hwif->dma_base == 0) @@ -319,7 +320,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->dma_lost_irq = &pdc202xx_dma_lost_irq; hwif->dma_timeout = &pdc202xx_dma_timeout; - if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { + if (dev->device != PCI_DEVICE_ID_PROMISE_20246) { if (hwif->cbl != ATA_CBL_PATA40_SHORT) hwif->cbl = pdc202xx_old_cable_detect(hwif); @@ -334,7 +335,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; if (hwif->channel) { - ide_setup_dma(hwif, dmabase, 8); + ide_setup_dma(hwif, dmabase); return; } @@ -358,7 +359,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) } #endif /* CONFIG_PDC202XX_BURST */ - ide_setup_dma(hwif, dmabase, 8); + ide_setup_dma(hwif, dmabase); } static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index bd6d3f77d30c..c1a6b68337d5 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.54 Sep 5, 2007 - * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat Inc <alan@redhat.com> @@ -8,53 +6,8 @@ * * May be copied or modified under the terms of the GNU General Public License * - * PIO mode setting function for Intel chipsets. - * For use instead of BIOS settings. - * - * 40-41 - * 42-43 - * - * 41 - * 43 - * - * | PIO 0 | c0 | 80 | 0 | - * | PIO 2 | SW2 | d0 | 90 | 4 | - * | PIO 3 | MW1 | e1 | a1 | 9 | - * | PIO 4 | MW2 | e3 | a3 | b | - * - * 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 - * - * 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 - * - * 54 8421|8421 ata66 drive|ata66 enable - * - * 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_byte(HWIF(drive)->pci_dev, 0x48, ®48); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54); + * Documentation: * - * Documentation * Publically available from Intel web site. Errata documentation * is also publically available. As an aide to anyone hacking on this * driver the list of errata that are relevant is below.going back to @@ -116,7 +69,7 @@ static int no_piix_dma; static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; @@ -185,7 +138,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = hwif->channel ? 0x42 : 0x40; int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; @@ -305,7 +258,7 @@ static const struct ich_laptop ich_laptop[] = { static u8 __devinit piix_cable_detect(ide_hwif_t *hwif) { - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); const struct ich_laptop *lap = &ich_laptop[0]; u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30; diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index 6b10ae260fa2..7ed6625819d4 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003 - * * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ @@ -32,8 +30,8 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 reg; - struct pci_dev *dev = hwif->pci_dev; if (!pci_read_config_word (dev, 0x40, ®) && !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 32fdf53379f5..af499a60eb31 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/sc1200.c Version 0.97 Aug 3 2007 - * * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com> * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * @@ -87,7 +85,7 @@ static const unsigned int sc1200_pio_timings[4][5] = static void sc1200_tunepio(ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = drive->hwif; - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0; pci_read_config_dword(pdev, basereg + 4, &format); @@ -130,6 +128,7 @@ out: static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); int unit = drive->select.b.unit; unsigned int reg, timings; unsigned short pci_clock; @@ -160,12 +159,11 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0]; if (unit == 0) { /* are we configuring drive0? */ - pci_read_config_dword(hwif->pci_dev, basereg+4, ®); + pci_read_config_dword(dev, basereg + 4, ®); timings |= reg & 0x80000000; /* preserve PIO format bit */ - pci_write_config_dword(hwif->pci_dev, basereg+4, timings); - } else { - pci_write_config_dword(hwif->pci_dev, basereg+12, timings); - } + pci_write_config_dword(dev, basereg + 4, timings); + } else + pci_write_config_dword(dev, basereg + 12, timings); } /* Replacement for the standard ide_dma_end action in diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 24a85bbcd2a6..7694969b02ce 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -594,7 +594,7 @@ static int __devinit init_setup_scc(struct pci_dev *dev, static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct scc_ports *ports = pci_get_drvdata(dev); unsigned long dma_base = ports->dma; @@ -620,7 +620,7 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c; hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40; - hwif->irq = hwif->pci_dev->irq; + hwif->irq = dev->irq; hwif->dma_base = dma_base; hwif->config_data = ports->ctl; hwif->mmio = 1; @@ -636,7 +636,8 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) static void __devinit init_iops_scc(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); + hwif->hwif_data = NULL; if (pci_get_drvdata(dev) == NULL) return; @@ -726,10 +727,8 @@ static void __devexit scc_remove(struct pci_dev *dev) unsigned long dma_size = pci_resource_len(dev, 1); if (hwif->dmatable_cpu) { - pci_free_consistent(hwif->pci_dev, - PRD_ENTRIES * PRD_BYTES, - hwif->dmatable_cpu, - hwif->dmatable_dma); + pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES, + hwif->dmatable_cpu, hwif->dmatable_dma); hwif->dmatable_cpu = NULL; } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 877c09bf4829..f495253b7d41 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/serverworks.c Version 0.22 Jun 27 2007 - * * Copyright (C) 1998-2000 Michel Aubry * Copyright (C) 1998-2000 Andrzej Krzysztofowicz * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> @@ -67,7 +65,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list) static u8 svwks_udma_filter(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u8 mask = 0; if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) @@ -130,7 +128,7 @@ static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]); @@ -153,7 +151,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed) static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 }; ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = (drive->select.b.unit & 0x01); u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; @@ -287,7 +285,8 @@ static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif) */ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && dev->vendor == PCI_VENDOR_ID_SERVERWORKS && (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || @@ -305,7 +304,8 @@ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif) */ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); + if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && dev->vendor == PCI_VENDOR_ID_SERVERWORKS && dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) @@ -316,7 +316,7 @@ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif) static u8 __devinit ata66_svwks(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); /* Server Works */ if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) @@ -340,6 +340,8 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif) static void __devinit init_hwif_svwks (ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + hwif->set_pio_mode = &svwks_set_pio_mode; hwif->set_dma_mode = &svwks_set_dma_mode; hwif->udma_filter = &svwks_udma_filter; @@ -347,7 +349,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) if (!hwif->dma_base) return; - if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { if (hwif->cbl != ATA_CBL_PATA40_SHORT) hwif->cbl = ata66_svwks(hwif); } @@ -418,7 +420,9 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device d = serverworks_chipsets[idx]; - if (idx == 2 || idx == 3) { + if (idx == 1) + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + else if (idx == 2 || idx == 3) { if ((PCI_FUNC(dev->devfn) & 1) == 0) { if (pci_resource_start(dev, 0) != 0x01f1) d.host_flags &= ~IDE_HFLAG_BOOTABLE; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 9e0be7d54980..85902074b1fc 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -159,6 +159,7 @@ sgiioc4_clearirq(ide_drive_t * drive) } if (intr_reg & 0x02) { + struct pci_dev *dev = to_pci_dev(hwif->dev); /* Error when transferring DMA data on PCI bus */ u32 pci_err_addr_low, pci_err_addr_high, pci_stat_cmd_reg; @@ -167,7 +168,7 @@ sgiioc4_clearirq(ide_drive_t * drive) readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]); pci_err_addr_high = readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4)); - pci_read_config_dword(hwif->pci_dev, PCI_COMMAND, + pci_read_config_dword(dev, PCI_COMMAND, &pci_stat_cmd_reg); printk(KERN_ERR "%s(%s) : PCI Bus Error when doing DMA:" @@ -178,8 +179,7 @@ sgiioc4_clearirq(ide_drive_t * drive) __FUNCTION__, drive->name, pci_err_addr_high, pci_err_addr_low); /* Clear the PCI Error indicator */ - pci_write_config_dword(hwif->pci_dev, PCI_COMMAND, - 0x00000146); + pci_write_config_dword(dev, PCI_COMMAND, 0x00000146); } /* Clear the Interrupt, Error bits on the IOC4 */ @@ -334,6 +334,7 @@ sgiioc4_INB(unsigned long port) static int __devinit ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) { + struct pci_dev *dev = to_pci_dev(hwif->dev); void __iomem *virt_dma_base; int num_ports = sizeof (ioc4_dma_regs_t); void *pad; @@ -359,7 +360,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) } hwif->dma_base = (unsigned long) virt_dma_base; - hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, + hwif->dmatable_cpu = pci_alloc_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, &hwif->dmatable_dma); @@ -368,7 +369,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) hwif->sg_max_nents = IOC4_PRD_ENTRIES; - pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE, + pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE, (dma_addr_t *) &(hwif->dma_status)); if (pad) { @@ -376,8 +377,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) return 0; } - pci_free_consistent(hwif->pci_dev, - IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, + pci_free_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, hwif->dmatable_cpu, hwif->dmatable_dma); printk(KERN_INFO "%s() -- Error! Unable to allocate DMA Maps for drive %s\n", @@ -517,8 +517,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) } use_pio_instead: - pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); + ide_destroy_dmatable(drive); return 0; /* revert to PIO for this request */ } @@ -641,7 +640,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) hw.dev = &dev->dev; ide_init_port_hw(hwif, &hw); - hwif->pci_dev = dev; + hwif->dev = &dev->dev; hwif->channel = 0; /* Single Channel chip */ /* The IOC4 uses MMIO rather than Port IO. */ diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 908f37b4e0ee..4877bc8cd599 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.19 Nov 16 2007 - * * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> * Copyright (C) 2007 MontaVista Software, Inc. @@ -79,7 +77,7 @@ static int pdev_is_sata(struct pci_dev *pdev) static inline int is_sata(ide_hwif_t *hwif) { - return pdev_is_sata(hwif->pci_dev); + return pdev_is_sata(to_pci_dev(hwif->dev)); } /** @@ -140,13 +138,14 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) static u8 sil_pata_udma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long base = (unsigned long) hwif->hwif_data; u8 mask = 0, scsc = 0; if (hwif->mmio) scsc = hwif->INB(base + 0x4A); else - pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); + pci_read_config_byte(dev, 0x8A, &scsc); if ((scsc & 0x30) == 0x10) /* 133 */ mask = ATA_UDMA6; @@ -219,19 +218,21 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) mode |= (unit ? 0x10 : 0x01); hwif->OUTB(mode, base + addr_mask); } else { - pci_write_config_word(hwif->pci_dev, addr, speedp); - pci_write_config_word(hwif->pci_dev, tfaddr, speedt); - pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); + struct pci_dev *dev = to_pci_dev(hwif->dev); + + pci_write_config_word(dev, addr, speedp); + pci_write_config_word(dev, tfaddr, speedt); + pci_read_config_word(dev, tfaddr - 2, &speedp); speedp &= ~0x200; /* Set IORDY for mode 3 or 4 */ if (pio > 2) speedp |= 0x200; - pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); + pci_write_config_word(dev, tfaddr - 2, speedp); - pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); + pci_read_config_byte(dev, addr_mask, &mode); mode &= ~(unit ? 0x30 : 0x03); mode |= (unit ? 0x10 : 0x01); - pci_write_config_byte(hwif->pci_dev, addr_mask, mode); + pci_write_config_byte(dev, addr_mask, mode); } } @@ -250,6 +251,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; unsigned long base = (unsigned long)hwif->hwif_data; @@ -266,10 +268,10 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) multi = hwif->INW(ma); ultra = hwif->INW(ua); } else { - pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); - pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); - pci_read_config_word(hwif->pci_dev, ma, &multi); - pci_read_config_word(hwif->pci_dev, ua, &ultra); + pci_read_config_byte(dev, 0x8A, &scsc); + pci_read_config_byte(dev, addr_mask, &mode); + pci_read_config_word(dev, ma, &multi); + pci_read_config_word(dev, ua, &ultra); } mode &= ~((unit) ? 0x30 : 0x03); @@ -293,9 +295,9 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) hwif->OUTW(multi, ma); hwif->OUTW(ultra, ua); } else { - pci_write_config_byte(hwif->pci_dev, addr_mask, mode); - pci_write_config_word(hwif->pci_dev, ma, multi); - pci_write_config_word(hwif->pci_dev, ua, ultra); + pci_write_config_byte(dev, addr_mask, mode); + pci_write_config_word(dev, ma, multi); + pci_write_config_word(dev, ua, ultra); } } @@ -303,6 +305,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) static int siimage_io_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 dma_altstat = 0; unsigned long addr = siimage_selreg(hwif, 1); @@ -311,7 +314,7 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive) return 1; /* return 1 if Device INTR asserted */ - pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat); + pci_read_config_byte(dev, addr, &dma_altstat); if (dma_altstat & 8) return 0; //return 1; return 0; @@ -377,13 +380,14 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) static int sil_sata_busproc(ide_drive_t * drive, int state) { ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); u32 stat_config = 0; unsigned long addr = siimage_selreg(hwif, 0); if (hwif->mmio) stat_config = readl((void __iomem *)addr); else - pci_read_config_dword(hwif->pci_dev, addr, &stat_config); + pci_read_config_dword(dev, addr, &stat_config); switch (state) { case BUSSTATE_ON: @@ -643,7 +647,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); void *addr = pci_get_drvdata(dev); u8 ch = hwif->channel; hw_regs_t hw; @@ -756,12 +760,14 @@ static void __devinit sil_quirkproc(ide_drive_t *drive) static void __devinit init_iops_siimage(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + hwif->hwif_data = NULL; /* Pessimal until we finish probing */ hwif->rqsize = 15; - if (pci_get_drvdata(hwif->pci_dev) == NULL) + if (pci_get_drvdata(dev) == NULL) return; init_mmio_iops_siimage(hwif); @@ -777,11 +783,12 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif) static u8 __devinit ata66_siimage(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long addr = siimage_selreg(hwif, 0); u8 ata66 = 0; - if (pci_get_drvdata(hwif->pci_dev) == NULL) - pci_read_config_byte(hwif->pci_dev, addr, &ata66); + if (pci_get_drvdata(dev) == NULL) + pci_read_config_byte(dev, addr, &ata66); else ata66 = hwif->INB(addr); diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 85d36996e6af..2a461de22aa0 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.31 Aug 9, 2007 - * * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> @@ -197,7 +195,7 @@ static char* chipset_capability[] = { static u8 sis_ata133_get_base(ide_drive_t *drive) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 reg54 = 0; pci_read_config_dword(dev, 0x54, ®54); @@ -207,7 +205,7 @@ static u8 sis_ata133_get_base(ide_drive_t *drive) static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u16 t1 = 0; u8 drive_pci = 0x40 + drive->dn * 2; @@ -230,7 +228,7 @@ static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode) static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u8 t1, drive_pci = 0x40 + drive->dn * 2; /* timing bits: 7:4 active 3:0 recovery */ @@ -253,7 +251,7 @@ static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode) static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 t1 = 0; u8 drive_pci = sis_ata133_get_base(drive), clk, idx; @@ -286,7 +284,7 @@ static void sis_program_timings(ide_drive_t *drive, const u8 mode) static void config_drive_art_rwp (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg4bh = 0; u8 rw_prefetch = 0; @@ -307,7 +305,7 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 regdw = 0; u8 drive_pci = sis_ata133_get_base(drive), clk, idx; @@ -326,7 +324,7 @@ static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family; pci_read_config_byte(dev, drive_pci + 1, ®); @@ -359,7 +357,7 @@ static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed) static u8 sis5513_ata133_udma_filter(ide_drive_t *drive) { - struct pci_dev *dev = drive->hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 regdw = 0; u8 drive_pci = sis_ata133_get_base(drive); @@ -530,7 +528,7 @@ static const struct sis_laptop sis_laptop[] = { static u8 __devinit ata66_sis5513(ide_hwif_t *hwif) { - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); const struct sis_laptop *lap = &sis_laptop[0]; u8 ata66 = 0; @@ -545,12 +543,12 @@ static u8 __devinit ata66_sis5513(ide_hwif_t *hwif) if (chipset_family >= ATA_133) { u16 regw = 0; u16 reg_addr = hwif->channel ? 0x52: 0x50; - pci_read_config_word(hwif->pci_dev, reg_addr, ®w); + pci_read_config_word(pdev, reg_addr, ®w); ata66 = (regw & 0x8000) ? 0 : 1; } else if (chipset_family >= ATA_66) { u8 reg48h = 0; u8 mask = hwif->channel ? 0x20 : 0x10; - pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); + pci_read_config_byte(pdev, 0x48, ®48h); ata66 = (reg48h & mask) ? 0 : 1; } diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index c7a125b66c29..da13a1298ada 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/sl82c105.c - * * SL82C105/Winbond 553 IDE driver * * Maintainer unknown. @@ -78,7 +76,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) */ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); int reg = 0x44 + drive->dn * 4; u16 drv_ctrl; @@ -147,7 +145,7 @@ static inline void sl82c105_reset_host(struct pci_dev *dev) static void sl82c105_dma_lost_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; u8 dma_cmd; @@ -184,7 +182,7 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive) static void sl82c105_dma_start(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int reg = 0x44 + drive->dn * 4; DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name)); @@ -197,15 +195,17 @@ static void sl82c105_dma_start(ide_drive_t *drive) static void sl82c105_dma_timeout(ide_drive_t *drive) { + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name)); - sl82c105_reset_host(HWIF(drive)->pci_dev); + sl82c105_reset_host(dev); ide_dma_timeout(drive); } static int sl82c105_dma_end(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); int reg = 0x44 + drive->dn * 4; int ret; @@ -224,7 +224,7 @@ static int sl82c105_dma_end(ide_drive_t *drive) */ static void sl82c105_resetproc(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); u32 val; DBG(("sl82c105_resetproc(drive:%s)\n", drive->name)); @@ -293,6 +293,7 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c */ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned int rev; DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); @@ -304,7 +305,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) if (!hwif->dma_base) return; - rev = sl82c105_bridge_revision(hwif->pci_dev); + rev = sl82c105_bridge_revision(dev); if (rev <= 5) { /* * Never ever EVER under any circumstances enable diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index dbbb46819a2d..a6cf810c4699 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.19 Sep 24, 2007 - * * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> * @@ -26,7 +24,7 @@ static DEFINE_SPINLOCK(slc90e66_lock); static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; @@ -79,7 +77,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 maslave = hwif->channel ? 0x42 : 0x40; int sitre = 0, a_speed = 7 << (drive->dn * 4); int u_speed = 0, u_flag = 1 << drive->dn; @@ -122,13 +120,14 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg47 = 0; u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ hwif->set_pio_mode = &slc90e66_set_pio_mode; hwif->set_dma_mode = &slc90e66_set_dma_mode; - pci_read_config_byte(hwif->pci_dev, 0x47, ®47); + pci_read_config_byte(dev, 0x47, ®47); if (hwif->dma_base == 0) return; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index e1faf6c2fe16..9fbbb4f2dd54 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -1,6 +1,4 @@ /* - * drivers/ide/pci/tc86c001.c Version 1.01 Sep 5, 2007 - * * Copyright (C) 2002 Toshiba Corporation * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com> * @@ -164,7 +162,8 @@ static int tc86c001_busproc(ide_drive_t *drive, int state) static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) { - unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long sc_base = pci_resource_start(dev, 5); u16 scr1 = inw(sc_base + 0x00); /* System Control 1 Register bit 15 (Soft Reset) set */ diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index ae52a96a1cf9..852b72693736 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -1,6 +1,4 @@ /* - * triflex.c - * * IDE Chipset driver for the Compaq TriFlex IDE controller. * * Known to work with the Compaq Workstation 5x00 series. @@ -43,7 +41,7 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); u8 channel_offset = hwif->channel ? 0x74 : 0x70; u16 timing = 0; u32 triflex_timings = 0; diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index 04cd893e1ab0..d9ebb698953a 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -1,8 +1,7 @@ /* - * linux/drivers/ide/pci/trm290.c Version 1.05 Dec. 26, 2007 - * * Copyright (c) 1997-1998 Mark Lord * Copyright (c) 2007 MontaVista Software, Inc. <source@mvista.com> + * * May be copied or modified under the terms of the GNU General Public License * * June 22, 2004 - get rid of check_region @@ -209,10 +208,10 @@ static int trm290_dma_setup(ide_drive_t *drive) } /* select DMA xfer */ trm290_prepare_drive(drive, 1); - outl(hwif->dmatable_dma | rw, hwif->dma_command); + outl(hwif->dmatable_dma | rw, hwif->dma_base); drive->waiting_for_dma = 1; /* start DMA */ - outw((count * 2) - 1, hwif->dma_status); + outw(count * 2 - 1, hwif->dma_base + 2); return 0; } @@ -222,23 +221,21 @@ static void trm290_dma_start(ide_drive_t *drive) static int trm290_ide_dma_end (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u16 status = 0; + u16 status; drive->waiting_for_dma = 0; /* purge DMA mappings */ ide_destroy_dmatable(drive); - status = inw(hwif->dma_status); - return (status != 0x00ff); + status = inw(HWIF(drive)->dma_base + 2); + return status != 0x00ff; } static int trm290_ide_dma_test_irq (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u16 status = 0; + u16 status; - status = inw(hwif->dma_status); - return (status == 0x00ff); + status = inw(HWIF(drive)->dma_base + 2); + return status == 0x00ff; } static void trm290_dma_host_set(ide_drive_t *drive, int on) @@ -247,21 +244,37 @@ static void trm290_dma_host_set(ide_drive_t *drive, int on) static void __devinit init_hwif_trm290(ide_hwif_t *hwif) { - unsigned int cfgbase = 0; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned int cfg_base = pci_resource_start(dev, 4); unsigned long flags; u8 reg = 0; - struct pci_dev *dev = hwif->pci_dev; - - cfgbase = pci_resource_start(dev, 4); - if ((dev->class & 5) && cfgbase) { - hwif->config_data = cfgbase; - printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n", - hwif->config_data); - } else { - hwif->config_data = 0x3df0; - printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n", - hwif->config_data); + + if ((dev->class & 5) && cfg_base) + printk(KERN_INFO "TRM290: chip"); + else { + cfg_base = 0x3df0; + printk(KERN_INFO "TRM290: using default"); } + printk(KERN_CONT " config base at 0x%04x\n", cfg_base); + hwif->config_data = cfg_base; + hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0); + + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx", + hwif->name, hwif->dma_base, hwif->dma_base + 3); + + if (!request_region(hwif->dma_base, 4, hwif->name)) { + printk(KERN_CONT " -- Error, ports in use.\n"); + return; + } + + hwif->dmatable_cpu = pci_alloc_consistent(dev, PRD_ENTRIES * PRD_BYTES, + &hwif->dmatable_dma); + if (!hwif->dmatable_cpu) { + printk(KERN_CONT " -- Error, unable to allocate DMA table.\n"); + release_region(hwif->dma_base, 4); + return; + } + printk(KERN_CONT "\n"); local_irq_save(flags); /* put config reg into first byte of hwif->select_data */ @@ -276,15 +289,13 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) outb(reg, hwif->config_data + 3); local_irq_restore(flags); - if ((reg & 0x10)) + if (reg & 0x10) /* legacy mode */ hwif->irq = hwif->channel ? 15 : 14; else if (!hwif->irq && hwif->mate && hwif->mate->irq) /* sharing IRQ with mate */ hwif->irq = hwif->mate->irq; - ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); - hwif->dma_host_set = &trm290_dma_host_set; hwif->dma_setup = &trm290_dma_setup; hwif->dma_exec_cmd = &trm290_dma_exec_cmd; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 4b32c90f4896..24cb9047fb41 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -1,7 +1,4 @@ /* - * - * Version 3.50 - * * VIA IDE driver for Linux. Supported southbridges: * * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, @@ -121,8 +118,8 @@ struct via82cxxx_dev static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) { - struct pci_dev *dev = hwif->pci_dev; - struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct via82cxxx_dev *vdev = pci_get_drvdata(dev); u8 t; if (~vdev->via_config->flags & VIA_BAD_AST) { @@ -159,8 +156,10 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) static void via_set_drive(ide_drive_t *drive, const u8 speed) { - ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); - struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev); + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *peer = hwif->drives + (~drive->dn & 1); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct via82cxxx_dev *vdev = pci_get_drvdata(dev); struct ide_timing t, p; unsigned int T, UT; @@ -408,7 +407,7 @@ static int via_cable_override(struct pci_dev *pdev) static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif) { - struct pci_dev *pdev = hwif->pci_dev; + struct pci_dev *pdev = to_pci_dev(hwif->dev); struct via82cxxx_dev *vdev = pci_get_drvdata(pdev); if (via_cable_override(pdev)) diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index 3fd5d45b5e0e..45c1d55e60df 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ppc/ide-m8xx.c - * * Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de * Modified for direct IDE interface * by Thomas Lange, thomas@corelatus.com diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 736d12c8e68a..23112ef68f67 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ppc/pmac.c - * * Support for IDE interfaces on PowerMacs. + * * These IDE interfaces are memory-mapped and have a DBDMA channel * for doing DMA. * @@ -1011,7 +1010,7 @@ pmac_ide_do_resume(ide_hwif_t *hwif) * (it is kept in 2.4). This introduce an interface numbering change on some * rare machines unfortunately, but it's better this way. */ -static int +static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) { struct device_node *np = pmif->node; @@ -1200,7 +1199,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) base = ioremap(macio_resource_start(mdev, 0), 0x400); regbase = (unsigned long) base; - hwif->pci_dev = mdev->bus->pdev; + hwif->dev = &mdev->bus->pdev->dev; pmif->mdev = mdev; pmif->node = mdev->ofdev.node; @@ -1228,12 +1227,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) /* The inteface is released to the common IDE layer */ dev_set_drvdata(&mdev->ofdev.dev, NULL); iounmap(base); - if (pmif->dma_regs) + if (pmif->dma_regs) { iounmap(pmif->dma_regs); + macio_release_resource(mdev, 1); + } memset(pmif, 0, sizeof(*pmif)); macio_release_resource(mdev, 0); - if (pmif->dma_regs) - macio_release_resource(mdev, 1); } return rc; @@ -1315,7 +1314,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) return -ENXIO; } - hwif->pci_dev = pdev; + hwif->dev = &pdev->dev; pmif->mdev = NULL; pmif->node = np; @@ -1535,11 +1534,10 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) } printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); - use_pio_instead: - pci_unmap_sg(hwif->pci_dev, - hwif->sg_table, - hwif->sg_nents, - hwif->sg_dma_direction); + +use_pio_instead: + ide_destroy_dmatable(drive); + return 0; /* revert to PIO for this request */ } @@ -1548,12 +1546,9 @@ static void pmac_ide_destroy_dmatable (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = HWIF(drive)->pci_dev; - struct scatterlist *sg = hwif->sg_table; - int nents = hwif->sg_nents; - if (nents) { - pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction); + if (hwif->sg_nents) { + ide_destroy_dmatable(drive); hwif->sg_nents = 0; } } @@ -1726,13 +1721,15 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive) * Allocate the data structures needed for using DMA with an interface * and fill the proper list of functions pointers */ -static void __init +static void __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + /* We won't need pci_dev if we switch to generic consistent * DMA routines ... */ - if (hwif->pci_dev == NULL) + if (dev == NULL) return; /* * Allocate space for the DBDMA commands. @@ -1740,7 +1737,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) * aligning the start address to a multiple of 16 bytes. */ pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent( - hwif->pci_dev, + dev, (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), &hwif->dmatable_dma); if (pmif->dma_table_cpu == NULL) { diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 676c66e72881..05db429a7da8 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -1,9 +1,8 @@ /* - * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19 + * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 1995-1998 Mark Lord + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * - * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * - * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License */ @@ -140,6 +139,16 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) } #ifdef CONFIG_BLK_DEV_IDEDMA_PCI +static void ide_pci_clear_simplex(unsigned long dma_base, const char *name) +{ + u8 dma_stat = inb(dma_base + 2); + + outb(dma_stat & 0x60, dma_base + 2); + dma_stat = inb(dma_base + 2); + if (dma_stat & 0x80) + printk(KERN_INFO "%s: simplex device: DMA forced\n", name); +} + /** * ide_get_or_set_dma_base - setup BMIBA * @d: IDE port info @@ -152,8 +161,9 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_hwif_t *hwif) { - unsigned long dma_base = 0; - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long dma_base = 0; + u8 dma_stat = 0; if (hwif->mmio) return hwif->dma_base; @@ -174,52 +184,30 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_ if (hwif->channel) dma_base += 8; - if ((d->host_flags & IDE_HFLAG_CS5520) == 0) { - u8 simplex_stat = 0; - - switch(dev->device) { - case PCI_DEVICE_ID_AL_M5219: - case PCI_DEVICE_ID_AL_M5229: - case PCI_DEVICE_ID_AMD_VIPER_7409: - case PCI_DEVICE_ID_CMD_643: - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - case PCI_DEVICE_ID_REVOLUTION: - simplex_stat = inb(dma_base + 2); - outb(simplex_stat & 0x60, dma_base + 2); - simplex_stat = inb(dma_base + 2); - if (simplex_stat & 0x80) { - printk(KERN_INFO "%s: simplex device: " - "DMA forced\n", - d->name); - } - break; - default: - /* - * If the device claims "simplex" DMA, - * this means only one of the two interfaces - * can be trusted with DMA at any point in time. - * So we should enable DMA only on one of the - * two interfaces. - */ - simplex_stat = hwif->INB(dma_base + 2); - if (simplex_stat & 0x80) { - /* simplex device? */ -/* - * At this point we haven't probed the drives so we can't make the - * appropriate decision. Really we should defer this problem - * until we tune the drive then try to grab DMA ownership if we want - * to be the DMA end. This has to be become dynamic to handle hot - * plug. - */ - if (hwif->mate && hwif->mate->dma_base) { - printk(KERN_INFO "%s: simplex device: " - "DMA disabled\n", - d->name); - dma_base = 0; - } - } - } + if (d->host_flags & IDE_HFLAG_CS5520) + goto out; + + if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) { + ide_pci_clear_simplex(dma_base, d->name); + goto out; + } + + /* + * If the device claims "simplex" DMA, this means that only one of + * the two interfaces can be trusted with DMA at any point in time + * (so we should enable DMA only on one of the two interfaces). + * + * FIXME: At this point we haven't probed the drives so we can't make + * the appropriate decision. Really we should defer this problem until + * we tune the drive then try to grab DMA ownership if we want to be + * the DMA end. This has to be become dynamic to handle hot-plug. + */ + dma_stat = hwif->INB(dma_base + 2); + if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) { + printk(KERN_INFO "%s: simplex device: DMA disabled\n", d->name); + dma_base = 0; } +out: return dma_base; } #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ @@ -240,7 +228,9 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise); * @d: IDE port info * * Enable the IDE PCI device. We attempt to enable the device in full - * but if that fails then we only need BAR4 so we will enable that. + * but if that fails then we only need IO space. The PCI code should + * have setup the proper resources for us already for controllers in + * legacy mode. * * Returns zero on success or an error code */ @@ -250,7 +240,7 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d) int ret; if (pci_enable_device(dev)) { - ret = pci_enable_device_bars(dev, 1 << 4); + ret = pci_enable_device_io(dev); if (ret < 0) { printk(KERN_WARNING "%s: (ide_setup_pci_device:) " "Could not enable device.\n", d->name); @@ -402,7 +392,7 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port hwif->noprobe = oldnoprobe; - hwif->pci_dev = dev; + hwif->dev = &dev->dev; hwif->cds = d; hwif->channel = port; @@ -451,7 +441,7 @@ static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info * if (d->init_dma) { d->init_dma(hwif, dma_base); } else { - ide_setup_dma(hwif, dma_base, 8); + ide_setup_dma(hwif, dma_base); } } else { printk(KERN_INFO "%s: %s Bus-Master DMA disabled " diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 9e5ea074ad20..ef5a6a245f5f 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -108,6 +108,7 @@ int pci_bus_add_device(struct pci_dev *dev) void pci_bus_add_devices(struct pci_bus *bus) { struct pci_dev *dev; + struct pci_bus *child_bus; int retval; list_for_each_entry(dev, &bus->devices, bus_list) { @@ -138,11 +139,19 @@ void pci_bus_add_devices(struct pci_bus *bus) up_write(&pci_bus_sem); } pci_bus_add_devices(dev->subordinate); - retval = sysfs_create_link(&dev->subordinate->class_dev.kobj, - &dev->dev.kobj, "bridge"); + + /* register the bus with sysfs as the parent is now + * properly registered. */ + child_bus = dev->subordinate; + child_bus->dev.parent = child_bus->bridge; + retval = device_register(&child_bus->dev); + if (!retval) + retval = device_create_file(&child_bus->dev, + &dev_attr_cpuaffinity); if (retval) - dev_err(&dev->dev, "Error creating sysfs " - "bridge symlink, continuing...\n"); + dev_err(&dev->dev, "Error registering pci_bus" + " device bridge symlink," + " continuing...\n"); } } } @@ -204,7 +213,6 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), } up_read(&pci_bus_sem); } -EXPORT_SYMBOL_GPL(pci_walk_bus); EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL_GPL(pci_bus_add_device); diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 5dfdfdac92e1..91b2dc956be5 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/dmar.h> +#include "iova.h" #undef PREFIX #define PREFIX "DMAR:" @@ -263,8 +264,8 @@ parse_dmar_table(void) if (!dmar) return -ENODEV; - if (!dmar->width) { - printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n"); + if (dmar->width < PAGE_SHIFT_4K - 1) { + printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); return -EINVAL; } @@ -301,11 +302,24 @@ parse_dmar_table(void) int __init dmar_table_init(void) { - parse_dmar_table(); + int ret; + + ret = parse_dmar_table(); + if (ret) { + printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); + return ret; + } + if (list_empty(&dmar_drhd_units)) { printk(KERN_INFO PREFIX "No DMAR devices found\n"); return -ENODEV; } + + if (list_empty(&dmar_rmrr_units)) { + printk(KERN_INFO PREFIX "No RMRR found\n"); + return -ENODEV; + } + return 0; } diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index a64449d489d6..2cdd8326f136 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -3,8 +3,8 @@ # menuconfig HOTPLUG_PCI - tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL && HOTPLUG + tristate "Support for PCI Hotplug" + depends on PCI && HOTPLUG ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 34a1891191fd..9bdbe1a6688f 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o @@ -16,6 +15,9 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o +# Link this last so it doesn't claim devices that have a real hotplug driver +obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o + pci_hotplug-objs := pci_hotplug_core.o ifdef CONFIG_HOTPLUG_PCI_CPCI diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 1ef417cca2db..7a29164d4b32 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -113,7 +113,6 @@ struct acpiphp_slot { u8 device; /* pci device# */ u32 sun; /* ACPI _SUN (slot unique number) */ - u32 slotno; /* slot number relative to bridge */ u32 flags; /* see below */ }; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ff1b1c71291a..cf22f9e01e00 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -102,7 +102,7 @@ static int is_ejectable(acpi_handle handle) } -/* callback routine to check the existence of ejectable slots */ +/* callback routine to check for the existence of ejectable slots */ static acpi_status is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -117,7 +117,7 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) } } -/* callback routine to check for the existance of a pci dock device */ +/* callback routine to check for the existence of a pci dock device */ static acpi_status is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -1528,7 +1528,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); dbg("%s: re-enumerating slots under %s\n", __FUNCTION__, objname); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpiphp_check_bridge(bridge); } return AE_OK ; diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index d7a293e3faf5..94b640146d44 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -39,6 +39,7 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/workqueue.h> #include "../pci.h" #if !defined(MODULE) @@ -63,10 +64,16 @@ struct dummy_slot { struct list_head node; struct hotplug_slot *slot; struct pci_dev *dev; + struct work_struct remove_work; + unsigned long removed; }; static int debug; static LIST_HEAD(slot_list); +static struct workqueue_struct *dummyphp_wq; + +static void pci_rescan_worker(struct work_struct *work); +static DECLARE_WORK(pci_rescan_work, pci_rescan_worker); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); @@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev) slot->name = &dev->dev.bus_id[0]; dbg("slot->name = %s\n", slot->name); - dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); + dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); if (!dslot) goto error_info; @@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot) err("Problem unregistering a slot %s\n", dslot->slot->name); } +/* called from the single-threaded workqueue handler to remove a slot */ +static void remove_slot_worker(struct work_struct *work) +{ + struct dummy_slot *dslot = + container_of(work, struct dummy_slot, remove_work); + remove_slot(dslot); +} + /** * pci_rescan_slot - Rescan slot * @temp: Device template. Should be set: bus and devfn. @@ -267,11 +282,17 @@ static inline void pci_rescan(void) { pci_rescan_buses(&pci_root_buses); } +/* called from the single-threaded workqueue handler to rescan all pci buses */ +static void pci_rescan_worker(struct work_struct *work) +{ + pci_rescan(); +} static int enable_slot(struct hotplug_slot *hotplug_slot) { /* mis-use enable_slot for rescanning of the pci bus */ - pci_rescan(); + cancel_work_sync(&pci_rescan_work); + queue_work(dummyphp_wq, &pci_rescan_work); return -ENODEV; } @@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot) err("Can't remove PCI devices with other PCI devices behind it yet.\n"); return -ENODEV; } + if (test_and_set_bit(0, &dslot->removed)) { + dbg("Slot already scheduled for removal\n"); + return -ENODEV; + } /* search for subfunctions and disable them first */ if (!(dslot->dev->devfn & 7)) { for (func = 1; func < 8; func++) { @@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot) /* remove the device from the pci core */ pci_remove_bus_device(dslot->dev); - /* blow away this sysfs entry and other parts. */ - remove_slot(dslot); + /* queue work item to blow away this sysfs entry and other parts. */ + INIT_WORK(&dslot->remove_work, remove_slot_worker); + queue_work(dummyphp_wq, &dslot->remove_work); return 0; } @@ -340,6 +366,7 @@ static void cleanup_slots (void) struct list_head *next; struct dummy_slot *dslot; + destroy_workqueue(dummyphp_wq); list_for_each_safe (tmp, next, &slot_list) { dslot = list_entry (tmp, struct dummy_slot, node); remove_slot(dslot); @@ -351,6 +378,10 @@ static int __init dummyphp_init(void) { info(DRIVER_DESC "\n"); + dummyphp_wq = create_singlethread_workqueue(MY_NAME); + if (!dummyphp_wq) + return -ENOMEM; + return pci_scan_buses(); } diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index a90c28d0c69d..87b6b8b280e6 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -761,10 +761,13 @@ static void ibm_unconfigure_device(struct pci_func *func) debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); for (j = 0; j < 0x08; j++) { - temp = pci_find_slot(func->busno, (func->device << 3) | j); - if (temp) + temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); + if (temp) { pci_remove_bus_device(temp); + pci_dev_put(temp); + } } + pci_dev_put(func->dev); } /* @@ -823,7 +826,7 @@ static int ibm_configure_device(struct pci_func *func) if (!(bus_structure_fixup(func->busno))) flag = 1; if (func->dev == NULL) - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { @@ -836,7 +839,7 @@ static int ibm_configure_device(struct pci_func *func) if (num) pci_bus_add_devices(bus); - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { err("ERROR... : pci_dev still NULL\n"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 47bb0e1ff3fa..dd59a050260f 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -137,7 +137,7 @@ static int get_##name (struct hotplug_slot *slot, type *value) \ int retval = 0; \ if (try_module_get(ops->owner)) { \ if (ops->get_##name) \ - retval = ops->get_##name (slot, value); \ + retval = ops->get_##name(slot, value); \ else \ *value = slot->info->name; \ module_put(ops->owner); \ @@ -625,7 +625,7 @@ int pci_hp_register (struct hotplug_slot *slot) if ((slot->info == NULL) || (slot->ops == NULL)) return -EINVAL; if (slot->release == NULL) { - dbg("Why are you trying to register a hotplug slot" + dbg("Why are you trying to register a hotplug slot " "without a proper release function?\n"); return -EINVAL; } diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 7959c222dc24..ca656b27a500 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -82,24 +82,18 @@ struct event_info { }; struct controller { - struct controller *next; struct mutex crit_sect; /* critical section mutex */ struct mutex ctrl_lock; /* controller lock */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; struct list_head slot_list; - struct slot *slot; struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ - u8 bus; - u8 device; - u8 function; u8 slot_device_offset; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 ctrlcap; - u16 vendor_id; u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; @@ -161,6 +155,9 @@ extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot); extern void pciehp_queue_pushbutton_work(struct work_struct *work); int pcie_init(struct controller *ctrl, struct pcie_device *dev); +int pciehp_enable_slot(struct slot *p_slot); +int pciehp_disable_slot(struct slot *p_slot); +int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev); static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 6462ac3b405f..7f4836b8e71e 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -453,13 +453,9 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ pci_set_drvdata(pdev, ctrl); - ctrl->bus = pdev->bus->number; /* ctrl bus */ - ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ - - ctrl->device = PCI_SLOT(pdev->devfn); - ctrl->function = PCI_FUNC(pdev->devfn); - dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, - ctrl->bus, ctrl->device, ctrl->function, pdev->irq); + dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", + __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); /* Setup the slot information structures */ rc = init_slots(ctrl); @@ -471,6 +467,11 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ + if (value) { + rc = pciehp_enable_slot(t_slot); + if (rc) /* -ENODEV: shouldn't happen, but deal with it */ + value = 0; + } if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) @@ -509,6 +510,24 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) static int pciehp_resume (struct pcie_device *dev) { printk("%s ENTRY\n", __FUNCTION__); + if (pciehp_force) { + struct pci_dev *pdev = dev->port; + struct controller *ctrl = pci_get_drvdata(pdev); + struct slot *t_slot; + u8 status; + + /* reinitialize the chipset's event detection logic */ + pcie_init_hardware_part2(ctrl, dev); + + t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); + + /* Check if slot is occupied */ + t_slot->hpc_ops->get_adapter_status(t_slot, &status); + if (status) + pciehp_enable_slot(t_slot); + else + pciehp_disable_slot(t_slot); + } return 0; } #endif diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f1e0966cee95..b23061c56115 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -37,8 +37,6 @@ #include "pciehp.h" static void interrupt_event_handler(struct work_struct *work); -static int pciehp_enable_slot(struct slot *p_slot); -static int pciehp_disable_slot(struct slot *p_slot); static int queue_interrupt_event(struct slot *p_slot, u32 event_type) { @@ -197,12 +195,6 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) __FUNCTION__); return; } - /* - * After turning power off, we must wait for at least - * 1 second before taking any action that relies on - * power having been removed from the slot/adapter. - */ - msleep(1000); } } @@ -215,15 +207,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) */ static int board_added(struct slot *p_slot) { - u8 hp_slot; int retval = 0; struct controller *ctrl = p_slot->ctrl; - hp_slot = p_slot->device - ctrl->slot_device_offset; - dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n", __FUNCTION__, p_slot->device, - ctrl->slot_device_offset, hp_slot); + ctrl->slot_device_offset, p_slot->hp_slot); if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ @@ -281,8 +270,6 @@ err_exit: */ static int remove_board(struct slot *p_slot) { - u8 device; - u8 hp_slot; int retval = 0; struct controller *ctrl = p_slot->ctrl; @@ -290,11 +277,7 @@ static int remove_board(struct slot *p_slot) if (retval) return retval; - device = p_slot->device; - hp_slot = p_slot->device - ctrl->slot_device_offset; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot); if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ @@ -621,12 +604,6 @@ int pciehp_disable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } - /* - * After turning power off, we must wait for at least - * 1 second before taking any action that relies on - * power having been removed from the slot/adapter. - */ - msleep(1000); } ret = remove_board(p_slot); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 06d025b8b13f..6eba9b2cfb90 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot) return retval; } +static inline int pcie_mask_bad_dllp(struct controller *ctrl) +{ + struct pci_dev *dev = ctrl->pci_dev; + int pos; + u32 reg; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return 0; + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); + if (reg & PCI_ERR_COR_BAD_DLLP) + return 0; + reg |= PCI_ERR_COR_BAD_DLLP; + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); + return 1; +} + +static inline void pcie_unmask_bad_dllp(struct controller *ctrl) +{ + struct pci_dev *dev = ctrl->pci_dev; + u32 reg; + int pos; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return; + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); + if (!(reg & PCI_ERR_COR_BAD_DLLP)) + return; + reg &= ~PCI_ERR_COR_BAD_DLLP; + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); +} + static int hpc_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; int retval = 0; + int changed; dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); + /* + * Set Bad DLLP Mask bit in Correctable Error Mask + * Register. This is the workaround against Bad DLLP error + * that sometimes happens during turning power off the slot + * which conforms to PCI Express 1.0a spec. + */ + changed = pcie_mask_bad_dllp(ctrl); + slot_cmd = POWER_OFF; cmd_mask = PWR_CTRL; /* @@ -674,6 +716,16 @@ static int hpc_power_off_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. + */ + msleep(1000); + + if (changed) + pcie_unmask_bad_dllp(ctrl); + return retval; } @@ -1067,13 +1119,143 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif -int pcie_init(struct controller * ctrl, struct pcie_device *dev) +static int pcie_init_hardware_part1(struct controller *ctrl, + struct pcie_device *dev) +{ + int rc; + u16 temp_word; + u32 slot_cap; + u16 slot_status; + + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); + if (rc) { + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); + return -1; + } + + /* Mask Hot-plug Interrupt Enable */ + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + return -1; + } + + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | + 0x00; + + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + if (rc) { + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + return -1; + } + + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (rc) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + return -1; + } + + temp_word = 0x1F; /* Clear all events */ + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); + if (rc) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + return -1; + } + return 0; +} + +int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { int rc; u16 temp_word; - u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; + u16 slot_status; + + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + goto abort; + } + + intr_enable = intr_enable | PRSN_DETECT_ENABLE; + + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); + if (rc) { + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); + goto abort; + } + + if (ATTN_BUTTN(slot_cap)) + intr_enable = intr_enable | ATTN_BUTTN_ENABLE; + + if (POWER_CTRL(slot_cap)) + intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; + + if (MRL_SENS(slot_cap)) + intr_enable = intr_enable | MRL_DETECT_ENABLE; + + temp_word = (temp_word & ~intr_enable) | intr_enable; + + if (pciehp_poll_mode) { + temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; + } else { + temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; + } + + /* + * Unmask Hot-plug Interrupt Enable for the interrupt + * notification mechanism case. + */ + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + if (rc) { + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + goto abort; + } + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (rc) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + goto abort_disable_intr; + } + + temp_word = 0x1F; /* Clear all events */ + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); + if (rc) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + goto abort_disable_intr; + } + + if (pciehp_force) { + dbg("Bypassing BIOS check for pciehp use on %s\n", + pci_name(ctrl->pci_dev)); + } else { + rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); + if (rc) + goto abort_disable_intr; + } + + return 0; + + /* We end up here for the many possible ways to fail this API. */ +abort_disable_intr: + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); + if (!rc) { + temp_word &= ~(intr_enable | HP_INTR_ENABLE); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + } + if (rc) + err("%s : disabling interrupts failed\n", __FUNCTION__); +abort: + return -1; +} + +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + int rc; + u16 cap_reg; + u32 slot_cap; int cap_base; u16 slot_status, slot_ctrl; struct pci_dev *pdev; @@ -1084,9 +1266,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", __FUNCTION__, pdev->vendor, pdev->device); - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { + cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap_base == 0) { dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } ctrl->cap_base = cap_base; @@ -1096,7 +1279,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = pciehp_readw(ctrl, CAPREG, &cap_reg); if (rc) { err("%s: Cannot read CAPREG register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); @@ -1106,26 +1289,26 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { dbg("%s : This is not a root port or the port is not " "connected to a slot\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTCAP offset %x slot_cap %x\n", __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } /* For debugging purpose */ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTSTATUS offset %x slot_status %x\n", __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); @@ -1133,7 +1316,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); @@ -1161,36 +1344,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->first_slot = slot_cap >> 19; ctrl->ctrlcap = slot_cap & 0x0000007f; - /* Mask Hot-plug Interrupt Enable */ - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - dbg("%s: SLOTCTRL %x value read %x\n", - __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | - 0x00; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; - } + rc = pcie_init_hardware_part1(ctrl, dev); + if (rc) + goto abort; if (pciehp_poll_mode) { /* Install interrupt polling timer. Start with 10 sec delay */ @@ -1206,7 +1362,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); - goto abort_free_ctlr; + goto abort; } } dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, @@ -1224,82 +1380,16 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) } } - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_irq; + rc = pcie_init_hardware_part2(ctrl, dev); + if (rc == 0) { + ctrl->hpc_ops = &pciehp_hpc_ops; + return 0; } - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; - - temp_word = (temp_word & ~intr_enable) | intr_enable; - - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - - /* - * Unmask Hot-plug Interrupt Enable for the interrupt - * notification mechanism case. - */ - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); - goto abort_free_irq; - } - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_disable_intr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); - goto abort_disable_intr; - } - - if (pciehp_force) { - dbg("Bypassing BIOS check for pciehp use on %s\n", - pci_name(ctrl->pci_dev)); - } else { - rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); - if (rc) - goto abort_disable_intr; - } - - ctrl->hpc_ops = &pciehp_hpc_ops; - - return 0; - - /* We end up here for the many possible ways to fail this API. */ -abort_disable_intr: - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (!rc) { - temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - } - if (rc) - err("%s : disabling interrupts failed\n", __FUNCTION__); - abort_free_irq: if (pciehp_poll_mode) del_timer_sync(&ctrl->poll_timer); else free_irq(ctrl->pci_dev->irq, ctrl); - -abort_free_ctlr: +abort: return -1; } diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index c424aded13fb..dd50713966d1 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -105,12 +105,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) } /* Find Advanced Error Reporting Enhanced Capability */ - pos = 256; - do { - pci_read_config_dword(dev, pos, ®32); - if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) - break; - } while ((pos = PCI_EXT_CAP_NEXT(reg32))); + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (!pos) return; @@ -248,11 +243,15 @@ int pciehp_unconfigure_device(struct slot *p_slot) u8 bctl = 0; u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + u16 command; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); + if (ret) + presence = 0; - for (j=0; j<8 ; j++) { + for (j = 0; j < 8; j++) { struct pci_dev* temp = pci_get_slot(parent, (p_slot->device << 3) | j); if (!temp) @@ -263,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot) pci_dev_put(temp); continue; } - if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - ret = p_slot->hpc_ops->get_adapter_status(p_slot, - &presence); - if (!ret && presence) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, - &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", - pci_name(temp)); - pci_dev_put(temp); - continue; - } + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", + pci_name(temp)); + pci_dev_put(temp); + continue; } } pci_remove_bus_device(temp); + /* + * Ensure that no new Requests will be generated from + * the device. + */ + if (presence) { + pci_read_config_word(temp, PCI_COMMAND, &command); + command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + command |= PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(temp, PCI_COMMAND, command); + } pci_dev_put(temp); } /* @@ -288,4 +292,3 @@ int pciehp_unconfigure_device(struct slot *p_slot) return rc; } - diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index c822a779653f..7d5921b1ee78 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -74,7 +74,6 @@ struct slot { u32 type; u32 power_domain; char *name; - char *location; struct device_node *dn; struct pci_bus *bus; struct list_head *pci_devs; diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0de84533cd80..6571e9b4c2ec 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -64,19 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) return rc; } -static void set_slot_name(struct slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *bridge; - - bridge = bus->self; - if (bridge) - strcpy(slot->name, pci_name(bridge)); - else - sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), - bus->number); -} - /** * rpaphp_enable_slot - record slot state, config pci device * @slot: target &slot @@ -115,7 +102,6 @@ int rpaphp_enable_slot(struct slot *slot) info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; - set_slot_name(slot); /* if there's an adapter in the slot, go add the pci devices */ if (state == PRESENT) { diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index d4ee8723fcb3..8ad3debb3794 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -33,23 +33,31 @@ #include <asm/rtas.h> #include "rpaphp.h" -static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) +static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf) { - char *value; - int retval = -ENOENT; + int retval; struct slot *slot = (struct slot *)php_slot->private; + struct pci_bus *bus; if (!slot) - return retval; + return -ENOENT; + + bus = slot->bus; + if (!bus) + return -ENOENT; + + if (bus->self) + retval = sprintf(buf, pci_name(bus->self)); + else + retval = sprintf(buf, "%04x:%02x:00.0", + pci_domain_nr(bus), bus->number); - value = slot->location; - retval = sprintf (buf, "%s\n", value); return retval; } -static struct hotplug_slot_attribute php_attr_location = { - .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, - .show = location_read_file, +static struct hotplug_slot_attribute php_attr_address = { + .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, + .show = address_read_file, }; /* free up the memory used by a slot */ @@ -64,7 +72,6 @@ void dealloc_slot_struct(struct slot *slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); - kfree(slot->location); kfree(slot); } @@ -83,16 +90,13 @@ struct slot *alloc_slot_struct(struct device_node *dn, GFP_KERNEL); if (!slot->hotplug_slot->info) goto error_hpslot; - slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL); + slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); if (!slot->hotplug_slot->name) goto error_info; - slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); - if (!slot->location) - goto error_name; slot->name = slot->hotplug_slot->name; + strcpy(slot->name, drc_name); slot->dn = dn; slot->index = drc_index; - strcpy(slot->location, drc_name); slot->power_domain = power_domain; slot->hotplug_slot->private = slot; slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; @@ -100,8 +104,6 @@ struct slot *alloc_slot_struct(struct device_node *dn, return (slot); -error_name: - kfree(slot->hotplug_slot->name); error_info: kfree(slot->hotplug_slot->info); error_hpslot: @@ -133,8 +135,8 @@ int rpaphp_deregister_slot(struct slot *slot) list_del(&slot->rpaphp_slot_list); - /* remove "phy_location" file */ - sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr); + /* remove "address" file */ + sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr); retval = pci_hp_deregister(php_slot); if (retval) @@ -166,8 +168,8 @@ int rpaphp_register_slot(struct slot *slot) return retval; } - /* create "phy_location" file */ - retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr); + /* create "address" file */ + retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr); if (retval) { err("sysfs_create_file failed with error %d\n", retval); goto sysfs_fail; @@ -175,8 +177,7 @@ int rpaphp_register_slot(struct slot *slot) /* add slot to our internal list */ list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); - info("Slot [%s](PCI location=%s) registered\n", slot->name, - slot->location); + info("Slot [%s] registered\n", slot->name); return 0; sysfs_fail: diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 5183a45d45b5..e8aa138128ce 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -597,7 +597,7 @@ static void hpc_release_ctlr(struct controller *ctrl) cleanup_slots(ctrl); /* - * Mask SERR and System Interrut generation + * Mask SERR and System Interrupt generation */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index e079a5237c94..4e01df99681a 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1781,7 +1781,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain, /* * First try to allocate an io virtual address in * DMA_32BIT_MASK and if that fails then try allocating - * from higer range + * from higher range */ iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK); if (!iova) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 07c9f09c856d..26938da8f438 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -25,6 +25,51 @@ static int pci_msi_enable = 1; +/* Arch hooks */ + +int __attribute__ ((weak)) +arch_msi_check_device(struct pci_dev *dev, int nvec, int type) +{ + return 0; +} + +int __attribute__ ((weak)) +arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) +{ + return 0; +} + +int __attribute__ ((weak)) +arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct msi_desc *entry; + int ret; + + list_for_each_entry(entry, &dev->msi_list, list) { + ret = arch_setup_msi_irq(dev, entry); + if (ret) + return ret; + } + + return 0; +} + +void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) +{ + return; +} + +void __attribute__ ((weak)) +arch_teardown_msi_irqs(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (entry->irq != 0) + arch_teardown_msi_irq(entry->irq); + } +} + static void msi_set_enable(struct pci_dev *dev, int enable) { int pos; @@ -230,7 +275,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable) pci_intx(dev, enable); } -#ifdef CONFIG_PM static void __pci_restore_msi_state(struct pci_dev *dev) { int pos; @@ -288,7 +332,7 @@ void pci_restore_msi_state(struct pci_dev *dev) __pci_restore_msi_state(dev); __pci_restore_msix_state(dev); } -#endif /* CONFIG_PM */ +EXPORT_SYMBOL_GPL(pci_restore_msi_state); /** * msi_capability_init - configure device's MSI capability structure @@ -683,49 +727,3 @@ void pci_msi_init_pci_dev(struct pci_dev *dev) { INIT_LIST_HEAD(&dev->msi_list); } - - -/* Arch hooks */ - -int __attribute__ ((weak)) -arch_msi_check_device(struct pci_dev* dev, int nvec, int type) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ - struct msi_desc *entry; - int ret; - - list_for_each_entry(entry, &dev->msi_list, list) { - ret = arch_setup_msi_irq(dev, entry); - if (ret) - return ret; - } - - return 0; -} - -void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) -{ - return; -} - -void __attribute__ ((weak)) -arch_teardown_msi_irqs(struct pci_dev *dev) -{ - struct msi_desc *entry; - - list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq != 0) - arch_teardown_msi_irq(entry->irq); - } -} diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 5c6a5d043007..e569645d59e2 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -156,13 +156,13 @@ run_osc_out: } /** - * pci_osc_support_set - register OS support to Firmware + * __pci_osc_support_set - register OS support to Firmware * @flags: OS support bits * * Update OS support fields and doing a _OSC Query to obtain an update * from Firmware on supported control bits. **/ -acpi_status pci_osc_support_set(u32 flags) +acpi_status __pci_osc_support_set(u32 flags, const char *hid) { u32 temp; acpi_status retval; @@ -176,7 +176,7 @@ acpi_status pci_osc_support_set(u32 flags) temp = ctrlset_buf[OSC_CONTROL_TYPE]; ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; - acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_get_devices(hid, acpi_query_osc, ctrlset_buf, (void **) &retval ); @@ -188,7 +188,6 @@ acpi_status pci_osc_support_set(u32 flags) } return AE_OK; } -EXPORT_SYMBOL(pci_osc_support_set); /** * pci_osc_control_set - commit requested control to Firmware diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c4fa35d1dd77..e571c72e6753 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -186,13 +186,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, set_cpus_allowed(current, node_to_cpumask(node)); /* And set default memory allocation policy */ oldpol = current->mempolicy; - current->mempolicy = &default_policy; - mpol_get(current->mempolicy); + current->mempolicy = NULL; /* fall back to system default policy */ #endif error = drv->probe(dev, id); #ifdef CONFIG_NUMA set_cpus_allowed(current, oldmask); - mpol_free(current->mempolicy); current->mempolicy = oldpol; #endif return error; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7d1877341aad..abf4203304e4 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -21,6 +21,7 @@ #include <linux/topology.h> #include <linux/mm.h> #include <linux/capability.h> +#include <linux/aspm.h> #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -358,7 +359,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); /* Only support 1, 2 or 4 byte accesses */ @@ -383,7 +384,7 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); /* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) @@ -407,7 +408,7 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, struct vm_area_struct *vma) { struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct class_device, + struct device, kobj)); return pci_mmap_legacy_page_range(bus, vma); @@ -650,6 +651,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) if (pcibios_add_platform_entries(pdev)) goto err_rom_file; + pcie_aspm_create_sysfs_dev_files(pdev); + return 0; err_rom_file: @@ -679,6 +682,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) if (!sysfs_initialized) return; + pcie_aspm_remove_sysfs_dev_files(pdev); + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 71d561fda0a2..b3e9294e4a0e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -18,6 +18,7 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/log2.h> +#include <linux/aspm.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -314,6 +315,24 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) } EXPORT_SYMBOL_GPL(pci_find_ht_capability); +void pcie_wait_pending_transaction(struct pci_dev *dev) +{ + int pos; + u16 reg16; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return; + while (1) { + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); + if (!(reg16 & PCI_EXP_DEVSTA_TRPND)) + break; + cpu_relax(); + } + +} +EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction); + /** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched @@ -353,7 +372,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * Restore the BAR values for a given device, so as to make it * accessible by its driver. */ -void +static void pci_restore_bars(struct pci_dev *dev) { int i, numres; @@ -501,6 +520,9 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (need_restore) pci_restore_bars(dev); + if (dev->bus->self) + pcie_aspm_pm_state_change(dev->bus->self); + return 0; } @@ -551,6 +573,7 @@ static int pci_save_pcie_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (pos <= 0) @@ -559,6 +582,8 @@ static int pci_save_pcie_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -569,7 +594,9 @@ static int pci_save_pcie_state(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_EXP; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -597,14 +624,17 @@ static int pci_save_pcix_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pos <= 0) return 0; - save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -612,7 +642,9 @@ static int pci_save_pcix_state(struct pci_dev *dev) cap = (u16 *)&save_state->data[0]; pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_PCIX; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -713,23 +745,19 @@ int pci_reenable_device(struct pci_dev *dev) return 0; } -/** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized - * @bars: bitmask of BAR's that must be configured - * - * Initialize device before it's used by a driver. Ask low-level code - * to enable selected I/O and memory resources. Wake up the device if it - * was suspended. Beware, this function can fail. - */ -int -pci_enable_device_bars(struct pci_dev *dev, int bars) +static int __pci_enable_device_flags(struct pci_dev *dev, + resource_size_t flags) { int err; + int i, bars = 0; if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + err = do_pci_enable_device(dev, bars); if (err < 0) atomic_dec(&dev->enable_cnt); @@ -737,6 +765,32 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) } /** + * pci_enable_device_io - Initialize a device for use with IO space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_io(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_IO); +} + +/** + * pci_enable_device_mem - Initialize a device for use with Memory space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable Memory resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_mem(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_MEM); +} + +/** * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * @@ -749,7 +803,7 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) */ int pci_enable_device(struct pci_dev *dev) { - return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); + return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } /* @@ -823,7 +877,8 @@ int pcim_enable_device(struct pci_dev *pdev) dr = get_pci_dr(pdev); if (unlikely(!dr)) return -ENOMEM; - WARN_ON(!!dr->enabled); + if (dr->enabled) + return 0; rc = pci_enable_device(pdev); if (!rc) { @@ -884,6 +939,9 @@ pci_disable_device(struct pci_dev *dev) if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; + /* Wait for all transactions are finished before disabling the device */ + pcie_wait_pending_transaction(dev); + pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; @@ -1618,9 +1676,9 @@ early_param("pci", pci_setup); device_initcall(pci_init); -EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_reenable_device); -EXPORT_SYMBOL(pci_enable_device_bars); +EXPORT_SYMBOL(pci_enable_device_io); +EXPORT_SYMBOL(pci_enable_device_mem); EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pcim_enable_device); EXPORT_SYMBOL(pcim_pin_device); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fc87e14b50de..eabeb1f2ec99 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -6,8 +6,10 @@ extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); /* Firmware callbacks */ -extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); -extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); +extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, + pm_message_t state); +extern int (*platform_pci_set_power_state)(struct pci_dev *dev, + pci_power_t state); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); @@ -45,12 +47,6 @@ static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif -#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) -void pci_restore_msi_state(struct pci_dev *dev); -#else -static inline void pci_restore_msi_state(struct pci_dev *dev) {} -#endif - #ifdef CONFIG_PCIEAER void pci_no_aer(void); #else @@ -68,14 +64,14 @@ static inline int pci_no_d1d2(struct pci_dev *dev) } extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; -extern struct class_device_attribute class_device_attr_cpuaffinity; +extern struct device_attribute dev_attr_cpuaffinity; /** * pci_match_one_device - Tell if a PCI device structure has a matching * PCI device id structure * @id: single PCI device id structure to match * @dev: the PCI device structure to match against - * + * * Returns the matching pci_device_id structure or %NULL if there is no match. */ static inline const struct pci_device_id * diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 287a9311716c..60104cf98796 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -26,3 +26,23 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. source "drivers/pci/pcie/aer/Kconfig" + +# +# PCI Express ASPM +# +config PCIEASPM + bool "PCI Express ASPM support(Experimental)" + depends on PCI && EXPERIMENTAL + default y + help + This enables PCI Express ASPM (Active State Power Management) and + Clock Power Management. ASPM supports state L0/L0s/L1. + + When in doubt, say N. +config PCIEASPM_DEBUG + bool "Debug PCI Express ASPM" + depends on PCIEASPM + default n + help + This enables PCI Express ASPM debug support. It will add per-device + interface to control ASPM. diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index e00fb99acf44..11f6bb1eae24 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -2,6 +2,9 @@ # Makefile for PCI-Express PORT Driver # +# Build PCI Express ASPM if needed +obj-$(CONFIG_PCIEASPM) += aspm.o + pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 1a1eb45a779e..8c199ae84f6d 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -31,26 +31,16 @@ int aer_osc_setup(struct pcie_device *pciedev) { acpi_status status = AE_NOT_FOUND; struct pci_dev *pdev = pciedev->port; - acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev); - struct pci_bus *parent; + acpi_handle handle = 0; - while (!handle) { - if (!pdev || !pdev->bus->parent) - break; - parent = pdev->bus->parent; - if (!parent->self) - /* Parent must be a host bridge */ - handle = acpi_get_pci_rootbridge_handle( - pci_domain_nr(parent), - parent->number); - else - handle = DEVICE_ACPI_HANDLE( - &(parent->self->dev)); - pdev = parent->self; - } + /* Find root host bridge */ + while (pdev->bus && pdev->bus->self) + pdev = pdev->bus->self; + handle = acpi_get_pci_rootbridge_handle( + pci_domain_nr(pdev->bus), pdev->bus->number); if (handle) { - pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); + pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c new file mode 100644 index 000000000000..1a5adeb10c95 --- /dev/null +++ b/drivers/pci/pcie/aspm.c @@ -0,0 +1,802 @@ +/* + * File: drivers/pci/pcie/aspm.c + * Enabling PCIE link L0s/L1 state and Clock Power Management + * + * Copyright (C) 2007 Intel + * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) + * Copyright (C) Shaohua Li (shaohua.li@intel.com) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/pci.h> +#include <linux/pci_regs.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/aspm.h> +#include <acpi/acpi_bus.h> +#include <linux/pci-acpi.h> +#include "../pci.h" + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "pcie_aspm." + +struct endpoint_state { + unsigned int l0s_acceptable_latency; + unsigned int l1_acceptable_latency; +}; + +struct pcie_link_state { + struct list_head sibiling; + struct pci_dev *pdev; + + /* ASPM state */ + unsigned int support_state; + unsigned int enabled_state; + unsigned int bios_aspm_state; + /* upstream component */ + unsigned int l0s_upper_latency; + unsigned int l1_upper_latency; + /* downstream component */ + unsigned int l0s_down_latency; + unsigned int l1_down_latency; + /* Clock PM state*/ + unsigned int clk_pm_capable; + unsigned int clk_pm_enabled; + unsigned int bios_clk_state; + + /* + * A pcie downstream port only has one slot under it, so at most there + * are 8 functions + */ + struct endpoint_state endpoints[8]; +}; + +static int aspm_disabled; +static DEFINE_MUTEX(aspm_lock); +static LIST_HEAD(link_list); + +#define POLICY_DEFAULT 0 /* BIOS default setting */ +#define POLICY_PERFORMANCE 1 /* high performance */ +#define POLICY_POWERSAVE 2 /* high power saving */ +static int aspm_policy; +static const char *policy_str[] = { + [POLICY_DEFAULT] = "default", + [POLICY_PERFORMANCE] = "performance", + [POLICY_POWERSAVE] = "powersave" +}; + +static int policy_to_aspm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Enable ASPM L0s/L1 */ + return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + case POLICY_DEFAULT: + return link_state->bios_aspm_state; + } + return 0; +} + +static int policy_to_clkpm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Disable Clock PM */ + return 1; + case POLICY_DEFAULT: + return link_state->bios_clk_state; + } + return 0; +} + +static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +{ + struct pci_dev *child_dev; + int pos; + u16 reg16; + struct pcie_link_state *link_state = pdev->link_state; + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (enable) + reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; + else + reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + } + link_state->clk_pm_enabled = !!enable; +} + +static void pcie_check_clock_pm(struct pci_dev *pdev) +{ + int pos; + u32 reg32; + u16 reg16; + int capable = 1, enabled = 1; + struct pci_dev *child_dev; + struct pcie_link_state *link_state = pdev->link_state; + + /* All functions should have the same cap and state, take the worst */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { + capable = 0; + enabled = 0; + break; + } + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) + enabled = 0; + } + link_state->clk_pm_capable = capable; + link_state->clk_pm_enabled = enabled; + link_state->bios_clk_state = enabled; + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); +} + +/* + * pcie_aspm_configure_common_clock: check if the 2 ends of a link + * could use common clock. If they are, configure them to use the + * common clock. That will reduce the ASPM state exit latency. + */ +static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +{ + int pos, child_pos; + u16 reg16 = 0; + struct pci_dev *child_dev; + int same_clock = 1; + + /* + * all functions of a slot should have the same Slot Clock + * Configuration, so just check one function + * */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + BUG_ON(!child_dev->is_pcie); + + /* Check downstream component if bit Slot Clock Configuration is 1 */ + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Check upstream component if bit Slot Clock Configuration is 1 */ + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Configure downstream component, all functions */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + reg16); + } + + /* Configure upstream component */ + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* retrain link */ + reg16 |= PCI_EXP_LNKCTL_RL; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* Wait for link training end */ + while (1) { + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + break; + cpu_relax(); + } +} + +/* + * calc_L0S_latency: Convert L0s latency encoding to ns + */ +static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 64; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 5*1000; /* > 4us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +/* + * calc_L1_latency: Convert L1 latency encoding to ns + */ +static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 1000; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 65*1000; /* > 64us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, + unsigned int *l0s, unsigned int *l1, unsigned int *enabled) +{ + int pos; + u16 reg16; + u32 reg32; + unsigned int latency; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); + *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; + if (*state != PCIE_LINK_STATE_L0S && + *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + * state = 0; + if (*state == 0) + return; + + latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_L0S_latency(latency, 0); + if (*state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_L1_latency(latency, 0); + } + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); +} + +static void pcie_aspm_cap_init(struct pci_dev *pdev) +{ + struct pci_dev *child_dev; + u32 state, tmp; + struct pcie_link_state *link_state = pdev->link_state; + + /* upstream component states */ + pcie_aspm_get_cap_device(pdev, &link_state->support_state, + &link_state->l0s_upper_latency, + &link_state->l1_upper_latency, + &link_state->enabled_state); + /* downstream component states, all functions have the same setting */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + pcie_aspm_get_cap_device(child_dev, &state, + &link_state->l0s_down_latency, + &link_state->l1_down_latency, + &tmp); + link_state->support_state &= state; + if (!link_state->support_state) + return; + link_state->enabled_state &= link_state->support_state; + link_state->bios_aspm_state = link_state->enabled_state; + + /* ENDPOINT states*/ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + int pos; + u32 reg32; + unsigned int latency; + struct endpoint_state *ep_state = + &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + + if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + continue; + + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); + latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + latency = calc_L0S_latency(latency, 1); + ep_state->l0s_acceptable_latency = latency; + if (link_state->support_state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + latency = calc_L1_latency(latency, 1); + ep_state->l1_acceptable_latency = latency; + } + } +} + +static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *parent_dev, *tmp_dev; + unsigned int latency, l1_latency = 0; + struct pcie_link_state *link_state; + struct endpoint_state *ep_state; + + parent_dev = pdev->bus->self; + link_state = parent_dev->link_state; + state &= link_state->support_state; + if (state == 0) + return 0; + ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + + /* + * Check latency for endpoint device. + * TBD: The latency from the endpoint to root complex vary per + * switch's upstream link state above the device. Here we just do a + * simple check which assumes all links above the device can be in L1 + * state, that is we just consider the worst case. If switch's upstream + * link can't be put into L0S/L1, then our check is too strictly. + */ + tmp_dev = pdev; + while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { + parent_dev = tmp_dev->bus->self; + link_state = parent_dev->link_state; + if (state & PCIE_LINK_STATE_L0S) { + latency = max_t(unsigned int, + link_state->l0s_upper_latency, + link_state->l0s_down_latency); + if (latency > ep_state->l0s_acceptable_latency) + state &= ~PCIE_LINK_STATE_L0S; + } + if (state & PCIE_LINK_STATE_L1) { + latency = max_t(unsigned int, + link_state->l1_upper_latency, + link_state->l1_down_latency); + if (latency + l1_latency > + ep_state->l1_acceptable_latency) + state &= ~PCIE_LINK_STATE_L1; + } + if (!parent_dev->bus->self) /* parent_dev is a root port */ + break; + else { + /* + * parent_dev is the downstream port of a switch, make + * tmp_dev the upstream port of the switch + */ + tmp_dev = parent_dev->bus->self; + /* + * every switch on the path to root complex need 1 more + * microsecond for L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + l1_latency += 1000; + } + } + return state; +} + +static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *child_dev; + + /* If no child, disable the link */ + if (list_empty(&pdev->subordinate->devices)) + return 0; + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + * */ + state = 0; + break; + } + if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + continue; + /* Device not in D0 doesn't need check latency */ + if (child_dev->current_state == PCI_D1 || + child_dev->current_state == PCI_D2 || + child_dev->current_state == PCI_D3hot || + child_dev->current_state == PCI_D3cold) + continue; + state = __pcie_aspm_check_state_one(child_dev, state); + } + return state; +} + +static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) +{ + u16 reg16; + int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~0x3; + reg16 |= state; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); +} + +static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +{ + struct pci_dev *child_dev; + int valid = 1; + struct pcie_link_state *link_state = pdev->link_state; + + /* + * if the downstream component has pci bridge function, don't do ASPM + * now + */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + valid = 0; + break; + } + } + if (!valid) + return; + + /* + * spec 2.0 suggests all functions should be configured the same + * setting for ASPM. Enabling ASPM L1 should be done in upstream + * component first and then downstream, and vice versa for disabling + * ASPM L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + __pcie_aspm_config_one_dev(pdev, state); + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) + __pcie_aspm_config_one_dev(child_dev, state); + + if (!(state & PCIE_LINK_STATE_L1)) + __pcie_aspm_config_one_dev(pdev, state); + + link_state->enabled_state = state; +} + +static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (link_state->support_state == 0) + return; + state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + + /* state 0 means disabling aspm */ + state = pcie_aspm_check_state(pdev, state); + if (link_state->enabled_state == state) + return; + __pcie_aspm_config_link(pdev, state); +} + +/* + * pcie_aspm_configure_link_state: enable/disable PCI express link state + * @pdev: the root port or switch downstream port + */ +static void pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + __pcie_aspm_configure_link_state(pdev, state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +static void free_link_state(struct pci_dev *pdev) +{ + kfree(pdev->link_state); + pdev->link_state = NULL; +} + +/* + * pcie_aspm_init_link_state: Initiate PCI express link state. + * It is called after the pcie and its children devices are scaned. + * @pdev: the root port or switch downstream port + */ +void pcie_aspm_init_link_state(struct pci_dev *pdev) +{ + unsigned int state; + struct pcie_link_state *link_state; + int error = 0; + + if (aspm_disabled || !pdev->is_pcie || pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + if (list_empty(&pdev->subordinate->devices)) + goto out; + + mutex_lock(&aspm_lock); + + link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); + if (!link_state) + goto unlock_out; + pdev->link_state = link_state; + + pcie_aspm_configure_common_clock(pdev); + + pcie_aspm_cap_init(pdev); + + /* config link state to avoid BIOS error */ + state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev)); + __pcie_aspm_config_link(pdev, state); + + pcie_check_clock_pm(pdev); + + link_state->pdev = pdev; + list_add(&link_state->sibiling, &link_list); + +unlock_out: + if (error) + free_link_state(pdev); + mutex_unlock(&aspm_lock); +out: + up_read(&pci_bus_sem); +} + +/* @pdev: the endpoint device */ +void pcie_aspm_exit_link_state(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state = parent->link_state; + + if (aspm_disabled || !pdev->is_pcie || !parent || !link_state) + return; + if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + + /* + * All PCIe functions are in one slot, remove one function will remove + * the the whole slot, so just wait + */ + if (!list_empty(&parent->subordinate->devices)) + goto out; + + /* All functions are removed, so just disable ASPM for the link */ + __pcie_aspm_config_one_dev(parent, 0); + list_del(&link_state->sibiling); + /* Clock PM is for endpoint device */ + + free_link_state(parent); +out: + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +/* @pdev: the root port or switch downstream port */ +void pcie_aspm_pm_state_change(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (aspm_disabled || !pdev->is_pcie || !pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + /* + * devices changed PM state, we should recheck if latency meets all + * functions' requirement + */ + pcie_aspm_configure_link_state(pdev, link_state->enabled_state); +} + +/* + * pci_disable_link_state - disable pci device's link state, so the link will + * never enter specific states + */ +void pci_disable_link_state(struct pci_dev *pdev, int state) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state; + + if (aspm_disabled || !pdev->is_pcie) + return; + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || + pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) + parent = pdev; + if (!parent) + return; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + link_state = parent->link_state; + link_state->support_state &= + ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); + if (state & PCIE_LINK_STATE_CLKPM) + link_state->clk_pm_capable = 0; + + __pcie_aspm_configure_link_state(parent, link_state->enabled_state); + if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) + pcie_set_clock_pm(parent, 0); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} +EXPORT_SYMBOL(pci_disable_link_state); + +static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) +{ + int i; + struct pci_dev *pdev; + struct pcie_link_state *link_state; + + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) + break; + if (i >= ARRAY_SIZE(policy_str)) + return -EINVAL; + if (i == aspm_policy) + return 0; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + aspm_policy = i; + list_for_each_entry(link_state, &link_list, sibiling) { + pdev = link_state->pdev; + __pcie_aspm_configure_link_state(pdev, + policy_to_aspm_state(pdev)); + if (link_state->clk_pm_capable && + link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + + } + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + return 0; +} + +static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp) +{ + int i, cnt = 0; + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (i == aspm_policy) + cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]); + else + cnt += sprintf(buffer + cnt, "%s ", policy_str[i]); + return cnt; +} + +module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy, + NULL, 0644); + +#ifdef CONFIG_PCIEASPM_DEBUG +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->enabled_state); +} + +static ssize_t link_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + if (state >= 0 && state <= 3) { + /* setup link aspm state */ + pcie_aspm_configure_link_state(pci_device, state); + return n; + } + + return -EINVAL; +} + +static ssize_t clk_ctl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->clk_pm_enabled); +} + +static ssize_t clk_ctl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + pcie_set_clock_pm(pci_device, !!state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + + return n; +} + +static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store); +static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store); + +static char power_group[] = "power"; +void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} + +void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} +#endif + +static int __init pcie_aspm_disable(char *str) +{ + aspm_disabled = 1; + return 1; +} + +__setup("pcie_noaspm", pcie_aspm_disable); + +static int __init pcie_aspm_init(void) +{ + if (aspm_disabled) + return 0; + pci_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| + OSC_CLOCK_PWR_CAPABILITY_SUPPORT); + return 0; +} + +fs_initcall(pcie_aspm_init); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index b20a9b81dae2..23d9eb073296 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -192,9 +192,8 @@ static int get_port_device_capability(struct pci_dev *dev) if (reg32 & SLOT_HP_CAPABLE_MASK) services |= PCIE_PORT_SERVICE_HP; } - /* PME Capable */ - pos = pci_find_capability(dev, PCI_CAP_ID_PME); - if (pos) + /* PME Capable - root port capability */ + if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT) services |= PCIE_PORT_SERVICE_PME; pos = PCI_CFG_SPACE_SIZE; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5fd585293e79..8b505bd925aa 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/cpumask.h> +#include <linux/aspm.h> #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -53,7 +54,7 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; b->legacy_io->read = pci_read_legacy_io; b->legacy_io->write = pci_write_legacy_io; - class_device_create_bin_file(&b->class_dev, b->legacy_io); + device_create_bin_file(&b->dev, b->legacy_io); /* Allocated above after the legacy_io struct */ b->legacy_mem = b->legacy_io + 1; @@ -61,15 +62,15 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_mem->size = 1024*1024; b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; b->legacy_mem->mmap = pci_mmap_legacy_mem; - class_device_create_bin_file(&b->class_dev, b->legacy_mem); + device_create_bin_file(&b->dev, b->legacy_mem); } } void pci_remove_legacy_files(struct pci_bus *b) { if (b->legacy_io) { - class_device_remove_bin_file(&b->class_dev, b->legacy_io); - class_device_remove_bin_file(&b->class_dev, b->legacy_mem); + device_remove_bin_file(&b->dev, b->legacy_io); + device_remove_bin_file(&b->dev, b->legacy_mem); kfree(b->legacy_io); /* both are allocated here */ } } @@ -81,26 +82,27 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; } /* * PCI Bus Class Devices */ -static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, +static ssize_t pci_bus_show_cpuaffinity(struct device *dev, + struct device_attribute *attr, char *buf) { int ret; cpumask_t cpumask; - cpumask = pcibus_to_cpumask(to_pci_bus(class_dev)); + cpumask = pcibus_to_cpumask(to_pci_bus(dev)); ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask); if (ret < PAGE_SIZE) buf[ret++] = '\n'; return ret; } -CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); +DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); /* * PCI Bus Class */ -static void release_pcibus_dev(struct class_device *class_dev) +static void release_pcibus_dev(struct device *dev) { - struct pci_bus *pci_bus = to_pci_bus(class_dev); + struct pci_bus *pci_bus = to_pci_bus(dev); if (pci_bus->bridge) put_device(pci_bus->bridge); @@ -109,7 +111,7 @@ static void release_pcibus_dev(struct class_device *class_dev) static struct class pcibus_class = { .name = "pci_bus", - .release = &release_pcibus_dev, + .dev_release = &release_pcibus_dev, }; static int __init pcibus_class_init(void) @@ -392,7 +394,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { struct pci_bus *child; int i; - int retval; /* * Allocate a new bus, and inherit stuff from the parent.. @@ -408,15 +409,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) child->bus_flags = parent->bus_flags; child->bridge = get_device(&bridge->dev); - child->class_dev.class = &pcibus_class; - sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); - retval = class_device_register(&child->class_dev); - if (retval) - goto error_register; - retval = class_device_create_file(&child->class_dev, - &class_device_attr_cpuaffinity); - if (retval) - goto error_file_create; + /* initialize some portions of the bus device, but don't register it + * now as the parent is not properly set up yet. This device will get + * registered later in pci_bus_add_devices() + */ + child->dev.class = &pcibus_class; + sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr); /* * Set up the primary, secondary and subordinate @@ -434,12 +432,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) bridge->subordinate = child; return child; - -error_file_create: - class_device_unregister(&child->class_dev); -error_register: - kfree(child); - return NULL; } struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) @@ -471,8 +463,6 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) } } -unsigned int pci_scan_child_bus(struct pci_bus *bus); - /* * If it's a bridge, configure it and scan the bus behind it. * For CardBus bridges, we don't scan behind as the devices will @@ -641,13 +631,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass (child->number > bus->subordinate) || (child->number < bus->number) || (child->subordinate < bus->number)) { - pr_debug("PCI: Bus #%02x (-#%02x) is %s" + pr_debug("PCI: Bus #%02x (-#%02x) is %s " "hidden behind%s bridge #%02x (-#%02x)\n", child->number, child->subordinate, (bus->number > child->subordinate && bus->subordinate < child->number) ? - "wholly " : " partially", - bus->self->transparent ? " transparent" : " ", + "wholly" : "partially", + bus->self->transparent ? " transparent" : "", bus->number, bus->subordinate); } bus = bus->parent; @@ -971,6 +961,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) return dev; } +EXPORT_SYMBOL(pci_scan_single_device); /** * pci_scan_slot - scan a PCI slot on a bus for devices. @@ -1011,6 +1002,10 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) break; } } + + if (bus->self) + pcie_aspm_init_link_state(bus->self); + return nr; } @@ -1103,32 +1098,27 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge = get_device(dev); - b->class_dev.class = &pcibus_class; - sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus); - error = class_device_register(&b->class_dev); + b->dev.class = &pcibus_class; + b->dev.parent = b->bridge; + sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus); + error = device_register(&b->dev); if (error) goto class_dev_reg_err; - error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity); + error = device_create_file(&b->dev, &dev_attr_cpuaffinity); if (error) - goto class_dev_create_file_err; + goto dev_create_file_err; /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); - error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge"); - if (error) - goto sys_create_link_err; - b->number = b->secondary = bus; b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; return b; -sys_create_link_err: - class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity); -class_dev_create_file_err: - class_device_unregister(&b->class_dev); +dev_create_file_err: + device_unregister(&b->dev); class_dev_reg_err: device_unregister(dev); dev_reg_err: @@ -1140,7 +1130,6 @@ err_out: kfree(b); return NULL; } -EXPORT_SYMBOL_GPL(pci_create_bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) @@ -1159,7 +1148,6 @@ EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); -EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL_GPL(pci_scan_child_bus); #endif diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 716439e25dd2..68aeeb7206de 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/smp_lock.h> #include <linux/capability.h> #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -202,15 +203,18 @@ struct pci_filp_private { int write_combine; }; -static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - const struct proc_dir_entry *dp = PDE(inode); + const struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); struct pci_dev *dev = dp->data; #ifdef HAVE_PCI_MMAP struct pci_filp_private *fpriv = file->private_data; #endif /* HAVE_PCI_MMAP */ int ret = 0; + lock_kernel(); + switch (cmd) { case PCIIOC_CONTROLLER: ret = pci_domain_nr(dev->bus); @@ -239,6 +243,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i break; }; + unlock_kernel(); return ret; } @@ -291,7 +296,7 @@ static const struct file_operations proc_bus_pci_operations = { .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, - .ioctl = proc_bus_pci_ioctl, + .unlocked_ioctl = proc_bus_pci_ioctl, #ifdef HAVE_PCI_MMAP .open = proc_bus_pci_open, .release = proc_bus_pci_release, @@ -370,7 +375,7 @@ static int show_device(struct seq_file *m, void *v) return 0; } -static struct seq_operations proc_bus_pci_devices_op = { +static const struct seq_operations proc_bus_pci_devices_op = { .start = pci_seq_start, .next = pci_seq_next, .stop = pci_seq_stop, @@ -480,7 +485,3 @@ static int __init pci_proc_init(void) __initcall(pci_proc_init); -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_proc_detach_bus); -#endif - diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 72e0bd5d80ac..0a953d43b9a2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/acpi.h> +#include <linux/kallsyms.h> #include "pci.h" /* The Mellanox Tavor device gives false positive parity errors @@ -46,14 +47,14 @@ static void quirk_passive_release(struct pci_dev *dev) while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d)); + dev_err(&d->dev, "PIIX3: Enabling Passive Release\n"); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release); /* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround but VIA don't answer queries. If you happen to have good contacts at VIA @@ -68,20 +69,20 @@ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) { if (!isa_dma_bridge_buggy) { isa_dma_bridge_buggy=1; - printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); + dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n"); } } /* * Its not totally clear which chipsets are the problematic ones * We know 82C586 and 82C596 variants are affected. */ -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs); int pci_pci_problems; EXPORT_SYMBOL(pci_pci_problems); @@ -92,12 +93,12 @@ EXPORT_SYMBOL(pci_pci_problems); static void __devinit quirk_nopcipci(struct pci_dev *dev) { if ((pci_pci_problems & PCIPCI_FAIL)==0) { - printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_FAIL; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci); static void __devinit quirk_nopciamd(struct pci_dev *dev) { @@ -105,11 +106,11 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev) pci_read_config_byte(dev, 0x08, &rev); if (rev == 0x13) { /* Erratum 24 */ - printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n"); + dev_info(&dev->dev, "Chipset erratum: Disabling direct PCI/AGP transfers\n"); pci_pci_problems |= PCIAGP_FAIL; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd); /* * Triton requires workarounds to be used by the drivers @@ -117,14 +118,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopci static void __devinit quirk_triton(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_TRITON)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_TRITON; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton); /* * VIA Apollo KT133 needs PCI latency patch @@ -139,25 +140,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir static void quirk_vialatency(struct pci_dev *dev) { struct pci_dev *p; - u8 rev; u8 busarb; /* Ok we have a potential problem chipset here. Now see if we have a buggy southbridge */ p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); if (p!=NULL) { - pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ /* Check for buggy part revisions */ - if (rev < 0x40 || rev > 0x42) + if (p->revision < 0x40 || p->revision > 0x42) goto exit; } else { p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); if (p==NULL) /* No problem parts */ goto exit; - pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); /* Check for buggy part revisions */ - if (rev < 0x10 || rev > 0x12) + if (p->revision < 0x10 || p->revision > 0x12) goto exit; } @@ -180,17 +178,17 @@ static void quirk_vialatency(struct pci_dev *dev) busarb &= ~(1<<5); busarb |= (1<<4); pci_write_config_byte(dev, 0x76, busarb); - printk(KERN_INFO "Applying VIA southbridge workaround.\n"); + dev_info(&dev->dev, "Applying VIA southbridge workaround\n"); exit: pci_dev_put(p); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency); /* Must restore this on a resume from RAM */ -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency); /* * VIA Apollo VP3 needs ETBF on BT848/878 @@ -198,20 +196,20 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_viala static void __devinit quirk_viaetbf(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VIAETBF; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf); static void __devinit quirk_vsfx(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VSFX)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VSFX; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx); /* * Ali Magik requires workarounds to be used by the drivers @@ -222,12 +220,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx static void __init quirk_alimagik(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik); /* * Natoma has some interesting boundary conditions with Zoran stuff @@ -236,16 +234,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimag static void __devinit quirk_natoma(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_NATOMA)==0) { - printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_NATOMA; } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma); /* * This chip can cause PCI parity errors if config register 0xA0 is read @@ -255,7 +253,7 @@ static void __devinit quirk_citrine(struct pci_dev *dev) { dev->cfg_size = 0xA0; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine); /* * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. @@ -270,8 +268,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev) r->end = 0x3ffffff; } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr, const char *name) @@ -292,7 +290,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, pcibios_bus_to_resource(dev, res, &bus_region); pci_claim_resource(dev, nr); - printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); + dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); } } @@ -302,12 +300,12 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, */ static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) { - printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n"); + dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n"); /* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */ request_region(0x3b0, 0x0C, "RadeonIGP"); request_region(0x3d3, 0x01, "RadeonIGP"); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce); /* * Let's make the southbridge information explicit instead @@ -329,7 +327,7 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) pci_read_config_word(dev, 0xE2, ®ion); quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi); static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) { @@ -354,7 +352,7 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p * let's get enough confirmation reports first. */ base &= -size; - printk("%s PIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1); } static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) @@ -379,7 +377,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int * reserve it, but let's get enough confirmation reports first. */ base &= -size; - printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1); } /* @@ -418,8 +416,8 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20); piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi); /* * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at @@ -436,16 +434,16 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x58, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi); static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) { @@ -457,20 +455,20 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x48, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi); /* * VIA ACPI: One IO region pointed to by longword at @@ -486,7 +484,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi); /* * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at @@ -509,7 +507,7 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) smb &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi); /* * VIA VT8235 ISA Bridge: Two IO regions pointed to by words at @@ -551,14 +549,14 @@ static void quirk_via_ioapic(struct pci_dev *dev) else tmp = 0x1f; /* all known bits (4-0) routed to external APIC */ - printk(KERN_INFO "PCI: %sbling Via external APIC routing\n", + dev_info(&dev->dev, "%sbling VIA external APIC routing\n", tmp == 0 ? "Disa" : "Ena"); /* Offset 0x58: External APIC IRQ output control */ pci_write_config_byte (dev, 0x58, tmp); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); /* * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit. @@ -573,7 +571,7 @@ static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev) pci_read_config_byte(dev, 0x5B, &misc_control2); if (!(misc_control2 & BYPASS_APIC_DEASSERT)) { - printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n"); + dev_info(&dev->dev, "Bypassing VIA 8237 APIC De-Assert Message\n"); pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT); } } @@ -592,18 +590,18 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_v static void __devinit quirk_amd_ioapic(struct pci_dev *dev) { if (dev->revision >= 0x02) { - printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); - printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); + dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); + dev_warn(&dev->dev, " : booting with the \"noapic\" option\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic); static void __init quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); #define AMD8131_revA0 0x01 #define AMD8131_revB0 0x11 @@ -617,7 +615,7 @@ static void quirk_amd_8131_ioapic(struct pci_dev *dev) return; if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) { - printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); + dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n"); pci_read_config_byte( dev, AMD8131_MISC, &tmp); tmp &= ~(1 << AMD8131_NIOAMODE_BIT); pci_write_config_byte( dev, AMD8131_MISC, tmp); @@ -634,8 +632,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) { if (dev->subordinate && dev->revision <= 0x12) { - printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X " - "MMRBC\n", dev->revision); + dev_info(&dev->dev, "AMD8131 rev %x detected; " + "disabling PCI-X MMRBC\n", dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } @@ -660,8 +658,8 @@ static void __devinit quirk_via_acpi(struct pci_dev *d) if (irq && (irq != 2)) d->irq = irq; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi); /* @@ -742,8 +740,8 @@ static void quirk_via_vlink(struct pci_dev *dev) pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { - printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n", - pci_name(dev), irq, new_irq); + dev_info(&dev->dev, "VIA VLink IRQ fixup, from %d to %d\n", + irq, new_irq); udelay(15); /* unknown if delay really needed */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } @@ -761,7 +759,7 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev) pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id); /* * CardBus controllers have a legacy base address that enables them @@ -791,15 +789,15 @@ static void quirk_amd_ordering(struct pci_dev *dev) pci_read_config_dword(dev, 0x4C, &pcic); if ((pcic&6)!=6) { pcic |= 6; - printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n"); + dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n"); pci_write_config_dword(dev, 0x4C, pcic); pci_read_config_dword(dev, 0x84, &pcic); pcic |= (1<<23); /* Required in this mode */ pci_write_config_dword(dev, 0x84, pcic); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering); /* * DreamWorks provided workaround for Dunord I-3000 problem @@ -814,7 +812,7 @@ static void __devinit quirk_dunord ( struct pci_dev * dev ) r->start = 0; r->end = 0xffffff; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord); /* * i82380FB mobile docking controller: its PCI-to-PCI bridge @@ -826,8 +824,8 @@ static void __devinit quirk_transparent_bridge(struct pci_dev *dev) { dev->transparent = 1; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge); /* * Common misconfiguration of the MediaGX/Geode PCI master that will @@ -841,12 +839,12 @@ static void quirk_mediagx_master(struct pci_dev *dev) pci_read_config_byte(dev, 0x41, ®); if (reg & 2) { reg &= ~2; - printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); + dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); pci_write_config_byte(dev, 0x41, reg); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master); /* * Ensure C0 rev restreaming is off. This is normally done by @@ -863,11 +861,11 @@ static void quirk_disable_pxb(struct pci_dev *pdev) if (config & (1<<6)) { config &= ~(1<<6); pci_write_config_word(pdev, 0x40, config); - printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n"); + dev_info(&pdev->dev, "C0 revision 450NX. Disabling PCI restreaming\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); static void __devinit quirk_sb600_sata(struct pci_dev *pdev) @@ -902,7 +900,7 @@ static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev) /* PCI layer will sort out resources */ } } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide ); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide); /* * Intel 82801CAM ICH3-M datasheet says IDE modes must be the same @@ -914,7 +912,7 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev) pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) { - printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n"); + dev_info(&pdev->dev, "IDE mode mismatch; forcing legacy mode\n"); prog &= ~5; pdev->class &= ~5; pci_write_config_byte(pdev, PCI_CLASS_PROG, prog); @@ -929,7 +927,7 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge); /* @@ -1022,6 +1020,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } + else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB) + switch (dev->subsystem_device) { + case 0x12bf: /* HP xw4100 */ + asus_hides_smbus = 1; + } else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x099c: /* HP Compaq nx6110 */ @@ -1049,17 +1052,18 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) } } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge); static void asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -1073,25 +1077,25 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev) pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); if (val & 0x8) - printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); else - printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); + dev_info(&dev->dev, "Enabled i801 SMBus device\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc); static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { @@ -1106,10 +1110,10 @@ static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev) val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */ writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */ iounmap(base); - printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n"); + dev_info(&dev->dev, "Enabled ICH6/i801 SMBus device\n"); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6); /* * SiS 96x south bridge: BIOS typically hides SMBus device... @@ -1119,18 +1123,18 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev) u8 val = 0; pci_read_config_byte(dev, 0x77, &val); if (val & 0x10) { - printk(KERN_INFO "Enabling SiS 96x SMBus.\n"); + dev_info(&dev->dev, "Enabling SiS 96x SMBus\n"); pci_write_config_byte(dev, 0x77, val & ~0x10); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus); /* * ... This is further complicated by the fact that some SiS96x south @@ -1163,8 +1167,8 @@ static void quirk_sis_503(struct pci_dev *dev) dev->device = devid; quirk_sis_96x_smbus(dev); } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503); /* @@ -1191,13 +1195,13 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev) pci_write_config_byte(dev, 0x50, val & (~0xc0)); pci_read_config_byte(dev, 0x50, &val); if (val & 0xc0) - printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); else - printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n"); + dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc); #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) @@ -1292,7 +1296,7 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev) } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif int pcie_mch_quirk; @@ -1302,9 +1306,9 @@ static void __devinit quirk_pcie_mch(struct pci_dev *pdev) { pcie_mch_quirk = 1; } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch); /* @@ -1314,11 +1318,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir static void __devinit quirk_pcie_pxh(struct pci_dev *dev) { pci_msi_off(dev); - dev->no_msi = 1; - - printk(KERN_WARNING "PCI: PXH quirk detected, " - "disabling MSI for SHPC device\n"); + dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n"); } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_0, quirk_pcie_pxh); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_1, quirk_pcie_pxh); @@ -1399,7 +1400,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev) case PCI_DEVICE_ID_NETMOS_9855: if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL && num_parallel) { - printk(KERN_INFO "PCI: Netmos %04x (%u parallel, " + dev_info(&dev->dev, "Netmos %04x (%u parallel, " "%u serial); changing class SERIAL to OTHER " "(use parport_serial)\n", dev->device, num_parallel, num_serial); @@ -1412,9 +1413,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos); static void __devinit quirk_e100_interrupt(struct pci_dev *dev) { - u16 command; + u16 command, pmcsr; u8 __iomem *csr; u8 cmd_hi; + int pm; switch (dev->device) { /* PCI IDs taken from drivers/net/e100.c */ @@ -1448,18 +1450,28 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev) if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0)) return; + /* + * Check that the device is in the D0 power state. If it's not, + * there is no point to look any further. + */ + pm = pci_find_capability(dev, PCI_CAP_ID_PM); + if (pm) { + pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) + return; + } + /* Convert from PCI bus to resource space. */ csr = ioremap(pci_resource_start(dev, 0), 8); if (!csr) { - printk(KERN_WARNING "PCI: Can't map %s e100 registers\n", - pci_name(dev)); + dev_warn(&dev->dev, "Can't map e100 registers\n"); return; } cmd_hi = readb(csr + 3); if (cmd_hi == 0) { - printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts " - "enabled, disabling\n", pci_name(dev)); + dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; " + "disabling\n"); writeb(1, csr + 3); } @@ -1474,7 +1486,7 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) */ if (dev->class == PCI_CLASS_NOT_DEFINED) { - printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n"); + dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n"); dev->class = PCI_CLASS_STORAGE_SCSI; } } @@ -1485,7 +1497,11 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f while (f < end) { if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { - pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); +#ifdef DEBUG + dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook); + print_fn_descriptor_symbol(": %s()\n", + (unsigned long) f->hook); +#endif f->hook(dev); } f++; @@ -1553,7 +1569,7 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) pci_read_config_word(dev, 0x40, &en1k); if (en1k & 0x200) { - printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n"); + dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n"); pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); @@ -1585,7 +1601,7 @@ static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev) iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00); if (iobl_adr != iobl_adr_1k) { - printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n", + dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n", iobl_adr,iobl_adr_1k); pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k); } @@ -1603,9 +1619,8 @@ static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) if (pci_read_config_byte(dev, 0xf41, &b) == 0) { if (!(b & 0x20)) { pci_write_config_byte(dev, 0xf41, b | 0x20); - printk(KERN_INFO - "PCI: Linking AER extended capability on %s\n", - pci_name(dev)); + dev_info(&dev->dev, + "Linking AER extended capability\n"); } } } @@ -1614,6 +1629,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_pcie_aer_ext_cap); +static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) +{ + /* + * Disable PCI Bus Parking and PCI Master read caching on CX700 + * which causes unspecified timing errors with a VT6212L on the PCI + * bus leading to USB2.0 packet loss. The defaults are that these + * features are turned off but some BIOSes turn them on. + */ + + uint8_t b; + if (pci_read_config_byte(dev, 0x76, &b) == 0) { + if (b & 0x40) { + /* Turn off PCI Bus Parking */ + pci_write_config_byte(dev, 0x76, b ^ 0x40); + + /* Turn off PCI Master read caching */ + pci_write_config_byte(dev, 0x72, 0x0); + pci_write_config_byte(dev, 0x75, 0x1); + pci_write_config_byte(dev, 0x77, 0x0); + + printk(KERN_INFO + "PCI: VIA CX700 PCI parking/caching fixup on %s\n", + pci_name(dev)); + } + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); + #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually @@ -1624,7 +1667,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, static void __init quirk_disable_all_msi(struct pci_dev *dev) { pci_no_msi(); - printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n"); + dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n"); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi); @@ -1635,9 +1678,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab static void __devinit quirk_disable_msi(struct pci_dev *dev) { if (dev->subordinate) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } @@ -1656,9 +1698,9 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { - printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n", + dev_info(&dev->dev, "Found %s HT MSI Mapping\n", flags & HT_MSI_FLAGS_ENABLE ? - "enabled" : "disabled", pci_name(dev)); + "enabled" : "disabled"); return (flags & HT_MSI_FLAGS_ENABLE) != 0; } @@ -1672,17 +1714,40 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) static void __devinit quirk_msi_ht_cap(struct pci_dev *dev) { if (dev->subordinate && !msi_ht_cap_enabled(dev)) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "MSI disabled on chipset %s.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE, quirk_msi_ht_cap); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, - quirk_msi_ht_cap); + + +/* + * Force enable MSI mapping capability on HT bridges + */ +static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) +{ + int pos, ttl = 48; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { + printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n", + pci_name(dev)); + + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags | HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, + quirk_msi_ht_cap_enable); /* The nVidia CK804 chipset may have 2 HT MSI mappings. * MSI are supported if the MSI capability set in any of these mappings. @@ -1701,9 +1766,8 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) if (!pdev) return; if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { - printk(KERN_WARNING "PCI: MSI quirk detected. " - "MSI disabled on chipset %s.\n", - pci_name(dev)); + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } pci_dev_put(pdev); @@ -1715,6 +1779,23 @@ static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) { dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; } +static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev) +{ + struct pci_dev *p; + + /* SB700 MSI issue will be fixed at HW level from revision A21, + * we need check PCI REVISION ID of SMBus controller to get SB700 + * revision. + */ + p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, + NULL); + if (!p) + return; + + if ((p->revision < 0x3B) && (p->revision >= 0x30)) + dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; + pci_dev_put(p); +} DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, quirk_msi_intx_disable_bug); @@ -1735,17 +1816,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, quirk_msi_intx_disable_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394, - quirk_msi_intx_disable_bug); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373, quirk_msi_intx_disable_bug); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 430281b2e921..ec4a82ba29a8 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -1,5 +1,6 @@ #include <linux/pci.h> #include <linux/module.h> +#include <linux/aspm.h> #include "pci.h" static void pci_free_resources(struct pci_dev *dev) @@ -30,6 +31,9 @@ static void pci_stop_dev(struct pci_dev *dev) dev->global_list.next = dev->global_list.prev = NULL; up_write(&pci_bus_sem); } + + if (dev->bus->self) + pcie_aspm_exit_link_state(dev); } static void pci_destroy_dev(struct pci_dev *dev) @@ -74,10 +78,8 @@ void pci_remove_bus(struct pci_bus *pci_bus) list_del(&pci_bus->node); up_write(&pci_bus_sem); pci_remove_legacy_files(pci_bus); - class_device_remove_file(&pci_bus->class_dev, - &class_device_attr_cpuaffinity); - sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge"); - class_device_unregister(&pci_bus->class_dev); + device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity); + device_unregister(&pci_bus->dev); } EXPORT_SYMBOL(pci_remove_bus); diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index dbbcc04abd1a..a98b2470b9ea 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -162,6 +162,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) return rom; } +#if 0 /** * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy * @pdev: pointer to pci device struct @@ -196,6 +197,7 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) return (void __iomem *)(unsigned long)res->start; } +#endif /* 0 */ /** * pci_unmap_rom - unmap the ROM from kernel space @@ -218,6 +220,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) pci_disable_rom(pdev); } +#if 0 /** * pci_remove_rom - disable the ROM and remove its sysfs attribute * @pdev: pointer to pci device struct @@ -236,6 +239,7 @@ void pci_remove_rom(struct pci_dev *pdev) IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); } +#endif /* 0 */ /** * pci_cleanup_rom - internal routine for freeing the ROM copy created @@ -256,6 +260,4 @@ void pci_cleanup_rom(struct pci_dev *pdev) } EXPORT_SYMBOL(pci_map_rom); -EXPORT_SYMBOL(pci_map_rom_copy); EXPORT_SYMBOL(pci_unmap_rom); -EXPORT_SYMBOL(pci_remove_rom); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 401e03c920bd..8a7232feb553 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *bus) * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. */ - printk(" IO window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, @@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); if (bus->resource[1]->flags & IORESOURCE_IO) { - printk(" IO window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, @@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_MEM) { - printk(" PREFETCH window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " PREFETCH window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, @@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *bus) pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); if (bus->resource[3]->flags & IORESOURCE_MEM) { - printk(" MEM window: %08lx-%08lx\n", - region.start, region.end); + printk(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, @@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; struct pci_bus_region region; - u32 l, io_upper16; + u32 l, bu, lu, io_upper16; DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge)); @@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus) /* Set up upper 16 bits of I/O base/limit. */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); DBG(KERN_INFO " IO window: %04lx-%04lx\n", - region.start, region.end); + (unsigned long)region.start, + (unsigned long)region.end); } else { /* Clear upper 16 bits of I/O base/limit. */ @@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus) if (bus->resource[1]->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - DBG(KERN_INFO " MEM window: %08lx-%08lx\n", - region.start, region.end); + DBG(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n", + (unsigned long)region.start, + (unsigned long)region.end); } else { l = 0x0000fff0; @@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ + bu = lu = 0; pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n", - region.start, region.end); +#ifdef CONFIG_RESOURCES_64BIT + bu = region.start >> 32; + lu = region.end >> 32; +#endif + DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n", + (unsigned long long)region.start, + (unsigned long long)region.end); } else { l = 0x0000fff0; @@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus) } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - /* Clear out the upper 32 bits of PREF base. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus *bus) static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) { struct pci_dev *dev; - unsigned long min_align, align, size; - unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */ + resource_size_t min_align, align, size; + resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); @@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; - unsigned long r_size; + resource_size_t r_size; if (r->parent || (r->flags & mask) != type) continue; @@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long order = __ffs(align) - 20; if (order > 11) { printk(KERN_WARNING "PCI: region %s/%d " - "too large: %llx-%llx\n", + "too large: 0x%016llx-0x%016llx\n", pci_name(dev), i, - (unsigned long long)r->start, - (unsigned long long)r->end); + (unsigned long long)r->start, + (unsigned long long)r->end); r->flags = 0; continue; } @@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long align = 0; min_align = 0; for (order = 0; order <= max_order; order++) { - unsigned long align1 = 1UL << (order + 20); - +#ifdef CONFIG_RESOURCES_64BIT + resource_size_t align1 = 1ULL << (order + 20); +#else + resource_size_t align1 = 1U << (order + 20); +#endif if (!align) min_align = align1; else if (ALIGN(align + min_align, min_align) < align1) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 6dfd86167e39..4be7ccf7e3ae 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) pcibios_resource_to_bus(dev, ®ion, res); - pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for " + pr_debug(" got res [%llx:%llx] bus [%llx:%llx] flags %lx for " "BAR %d of %s\n", (unsigned long long)res->start, (unsigned long long)res->end, - region.start, region.end, res->flags, resno, pci_name(dev)); + (unsigned long long)region.start, + (unsigned long long)region.end, + (unsigned long)res->flags, resno, pci_name(dev)); new = region.start | (res->flags & PCI_REGION_FLAG_MASK); if (res->flags & IORESOURCE_IO) @@ -125,7 +127,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return err; } -EXPORT_SYMBOL_GPL(pci_claim_resource); int pci_assign_resource(struct pci_dev *dev, int resno) { diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 2ac050d7f8cf..645d7a60e412 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -34,7 +34,6 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, if (!dev) goto error; - lock_kernel(); switch (len) { case 1: cfg_ret = pci_user_read_config_byte(dev, off, &byte); @@ -47,10 +46,8 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, break; default: err = -EINVAL; - unlock_kernel(); goto error; }; - unlock_kernel(); err = -EIO; if (cfg_ret != PCIBIOS_SUCCESSFUL) @@ -107,7 +104,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, if (!dev) return -ENODEV; - lock_kernel(); switch(len) { case 1: err = get_user(byte, (u8 __user *)buf); @@ -140,7 +136,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = -EINVAL; break; } - unlock_kernel(); pci_dev_put(dev); return err; } diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index db8bc20539e1..5ed00069846d 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -1,7 +1,6 @@ /* - * linux/drivers/scsi/ide-scsi.c Version 0.9 Jul 4, 1999 - * - * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 2004-2005 Bartlomiej Zolnierkiewicz */ /* diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3205f7488d1c..29b4cf9e059b 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2296,10 +2296,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; struct lpfc_sli *psli = &phba->sli; - int bars = pci_select_bars(pdev, IORESOURCE_MEM); dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); - if (pci_enable_device_bars(pdev, bars)) { + if (pci_enable_device_mem(pdev)) { printk(KERN_ERR "lpfc: Cannot re-enable " "PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6f129da37589..b72c7f170854 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2268,6 +2268,7 @@ typedef struct scsi_qla_host { spinlock_t hardware_lock ____cacheline_aligned; int bars; + int mem_only; device_reg_t __iomem *iobase; /* Base I/O address */ resource_size_t pio_address; #define MIN_IOBASE_LEN 0x100 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3954ed2d7b51..8f69caf83272 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1564,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; - int bars; + int bars, mem_only = 0; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); sht = &qla2x00_driver_template; @@ -1575,10 +1575,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { bars = pci_select_bars(pdev, IORESOURCE_MEM); sht = &qla24xx_driver_template; + mem_only = 1; } - if (pci_enable_device_bars(pdev, bars)) - goto probe_out; + if (mem_only) { + if (pci_enable_device_mem(pdev)) + goto probe_out; + } else { + if (pci_enable_device(pdev)) + goto probe_out; + } if (pci_find_aer_capability(pdev)) if (pci_enable_pcie_error_reporting(pdev)) @@ -1601,6 +1607,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no); ha->parent = NULL; ha->bars = bars; + ha->mem_only = mem_only; /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); @@ -2875,8 +2882,14 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) { pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; scsi_qla_host_t *ha = pci_get_drvdata(pdev); + int rc; + + if (ha->mem_only) + rc = pci_enable_device_mem(pdev); + else + rc = pci_enable_device(pdev); - if (pci_enable_device_bars(pdev, ha->bars)) { + if (rc) { qla_printk(KERN_WARNING, ha, "Can't re-enable PCI device after reset.\n"); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7a6499008b89..755823cdf62a 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -42,6 +42,10 @@ config USB_ARCH_HAS_OHCI default y if PPC_MPC52xx # MIPS: default y if SOC_AU1X00 + # SH: + default y if CPU_SUBTYPE_SH7720 + default y if CPU_SUBTYPE_SH7721 + default y if CPU_SUBTYPE_SH7763 # more: default PCI @@ -50,6 +54,7 @@ config USB_ARCH_HAS_EHCI boolean default y if PPC_83xx default y if SOC_AU1200 + default y if ARCH_IXP4XX default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index b450cbaa3a0b..86e64035edb0 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -2,10 +2,7 @@ # USB/ATM DSL configuration # -menu "USB DSL modem support" - depends on USB - -config USB_ATM +menuconfig USB_ATM tristate "USB DSL modem support" depends on USB && ATM select CRC32 @@ -18,6 +15,8 @@ config USB_ATM To compile this driver as a module, choose M here: the module will be called usbatm. +if USB_ATM + config USB_SPEEDTOUCH tristate "Speedtouch USB support" depends on USB_ATM @@ -70,4 +69,4 @@ config USB_XUSBATM To compile this driver as a module, choose M here: the module will be called xusbatm. -endmenu +endif # USB_ATM diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 389c5b164eb2..c5ec1a55eee3 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -999,7 +999,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) bi.dwAddress = swab32(blockidx->PageAddress); uea_dbg(INS_TO_USBDEV(sc), - "sending block %u for DSP page %u size %u adress %x\n", + "sending block %u for DSP page %u size %u address %x\n", blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); /* send block info through the IDMA pipe */ @@ -1990,7 +1990,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) return; bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " "Function : %d, Subfunction : %d\n", E1_FUNCTION_TYPE(cmv->bFunction), E1_FUNCTION_SUBTYPE(cmv->bFunction)); @@ -2038,7 +2038,7 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) return; bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " "Function : %d, Subfunction : %d\n", E4_FUNCTION_TYPE(cmv->wFunction), E4_FUNCTION_SUBTYPE(cmv->wFunction)); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 912d97aaf9bf..bcc42136c93f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) otherwise it is scheduled, and with high data rates data can get lost. */ tty->low_latency = 1; + if (usb_autopm_get_interface(acm->control)) { + mutex_unlock(&open_mutex); + return -EIO; + } + + mutex_lock(&acm->mutex); + mutex_unlock(&open_mutex); if (acm->used++) { + usb_autopm_put_interface(acm->control); goto done; } + acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dbg("usb_submit_urb(ctrl irq) failed"); @@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) done: err_out: - mutex_unlock(&open_mutex); + mutex_unlock(&acm->mutex); return rv; full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: + usb_autopm_put_interface(acm->control); acm->used--; - mutex_unlock(&open_mutex); + mutex_unlock(&acm->mutex); return -EIO; } @@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->writeurb); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); + usb_autopm_put_interface(acm->control); } else acm_tty_unregister(acm); } @@ -904,7 +915,7 @@ next_desc: } if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); + dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); skip_normal_probe: @@ -980,6 +991,7 @@ skip_normal_probe: spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); + mutex_init(&acm->mutex); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); @@ -1096,6 +1108,25 @@ alloc_fail: return -ENOMEM; } +static void stop_data_traffic(struct acm *acm) +{ + int i; + + tasklet_disable(&acm->urb_task); + + usb_kill_urb(acm->ctrlurb); + usb_kill_urb(acm->writeurb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->ru[i].urb); + + INIT_LIST_HEAD(&acm->filled_read_bufs); + INIT_LIST_HEAD(&acm->spare_read_bufs); + + tasklet_enable(&acm->urb_task); + + cancel_work_sync(&acm->work); +} + static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); @@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); - tasklet_disable(&acm->urb_task); - - usb_kill_urb(acm->ctrlurb); - usb_kill_urb(acm->writeurb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->ru[i].urb); - - INIT_LIST_HEAD(&acm->filled_read_bufs); - INIT_LIST_HEAD(&acm->spare_read_bufs); - - tasklet_enable(&acm->urb_task); - - flush_scheduled_work(); /* wait for acm_softint */ + stop_data_traffic(acm); acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); @@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf) tty_hangup(acm->tty); } +static int acm_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct acm *acm = usb_get_intfdata(intf); + + if (acm->susp_count++) + return 0; + /* + we treat opened interfaces differently, + we must guard against open + */ + mutex_lock(&acm->mutex); + + if (acm->used) + stop_data_traffic(acm); + + mutex_unlock(&acm->mutex); + return 0; +} + +static int acm_resume(struct usb_interface *intf) +{ + struct acm *acm = usb_get_intfdata(intf); + int rv = 0; + + if (--acm->susp_count) + return 0; + + mutex_lock(&acm->mutex); + if (acm->used) { + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); + if (rv < 0) + goto err_out; + + tasklet_schedule(&acm->urb_task); + } + +err_out: + mutex_unlock(&acm->mutex); + return rv; +} /* * USB driver structure. */ @@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, + .suspend = acm_suspend, + .resume = acm_resume, .id_table = acm_ids, + .supports_autosuspend = 1, }; /* diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 09f7765dbf8d..8df6a57dcf9e 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -107,6 +107,7 @@ struct acm { int write_used; /* number of non-empty write buffers */ int write_ready; /* write urb is not running */ spinlock_t write_lock; + struct mutex mutex; struct usb_cdc_line_coding line; /* bits, stop, parity */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct urb_task; /* rx processing */ @@ -120,6 +121,7 @@ struct acm { unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ + unsigned int susp_count; /* number of suspended interfaces */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 97b09f282705..5c33cdb9cac7 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -9,6 +9,21 @@ config USB_DEBUG of debug messages to the system log. Select this if you are having a problem with USB support and want to see more of what is going on. +config USB_ANNOUNCE_NEW_DEVICES + bool "USB announce new devices" + depends on USB + default N + help + Say Y here if you want the USB core to always announce the + idVendor, idProduct, Manufacturer, Product, and SerialNumber + strings for every new USB device to the syslog. This option is + usually used by distro vendors to help with debugging and to + let users know what specific device was added to the machine + in what location. + + If you do not want this kind of information sent to the system + log, or have any doubts about this, say N here. + comment "Miscellaneous USB options" depends on USB diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 28d4972f7ad5..cadb2dc1d28a 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -53,11 +53,13 @@ int hcd_buffer_create(struct usb_hcd *hcd) char name[16]; int i, size; - if (!hcd->self.controller->dma_mask) + if (!hcd->self.controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) return 0; - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - if (!(size = pool_max [i])) + for (i = 0; i < HCD_BUFFER_POOLS; i++) { + size = pool_max[i]; + if (!size) continue; snprintf(name, sizeof name, "buffer-%d", size); hcd->pool[i] = dma_pool_create(name, hcd->self.controller, @@ -80,10 +82,10 @@ int hcd_buffer_create(struct usb_hcd *hcd) */ void hcd_buffer_destroy(struct usb_hcd *hcd) { - int i; + int i; - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool[i]; + for (i = 0; i < HCD_BUFFER_POOLS; i++) { + struct dma_pool *pool = hcd->pool[i]; if (pool) { dma_pool_destroy(pool); hcd->pool[i] = NULL; @@ -107,7 +109,8 @@ void *hcd_buffer_alloc( int i; /* some USB hosts just use PIO */ - if (!bus->controller->dma_mask) { + if (!bus->controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) { *dma = ~(dma_addr_t) 0; return kmalloc(size, mem_flags); } @@ -132,7 +135,8 @@ void hcd_buffer_free( if (!addr) return; - if (!bus->controller->dma_mask) { + if (!bus->controller->dma_mask && + !(hcd->driver->flags & HCD_LOCAL_MEM)) { kfree(addr); return; } diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 1a8edcee7f30..a92122a216bc 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -238,7 +238,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno, /* Allocate space for the right(?) number of endpoints */ num_ep = num_ep_orig = alt->desc.bNumEndpoints; - alt->desc.bNumEndpoints = 0; // Use as a counter + alt->desc.bNumEndpoints = 0; /* Use as a counter */ if (num_ep > USB_MAXENDPOINTS) { dev_warn(ddev, "too many endpoints for config %d interface %d " "altsetting %d: %d, using maximum allowed: %d\n", @@ -246,7 +246,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, num_ep = USB_MAXENDPOINTS; } - if (num_ep > 0) { /* Can't allocate 0 bytes */ + if (num_ep > 0) { + /* Can't allocate 0 bytes */ len = sizeof(struct usb_host_endpoint) * num_ep; alt->endpoint = kzalloc(len, GFP_KERNEL); if (!alt->endpoint) @@ -475,8 +476,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, return 0; } -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally on disconnect/destroy path +/* hub-only!! ... and only exported for reset/reinit path. + * otherwise used internally on disconnect/destroy path + */ void usb_destroy_configuration(struct usb_device *dev) { int c, i; @@ -498,7 +500,7 @@ void usb_destroy_configuration(struct usb_device *dev) kfree(cf->string); for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) - kref_put(&cf->intf_cache[i]->ref, + kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); } } @@ -525,7 +527,7 @@ int usb_get_configuration(struct usb_device *dev) unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; - struct usb_config_descriptor *desc; + struct usb_config_descriptor *desc; cfgno = 0; if (dev->authorized == 0) /* Not really an error */ diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 87c794d60aa0..83d9dc379d96 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -89,7 +89,7 @@ static const char *format_string_serialnumber = static const char *format_bandwidth = /* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */ "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n"; - + static const char *format_device1 = /* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */ "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n"; @@ -101,7 +101,7 @@ static const char *format_device2 = static const char *format_config = /* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */ "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n"; - + static const char *format_iad = /* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */ "A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; @@ -122,7 +122,7 @@ static const char *format_endpt = */ static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); -static unsigned int conndiscevcnt = 0; +static unsigned int conndiscevcnt; /* this struct stores the poll state for <mountpoint>/devices pollers */ struct usb_device_status { @@ -172,12 +172,8 @@ static const char *class_decode(const int class) return clas_info[ix].class_name; } -static char *usb_dump_endpoint_descriptor( - int speed, - char *start, - char *end, - const struct usb_endpoint_descriptor *desc -) +static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, + const struct usb_endpoint_descriptor *desc) { char dir, unit, *type; unsigned interval, bandwidth = 1; @@ -235,22 +231,24 @@ static char *usb_dump_endpoint_descriptor( start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, desc->bmAttributes, type, - (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * bandwidth, + (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * + bandwidth, interval, unit); return start; } static char *usb_dump_interface_descriptor(char *start, char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, - int setno) + const struct usb_interface_cache *intfc, + const struct usb_interface *iface, + int setno) { - const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; + const struct usb_interface_descriptor *desc; const char *driver_name = ""; int active = 0; if (start > end) return start; + desc = &intfc->altsetting[setno].desc; if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name @@ -270,14 +268,10 @@ static char *usb_dump_interface_descriptor(char *start, char *end, return start; } -static char *usb_dump_interface( - int speed, - char *start, - char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, - int setno -) { +static char *usb_dump_interface(int speed, char *start, char *end, + const struct usb_interface_cache *intfc, + const struct usb_interface *iface, int setno) +{ const struct usb_host_interface *desc = &intfc->altsetting[setno]; int i; @@ -292,7 +286,7 @@ static char *usb_dump_interface( } static char *usb_dump_iad_descriptor(char *start, char *end, - const struct usb_interface_assoc_descriptor *iad) + const struct usb_interface_assoc_descriptor *iad) { if (start > end) return start; @@ -311,13 +305,15 @@ static char *usb_dump_iad_descriptor(char *start, char *end, * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) */ - -static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) +static char *usb_dump_config_descriptor(char *start, char *end, + const struct usb_config_descriptor *desc, + int active) { if (start > end) return start; start += sprintf(start, format_config, - active ? '*' : ' ', /* mark active/actual/current cfg. */ + /* mark active/actual/current cfg. */ + active ? '*' : ' ', desc->bNumInterfaces, desc->bConfigurationValue, desc->bmAttributes, @@ -325,13 +321,8 @@ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb return start; } -static char *usb_dump_config ( - int speed, - char *start, - char *end, - const struct usb_host_config *config, - int active -) +static char *usb_dump_config(int speed, char *start, char *end, + const struct usb_host_config *config, int active) { int i, j; struct usb_interface_cache *intfc; @@ -339,7 +330,8 @@ static char *usb_dump_config ( if (start > end) return start; - if (!config) /* getting these some in 2.3.7; none in 2.3.6 */ + if (!config) + /* getting these some in 2.3.7; none in 2.3.6 */ return start + sprintf(start, "(null Cfg. desc.)\n"); start = usb_dump_config_descriptor(start, end, &config->desc, active); for (i = 0; i < USB_MAXIADS; i++) { @@ -364,7 +356,8 @@ static char *usb_dump_config ( /* * Dump the different USB descriptors. */ -static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc) +static char *usb_dump_device_descriptor(char *start, char *end, + const struct usb_device_descriptor *desc) { u16 bcdUSB = le16_to_cpu(desc->bcdUSB); u16 bcdDevice = le16_to_cpu(desc->bcdDevice); @@ -374,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb start += sprintf(start, format_device1, bcdUSB >> 8, bcdUSB & 0xff, desc->bDeviceClass, - class_decode (desc->bDeviceClass), + class_decode(desc->bDeviceClass), desc->bDeviceSubClass, desc->bDeviceProtocol, desc->bMaxPacketSize0, @@ -391,12 +384,14 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb /* * Dump the different strings that this device holds. */ -static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev) +static char *usb_dump_device_strings(char *start, char *end, + struct usb_device *dev) { if (start > end) return start; if (dev->manufacturer) - start += sprintf(start, format_string_manufacturer, dev->manufacturer); + start += sprintf(start, format_string_manufacturer, + dev->manufacturer); if (start > end) goto out; if (dev->product) @@ -405,7 +400,8 @@ static char *usb_dump_device_strings(char *start, char *end, struct usb_device * goto out; #ifdef ALLOW_SERIAL_NUMBER if (dev->serial) - start += sprintf(start, format_string_serialnumber, dev->serial); + start += sprintf(start, format_string_serialnumber, + dev->serial); #endif out: return start; @@ -417,12 +413,12 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) if (start > end) return start; - + start = usb_dump_device_descriptor(start, end, &dev->descriptor); if (start > end) return start; - + start = usb_dump_device_strings(start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { @@ -439,7 +435,8 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) #ifdef PROC_EXTRA /* TBD: may want to add this code later */ -static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc) +static char *usb_dump_hub_descriptor(char *start, char *end, + const struct usb_hub_descriptor *desc) { int leng = USB_DT_HUB_NONVAR_SIZE; unsigned char *ptr = (unsigned char *)desc; @@ -455,13 +452,16 @@ static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hu return start; } -static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index) +static char *usb_dump_string(char *start, char *end, + const struct usb_device *dev, char *id, int index) { if (start > end) return start; start += sprintf(start, "Interface:"); - if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index]) - start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]); + if (index <= dev->maxstring && dev->stringindex && + dev->stringindex[index]) + start += sprintf(start, "%s: %.100s ", id, + dev->stringindex[index]); return start; } @@ -476,8 +476,10 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de * file_offset - the offset into the devices file on completion * The caller must own the device lock. */ -static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, - struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) +static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, + loff_t *skip_bytes, loff_t *file_offset, + struct usb_device *usbdev, struct usb_bus *bus, + int level, int index, int count) { int chix; int ret, cnt = 0; @@ -485,17 +487,19 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski char *pages_start, *data_end, *speed; unsigned int length; ssize_t total_written = 0; - + /* don't bother with anything else if we're not writing any data */ if (*nbytes <= 0) return 0; - + if (level > MAX_TOPO_LEVEL) return 0; - /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */ - if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1))) - return -ENOMEM; - + /* allocate 2^1 pages = 8K (on i386); + * should be more than enough for one device */ + pages_start = (char *)__get_free_pages(GFP_KERNEL, 1); + if (!pages_start) + return -ENOMEM; + if (usbdev->parent && usbdev->parent->devnum != -1) parent_devnum = usbdev->parent->devnum; /* @@ -541,15 +545,16 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski bus->bandwidth_allocated, max, (100 * bus->bandwidth_allocated + max / 2) / max, - bus->bandwidth_int_reqs, - bus->bandwidth_isoc_reqs); - + bus->bandwidth_int_reqs, + bus->bandwidth_isoc_reqs); + } - data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev); - + data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, + usbdev); + if (data_end > (pages_start + (2 * PAGE_SIZE) - 256)) data_end += sprintf(data_end, "(truncated)\n"); - + length = data_end - pages_start; /* if we can start copying some data to the user */ if (length > *skip_bytes) { @@ -567,17 +572,18 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski *skip_bytes = 0; } else *skip_bytes -= length; - + free_pages((unsigned long)pages_start, 1); - + /* Now look at all of this device's children. */ for (chix = 0; chix < usbdev->maxchild; chix++) { struct usb_device *childdev = usbdev->children[chix]; if (childdev) { usb_lock_device(childdev); - ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev, - bus, level + 1, chix, ++cnt); + ret = usb_device_dump(buffer, nbytes, skip_bytes, + file_offset, childdev, bus, + level + 1, chix, ++cnt); usb_unlock_device(childdev); if (ret == -EFAULT) return total_written; @@ -587,7 +593,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski return total_written; } -static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t usb_device_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) { struct usb_bus *bus; ssize_t ret, total_written = 0; @@ -607,7 +614,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte if (!bus->root_hub) continue; usb_lock_device(bus->root_hub); - ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); + ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, + bus->root_hub, bus, 0, 0, 0); usb_unlock_device(bus->root_hub); if (ret < 0) { mutex_unlock(&usb_bus_list_lock); @@ -620,7 +628,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte } /* Kernel lock for "lastev" protection */ -static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int usb_device_poll(struct file *file, + struct poll_table_struct *wait) { struct usb_device_status *st = file->private_data; unsigned int mask = 0; @@ -629,7 +638,8 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - /* we may have dropped BKL - need to check for having lost the race */ + /* we may have dropped BKL - + * need to check for having lost the race */ if (file->private_data) { kfree(st); st = file->private_data; @@ -652,7 +662,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct } lost_race: if (file->f_mode & FMODE_READ) - poll_wait(file, &deviceconndiscwq, wait); + poll_wait(file, &deviceconndiscwq, wait); if (st->lastev != conndiscevcnt) mask |= POLLIN; st->lastev = conndiscevcnt; @@ -662,18 +672,18 @@ lost_race: static int usb_device_open(struct inode *inode, struct file *file) { - file->private_data = NULL; - return 0; + file->private_data = NULL; + return 0; } static int usb_device_release(struct inode *inode, struct file *file) { kfree(file->private_data); file->private_data = NULL; - return 0; + return 0; } -static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) +static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig) { loff_t ret; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 1f4f6d02fe25..ae94176c64e4 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -75,14 +75,14 @@ struct async { u32 secid; }; -static int usbfs_snoop = 0; -module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); +static int usbfs_snoop; +module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define snoop(dev, format, arg...) \ do { \ if (usbfs_snoop) \ - dev_info( dev , format , ## arg); \ + dev_info(dev , format , ## arg); \ } while (0) #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) @@ -90,7 +90,7 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); #define MAX_USBFS_BUFFER_SIZE 16384 -static inline int connected (struct dev_state *ps) +static inline int connected(struct dev_state *ps) { return (!list_empty(&ps->list) && ps->dev->state != USB_STATE_NOTATTACHED); @@ -120,7 +120,8 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) return ret; } -static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) { struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; @@ -140,7 +141,8 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l } if (pos < sizeof(struct usb_device_descriptor)) { - struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */ + /* 18 bytes - fits on the stack */ + struct usb_device_descriptor temp_desc; memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor)); le16_to_cpus(&temp_desc.bcdUSB); @@ -210,17 +212,17 @@ err: static struct async *alloc_async(unsigned int numisoframes) { - unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); - struct async *as = kzalloc(assize, GFP_KERNEL); + struct async *as; - if (!as) - return NULL; + as = kzalloc(sizeof(struct async), GFP_KERNEL); + if (!as) + return NULL; as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); if (!as->urb) { kfree(as); return NULL; } - return as; + return as; } static void free_async(struct async *as) @@ -234,52 +236,54 @@ static void free_async(struct async *as) static inline void async_newpending(struct async *as) { - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_add_tail(&as->asynclist, &ps->async_pending); - spin_unlock_irqrestore(&ps->lock, flags); + struct dev_state *ps = as->ps; + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); + list_add_tail(&as->asynclist, &ps->async_pending); + spin_unlock_irqrestore(&ps->lock, flags); } static inline void async_removepending(struct async *as) { - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); + struct dev_state *ps = as->ps; + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); + list_del_init(&as->asynclist); + spin_unlock_irqrestore(&ps->lock, flags); } static inline struct async *async_getcompleted(struct dev_state *ps) { - unsigned long flags; - struct async *as = NULL; - - spin_lock_irqsave(&ps->lock, flags); - if (!list_empty(&ps->async_completed)) { - as = list_entry(ps->async_completed.next, struct async, asynclist); - list_del_init(&as->asynclist); - } - spin_unlock_irqrestore(&ps->lock, flags); - return as; + unsigned long flags; + struct async *as = NULL; + + spin_lock_irqsave(&ps->lock, flags); + if (!list_empty(&ps->async_completed)) { + as = list_entry(ps->async_completed.next, struct async, + asynclist); + list_del_init(&as->asynclist); + } + spin_unlock_irqrestore(&ps->lock, flags); + return as; } -static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb) +static inline struct async *async_getpending(struct dev_state *ps, + void __user *userurb) { - unsigned long flags; - struct async *as; + unsigned long flags; + struct async *as; - spin_lock_irqsave(&ps->lock, flags); + spin_lock_irqsave(&ps->lock, flags); list_for_each_entry(as, &ps->async_pending, asynclist) if (as->userurb == userurb) { list_del_init(&as->asynclist); spin_unlock_irqrestore(&ps->lock, flags); return as; } - spin_unlock_irqrestore(&ps->lock, flags); - return NULL; + spin_unlock_irqrestore(&ps->lock, flags); + return NULL; } static void snoop_urb(struct urb *urb, void __user *userurb) @@ -298,19 +302,19 @@ static void snoop_urb(struct urb *urb, void __user *userurb) dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); dev_info(&urb->dev->dev, "data: "); for (j = 0; j < urb->transfer_buffer_length; ++j) - printk ("%02x ", data[j]); + printk("%02x ", data[j]); printk("\n"); } static void async_completed(struct urb *urb) { - struct async *as = urb->context; - struct dev_state *ps = as->ps; + struct async *as = urb->context; + struct dev_state *ps = as->ps; struct siginfo sinfo; - spin_lock(&ps->lock); - list_move_tail(&as->asynclist, &ps->async_completed); - spin_unlock(&ps->lock); + spin_lock(&ps->lock); + list_move_tail(&as->asynclist, &ps->async_completed); + spin_unlock(&ps->lock); as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; @@ -325,7 +329,7 @@ static void async_completed(struct urb *urb) wake_up(&ps->wait); } -static void destroy_async (struct dev_state *ps, struct list_head *list) +static void destroy_async(struct dev_state *ps, struct list_head *list) { struct async *as; unsigned long flags; @@ -348,7 +352,8 @@ static void destroy_async (struct dev_state *ps, struct list_head *list) } } -static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum) +static void destroy_async_on_interface(struct dev_state *ps, + unsigned int ifnum) { struct list_head *p, *q, hitlist; unsigned long flags; @@ -364,7 +369,7 @@ static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum static inline void destroy_all_async(struct dev_state *ps) { - destroy_async(ps, &ps->async_pending); + destroy_async(ps, &ps->async_pending); } /* @@ -373,15 +378,15 @@ static inline void destroy_all_async(struct dev_state *ps) * they're also undone when devices disconnect. */ -static int driver_probe (struct usb_interface *intf, - const struct usb_device_id *id) +static int driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) { return -ENODEV; } static void driver_disconnect(struct usb_interface *intf) { - struct dev_state *ps = usb_get_intfdata (intf); + struct dev_state *ps = usb_get_intfdata(intf); unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; if (!ps) @@ -396,16 +401,31 @@ static void driver_disconnect(struct usb_interface *intf) else warn("interface number %u out of range", ifnum); - usb_set_intfdata (intf, NULL); + usb_set_intfdata(intf, NULL); /* force async requests to complete */ destroy_async_on_interface(ps, ifnum); } +/* The following routines are merely placeholders. There is no way + * to inform a user task about suspend or resumes. + */ +static int driver_suspend(struct usb_interface *intf, pm_message_t msg) +{ + return 0; +} + +static int driver_resume(struct usb_interface *intf) +{ + return 0; +} + struct usb_driver usbfs_driver = { .name = "usbfs", .probe = driver_probe, .disconnect = driver_disconnect, + .suspend = driver_suspend, + .resume = driver_resume, }; static int claimintf(struct dev_state *ps, unsigned int ifnum) @@ -459,15 +479,16 @@ static int checkintf(struct dev_state *ps, unsigned int ifnum) if (test_bit(ifnum, &ps->ifclaimed)) return 0; /* if not yet claimed, claim it for the driver */ - dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n", - task_pid_nr(current), current->comm, ifnum); + dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim " + "interface %u before use\n", task_pid_nr(current), + current->comm, ifnum); return claimintf(ps, ifnum); } static int findintfep(struct usb_device *dev, unsigned int ep) { unsigned int i, j, e; - struct usb_interface *intf; + struct usb_interface *intf; struct usb_host_interface *alts; struct usb_endpoint_descriptor *endpt; @@ -478,7 +499,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { intf = dev->actconfig->interface[i]; for (j = 0; j < intf->num_altsetting; j++) { - alts = &intf->altsetting[j]; + alts = &intf->altsetting[j]; for (e = 0; e < alts->desc.bNumEndpoints; e++) { endpt = &alts->endpoint[e].desc; if (endpt->bEndpointAddress == ep) @@ -486,10 +507,11 @@ static int findintfep(struct usb_device *dev, unsigned int ep) } } } - return -ENOENT; + return -ENOENT; } -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index) +static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, + unsigned int index) { int ret = 0; @@ -502,7 +524,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig index &= 0xff; switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: - if ((ret = findintfep(ps->dev, index)) >= 0) + ret = findintfep(ps->dev, index); + if (ret >= 0) ret = checkintf(ps, ret); break; @@ -546,7 +569,8 @@ static int usbdev_open(struct inode *inode, struct file *file) mutex_lock(&usbfs_mutex); ret = -ENOMEM; - if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) + ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); + if (!ps) goto out; ret = -ENOENT; @@ -627,15 +651,18 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; - if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) + ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); + if (ret) return ret; if (ctrl.wLength > PAGE_SIZE) return -EINVAL; - if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!tbuf) return -ENOMEM; tmo = ctrl.timeout; if (ctrl.bRequestType & 0x80) { - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { + if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, + ctrl.wLength)) { free_page((unsigned long)tbuf); return -EINVAL; } @@ -646,14 +673,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) ctrl.wIndex, ctrl.wLength); usb_unlock_device(dev); - i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, - ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); usb_lock_device(dev); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); for (j = 0; j < i; ++j) - printk("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (u8)(tbuf)[j]); printk("\n"); } if (copy_to_user(ctrl.data, tbuf, i)) { @@ -680,12 +708,13 @@ static int proc_control(struct dev_state *ps, void __user *arg) printk("\n"); } usb_unlock_device(dev); - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, - ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); usb_lock_device(dev); } free_page((unsigned long)tbuf); - if (i<0 && i != -EPIPE) { + if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, @@ -705,9 +734,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (copy_from_user(&bulk, arg, sizeof(bulk))) return -EFAULT; - if ((ret = findintfep(ps->dev, bulk.ep)) < 0) + ret = findintfep(ps->dev, bulk.ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; if (bulk.ep & USB_DIR_IN) pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); @@ -735,7 +766,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "bulk read: data "); for (j = 0; j < len2; ++j) - printk("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (u8)(tbuf)[j]); printk("\n"); } if (copy_to_user(bulk.data, tbuf, len2)) { @@ -775,9 +806,11 @@ static int proc_resetep(struct dev_state *ps, void __user *arg) if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = findintfep(ps->dev, ep)) < 0) + ret = findintfep(ps->dev, ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); return 0; @@ -791,18 +824,19 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg) if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = findintfep(ps->dev, ep)) < 0) + ret = findintfep(ps->dev, ep); + if (ret < 0) return ret; - if ((ret = checkintf(ps, ret))) + ret = checkintf(ps, ret); + if (ret) return ret; if (ep & USB_DIR_IN) - pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); - else - pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); + pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); + else + pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); return usb_clear_halt(ps->dev, pipe); } - static int proc_getdriver(struct dev_state *ps, void __user *arg) { @@ -856,23 +890,23 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) { int u; int status = 0; - struct usb_host_config *actconfig; + struct usb_host_config *actconfig; if (get_user(u, (int __user *)arg)) return -EFAULT; - actconfig = ps->dev->actconfig; - - /* Don't touch the device if any interfaces are claimed. - * It could interfere with other drivers' operations, and if + actconfig = ps->dev->actconfig; + + /* Don't touch the device if any interfaces are claimed. + * It could interfere with other drivers' operations, and if * an interface is claimed by usbfs it could easily deadlock. */ - if (actconfig) { - int i; - - for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { - if (usb_interface_claimed(actconfig->interface[i])) { - dev_warn (&ps->dev->dev, + if (actconfig) { + int i; + + for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { + if (usb_interface_claimed(actconfig->interface[i])) { + dev_warn(&ps->dev->dev, "usbfs: interface %d claimed by %s " "while '%s' sets config #%d\n", actconfig->interface[i] @@ -881,11 +915,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) actconfig->interface[i] ->dev.driver->name, current->comm, u); - status = -EBUSY; + status = -EBUSY; break; } - } - } + } + } /* SET_CONFIGURATION is often abused as a "cheap" driver reset, * so avoid usb_set_configuration()'s kick to sysfs @@ -901,8 +935,8 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) } static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, - struct usbdevfs_iso_packet_desc __user *iso_frame_desc, - void __user *arg) + struct usbdevfs_iso_packet_desc __user *iso_frame_desc, + void __user *arg) { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; @@ -917,12 +951,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!uurb->buffer) return -EINVAL; - if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX)) + if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || + uurb->signr > SIGRTMAX)) return -EINVAL; - if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { - if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0) + if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && + (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { + ifnum = findintfep(ps->dev, uurb->endpoint); + if (ifnum < 0) return ifnum; - if ((ret = checkintf(ps, ifnum))) + ret = checkintf(ps, ifnum); + if (ret) return ret; } if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { @@ -938,10 +976,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; - /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ - if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) + /* min 8 byte setup packet, + * max 8 byte setup plus an arbitrary data stage */ + if (uurb->buffer_length < 8 || + uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) return -EINVAL; - if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { kfree(dr); @@ -951,7 +992,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EINVAL; } - if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) { + ret = check_ctrlrecip(ps, dr->bRequestType, + le16_to_cpup(&dr->wIndex)); + if (ret) { kfree(dr); return ret; } @@ -997,11 +1040,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_ISO: /* arbitrary limit */ - if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) + if (uurb->number_of_packets < 1 || + uurb->number_of_packets > 128) return -EINVAL; if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; - isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; + isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * + uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { @@ -1009,7 +1054,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EFAULT; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { - /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */ + /* arbitrary limit, + * sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { kfree(isopkt); return -EINVAL; @@ -1039,25 +1085,27 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, default: return -EINVAL; } - if (!(as = alloc_async(uurb->number_of_packets))) { + as = alloc_async(uurb->number_of_packets); + if (!as) { kfree(isopkt); kfree(dr); return -ENOMEM; } - if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) { + as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); + if (!as->urb->transfer_buffer) { kfree(isopkt); kfree(dr); free_async(as); return -ENOMEM; } - as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | + as->urb->dev = ps->dev; + as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags | + as->urb->transfer_flags = uurb->flags | (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; - as->urb->setup_packet = (unsigned char*)dr; + as->urb->setup_packet = (unsigned char *)dr; as->urb->start_frame = uurb->start_frame; as->urb->number_of_packets = uurb->number_of_packets; if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1065,8 +1113,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); else as->urb->interval = ep->desc.bInterval; - as->urb->context = as; - as->urb->complete = async_completed; + as->urb->context = as; + as->urb->complete = async_completed; for (totlen = u = 0; u < uurb->number_of_packets; u++) { as->urb->iso_frame_desc[u].offset = totlen; as->urb->iso_frame_desc[u].length = isopkt[u].length; @@ -1074,7 +1122,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } kfree(isopkt); as->ps = ps; - as->userurb = arg; + as->userurb = arg; if (uurb->endpoint & USB_DIR_IN) as->userbuffer = uurb->buffer; else @@ -1093,14 +1141,15 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } } snoop_urb(as->urb, as->userurb); - async_newpending(as); - if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { - dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); - async_removepending(as); - free_async(as); - return ret; - } - return 0; + async_newpending(as); + if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { + dev_printk(KERN_DEBUG, &ps->dev->dev, + "usbfs: usb_submit_urb returned %d\n", ret); + async_removepending(as); + free_async(as); + return ret; + } + return 0; } static int proc_submiturb(struct dev_state *ps, void __user *arg) @@ -1110,7 +1159,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); + return proc_do_submiturb(ps, &uurb, + (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), + arg); } static int proc_unlinkurb(struct dev_state *ps, void __user *arg) @@ -1132,7 +1183,8 @@ static int processcompl(struct async *as, void __user * __user *arg) unsigned int i; if (as->userbuffer) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) + if (copy_to_user(as->userbuffer, urb->transfer_buffer, + urb->transfer_buffer_length)) return -EFAULT; if (put_user(as->status, &userurb->status)) return -EFAULT; @@ -1159,16 +1211,17 @@ static int processcompl(struct async *as, void __user * __user *arg) return 0; } -static struct async* reap_as(struct dev_state *ps) +static struct async *reap_as(struct dev_state *ps) { - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; struct usb_device *dev = ps->dev; add_wait_queue(&ps->wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if ((as = async_getcompleted(ps))) + as = async_getcompleted(ps); + if (as) break; if (signal_pending(current)) break; @@ -1232,10 +1285,12 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; - if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg)) + if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) return -EFAULT; - return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg); + return proc_do_submiturb(ps, &uurb, + ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, + arg); } static int processcompl_compat(struct async *as, void __user * __user *arg) @@ -1246,7 +1301,8 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) unsigned int i; if (as->userbuffer) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) + if (copy_to_user(as->userbuffer, urb->transfer_buffer, + urb->transfer_buffer_length)) return -EFAULT; if (put_user(as->status, &userurb->status)) return -EFAULT; @@ -1337,16 +1393,16 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) struct usb_driver *driver = NULL; /* alloc buffer */ - if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { - if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) + if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { + if ((buf = kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { - if (copy_from_user (buf, ctl->data, size)) { + if (copy_from_user(buf, ctl->data, size)) { kfree(buf); return -EFAULT; } } else { - memset (buf, 0, size); + memset(buf, 0, size); } } @@ -1357,15 +1413,15 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) if (ps->dev->state != USB_STATE_CONFIGURED) retval = -EHOSTUNREACH; - else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) - retval = -EINVAL; + else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno))) + retval = -EINVAL; else switch (ctl->ioctl_code) { /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); - dev_dbg (&intf->dev, "disconnect by usbfs\n"); + dev_dbg(&intf->dev, "disconnect by usbfs\n"); usb_driver_release_interface(driver, intf); } else retval = -ENODATA; @@ -1373,9 +1429,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: - usb_unlock_device(ps->dev); - retval = bus_rescan_devices(intf->dev.bus); - usb_lock_device(ps->dev); + if (!intf->dev.driver) + retval = device_attach(&intf->dev); + else + retval = -EBUSY; break; /* talk directly to the interface's driver */ @@ -1385,7 +1442,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { - retval = driver->ioctl (intf, ctl->ioctl_code, buf); + retval = driver->ioctl(intf, ctl->ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -1393,9 +1450,9 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* cleanup and return */ if (retval >= 0 - && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 + && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0 && size > 0 - && copy_to_user (ctl->data, buf, size) != 0) + && copy_to_user(ctl->data, buf, size) != 0) retval = -EFAULT; kfree(buf); @@ -1406,7 +1463,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg) { struct usbdevfs_ioctl ctrl; - if (copy_from_user(&ctrl, arg, sizeof (ctrl))) + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; return proc_ioctl(ps, &ctrl); } @@ -1434,7 +1491,8 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) * are assuming that somehow the configuration has been prevented from * changing. But there's no mechanism to ensure that... */ -static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int usbdev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; @@ -1577,7 +1635,8 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } /* No kernel lock - fine */ -static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int usbdev_poll(struct file *file, + struct poll_table_struct *wait) { struct dev_state *ps = file->private_data; unsigned int mask = 0; @@ -1648,7 +1707,7 @@ int __init usb_devio_init(void) int retval; retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX, - "usb_device"); + "usb_device"); if (retval) { err("unable to register minors for usb_device"); goto out; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7c3aaa9c5402..801b6f142fa7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,10 +202,10 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - if (udev->authorized == 0) { - dev_err(&intf->dev, "Device is not authorized for usage\n"); - return -ENODEV; - } + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } id = usb_match_id(intf, driver->id_table); if (!id) @@ -299,7 +299,7 @@ static int usb_unbind_interface(struct device *dev) * lock. */ int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void* priv) + struct usb_interface *iface, void *priv) { struct device *dev = &iface->dev; struct usb_device *udev = interface_to_usbdev(iface); @@ -325,7 +325,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, return retval; } -EXPORT_SYMBOL(usb_driver_claim_interface); +EXPORT_SYMBOL_GPL(usb_driver_claim_interface); /** * usb_driver_release_interface - unbind a driver from an interface @@ -370,7 +370,7 @@ void usb_driver_release_interface(struct usb_driver *driver, iface->needs_remote_wakeup = 0; usb_pm_unlock(udev); } -EXPORT_SYMBOL(usb_driver_release_interface); +EXPORT_SYMBOL_GPL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) @@ -398,7 +398,7 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && @@ -534,15 +534,15 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, id->driver_info is the way to create an entry that indicates that the driver want to examine every device and interface. */ - for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || - id->driver_info; id++) { + for (; id->idVendor || id->idProduct || id->bDeviceClass || + id->bInterfaceClass || id->driver_info; id++) { if (usb_match_one_id(interface, id)) return id; } return NULL; } -EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); +EXPORT_SYMBOL_GPL(usb_match_id); static int usb_device_match(struct device *dev, struct device_driver *drv) { @@ -586,7 +586,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) struct usb_device *usb_dev; /* driver is often null here; dev_dbg() would oops */ - pr_debug ("usb %s: uevent\n", dev->bus_id); + pr_debug("usb %s: uevent\n", dev->bus_id); if (is_usb_device(dev)) usb_dev = to_usb_device(dev); @@ -596,11 +596,11 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) } if (usb_dev->devnum < 0) { - pr_debug ("usb %s: already deleted?\n", dev->bus_id); + pr_debug("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; } if (!usb_dev->bus) { - pr_debug ("usb %s: bus removed?\n", dev->bus_id); + pr_debug("usb %s: bus removed?\n", dev->bus_id); return -ENODEV; } @@ -745,7 +745,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, return retval; } -EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); +EXPORT_SYMBOL_GPL(usb_register_driver); /** * usb_deregister - unregister a USB interface driver @@ -769,7 +769,7 @@ void usb_deregister(struct usb_driver *driver) usbfs_update_special(); } -EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); +EXPORT_SYMBOL_GPL(usb_deregister); #ifdef CONFIG_PM @@ -854,8 +854,10 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) dev_err(&intf->dev, "%s error %d\n", "suspend", status); } else { - // FIXME else if there's no suspend method, disconnect... - // Not possible if auto_pm is set... + /* + * FIXME else if there's no suspend method, disconnect... + * Not possible if auto_pm is set... + */ dev_warn(&intf->dev, "no suspend for driver %s?\n", driver->name); mark_quiesced(intf); @@ -894,7 +896,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) dev_err(&intf->dev, "%s error %d\n", "reset_resume", status); } else { - // status = -EOPNOTSUPP; + /* status = -EOPNOTSUPP; */ dev_warn(&intf->dev, "no %s for driver %s?\n", "reset_resume", driver->name); } @@ -905,7 +907,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) dev_err(&intf->dev, "%s error %d\n", "resume", status); } else { - // status = -EOPNOTSUPP; + /* status = -EOPNOTSUPP; */ dev_warn(&intf->dev, "no %s for driver %s?\n", "resume", driver->name); } @@ -1175,7 +1177,7 @@ static int usb_resume_both(struct usb_device *udev) * so if a root hub's controller is suspended * then we're stuck. */ status = usb_resume_device(udev); - } + } } else { /* Needed for setting udev->dev.power.power_state.event, diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 5d860bc9b421..8133c99c6c5c 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -204,7 +204,7 @@ int usb_register_dev(struct usb_interface *intf, exit: return retval; } -EXPORT_SYMBOL(usb_register_dev); +EXPORT_SYMBOL_GPL(usb_register_dev); /** * usb_deregister_dev - deregister a USB device's dynamic minor. @@ -245,4 +245,4 @@ void usb_deregister_dev(struct usb_interface *intf, intf->minor = -1; destroy_usb_class(); } -EXPORT_SYMBOL(usb_deregister_dev); +EXPORT_SYMBOL_GPL(usb_deregister_dev); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 3fb9af80cbf4..84760ddbc332 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -1,6 +1,6 @@ /* * (C) Copyright David Brownell 2000-2002 - * + * * 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 @@ -55,7 +55,7 @@ * * Store this function in the HCD's struct pci_driver as probe(). */ -int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct hc_driver *driver; struct usb_hcd *hcd; @@ -64,66 +64,71 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) if (usb_disabled()) return -ENODEV; - if (!id || !(driver = (struct hc_driver *) id->driver_data)) + if (!id) + return -EINVAL; + driver = (struct hc_driver *)id->driver_data; + if (!driver) return -EINVAL; - if (pci_enable_device (dev) < 0) + if (pci_enable_device(dev) < 0) return -ENODEV; dev->current_state = PCI_D0; dev->dev.power.power_state = PMSG_ON; - - if (!dev->irq) { - dev_err (&dev->dev, + + if (!dev->irq) { + dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); - retval = -ENODEV; + retval = -ENODEV; goto err1; - } + } - hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev)); + hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); if (!hcd) { retval = -ENOMEM; goto err1; } - if (driver->flags & HCD_MEMORY) { // EHCI, OHCI - hcd->rsrc_start = pci_resource_start (dev, 0); - hcd->rsrc_len = pci_resource_len (dev, 0); - if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len, + if (driver->flags & HCD_MEMORY) { + /* EHCI, OHCI */ + hcd->rsrc_start = pci_resource_start(dev, 0); + hcd->rsrc_len = pci_resource_len(dev, 0); + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { - dev_dbg (&dev->dev, "controller already in use\n"); + dev_dbg(&dev->dev, "controller already in use\n"); retval = -EBUSY; goto err2; } - hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { - dev_dbg (&dev->dev, "error mapping memory\n"); + dev_dbg(&dev->dev, "error mapping memory\n"); retval = -EFAULT; goto err3; } - } else { // UHCI + } else { + /* UHCI */ int region; for (region = 0; region < PCI_ROM_RESOURCE; region++) { - if (!(pci_resource_flags (dev, region) & + if (!(pci_resource_flags(dev, region) & IORESOURCE_IO)) continue; - hcd->rsrc_start = pci_resource_start (dev, region); - hcd->rsrc_len = pci_resource_len (dev, region); - if (request_region (hcd->rsrc_start, hcd->rsrc_len, + hcd->rsrc_start = pci_resource_start(dev, region); + hcd->rsrc_len = pci_resource_len(dev, region); + if (request_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) break; } if (region == PCI_ROM_RESOURCE) { - dev_dbg (&dev->dev, "no i/o regions available\n"); + dev_dbg(&dev->dev, "no i/o regions available\n"); retval = -EBUSY; goto err1; } } - pci_set_master (dev); + pci_set_master(dev); retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) @@ -132,19 +137,19 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) err4: if (driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); + iounmap(hcd->regs); err3: - release_mem_region (hcd->rsrc_start, hcd->rsrc_len); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else - release_region (hcd->rsrc_start, hcd->rsrc_len); + release_region(hcd->rsrc_start, hcd->rsrc_len); err2: - usb_put_hcd (hcd); + usb_put_hcd(hcd); err1: - pci_disable_device (dev); - dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); + pci_disable_device(dev); + dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_probe); +} +EXPORT_SYMBOL_GPL(usb_hcd_pci_probe); /* may be called without controller electrically present */ @@ -161,7 +166,7 @@ EXPORT_SYMBOL (usb_hcd_pci_probe); * * Store this function in the HCD's struct pci_driver as remove(). */ -void usb_hcd_pci_remove (struct pci_dev *dev) +void usb_hcd_pci_remove(struct pci_dev *dev) { struct usb_hcd *hcd; @@ -169,17 +174,17 @@ void usb_hcd_pci_remove (struct pci_dev *dev) if (!hcd) return; - usb_remove_hcd (hcd); + usb_remove_hcd(hcd); if (hcd->driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); - release_mem_region (hcd->rsrc_start, hcd->rsrc_len); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else { - release_region (hcd->rsrc_start, hcd->rsrc_len); + release_region(hcd->rsrc_start, hcd->rsrc_len); } - usb_put_hcd (hcd); + usb_put_hcd(hcd); pci_disable_device(dev); } -EXPORT_SYMBOL (usb_hcd_pci_remove); +EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); #ifdef CONFIG_PM @@ -191,7 +196,7 @@ EXPORT_SYMBOL (usb_hcd_pci_remove); * * Store this function in the HCD's struct pci_driver as suspend(). */ -int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) +int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) { struct usb_hcd *hcd; int retval = 0; @@ -246,12 +251,18 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) /* no DMA or IRQs except when HC is active */ if (dev->current_state == PCI_D0) { - pci_save_state (dev); - pci_disable_device (dev); + pci_save_state(dev); + pci_disable_device(dev); + } + + if (message.event == PM_EVENT_FREEZE || + message.event == PM_EVENT_PRETHAW) { + dev_dbg(hcd->self.controller, "--> no state change\n"); + goto done; } if (!has_pci_pm) { - dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); + dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n"); goto done; } @@ -260,30 +271,30 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset * some device state (e.g. as part of clock reinit). */ - retval = pci_set_power_state (dev, PCI_D3hot); + retval = pci_set_power_state(dev, PCI_D3hot); suspend_report_result(pci_set_power_state, retval); if (retval == 0) { int wake = device_can_wakeup(&hcd->self.root_hub->dev); wake = wake && device_may_wakeup(hcd->self.controller); - dev_dbg (hcd->self.controller, "--> PCI D3%s\n", + dev_dbg(hcd->self.controller, "--> PCI D3%s\n", wake ? "/wakeup" : ""); /* Ignore these return values. We rely on pci code to * reject requests the hardware can't implement, rather * than coding the same thing. */ - (void) pci_enable_wake (dev, PCI_D3hot, wake); - (void) pci_enable_wake (dev, PCI_D3cold, wake); + (void) pci_enable_wake(dev, PCI_D3hot, wake); + (void) pci_enable_wake(dev, PCI_D3cold, wake); } else { - dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", + dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n", retval); - (void) usb_hcd_pci_resume (dev); + (void) usb_hcd_pci_resume(dev); } } else if (hcd->state != HC_STATE_HALT) { - dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", + dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n", hcd->state); WARN_ON(1); retval = -EINVAL; @@ -298,7 +309,7 @@ done: if (machine_is(powermac)) { struct device_node *of_node; - of_node = pci_device_to_OF_node (dev); + of_node = pci_device_to_OF_node(dev); if (of_node) pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); @@ -308,7 +319,7 @@ done: return retval; } -EXPORT_SYMBOL (usb_hcd_pci_suspend); +EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); /** * usb_hcd_pci_resume - power management resume of a PCI-based HCD @@ -316,14 +327,14 @@ EXPORT_SYMBOL (usb_hcd_pci_suspend); * * Store this function in the HCD's struct pci_driver as resume(). */ -int usb_hcd_pci_resume (struct pci_dev *dev) +int usb_hcd_pci_resume(struct pci_dev *dev) { struct usb_hcd *hcd; int retval; hcd = pci_get_drvdata(dev); if (hcd->state != HC_STATE_SUSPENDED) { - dev_dbg (hcd->self.controller, + dev_dbg(hcd->self.controller, "can't resume, not suspended!\n"); return 0; } @@ -333,9 +344,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) if (machine_is(powermac)) { struct device_node *of_node; - of_node = pci_device_to_OF_node (dev); + of_node = pci_device_to_OF_node(dev); if (of_node) - pmac_call_feature (PMAC_FTR_USB_ENABLE, + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif @@ -374,8 +385,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev) } #endif /* yes, ignore these results too... */ - (void) pci_enable_wake (dev, dev->current_state, 0); - (void) pci_enable_wake (dev, PCI_D3cold, 0); + (void) pci_enable_wake(dev, dev->current_state, 0); + (void) pci_enable_wake(dev, PCI_D3cold, 0); } else { /* Same basic cases: clean (powered/not), dirty */ dev_dbg(hcd->self.controller, "PCI legacy resume\n"); @@ -386,14 +397,14 @@ int usb_hcd_pci_resume (struct pci_dev *dev) * but that won't re-enable bus mastering. Yet pci_disable_device() * explicitly disables bus mastering... */ - retval = pci_enable_device (dev); + retval = pci_enable_device(dev); if (retval < 0) { - dev_err (hcd->self.controller, + dev_err(hcd->self.controller, "can't re-enable after resume, %d!\n", retval); return retval; } - pci_set_master (dev); - pci_restore_state (dev); + pci_set_master(dev); + pci_restore_state(dev); dev->dev.power.power_state = PMSG_ON; @@ -402,15 +413,15 @@ int usb_hcd_pci_resume (struct pci_dev *dev) if (hcd->driver->resume) { retval = hcd->driver->resume(hcd); if (retval) { - dev_err (hcd->self.controller, + dev_err(hcd->self.controller, "PCI post-resume error %d!\n", retval); - usb_hc_died (hcd); + usb_hc_died(hcd); } } return retval; } -EXPORT_SYMBOL (usb_hcd_pci_resume); +EXPORT_SYMBOL_GPL(usb_hcd_pci_resume); #endif /* CONFIG_PM */ @@ -418,7 +429,7 @@ EXPORT_SYMBOL (usb_hcd_pci_resume); * usb_hcd_pci_shutdown - shutdown host controller * @dev: USB Host Controller being shutdown */ -void usb_hcd_pci_shutdown (struct pci_dev *dev) +void usb_hcd_pci_shutdown(struct pci_dev *dev) { struct usb_hcd *hcd; @@ -429,5 +440,5 @@ void usb_hcd_pci_shutdown (struct pci_dev *dev) if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } -EXPORT_SYMBOL (usb_hcd_pci_shutdown); +EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d5ed3fa9e304..e52ed1663b3c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -35,6 +35,7 @@ #include <linux/mutex.h> #include <asm/irq.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #include <linux/platform_device.h> #include <linux/workqueue.h> @@ -131,8 +132,8 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __le16 idVendor; */ - 0x00, 0x00, /* __le16 idProduct; */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x02, 0x00, /* __le16 idProduct; device 0x0002 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ @@ -154,8 +155,8 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __le16 idVendor; */ - 0x00, 0x00, /* __le16 idProduct; */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x01, 0x00, /* __le16 idProduct; device 0x0001 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ @@ -807,13 +808,13 @@ static int usb_register_bus(struct usb_bus *bus) } set_bit (busnum, busmap.busmap); bus->busnum = busnum; - bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", - busnum); - result = PTR_ERR(bus->class_dev); - if (IS_ERR(bus->class_dev)) + + bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0), + "usb_host%d", busnum); + result = PTR_ERR(bus->dev); + if (IS_ERR(bus->dev)) goto error_create_class_dev; - class_set_devdata(bus->class_dev, bus); + dev_set_drvdata(bus->dev, bus); /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); @@ -857,7 +858,7 @@ static void usb_deregister_bus (struct usb_bus *bus) clear_bit (bus->busnum, busmap.busmap); - class_device_unregister(bus->class_dev); + device_unregister(bus->dev); } /** @@ -970,7 +971,7 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) return -1; } } -EXPORT_SYMBOL (usb_calc_bus_time); +EXPORT_SYMBOL_GPL(usb_calc_bus_time); /*-------------------------------------------------------------------------*/ @@ -1112,48 +1113,177 @@ void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) } EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); -static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +/* + * Some usb host controllers can only perform dma using a small SRAM area. + * The usb core itself is however optimized for host controllers that can dma + * using regular system memory - like pci devices doing bus mastering. + * + * To support host controllers with limited dma capabilites we provide dma + * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag. + * For this to work properly the host controller code must first use the + * function dma_declare_coherent_memory() to point out which memory area + * that should be used for dma allocations. + * + * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for + * dma using dma_alloc_coherent() which in turn allocates from the memory + * area pointed out with dma_declare_coherent_memory(). + * + * So, to summarize... + * + * - We need "local" memory, canonical example being + * a small SRAM on a discrete controller being the + * only memory that the controller can read ... + * (a) "normal" kernel memory is no good, and + * (b) there's not enough to share + * + * - The only *portable* hook for such stuff in the + * DMA framework is dma_declare_coherent_memory() + * + * - So we use that, even though the primary requirement + * is that the memory be "local" (hence addressible + * by that device), not "coherent". + * + */ + +static int hcd_alloc_coherent(struct usb_bus *bus, + gfp_t mem_flags, dma_addr_t *dma_handle, + void **vaddr_handle, size_t size, + enum dma_data_direction dir) +{ + unsigned char *vaddr; + + vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr), + mem_flags, dma_handle); + if (!vaddr) + return -ENOMEM; + + /* + * Store the virtual address of the buffer at the end + * of the allocated dma buffer. The size of the buffer + * may be uneven so use unaligned functions instead + * of just rounding up. It makes sense to optimize for + * memory footprint over access speed since the amount + * of memory available for dma may be limited. + */ + put_unaligned((unsigned long)*vaddr_handle, + (unsigned long *)(vaddr + size)); + + if (dir == DMA_TO_DEVICE) + memcpy(vaddr, *vaddr_handle, size); + + *vaddr_handle = vaddr; + return 0; +} + +static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle, + void **vaddr_handle, size_t size, + enum dma_data_direction dir) +{ + unsigned char *vaddr = *vaddr_handle; + + vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size)); + + if (dir == DMA_FROM_DEVICE) + memcpy(vaddr, *vaddr_handle, size); + + hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle); + + *vaddr_handle = vaddr; + *dma_handle = 0; +} + +static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { + enum dma_data_direction dir; + int ret = 0; + /* Map the URB's buffers for DMA access. * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - urb->setup_dma = dma_map_single ( + if (is_root_hub(urb->dev)) + return 0; + + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (hcd->self.uses_dma) + urb->setup_dma = dma_map_single( hcd->self.controller, urb->setup_packet, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + else if (hcd->driver->flags & HCD_LOCAL_MEM) + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + } + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (ret == 0 && urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (hcd->self.uses_dma) urb->transfer_dma = dma_map_single ( hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + dir); + else if (hcd->driver->flags & HCD_LOCAL_MEM) { + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); + + if (ret && usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + hcd_free_coherent(urb->dev->bus, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } } + return ret; } static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + enum dma_data_direction dir; + + if (is_root_hub(urb->dev)) + return; + + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (hcd->self.uses_dma) dma_unmap_single(hcd->self.controller, urb->setup_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + else if (hcd->driver->flags & HCD_LOCAL_MEM) + hcd_free_coherent(urb->dev->bus, &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (hcd->self.uses_dma) dma_unmap_single(hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + dir); + else if (hcd->driver->flags & HCD_LOCAL_MEM) + hcd_free_coherent(urb->dev->bus, &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); } } @@ -1185,7 +1315,12 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * URBs must be submitted in process context with interrupts * enabled. */ - map_urb_for_dma(hcd, urb); + status = map_urb_for_dma(hcd, urb, mem_flags); + if (unlikely(status)) { + usbmon_urb_submit_error(&hcd->self, urb, status); + goto error; + } + if (is_root_hub(urb->dev)) status = rh_urb_enqueue(hcd, urb); else @@ -1194,6 +1329,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); + error: urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); @@ -1291,7 +1427,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) wake_up (&usb_kill_urb_queue); usb_put_urb (urb); } -EXPORT_SYMBOL (usb_hcd_giveback_urb); +EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ @@ -1531,7 +1667,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); return status; } -EXPORT_SYMBOL (usb_bus_start_enum); +EXPORT_SYMBOL_GPL(usb_bus_start_enum); #endif @@ -1638,7 +1774,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, "USB Host Controller"; return hcd; } -EXPORT_SYMBOL (usb_create_hcd); +EXPORT_SYMBOL_GPL(usb_create_hcd); static void hcd_release (struct kref *kref) { @@ -1653,14 +1789,14 @@ struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) kref_get (&hcd->kref); return hcd; } -EXPORT_SYMBOL (usb_get_hcd); +EXPORT_SYMBOL_GPL(usb_get_hcd); void usb_put_hcd (struct usb_hcd *hcd) { if (hcd) kref_put (&hcd->kref, hcd_release); } -EXPORT_SYMBOL (usb_put_hcd); +EXPORT_SYMBOL_GPL(usb_put_hcd); /** * usb_add_hcd - finish generic HCD structure initialization and register @@ -1786,7 +1922,7 @@ err_register_bus: hcd_buffer_destroy(hcd); return retval; } -EXPORT_SYMBOL (usb_add_hcd); +EXPORT_SYMBOL_GPL(usb_add_hcd); /** * usb_remove_hcd - shutdown processing for generic HCDs @@ -1828,7 +1964,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); } -EXPORT_SYMBOL (usb_remove_hcd); +EXPORT_SYMBOL_GPL(usb_remove_hcd); void usb_hcd_platform_shutdown(struct platform_device* dev) @@ -1838,7 +1974,7 @@ usb_hcd_platform_shutdown(struct platform_device* dev) if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } -EXPORT_SYMBOL (usb_hcd_platform_shutdown); +EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 98e24194a4ab..2d1c3d5e47b8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -125,7 +125,7 @@ struct usb_hcd { /* more shared queuing code would be good; it should support * smarter scheduling, handle transaction translators, etc; - * input size of periodic table to an interrupt scheduler. + * input size of periodic table to an interrupt scheduler. * (ohci 32, uhci 1024, ehci 256/512/1024). */ @@ -133,16 +133,16 @@ struct usb_hcd { * this structure. */ unsigned long hcd_priv[0] - __attribute__ ((aligned (sizeof(unsigned long)))); + __attribute__ ((aligned(sizeof(unsigned long)))); }; /* 2.4 does this a bit differently ... */ -static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) +static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd) { return &hcd->self; } -static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus) +static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus) { return container_of(bus, struct usb_hcd, self); } @@ -165,6 +165,7 @@ struct hc_driver { int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */ #define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB2 0x0020 /* USB 2.0 */ @@ -201,15 +202,18 @@ struct hc_driver { struct usb_host_endpoint *ep); /* root hub support */ - int (*hub_status_data) (struct usb_hcd *hcd, char *buf); - int (*hub_control) (struct usb_hcd *hcd, + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); - int (*bus_suspend)(struct usb_hcd *); - int (*bus_resume)(struct usb_hcd *); - int (*start_port_reset)(struct usb_hcd *, unsigned port_num); - void (*hub_irq_enable)(struct usb_hcd *); + int (*bus_suspend)(struct usb_hcd *); + int (*bus_resume)(struct usb_hcd *); + int (*start_port_reset)(struct usb_hcd *, unsigned port_num); + void (*hub_irq_enable)(struct usb_hcd *); /* Needed only if port-change IRQs are level-triggered */ + + /* force handover of high-speed port to full-speed companion */ + void (*relinquish_port)(struct usb_hcd *, int); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); @@ -217,56 +221,56 @@ extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status); extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); -extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); -extern int usb_hcd_unlink_urb (struct urb *urb, int status); +extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags); +extern int usb_hcd_unlink_urb(struct urb *urb, int status); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); -extern int usb_hcd_get_frame_number (struct usb_device *udev); +extern int usb_hcd_get_frame_number(struct usb_device *udev); -extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, +extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, char *bus_name); -extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd); -extern void usb_put_hcd (struct usb_hcd *hcd); +extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd); +extern void usb_put_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); struct platform_device; -extern void usb_hcd_platform_shutdown(struct platform_device* dev); +extern void usb_hcd_platform_shutdown(struct platform_device *dev); #ifdef CONFIG_PCI struct pci_dev; struct pci_device_id; -extern int usb_hcd_pci_probe (struct pci_dev *dev, +extern int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); -extern void usb_hcd_pci_remove (struct pci_dev *dev); +extern void usb_hcd_pci_remove(struct pci_dev *dev); #ifdef CONFIG_PM -extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state); -extern int usb_hcd_pci_resume (struct pci_dev *dev); +extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state); +extern int usb_hcd_pci_resume(struct pci_dev *dev); #endif /* CONFIG_PM */ -extern void usb_hcd_pci_shutdown (struct pci_dev *dev); +extern void usb_hcd_pci_shutdown(struct pci_dev *dev); #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ -int hcd_buffer_create (struct usb_hcd *hcd); -void hcd_buffer_destroy (struct usb_hcd *hcd); +int hcd_buffer_create(struct usb_hcd *hcd); +void hcd_buffer_destroy(struct usb_hcd *hcd); -void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, +void *hcd_buffer_alloc(struct usb_bus *bus, size_t size, gfp_t mem_flags, dma_addr_t *dma); -void hcd_buffer_free (struct usb_bus *bus, size_t size, +void hcd_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); /* generic bus glue, needed for host controllers that don't use PCI */ -extern irqreturn_t usb_hcd_irq (int irq, void *__hcd); +extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); -extern void usb_hc_died (struct usb_hcd *hcd); +extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); /* -------------------------------------------------------------------------- */ @@ -319,9 +323,9 @@ extern void usb_destroy_configuration(struct usb_device *dev); * Generic bandwidth allocation constants/support */ #define FRAME_TIME_USECS 1000L -#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ +#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ /* Trying not to use worst-case bit-stuffing - of (7/6 * 8 * bytecount) = 9.33 * bytecount */ + * of (7/6 * 8 * bytecount) = 9.33 * bytecount */ /* bytecount = data payload byte count */ #define NS_TO_US(ns) ((ns + 500L) / 1000L) @@ -333,9 +337,9 @@ extern void usb_destroy_configuration(struct usb_device *dev); */ #define BW_HOST_DELAY 1000L /* nanoseconds */ #define BW_HUB_LS_SETUP 333L /* nanoseconds */ - /* 4 full-speed bit times (est.) */ + /* 4 full-speed bit times (est.) */ -#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ +#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ #define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) #define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) @@ -345,16 +349,16 @@ extern void usb_destroy_configuration(struct usb_device *dev); * to preallocate bandwidth) */ #define USB2_HOST_DELAY 5 /* nsec, guess */ -#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \ +#define HS_NSECS(bytes) (((55 * 8 * 2083) \ + (2083UL * (3 + BitTime(bytes))))/1000 \ + USB2_HOST_DELAY) -#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \ +#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \ + (2083UL * (3 + BitTime(bytes))))/1000 \ + USB2_HOST_DELAY) #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes)) #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes)) -extern long usb_calc_bus_time (int speed, int is_input, +extern long usb_calc_bus_time(int speed, int is_input, int isoc, int bytecount); /*-------------------------------------------------------------------------*/ @@ -370,16 +374,16 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; -extern void usb_enable_root_hub_irq (struct usb_bus *bus); +extern void usb_enable_root_hub_irq(struct usb_bus *bus); -extern int usb_find_interface_driver (struct usb_device *dev, +extern int usb_find_interface_driver(struct usb_device *dev, struct usb_interface *interface); #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #ifdef CONFIG_PM -extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); -extern void usb_root_hub_lost_power (struct usb_device *rhdev); +extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); +extern void usb_root_hub_lost_power(struct usb_device *rhdev); extern int hcd_bus_suspend(struct usb_device *rhdev); extern int hcd_bus_resume(struct usb_device *rhdev); #else @@ -399,13 +403,13 @@ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbfs_update_special (void); +extern void usbfs_update_special(void); extern int usbfs_init(void); extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbfs_update_special (void) {} +static inline void usbfs_update_special(void) {} static inline int usbfs_init(void) { return 0; } static inline void usbfs_cleanup(void) { } @@ -460,7 +464,7 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, /*-------------------------------------------------------------------------*/ /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ -// bleech -- resurfaced in 2.4.11 or 2.4.12 +/* bleech -- resurfaced in 2.4.11 or 2.4.12 */ #define bitmap DeviceRemovable @@ -468,8 +472,8 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, /* random stuff */ -#define RUN_CONTEXT (in_irq () ? "in_irq" \ - : (in_interrupt () ? "in_interrupt" : "can sleep")) +#define RUN_CONTEXT (in_irq() ? "in_irq" \ + : (in_interrupt() ? "in_interrupt" : "can sleep")) /* This rwsem is for use only by the hub driver and ehci-hcd. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b04d232d4c65..68fc5219ca15 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -37,6 +37,13 @@ #define USB_PERSIST 0 #endif +/* if we are in debug mode, always announce new devices */ +#ifdef DEBUG +#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES +#define CONFIG_USB_ANNOUNCE_NEW_DEVICES +#endif +#endif + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -487,6 +494,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) schedule_work (&tt->kevent); spin_unlock_irqrestore (&tt->lock, flags); } +EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); static void hub_power_on(struct usb_hub *hub) { @@ -1027,8 +1035,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->children[i]) recursively_mark_NOTATTACHED(udev->children[i]); } - if (udev->state == USB_STATE_SUSPENDED) + if (udev->state == USB_STATE_SUSPENDED) { udev->discon_suspended = 1; + udev->active_duration -= jiffies; + } udev->state = USB_STATE_NOTATTACHED; } @@ -1077,6 +1087,12 @@ void usb_set_device_state(struct usb_device *udev, else device_init_wakeup(&udev->dev, 0); } + if (udev->state == USB_STATE_SUSPENDED && + new_state != USB_STATE_SUSPENDED) + udev->active_duration -= jiffies; + else if (new_state == USB_STATE_SUSPENDED && + udev->state != USB_STATE_SUSPENDED) + udev->active_duration += jiffies; udev->state = new_state; } else recursively_mark_NOTATTACHED(udev); @@ -1207,7 +1223,7 @@ void usb_disconnect(struct usb_device **pdev) put_device(&udev->dev); } -#ifdef DEBUG +#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES static void show_string(struct usb_device *udev, char *id, char *string) { if (!string) @@ -1215,12 +1231,24 @@ static void show_string(struct usb_device *udev, char *id, char *string) dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); } +static void announce_device(struct usb_device *udev) +{ + dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); +} #else -static inline void show_string(struct usb_device *udev, char *id, char *string) -{} +static inline void announce_device(struct usb_device *udev) { } #endif - #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" #endif @@ -1390,14 +1418,7 @@ int usb_new_device(struct usb_device *udev) } /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + announce_device(udev); return err; fail: @@ -2482,6 +2503,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); int status, i; @@ -2645,6 +2667,8 @@ loop: done: hub_port_disable(hub, port1, 1); + if (hcd->driver->relinquish_port && !hub->hdev->parent) + hcd->driver->relinquish_port(hcd, port1); } static void hub_events(void) @@ -2946,7 +2970,7 @@ static int config_descriptors_changed(struct usb_device *udev) if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) len = le16_to_cpu(udev->config[index].desc.wTotalLength); } - buf = kmalloc (len, GFP_KERNEL); + buf = kmalloc(len, GFP_NOIO); if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); /* assume the worst */ @@ -3093,7 +3117,7 @@ re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } -EXPORT_SYMBOL(usb_reset_device); +EXPORT_SYMBOL_GPL(usb_reset_device); /** * usb_reset_composite_device - warn interface drivers and perform a USB port reset @@ -3110,16 +3134,12 @@ EXPORT_SYMBOL(usb_reset_device); * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock * the device using usb_lock_device_for_reset(). - * - * The interface locks are acquired during the pre_reset stage and released - * during the post_reset stage. However if iface is not NULL and is - * currently being probed, we assume that the caller already owns its - * lock. */ int usb_reset_composite_device(struct usb_device *udev, struct usb_interface *iface) { int ret; + int i; struct usb_host_config *config = udev->actconfig; if (udev->state == USB_STATE_NOTATTACHED || @@ -3136,16 +3156,11 @@ int usb_reset_composite_device(struct usb_device *udev, iface = NULL; if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - cintf = config->interface[i]; - if (cintf != iface) - down(&cintf->dev.sem); - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { + struct usb_interface *cintf = config->interface[i]; + struct usb_driver *drv; + + if (cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); if (drv->pre_reset) (drv->pre_reset)(cintf); @@ -3157,25 +3172,20 @@ int usb_reset_composite_device(struct usb_device *udev, ret = usb_reset_device(udev); if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { - cintf = config->interface[i]; - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { + struct usb_interface *cintf = config->interface[i]; + struct usb_driver *drv; + + if (cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); if (drv->post_reset) (drv->post_reset)(cintf); /* FIXME: Unbind if post_reset returns an error or isn't defined */ } - if (cintf != iface) - up(&cintf->dev.sem); } } usb_autosuspend_device(udev); return ret; } -EXPORT_SYMBOL(usb_reset_composite_device); +EXPORT_SYMBOL_GPL(usb_reset_composite_device); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index cf9559c6c9b6..1551aed65e05 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -55,16 +55,16 @@ #define USB_PORT_FEAT_TEST 21 #define USB_PORT_FEAT_INDICATOR 22 -/* +/* * Hub Status and Hub Change results * See USB 2.0 spec Table 11-19 and Table 11-20 */ struct usb_port_status { __le16 wPortStatus; - __le16 wPortChange; + __le16 wPortChange; } __attribute__ ((packed)); -/* +/* * wPortStatus bit field * See USB 2.0 spec Table 11-21 */ @@ -81,7 +81,7 @@ struct usb_port_status { #define USB_PORT_STAT_INDICATOR 0x1000 /* bits 13 to 15 are reserved */ -/* +/* * wPortChange bit field * See USB 2.0 spec Table 11-22 * Bits 0 to 4 shown, bits 5 to 15 are reserved @@ -93,7 +93,7 @@ struct usb_port_status { #define USB_PORT_STAT_C_RESET 0x0010 /* - * wHubCharacteristics (masks) + * wHubCharacteristics (masks) * See USB 2.0 spec Table 11-13, offset 3 */ #define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ @@ -119,8 +119,8 @@ struct usb_hub_status { #define HUB_CHANGE_OVERCURRENT 0x0002 -/* - * Hub descriptor +/* + * Hub descriptor * See USB 2.0 spec Table 11-13 */ @@ -134,7 +134,7 @@ struct usb_hub_descriptor { __le16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; - /* add 1 bit for hub status change; round to bytes */ + /* add 1 bit for hub status change; round to bytes */ __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; } __attribute__ ((packed)); @@ -190,6 +190,6 @@ struct usb_tt_clear { u16 devinfo; }; -extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); +extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index cd4f11157280..83a373e9cc36 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -38,10 +38,15 @@ #include <linux/usbdevice_fs.h> #include <linux/parser.h> #include <linux/notifier.h> +#include <linux/seq_file.h> #include <asm/byteorder.h> #include "usb.h" #include "hcd.h" +#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) +#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) +#define USBFS_DEFAULT_LISTMODE S_IRUGO + static struct super_operations usbfs_ops; static const struct file_operations default_file_operations; static struct vfsmount *usbfs_mount; @@ -57,9 +62,33 @@ static uid_t listuid; /* = 0 */ static gid_t devgid; /* = 0 */ static gid_t busgid; /* = 0 */ static gid_t listgid; /* = 0 */ -static umode_t devmode = S_IWUSR | S_IRUGO; -static umode_t busmode = S_IXUGO | S_IRUGO; -static umode_t listmode = S_IRUGO; +static umode_t devmode = USBFS_DEFAULT_DEVMODE; +static umode_t busmode = USBFS_DEFAULT_BUSMODE; +static umode_t listmode = USBFS_DEFAULT_LISTMODE; + +static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt) +{ + if (devuid != 0) + seq_printf(seq, ",devuid=%u", devuid); + if (devgid != 0) + seq_printf(seq, ",devgid=%u", devgid); + if (devmode != USBFS_DEFAULT_DEVMODE) + seq_printf(seq, ",devmode=%o", devmode); + if (busuid != 0) + seq_printf(seq, ",busuid=%u", busuid); + if (busgid != 0) + seq_printf(seq, ",busgid=%u", busgid); + if (busmode != USBFS_DEFAULT_BUSMODE) + seq_printf(seq, ",busmode=%o", busmode); + if (listuid != 0) + seq_printf(seq, ",listuid=%u", listuid); + if (listgid != 0) + seq_printf(seq, ",listgid=%u", listgid); + if (listmode != USBFS_DEFAULT_LISTMODE) + seq_printf(seq, ",listmode=%o", listmode); + + return 0; +} enum { Opt_devuid, Opt_devgid, Opt_devmode, @@ -93,9 +122,9 @@ static int parse_options(struct super_block *s, char *data) devgid = 0; busgid = 0; listgid = 0; - devmode = S_IWUSR | S_IRUGO; - busmode = S_IXUGO | S_IRUGO; - listmode = S_IRUGO; + devmode = USBFS_DEFAULT_DEVMODE; + busmode = USBFS_DEFAULT_BUSMODE; + listmode = USBFS_DEFAULT_LISTMODE; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -418,6 +447,7 @@ static struct super_operations usbfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .remount_fs = remount, + .show_options = usbfs_show_options, }; static int usbfs_fill_super(struct super_block *sb, void *data, int silent) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fcd40ecbeecc..fefb92296e8f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -39,7 +39,7 @@ static void usb_api_blocking_completion(struct urb *urb) * own interruptible routines. */ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) -{ +{ struct api_context ctx; unsigned long expire; int retval; @@ -74,9 +74,9 @@ out: } /*-------------------------------------------------------------------*/ -// returns status (negative) or length (positive) +/* returns status (negative) or length (positive) */ static int usb_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, + unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout) { @@ -87,7 +87,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) return -ENOMEM; - + usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, len, usb_api_blocking_completion, NULL); @@ -99,47 +99,51 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, } /** - * usb_control_msg - Builds a control urb, sends it off and waits for completion - * @dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @request: USB message request value - * @requesttype: USB message request type value - * @value: USB message value - * @index: USB message index value - * @data: pointer to the data to send - * @size: length in bytes of the data to send - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple control message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns the number of bytes transferred, otherwise a negative error number. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to send - * a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. + * usb_control_msg - Builds a control urb, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @data: pointer to the data to send + * @size: length in bytes of the data to send + * @timeout: time in msecs to wait for the message to complete before timing + * out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a simple control message to a specified endpoint and + * waits for the message to complete, or timeout. + * + * If successful, it returns the number of bytes transferred, otherwise a + * negative error number. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb(). + * If a thread in your driver uses this call, make sure your disconnect() + * method can wait for it to complete. Since you don't have a handle on the + * URB used, you can't cancel the request. */ -int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, __u16 size, int timeout) +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, + __u8 requesttype, __u16 value, __u16 index, void *data, + __u16 size, int timeout) { - struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); + struct usb_ctrlrequest *dr; int ret; - + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); if (!dr) return -ENOMEM; - dr->bRequestType= requesttype; + dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16p(&value); dr->wIndex = cpu_to_le16p(&index); dr->wLength = cpu_to_le16p(&size); - //dbg("usb_control_msg"); + /* dbg("usb_control_msg"); */ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); @@ -147,7 +151,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u return ret; } - +EXPORT_SYMBOL_GPL(usb_control_msg); /** * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion @@ -155,9 +159,11 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * @pipe: endpoint "pipe" to send the message to * @data: pointer to the data to send * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred in bytes + * @actual_length: pointer to a location to put the actual length transferred + * in bytes * @timeout: time in msecs to wait for the message to complete before * timing out (if 0 the wait is forever) + * * Context: !in_interrupt () * * This function sends a simple interrupt message to a specified endpoint and @@ -181,38 +187,38 @@ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, EXPORT_SYMBOL_GPL(usb_interrupt_msg); /** - * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion - * @usb_dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @data: pointer to the data to send - * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple bulk message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns 0, otherwise a negative error number. - * The number of actual bytes transferred will be stored in the - * actual_length paramater. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to - * send a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. - * - * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT - * ioctl, users are forced to abuse this routine by using it to submit - * URBs for interrupt endpoints. We will take the liberty of creating - * an interrupt URB (with the default interval) if the target is an - * interrupt endpoint. + * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred + * in bytes + * @timeout: time in msecs to wait for the message to complete before + * timing out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a simple bulk message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns 0, otherwise a negative error number. The number + * of actual bytes transferred will be stored in the actual_length paramater. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb() If a thread in your + * driver uses this call, make sure your disconnect() method can wait for it to + * complete. Since you don't have a handle on the URB used, you can't cancel + * the request. + * + * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl, + * users are forced to abuse this routine by using it to submit URBs for + * interrupt endpoints. We will take the liberty of creating an interrupt URB + * (with the default interval) if the target is an interrupt endpoint. */ -int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) +int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) { struct urb *urb; struct usb_host_endpoint *ep; @@ -238,29 +244,30 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, return usb_start_wait_urb(urb, timeout, actual_length); } +EXPORT_SYMBOL_GPL(usb_bulk_msg); /*-------------------------------------------------------------------*/ -static void sg_clean (struct usb_sg_request *io) +static void sg_clean(struct usb_sg_request *io) { if (io->urbs) { while (io->entries--) - usb_free_urb (io->urbs [io->entries]); - kfree (io->urbs); + usb_free_urb(io->urbs [io->entries]); + kfree(io->urbs); io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), - io->sg, io->nents); + usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } -static void sg_complete (struct urb *urb) +static void sg_complete(struct urb *urb) { - struct usb_sg_request *io = urb->context; + struct usb_sg_request *io = urb->context; int status = urb->status; - spin_lock (&io->lock); + spin_lock(&io->lock); /* In 2.5 we require hcds' endpoint queues not to progress after fault * reports, until the completion callback (this!) returns. That lets @@ -276,13 +283,13 @@ static void sg_complete (struct urb *urb) && (io->status != -ECONNRESET || status != -ECONNRESET) && urb->actual_length) { - dev_err (io->dev->bus->controller, + dev_err(io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, usb_endpoint_num(&urb->ep->desc), usb_urb_dir_in(urb) ? "in" : "out", status, io->status); - // BUG (); + /* BUG (); */ } if (io->status == 0 && status && status != -ECONNRESET) { @@ -294,22 +301,22 @@ static void sg_complete (struct urb *urb) * unlink pending urbs so they won't rx/tx bad data. * careful: unlink can sometimes be synchronous... */ - spin_unlock (&io->lock); + spin_unlock(&io->lock); for (i = 0, found = 0; i < io->entries; i++) { if (!io->urbs [i] || !io->urbs [i]->dev) continue; if (found) { - retval = usb_unlink_urb (io->urbs [i]); + retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -ENODEV && retval != -EBUSY) - dev_err (&io->dev->dev, + dev_err(&io->dev->dev, "%s, unlink --> %d\n", __FUNCTION__, retval); } else if (urb == io->urbs [i]) found = 1; } - spin_lock (&io->lock); + spin_lock(&io->lock); } urb->dev = NULL; @@ -317,9 +324,9 @@ static void sg_complete (struct urb *urb) io->bytes += urb->actual_length; io->count--; if (!io->count) - complete (&io->complete); + complete(&io->complete); - spin_unlock (&io->lock); + spin_unlock(&io->lock); } @@ -348,28 +355,21 @@ static void sg_complete (struct urb *urb) * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. */ -int usb_sg_init ( - struct usb_sg_request *io, - struct usb_device *dev, - unsigned pipe, - unsigned period, - struct scatterlist *sg, - int nents, - size_t length, - gfp_t mem_flags -) +int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, + unsigned pipe, unsigned period, struct scatterlist *sg, + int nents, size_t length, gfp_t mem_flags) { - int i; - int urb_flags; - int dma; + int i; + int urb_flags; + int dma; if (!io || !dev || !sg - || usb_pipecontrol (pipe) - || usb_pipeisoc (pipe) + || usb_pipecontrol(pipe) + || usb_pipeisoc(pipe) || nents <= 0) return -EINVAL; - spin_lock_init (&io->lock); + spin_lock_init(&io->lock); io->dev = dev; io->pipe = pipe; io->sg = sg; @@ -381,7 +381,7 @@ int usb_sg_init ( dma = (dev->dev.dma_mask != NULL); if (dma) io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), - sg, nents); + sg, nents); else io->entries = nents; @@ -390,30 +390,30 @@ int usb_sg_init ( return io->entries; io->count = io->entries; - io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); + io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; - if (usb_pipein (pipe)) + if (usb_pipein(pipe)) urb_flags |= URB_SHORT_NOT_OK; for (i = 0; i < io->entries; i++) { - unsigned len; + unsigned len; - io->urbs [i] = usb_alloc_urb (0, mem_flags); - if (!io->urbs [i]) { + io->urbs[i] = usb_alloc_urb(0, mem_flags); + if (!io->urbs[i]) { io->entries = i; goto nomem; } - io->urbs [i]->dev = NULL; - io->urbs [i]->pipe = pipe; - io->urbs [i]->interval = period; - io->urbs [i]->transfer_flags = urb_flags; + io->urbs[i]->dev = NULL; + io->urbs[i]->pipe = pipe; + io->urbs[i]->interval = period; + io->urbs[i]->transfer_flags = urb_flags; - io->urbs [i]->complete = sg_complete; - io->urbs [i]->context = io; + io->urbs[i]->complete = sg_complete; + io->urbs[i]->context = io; /* * Some systems need to revert to PIO when DMA is temporarily @@ -432,8 +432,8 @@ int usb_sg_init ( * to prevent stale pointers and to help spot bugs. */ if (dma) { - io->urbs [i]->transfer_dma = sg_dma_address (sg + i); - len = sg_dma_len (sg + i); + io->urbs[i]->transfer_dma = sg_dma_address(sg + i); + len = sg_dma_len(sg + i); #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU) io->urbs[i]->transfer_buffer = NULL; #else @@ -441,31 +441,31 @@ int usb_sg_init ( #endif } else { /* hc may use _only_ transfer_buffer */ - io->urbs [i]->transfer_buffer = sg_virt(&sg[i]); - len = sg [i].length; + io->urbs[i]->transfer_buffer = sg_virt(&sg[i]); + len = sg[i].length; } if (length) { - len = min_t (unsigned, len, length); + len = min_t(unsigned, len, length); length -= len; if (length == 0) io->entries = i + 1; } - io->urbs [i]->transfer_buffer_length = len; + io->urbs[i]->transfer_buffer_length = len; } - io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; + io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; /* transaction state */ io->status = 0; io->bytes = 0; - init_completion (&io->complete); + init_completion(&io->complete); return 0; nomem: - sg_clean (io); + sg_clean(io); return -ENOMEM; } - +EXPORT_SYMBOL_GPL(usb_sg_init); /** * usb_sg_wait - synchronously execute scatter/gather request @@ -506,31 +506,32 @@ nomem: * speed interrupt endpoints, which allow at most one packet per millisecond, * of at most 8 or 64 bytes (respectively). */ -void usb_sg_wait (struct usb_sg_request *io) +void usb_sg_wait(struct usb_sg_request *io) { - int i, entries = io->entries; + int i; + int entries = io->entries; /* queue the urbs. */ - spin_lock_irq (&io->lock); + spin_lock_irq(&io->lock); i = 0; while (i < entries && !io->status) { - int retval; + int retval; - io->urbs [i]->dev = io->dev; - retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC); + io->urbs[i]->dev = io->dev; + retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC); /* after we submit, let completions or cancelations fire; * we handshake using io->status. */ - spin_unlock_irq (&io->lock); + spin_unlock_irq(&io->lock); switch (retval) { /* maybe we retrying will recover */ - case -ENXIO: // hc didn't queue this one + case -ENXIO: /* hc didn't queue this one */ case -EAGAIN: case -ENOMEM: io->urbs[i]->dev = NULL; retval = 0; - yield (); + yield(); break; /* no error? continue immediately. @@ -541,34 +542,35 @@ void usb_sg_wait (struct usb_sg_request *io) */ case 0: ++i; - cpu_relax (); + cpu_relax(); break; /* fail any uncompleted urbs */ default: - io->urbs [i]->dev = NULL; - io->urbs [i]->status = retval; - dev_dbg (&io->dev->dev, "%s, submit --> %d\n", + io->urbs[i]->dev = NULL; + io->urbs[i]->status = retval; + dev_dbg(&io->dev->dev, "%s, submit --> %d\n", __FUNCTION__, retval); - usb_sg_cancel (io); + usb_sg_cancel(io); } - spin_lock_irq (&io->lock); + spin_lock_irq(&io->lock); if (retval && (io->status == 0 || io->status == -ECONNRESET)) io->status = retval; } io->count -= entries - i; if (io->count == 0) - complete (&io->complete); - spin_unlock_irq (&io->lock); + complete(&io->complete); + spin_unlock_irq(&io->lock); /* OK, yes, this could be packaged as non-blocking. * So could the submit loop above ... but it's easier to * solve neither problem than to solve both! */ - wait_for_completion (&io->complete); + wait_for_completion(&io->complete); - sg_clean (io); + sg_clean(io); } +EXPORT_SYMBOL_GPL(usb_sg_wait); /** * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() @@ -578,32 +580,33 @@ void usb_sg_wait (struct usb_sg_request *io) * It can also prevents one initialized by usb_sg_init() from starting, * so that call just frees resources allocated to the request. */ -void usb_sg_cancel (struct usb_sg_request *io) +void usb_sg_cancel(struct usb_sg_request *io) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave (&io->lock, flags); + spin_lock_irqsave(&io->lock, flags); /* shut everything down, if it didn't already */ if (!io->status) { - int i; + int i; io->status = -ECONNRESET; - spin_unlock (&io->lock); + spin_unlock(&io->lock); for (i = 0; i < io->entries; i++) { - int retval; + int retval; if (!io->urbs [i]->dev) continue; - retval = usb_unlink_urb (io->urbs [i]); + retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -EBUSY) - dev_warn (&io->dev->dev, "%s, unlink --> %d\n", + dev_warn(&io->dev->dev, "%s, unlink --> %d\n", __FUNCTION__, retval); } - spin_lock (&io->lock); + spin_lock(&io->lock); } - spin_unlock_irqrestore (&io->lock, flags); + spin_unlock_irqrestore(&io->lock, flags); } +EXPORT_SYMBOL_GPL(usb_sg_cancel); /*-------------------------------------------------------------------*/ @@ -629,12 +632,13 @@ void usb_sg_cancel (struct usb_sg_request *io) * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +int usb_get_descriptor(struct usb_device *dev, unsigned char type, + unsigned char index, void *buf, int size) { int i; int result; - - memset(buf,0,size); // Make sure we parse really received data + + memset(buf, 0, size); /* Make sure we parse really received data */ for (i = 0; i < 3; ++i) { /* retry on length 0 or error; some devices are flakey */ @@ -652,6 +656,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char } return result; } +EXPORT_SYMBOL_GPL(usb_get_descriptor); /** * usb_get_string - gets a string descriptor @@ -708,7 +713,7 @@ static void usb_try_string_workarounds(unsigned char *buf, int *length) } static int usb_string_sub(struct usb_device *dev, unsigned int langid, - unsigned int index, unsigned char *buf) + unsigned int index, unsigned char *buf) { int rc; @@ -751,7 +756,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, * @buf: where to put the string * @size: how big is "buf"? * Context: !in_interrupt () - * + * * This converts the UTF-16LE encoded strings returned by devices, from * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones * that are more usable in most kernel contexts. Note that all characters @@ -787,23 +792,23 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (!dev->have_langid) { err = usb_string_sub(dev, 0, 0, tbuf); if (err < 0) { - dev_err (&dev->dev, + dev_err(&dev->dev, "string descriptor 0 read error: %d\n", err); goto errout; } else if (err < 4) { - dev_err (&dev->dev, "string descriptor 0 too short\n"); + dev_err(&dev->dev, "string descriptor 0 too short\n"); err = -EINVAL; goto errout; } else { dev->have_langid = 1; - dev->string_langid = tbuf[2] | (tbuf[3]<< 8); - /* always use the first langid listed */ - dev_dbg (&dev->dev, "default language 0x%04x\n", + dev->string_langid = tbuf[2] | (tbuf[3] << 8); + /* always use the first langid listed */ + dev_dbg(&dev->dev, "default language 0x%04x\n", dev->string_langid); } } - + err = usb_string_sub(dev, dev->string_langid, index, tbuf); if (err < 0) goto errout; @@ -821,12 +826,15 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = idx; if (tbuf[1] != USB_DT_STRING) - dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf); + dev_dbg(&dev->dev, + "wrong descriptor type %02x for string %d (\"%s\")\n", + tbuf[1], index, buf); errout: kfree(tbuf); return err; } +EXPORT_SYMBOL_GPL(usb_string); /** * usb_cache_string - read a string descriptor and cache it for later use @@ -842,9 +850,15 @@ char *usb_cache_string(struct usb_device *udev, int index) char *smallbuf = NULL; int len; - if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) { - if ((len = usb_string(udev, index, buf, 256)) > 0) { - if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL) + if (index <= 0) + return NULL; + + buf = kmalloc(256, GFP_KERNEL); + if (buf) { + len = usb_string(udev, index, buf, 256); + if (len > 0) { + smallbuf = kmalloc(++len, GFP_KERNEL); + if (!smallbuf) return buf; memcpy(smallbuf, buf, len); } @@ -883,7 +897,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) return -ENOMEM; ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); - if (ret >= 0) + if (ret >= 0) memcpy(&dev->descriptor, desc, size); kfree(desc); return ret; @@ -927,6 +941,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data) kfree(status); return ret; } +EXPORT_SYMBOL_GPL(usb_get_status); /** * usb_clear_halt - tells device to clear endpoint halt/stall condition @@ -955,8 +970,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe) { int result; int endp = usb_pipeendpoint(pipe); - - if (usb_pipein (pipe)) + + if (usb_pipein(pipe)) endp |= USB_DIR_IN; /* we don't care if it wasn't halted first. in fact some devices @@ -985,6 +1000,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) return 0; } +EXPORT_SYMBOL_GPL(usb_clear_halt); /** * usb_disable_endpoint -- Disable an endpoint by address @@ -1038,7 +1054,7 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) } } -/* +/** * usb_disable_device - Disable all the endpoints for a USB device * @dev: the device whose endpoints are being disabled * @skip_ep0: 0 to disable endpoint 0, 1 to skip it. @@ -1053,7 +1069,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) int i; dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__, - skip_ep0 ? "non-ep0" : "all"); + skip_ep0 ? "non-ep0" : "all"); for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i); usb_disable_endpoint(dev, i + USB_DIR_IN); @@ -1071,17 +1087,17 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) interface = dev->actconfig->interface[i]; if (!device_is_registered(&interface->dev)) continue; - dev_dbg (&dev->dev, "unregistering interface %s\n", + dev_dbg(&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); - device_del (&interface->dev); + device_del(&interface->dev); } /* Now that the interfaces are unbound, nobody should * try to access them. */ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - put_device (&dev->actconfig->interface[i]->dev); + put_device(&dev->actconfig->interface[i]->dev); dev->actconfig->interface[i] = NULL; } dev->actconfig = NULL; @@ -1090,8 +1106,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) } } - -/* +/** * usb_enable_endpoint - Enable an endpoint for USB communications * @dev: the device whose interface is being enabled * @ep: the endpoint @@ -1116,7 +1131,7 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) ep->enabled = 1; } -/* +/** * usb_enable_interface - Enable all the endpoints for an interface * @dev: the device whose interface is being enabled * @intf: pointer to the interface descriptor @@ -1172,6 +1187,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + unsigned int epaddr; + unsigned int pipe; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1226,11 +1243,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) int i; for (i = 0; i < alt->desc.bNumEndpoints; i++) { - unsigned int epaddr = - alt->endpoint[i].desc.bEndpointAddress; - unsigned int pipe = - __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr) - | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN); + epaddr = alt->endpoint[i].desc.bEndpointAddress; + pipe = __create_pipe(dev, + USB_ENDPOINT_NUMBER_MASK & epaddr) | + (usb_endpoint_out(epaddr) ? + USB_DIR_OUT : USB_DIR_IN); usb_clear_halt(dev, pipe); } @@ -1253,6 +1270,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return 0; } +EXPORT_SYMBOL_GPL(usb_set_interface); /** * usb_reset_configuration - lightweight device reset @@ -1328,6 +1346,7 @@ int usb_reset_configuration(struct usb_device *dev) } return 0; } +EXPORT_SYMBOL_GPL(usb_reset_configuration); static void usb_release_interface(struct device *dev) { @@ -1357,7 +1376,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; if (add_uevent_var(env, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + "MODALIAS=usb:" + "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice), @@ -1387,8 +1407,8 @@ struct device_type usb_if_device_type = { }; static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, - struct usb_host_config *config, - u8 inum) + struct usb_host_config *config, + u8 inum) { struct usb_interface_assoc_descriptor *retval = NULL; struct usb_interface_assoc_descriptor *intf_assoc; @@ -1415,7 +1435,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, return retval; } - /* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated @@ -1533,12 +1552,12 @@ free_interfaces: * getting rid of old interfaces means unbinding their drivers. */ if (dev->state != USB_STATE_ADDRESS) - usb_disable_device (dev, 1); // Skip ep0 - - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { + usb_disable_device(dev, 1); /* Skip ep0 */ + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) { /* All the old state is gone, so what else can we do? * The device is probably useless now anyway. */ @@ -1585,11 +1604,11 @@ free_interfaces: intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; intf->dev.dma_mask = dev->dev.dma_mask; - device_initialize (&intf->dev); + device_initialize(&intf->dev); mark_quiesced(intf); - sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, alt->desc.bInterfaceNumber); + sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d", + dev->bus->busnum, dev->devpath, + configuration, alt->desc.bInterfaceNumber); } kfree(new_interfaces); @@ -1605,11 +1624,11 @@ free_interfaces: for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; - dev_dbg (&dev->dev, + dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, intf->cur_altsetting->desc.bInterfaceNumber); - ret = device_add (&intf->dev); + ret = device_add(&intf->dev); if (ret != 0) { dev_err(&dev->dev, "device_add(%s) --> %d\n", intf->dev.bus_id, ret); @@ -1677,22 +1696,3 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); - -// synchronous request completion model -EXPORT_SYMBOL(usb_control_msg); -EXPORT_SYMBOL(usb_bulk_msg); - -EXPORT_SYMBOL(usb_sg_init); -EXPORT_SYMBOL(usb_sg_cancel); -EXPORT_SYMBOL(usb_sg_wait); - -// synchronous control message convenience routines -EXPORT_SYMBOL(usb_get_descriptor); -EXPORT_SYMBOL(usb_get_status); -EXPORT_SYMBOL(usb_string); - -// synchronous calls that also maintain usbcore state -EXPORT_SYMBOL(usb_clear_halt); -EXPORT_SYMBOL(usb_reset_configuration); -EXPORT_SYMBOL(usb_set_interface); - diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 6b36897ca151..7542dce3f5a1 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(usb_register_notify); * usb_unregister_notify - unregister a notifier callback * @nb: pointer to the notifier block for the callback events. * - * usb_register_notifier() must have been previously called for this function + * usb_register_notify() must have been previously called for this function * to work properly. */ void usb_unregister_notify(struct notifier_block *nb) diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 7f31a495a25d..e8cdce571bb1 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -14,7 +14,7 @@ * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. * * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! - */ + */ static struct usb_device_id whitelist_table [] = { @@ -55,7 +55,7 @@ static int is_targeted(struct usb_device *dev) return 1; /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) return 0; @@ -86,7 +86,7 @@ static int is_targeted(struct usb_device *dev) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 32bd130b1eed..a37ccbd1e007 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -72,7 +72,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, return (value < 0) ? value : count; } -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, show_bConfigurationValue, set_bConfigurationValue); /* String fields */ @@ -249,6 +249,41 @@ static void remove_persist_attributes(struct device *dev) #ifdef CONFIG_USB_SUSPEND static ssize_t +show_connected_duration(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + + return sprintf(buf, "%u\n", + jiffies_to_msecs(jiffies - udev->connect_time)); +} + +static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL); + +/* + * If the device is resumed, the last time the device was suspended has + * been pre-subtracted from active_duration. We add the current time to + * get the duration that the device was actually active. + * + * If the device is suspended, the active_duration is up-to-date. + */ +static ssize_t +show_active_duration(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + int duration; + + if (udev->state != USB_STATE_SUSPENDED) + duration = jiffies_to_msecs(jiffies + udev->active_duration); + else + duration = jiffies_to_msecs(udev->active_duration); + return sprintf(buf, "%u\n", duration); +} + +static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); + +static ssize_t show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); @@ -365,6 +400,14 @@ static int add_power_attributes(struct device *dev) rc = sysfs_add_file_to_group(&dev->kobj, &dev_attr_level.attr, power_group); + if (rc == 0) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_connected_duration.attr, + power_group); + if (rc == 0) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_active_duration.attr, + power_group); } return rc; } @@ -372,6 +415,12 @@ static int add_power_attributes(struct device *dev) static void remove_power_attributes(struct device *dev) { sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_active_duration.attr, + power_group); + sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_connected_duration.attr, + power_group); + sysfs_remove_file_from_group(&dev->kobj, &dev_attr_level.attr, power_group); sysfs_remove_file_from_group(&dev->kobj, @@ -601,21 +650,21 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) /* Interface Accociation Descriptor fields */ #define usb_intf_assoc_attr(field, format_string) \ static ssize_t \ -show_iad_##field (struct device *dev, struct device_attribute *attr, \ +show_iad_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct usb_interface *intf = to_usb_interface (dev); \ + struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf (buf, format_string, \ - intf->intf_assoc->field); \ + return sprintf(buf, format_string, \ + intf->intf_assoc->field); \ } \ static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL); -usb_intf_assoc_attr (bFirstInterface, "%02x\n") -usb_intf_assoc_attr (bInterfaceCount, "%02d\n") -usb_intf_assoc_attr (bFunctionClass, "%02x\n") -usb_intf_assoc_attr (bFunctionSubClass, "%02x\n") -usb_intf_assoc_attr (bFunctionProtocol, "%02x\n") +usb_intf_assoc_attr(bFirstInterface, "%02x\n") +usb_intf_assoc_attr(bInterfaceCount, "%02d\n") +usb_intf_assoc_attr(bFunctionClass, "%02x\n") +usb_intf_assoc_attr(bFunctionSubClass, "%02x\n") +usb_intf_assoc_attr(bFunctionProtocol, "%02x\n") /* Interface fields */ #define usb_intf_attr(field, format_string) \ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index d05ead20081c..9d7e63292c01 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -42,6 +42,7 @@ void usb_init_urb(struct urb *urb) INIT_LIST_HEAD(&urb->anchor_list); } } +EXPORT_SYMBOL_GPL(usb_init_urb); /** * usb_alloc_urb - creates a new urb for a USB driver to use @@ -73,6 +74,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) usb_init_urb(urb); return urb; } +EXPORT_SYMBOL_GPL(usb_alloc_urb); /** * usb_free_urb - frees the memory used by a urb when all users of it are finished @@ -89,6 +91,7 @@ void usb_free_urb(struct urb *urb) if (urb) kref_put(&urb->kref, urb_destroy); } +EXPORT_SYMBOL_GPL(usb_free_urb); /** * usb_get_urb - increments the reference count of the urb @@ -100,12 +103,13 @@ void usb_free_urb(struct urb *urb) * * A pointer to the urb with the incremented reference counter is returned. */ -struct urb * usb_get_urb(struct urb *urb) +struct urb *usb_get_urb(struct urb *urb) { if (urb) kref_get(&urb->kref); return urb; } +EXPORT_SYMBOL_GPL(usb_get_urb); /** * usb_anchor_urb - anchors an URB while it is processed @@ -172,7 +176,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink - * (a software-induced fault, also called "request cancellation"). + * (a software-induced fault, also called "request cancellation"). * * URBs may be submitted in interrupt context. * @@ -255,7 +259,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * semaphores), or * (c) current->state != TASK_RUNNING, this is the case only after * you've changed it. - * + * * GFP_NOIO is used in the block io path and error handling of storage * devices. * @@ -284,7 +288,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) + dev = urb->dev; + if ((!dev) || (dev->state < USB_STATE_DEFAULT)) return -ENODEV; /* For now, get the endpoint from the pipe. Eventually drivers @@ -347,11 +352,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) max *= mult; } - if (urb->number_of_packets <= 0) + if (urb->number_of_packets <= 0) return -EINVAL; for (n = 0; n < urb->number_of_packets; n++) { len = urb->iso_frame_desc[n].length; - if (len < 0 || len > max) + if (len < 0 || len > max) return -EMSGSIZE; urb->iso_frame_desc[n].status = -EXDEV; urb->iso_frame_desc[n].actual_length = 0; @@ -416,7 +421,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* too big? */ switch (dev->speed) { case USB_SPEED_HIGH: /* units are microframes */ - // NOTE usb handles 2^15 + /* NOTE usb handles 2^15 */ if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; max = 1024 * 8; @@ -426,12 +431,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; - // NOTE ohci only handles up to 32 + /* NOTE ohci only handles up to 32 */ max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; - // NOTE usb and ohci handle up to 2^15 + /* NOTE usb and ohci handle up to 2^15 */ max = 1024; } break; @@ -444,6 +449,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return usb_hcd_submit_urb(urb, mem_flags); } +EXPORT_SYMBOL_GPL(usb_submit_urb); /*-------------------------------------------------------------------*/ @@ -514,6 +520,7 @@ int usb_unlink_urb(struct urb *urb) return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } +EXPORT_SYMBOL_GPL(usb_unlink_urb); /** * usb_kill_urb - cancel a transfer request and wait for it to finish @@ -553,6 +560,7 @@ void usb_kill_urb(struct urb *urb) --urb->reject; mutex_unlock(&reject_mutex); } +EXPORT_SYMBOL_GPL(usb_kill_urb); /** * usb_kill_anchored_urbs - cancel transfer requests en masse @@ -567,7 +575,8 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor) spin_lock_irq(&anchor->lock); while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list); + victim = list_entry(anchor->urb_list.prev, struct urb, + anchor_list); /* we must make sure the URB isn't freed before we kill it*/ usb_get_urb(victim); spin_unlock_irq(&anchor->lock); @@ -595,11 +604,3 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, msecs_to_jiffies(timeout)); } EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); - -EXPORT_SYMBOL(usb_init_urb); -EXPORT_SYMBOL(usb_alloc_urb); -EXPORT_SYMBOL(usb_free_urb); -EXPORT_SYMBOL(usb_get_urb); -EXPORT_SYMBOL(usb_submit_urb); -EXPORT_SYMBOL(usb_unlink_urb); -EXPORT_SYMBOL(usb_kill_urb); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8f142370103d..4e984060c984 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -96,6 +96,7 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, return NULL; } +EXPORT_SYMBOL_GPL(usb_ifnum_to_if); /** * usb_altnum_to_altsetting - get the altsetting structure with a given @@ -115,8 +116,9 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, * Don't call this function unless you are bound to the intf interface * or you have locked the device! */ -struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf, - unsigned int altnum) +struct usb_host_interface *usb_altnum_to_altsetting( + const struct usb_interface *intf, + unsigned int altnum) { int i; @@ -126,13 +128,14 @@ struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface * } return NULL; } +EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); struct find_interface_arg { int minor; struct usb_interface *interface; }; -static int __find_interface(struct device * dev, void * data) +static int __find_interface(struct device *dev, void *data) { struct find_interface_arg *arg = data; struct usb_interface *intf; @@ -154,7 +157,7 @@ static int __find_interface(struct device * dev, void * data) * @drv: the driver whose current configuration is considered * @minor: the minor number of the desired device * - * This walks the driver device list and returns a pointer to the interface + * This walks the driver device list and returns a pointer to the interface * with the matching minor. Note, this only works for devices that share the * USB major number. */ @@ -170,6 +173,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) __find_interface); return argb.interface; } +EXPORT_SYMBOL_GPL(usb_find_interface); /** * usb_release_dev - free a usb device structure when all users of it are finished. @@ -230,7 +234,7 @@ static int ksuspend_usb_init(void) * singlethreaded. Its job doesn't justify running on more * than one CPU. */ - ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd"); + ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd"); if (!ksuspend_usb_wq) return -ENOMEM; return 0; @@ -269,8 +273,8 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) * * This call may not be used in a non-sleeping context. */ -struct usb_device * -usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) +struct usb_device *usb_alloc_dev(struct usb_device *parent, + struct usb_bus *bus, unsigned port1) { struct usb_device *dev; struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); @@ -339,6 +343,8 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; + dev->connect_time = jiffies; + dev->active_duration = -jiffies; #endif if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; @@ -367,6 +373,7 @@ struct usb_device *usb_get_dev(struct usb_device *dev) get_device(&dev->dev); return dev; } +EXPORT_SYMBOL_GPL(usb_get_dev); /** * usb_put_dev - release a use of the usb device structure @@ -380,6 +387,7 @@ void usb_put_dev(struct usb_device *dev) if (dev) put_device(&dev->dev); } +EXPORT_SYMBOL_GPL(usb_put_dev); /** * usb_get_intf - increments the reference count of the usb interface structure @@ -400,6 +408,7 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf) get_device(&intf->dev); return intf; } +EXPORT_SYMBOL_GPL(usb_get_intf); /** * usb_put_intf - release a use of the usb interface structure @@ -414,7 +423,7 @@ void usb_put_intf(struct usb_interface *intf) if (intf) put_device(&intf->dev); } - +EXPORT_SYMBOL_GPL(usb_put_intf); /* USB device locking * @@ -461,11 +470,11 @@ int usb_lock_device_for_reset(struct usb_device *udev, return -EHOSTUNREACH; if (iface) { switch (iface->condition) { - case USB_INTERFACE_BINDING: + case USB_INTERFACE_BINDING: return 0; - case USB_INTERFACE_BOUND: + case USB_INTERFACE_BOUND: break; - default: + default: return -EINTR; } } @@ -487,7 +496,7 @@ int usb_lock_device_for_reset(struct usb_device *udev, } return 1; } - +EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) @@ -540,10 +549,10 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) struct list_head *buslist; struct usb_bus *bus; struct usb_device *dev = NULL; - + mutex_lock(&usb_bus_list_lock); for (buslist = usb_bus_list.next; - buslist != &usb_bus_list; + buslist != &usb_bus_list; buslist = buslist->next) { bus = container_of(buslist, struct usb_bus, bus_list); if (!bus->root_hub) @@ -576,6 +585,7 @@ int usb_get_current_frame_number(struct usb_device *dev) { return usb_hcd_get_frame_number(dev); } +EXPORT_SYMBOL_GPL(usb_get_current_frame_number); /*-------------------------------------------------------------------*/ /* @@ -584,7 +594,7 @@ int usb_get_current_frame_number(struct usb_device *dev) */ int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr) + unsigned char type, void **ptr) { struct usb_descriptor_header *header; @@ -595,7 +605,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, printk(KERN_ERR "%s: bogus descriptor, type %d length %d\n", usbcore_name, - header->bDescriptorType, + header->bDescriptorType, header->bLength); return -1; } @@ -610,6 +620,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, } return -1; } +EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); /** * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP @@ -633,17 +644,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc( - struct usb_device *dev, - size_t size, - gfp_t mem_flags, - dma_addr_t *dma -) +void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, + dma_addr_t *dma) { if (!dev || !dev->bus) return NULL; return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_alloc); /** * usb_buffer_free - free memory allocated with usb_buffer_alloc() @@ -656,12 +664,8 @@ void *usb_buffer_alloc( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free( - struct usb_device *dev, - size_t size, - void *addr, - dma_addr_t dma -) +void usb_buffer_free(struct usb_device *dev, size_t size, void *addr, + dma_addr_t dma) { if (!dev || !dev->bus) return; @@ -669,6 +673,7 @@ void usb_buffer_free( return; hcd_buffer_free(dev->bus, size, addr, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_free); /** * usb_buffer_map - create DMA mapping(s) for an urb @@ -708,14 +713,15 @@ struct urb *usb_buffer_map(struct urb *urb) urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - // FIXME generic api broken like pci, can't report errors - // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; + /* FIXME generic api broken like pci, can't report errors */ + /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */ } else urb->transfer_dma = ~0; urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); return urb; } +EXPORT_SYMBOL_GPL(usb_buffer_map); #endif /* 0 */ /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -753,6 +759,7 @@ void usb_buffer_dmasync(struct urb *urb) DMA_TO_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync); #endif /** @@ -788,6 +795,7 @@ void usb_buffer_unmap(struct urb *urb) urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap); #endif /* 0 */ /** @@ -828,10 +836,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in, || !controller->dma_mask) return -1; - // FIXME generic api broken like pci, can't report errors + /* FIXME generic api broken like pci, can't report errors */ return dma_map_sg(controller, sg, nents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_map_sg); /* XXX DISABLED, no users currently. If you wish to re-enable this * XXX please determine whether the sync is to transfer ownership of @@ -865,6 +874,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, dma_sync_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); #endif /** @@ -891,6 +901,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, dma_unmap_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); /* format to disable USB on kernel command line is: nousb */ __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444); @@ -902,6 +913,7 @@ int usb_disabled(void) { return nousb; } +EXPORT_SYMBOL_GPL(usb_disabled); /* * Init @@ -918,7 +930,7 @@ static int __init usb_init(void) if (retval) goto out; retval = bus_register(&usb_bus_type); - if (retval) + if (retval) goto bus_register_failed; retval = usb_host_init(); if (retval) @@ -983,45 +995,4 @@ static void __exit usb_exit(void) subsys_initcall(usb_init); module_exit(usb_exit); - -/* - * USB may be built into the kernel or be built as modules. - * These symbols are exported for device (or host controller) - * driver modules to use. - */ - -EXPORT_SYMBOL(usb_disabled); - -EXPORT_SYMBOL_GPL(usb_get_intf); -EXPORT_SYMBOL_GPL(usb_put_intf); - -EXPORT_SYMBOL(usb_put_dev); -EXPORT_SYMBOL(usb_get_dev); -EXPORT_SYMBOL(usb_hub_tt_clear_buffer); - -EXPORT_SYMBOL(usb_lock_device_for_reset); - -EXPORT_SYMBOL(usb_find_interface); -EXPORT_SYMBOL(usb_ifnum_to_if); -EXPORT_SYMBOL(usb_altnum_to_altsetting); - -EXPORT_SYMBOL(__usb_get_extra_descriptor); - -EXPORT_SYMBOL(usb_get_current_frame_number); - -EXPORT_SYMBOL(usb_buffer_alloc); -EXPORT_SYMBOL(usb_buffer_free); - -#if 0 -EXPORT_SYMBOL(usb_buffer_map); -EXPORT_SYMBOL(usb_buffer_dmasync); -EXPORT_SYMBOL(usb_buffer_unmap); -#endif - -EXPORT_SYMBOL(usb_buffer_map_sg); -#if 0 -EXPORT_SYMBOL(usb_buffer_dmasync_sg); -#endif -EXPORT_SYMBOL(usb_buffer_unmap_sg); - MODULE_LICENSE("GPL"); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index c52626c51f70..2375194a9d43 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,22 +1,23 @@ /* Functions local to drivers/usb/core/ */ -extern int usb_create_sysfs_dev_files (struct usb_device *dev); -extern void usb_remove_sysfs_dev_files (struct usb_device *dev); -extern int usb_create_sysfs_intf_files (struct usb_interface *intf); -extern void usb_remove_sysfs_intf_files (struct usb_interface *intf); -extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, +extern int usb_create_sysfs_dev_files(struct usb_device *dev); +extern void usb_remove_sysfs_dev_files(struct usb_device *dev); +extern int usb_create_sysfs_intf_files(struct usb_interface *intf); +extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); +extern int usb_create_ep_files(struct device *parent, + struct usb_host_endpoint *endpoint, struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); extern void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep); -extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); -extern void usb_disable_interface (struct usb_device *dev, +extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr); +extern void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); -extern void usb_disable_device (struct usb_device *dev, int skip_ep0); -extern int usb_deauthorize_device (struct usb_device *); -extern int usb_authorize_device (struct usb_device *); +extern void usb_disable_device(struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device(struct usb_device *); +extern int usb_authorize_device(struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 77a3759d6fc7..c13955164686 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -12,10 +12,9 @@ # With help from a special transceiver and a "Mini-AB" jack, systems with # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). # -menu "USB Gadget Support" -config USB_GADGET - tristate "Support for USB Gadgets" +menuconfig USB_GADGET + tristate "USB Gadget Support" help USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. @@ -42,6 +41,8 @@ config USB_GADGET For more information, see <http://www.linux-usb.org/gadget> and the kernel DocBook documentation for this API. +if USB_GADGET + config USB_GADGET_DEBUG boolean "Debugging messages" depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL @@ -220,6 +221,16 @@ config USB_M66592 default USB_GADGET select USB_GADGET_SELECTED +config SUPERH_BUILT_IN_M66592 + boolean "Enable SuperH built-in USB like the M66592" + depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722 + help + SH7722 has USB like the M66592. + + The transfer rate is very slow when use "Ethernet Gadget". + However, this problem is improved if change a value of + NET_IP_ALIGN to 4. + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI @@ -538,6 +549,20 @@ config USB_MIDI_GADGET Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_midi". +config USB_G_PRINTER + tristate "Printer Gadget" + help + The Printer Gadget channels data between the USB host and a + userspace program driving the print engine. The user space + program reads and writes the device file /dev/g_printer to + receive or send printer data. It can use ioctl calls to + the device file to get or set printer status. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_printer". + + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. # put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. @@ -546,4 +571,4 @@ config USB_MIDI_GADGET endchoice -endmenu +endif # USB_GADGET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 904e57bf6112..c3aab80b6c76 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,8 @@ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o +g_printer-objs := printer.o usbstring.o config.o \ + epautoconf.o ifeq ($(CONFIG_USB_ETH_RNDIS),y) g_ether-objs += rndis.o @@ -38,5 +40,6 @@ obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o +obj-$(CONFIG_USB_G_PRINTER) += g_printer.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index c72e9620bf8d..b663f23f2642 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1244,7 +1244,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) /* stop OUT naking */ if (!ep->in) { if (!use_dma && udc_rxfifo_pending) { - DBG(dev, "udc_queue(): pending bytes in" + DBG(dev, "udc_queue(): pending bytes in " "rxfifo after nyet\n"); /* * read pending bytes afer nyet: @@ -2038,6 +2038,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; dev->driver = NULL; /* set SD */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index cd62b029d176..a83e8b798ec9 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,8 +21,7 @@ * Boston, MA 02111-1307, USA. */ -#undef DEBUG -#undef VERBOSE +#undef VERBOSE_DEBUG #undef PACKET_TRACE #include <linux/kernel.h> @@ -46,8 +45,8 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/mach-types.h> +#include <asm/gpio.h> -#include <asm/arch/gpio.h> #include <asm/arch/board.h> #include <asm/arch/cpu.h> #include <asm/arch/at91sam9261_matrix.h> @@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep) */ static struct usb_request * -at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags) +at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct at91_request *req; @@ -881,6 +880,8 @@ static void clk_off(struct at91_udc *udc) */ static void pullup(struct at91_udc *udc, int is_on) { + int active = !udc->board.pullup_active_low; + if (!udc->enabled || !udc->vbus) is_on = 0; DBG("%sactive\n", is_on ? "" : "in"); @@ -890,7 +891,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, 0); if (cpu_is_at91rm9200()) - at91_set_gpio_value(udc->board.pullup_pin, 1); + gpio_set_value(udc->board.pullup_pin, active); else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); @@ -908,7 +909,7 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); if (cpu_is_at91rm9200()) - at91_set_gpio_value(udc->board.pullup_pin, 0); + gpio_set_value(udc->board.pullup_pin, !active); else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); @@ -1153,7 +1154,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_GET_STATUS: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc)) + if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) goto stall; if (tmp) { @@ -1176,7 +1177,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_SET_FEATURE: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; if (!ep->desc || ep->is_iso) goto stall; @@ -1195,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_CLEAR_FEATURE: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; if (tmp == 0) goto succeed; @@ -1551,7 +1552,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc) /* vbus needs at least brief debouncing */ udelay(10); - value = at91_get_gpio_value(udc->board.vbus_pin); + value = gpio_get_value(udc->board.vbus_pin); if (value != udc->vbus) at91_vbus_session(&udc->gadget, value); @@ -1616,6 +1617,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) local_irq_enable(); driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->gadget.dev.driver_data = NULL; udc->driver = NULL; DBG("unbound from %s\n", driver->driver.name); @@ -1645,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev) } if (pdev->num_resources != 2) { - DBG("invalid num_resources"); + DBG("invalid num_resources\n"); return -ENODEV; } if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) { - DBG("invalid resource type"); + DBG("invalid resource type\n"); return -ENODEV; } @@ -1672,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev) udc->pdev = pdev; udc->enabled = 0; + /* rm9200 needs manual D+ pullup; off by default */ + if (cpu_is_at91rm9200()) { + if (udc->board.pullup_pin <= 0) { + DBG("no D+ pullup?\n"); + retval = -ENODEV; + goto fail0; + } + retval = gpio_request(udc->board.pullup_pin, "udc_pullup"); + if (retval) { + DBG("D+ pullup is busy\n"); + goto fail0; + } + gpio_direction_output(udc->board.pullup_pin, + udc->board.pullup_active_low); + } + udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1); if (!udc->udp_baseaddr) { - release_mem_region(res->start, res->end - res->start + 1); - return -ENOMEM; + retval = -ENOMEM; + goto fail0a; } udc_reinit(udc); @@ -1686,12 +1705,13 @@ static int __init at91udc_probe(struct platform_device *pdev) if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG("clocks missing\n"); retval = -ENODEV; - goto fail0; + /* NOTE: we "know" here that refcounts on these are NOPs */ + goto fail0b; } retval = device_register(&udc->gadget.dev); if (retval < 0) - goto fail0; + goto fail0b; /* don't do anything until we have both gadget driver and VBUS */ clk_enable(udc->iclk); @@ -1703,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev) /* request UDC and maybe VBUS irqs */ udc->udp_irq = platform_get_irq(pdev, 0); - if (request_irq(udc->udp_irq, at91_udc_irq, - IRQF_DISABLED, driver_name, udc)) { + retval = request_irq(udc->udp_irq, at91_udc_irq, + IRQF_DISABLED, driver_name, udc); + if (retval < 0) { DBG("request irq %d failed\n", udc->udp_irq); - retval = -EBUSY; goto fail1; } if (udc->board.vbus_pin > 0) { + retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); + if (retval < 0) { + DBG("request vbus pin failed\n"); + goto fail2; + } + gpio_direction_input(udc->board.vbus_pin); + /* * Get the initial state of VBUS - we cannot expect * a pending interrupt. */ - udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); + udc->vbus = gpio_get_value(udc->board.vbus_pin); if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { DBG("request vbus irq %d failed\n", udc->board.vbus_pin); free_irq(udc->udp_irq, udc); retval = -EBUSY; - goto fail1; + goto fail3; } } else { DBG("no VBUS detection, assuming always-on\n"); @@ -1734,8 +1761,18 @@ static int __init at91udc_probe(struct platform_device *pdev) INFO("%s version %s\n", driver_name, DRIVER_VERSION); return 0; +fail3: + if (udc->board.vbus_pin > 0) + gpio_free(udc->board.vbus_pin); +fail2: + free_irq(udc->udp_irq, udc); fail1: device_unregister(&udc->gadget.dev); +fail0b: + iounmap(udc->udp_baseaddr); +fail0a: + if (cpu_is_at91rm9200()) + gpio_free(udc->board.pullup_pin); fail0: release_mem_region(res->start, res->end - res->start + 1); DBG("%s probe failed, %d\n", driver_name, retval); @@ -1756,12 +1793,18 @@ static int __exit at91udc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); - if (udc->board.vbus_pin > 0) + if (udc->board.vbus_pin > 0) { free_irq(udc->board.vbus_pin, udc); + gpio_free(udc->board.vbus_pin); + } free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); iounmap(udc->udp_baseaddr); + + if (cpu_is_at91rm9200()) + gpio_free(udc->board.pullup_pin); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, res->end - res->start + 1); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 7e34e2f864f9..a973f2a50fb9 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -53,7 +53,7 @@ #define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ #define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ -#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ +#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrupt Status */ #define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ @@ -158,13 +158,7 @@ struct at91_request { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG # define VDBG DBG #else # define VDBG(stuff...) do{}while(0) @@ -176,9 +170,10 @@ struct at91_request { # define PACKET(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) +#define DBG(stuff...) pr_debug("udc: " stuff) #endif diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 4fb5ff469574..af8b2a3a2d4a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1384,8 +1384,7 @@ delegate: return retval; stall: - printk(KERN_ERR - "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " "halting endpoint...\n", ep->ep.name, crq->bRequestType, crq->bRequest, le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), @@ -1456,8 +1455,7 @@ restart: set_protocol_stall(udc, ep); break; default: - printk(KERN_ERR - "udc: %s: TXCOMP: Invalid endpoint state %d, " + pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, " "halting endpoint...\n", ep->ep.name, ep->state); set_protocol_stall(udc, ep); @@ -1486,8 +1484,7 @@ restart: default: usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - printk(KERN_ERR - "udc: %s: RXRDY: Invalid endpoint state %d, " + pr_err("udc: %s: RXRDY: Invalid endpoint state %d, " "halting endpoint...\n", ep->ep.name, ep->state); set_protocol_stall(udc, ep); @@ -1532,7 +1529,7 @@ restart: pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); DBG(DBG_HW, "Packet length: %u\n", pkt_len); if (pkt_len != sizeof(crq)) { - printk(KERN_WARNING "udc: Invalid packet length %u " + pr_warning("udc: Invalid packet length %u " "(expected %lu)\n", pkt_len, sizeof(crq)); set_protocol_stall(udc, ep); return; diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index a68304e31a68..08bf6f9aaf7e 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -216,7 +216,6 @@ #define FIFO_IOMEM_ID 0 #define CTRL_IOMEM_ID 1 -#ifdef DEBUG #define DBG_ERR 0x0001 /* report all error returns */ #define DBG_HW 0x0002 /* debug hardware initialization */ #define DBG_GADGET 0x0004 /* calls to/from gadget driver */ @@ -230,14 +229,12 @@ #define DBG_NONE 0x0000 #define DEBUG_LEVEL (DBG_ERR) + #define DBG(level, fmt, ...) \ do { \ if ((level) & DEBUG_LEVEL) \ - printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + pr_debug("udc: " fmt, ## __VA_ARGS__); \ } while (0) -#else -#define DBG(level, fmt...) -#endif enum usba_ctrl_state { WAIT_FOR_SETUP, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 9db2482bdfa2..cbe44535c0f0 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -61,6 +61,8 @@ #define DRIVER_DESC "USB Host+Gadget Emulator" #define DRIVER_VERSION "02 May 2005" +#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ + static const char driver_name [] = "dummy_hcd"; static const char driver_desc [] = "USB Host+Gadget Emulator"; @@ -772,18 +774,17 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) list_del_init (&dum->ep [0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); + driver->driver.bus = NULL; dum->driver = driver; dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = driver->bind (&dum->gadget)) != 0) - goto err_bind_gadget; - - driver->driver.bus = dum->gadget.dev.parent->bus; - if ((retval = driver_register (&driver->driver)) != 0) - goto err_register; - if ((retval = device_bind_driver (&dum->gadget.dev)) != 0) - goto err_bind_driver; + retval = driver->bind(&dum->gadget); + if (retval) { + dum->driver = NULL; + dum->gadget.dev.driver = NULL; + return retval; + } /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); @@ -793,20 +794,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; - -err_bind_driver: - driver_unregister (&driver->driver); -err_register: - if (driver->unbind) - driver->unbind (&dum->gadget); - spin_lock_irq (&dum->lock); - dum->pullup = 0; - set_link_state (dum); - spin_unlock_irq (&dum->lock); -err_bind_gadget: - dum->driver = NULL; - dum->gadget.dev.driver = NULL; - return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -830,11 +817,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); + dum->gadget.dev.driver = NULL; dum->driver = NULL; - device_release_driver (&dum->gadget.dev); - driver_unregister (&driver->driver); - spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; set_link_state (dum); @@ -1827,8 +1812,7 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - /* only show a low-power port: just 8mA */ - hcd->power_budget = 8; + hcd->power_budget = POWER_BUDGET; hcd->state = HC_STATE_RUNNING; hcd->uses_new_polling = 1; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9e732bff9df0..a70e255402b8 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1067,19 +1067,19 @@ done: /* on error, disable any endpoints */ if (result < 0) { - if (!subset_active(dev)) + if (!subset_active(dev) && dev->status_ep) (void) usb_ep_disable (dev->status_ep); dev->status = NULL; (void) usb_ep_disable (dev->in_ep); (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; - } else + } /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ - if (!cdc_active (dev)) { + else if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 1d174dcb3ac9..3301167d4f2a 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -275,19 +275,15 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#ifdef DEBUG #define LDBG(lun,fmt,args...) \ dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ - printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) -#else -#define LDBG(lun,fmt,args...) \ - do { } while (0) -#define MDBG(fmt,args...) \ - do { } while (0) + pr_debug(DRIVER_NAME ": " fmt , ## args) + +#ifndef DEBUG #undef VERBOSE_DEBUG #undef DUMP_MSGS -#endif /* DEBUG */ +#endif /* !DEBUG */ #ifdef VERBOSE_DEBUG #define VLDBG LDBG @@ -304,7 +300,7 @@ MODULE_LICENSE("Dual BSD/GPL"); dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ - printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) + pr_info(DRIVER_NAME ": " fmt , ## args) #define DBG(d, fmt, args...) \ dev_dbg(&(d)->gadget->dev , fmt , ## args) diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 038e7d7b4da1..63e8fa3a69e1 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -776,7 +776,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad params\n", __FUNCTION__); return -EINVAL; } - if (!_ep || (!ep->desc && ep_index(ep))) { + if (unlikely(!_ep || !ep->desc)) { VDBG("%s, bad ep\n", __FUNCTION__); return -EINVAL; } @@ -1896,7 +1896,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, spin_lock_irqsave(&udc->lock, flags); - /* ------basic driver infomation ---- */ + /* ------basic driver information ---- */ t = scnprintf(next, size, DRIVER_DESC "\n" "%s version: %s\n" diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 832ab82b4882..9fb0b1ec8526 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -551,9 +551,9 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length) #define VDBG(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 7da7fcb05640..5b42ccd0035f 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1158,7 +1158,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget) /* support optional vendor/distro customization */ if (idVendor) { if (!idProduct) { - printk(KERN_ERR "idVendor needs idProduct!\n"); + pr_err("idVendor needs idProduct!\n"); return -ENODEV; } device_desc.idVendor = cpu_to_le16(idVendor); @@ -1190,7 +1190,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget) in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc); if (!in_ep) { autoconf_fail: - printk(KERN_ERR "%s: can't autoconfigure on %s\n", + pr_err("%s: can't autoconfigure on %s\n", shortname, gadget->name); return -ENODEV; } @@ -1212,7 +1212,7 @@ autoconf_fail: * it SHOULD NOT have problems with bulk-capable hardware. * so warn about unrecognized controllers, don't panic. */ - printk(KERN_WARNING "%s: controller '%s' not recognized\n", + pr_warning("%s: controller '%s' not recognized\n", shortname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 2ec9d196a8cf..d3e702576de6 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1422,6 +1422,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; DBG(dev, "unregistered driver '%s'\n", driver->driver.name); return 0; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 47ef8bd58a00..805602a687cb 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1699,7 +1699,7 @@ gadgetfs_bind (struct usb_gadget *gadget) if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { - printk (KERN_ERR "%s expected %s controller not %s\n", + pr_err("%s expected %s controller not %s\n", shortname, CHIP, gadget->name); return -ENODEV; } diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 367b75c0b25b..37243ef7104e 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -474,6 +474,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; device_del(&dev->gadget.dev); udc_disable(dev); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index ebc5536aa271..835948f0715a 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); -#define DRIVER_VERSION "29 May 2007" +#define DRIVER_VERSION "18 Oct 2007" /* module parameters */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +static unsigned short endian = M66592_LITTLE; +module_param(endian, ushort, 0644); +MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)"); +#else static unsigned short clock = M66592_XTAL24; module_param(clock, ushort, 0644); MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " @@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL; module_param(irq_sense, ushort, 0644); MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " "(default=2)"); +#endif static const char udc_name[] = "m66592_udc"; static const char *m66592_ep_name[] = { @@ -141,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); pid = m66592_read(m66592, offset) & M66592_PID; } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); return pid; } @@ -157,7 +163,7 @@ static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, offset = get_pipectr_addr(pipenum); m66592_mdfy(m66592, pid, M66592_PID, offset); } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); } static inline void pipe_start(struct m66592 *m66592, u16 pipenum) @@ -186,7 +192,7 @@ static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); ret = m66592_read(m66592, offset); } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + pr_err("unexpect pipe num (%d)\n", pipenum); return ret; } @@ -203,7 +209,7 @@ static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) offset = get_pipectr_addr(pipenum); m66592_bset(m66592, M66592_SQCLR, offset); } else - printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum); + pr_err("unexpect pipe num(%d)\n", pipenum); } static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) @@ -285,7 +291,7 @@ static int pipe_buffer_setting(struct m66592 *m66592, break; } if (m66592->bi_bufnum > M66592_MAX_BUFNUM) { - printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n", + pr_err("m66592 pipe memory is insufficient(%d)\n", m66592->bi_bufnum); return -ENOMEM; } @@ -326,7 +332,7 @@ static void pipe_buffer_release(struct m66592 *m66592, if (info->type == M66592_BULK) m66592->bulk--; } else - printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", + pr_err("ep_release: unexpect pipenum (%d)\n", info->pipe); } @@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->fifosel = M66592_D0FIFOSEL; ep->fifoctr = M66592_D0FIFOCTR; ep->fifotrn = M66592_D0FIFOTRN; +#if !defined(CONFIG_SUPERH_BUILT_IN_M66592) } else if (m66592->num_dma == 1) { m66592->num_dma++; ep->use_dma = 1; @@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->fifosel = M66592_D1FIFOSEL; ep->fifoctr = M66592_D1FIFOCTR; ep->fifotrn = M66592_D1FIFOTRN; +#endif } else { ep->use_dma = 0; ep->fifoaddr = M66592_CFIFO; @@ -422,7 +430,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, case USB_ENDPOINT_XFER_BULK: if (m66592->bulk >= M66592_MAX_NUM_BULK) { if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - printk(KERN_ERR "bulk pipe is insufficient\n"); + pr_err("bulk pipe is insufficient\n"); return -ENODEV; } else { info.pipe = M66592_BASE_PIPENUM_ISOC @@ -438,7 +446,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, break; case USB_ENDPOINT_XFER_INT: if (m66592->interrupt >= M66592_MAX_NUM_INT) { - printk(KERN_ERR "interrupt pipe is insufficient\n"); + pr_err("interrupt pipe is insufficient\n"); return -ENODEV; } info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; @@ -447,7 +455,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, break; case USB_ENDPOINT_XFER_ISOC: if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - printk(KERN_ERR "isochronous pipe is insufficient\n"); + pr_err("isochronous pipe is insufficient\n"); return -ENODEV; } info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; @@ -455,7 +463,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, counter = &m66592->isochronous; break; default: - printk(KERN_ERR "unexpect xfer type\n"); + pr_err("unexpect xfer type\n"); return -EINVAL; } ep->type = info.type; @@ -470,7 +478,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, ret = pipe_buffer_setting(m66592, &info); if (ret < 0) { - printk(KERN_ERR "pipe_buffer_setting fail\n"); + pr_err("pipe_buffer_setting fail\n"); return ret; } @@ -606,11 +614,33 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) control_end(ep->m66592, 0); break; default: - printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq); + pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq); break; } } +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +static void init_controller(struct m66592 *m66592) +{ + usbf_start_clock(); + m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ + m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); + m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); + m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); + + /* This is a workaound for SH7722 2nd cut */ + m66592_bset(m66592, 0x8000, M66592_DVSTCTR); + m66592_bset(m66592, 0x1000, M66592_TESTMODE); + m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); + + m66592_bset(m66592, M66592_INTL, M66592_INTENB1); + + m66592_write(m66592, 0, M66592_CFBCFG); + m66592_write(m66592, 0, M66592_D0FBCFG); + m66592_bset(m66592, endian, M66592_CFBCFG); + m66592_bset(m66592, endian, M66592_D0FBCFG); +} +#else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ static void init_controller(struct m66592 *m66592) { m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), @@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592) m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, M66592_DMA0CFG); } +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ static void disable_controller(struct m66592 *m66592) { +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + usbf_stop_clock(); +#else m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); @@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592) m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); +#endif } static void m66592_start_xclock(struct m66592 *m66592) { +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + usbf_start_clock(); +#else u16 tmp; tmp = m66592_read(m66592, M66592_SYSCFG); if (!(tmp & M66592_XCKE)) m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); +#endif } /*-------------------------------------------------------------------------*/ @@ -709,7 +748,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) do { tmp = m66592_read(m66592, ep->fifoctr); if (i++ > 100000) { - printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus" + pr_err("pipe0 is busy. maybe cpu i/o bus " "conflict. please power off this controller."); return; } @@ -759,7 +798,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) if (unlikely((tmp & M66592_FRDY) == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); - printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum); + pr_err("write fifo not ready. pipnum=%d\n", pipenum); return; } @@ -808,7 +847,7 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) req->req.status = -EPIPE; pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); - printk(KERN_ERR "read fifo not ready"); + pr_err("read fifo not ready"); return; } @@ -1063,7 +1102,7 @@ static void m66592_update_usb_speed(struct m66592 *m66592) break; default: m66592->gadget.speed = USB_SPEED_UNKNOWN; - printk(KERN_ERR "USB speed unknown\n"); + pr_err("USB speed unknown\n"); } } @@ -1122,7 +1161,7 @@ __acquires(m66592->lock) control_end(m66592, 0); break; default: - printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq); + pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq); break; } } @@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) intsts0 = m66592_read(m66592, M66592_INTSTS0); intenb0 = m66592_read(m66592, M66592_INTENB0); +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + if (!intsts0 && !intenb0) { + /* + * When USB clock stops, it cannot read register. Even if a + * clock stops, the interrupt occurs. So this driver turn on + * a clock by this timing and do re-reading of register. + */ + m66592_start_xclock(m66592); + intsts0 = m66592_read(m66592, M66592_INTSTS0); + intenb0 = m66592_read(m66592, M66592_INTENB0); + } +#endif + savepipe = m66592_read(m66592, M66592_CFIFOSEL); mask0 = intsts0 & intenb0; @@ -1409,13 +1461,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) retval = device_add(&m66592->gadget.dev); if (retval) { - printk(KERN_ERR "device_add error (%d)\n", retval); + pr_err("device_add error (%d)\n", retval); goto error; } retval = driver->bind (&m66592->gadget); if (retval) { - printk(KERN_ERR "bind to driver error (%d)\n", retval); + pr_err("bind to driver error (%d)\n", retval); device_del(&m66592->gadget.dev); goto error; } @@ -1456,6 +1508,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); driver->unbind(&m66592->gadget); + m66592->gadget.dev.driver = NULL; init_controller(m66592); disable_controller(m66592); @@ -1485,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev) iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); + usbf_stop_clock(); kfree(m66592); return 0; } @@ -1508,28 +1562,28 @@ static int __init m66592_probe(struct platform_device *pdev) (char *)udc_name); if (!res) { ret = -ENODEV; - printk(KERN_ERR "platform_get_resource_byname error.\n"); + pr_err("platform_get_resource_byname error.\n"); goto clean_up; } irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENODEV; - printk(KERN_ERR "platform_get_irq error.\n"); + pr_err("platform_get_irq error.\n"); goto clean_up; } reg = ioremap(res->start, resource_len(res)); if (reg == NULL) { ret = -ENOMEM; - printk(KERN_ERR "ioremap error.\n"); + pr_err("ioremap error.\n"); goto clean_up; } /* initialize ucd */ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { - printk(KERN_ERR "kzalloc error\n"); + pr_err("kzalloc error\n"); goto clean_up; } @@ -1555,7 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev) ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED, udc_name, m66592); if (ret < 0) { - printk(KERN_ERR "request_irq error (%d)\n", ret); + pr_err("request_irq error (%d)\n", ret); goto clean_up; } diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index bfa0c645f229..17b792b7f6bf 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -72,6 +72,11 @@ #define M66592_P_TST_J 0x0001 /* PERI TEST J */ #define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#define M66592_CFBCFG 0x0A +#define M66592_D0FBCFG 0x0C +#define M66592_LITTLE 0x0100 /* b8: Little endian mode */ +#else #define M66592_PINCFG 0x0A #define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ #define M66592_BIGEND 0x0100 /* b8: Big endian mode */ @@ -91,6 +96,7 @@ #define M66592_PKTM 0x0020 /* b5: Packet mode */ #define M66592_DENDE 0x0010 /* b4: Dend enable */ #define M66592_OBUS 0x0004 /* b2: OUTbus mode */ +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ #define M66592_CFIFO 0x10 #define M66592_D0FIFO 0x14 @@ -103,9 +109,13 @@ #define M66592_REW 0x4000 /* b14: Buffer rewind */ #define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ #define M66592_DREQE 0x1000 /* b12: DREQ output enable */ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */ +#else #define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ #define M66592_MBW_8 0x0000 /* 8bit */ #define M66592_MBW_16 0x0400 /* 16bit */ +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ #define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ #define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ #define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ @@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592, { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + len = (len + 3) / 4; + insl(fifoaddr, buf, len); +#else len = (len + 1) / 2; insw(fifoaddr, buf, len); +#endif } static inline void m66592_write(struct m66592 *m66592, u16 val, @@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592, void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) + unsigned long count; + unsigned char *pb; + int i; + + count = len / 4; + outsl(fifoaddr, buf, count); + + if (len & 0x00000003) { + pb = buf + count * 4; + for (i = 0; i < (len & 0x00000003); i++) { + if (m66592_read(m66592, M66592_CFBCFG)) /* little */ + outb(pb[i], fifoaddr + (3 - i)); + else + outb(pb[i], fifoaddr + i); + } + } +#else unsigned long odd = len & 0x0001; len = len / 2; @@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592, unsigned char *p = buf + len*2; outb(*p, fifoaddr); } +#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ } static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, @@ -570,6 +604,26 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, #define m66592_bset(m66592, val, offset) \ m66592_mdfy(m66592, val, 0, offset) +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) +#include <asm/io.h> +#define MSTPCR2 0xA4150038 /* for SH7722 */ +#define MSTPCR2_USB 0x00000800 + +static inline void usbf_start_clock(void) +{ + ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2); +} + +static inline void usbf_stop_clock(void) +{ + ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2); +} + +#else +#define usbf_start_clock(x) +#define usbf_stop_clock(x) +#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ + #endif /* ifndef __M66592_UDC_H__ */ diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d5d473f8144b..33469cf5aec3 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2435,7 +2435,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x" + VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x " "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index d377154658b5..e6d68bda428a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -4,6 +4,8 @@ * Copyright (C) 2004 Texas Instruments, Inc. * Copyright (C) 2004-2005 David Brownell * + * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -60,11 +62,6 @@ /* bulk DMA seems to be behaving for both IN and OUT */ #define USE_DMA -/* FIXME: OMAP2 currently has some problem in DMA mode */ -#ifdef CONFIG_ARCH_OMAP2 -#undef USE_DMA -#endif - /* ISO too */ #define USE_ISO @@ -73,6 +70,8 @@ #define DMA_ADDR_INVALID (~(dma_addr_t)0) +#define OMAP2_DMA_CH(ch) (((ch) - 1) << 1) +#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch)) /* * The OMAP UDC needs _very_ early endpoint setup: before enabling the @@ -571,20 +570,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) const int sync_mode = cpu_is_omap15xx() ? OMAP_DMA_SYNC_FRAME : OMAP_DMA_SYNC_ELEMENT; + int dma_trigger = 0; + + if (cpu_is_omap24xx()) + dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel); /* measure length in either bytes or packets */ if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) + || (cpu_is_omap24xx() && length < ep->maxpacket) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - length, 1, sync_mode, 0, 0); + length, 1, sync_mode, dma_trigger, 0); } else { length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); txdma_ctrl = length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, ep->ep.maxpacket >> 1, length, sync_mode, - 0, 0); + dma_trigger, 0); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, @@ -622,20 +626,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) static void next_out_dma(struct omap_ep *ep, struct omap_req *req) { - unsigned packets; + unsigned packets = req->req.length - req->req.actual; + int dma_trigger = 0; + + if (cpu_is_omap24xx()) + dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel); /* NOTE: we filtered out "short reads" before, so we know * the buffer has only whole numbers of packets. + * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode */ - - /* set up this DMA transfer, enable the fifo, start */ - packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; - packets = min(packets, (unsigned)UDC_RXN_TC + 1); - req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, packets, - OMAP_DMA_SYNC_ELEMENT, - 0, 0); + if (cpu_is_omap24xx() && packets < ep->maxpacket) { + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, + packets, 1, OMAP_DMA_SYNC_ELEMENT, + dma_trigger, 0); + req->dma_bytes = packets; + } else { + /* set up this DMA transfer, enable the fifo, start */ + packets /= ep->ep.maxpacket; + packets = min(packets, (unsigned)UDC_RXN_TC + 1); + req->dma_bytes = packets * ep->ep.maxpacket; + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, packets, + OMAP_DMA_SYNC_ELEMENT, + dma_trigger, 0); + } omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, 0, 0); @@ -743,6 +758,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) { u16 reg; int status, restart, is_in; + int dma_channel; is_in = ep->bEndpointAddress & USB_DIR_IN; if (is_in) @@ -769,11 +785,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->dma_channel = channel; if (is_in) { - status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel, + if (cpu_is_omap24xx()) + dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel); + else + dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel; + status = omap_request_dma(dma_channel, ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_TXDMA_CFG_REG = reg; - /* EMIFF */ + /* EMIFF or SDRC */ omap_set_dma_src_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); omap_set_dma_src_data_pack(ep->lch, 1); @@ -785,7 +805,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) 0, 0); } } else { - status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, + if (cpu_is_omap24xx()) + dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel); + else + dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel; + + status = omap_request_dma(dma_channel, ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_RXDMA_CFG_REG = reg; @@ -795,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) OMAP_DMA_AMODE_CONSTANT, (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), 0, 0); - /* EMIFF */ + /* EMIFF or SDRC */ omap_set_dma_dest_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); omap_set_dma_dest_data_pack(ep->lch, 1); @@ -808,7 +833,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); /* channel type P: hw synch (fifo) */ - if (!cpu_is_omap15xx()) + if (cpu_class_is_omap1() && !cpu_is_omap15xx()) OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; } @@ -926,11 +951,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* this isn't bogus, but OMAP DMA isn't the only hardware to * have a hard time with partial packet reads... reject it. + * Except OMAP2 can handle the small packets. */ if (use_dma && ep->has_dma && ep->bEndpointAddress != 0 && (ep->bEndpointAddress & USB_DIR_IN) == 0 + && !cpu_class_is_omap2() && (req->req.length % ep->ep.maxpacket) != 0) { DBG("%s, no partial packet OUT reads\n", __FUNCTION__); return -EMSGSIZE; @@ -1001,7 +1028,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* STATUS for zero length DATA stages is * always an IN ... even for IN transfers, - * a wierd case which seem to stall OMAP. + * a weird case which seem to stall OMAP. */ UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR); UDC_CTRL_REG = UDC_CLR_EP; diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index 1dc398bb9ab2..c6b9cbc7230a 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -182,21 +182,16 @@ struct omap_udc { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - #ifdef VERBOSE # define VDBG DBG #else # define VDBG(stuff...) do{}while(0) #endif -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) +#define DBG(stuff...) pr_debug("udc: " stuff) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c new file mode 100644 index 000000000000..9fdabc8fcac4 --- /dev/null +++ b/drivers/usb/gadget/printer.c @@ -0,0 +1,1592 @@ +/* + * printer.c -- Printer gadget driver + * + * Copyright (C) 2003-2005 David Brownell + * Copyright (C) 2006 Craig W. Nadler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/utsname.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <linux/cdev.h> + +#include <asm/byteorder.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <asm/system.h> +#include <linux/uaccess.h> +#include <asm/unaligned.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/g_printer.h> + +#include "gadget_chips.h" + +#define DRIVER_DESC "Printer Gadget" +#define DRIVER_VERSION "2007 OCT 06" + +static const char shortname [] = "printer"; +static const char driver_desc [] = DRIVER_DESC; + +static dev_t g_printer_devno; + +static struct class *usb_gadget_class; + +/*-------------------------------------------------------------------------*/ + +struct printer_dev { + spinlock_t lock; /* lock this structure */ + /* lock buffer lists during read/write calls */ + spinlock_t lock_printer_io; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + u8 config; + s8 interface; + struct usb_ep *in_ep, *out_ep; + const struct usb_endpoint_descriptor + *in, *out; + struct list_head rx_reqs; /* List of free RX structs */ + struct list_head rx_reqs_active; /* List of Active RX xfers */ + struct list_head rx_buffers; /* List of completed xfers */ + /* wait until there is data to be read. */ + wait_queue_head_t rx_wait; + struct list_head tx_reqs; /* List of free TX structs */ + struct list_head tx_reqs_active; /* List of Active TX xfers */ + /* Wait until there are write buffers available to use. */ + wait_queue_head_t tx_wait; + /* Wait until all write buffers have been sent. */ + wait_queue_head_t tx_flush_wait; + struct usb_request *current_rx_req; + size_t current_rx_bytes; + u8 *current_rx_buf; + u8 printer_status; + u8 reset_printer; + struct class_device *printer_class_dev; + struct cdev printer_cdev; + struct device *pdev; + u8 printer_cdev_open; + wait_queue_head_t wait; +}; + +static struct printer_dev usb_printer_gadget; + +/*-------------------------------------------------------------------------*/ + +/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ + +/* Thanks to NetChip Technologies for donating this product ID. + */ +#define PRINTER_VENDOR_NUM 0x0525 /* NetChip */ +#define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ + +/* Some systems will want different product identifers published in the + * device descriptor, either numbers or strings or both. These string + * parameters are in UTF-8 (superset of ASCII's 7 bit characters). + */ + +static ushort __initdata idVendor; +module_param(idVendor, ushort, S_IRUGO); +MODULE_PARM_DESC(idVendor, "USB Vendor ID"); + +static ushort __initdata idProduct; +module_param(idProduct, ushort, S_IRUGO); +MODULE_PARM_DESC(idProduct, "USB Product ID"); + +static ushort __initdata bcdDevice; +module_param(bcdDevice, ushort, S_IRUGO); +MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); + +static char *__initdata iManufacturer; +module_param(iManufacturer, charp, S_IRUGO); +MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); + +static char *__initdata iProduct; +module_param(iProduct, charp, S_IRUGO); +MODULE_PARM_DESC(iProduct, "USB Product string"); + +static char *__initdata iSerialNum; +module_param(iSerialNum, charp, S_IRUGO); +MODULE_PARM_DESC(iSerialNum, "1"); + +static char *__initdata iPNPstring; +module_param(iPNPstring, charp, S_IRUGO); +MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); + +/* Number of requests to allocate per endpoint, not used for ep0. */ +static unsigned qlen = 10; +module_param(qlen, uint, S_IRUGO|S_IWUSR); + +#define QLEN qlen + +#ifdef CONFIG_USB_GADGET_DUALSPEED +#define DEVSPEED USB_SPEED_HIGH +#else /* full speed (low speed doesn't do bulk) */ +#define DEVSPEED USB_SPEED_FULL +#endif + +/*-------------------------------------------------------------------------*/ + +#define xprintk(d, level, fmt, args...) \ + printk(level "%s: " fmt, DRIVER_DESC, ## args) + +#ifdef DEBUG +#define DBG(dev, fmt, args...) \ + xprintk(dev, KERN_DEBUG, fmt, ## args) +#else +#define DBG(dev, fmt, args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG(dev, fmt, args...) \ + xprintk(dev, KERN_DEBUG, fmt, ## args) +#else +#define VDBG(dev, fmt, args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev, fmt, args...) \ + xprintk(dev, KERN_ERR, fmt, ## args) +#define WARN(dev, fmt, args...) \ + xprintk(dev, KERN_WARNING, fmt, ## args) +#define INFO(dev, fmt, args...) \ + xprintk(dev, KERN_INFO, fmt, ## args) + +/*-------------------------------------------------------------------------*/ + +/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly + * ep0 implementation: descriptors, config management, setup(). + * also optional class-specific notification interrupt transfer. + */ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. + */ + +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIALNUM 3 + +/* holds our biggest descriptor */ +#define USB_DESC_BUFSIZE 256 +#define USB_BUFSIZE 8192 + +/* This device advertises one configuration. */ +#define DEV_CONFIG_VALUE 1 +#define PRINTER_INTERFACE 0 + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .idVendor = __constant_cpu_to_le16(PRINTER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(PRINTER_PRODUCT_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUM, + .bNumConfigurations = 1 +}; + +static struct usb_otg_descriptor otg_desc = { + .bLength = sizeof otg_desc, + .bDescriptorType = USB_DT_OTG, + .bmAttributes = USB_OTG_SRP +}; + +static struct usb_config_descriptor config_desc = { + .bLength = sizeof config_desc, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 1, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1 /* Self-Powered */ +}; + +static struct usb_interface_descriptor intf_desc = { + .bLength = sizeof intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = PRINTER_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_PRINTER, + .bInterfaceSubClass = 1, /* Printer Sub-Class */ + .bInterfaceProtocol = 2, /* Bi-Directional */ + .iInterface = 0 +}; + +static struct usb_endpoint_descriptor fs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static struct usb_endpoint_descriptor fs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK +}; + +static const struct usb_descriptor_header *fs_printer_function [11] = { + (struct usb_descriptor_header *) &otg_desc, + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_ep_in_desc, + (struct usb_descriptor_header *) &fs_ep_out_desc, + NULL +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + */ + +static struct usb_endpoint_descriptor hs_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512) +}; + +static struct usb_endpoint_descriptor hs_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512) +}; + +static struct usb_qualifier_descriptor dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PRINTER, + .bNumConfigurations = 1 +}; + +static const struct usb_descriptor_header *hs_printer_function [11] = { + (struct usb_descriptor_header *) &otg_desc, + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_ep_in_desc, + (struct usb_descriptor_header *) &hs_ep_out_desc, + NULL +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g, hs, fs) (((void)(g)), (fs)) + +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ + +/*-------------------------------------------------------------------------*/ + +/* descriptors that are built on-demand */ + +static char manufacturer [50]; +static char product_desc [40] = DRIVER_DESC; +static char serial_num [40] = "1"; +static char pnp_string [1024] = + "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; + +/* static strings, in UTF-8 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, product_desc, }, + { STRING_SERIALNUM, serial_num, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, gfp_flags); + + if (req != NULL) { + req->length = len; + req->buf = kmalloc(len, gfp_flags); + if (req->buf == NULL) { + usb_ep_free_request(ep, req); + return NULL; + } + } + + return req; +} + +static void +printer_req_free(struct usb_ep *ep, struct usb_request *req) +{ + if (ep != NULL && req != NULL) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + int status = req->status; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + list_del_init(&req->list); /* Remode from Active List */ + + switch (status) { + + /* normal completion */ + case 0: + list_add_tail(&req->list, &dev->rx_buffers); + wake_up_interruptible(&dev->rx_wait); + DBG(dev, "G_Printer : rx length %d\n", req->actual); + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + VDBG(dev, "rx shutdown, code %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + + /* for hardware automagic (such as pxa) */ + case -ECONNABORTED: /* endpoint reset */ + DBG(dev, "rx %s reset\n", ep->name); + list_add(&req->list, &dev->rx_reqs); + break; + + /* data overrun */ + case -EOVERFLOW: + /* FALLTHROUGH */ + + default: + DBG(dev, "rx status %d\n", status); + list_add(&req->list, &dev->rx_reqs); + break; + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct printer_dev *dev = ep->driver_data; + + switch (req->status) { + default: + VDBG(dev, "tx err %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + break; + case 0: + break; + } + + spin_lock(&dev->lock); + /* Take the request struct off the active list and put it on the + * free list. + */ + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + wake_up_interruptible(&dev->tx_wait); + if (likely(list_empty(&dev->tx_reqs_active))) + wake_up_interruptible(&dev->tx_flush_wait); + + spin_unlock(&dev->lock); +} + +/*-------------------------------------------------------------------------*/ + +static int +printer_open(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev; + unsigned long flags; + int ret = -EBUSY; + + dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); + + spin_lock_irqsave(&dev->lock, flags); + + if (!dev->printer_cdev_open) { + dev->printer_cdev_open = 1; + fd->private_data = dev; + ret = 0; + /* Change the printer status to show that it's on-line. */ + dev->printer_status |= PRINTER_SELECTED; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_open returned %x\n", ret); + + return ret; +} + +static int +printer_close(struct inode *inode, struct file *fd) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + dev->printer_cdev_open = 0; + fd->private_data = NULL; + /* Change printer status to show that the printer is off-line. */ + dev->printer_status &= ~PRINTER_SELECTED; + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "printer_close\n"); + + return 0; +} + +static ssize_t +printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; + size_t bytes_copied; + struct usb_request *req; + /* This is a pointer to the current USB rx request. */ + struct usb_request *current_rx_req; + /* This is the number of bytes in the current rx buffer. */ + size_t current_rx_bytes; + /* This is a pointer to the current rx buffer. */ + u8 *current_rx_buf; + + if (len == 0) + return -EINVAL; + + DBG(dev, "printer_read trying to read %d bytes\n", (int)len); + + spin_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* We will use this flag later to check if a printer reset happened + * after we turn interrupts back on. + */ + dev->reset_printer = 0; + + while (likely(!list_empty(&dev->rx_reqs))) { + int error; + + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del_init(&req->list); + + /* The USB Host sends us whatever amount of data it wants to + * so we always set the length field to the full USB_BUFSIZE. + * If the amount of data is more than the read() caller asked + * for it will be stored in the request buffer until it is + * asked for by read(). + */ + req->length = USB_BUFSIZE; + req->complete = rx_complete; + + error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); + if (error) { + DBG(dev, "rx submit --> %d\n", error); + list_add(&req->list, &dev->rx_reqs); + break; + } else { + list_add(&req->list, &dev->rx_reqs_active); + } + } + + bytes_copied = 0; + current_rx_req = dev->current_rx_req; + current_rx_bytes = dev->current_rx_bytes; + current_rx_buf = dev->current_rx_buf; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + /* Check if there is any data in the read buffers. Please note that + * current_rx_bytes is the number of bytes in the current rx buffer. + * If it is zero then check if there are any other rx_buffers that + * are on the completed list. We are only out of data if all rx + * buffers are empty. + */ + if ((current_rx_bytes == 0) && + (likely(list_empty(&dev->rx_buffers)))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If no data is available check if this is a NON-Blocking + * call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until data is available */ + wait_event_interruptible(dev->rx_wait, + (likely(!list_empty(&dev->rx_buffers)))); + spin_lock_irqsave(&dev->lock, flags); + } + + /* We have data to return then copy it to the caller's buffer.*/ + while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) + && len) { + if (current_rx_bytes == 0) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del_init(&req->list); + + if (req->actual && req->buf) { + current_rx_req = req; + current_rx_bytes = req->actual; + current_rx_buf = req->buf; + } else { + list_add(&req->list, &dev->rx_reqs); + continue; + } + } + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (len > current_rx_bytes) + size = current_rx_bytes; + else + size = len; + + size -= copy_to_user(buf, current_rx_buf, size); + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset free the req and buffer */ + if (dev->reset_printer) { + printer_req_free(dev->out_ep, current_rx_req); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* If we not returning all the data left in this RX request + * buffer then adjust the amount of data left in the buffer. + * Othewise if we are done with this RX request buffer then + * requeue it to get any incoming data from the USB host. + */ + if (size < current_rx_bytes) { + current_rx_bytes -= size; + current_rx_buf += size; + } else { + list_add(¤t_rx_req->list, &dev->rx_reqs); + current_rx_bytes = 0; + current_rx_buf = NULL; + current_rx_req = NULL; + } + } + + dev->current_rx_req = current_rx_req; + dev->current_rx_bytes = current_rx_bytes; + dev->current_rx_buf = current_rx_buf; + + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); + + if (bytes_copied) + return bytes_copied; + else + return -EAGAIN; +} + +static ssize_t +printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + size_t size; /* Amount of data in a TX request. */ + size_t bytes_copied = 0; + struct usb_request *req; + + DBG(dev, "printer_write trying to send %d bytes\n", (int)len); + + if (len == 0) + return -EINVAL; + + spin_lock(&dev->lock_printer_io); + spin_lock_irqsave(&dev->lock, flags); + + /* Check if a printer reset happens while we have interrupts on */ + dev->reset_printer = 0; + + /* Check if there is any available write buffers */ + if (likely(list_empty(&dev->tx_reqs))) { + /* Turn interrupts back on before sleeping. */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* + * If write buffers are available check if this is + * a NON-Blocking call or not. + */ + if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + /* Sleep until a write buffer is available */ + wait_event_interruptible(dev->tx_wait, + (likely(!list_empty(&dev->tx_reqs)))); + spin_lock_irqsave(&dev->lock, flags); + } + + while (likely(!list_empty(&dev->tx_reqs)) && len) { + + if (len > USB_BUFSIZE) + size = USB_BUFSIZE; + else + size = len; + + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del_init(&req->list); + + req->complete = tx_complete; + req->length = size; + + /* Check if we need to send a zero length packet. */ + if (len > size) + /* They will be more TX requests so no yet. */ + req->zero = 0; + else + /* If the data amount is not a multple of the + * maxpacket size then send a zero length packet. + */ + req->zero = ((len % dev->in_ep->maxpacket) == 0); + + /* Don't leave irqs off while doing memory copies */ + spin_unlock_irqrestore(&dev->lock, flags); + + if (copy_from_user(req->buf, buf, size)) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock(&dev->lock_printer_io); + return bytes_copied; + } + + bytes_copied += size; + len -= size; + buf += size; + + spin_lock_irqsave(&dev->lock, flags); + + /* We've disconnected or reset so free the req and buffer */ + if (dev->reset_printer) { + printer_req_free(dev->in_ep, req); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + return -EAGAIN; + } + + list_add(&req->list, &dev->tx_reqs_active); + + } + + spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock(&dev->lock_printer_io); + + DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); + + if (bytes_copied) { + return bytes_copied; + } else { + return -EAGAIN; + } +} + +static int +printer_fsync(struct file *fd, struct dentry *dentry, int datasync) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int tx_list_empty; + + spin_lock_irqsave(&dev->lock, flags); + tx_list_empty = (likely(list_empty(&dev->tx_reqs))); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!tx_list_empty) { + /* Sleep until all data has been sent */ + wait_event_interruptible(dev->tx_flush_wait, + (likely(list_empty(&dev->tx_reqs_active)))); + } + + return 0; +} + +static unsigned int +printer_poll(struct file *fd, poll_table *wait) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + poll_wait(fd, &dev->rx_wait, wait); + poll_wait(fd, &dev->tx_wait, wait); + + spin_lock_irqsave(&dev->lock, flags); + if (likely(!list_empty(&dev->tx_reqs))) + status |= POLLOUT | POLLWRNORM; + + if (likely(!list_empty(&dev->rx_buffers))) + status |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +static int +printer_ioctl(struct inode *inode, struct file *fd, unsigned int code, + unsigned long arg) +{ + struct printer_dev *dev = fd->private_data; + unsigned long flags; + int status = 0; + + DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); + + /* handle ioctls */ + + spin_lock_irqsave(&dev->lock, flags); + + switch (code) { + case GADGET_GET_PRINTER_STATUS: + status = (int)dev->printer_status; + break; + case GADGET_SET_PRINTER_STATUS: + dev->printer_status = (u8)arg; + break; + default: + /* could not handle ioctl */ + DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n", + code); + status = -ENOTTY; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +/* used after endpoint configuration */ +static struct file_operations printer_io_operations = { + .owner = THIS_MODULE, + .open = printer_open, + .read = printer_read, + .write = printer_write, + .fsync = printer_fsync, + .poll = printer_poll, + .ioctl = printer_ioctl, + .release = printer_close +}; + +/*-------------------------------------------------------------------------*/ + +static int +set_printer_interface(struct printer_dev *dev) +{ + int result = 0; + + dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); + dev->in_ep->driver_data = dev; + + dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc); + dev->out_ep->driver_data = dev; + + result = usb_ep_enable(dev->in_ep, dev->in); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + + result = usb_ep_enable(dev->out_ep, dev->out); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); + goto done; + } + +done: + /* on error, disable any endpoints */ + if (result != 0) { + (void) usb_ep_disable(dev->in_ep); + (void) usb_ep_disable(dev->out_ep); + dev->in = NULL; + dev->out = NULL; + } + + /* caller is responsible for cleanup on error */ + return result; +} + +static void printer_reset_interface(struct printer_dev *dev) +{ + if (dev->interface < 0) + return; + + DBG(dev, "%s\n", __FUNCTION__); + + if (dev->in) + usb_ep_disable(dev->in_ep); + + if (dev->out) + usb_ep_disable(dev->out_ep); + + dev->interface = -1; +} + +/* change our operational config. must agree with the code + * that returns config descriptors, and altsetting code. + */ +static int +printer_set_config(struct printer_dev *dev, unsigned number) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + if (gadget_is_sa1100(gadget) && dev->config) { + /* tx fifo is full, but we can't clear it...*/ + INFO(dev, "can't change configurations\n"); + return -ESPIPE; + } + + switch (number) { + case DEV_CONFIG_VALUE: + result = 0; + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + break; + } + + if (result) { + usb_gadget_vbus_draw(dev->gadget, + dev->gadget->is_otg ? 8 : 100); + } else { + char *speed; + unsigned power; + + power = 2 * config_desc.bMaxPower; + usb_gadget_vbus_draw(dev->gadget, power); + + switch (gadget->speed) { + case USB_SPEED_FULL: speed = "full"; break; +#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_SPEED_HIGH: speed = "high"; break; +#endif + default: speed = "?"; break; + } + + dev->config = number; + INFO(dev, "%s speed config #%d: %d mA, %s\n", + speed, number, power, driver_desc); + } + return result; +} + +static int +config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, + int is_otg) +{ + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (speed == USB_SPEED_HIGH); + + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + + if (hs) { + function = hs_printer_function; + } else { + function = fs_printer_function; + } +#else + function = fs_printer_function; +#endif + + if (index >= device_desc.bNumConfigurations) + return -EINVAL; + + /* for now, don't advertise srp-only devices */ + if (!is_otg) + function++; + + len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE, + function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; +} + +/* Change our operational Interface. */ +static int +set_interface(struct printer_dev *dev, unsigned number) +{ + int result = 0; + + if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) { + /* tx fifo is full, but we can't clear it...*/ + INFO(dev, "can't change interfaces\n"); + return -ESPIPE; + } + + /* Free the current interface */ + switch (dev->interface) { + case PRINTER_INTERFACE: + printer_reset_interface(dev); + break; + } + + switch (number) { + case PRINTER_INTERFACE: + result = set_printer_interface(dev); + if (result) { + printer_reset_interface(dev); + } else { + dev->interface = PRINTER_INTERFACE; + } + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + } + + if (!result) + INFO(dev, "Using interface %x\n", number); + + return result; +} + +static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DBG((struct printer_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +static void printer_soft_reset(struct printer_dev *dev) +{ + struct usb_request *req; + + INFO(dev, "Received Printer Reset Request\n"); + + if (usb_ep_disable(dev->in_ep)) + DBG(dev, "Failed to disable USB in_ep\n"); + if (usb_ep_disable(dev->out_ep)) + DBG(dev, "Failed to disable USB out_ep\n"); + + if (dev->current_rx_req != NULL) { + list_add(&dev->current_rx_req->list, &dev->rx_reqs); + dev->current_rx_req = NULL; + } + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + dev->reset_printer = 1; + + while (likely(!(list_empty(&dev->rx_buffers)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->rx_reqs_active)))) { + req = container_of(dev->rx_buffers.next, struct usb_request, + list); + list_del_init(&req->list); + list_add(&req->list, &dev->rx_reqs); + } + + while (likely(!(list_empty(&dev->tx_reqs_active)))) { + req = container_of(dev->tx_reqs_active.next, + struct usb_request, list); + list_del_init(&req->list); + list_add(&req->list, &dev->tx_reqs); + } + + if (usb_ep_enable(dev->in_ep, dev->in)) + DBG(dev, "Failed to enable USB in_ep\n"); + if (usb_ep_enable(dev->out_ep, dev->out)) + DBG(dev, "Failed to enable USB out_ep\n"); + + wake_up_interruptible(&dev->tx_wait); + wake_up_interruptible(&dev->tx_flush_wait); +} + +/*-------------------------------------------------------------------------*/ + +/* + * The setup() callback implements all the ep0 functionality that's not + * handled lower down. + */ +static int +printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct printer_dev *dev = get_gadget_data(gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); + + DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); + + req->complete = printer_setup_complete; + + switch (ctrl->bRequestType&USB_TYPE_MASK) { + + case USB_TYPE_STANDARD: + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + break; + switch (wValue >> 8) { + + case USB_DT_DEVICE: + value = min(wLength, (u16) sizeof device_desc); + memcpy(req->buf, &device_desc, value); + break; +#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; + value = min(wLength, + (u16) sizeof dev_qualifier); + memcpy(req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; + /* FALLTHROUGH */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + case USB_DT_CONFIG: + value = config_buf(gadget->speed, req->buf, + wValue >> 8, + wValue & 0xff, + gadget->is_otg); + if (value >= 0) + value = min(wLength, (u16) value); + break; + + case USB_DT_STRING: + value = usb_gadget_get_string(&stringtab, + wValue & 0xff, req->buf); + if (value >= 0) + value = min(wLength, (u16) value); + break; + } + break; + + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + break; + if (gadget->a_hnp_support) + DBG(dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DBG(dev, "HNP needs a different root port\n"); + value = printer_set_config(dev, wValue); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + break; + *(u8 *)req->buf = dev->config; + value = min(wLength, (u16) 1); + break; + + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE || + !dev->config) + break; + + value = set_interface(dev, PRINTER_INTERFACE); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != + (USB_DIR_IN|USB_RECIP_INTERFACE) + || !dev->config) + break; + + *(u8 *)req->buf = dev->interface; + value = min(wLength, (u16) 1); + break; + + default: + goto unknown; + } + break; + + case USB_TYPE_CLASS: + switch (ctrl->bRequest) { + case 0: /* Get the IEEE-1284 PNP String */ + /* Only one printer interface is supported. */ + if ((wIndex>>8) != PRINTER_INTERFACE) + break; + + value = (pnp_string[0]<<8)|pnp_string[1]; + memcpy(req->buf, pnp_string, value); + DBG(dev, "1284 PNP String: %x %s\n", value, + &pnp_string[2]); + break; + + case 1: /* Get Port Status */ + /* Only one printer interface is supported. */ + if (wIndex != PRINTER_INTERFACE) + break; + + *(u8 *)req->buf = dev->printer_status; + value = min(wLength, (u16) 1); + break; + + case 2: /* Soft Reset */ + /* Only one printer interface is supported. */ + if (wIndex != PRINTER_INTERFACE) + break; + + printer_soft_reset(dev); + + value = 0; + break; + + default: + goto unknown; + } + break; + + default: +unknown: + VDBG(dev, + "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); + break; + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < wLength + && (value % gadget->ep0->maxpacket) == 0; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(dev, "ep_queue --> %d\n", value); + req->status = 0; + printer_setup_complete(gadget->ep0, req); + } + } + + /* host either stalls (value < 0) or reports success */ + return value; +} + +static void +printer_disconnect(struct usb_gadget *gadget) +{ + struct printer_dev *dev = get_gadget_data(gadget); + unsigned long flags; + + DBG(dev, "%s\n", __FUNCTION__); + + spin_lock_irqsave(&dev->lock, flags); + + printer_reset_interface(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void +printer_unbind(struct usb_gadget *gadget) +{ + struct printer_dev *dev = get_gadget_data(gadget); + struct usb_request *req; + + + DBG(dev, "%s\n", __FUNCTION__); + + /* Remove sysfs files */ + device_destroy(usb_gadget_class, g_printer_devno); + + /* Remove Character Device */ + cdev_del(&dev->printer_cdev); + + /* we must already have been disconnected ... no i/o may be active */ + WARN_ON(!list_empty(&dev->tx_reqs_active)); + WARN_ON(!list_empty(&dev->rx_reqs_active)); + + /* Free all memory for this driver. */ + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + + if (dev->current_rx_req != NULL); + printer_req_free(dev->out_ep, dev->current_rx_req); + + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + + while (!list_empty(&dev->rx_buffers)) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + + if (dev->req) { + printer_req_free(gadget->ep0, dev->req); + dev->req = NULL; + } + + set_gadget_data(gadget, NULL); +} + +static int __init +printer_bind(struct usb_gadget *gadget) +{ + struct printer_dev *dev; + struct usb_ep *in_ep, *out_ep; + int status = -ENOMEM; + int gcnum; + size_t len; + u32 i; + struct usb_request *req; + + dev = &usb_printer_gadget; + + + /* Setup the sysfs files for the printer gadget. */ + dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, + "g_printer"); + if (IS_ERR(dev->pdev)) { + ERROR(dev, "Failed to create device: g_printer\n"); + goto fail; + } + + /* + * Register a character device as an interface to a user mode + * program that handles the printer specific functionality. + */ + cdev_init(&dev->printer_cdev, &printer_io_operations); + dev->printer_cdev.owner = THIS_MODULE; + status = cdev_add(&dev->printer_cdev, g_printer_devno, 1); + if (status) { + ERROR(dev, "Failed to open char device\n"); + goto fail; + } + + if (gadget_is_sa1100(gadget)) { + /* hardware can't write zero length packets. */ + ERROR(dev, "SA1100 controller is unsupport by this driver\n"); + goto fail; + } + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) { + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); + } else { + dev_warn(&gadget->dev, "controller '%s' not recognized\n", + gadget->name); + /* unrecognized, but safe unless bulk is REALLY quirky */ + device_desc.bcdDevice = + __constant_cpu_to_le16(0xFFFF); + } + snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + gadget->name); + + device_desc.idVendor = + __constant_cpu_to_le16(PRINTER_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(PRINTER_PRODUCT_NUM); + + /* support optional vendor/distro customization */ + if (idVendor) { + if (!idProduct) { + dev_err(&gadget->dev, "idVendor needs idProduct!\n"); + return -ENODEV; + } + device_desc.idVendor = cpu_to_le16(idVendor); + device_desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + device_desc.bcdDevice = cpu_to_le16(bcdDevice); + } + + if (iManufacturer) + strlcpy(manufacturer, iManufacturer, sizeof manufacturer); + + if (iProduct) + strlcpy(product_desc, iProduct, sizeof product_desc); + + if (iSerialNum) + strlcpy(serial_num, iSerialNum, sizeof serial_num); + + if (iPNPstring) + strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); + + len = strlen(pnp_string); + pnp_string[0] = (len >> 8) & 0xFF; + pnp_string[1] = len & 0xFF; + + /* all we really need is bulk IN/OUT */ + usb_ep_autoconfig_reset(gadget); + in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc); + if (!in_ep) { +autoconf_fail: + dev_err(&gadget->dev, "can't autoconfigure on %s\n", + gadget->name); + return -ENODEV; + } + in_ep->driver_data = in_ep; /* claim */ + + out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc); + if (!out_ep) + goto autoconf_fail; + out_ep->driver_data = out_ep; /* claim */ + +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; +#endif /* DUALSPEED */ + + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + usb_gadget_set_selfpowered(gadget); + + if (gadget->is_otg) { + otg_desc.bmAttributes |= USB_OTG_HNP, + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + config_desc.bMaxPower = 4; + } + + spin_lock_init(&dev->lock); + spin_lock_init(&dev->lock_printer_io); + INIT_LIST_HEAD(&dev->tx_reqs); + INIT_LIST_HEAD(&dev->tx_reqs_active); + INIT_LIST_HEAD(&dev->rx_reqs); + INIT_LIST_HEAD(&dev->rx_reqs_active); + INIT_LIST_HEAD(&dev->rx_buffers); + init_waitqueue_head(&dev->rx_wait); + init_waitqueue_head(&dev->tx_wait); + init_waitqueue_head(&dev->tx_flush_wait); + + dev->config = 0; + dev->interface = -1; + dev->printer_cdev_open = 0; + dev->printer_status = PRINTER_NOT_ERROR; + dev->current_rx_req = NULL; + dev->current_rx_bytes = 0; + dev->current_rx_buf = NULL; + + dev->in_ep = in_ep; + dev->out_ep = out_ep; + + /* preallocate control message data and buffer */ + dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE, + GFP_KERNEL); + if (!dev->req) { + status = -ENOMEM; + goto fail; + } + + for (i = 0; i < QLEN; i++) { + req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) { + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } + return -ENOMEM; + } + list_add(&req->list, &dev->tx_reqs); + } + + for (i = 0; i < QLEN; i++) { + req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL); + if (!req) { + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } + return -ENOMEM; + } + list_add(&req->list, &dev->rx_reqs); + } + + dev->req->complete = printer_setup_complete; + + /* finish hookup to lower layer ... */ + dev->gadget = gadget; + set_gadget_data(gadget, dev); + gadget->ep0->driver_data = dev; + + INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); + INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, + in_ep->name); + + return 0; + +fail: + printer_unbind(gadget); + return status; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver printer_driver = { + .speed = DEVSPEED, + + .function = (char *) driver_desc, + .bind = printer_bind, + .unbind = printer_unbind, + + .setup = printer_setup, + .disconnect = printer_disconnect, + + .driver = { + .name = (char *) shortname, + .owner = THIS_MODULE, + }, +}; + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Craig Nadler"); +MODULE_LICENSE("GPL"); + +static int __init +init(void) +{ + int status; + + usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); + if (IS_ERR(usb_gadget_class)) { + status = PTR_ERR(usb_gadget_class); + ERROR(dev, "unable to create usb_gadget class %d\n", status); + return status; + } + + status = alloc_chrdev_region(&g_printer_devno, 0, 1, + "USB printer gadget"); + if (status) { + ERROR(dev, "alloc_chrdev_region %d\n", status); + class_destroy(usb_gadget_class); + return status; + } + + status = usb_gadget_register_driver(&printer_driver); + if (status) { + class_destroy(usb_gadget_class); + unregister_chrdev_region(g_printer_devno, 1); + DBG(dev, "usb_gadget_register_driver %x\n", status); + } + + return status; +} +module_init(init); + +static void __exit +cleanup(void) +{ + int status; + + spin_lock(&usb_printer_gadget.lock_printer_io); + class_destroy(usb_gadget_class); + unregister_chrdev_region(g_printer_devno, 2); + + status = usb_gadget_unregister_driver(&printer_driver); + if (status) + ERROR(dev, "usb_gadget_unregister_driver %x\n", status); + + spin_unlock(&usb_printer_gadget.lock_printer_io); +} +module_exit(cleanup); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 3173b39f0bfd..4402d6f042d9 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -24,7 +24,7 @@ * */ -// #define VERBOSE DBG_VERBOSE +/* #define VERBOSE_DEBUG */ #include <linux/device.h> #include <linux/module.h> @@ -38,13 +38,14 @@ #include <linux/timer.h> #include <linux/list.h> #include <linux/interrupt.h> -#include <linux/proc_fs.h> #include <linux/mm.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/irq.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/seq_file.h> +#include <linux/debugfs.h> #include <asm/byteorder.h> #include <asm/dma.h> @@ -127,8 +128,10 @@ static int is_vbus_present(void) { struct pxa2xx_udc_mach_info *mach = the_controller->mach; - if (mach->gpio_vbus) - return gpio_get_value(mach->gpio_vbus); + if (mach->gpio_vbus) { + int value = gpio_get_value(mach->gpio_vbus); + return mach->gpio_vbus_inverted ? !value : value; + } if (mach->udc_is_connected) return mach->udc_is_connected(); return 1; @@ -677,7 +680,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == 0 /* ep0 */) { + if (ep->desc == NULL/* ep0 */) { unsigned length = _req->length; switch (dev->ep0state) { @@ -731,7 +734,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* pio or dma irq handler advances the queue. */ - if (likely (req != 0)) + if (likely(req != NULL)) list_add_tail(&req->queue, &ep->queue); local_irq_restore(flags); @@ -991,45 +994,32 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = { /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static const char proc_node_name [] = "driver/udc"; +#ifdef CONFIG_USB_GADGET_DEBUG_FS static int -udc_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *_dev) +udc_seq_show(struct seq_file *m, void *d) { - char *buf = page; - struct pxa2xx_udc *dev = _dev; - char *next = buf; - unsigned size = count; + struct pxa2xx_udc *dev = m->private; unsigned long flags; - int i, t; + int i; u32 tmp; - if (off != 0) - return 0; - local_irq_save(flags); /* basic device status */ - t = scnprintf(next, size, DRIVER_DESC "\n" + seq_printf(m, DRIVER_DESC "\n" "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR "(pio)", dev->driver ? dev->driver->driver.name : "(none)", is_vbus_present() ? "full speed" : "disconnected"); - size -= t; - next += t; /* registers for device and ep0 */ - t = scnprintf(next, size, + seq_printf(m, "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); - size -= t; - next += t; tmp = UDCCR; - t = scnprintf(next, size, + seq_printf(m, "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp, (tmp & UDCCR_REM) ? " rem" : "", (tmp & UDCCR_RSTIR) ? " rstir" : "", @@ -1039,11 +1029,9 @@ udc_proc_read(char *page, char **start, off_t off, int count, (tmp & UDCCR_RSM) ? " rsm" : "", (tmp & UDCCR_UDA) ? " uda" : "", (tmp & UDCCR_UDE) ? " ude" : ""); - size -= t; - next += t; tmp = UDCCS0; - t = scnprintf(next, size, + seq_printf(m, "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp, (tmp & UDCCS0_SA) ? " sa" : "", (tmp & UDCCS0_RNE) ? " rne" : "", @@ -1053,28 +1041,22 @@ udc_proc_read(char *page, char **start, off_t off, int count, (tmp & UDCCS0_FTF) ? " ftf" : "", (tmp & UDCCS0_IPR) ? " ipr" : "", (tmp & UDCCS0_OPR) ? " opr" : ""); - size -= t; - next += t; if (dev->has_cfr) { tmp = UDCCFR; - t = scnprintf(next, size, + seq_printf(m, "udccfr %02X =%s%s\n", tmp, (tmp & UDCCFR_AREN) ? " aren" : "", (tmp & UDCCFR_ACM) ? " acm" : ""); - size -= t; - next += t; } if (!is_vbus_present() || !dev->driver) goto done; - t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", + seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", dev->stats.write.bytes, dev->stats.write.ops, dev->stats.read.bytes, dev->stats.read.ops, dev->stats.irqs); - size -= t; - next += t; /* dump endpoint queues */ for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { @@ -1082,61 +1064,68 @@ udc_proc_read(char *page, char **start, off_t off, int count, struct pxa2xx_request *req; if (i != 0) { - const struct usb_endpoint_descriptor *d; + const struct usb_endpoint_descriptor *desc; - d = ep->desc; - if (!d) + desc = ep->desc; + if (!desc) continue; tmp = *dev->ep [i].reg_udccs; - t = scnprintf(next, size, + seq_printf(m, "%s max %d %s udccs %02x irqs %lu\n", - ep->ep.name, le16_to_cpu (d->wMaxPacketSize), + ep->ep.name, le16_to_cpu(desc->wMaxPacketSize), "pio", tmp, ep->pio_irqs); /* TODO translate all five groups of udccs bits! */ } else /* ep0 should only have one transfer queued */ - t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n", + seq_printf(m, "ep0 max 16 pio irqs %lu\n", ep->pio_irqs); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "\t(nothing queued)\n"); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; + seq_printf(m, "\t(nothing queued)\n"); continue; } list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, + seq_printf(m, "\treq %p len %d/%d buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; } } done: local_irq_restore(flags); - *eof = 1; - return count - size; + return 0; } -#define create_proc_files() \ - create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) -#define remove_proc_files() \ - remove_proc_entry(proc_node_name, NULL) +static int +udc_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, udc_seq_show, inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = udc_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +#define create_debug_files(dev) \ + do { \ + dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ + S_IRUGO, NULL, dev, &debug_fops); \ + } while (0) +#define remove_debug_files(dev) \ + do { \ + if (dev->debugfs_udc) \ + debugfs_remove(dev->debugfs_udc); \ + } while (0) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ -#define create_proc_files() do {} while (0) -#define remove_proc_files() do {} while (0) +#define create_debug_files(dev) do {} while (0) +#define remove_debug_files(dev) do {} while (0) #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ @@ -1345,6 +1334,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) local_irq_enable(); driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; dev->driver = NULL; device_del (&dev->gadget.dev); @@ -1397,6 +1387,9 @@ static irqreturn_t udc_vbus_irq(int irq, void *_dev) struct pxa2xx_udc *dev = _dev; int vbus = gpio_get_value(dev->mach->gpio_vbus); + if (dev->mach->gpio_vbus_inverted) + vbus = !vbus; + pxa2xx_udc_vbus_session(&dev->gadget, vbus); return IRQ_HANDLED; } @@ -2099,7 +2092,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) /* insist on Intel/ARM/XScale */ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { - printk(KERN_ERR "%s: not XScale!\n", driver_name); + pr_err("%s: not XScale!\n", driver_name); return -ENODEV; } @@ -2128,7 +2121,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) break; #endif default: - printk(KERN_ERR "%s: unrecognized processor: %08x\n", + pr_err("%s: unrecognized processor: %08x\n", driver_name, chiprev); /* iop3xx, ixp4xx, ... */ return -ENODEV; @@ -2199,7 +2192,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) retval = request_irq(irq, pxa2xx_udc_irq, IRQF_DISABLED, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %d, err %d\n", + pr_err("%s: can't get irq %d, err %d\n", driver_name, irq, retval); goto err_irq1; } @@ -2212,7 +2205,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_DISC_IRQ, retval); lubbock_fail0: goto err_irq_lub; @@ -2222,7 +2215,7 @@ lubbock_fail0: IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_IRQ, retval); free_irq(LUBBOCK_USB_DISC_IRQ, dev); goto lubbock_fail0; @@ -2235,12 +2228,12 @@ lubbock_fail0: IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %i, err %d\n", + pr_err("%s: can't get irq %i, err %d\n", driver_name, vbus_irq, retval); goto err_vbus_irq; } } - create_proc_files(); + create_debug_files(dev); return 0; @@ -2277,7 +2270,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) return -EBUSY; udc_disable(dev); - remove_proc_files(); + remove_debug_files(dev); if (dev->got_irq) { free_irq(platform_get_irq(pdev, 0), dev); @@ -2361,7 +2354,7 @@ static struct platform_driver udc_driver = { static int __init udc_init(void) { - printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); + pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); return platform_driver_probe(&udc_driver, pxa2xx_udc_probe); } module_init(udc_init); diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1db46d705777..b67e3ff5e4eb 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -129,6 +129,10 @@ struct pxa2xx_udc { struct pxa2xx_udc_mach_info *mach; u64 dma_mask; struct pxa2xx_ep ep [PXA_UDC_NUM_ENDPOINTS]; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_udc; +#endif }; /*-------------------------------------------------------------------------*/ @@ -151,17 +155,19 @@ static struct pxa2xx_udc *the_controller; #define DBG_NOISY 3 /* ... even more: request level */ #define DBG_VERY_NOISY 4 /* ... even more: packet level */ +#define DMSG(stuff...) pr_debug("udc: " stuff) + #ifdef DEBUG +static int is_vbus_present(void); + static const char *state_name[] = { "EP0_IDLE", "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", "EP0_END_XFER", "EP0_STALL" }; -#define DMSG(stuff...) printk(KERN_DEBUG "udc: " stuff) - -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG # define UDC_DEBUG DBG_VERBOSE #else # define UDC_DEBUG DBG_NORMAL @@ -207,7 +213,7 @@ dump_state(struct pxa2xx_udc *dev) unsigned i; DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - is_usb_connected() ? "host " : "disconnected", + is_vbus_present() ? "host " : "disconnected", state_name[dev->ep0state], UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); dump_udccr("udccr"); @@ -224,7 +230,7 @@ dump_state(struct pxa2xx_udc *dev) } else DMSG("ep0 driver '%s'\n", dev->driver->driver.name); - if (!is_usb_connected()) + if (!is_vbus_present()) return; dump_udccs0 ("udccs0"); @@ -233,7 +239,7 @@ dump_state(struct pxa2xx_udc *dev) dev->stats.read.bytes, dev->stats.read.ops); for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { - if (dev->ep [i].desc == 0) + if (dev->ep [i].desc == NULL) continue; DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs); } @@ -241,8 +247,6 @@ dump_state(struct pxa2xx_udc *dev) #else -#define DMSG(stuff...) do{}while(0) - #define dump_udccr(x) do{}while(0) #define dump_udccs0(x) do{}while(0) #define dump_state(x) do{}while(0) @@ -253,8 +257,9 @@ dump_state(struct pxa2xx_udc *dev) #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) +#define ERR(stuff...) pr_err("udc: " stuff) +#define WARN(stuff...) pr_warning("udc: " stuff) +#define INFO(stuff...) pr_info("udc: " stuff) #endif /* __LINUX_USB_GADGET_PXA2XX_H */ diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index db1b2bfcee4e..3d036647431f 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -53,21 +53,18 @@ */ #if 0 -#define DBG(str,args...) do { \ - if (rndis_debug) \ - printk(KERN_DEBUG str , ## args ); \ - } while (0) static int rndis_debug = 0; - module_param (rndis_debug, int, 0); MODULE_PARM_DESC (rndis_debug, "enable debugging"); - #else - #define rndis_debug 0 -#define DBG(str,args...) do{}while(0) #endif +#define DBG(str,args...) do { \ + if (rndis_debug) \ + pr_debug(str , ## args); \ + } while (0) + #define RNDIS_MAX_CONFIGS 1 @@ -679,7 +676,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, #endif default: - printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", + pr_warning("%s: query unknown OID 0x%08X\n", __FUNCTION__, OID); } if (retval < 0) @@ -804,7 +801,7 @@ update_linkstate: #endif /* RNDIS_PM */ default: - printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", + pr_warning("%s: set unknown OID 0x%08X, size %d\n", __FUNCTION__, OID, buf_len); } @@ -1126,8 +1123,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf) * In one case those messages seemed to relate to the host * suspending itself. */ - printk (KERN_WARNING - "%s: unknown RNDIS message 0x%08X len %d\n", + pr_warning("%s: unknown RNDIS message 0x%08X len %d\n", __FUNCTION__ , MsgType, MsgLength); { unsigned i; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 4ce050c3d13f..aadc4204d6f9 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -893,7 +893,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) /* * s3c2410_udc_irq - interrupt handler */ -static irqreturn_t s3c2410_udc_irq(int irq, void *_dev) +static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) { struct s3c2410_udc *dev = _dev; int usb_status; @@ -1016,7 +1016,7 @@ static irqreturn_t s3c2410_udc_irq(int irq, void *_dev) } } - dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq); + dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); /* Restore old index */ udc_write(idx, S3C2410_UDC_INDEX_REG); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f5738eb8e765..f5c3896b1d95 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -89,9 +89,9 @@ static int debug = 1; #endif #define gs_debug(format, arg...) \ - do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) + do { if (debug) pr_debug(format, ## arg); } while (0) #define gs_debug_level(level, format, arg...) \ - do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) + do { if (debug >= level) pr_debug(format, ## arg); } while (0) /* Thanks to NetChip Technologies for donating this product ID. @@ -553,7 +553,8 @@ static int __init gs_module_init(void) retval = usb_gadget_register_driver(&gs_gadget_driver); if (retval) { - printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval); + pr_err("gs_module_init: cannot register gadget driver, " + "ret=%d\n", retval); return retval; } @@ -579,11 +580,13 @@ static int __init gs_module_init(void) if (retval) { usb_gadget_unregister_driver(&gs_gadget_driver); put_tty_driver(gs_tty_driver); - printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval); + pr_err("gs_module_init: cannot register tty driver, " + "ret=%d\n", retval); return retval; } - printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR); + pr_info("gs_module_init: %s %s loaded\n", + GS_LONG_NAME, GS_VERSION_STR); return 0; } @@ -598,7 +601,8 @@ static void __exit gs_module_exit(void) put_tty_driver(gs_tty_driver); usb_gadget_unregister_driver(&gs_gadget_driver); - printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR); + pr_info("gs_module_exit: %s %s unloaded\n", + GS_LONG_NAME, GS_VERSION_STR); } /* TTY Driver */ @@ -621,7 +625,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file); if (port_num < 0 || port_num >= GS_NUM_PORTS) { - printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n", + pr_err("gs_open: (%d,%p,%p) invalid port number\n", port_num, tty, file); return -ENODEV; } @@ -629,15 +633,14 @@ static int gs_open(struct tty_struct *tty, struct file *file) dev = gs_device; if (dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n", + pr_err("gs_open: (%d,%p,%p) NULL device pointer\n", port_num, tty, file); return -ENODEV; } mtx = &gs_open_close_lock[port_num]; if (mutex_lock_interruptible(mtx)) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) interrupted waiting for mutex\n", + pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n", port_num, tty, file); return -ERESTARTSYS; } @@ -645,8 +648,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_lock_irqsave(&dev->dev_lock, flags); if (dev->dev_config == GS_NO_CONFIG_ID) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) device is not connected\n", + pr_err("gs_open: (%d,%p,%p) device is not connected\n", port_num, tty, file); ret = -ENODEV; goto exit_unlock_dev; @@ -655,7 +657,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) port = dev->dev_port[port_num]; if (port == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n", + pr_err("gs_open: (%d,%p,%p) NULL port pointer\n", port_num, tty, file); ret = -ENODEV; goto exit_unlock_dev; @@ -665,7 +667,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_unlock(&dev->dev_lock); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n", port_num, tty, file); ret = -EIO; goto exit_unlock_port; @@ -692,8 +694,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* might have been disconnected while asleep, check */ if (port->port_dev == NULL) { - printk(KERN_ERR - "gs_open: (%d,%p,%p) port disconnected (2)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n", port_num, tty, file); port->port_in_use = 0; ret = -EIO; @@ -701,7 +702,8 @@ static int gs_open(struct tty_struct *tty, struct file *file) } if ((port->port_write_buf=buf) == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n", + pr_err("gs_open: (%d,%p,%p) cannot allocate " + "port write buffer\n", port_num, tty, file); port->port_in_use = 0; ret = -ENOMEM; @@ -714,7 +716,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* might have been disconnected while asleep, check */ if (port->port_dev == NULL) { - printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n", + pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n", port_num, tty, file); port->port_in_use = 0; ret = -EIO; @@ -762,7 +764,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) struct mutex *mtx; if (port == NULL) { - printk(KERN_ERR "gs_close: NULL port pointer\n"); + pr_err("gs_close: NULL port pointer\n"); return; } @@ -774,8 +776,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); if (port->port_open_count == 0) { - printk(KERN_ERR - "gs_close: (%d,%p,%p) port is already closed\n", + pr_err("gs_close: (%d,%p,%p) port is already closed\n", port->port_num, tty, file); goto exit; } @@ -837,7 +838,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) int ret; if (port == NULL) { - printk(KERN_ERR "gs_write: NULL port pointer\n"); + pr_err("gs_write: NULL port pointer\n"); return -EIO; } @@ -850,14 +851,14 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n", + pr_err("gs_write: (%d,%p) port is not connected\n", port->port_num, tty); ret = -EIO; goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_write: (%d,%p) port is closed\n", + pr_err("gs_write: (%d,%p) port is closed\n", port->port_num, tty); ret = -EBADF; goto exit; @@ -888,7 +889,7 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_put_char: NULL port pointer\n"); + pr_err("gs_put_char: NULL port pointer\n"); return; } @@ -898,13 +899,13 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n", + pr_err("gs_put_char: (%d,%p) port is not connected\n", port->port_num, tty); goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n", + pr_err("gs_put_char: (%d,%p) port is closed\n", port->port_num, tty); goto exit; } @@ -924,7 +925,7 @@ static void gs_flush_chars(struct tty_struct *tty) struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_flush_chars: NULL port pointer\n"); + pr_err("gs_flush_chars: NULL port pointer\n"); return; } @@ -933,14 +934,13 @@ static void gs_flush_chars(struct tty_struct *tty) spin_lock_irqsave(&port->port_lock, flags); if (port->port_dev == NULL) { - printk(KERN_ERR - "gs_flush_chars: (%d,%p) port is not connected\n", + pr_err("gs_flush_chars: (%d,%p) port is not connected\n", port->port_num, tty); goto exit; } if (port->port_open_count == 0) { - printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n", + pr_err("gs_flush_chars: (%d,%p) port is closed\n", port->port_num, tty); goto exit; } @@ -1038,7 +1038,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, struct gs_port *port = tty->driver_data; if (port == NULL) { - printk(KERN_ERR "gs_ioctl: NULL port pointer\n"); + pr_err("gs_ioctl: NULL port pointer\n"); return -EIO; } @@ -1076,7 +1076,7 @@ static int gs_send(struct gs_dev *dev) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_send: NULL device pointer\n"); + pr_err("gs_send: NULL device pointer\n"); return -ENODEV; } @@ -1103,7 +1103,7 @@ static int gs_send(struct gs_dev *dev) req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR + pr_err( "gs_send: cannot queue read request, ret=%d\n", ret); spin_lock_irqsave(&dev->dev_lock, flags); @@ -1144,9 +1144,7 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size) port = dev->dev_port[0]; if (port == NULL) { - printk(KERN_ERR - "gs_send_packet: port=%d, NULL port pointer\n", - 0); + pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0); return -EIO; } @@ -1193,7 +1191,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) port = dev->dev_port[0]; if (port == NULL) { - printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n", + pr_err("gs_recv_packet: port=%d, NULL port pointer\n", port->port_num); return -EIO; } @@ -1201,7 +1199,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) spin_lock(&port->port_lock); if (port->port_open_count == 0) { - printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n", + pr_err("gs_recv_packet: port=%d, port is closed\n", port->port_num); ret = -EIO; goto exit; @@ -1211,14 +1209,14 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) tty = port->port_tty; if (tty == NULL) { - printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n", + pr_err("gs_recv_packet: port=%d, NULL tty pointer\n", port->port_num); ret = -EIO; goto exit; } if (port->port_tty->magic != TTY_MAGIC) { - printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n", + pr_err("gs_recv_packet: port=%d, bad tty magic\n", port->port_num); ret = -EIO; goto exit; @@ -1245,7 +1243,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) struct gs_dev *dev = ep->driver_data; if (dev == NULL) { - printk(KERN_ERR "gs_read_complete: NULL device pointer\n"); + pr_err("gs_read_complete: NULL device pointer\n"); return; } @@ -1256,7 +1254,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) requeue: req->length = ep->maxpacket; if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR + pr_err( "gs_read_complete: cannot queue read request, ret=%d\n", ret); } @@ -1270,7 +1268,7 @@ requeue: default: /* unexpected */ - printk(KERN_ERR + pr_err( "gs_read_complete: unexpected status error, status=%d\n", req->status); goto requeue; @@ -1287,7 +1285,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) struct gs_req_entry *gs_req = req->context; if (dev == NULL) { - printk(KERN_ERR "gs_write_complete: NULL device pointer\n"); + pr_err("gs_write_complete: NULL device pointer\n"); return; } @@ -1296,8 +1294,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) /* normal completion */ requeue: if (gs_req == NULL) { - printk(KERN_ERR - "gs_write_complete: NULL request pointer\n"); + pr_err("gs_write_complete: NULL request pointer\n"); return; } @@ -1316,7 +1313,7 @@ requeue: break; default: - printk(KERN_ERR + pr_err( "gs_write_complete: unexpected status error, status=%d\n", req->status); goto requeue; @@ -1351,7 +1348,7 @@ static int __init gs_bind(struct usb_gadget *gadget) gs_device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); else { - printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", + pr_warning("gs_bind: controller '%s' not recognized\n", gadget->name); /* unrecognized, but safe unless bulk is REALLY quirky */ gs_device_desc.bcdDevice = @@ -1375,7 +1372,7 @@ static int __init gs_bind(struct usb_gadget *gadget) if (use_acm) { ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); if (!ep) { - printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); + pr_err("gs_bind: cannot run ACM on %s\n", gadget->name); goto autoconf_fail; } gs_device_desc.idProduct = __constant_cpu_to_le16( @@ -1425,7 +1422,7 @@ static int __init gs_bind(struct usb_gadget *gadget) set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { - printk(KERN_ERR "gs_bind: cannot allocate ports\n"); + pr_err("gs_bind: cannot allocate ports\n"); gs_unbind(gadget); return ret; } @@ -1441,13 +1438,13 @@ static int __init gs_bind(struct usb_gadget *gadget) gadget->ep0->driver_data = dev; - printk(KERN_INFO "gs_bind: %s %s bound\n", + pr_info("gs_bind: %s %s bound\n", GS_LONG_NAME, GS_VERSION_STR); return 0; autoconf_fail: - printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); + pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name); return -ENODEV; } @@ -1480,7 +1477,7 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) set_gadget_data(gadget, NULL); } - printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME, + pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME, GS_VERSION_STR); } @@ -1513,7 +1510,8 @@ static int gs_setup(struct usb_gadget *gadget, break; default: - printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", + pr_err("gs_setup: unknown request, type=%02x, request=%02x, " + "value=%04x, index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; @@ -1526,7 +1524,7 @@ static int gs_setup(struct usb_gadget *gadget, && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { - printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n", + pr_err("gs_setup: cannot queue response, ret=%d\n", ret); req->status = 0; gs_setup_complete(gadget->ep0, req); @@ -1656,7 +1654,8 @@ set_interface_done: break; default: - printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", + pr_err("gs_setup: unknown standard request, type=%02x, " + "request=%02x, value=%04x, index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; @@ -1682,7 +1681,7 @@ static int gs_setup_class(struct usb_gadget *gadget, * handler copy that data to port->port_line_coding (iff * it's valid) and maybe pass it on. Until then, fail. */ - printk(KERN_WARNING "gs_setup: set_line_coding " + pr_warning("gs_setup: set_line_coding " "unuspported\n"); break; @@ -1702,12 +1701,12 @@ static int gs_setup_class(struct usb_gadget *gadget, * handler use that to set the state (iff it's valid) and * maybe pass it on. Until then, fail. */ - printk(KERN_WARNING "gs_setup: set_control_line_state " + pr_warning("gs_setup: set_control_line_state " "unuspported\n"); break; default: - printk(KERN_ERR "gs_setup: unknown class request, " + pr_err("gs_setup: unknown class request, " "type=%02x, request=%02x, value=%04x, " "index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -1724,7 +1723,8 @@ static int gs_setup_class(struct usb_gadget *gadget, static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) { - printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n", + pr_err("gs_setup_complete: status error, status=%d, " + "actual=%d, length=%d\n", req->status, req->actual, req->length); } } @@ -1751,11 +1751,11 @@ static void gs_disconnect(struct usb_gadget *gadget) /* re-allocate ports for the next connection */ if (gs_alloc_ports(dev, GFP_ATOMIC) != 0) - printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n"); + pr_err("gs_disconnect: cannot re-allocate ports\n"); spin_unlock_irqrestore(&dev->dev_lock, flags); - printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME); + pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME); } /* @@ -1778,7 +1778,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_set_config: NULL device pointer\n"); + pr_err("gs_set_config: NULL device pointer\n"); return 0; } @@ -1823,7 +1823,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_notify_ep = ep; dev->dev_notify_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable NOTIFY " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1839,7 +1840,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_in_ep = ep; dev->dev_in_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable IN " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1855,7 +1857,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) dev->dev_out_ep = ep; dev->dev_out_ep_desc = ep_desc; } else { - printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n", + pr_err("gs_set_config: cannot enable OUT " + "endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } @@ -1865,7 +1868,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) { - printk(KERN_ERR "gs_set_config: cannot find endpoints\n"); + pr_err("gs_set_config: cannot find endpoints\n"); ret = -ENODEV; goto exit_reset_config; } @@ -1876,11 +1879,12 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) { req->complete = gs_read_complete; if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) { - printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n", - ret); + pr_err("gs_set_config: cannot queue read " + "request, ret=%d\n", ret); } } else { - printk(KERN_ERR "gs_set_config: cannot allocate read requests\n"); + pr_err("gs_set_config: cannot allocate " + "read requests\n"); ret = -ENOMEM; goto exit_reset_config; } @@ -1893,13 +1897,14 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) req_entry->re_req->complete = gs_write_complete; list_add(&req_entry->re_entry, &dev->dev_req_list); } else { - printk(KERN_ERR "gs_set_config: cannot allocate write requests\n"); + pr_err("gs_set_config: cannot allocate " + "write requests\n"); ret = -ENOMEM; goto exit_reset_config; } } - printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n", + pr_info("gs_set_config: %s configured, %s speed %s config\n", GS_LONG_NAME, gadget->speed == USB_SPEED_HIGH ? "high" : "full", config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM"); @@ -1926,7 +1931,7 @@ static void gs_reset_config(struct gs_dev *dev) struct gs_req_entry *req_entry; if (dev == NULL) { - printk(KERN_ERR "gs_reset_config: NULL device pointer\n"); + pr_err("gs_reset_config: NULL device pointer\n"); return; } diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcde5d9c87df..d3d4f4048e6c 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1115,7 +1115,7 @@ zero_bind (struct usb_gadget *gadget) ep = usb_ep_autoconfig (gadget, &fs_source_desc); if (!ep) { autoconf_fail: - printk (KERN_ERR "%s: can't autoconfigure on %s\n", + pr_err("%s: can't autoconfigure on %s\n", shortname, gadget->name); return -ENODEV; } @@ -1139,7 +1139,7 @@ autoconf_fail: * things like configuration and altsetting numbering * can need hardware-specific attention though. */ - printk (KERN_WARNING "%s: controller '%s' not recognized\n", + pr_warning("%s: controller '%s' not recognized\n", shortname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999); } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 49a91c5ee51b..d97b16b52efa 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -29,15 +29,6 @@ config USB_EHCI_HCD To compile this driver as a module, choose M here: the module will be called ehci-hcd. -config USB_EHCI_SPLIT_ISO - bool "Full speed ISO transactions (EXPERIMENTAL)" - depends on USB_EHCI_HCD && EXPERIMENTAL - default n - ---help--- - This code is new and hasn't been used with many different - EHCI or USB 2.0 transaction translator implementations. - It should work for ISO-OUT transfers, like audio. - config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators (EXPERIMENTAL)" depends on USB_EHCI_HCD && EXPERIMENTAL @@ -69,21 +60,30 @@ config USB_EHCI_TT_NEWSCHED config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX) + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX) default y config USB_EHCI_BIG_ENDIAN_DESC bool - depends on USB_EHCI_HCD && 440EPX + depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX) default y config USB_EHCI_FSL bool + depends on USB_EHCI_HCD select USB_EHCI_ROOT_HUB_TT default y if MPC834x || PPC_MPC831x ---help--- Variation of ARC USB block used in some Freescale chips. +config USB_EHCI_HCD_PPC_OF + bool "EHCI support for PPC USB controller on OF platform bus" + depends on USB_EHCI_HCD && PPC_OF + default y + ---help--- + Enables support for the USB controller present on the PowerPC + OpenFirmware platform bus. + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 766ef68a0b43..da7532d38bf1 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -222,6 +222,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index c9cc4413198e..64ebfc5548a3 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -323,7 +323,43 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } #else -/* troubleshooting help: expose state in sysfs */ +/* troubleshooting help: expose state in debugfs */ + +static int debug_async_open(struct inode *, struct file *); +static int debug_periodic_open(struct inode *, struct file *); +static int debug_registers_open(struct inode *, struct file *); +static int debug_async_open(struct inode *, struct file *); +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, +}; + +static struct dentry *ehci_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct usb_bus *bus; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *page; +}; #define speed_char(info1) ({ char tmp; \ switch (info1 & (3 << 12)) { \ @@ -441,10 +477,8 @@ done: *nextp = next; } -static ssize_t -show_async (struct class_device *class_dev, char *buf) +static ssize_t fill_async_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -452,14 +486,13 @@ show_async (struct class_device *class_dev, char *buf) char *next; struct ehci_qh *qh; - *buf = 0; - - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; + *next = 0; + /* dumps a snapshot of the async schedule. * usually empty except for long-term bulk reads, or head. * one QH per line, and TDs we know about @@ -477,16 +510,12 @@ show_async (struct class_device *class_dev, char *buf) } spin_unlock_irqrestore (&ehci->lock, flags); - return strlen (buf); + return strlen(buf->page); } -static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL); #define DBG_SCHED_LIMIT 64 - -static ssize_t -show_periodic (struct class_device *class_dev, char *buf) +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -500,10 +529,9 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size); @@ -623,14 +651,10 @@ show_periodic (struct class_device *class_dev, char *buf) return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); - #undef DBG_SCHED_LIMIT -static ssize_t -show_registers (struct class_device *class_dev, char *buf) +static ssize_t fill_registers_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ehci_hcd *ehci; unsigned long flags; @@ -639,15 +663,14 @@ show_registers (struct class_device *class_dev, char *buf) static char fmt [] = "%*s\n"; static char label [] = ""; - bus = class_get_devdata(class_dev); - hcd = bus_to_hcd(bus); + hcd = bus_to_hcd(buf->bus); ehci = hcd_to_ehci (hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; spin_lock_irqsave (&ehci->lock, flags); - if (bus->controller->power.power_state.event) { + if (buf->bus->controller->power.power_state.event) { size = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" @@ -763,9 +786,7 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p%s\n", - ehci->reclaim, - ehci->reclaim_ready ? " ready" : ""); + temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim); size -= temp; next += temp; } @@ -789,26 +810,150 @@ done: return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); -static inline void create_debug_files (struct ehci_hcd *ehci) +static struct debug_buffer *alloc_buffer(struct usb_bus *bus, + ssize_t (*fill_func)(struct debug_buffer *)) { - struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; - int retval; + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); - retval = class_device_create_file(cldev, &class_device_attr_async); - retval = class_device_create_file(cldev, &class_device_attr_periodic); - retval = class_device_create_file(cldev, &class_device_attr_registers); + if (buf) { + buf->bus = bus; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + } + + return buf; } -static inline void remove_debug_files (struct ehci_hcd *ehci) +static int fill_buffer(struct debug_buffer *buf) { - struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; + int ret = 0; + + if (!buf->page) + buf->page = (char *)get_zeroed_page(GFP_KERNEL); + + if (!buf->page) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); - class_device_remove_file(cldev, &class_device_attr_async); - class_device_remove_file(cldev, &class_device_attr_periodic); - class_device_remove_file(cldev, &class_device_attr_registers); + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; } -#endif /* STUB_DEBUG_FILES */ +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->page, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + if (buf) { + if (buf->page) + free_page((unsigned long)buf->page); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_periodic_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static inline void create_debug_files (struct ehci_hcd *ehci) +{ + struct usb_bus *bus = &ehci_to_hcd(ehci)->self; + + ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root); + if (!ehci->debug_dir) + goto dir_error; + + ehci->debug_async = debugfs_create_file("async", S_IRUGO, + ehci->debug_dir, bus, + &debug_async_fops); + if (!ehci->debug_async) + goto async_error; + + ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, + ehci->debug_dir, bus, + &debug_periodic_fops); + if (!ehci->debug_periodic) + goto periodic_error; + + ehci->debug_registers = debugfs_create_file("registers", S_IRUGO, + ehci->debug_dir, bus, + &debug_registers_fops); + if (!ehci->debug_registers) + goto registers_error; + return; + +registers_error: + debugfs_remove(ehci->debug_periodic); +periodic_error: + debugfs_remove(ehci->debug_async); +async_error: + debugfs_remove(ehci->debug_dir); +dir_error: + ehci->debug_periodic = NULL; + ehci->debug_async = NULL; + ehci->debug_dir = NULL; +} + +static inline void remove_debug_files (struct ehci_hcd *ehci) +{ + debugfs_remove(ehci->debug_registers); + debugfs_remove(ehci->debug_periodic); + debugfs_remove(ehci->debug_async); + debugfs_remove(ehci->debug_dir); +} + +#endif /* STUB_DEBUG_FILES */ diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 430821cb95c8..adb0defa1631 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -25,7 +25,7 @@ #include "ehci-fsl.h" -/* FIXME: Power Managment is un-ported so temporarily disable it */ +/* FIXME: Power Management is un-ported so temporarily disable it */ #undef CONFIG_PM /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ @@ -323,6 +323,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; static int ehci_fsl_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5f2d74ed5ad7..4caa6a8b9a37 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -33,6 +33,7 @@ #include <linux/usb.h> #include <linux/moduleparam.h> #include <linux/dma-mapping.h> +#include <linux/debugfs.h> #include "../core/hcd.h" @@ -109,7 +110,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -266,6 +267,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ +static void end_unlink_async(struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -275,25 +277,41 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ -static void ehci_watchdog (unsigned long param) +static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; + u32 status, cmd; spin_lock_irqsave (&ehci->lock, flags); + WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen with a vt8235 */ + status = ehci_readl(ehci, &ehci->regs->status); + cmd = ehci_readl(ehci, &ehci->regs->command); + ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); + + /* lost IAA irqs wedge things badly; seen first with a vt8235 */ if (ehci->reclaim) { - u32 status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); - ehci->reclaim_ready = 1; } + ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command); + end_unlink_async(ehci); } - /* stop async processing after it's idled a bit */ + spin_unlock_irqrestore(&ehci->lock, flags); +} + +static void ehci_watchdog(unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + unsigned long flags; + + spin_lock_irqsave(&ehci->lock, flags); + + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -363,8 +381,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -399,6 +415,7 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -447,6 +464,10 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; + init_timer(&ehci->iaa_watchdog); + ehci->iaa_watchdog.function = ehci_iaa_watchdog; + ehci->iaa_watchdog.data = (unsigned long) ehci; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -463,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; - ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -654,8 +674,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - ehci->reclaim_ready = 1; - bh = 1; + end_unlink_async(ehci); } /* remote wakeup [4.3.1] */ @@ -761,10 +780,16 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { + /* failfast */ + if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) + end_unlink_async(ehci); + + /* if it's not linked then there's nothing to do */ + if (qh->qh_state != QH_STATE_LINKED) + ; + + /* defer till later if busy */ + else if (ehci->reclaim) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -774,12 +799,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* bypass IAA if the hc can't care */ - } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) - end_unlink_async (ehci); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) + /* start IAA cycle */ + } else start_unlink_async (ehci, qh); } @@ -806,7 +827,19 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - unlink_async (ehci, qh); + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + unlink_async(ehci, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + WARN_ON(1); + break; + } break; case PIPE_INTERRUPT: @@ -829,16 +862,16 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) && HC_IS_RUNNING (hcd->state)) { - int status; + int schedule_status; - status = qh_schedule (ehci, qh); + schedule_status = qh_schedule (ehci, qh); spin_unlock_irqrestore (&ehci->lock, flags); - if (status != 0) { + if (schedule_status != 0) { // shouldn't happen often, but ... // FIXME kill those tds' urbs err ("can't reschedule qh %p, err %d", - qh, status); + qh, schedule_status); } return status; } @@ -898,6 +931,7 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); @@ -959,11 +993,26 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver #endif -#ifdef CONFIG_440EPX +#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE) #include "ehci-ppc-soc.c" #define PLATFORM_DRIVER ehci_ppc_soc_driver #endif +#ifdef CONFIG_USB_EHCI_HCD_PPC_OF +#include "ehci-ppc-of.c" +#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver +#endif + +#ifdef CONFIG_ARCH_ORION +#include "ehci-orion.c" +#define PLATFORM_DRIVER ehci_orion_driver +#endif + +#ifdef CONFIG_ARCH_IXP4XX +#include "ehci-ixp4xx.c" +#define PLATFORM_DRIVER ixp4xx_ehci_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ehci-hcd" @@ -978,41 +1027,66 @@ static int __init ehci_hcd_init(void) sizeof(struct ehci_qh), sizeof(struct ehci_qtd), sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); +#ifdef DEBUG + ehci_debug_root = debugfs_create_dir("ehci", NULL); + if (!ehci_debug_root) + return -ENOENT; +#endif + #ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) - return retval; + goto clean0; #endif #ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) { -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif - return retval; - } + if (retval < 0) + goto clean1; #endif #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) { -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); + if (retval < 0) + goto clean2; +#endif + +#ifdef OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + if (retval < 0) + goto clean3; +#endif + return retval; + +#ifdef OF_PLATFORM_DRIVER + /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ +clean3: +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +clean2: #endif #ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); + pci_unregister_driver(&PCI_DRIVER); +clean1: #endif - return retval; - } +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +clean0: +#endif +#ifdef DEBUG + debugfs_remove(ehci_debug_root); + ehci_debug_root = NULL; #endif - return retval; } module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif @@ -1022,6 +1096,9 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif +#ifdef DEBUG + debugfs_remove(ehci_debug_root); +#endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 735db4aec831..40e8240b7851 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -123,6 +123,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) if (time_before (jiffies, ehci->next_statechange)) msleep(5); + del_timer_sync(&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); @@ -134,7 +136,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); /* Unlike other USB host controller types, EHCI doesn't have @@ -170,8 +172,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } } + /* Apparently some devices need a >= 1-uframe delay here */ + if (ehci->bus_suspended) + udelay(150); + /* turn off now-idle HC */ - del_timer_sync (&ehci->watchdog); ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; @@ -291,14 +296,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ /* Display the ports dedicated to the companion controller */ -static ssize_t show_companion(struct class_device *class_dev, char *buf) +static ssize_t show_companion(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ehci_hcd *ehci; int nports, index, n; int count = PAGE_SIZE; char *ptr = buf; - ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); nports = HCS_N_PORTS(ehci->hcs_params); for (index = 0; index < nports; ++index) { @@ -312,40 +319,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf) } /* - * Dedicate or undedicate a port to the companion controller. - * Syntax is "[-]portnum", where a leading '-' sign means - * return control of the port to the EHCI controller. + * Sets the owner of a port */ -static ssize_t store_companion(struct class_device *class_dev, - const char *buf, size_t count) +static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) { - struct ehci_hcd *ehci; - int portnum, new_owner, try; u32 __iomem *status_reg; u32 port_status; + int try; - ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); - new_owner = PORT_OWNER; /* Owned by companion */ - if (sscanf(buf, "%d", &portnum) != 1) - return -EINVAL; - if (portnum < 0) { - portnum = - portnum; - new_owner = 0; /* Owned by EHCI */ - } - if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) - return -ENOENT; - status_reg = &ehci->regs->port_status[--portnum]; - if (new_owner) - set_bit(portnum, &ehci->companion_ports); - else - clear_bit(portnum, &ehci->companion_ports); + status_reg = &ehci->regs->port_status[portnum]; /* * The controller won't set the OWNER bit if the port is * enabled, so this loop will sometimes require at least two * iterations: one to disable the port and one to set OWNER. */ - for (try = 4; try > 0; --try) { spin_lock_irq(&ehci->lock); port_status = ehci_readl(ehci, status_reg); @@ -362,9 +350,39 @@ static ssize_t store_companion(struct class_device *class_dev, if (try > 1) msleep(5); } +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + portnum--; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + set_owner(ehci, portnum, new_owner); return count; } -static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); +static DEVICE_ATTR(companion, 0644, show_companion, store_companion); static inline void create_companion_file(struct ehci_hcd *ehci) { @@ -372,16 +390,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci) /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, - &class_device_attr_companion); + i = device_create_file(ehci_to_hcd(ehci)->self.dev, + &dev_attr_companion); } static inline void remove_companion_file(struct ehci_hcd *ehci) { /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, - &class_device_attr_companion); + device_remove_file(ehci_to_hcd(ehci)->self.dev, + &dev_attr_companion); } @@ -393,10 +411,8 @@ static int check_reset_complete ( u32 __iomem *status_reg, int port_status ) { - if (!(port_status & PORT_CONNECT)) { - ehci->reset_done [index] = 0; + if (!(port_status & PORT_CONNECT)) return port_status; - } /* if reset finished and it's still not enabled -- handoff */ if (!(port_status & PORT_PE)) { @@ -475,8 +491,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) * controller by the user. */ - if (!(temp & PORT_CONNECT)) - ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 && time_after_eq(jiffies, @@ -864,3 +878,13 @@ error: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } + +static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + if (ehci_is_TDI(ehci)) + return; + set_owner(ehci, --portnum, PORT_OWNER); +} + diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c new file mode 100644 index 000000000000..3041d8f055f4 --- /dev/null +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -0,0 +1,152 @@ +/* + * IXP4XX EHCI Host Controller Driver + * + * Author: Vladimir Barinov <vbarinov@ru.mvista.com> + * + * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com> + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/platform_device.h> + +static int ixp4xx_ehci_init(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval = 0; + + ehci->big_endian_desc = 1; + ehci->big_endian_mmio = 1; + + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ehci->is_tdi_rh_tt = 1; + ehci_reset(ehci); + + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci_port_power(ehci, 0); + + return retval; +} + +static const struct hc_driver ixp4xx_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "IXP4XX EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = ixp4xx_ehci_init, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .get_frame_number = ehci_get_frame, + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#if defined(CONFIG_PM) + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +static int ixp4xx_ehci_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + const struct hc_driver *driver = &ixp4xx_ehci_hc_driver; + struct resource *res; + int irq; + int retval; + + if (usb_disabled()) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + return -ENODEV; + } + irq = res->start; + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto fail_create_hcd; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + pdev->dev.bus_id); + retval = -ENODEV; + goto fail_request_resource; + } + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + driver->description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + retval = -EBUSY; + goto fail_request_resource; + } + + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (hcd->regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail_ioremap; + } + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) + goto fail_add_hcd; + + return retval; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +fail_request_resource: + usb_put_hcd(hcd); +fail_create_hcd: + dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval); + return retval; +} + +static int ixp4xx_ehci_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + return 0; +} + +MODULE_ALIAS("ixp4xx-ehci"); + +static struct platform_driver ixp4xx_ehci_driver = { + .probe = ixp4xx_ehci_probe, + .remove = ixp4xx_ehci_remove, + .driver = { + .name = "ixp4xx-ehci", + .bus = &platform_bus_type + }, +}; diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c new file mode 100644 index 000000000000..e129981f139f --- /dev/null +++ b/drivers/usb/host/ehci-orion.c @@ -0,0 +1,272 @@ +/* + * drivers/usb/host/ehci-orion.c + * + * Tzachi Perelstein <tzachi@marvell.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <asm/arch/orion.h> + +#define rdl(off) __raw_readl(hcd->regs + (off)) +#define wrl(off, val) __raw_writel((val), hcd->regs + (off)) + +#define USB_CAUSE 0x310 +#define USB_MASK 0x314 +#define USB_CMD 0x140 +#define USB_MODE 0x1a8 +#define USB_IPG 0x360 +#define USB_PHY_PWR_CTRL 0x400 +#define USB_PHY_TX_CTRL 0x420 +#define USB_PHY_RX_CTRL 0x430 +#define USB_PHY_IVREF_CTRL 0x440 +#define USB_PHY_TST_GRP_CTRL 0x450 + +/* + * Implement Orion USB controller specification guidelines + */ +static void orion_usb_setup(struct usb_hcd *hcd) +{ + /* + * Clear interrupt cause and mask + */ + wrl(USB_CAUSE, 0); + wrl(USB_MASK, 0); + + /* + * Reset controller + */ + wrl(USB_CMD, rdl(USB_CMD) | 0x2); + while (rdl(USB_CMD) & 0x2); + + /* + * GL# USB-10: Set IPG for non start of frame packets + * Bits[14:8]=0xc + */ + wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00); + + /* + * GL# USB-9: USB 2.0 Power Control + * BG_VSEL[7:6]=0x1 + */ + wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40); + + /* + * GL# USB-1: USB PHY Tx Control - force calibration to '8' + * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8 + */ + wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040); + + /* + * GL# USB-3 GL# USB-9: USB PHY Rx Control + * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0, + * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1 + */ + wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010); + + /* + * GL# USB-3 GL# USB-9: USB PHY IVREF Control + * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0 + */ + wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32); + + /* + * GL# USB-3 GL# USB-9: USB PHY Test Group Control + * REG_FIFO_SQ_RST[15]=0 + */ + wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000); + + /* + * Stop and reset controller + */ + wrl(USB_CMD, rdl(USB_CMD) & ~0x1); + wrl(USB_CMD, rdl(USB_CMD) | 0x2); + while (rdl(USB_CMD) & 0x2); + + /* + * GL# USB-5 Streaming disable REG_USB_MODE[4]=1 + * TBD: This need to be done after each reset! + * GL# USB-4 Setup USB Host mode + */ + wrl(USB_MODE, 0x13); +} + +static int ehci_orion_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* + * data structure init + */ + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci_reset(ehci); + ehci_port_power(ehci, 0); + + return retval; +} + +static const struct hc_driver ehci_orion_hc_driver = { + .description = hcd_name, + .product_desc = "Marvell Orion EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_orion_setup, + .start = ehci_run, +#ifdef CONFIG_PM + .suspend = ehci_bus_suspend, + .resume = ehci_bus_resume, +#endif + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +static int __init ehci_orion_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + void __iomem *regs; + int irq, err; + + if (usb_disabled()) + return -ENODEV; + + pr_debug("Initializing Orion-SoC USB Host Controller\n"); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + err = -ENODEV; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + pdev->dev.bus_id); + err = -ENODEV; + goto err1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + ehci_orion_hc_driver.description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + err = -EBUSY; + goto err1; + } + + regs = ioremap(res->start, res->end - res->start + 1); + if (regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + err = -EFAULT; + goto err2; + } + + hcd = usb_create_hcd(&ehci_orion_hc_driver, + &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + err = -ENOMEM; + goto err3; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + hcd->regs = regs; + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + ehci->is_tdi_rh_tt = 1; + ehci->sbrn = 0x20; + + /* + * setup Orion USB controller + */ + orion_usb_setup(hcd); + + err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED); + if (err) + goto err4; + + return 0; + +err4: + usb_put_hcd(hcd); +err3: + iounmap(regs); +err2: + release_mem_region(res->start, res->end - res->start + 1); +err1: + dev_err(&pdev->dev, "init %s fail, %d\n", + pdev->dev.bus_id, err); + + return err; +} + +static int __exit ehci_orion_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + return 0; +} + +MODULE_ALIAS("platform:orion-ehci"); + +static struct platform_driver ehci_orion_driver = { + .probe = ehci_orion_drv_probe, + .remove = __exit_p(ehci_orion_drv_remove), + .shutdown = usb_hcd_platform_shutdown, + .driver.name = "orion-ehci", +}; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index ad0d4965f2fb..3ba01664f821 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); spin_unlock_irq(&ehci->lock); @@ -364,6 +364,7 @@ static const struct hc_driver ehci_pci_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c new file mode 100644 index 000000000000..ee305b1f99ff --- /dev/null +++ b/drivers/usb/host/ehci-ppc-of.c @@ -0,0 +1,238 @@ +/* + * EHCI HCD (Host Controller Driver) for USB. + * + * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus + * Tested on AMCC PPC 440EPx + * + * Valentine Barshak <vbarshak@ru.mvista.com> + * + * Based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de> + * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com> + * + * This file is licenced under the GPL. + */ + +#include <linux/signal.h> + +#include <linux/of.h> +#include <linux/of_platform.h> + +/* called during probe() after chip reset completes */ +static int ehci_ppc_of_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci->sbrn = 0x20; + return ehci_reset(ehci); +} + + +static const struct hc_driver ehci_ppc_of_hc_driver = { + .description = hcd_name, + .product_desc = "OF EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_ppc_of_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + + +/* + * 440EPx Errata USBH_3 + * Fix: Enable Break Memory Transfer (BMT) in INSNREG3 + */ +#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0) +static int __devinit +ppc44x_enable_bmt(struct device_node *dn) +{ + __iomem u32 *insreg_virt; + + insreg_virt = of_iomap(dn, 1); + if (!insreg_virt) + return -EINVAL; + + out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT); + + iounmap(insreg_virt); + return 0; +} + + +static int __devinit +ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dn = op->node; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource res; + int irq; + int rv; + + if (usb_disabled()) + return -ENODEV; + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + + rv = of_address_to_resource(dn, 0, &res); + if (rv) + return rv; + + hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = res.end - res.start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); + rv = -EBUSY; + goto err_rmr; + } + + irq = irq_of_parse_and_map(dn, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); + rv = -EBUSY; + goto err_irq; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + printk(KERN_ERR __FILE__ ": ioremap failed\n"); + rv = -ENOMEM; + goto err_ioremap; + } + + ehci = hcd_to_ehci(hcd); + + if (of_get_property(dn, "big-endian", NULL)) { + ehci->big_endian_mmio = 1; + ehci->big_endian_desc = 1; + } + if (of_get_property(dn, "big-endian-regs", NULL)) + ehci->big_endian_mmio = 1; + if (of_get_property(dn, "big-endian-desc", NULL)) + ehci->big_endian_desc = 1; + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) { + rv = ppc44x_enable_bmt(dn); + ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n", + rv ? "NOT ": ""); + } + + rv = usb_add_hcd(hcd, irq, 0); + if (rv == 0) + return 0; + + iounmap(hcd->regs); +err_ioremap: + irq_dispose_mapping(irq); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return rv; +} + + +static int ehci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + irq_dispose_mapping(hcd->irq); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + + +static int ehci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); + + return 0; +} + + +static struct of_device_id ehci_hcd_ppc_of_match[] = { + { + .compatible = "usb-ehci", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); + + +static struct of_platform_driver ehci_hcd_ppc_of_driver = { + .name = "ppc-of-ehci", + .match_table = ehci_hcd_ppc_of_match, + .probe = ehci_hcd_ppc_of_probe, + .remove = ehci_hcd_ppc_of_remove, + .shutdown = ehci_hcd_ppc_of_shutdown, + .driver = { + .name = "ppc-of-ehci", + .owner = THIS_MODULE, + }, +}; diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 452d4b1bc859..a3249078c808 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -162,6 +162,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 03a6b2f4e6ed..bbda58eb8813 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -72,6 +72,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, #endif + .relinquish_port = ehci_relinquish_port, }; static int ps3_ehci_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b10f39c047e9..776a97f33914 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -198,7 +198,8 @@ static int qtd_copy_status ( /* if async CSPLIT failed, try cleaning out the TT buffer */ if (status != -EPIPE - && urb->dev->tt && !usb_pipeint (urb->pipe) + && urb->dev->tt + && !usb_pipeint(urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_TDI(ehci) @@ -211,6 +212,9 @@ static int qtd_copy_status ( urb->dev->ttport, urb->dev->devnum, usb_pipeendpoint (urb->pipe), token); #endif /* DEBUG */ + /* REVISIT ARC-derived cores don't clear the root + * hub TT buffer in this way... + */ usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } @@ -638,6 +642,7 @@ qh_make ( u32 info1 = 0, info2 = 0; int is_input, type; int maxp = 0; + struct usb_tt *tt = urb->dev->tt; if (!qh) return qh; @@ -661,8 +666,9 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0, - hb_mult (maxp) * max_packet (maxp))); + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + is_input, 0, + hb_mult(maxp) * max_packet(maxp))); qh->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { @@ -680,7 +686,6 @@ qh_make ( goto done; } } else { - struct usb_tt *tt = urb->dev->tt; int think_time; /* gap is f(FS/LS transfer times) */ @@ -736,10 +741,8 @@ qh_make ( /* set the address of the TT; for TDI's integrated * root hub tt, leave it zeroed. */ - if (!ehci_is_TDI(ehci) - || urb->dev->tt->hub != - ehci_to_hcd(ehci)->self.root_hub) - info2 |= urb->dev->tt->hub->devnum << 16; + if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub) + info2 |= tt->hub->devnum << 16; /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ @@ -973,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - timer_action_done (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_done(ehci); // qh->hw_next = cpu_to_hc32(qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -983,7 +986,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; - ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1059,11 +1061,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - ehci->reclaim_ready = 0; cmd |= CMD_IAAD; ehci_writel(ehci, cmd, &ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command); - timer_action (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_start(ehci); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 80d99bce2b38..8a8e08a51ba3 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -119,7 +119,8 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: - usecs += q->itd->usecs [uframe]; + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; @@ -211,7 +212,7 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) * low/fullspeed transfer can "carry over" from one uframe to the next, * since the TT just performs downstream transfers in sequence. * - * For example two seperate 100 usec transfers can start in the same uframe, + * For example two separate 100 usec transfers can start in the same uframe, * and the second one would "carry over" 75 usecs into the next uframe. */ static void @@ -1536,7 +1537,6 @@ itd_link_urb ( uframe = next_uframe & 0x07; frame = next_uframe >> 3; - itd->usecs [uframe] = stream->usecs; itd_patch(ehci, itd, iso_sched, packet, uframe); next_uframe += stream->interval; @@ -1565,6 +1565,16 @@ itd_link_urb ( #define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) +/* Process and recycle a completed ITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ static unsigned itd_complete ( struct ehci_hcd *ehci, @@ -1577,6 +1587,7 @@ itd_complete ( int urb_index = -1; struct ehci_iso_stream *stream = itd->stream; struct usb_device *dev; + unsigned retval = false; /* for each uframe with a packet */ for (uframe = 0; uframe < 8; uframe++) { @@ -1610,30 +1621,21 @@ itd_complete ( } } - usb_put_urb (urb); - itd->urb = NULL; - itd->stream = NULL; - list_move (&itd->itd_list, &stream->free_list); - iso_stream_put (ehci, stream); - /* handle completion now? */ if (likely ((urb_index + 1) != urb->number_of_packets)) - return 0; + goto done; /* ASSERT: it's really the last itd for this urb list_for_each_entry (itd, &stream->td_list, itd_list) BUG_ON (itd->urb == urb); */ - /* give urb back to the driver ... can be out-of-order */ + /* give urb back to the driver; completion often (re)submits */ dev = urb->dev; ehci_urb_done(ehci, urb, 0); + retval = true; urb = NULL; - - /* defer stopping schedule; completion can submit */ ehci->periodic_sched--; - if (unlikely (!ehci->periodic_sched)) - (void) disable_periodic (ehci); ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (unlikely (list_empty (&stream->td_list))) { @@ -1645,8 +1647,15 @@ itd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); + /* OK to recycle this ITD now that its completion callback ran. */ +done: + usb_put_urb(urb); + itd->urb = NULL; + itd->stream = NULL; + list_move(&itd->itd_list, &stream->free_list); + iso_stream_put(ehci, stream); - return 1; + return retval; } /*-------------------------------------------------------------------------*/ @@ -1712,8 +1721,6 @@ done: return status; } -#ifdef CONFIG_USB_EHCI_SPLIT_ISO - /*-------------------------------------------------------------------------*/ /* @@ -1950,6 +1957,16 @@ sitd_link_urb ( #define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ | SITD_STS_XACT | SITD_STS_MMF) +/* Process and recycle a completed SITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ static unsigned sitd_complete ( struct ehci_hcd *ehci, @@ -1961,6 +1978,7 @@ sitd_complete ( int urb_index = -1; struct ehci_iso_stream *stream = sitd->stream; struct usb_device *dev; + unsigned retval = false; urb_index = sitd->index; desc = &urb->iso_frame_desc [urb_index]; @@ -1981,32 +1999,23 @@ sitd_complete ( desc->status = 0; desc->actual_length = desc->length - SITD_LENGTH (t); } - - usb_put_urb (urb); - sitd->urb = NULL; - sitd->stream = NULL; - list_move (&sitd->sitd_list, &stream->free_list); stream->depth -= stream->interval << 3; - iso_stream_put (ehci, stream); /* handle completion now? */ if ((urb_index + 1) != urb->number_of_packets) - return 0; + goto done; /* ASSERT: it's really the last sitd for this urb list_for_each_entry (sitd, &stream->td_list, sitd_list) BUG_ON (sitd->urb == urb); */ - /* give urb back to the driver */ + /* give urb back to the driver; completion often (re)submits */ dev = urb->dev; ehci_urb_done(ehci, urb, 0); + retval = true; urb = NULL; - - /* defer stopping schedule; completion can submit */ ehci->periodic_sched--; - if (!ehci->periodic_sched) - (void) disable_periodic (ehci); ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (list_empty (&stream->td_list)) { @@ -2018,8 +2027,15 @@ sitd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); + /* OK to recycle this SITD now that its completion callback ran. */ +done: + usb_put_urb(urb); + sitd->urb = NULL; + sitd->stream = NULL; + list_move(&sitd->sitd_list, &stream->free_list); + iso_stream_put(ehci, stream); - return 1; + return retval; } @@ -2082,26 +2098,6 @@ done: return status; } -#else - -static inline int -sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags) -{ - ehci_dbg (ehci, "split iso support is disabled\n"); - return -ENOSYS; -} - -static inline unsigned -sitd_complete ( - struct ehci_hcd *ehci, - struct ehci_sitd *sitd -) { - ehci_err (ehci, "sitd_complete %p?\n", sitd); - return 0; -} - -#endif /* USB_EHCI_SPLIT_ISO */ - /*-------------------------------------------------------------------------*/ static void @@ -2127,17 +2123,9 @@ scan_periodic (struct ehci_hcd *ehci) for (;;) { union ehci_shadow q, *q_p; __hc32 type, *hw_p; - unsigned uframes; + unsigned incomplete = false; - /* don't scan past the live uframe */ frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { - /* safe to scan the whole frame at once */ - now_uframe |= 0x07; - uframes = 8; - } restart: /* scan each element in frame's queue for completions */ @@ -2175,12 +2163,15 @@ restart: q = q.fstn->fstn_next; break; case Q_TYPE_ITD: - /* skip itds for later in the frame */ + /* If this ITD is still active, leave it for + * later processing ... check the next entry. + */ rmb (); - for (uf = live ? uframes : 8; uf < 8; uf++) { + for (uf = 0; uf < 8 && live; uf++) { if (0 == (q.itd->hw_transaction [uf] & ITD_ACTIVE(ehci))) continue; + incomplete = true; q_p = &q.itd->itd_next; hw_p = &q.itd->hw_next; type = Q_NEXT_TYPE(ehci, @@ -2188,10 +2179,12 @@ restart: q = *q_p; break; } - if (uf != 8) + if (uf < 8 && live) break; - /* this one's ready ... HC won't cache the + /* Take finished ITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. HC won't cache the * pointer for much longer, if at all. */ *q_p = q.itd->itd_next; @@ -2202,8 +2195,12 @@ restart: q = *q_p; break; case Q_TYPE_SITD: + /* If this SITD is still active, leave it for + * later processing ... check the next entry. + */ if ((q.sitd->hw_results & SITD_ACTIVE(ehci)) && live) { + incomplete = true; q_p = &q.sitd->sitd_next; hw_p = &q.sitd->hw_next; type = Q_NEXT_TYPE(ehci, @@ -2211,6 +2208,11 @@ restart: q = *q_p; break; } + + /* Take finished SITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. + */ *q_p = q.sitd->sitd_next; *hw_p = q.sitd->hw_next; type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); @@ -2226,11 +2228,24 @@ restart: } /* assume completion callbacks modify the queue */ - if (unlikely (modified)) - goto restart; + if (unlikely (modified)) { + if (likely(ehci->periodic_sched > 0)) + goto restart; + /* maybe we can short-circuit this scan! */ + disable_periodic(ehci); + now_uframe = clock; + break; + } } - /* stop when we catch up to the HC */ + /* If we can tell we caught up to the hardware, stop now. + * We can't advance our scan without collecting the ISO + * transfers that are still pending in this frame. + */ + if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { + ehci->next_uframe = now_uframe; + break; + } // FIXME: this assumes we won't get lapped when // latencies climb; that should be rare, but... @@ -2243,7 +2258,8 @@ restart: if (now_uframe == clock) { unsigned now; - if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) + if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) + || ehci->periodic_sched == 0) break; ehci->next_uframe = now_uframe; now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 951d69fec513..bf92d209a1a9 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -74,7 +74,6 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -105,6 +104,7 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ + struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -127,6 +127,14 @@ struct ehci_hcd { /* one per controller */ #else # define COUNT(x) do {} while (0) #endif + + /* debug files */ +#ifdef DEBUG + struct dentry *debug_dir; + struct dentry *debug_async; + struct dentry *debug_periodic; + struct dentry *debug_registers; +#endif }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ @@ -140,9 +148,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } +static inline void +iaa_watchdog_start(struct ehci_hcd *ehci) +{ + WARN_ON(timer_pending(&ehci->iaa_watchdog)); + mod_timer(&ehci->iaa_watchdog, + jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); +} + +static inline void iaa_watchdog_done(struct ehci_hcd *ehci) +{ + del_timer(&ehci->iaa_watchdog); +} + enum ehci_timer_action { TIMER_IO_WATCHDOG, - TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -160,9 +180,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { - case TIMER_IAA_WATCHDOG: - t = EHCI_IAA_JIFFIES; - break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -179,8 +196,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (action != TIMER_IAA_WATCHDOG - && t > ehci->watchdog.expires + if (time_before_eq(t, ehci->watchdog.expires) && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); @@ -534,8 +550,8 @@ struct ehci_iso_stream { * trusting urb->interval == f(epdesc->bInterval) and * including the extra info for hw_bufp[0..2] */ - u8 interval; u8 usecs, c_usecs; + u16 interval; u16 tt_usecs; u16 maxp; u16 raw_mask; @@ -586,7 +602,6 @@ struct ehci_itd { unsigned frame; /* where scheduled */ unsigned pg; unsigned index[8]; /* in urb->iso_frame_desc */ - u8 usecs[8]; } __attribute__ ((aligned (32))); /*-------------------------------------------------------------------------*/ @@ -725,11 +740,16 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) * definition below can die once the 4xx support is * finally ported over. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) #define readl_be(addr) in_be32((__force unsigned *)addr) #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) #endif +#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX) +#define readl_be(addr) __raw_readl((__force unsigned *)addr) +#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr) +#endif + static inline unsigned int ehci_readl(const struct ehci_hcd *ehci, __u32 __iomem * regs) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c27417f5b9d8..0130fd8571e4 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -918,7 +918,6 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf) | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; buf[0] |= 1 << (i + 1); - continue; } } spin_unlock_irqrestore(&isp116x->lock, flags); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index d849c809acbd..126fcbdd6408 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -17,6 +17,8 @@ #include <asm/mach-types.h> #include <asm/hardware.h> +#include <asm/gpio.h> + #include <asm/arch/board.h> #include <asm/arch/cpu.h> @@ -271,12 +273,41 @@ static const struct hc_driver ohci_at91_hc_driver = { static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int i; + + if (pdata) { + /* REVISIT make the driver support per-port power switching, + * and also overcurrent detection. Here we assume the ports + * are always powered while this driver is active, and use + * active-low power switches. + */ + for (i = 0; i < pdata->ports; i++) { + if (pdata->vbus_pin[i] <= 0) + continue; + gpio_request(pdata->vbus_pin[i], "ohci_vbus"); + gpio_direction_output(pdata->vbus_pin[i], 0); + } + } + device_init_wakeup(&pdev->dev, 1); return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); } static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) { + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int i; + + if (pdata) { + for (i = 0; i < pdata->ports; i++) { + if (pdata->vbus_pin[i] <= 0) + continue; + gpio_direction_output(pdata->vbus_pin[i], 1); + gpio_free(pdata->vbus_pin[i]); + } + } + device_init_wakeup(&pdev->dev, 0); return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev); } diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index ebab5ce8f5ce..a22c30aa745d 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -401,6 +401,42 @@ static inline void remove_debug_files (struct ohci_hcd *bus) { } #else +static int debug_async_open(struct inode *, struct file *); +static int debug_periodic_open(struct inode *, struct file *); +static int debug_registers_open(struct inode *, struct file *); +static int debug_async_open(struct inode *, struct file *); +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, +}; + +static struct dentry *ohci_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct device *dev; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *page; +}; + static ssize_t show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) { @@ -467,8 +503,7 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) return count - size; } -static ssize_t -show_async (struct class_device *class_dev, char *buf) +static ssize_t fill_async_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -476,25 +511,23 @@ show_async (struct class_device *class_dev, char *buf) size_t temp; unsigned long flags; - bus = class_get_devdata(class_dev); + bus = dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); /* display control and bulk lists together, for simplicity */ spin_lock_irqsave (&ohci->lock, flags); - temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail); - temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail); + temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail); + temp += show_list(ohci, buf->page + temp, buf->count - temp, + ohci->ed_bulktail); spin_unlock_irqrestore (&ohci->lock, flags); return temp; } -static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL); - #define DBG_SCHED_LIMIT 64 -static ssize_t -show_periodic (struct class_device *class_dev, char *buf) +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -509,10 +542,10 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = class_get_devdata(class_dev); + bus = (struct usb_bus *)dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); - next = buf; + next = buf->page; size = PAGE_SIZE; temp = scnprintf (next, size, "size = %d\n", NUM_INTS); @@ -589,13 +622,9 @@ show_periodic (struct class_device *class_dev, char *buf) return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); - - #undef DBG_SCHED_LIMIT -static ssize_t -show_registers (struct class_device *class_dev, char *buf) +static ssize_t fill_registers_buffer(struct debug_buffer *buf) { struct usb_bus *bus; struct usb_hcd *hcd; @@ -606,11 +635,11 @@ show_registers (struct class_device *class_dev, char *buf) char *next; u32 rdata; - bus = class_get_devdata(class_dev); + bus = (struct usb_bus *)dev_get_drvdata(buf->dev); hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); regs = ohci->regs; - next = buf; + next = buf->page; size = PAGE_SIZE; spin_lock_irqsave (&ohci->lock, flags); @@ -677,29 +706,155 @@ show_registers (struct class_device *class_dev, char *buf) done: spin_unlock_irqrestore (&ohci->lock, flags); + return PAGE_SIZE - size; } -static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); +static struct debug_buffer *alloc_buffer(struct device *dev, + ssize_t (*fill_func)(struct debug_buffer *)) +{ + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + if (buf) { + buf->dev = dev; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + } + + return buf; +} + +static int fill_buffer(struct debug_buffer *buf) +{ + int ret = 0; + + if (!buf->page) + buf->page = (char *)get_zeroed_page(GFP_KERNEL); + + if (!buf->page) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); + + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; +} + +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->page, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + + if (buf) { + if (buf->page) + free_page((unsigned long)buf->page); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_periodic_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} static inline void create_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; - int retval; + struct usb_bus *bus = &ohci_to_hcd(ohci)->self; + struct device *dev = bus->dev; + + ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root); + if (!ohci->debug_dir) + goto dir_error; + + ohci->debug_async = debugfs_create_file("async", S_IRUGO, + ohci->debug_dir, dev, + &debug_async_fops); + if (!ohci->debug_async) + goto async_error; + + ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, + ohci->debug_dir, dev, + &debug_periodic_fops); + if (!ohci->debug_periodic) + goto periodic_error; + + ohci->debug_registers = debugfs_create_file("registers", S_IRUGO, + ohci->debug_dir, dev, + &debug_registers_fops); + if (!ohci->debug_registers) + goto registers_error; - retval = class_device_create_file(cldev, &class_device_attr_async); - retval = class_device_create_file(cldev, &class_device_attr_periodic); - retval = class_device_create_file(cldev, &class_device_attr_registers); ohci_dbg (ohci, "created debug files\n"); + return; + +registers_error: + debugfs_remove(ohci->debug_periodic); +periodic_error: + debugfs_remove(ohci->debug_async); +async_error: + debugfs_remove(ohci->debug_dir); +dir_error: + ohci->debug_periodic = NULL; + ohci->debug_async = NULL; + ohci->debug_dir = NULL; } static inline void remove_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; - - class_device_remove_file(cldev, &class_device_attr_async); - class_device_remove_file(cldev, &class_device_attr_periodic); - class_device_remove_file(cldev, &class_device_attr_registers); + debugfs_remove(ohci->debug_registers); + debugfs_remove(ohci->debug_periodic); + debugfs_remove(ohci->debug_async); + debugfs_remove(ohci->debug_dir); } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ddd4ee1f2413..dd4798ee028e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -36,6 +36,7 @@ #include <linux/dmapool.h> #include <linux/reboot.h> #include <linux/workqueue.h> +#include <linux/debugfs.h> #include <asm/io.h> #include <asm/irq.h> @@ -809,13 +810,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) } if (ints & OHCI_INTR_WDH) { - if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); spin_lock (&ohci->lock); dl_done_list (ohci); spin_unlock (&ohci->lock); - if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { @@ -1032,6 +1029,13 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER usb_hcd_pnx4008_driver #endif +#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) +#include "ohci-sh.c" +#define PLATFORM_DRIVER ohci_hcd_sh_driver +#endif + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" @@ -1048,6 +1052,11 @@ MODULE_LICENSE ("GPL"); #define SSB_OHCI_DRIVER ssb_ohci_driver #endif +#ifdef CONFIG_MFD_SM501 +#include "ohci-sm501.c" +#define PLATFORM_DRIVER ohci_hcd_sm501_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ @@ -1068,6 +1077,14 @@ static int __init ohci_hcd_mod_init(void) pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); +#ifdef DEBUG + ohci_debug_root = debugfs_create_dir("ohci", NULL); + if (!ohci_debug_root) { + retval = -ENOENT; + goto error_debug; + } +#endif + #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); if (retval < 0) @@ -1130,6 +1147,12 @@ static int __init ohci_hcd_mod_init(void) ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif +#ifdef DEBUG + debugfs_remove(ohci_debug_root); + ohci_debug_root = NULL; + error_debug: +#endif + return retval; } module_init(ohci_hcd_mod_init); @@ -1154,6 +1177,9 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif +#ifdef DEBUG + debugfs_remove(ohci_debug_root); +#endif } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c new file mode 100644 index 000000000000..5309ac039e15 --- /dev/null +++ b/drivers/usb/host/ohci-sh.c @@ -0,0 +1,143 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * Copyright (C) 2008 Renesas Solutions Corp. + * + * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/platform_device.h> + +static int ohci_sh_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + ohci_init(ohci); + ohci_run(ohci); + hcd->state = HC_STATE_RUNNING; + return 0; +} + +static const struct hc_driver ohci_sh_hc_driver = { + .description = hcd_name, + .product_desc = "SuperH OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_sh_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +#define resource_len(r) (((r)->end - (r)->start) + 1) +static int ohci_hcd_sh_probe(struct platform_device *pdev) +{ + struct resource *res = NULL; + struct usb_hcd *hcd = NULL; + int irq = -1; + int ret; + + if (usb_disabled()) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err("platform_get_resource error."); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + err("platform_get_irq error."); + return -ENODEV; + } + + /* initialize hcd */ + hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); + if (!hcd) { + err("Failed to create hcd"); + return -ENOMEM; + } + + hcd->regs = (void __iomem *)res->start; + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_len(res); + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED); + if (ret != 0) { + err("Failed to add hcd"); + usb_put_hcd(hcd); + return ret; + } + + return ret; +} + +static int ohci_hcd_sh_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + + return 0; +} + +static struct platform_driver ohci_hcd_sh_driver = { + .probe = ohci_hcd_sh_probe, + .remove = ohci_hcd_sh_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "sh_ohci", + .owner = THIS_MODULE, + }, +}; + diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c new file mode 100644 index 000000000000..a97070142869 --- /dev/null +++ b/drivers/usb/host/ohci-sm501.c @@ -0,0 +1,264 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2005 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2008 Magnus Damm + * + * SM501 Bus Glue - based on ohci-omap.c + * + * This file is licenced under the GPL. + */ + +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/sm501.h> +#include <linux/sm501-regs.h> + +static int ohci_sm501_init(struct usb_hcd *hcd) +{ + return ohci_init(hcd_to_ohci(hcd)); +} + +static int ohci_sm501_start(struct usb_hcd *hcd) +{ + struct device *dev = hcd->self.controller; + int ret; + + ret = ohci_run(hcd_to_ohci(hcd)); + if (ret < 0) { + dev_err(dev, "can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + } + + return ret; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_sm501_hc_driver = { + .description = hcd_name, + .product_desc = "SM501 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, + + /* + * basic lifecycle operations + */ + .reset = ohci_sm501_init, + .start = ohci_sm501_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) +{ + const struct hc_driver *driver = &ohci_sm501_hc_driver; + struct device *dev = &pdev->dev; + struct resource *res, *mem; + int retval, irq; + struct usb_hcd *hcd = 0; + + irq = retval = platform_get_irq(pdev, 0); + if (retval < 0) + goto err0; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (mem == NULL) { + dev_err(dev, "no resource definition for memory\n"); + retval = -ENOENT; + goto err0; + } + + if (!request_mem_region(mem->start, mem->end - mem->start + 1, + pdev->name)) { + dev_err(dev, "request_mem_region failed\n"); + retval = -EBUSY; + goto err0; + } + + /* The sm501 chip is equipped with local memory that may be used + * by on-chip devices such as the video controller and the usb host. + * This driver uses dma_declare_coherent_memory() to make sure + * usb allocations with dma_alloc_coherent() allocate from + * this local memory. The dma_handle returned by dma_alloc_coherent() + * will be an offset starting from 0 for the first local memory byte. + * + * So as long as data is allocated using dma_alloc_coherent() all is + * fine. This is however not always the case - buffers may be allocated + * using kmalloc() - so the usb core needs to be told that it must copy + * data into our local memory if the buffers happen to be placed in + * regular memory. The HCD_LOCAL_MEM flag does just that. + */ + + if (!dma_declare_coherent_memory(dev, mem->start, + mem->start - mem->parent->start, + (mem->end - mem->start) + 1, + DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)) { + dev_err(dev, "cannot declare coherent memory\n"); + retval = -ENXIO; + goto err1; + } + + /* allocate, reserve and remap resources for registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "no resource definition for registers\n"); + retval = -ENOENT; + goto err2; + } + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto err2; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) { + dev_err(dev, "request_mem_region failed\n"); + retval = -EBUSY; + goto err3; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (hcd->regs == NULL) { + dev_err(dev, "cannot remap registers\n"); + retval = -ENXIO; + goto err4; + } + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (retval) + goto err4; + + /* enable power and unmask interrupts */ + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); + sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0); + + return 0; +err4: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err3: + usb_put_hcd(hcd); +err2: + dma_release_declared_memory(dev); +err1: + release_mem_region(mem->start, mem->end - mem->start + 1); +err0: + return retval; +} + +static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct resource *mem; + + usb_remove_hcd(hcd); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + dma_release_declared_memory(&pdev->dev); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(mem->start, mem->end - mem->start + 1); + + /* mask interrupts and disable power */ + + sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6); + sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM +static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct device *dev = &pdev->dev; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->power.power_state = PMSG_SUSPEND; + return 0; +} + +static int ohci_sm501_resume(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); + dev->power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(platform_get_drvdata(pdev)); + return 0; +} +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * Driver definition to register with the SM501 bus + */ +static struct platform_driver ohci_hcd_sm501_driver = { + .probe = ohci_hcd_sm501_drv_probe, + .remove = ohci_hcd_sm501_drv_remove, + .shutdown = usb_hcd_platform_shutdown, +#ifdef CONFIG_PM + .suspend = ohci_sm501_suspend, + .resume = ohci_sm501_resume, +#endif + .driver = { + .owner = THIS_MODULE, + .name = "sm501-usb", + }, +}; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 47c5c66a282c..dc544ddc7849 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -408,6 +408,13 @@ struct ohci_hcd { unsigned eds_scheduled; struct ed *ed_to_check; unsigned zf_delay; + +#ifdef DEBUG + struct dentry *debug_dir; + struct dentry *debug_async; + struct dentry *debug_periodic; + struct dentry *debug_registers; +#endif }; #ifdef CONFIG_PCI diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c225159ca3d3..0ee694f043cc 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -190,9 +190,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) msleep(10); } if (wait_time <= 0) - printk(KERN_WARNING "%s %s: BIOS handoff " - "failed (BIOS bug ?) %08x\n", - pdev->dev.bus_id, "OHCI", + dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" + " (BIOS bug?) %08x\n", readl(base + OHCI_CONTROL)); /* reset controller, preserving RWC */ @@ -243,8 +242,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) switch (cap & 0xff) { case 1: /* BIOS/SMM/... handoff support */ if ((cap & EHCI_USBLEGSUP_BIOS)) { - pr_debug("%s %s: BIOS handoff\n", - pdev->dev.bus_id, "EHCI"); + dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n"); #if 0 /* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on, @@ -285,9 +283,8 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) /* well, possibly buggy BIOS... try to shut * it down, and hope nothing goes too wrong */ - printk(KERN_WARNING "%s %s: BIOS handoff " - "failed (BIOS bug ?) %08x\n", - pdev->dev.bus_id, "EHCI", cap); + dev_warn(&pdev->dev, "EHCI: BIOS handoff failed" + " (BIOS bug?) %08x\n", cap); pci_write_config_byte(pdev, offset + 2, 0); } @@ -306,17 +303,14 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) cap = 0; /* FALLTHROUGH */ default: - printk(KERN_WARNING "%s %s: unrecognized " - "capability %02x\n", - pdev->dev.bus_id, "EHCI", - cap & 0xff); + dev_warn(&pdev->dev, "EHCI: unrecognized capability " + "%02x\n", cap & 0xff); break; } offset = (cap >> 8) & 0xff; } if (!count) - printk(KERN_DEBUG "%s %s: capability loop?\n", - pdev->dev.bus_id, "EHCI"); + dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n"); /* * halt EHCI & disable its interrupts in any case diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index fe9ceb077d9b..57388252b693 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -405,7 +405,7 @@ struct r8a66597_pipe_info { u16 pipenum; - u16 address; /* R8A66597 HCD usb addres */ + u16 address; /* R8A66597 HCD usb address */ u16 epnum; u16 maxpacket; u16 type; diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index d1131a87a5b1..0fb114ca1eba 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -478,8 +478,6 @@ static int mdc800_usb_probe (struct usb_interface *intf, { irq_interval=intf_desc->endpoint [j].desc.bInterval; } - - continue; } } if (mdc800->endpoint[i] == -1) diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index d721380b242d..937940404b7a 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -1,7 +1,7 @@ /* * cypress_cy7c63.c * -* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de) +* Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de) * * This driver is based on the Cypress USB Driver by Marcus Maul * (cyport) and the 2.0 version of Greg Kroah-Hartman's @@ -21,6 +21,9 @@ * Supported functions: Read/Write Ports * * +* For up-to-date information please visit: +* http://www.obock.de/kernel/cypress +* * 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, version 2. @@ -31,7 +34,7 @@ #include <linux/kernel.h> #include <linux/usb.h> -#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)" +#define DRIVER_AUTHOR "Oliver Bock (bock@tfh-berlin.de)" #define DRIVER_DESC "Cypress CY7C63xxx USB driver" #define CYPRESS_VENDOR_ID 0xa2c diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 764696ff1e8e..801070502cc1 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -715,7 +715,7 @@ static unsigned iowarrior_poll(struct file *file, poll_table * wait) * would use "struct net_driver" instead, and a serial * device would use "struct tty_driver". */ -static struct file_operations iowarrior_fops = { +static const struct file_operations iowarrior_fops = { .owner = THIS_MODULE, .write = iowarrior_write, .read = iowarrior_read, diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index aab320085ebf..6664043f4645 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -205,7 +205,7 @@ static DEFINE_MUTEX(open_disc_mutex); /* Structure to hold all of our device specific stuff */ struct lego_usb_tower { - struct semaphore sem; /* locks this structure */ + struct mutex lock; /* locks this structure */ struct usb_device* udev; /* save off the usb device pointer */ unsigned char minor; /* the starting minor number for this device */ @@ -361,7 +361,7 @@ static int tower_open (struct inode *inode, struct file *file) } /* lock this device */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { mutex_unlock(&open_disc_mutex); retval = -ERESTARTSYS; goto exit; @@ -421,7 +421,7 @@ static int tower_open (struct inode *inode, struct file *file) file->private_data = dev; unlock_exit: - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); @@ -448,7 +448,7 @@ static int tower_release (struct inode *inode, struct file *file) } mutex_lock(&open_disc_mutex); - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -460,7 +460,9 @@ static int tower_release (struct inode *inode, struct file *file) } if (dev->udev == NULL) { /* the device was unplugged before the file was released */ - up (&dev->sem); /* unlock here as tower_delete frees dev */ + + /* unlock here as tower_delete frees dev */ + mutex_unlock(&dev->lock); tower_delete (dev); goto exit; } @@ -473,7 +475,7 @@ static int tower_release (struct inode *inode, struct file *file) dev->open_count = 0; unlock_exit: - up (&dev->sem); + mutex_unlock(&dev->lock); exit: mutex_unlock(&open_disc_mutex); @@ -586,7 +588,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, dev = (struct lego_usb_tower *)file->private_data; /* lock this object */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -653,7 +655,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, unlock_exit: /* unlock the device */ - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); @@ -675,7 +677,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t dev = (struct lego_usb_tower *)file->private_data; /* lock this object */ - if (down_interruptible (&dev->sem)) { + if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; } @@ -737,7 +739,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t unlock_exit: /* unlock the device */ - up (&dev->sem); + mutex_unlock(&dev->lock); exit: dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); @@ -862,7 +864,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device goto exit; } - init_MUTEX (&dev->sem); + mutex_init(&dev->lock); dev->udev = udev; dev->open_count = 0; @@ -1007,16 +1009,16 @@ static void tower_disconnect (struct usb_interface *interface) /* give back our minor */ usb_deregister_dev (interface, &tower_class); - down (&dev->sem); + mutex_lock(&dev->lock); mutex_unlock(&open_disc_mutex); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { - up (&dev->sem); + mutex_unlock(&dev->lock); tower_delete (dev); } else { dev->udev = NULL; - up (&dev->sem); + mutex_unlock(&dev->lock); } info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE)); diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 9244d067cec1..cb7fa0eaf3ae 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -323,7 +323,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, usb_kill_urb(urb); retval = -ETIMEDOUT; } else { - /* URB completed within timout */ + /* URB completed within timeout */ retval = urb->status; readbytes = urb->actual_length; } @@ -3195,20 +3195,6 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->present = 1; -#ifdef SISUSB_OLD_CONFIG_COMPAT - { - int ret; - /* Our ioctls are all "32/64bit compatible" */ - ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL); - ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); - ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); - if (ret) - dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); - else - sisusb->ioctl32registered = 1; - } -#endif - if (dev->speed == USB_SPEED_HIGH) { int initscreen = 1; #ifdef INCL_SISUSB_CON @@ -3271,19 +3257,6 @@ static void sisusb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); -#ifdef SISUSB_OLD_CONFIG_COMPAT - if (sisusb->ioctl32registered) { - int ret; - sisusb->ioctl32registered = 0; - ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE); - ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); - ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); - if (ret) { - dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); - } - } -#endif - sisusb->present = 0; sisusb->ready = 0; diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index d2d7872cd022..cf0b4a5883f6 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -120,9 +120,6 @@ struct sisusb_usb_data { int isopen; /* !=0 if open */ int present; /* !=0 if device is present on the bus */ int ready; /* !=0 if device is ready for userland */ -#ifdef SISUSB_OLD_CONFIG_COMPAT - int ioctl32registered; -#endif int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index ea3162146481..da922dfc0dcc 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/scatterlist.h> +#include <linux/mutex.h> #include <linux/usb.h> @@ -64,7 +65,7 @@ struct usbtest_dev { int in_iso_pipe; int out_iso_pipe; struct usb_endpoint_descriptor *iso_in, *iso_out; - struct semaphore sem; + struct mutex lock; #define TBUF_SIZE 256 u8 *buf; @@ -1151,6 +1152,7 @@ static int verify_halted (int ep, struct urb *urb) dbg ("ep %02x couldn't get halt status, %d", ep, retval); return retval; } + le16_to_cpus(&status); if (status != 1) { dbg ("ep %02x bogus status: %04x != 1", ep, status); return -EINVAL; @@ -1310,7 +1312,7 @@ static int ctrl_out (struct usbtest_dev *dev, len += vary; /* [real world] the "zero bytes IN" case isn't really used. - * hardware can easily trip up in this wierd case, since its + * hardware can easily trip up in this weird case, since its * status stage is IN, not OUT like other ep0in transfers. */ if (len > length) @@ -1558,11 +1560,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) || param->sglen < 0 || param->vary < 0) return -EINVAL; - if (down_interruptible (&dev->sem)) + if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; if (intf->dev.power.power_state.event != PM_EVENT_ON) { - up (&dev->sem); + mutex_unlock(&dev->lock); return -EHOSTUNREACH; } @@ -1574,7 +1576,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) int res; if (intf->altsetting->desc.bInterfaceNumber) { - up (&dev->sem); + mutex_unlock(&dev->lock); return -ENODEV; } res = set_altsetting (dev, dev->info->alt); @@ -1582,7 +1584,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) dev_err (&intf->dev, "set altsetting to %d failed, %d\n", dev->info->alt, res); - up (&dev->sem); + mutex_unlock(&dev->lock); return res; } } @@ -1855,7 +1857,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) param->duration.tv_usec += 1000 * 1000; param->duration.tv_sec -= 1; } - up (&dev->sem); + mutex_unlock(&dev->lock); return retval; } @@ -1905,7 +1907,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) return -ENOMEM; info = (struct usbtest_info *) id->driver_info; dev->info = info; - init_MUTEX (&dev->sem); + mutex_init(&dev->lock); dev->intf = intf; @@ -1990,8 +1992,6 @@ static void usbtest_disconnect (struct usb_interface *intf) { struct usbtest_dev *dev = usb_get_intfdata (intf); - down (&dev->sem); - usb_set_intfdata (intf, NULL); dev_dbg (&intf->dev, "disconnect\n"); kfree (dev); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f06e4e2b49d3..1774ba5c4c3b 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1026,6 +1026,8 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait) return mask; } +#if 0 + /* * open and close: just keep track of how many times the device is * mapped, to use the proper memory allocation function. @@ -1045,33 +1047,31 @@ static void mon_bin_vma_close(struct vm_area_struct *vma) /* * Map ring pages to user space. */ -struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct mon_reader_bin *rp = vma->vm_private_data; unsigned long offset, chunk_idx; struct page *pageptr; - offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= rp->b_size) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); - if (type) - *type = VM_FAULT_MINOR; - return pageptr; + vmf->page = pageptr; + return 0; } struct vm_operations_struct mon_bin_vm_ops = { .open = mon_bin_vma_open, .close = mon_bin_vma_close, - .nopage = mon_bin_vma_nopage, + .fault = mon_bin_vma_fault, }; int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) { - /* don't do anything here: "nopage" will set up page table entries */ + /* don't do anything here: "fault" will set up page table entries */ vma->vm_ops = &mon_bin_vm_ops; vma->vm_flags |= VM_RESERVED; vma->vm_private_data = filp->private_data; @@ -1079,7 +1079,9 @@ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } -struct file_operations mon_fops_binary = { +#endif /* 0 */ + +static const struct file_operations mon_fops_binary = { .owner = THIS_MODULE, .open = mon_bin_open, .llseek = no_llseek, diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 4a86696e6c7d..c1e65dfd9353 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -2,10 +2,7 @@ # USB Serial device configuration # -menu "USB Serial Converter support" - depends on USB!=n - -config USB_SERIAL +menuconfig USB_SERIAL tristate "USB Serial Converter support" depends on USB ---help--- @@ -20,6 +17,8 @@ config USB_SERIAL To compile this driver as a module, choose M here: the module will be called usbserial. +if USB_SERIAL + config USB_SERIAL_CONSOLE bool "USB Serial Console device support (EXPERIMENTAL)" depends on USB_SERIAL=y && EXPERIMENTAL @@ -43,6 +42,12 @@ config USB_SERIAL_CONSOLE If unsure, say N. +config USB_EZUSB + bool "Functions for loading firmware on EZUSB chips" + depends on USB_SERIAL + help + Say Y here if you need EZUSB device support. + config USB_SERIAL_GENERIC bool "USB Generic Serial Driver" depends on USB_SERIAL @@ -105,6 +110,7 @@ config USB_SERIAL_CH341 config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a ConnectTech WhiteHEAT 4 port USB to serial converter device. @@ -282,9 +288,21 @@ config USB_SERIAL_IPW To compile this driver as a module, choose M here: the module will be called ipw. +config USB_SERIAL_IUU + tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)" + depends on USB_SERIAL && EXPERIMENTAL + help + Say Y here if you want to use a IUU in phoenix mode and get + an extra ttyUSBx device. More information available on + http://eczema.ecze.com/iuu_phoenix.html + + To compile this driver as a module, choose M here: the + module will be called iuu_phoenix.o + config USB_SERIAL_KEYSPAN_PDA tristate "USB Keyspan PDA Single Port Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a Keyspan PDA single port USB to serial converter device. This driver makes use of firmware @@ -296,6 +314,7 @@ config USB_SERIAL_KEYSPAN_PDA config USB_SERIAL_KEYSPAN tristate "USB Keyspan USA-xxx Serial Driver" depends on USB_SERIAL + select USB_EZUSB ---help--- Say Y here if you want to use Keyspan USB to serial converter devices. This driver makes use of Keyspan's official firmware @@ -538,6 +557,7 @@ config USB_SERIAL_CYBERJACK config USB_SERIAL_XIRCOM tristate "USB Xircom / Entregra Single Port Serial Driver" depends on USB_SERIAL + select USB_EZUSB help Say Y here if you want to use a Xircom or Entregra single port USB to serial converter device. This driver makes use of firmware @@ -585,11 +605,4 @@ config USB_SERIAL_DEBUG To compile this driver as a module, choose M here: the module will be called usb-debug. -config USB_EZUSB - bool - depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT - default y - - -endmenu - +endif # USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index d6fb384e52b2..0db109a54d10 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o +obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 77bb893bf2e9..f156dba0300f 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -217,7 +217,10 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) priv->rts_state = 0; priv->dtr_state = 0; - airprime_send_setup(port); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + airprime_send_setup(port); + mutex_lock(&port->serial->disc_mutex); for (i = 0; i < NUM_READ_URBS; ++i) { usb_kill_urb (priv->read_urbp[i]); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index ddfee918000d..fe2bfd67ba8e 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -151,8 +151,10 @@ static int ark3116_attach(struct usb_serial *serial) return 0; cleanup: - for (--i; i >= 0; --i) + for (--i; i >= 0; --i) { + kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); + } return -ENOMEM; } diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 86724e885704..df0a2b3b0294 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -350,14 +350,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios unsigned long control_state; int bad_flow_control; speed_t baud; + struct ktermios *termios = port->tty->termios; - if ((!port->tty) || (!port->tty->termios)) { - dbg ("%s - no tty or termios structure", __FUNCTION__); - return; - } + iflag = termios->c_iflag; + cflag = termios->c_cflag; - iflag = port->tty->termios->c_iflag; - cflag = port->tty->termios->c_cflag; + termios->c_cflag &= ~CMSPAR; /* get a local copy of the current port settings */ spin_lock_irqsave(&priv->lock, flags); @@ -369,33 +367,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios old_cflag = old_termios->c_cflag; /* Set the baud rate */ - if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { + if ((cflag & CBAUD) != (old_cflag & CBAUD)) { /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag&CBAUD) == B0 ) { control_state |= (TIOCM_DTR|TIOCM_RTS); if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) err("Set DTR error"); /* don't set RTS if using hardware flow control */ - if (!(old_cflag&CRTSCTS) ) + if (!(old_cflag & CRTSCTS)) if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0) err("Set RTS error"); } } baud = tty_get_baud_rate(port->tty); - if (baud == 0) { - dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__); - return; - } - urb_value = BELKIN_SA_BAUD(baud); - /* Clip to maximum speed */ - if (urb_value == 0) - urb_value = 1; - /* Turn it back into a resulting real baud rate */ - baud = BELKIN_SA_BAUD(urb_value); - /* FIXME: Once the tty updates are done then push this back to the tty */ - - if ((cflag & CBAUD) != B0 ) { + if (baud) { + urb_value = BELKIN_SA_BAUD(baud); + /* Clip to maximum speed */ + if (urb_value == 0) + urb_value = 1; + /* Turn it back into a resulting real baud rate */ + baud = BELKIN_SA_BAUD(urb_value); + + /* Report the actual baud rate back to the caller */ + tty_encode_baud_rate(port->tty, baud, baud); if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) err("Set baudrate error"); } else { diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 0362654d3b52..66ce30c1b75b 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -64,8 +64,8 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial *serial; struct usb_serial_port *port; int retval = 0; - struct tty_struct *tty; - struct ktermios *termios; + struct tty_struct *tty = NULL; + struct ktermios *termios = NULL, dummy; dbg ("%s", __FUNCTION__); @@ -133,11 +133,14 @@ static int usb_console_setup(struct console *co, char *options) } co->cflag = cflag; - /* grab the first serial port that happens to be connected */ - serial = usb_serial_get_by_index(0); + /* + * no need to check the index here: if the index is wrong, console + * code won't call us + */ + serial = usb_serial_get_by_index(co->index); if (serial == NULL) { /* no device is connected yet, sorry :( */ - err ("No USB device connected to ttyUSB0"); + err ("No USB device connected to ttyUSB%i", co->index); return -ENODEV; } @@ -148,49 +151,64 @@ static int usb_console_setup(struct console *co, char *options) ++port->open_count; if (port->open_count == 1) { + if (serial->type->set_termios) { + /* + * allocate a fake tty so the driver can initialize + * the termios structure, then later call set_termios to + * configure according to command line arguments + */ + tty = kzalloc(sizeof(*tty), GFP_KERNEL); + if (!tty) { + retval = -ENOMEM; + err("no more memory"); + goto reset_open_count; + } + termios = kzalloc(sizeof(*termios), GFP_KERNEL); + if (!termios) { + retval = -ENOMEM; + err("no more memory"); + goto free_tty; + } + memset(&dummy, 0, sizeof(struct ktermios)); + tty->termios = termios; + port->tty = tty; + } + /* only call the device specific open if this * is the first time the port is opened */ if (serial->type->open) retval = serial->type->open(port, NULL); else retval = usb_serial_generic_open(port, NULL); - if (retval) - port->open_count = 0; - } - if (retval) { - err ("could not open USB console port"); - return retval; - } - - if (serial->type->set_termios) { - struct ktermios dummy; - /* build up a fake tty structure so that the open call has something - * to look at to get the cflag value */ - tty = kzalloc(sizeof(*tty), GFP_KERNEL); - if (!tty) { - err ("no more memory"); - return -ENOMEM; + if (retval) { + err("could not open USB console port"); + goto free_termios; } - termios = kzalloc(sizeof(*termios), GFP_KERNEL); - if (!termios) { - err ("no more memory"); - kfree (tty); - return -ENOMEM; - } - memset(&dummy, 0, sizeof(struct ktermios)); - termios->c_cflag = cflag; - tty->termios = termios; - port->tty = tty; - /* set up the initial termios settings */ - serial->type->set_termios(port, &dummy); - port->tty = NULL; - kfree (termios); - kfree (tty); + if (serial->type->set_termios) { + termios->c_cflag = cflag; + serial->type->set_termios(port, &dummy); + + port->tty = NULL; + kfree(termios); + kfree(tty); + } } + port->console = 1; + retval = 0; + +out: return retval; +free_termios: + kfree(termios); + port->tty = NULL; +free_tty: + kfree(tty); +reset_open_count: + port->open_count = 0; +goto out; } static void usb_console_write(struct console *co, const char *buf, unsigned count) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 22833589c4be..f3ca66017a03 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ @@ -76,8 +77,13 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ + { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ + { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; @@ -342,7 +348,10 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp) usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); - cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); + mutex_unlock(&port->serial->disc_mutex); } /* diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 4353df92487f..8d9b045aa7e8 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -319,7 +319,6 @@ static void cyberjack_read_int_callback( struct urb *urb ) /* React only to interrupts signaling a bulk_in transfer */ if( (urb->actual_length==4) && (data[0]==0x01) ) { short old_rdtodo; - int result; /* This is a announcement of coming bulk_ins. */ unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 163386336a5d..08c65c1a3771 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) { struct cypress_private *priv = usb_get_serial_port_data(port); unsigned int c_cflag; - unsigned long flags; int bps; long timeout; wait_queue_t wait; @@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); /* wait for data to drain from buffer */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); timeout = CYPRESS_CLOSING_WAIT; init_waitqueue_entry(&wait, current); add_wait_queue(&port->tty->write_wait, &wait); @@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) set_current_state(TASK_INTERRUPTIBLE); if (cypress_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->serial->interface)) + /* without mutex, allowed due to harmless failure mode */ + || port->serial->disconnected) break; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&port->tty->write_wait, &wait); /* clear out any remaining data in the buffer */ cypress_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - + spin_unlock_irq(&priv->lock); + + /* writing is potentially harmful, lock must be taken */ + mutex_lock(&port->serial->disc_mutex); + if (port->serial->disconnected) { + mutex_unlock(&port->serial->disc_mutex); + return; + } /* wait for characters to drain from device */ bps = tty_get_baud_rate(port->tty); if (bps > 1200) @@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) if (c_cflag & HUPCL) { /* drop dtr and rts */ priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->line_control = 0; priv->cmd_ctrl = 1; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); cypress_write(port, NULL, 0); } } @@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) if (stats) dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); + mutex_unlock(&port->serial->disc_mutex); } /* cypress_close */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index ae410c4678ea..5f9c6e46bee5 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) unsigned char buf[32]; struct tty_struct *tty = port->tty; struct digi_port *priv = usb_get_serial_port_data(port); - unsigned long flags = 0; dbg("digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count); + mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ - if (!usb_get_intfdata(port->serial->interface)) + if (port->serial->disconnected) goto exit; /* do cleanup only after final close on this port */ - spin_lock_irqsave(&priv->dp_port_lock, flags); + spin_lock_irq(&priv->dp_port_lock); priv->dp_in_close = 1; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); + spin_unlock_irq(&priv->dp_port_lock); /* tell line discipline to process only XON/XOFF */ tty->closing = 1; @@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) } tty->closing = 0; exit: - spin_lock_irqsave(&priv->dp_port_lock, flags); + spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; wake_up_interruptible(&priv->dp_close_wait); - spin_unlock_irqrestore(&priv->dp_port_lock, flags); + spin_unlock_irq(&priv->dp_port_lock); + mutex_unlock(&port->serial->disc_mutex); dbg("digi_close: done"); } diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index 97ee718b1da2..3f698baa0abb 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -53,6 +53,6 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) } -EXPORT_SYMBOL(ezusb_writememory); -EXPORT_SYMBOL(ezusb_set_reset); +EXPORT_SYMBOL_GPL(ezusb_writememory); +EXPORT_SYMBOL_GPL(ezusb_set_reset); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c40e77dccf8e..90dcc625f70d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,226 +17,8 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * - * (21/Jul/2004) Ian Abbott - * Incorporated Steven Turner's code to add support for the FT2232C chip. - * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have - * fixed a couple of things. - * - * (27/May/2004) Ian Abbott - * Improved throttling code, mostly stolen from the WhiteHEAT driver. - * - * (26/Mar/2004) Jan Capek - * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc. - * - * (09/Feb/2004) Ian Abbott - * Changed full name of USB-UIRT device to avoid "/" character. - * Added FTDI's alternate PID (0x6006) for FT232/245 devices. - * Added PID for "ELV USB Module UO100" from Stefan Frings. - * - * (21/Oct/2003) Ian Abbott - * Renamed some VID/PID macros for Matrix Orbital and Perle Systems - * devices. Removed Matrix Orbital and Perle Systems devices from the - * 8U232AM device table, but left them in the FT232BM table, as they are - * known to use only FT232BM. - * - * (17/Oct/2003) Scott Allen - * Added vid/pid for Perle Systems UltraPort USB serial converters - * - * (21/Sep/2003) Ian Abbott - * Added VID/PID for Omnidirectional Control Technology US101 USB to - * RS-232 adapter (also rebadged as Dick Smith Electronics XH6381). - * VID/PID supplied by Donald Gordon. - * - * (19/Aug/2003) Ian Abbott - * Freed urb's transfer buffer in write bulk callback. - * Omitted some paranoid checks in write bulk callback that don't matter. - * Scheduled work in write bulk callback regardless of port's open count. - * - * (05/Aug/2003) Ian Abbott - * Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter. - * VID/PID provided by Steve Briggs. - * - * (23/Jul/2003) Ian Abbott - * Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from - * Wayne Wylupski. - * - * (10/Jul/2003) David Glance - * Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800. - * - * (27/Jun/2003) Ian Abbott - * Reworked the urb handling logic. We have no more pool, but dynamically - * allocate the urb and the transfer buffer on the fly. In testing this - * does not incure any measurable overhead. This also relies on the fact - * that we have proper reference counting logic for urbs. I nicked this - * from Greg KH's Visor driver. - * - * (23/Jun/2003) Ian Abbott - * Reduced flip buffer pushes and corrected a data length test in - * ftdi_read_bulk_callback. - * Defererence pointers after any paranoid checks, not before. - * - * (21/Jun/2003) Erik Nygren - * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. - * See <http://www.home-electro.com/tira1.htm>. Only operates properly - * at 100000 and RTS-CTS, so set custom divisor mode on startup. - * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. - * - * (18/Jun/2003) Ian Abbott - * Added Device ID of the USB relais from Rudolf Gugler (backported from - * Philipp Gühring's patch for 2.5.x kernel). - * Moved read transfer buffer reallocation into startup function. - * Free existing write urb and transfer buffer in startup function. - * Only use urbs in write urb pool that were successfully allocated. - * Moved some constant macros out of functions. - * Minor whitespace and comment changes. - * - * (12/Jun/2003) David Norwood - * Added support for USB-UIRT IR transceiver using 8U232AM chip. - * See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>. Only - * operates properly at 312500, so set custom divisor mode on startup. - * - * (12/Jun/2003) Ian Abbott - * Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang - * - I've eliminated some that don't seem to exist! - * Added Home Electronics Tira-1 IR transceiver pid from Chris Horn - * Some whitespace/coding-style cleanups - * - * (11/Jun/2003) Ian Abbott - * Fixed unsafe spinlock usage in ftdi_write - * - * (24/Feb/2003) Richard Shooter - * Increase read buffer size to improve read speeds at higher baud rates - * (specifically tested with up to 1Mb/sec at 1.5M baud) - * - * (23/Feb/2003) John Wilkins - * Added Xon/xoff flow control (activating support in the ftdi device) - * Added vid/pid for Videonetworks/Homechoice (UK ISP) - * - * (23/Feb/2003) Bill Ryder - * Added matrix orb device vid/pids from Wayne Wylupski - * - * (19/Feb/2003) Ian Abbott - * For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has - * changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI, - * ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in - * force, don't bother changing baud rate when custom_divisor has changed. - * - * (18/Feb/2003) Ian Abbott - * Fixed TIOCMGET handling to include state of DTR and RTS, the state - * of which are now saved by set_dtr() and set_rts(). - * Fixed improper storage class for buf in set_dtr() and set_rts(). - * Added FT232BM chip type and support for its extra baud rates (compared - * to FT8U232AM). - * Took account of special case divisor values for highest baud rates of - * FT8U232AM and FT232BM. - * For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used, - * as previous alt_speed setting is now stale. - * Moved startup code common between the startup routines for the - * different chip types into a common subroutine. - * - * (17/Feb/2003) Bill Ryder - * Added write urb buffer pool on a per device basis - * Added more checking for open file on callbacks (fixed OOPS) - * Added CrystalFontz 632 and 634 PIDs - * (thanx to CrystalFontz for the sample devices - they flushed out - * some driver bugs) - * Minor debugging message changes - * Added throttle, unthrottle and chars_in_buffer functions - * Fixed FTDI_SIO (the original device) bug - * Fixed some shutdown handling - * - * - * - * - * (07/Jun/2002) Kuba Ober - * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor - * function. It was getting too complex. - * Fix the divisor calculation logic which was setting divisor of 0.125 - * instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8. - * Also make it bump up the divisor to next integer in case of 7/8 - it's - * a better approximation. - * - * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch - * Not tested by me but it doesn't break anything I use. - * - * (04/Jan/2002) Kuba Ober - * Implemented 38400 baudrate kludge, where it can be substituted with other - * values. That's the only way to set custom baudrates. - * Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy. - * FIXME: both baudrate things should eventually go to usbserial.c as other - * devices may need that functionality too. Actually, it can probably be - * merged in serial.c somehow - too many drivers repeat this code over - * and over. - * Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time. - * Divisors for baudrates are calculated by a macro. - * Small code cleanups. Ugly whitespace changes for Plato's sake only ;-]. - * - * (04/Nov/2001) Bill Ryder - * Fixed bug in read_bulk_callback where incorrect urb buffer was used. - * Cleaned up write offset calculation - * Added write_room since default values can be incorrect for sio - * Changed write_bulk_callback to use same queue_task as other drivers - * (the previous version caused panics) - * Removed port iteration code since the device only has one I/O port and it - * was wrong anyway. - * - * (31/May/2001) gkh - * Switched from using spinlock to a semaphore, which fixes lots of problems. - * - * (23/May/2001) Bill Ryder - * Added runtime debug patch (thanx Tyson D Sawyer). - * Cleaned up comments for 8U232 - * Added parity, framing and overrun error handling - * Added receive break handling. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (18/March/2001) Bill Ryder - * (Not released) - * Added send break handling. (requires kernel patch too) - * Fixed 8U232AM hardware RTS/CTS etc status reporting. - * Added flipbuf fix copied from generic device - * - * (12/3/2000) Bill Ryder - * Added support for 8U232AM device. - * Moved PID and VIDs into header file only. - * Turned on low-latency for the tty (device will do high baudrates) - * Added shutdown routine to close files when device removed. - * More debug and error message cleanups. - * - * (11/13/2000) Bill Ryder - * Added spinlock protected open code and close code. - * Multiple opens work (sort of - see webpage mentioned above). - * Cleaned up comments. Removed multiple PID/VID definitions. - * Factorised cts/dtr code - * Made use of __FUNCTION__ in dbg's - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * - * (04/04/2000) Bill Ryder - * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are - * handled elsewhere in the tty io driver chain). - * - * (03/30/2000) Bill Ryder - * Implemented lots of ioctls - * Fixed a race condition in write - * Changed some dbg's to errs - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. + * Change entries from 2004 and earlier can be found in versions of this + * file in kernel versions prior to the 2.6.24 release. * */ @@ -309,12 +91,12 @@ struct ftdi_sio_quirk { void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */ }; -static int ftdi_olimex_probe (struct usb_serial *serial); +static int ftdi_jtag_probe (struct usb_serial *serial); static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); -static struct ftdi_sio_quirk ftdi_olimex_quirk = { - .probe = ftdi_olimex_probe, +static struct ftdi_sio_quirk ftdi_jtag_quirk = { + .probe = ftdi_jtag_probe, }; static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { @@ -471,30 +253,28 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, /* - * These will probably use user-space drivers. Uncomment them if - * you need them or use the user-specified vendor/product module - * parameters (see ftdi_sio.h for the numbers). Make a fuss if - * you think the driver should recognize any of them by default. + * Due to many user requests for multiple ELV devices we enable + * them by default. */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ + { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, @@ -545,6 +325,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, @@ -569,8 +350,13 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), - .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk }, + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -1283,10 +1069,11 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv) } /* ftdi_HE_TIRA1_setup */ /* - * First port on Olimex arm-usb-ocd is reserved for JTAG interface - * and can be accessed from userspace using openocd. + * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko + * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from + * userspace using openocd. */ -static int ftdi_olimex_probe(struct usb_serial *serial) +static int ftdi_jtag_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; @@ -1294,7 +1081,7 @@ static int ftdi_olimex_probe(struct usb_serial *serial) dbg("%s",__FUNCTION__); if (interface == udev->actconfig->interface[0]) { - info("Ignoring reserved serial port on Olimex arm-usb-ocd\n"); + info("Ignoring serial port reserved for JTAG"); return -ENODEV; } @@ -1411,7 +1198,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) dbg("%s", __FUNCTION__); - if (c_cflag & HUPCL){ + mutex_lock(&port->serial->disc_mutex); + if (c_cflag & HUPCL && !port->serial->disconnected){ /* Disable flow control */ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1425,6 +1213,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) /* drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Note change no line if hupcl is off */ + mutex_unlock(&port->serial->disc_mutex); /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index b51cbb0eaa05..6eee2ab914ec 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -98,6 +98,10 @@ #define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ #define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ +/* OOCDlink by Joern Kaipf <joernk@web.de> + * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */ +#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 @@ -245,6 +249,7 @@ #define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ #define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ #define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ +#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */ /* * Definitions for ID TECH (www.idt-net.com) devices @@ -278,6 +283,7 @@ #define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ #define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ #define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ +#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ /* * Protego product ids @@ -534,6 +540,8 @@ #define OLIMEX_VID 0x15BA #define OLIMEX_ARM_USB_OCD_PID 0x0003 +/* www.elsterelectricity.com Elster Unicom III Optical Probe */ +#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ /* * The Mobility Lab (TML) @@ -556,6 +564,13 @@ /* + * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 + * Submitted by Harald Welte <laforge@openmoko.org> + */ +#define FIC_VID 0x1457 +#define FIC_NEO1973_DEBUG_PID 0x5118 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index f1c90cfe7251..d74e43d69230 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1020,19 +1020,26 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp) if (!serial) return; - garmin_clear(garmin_data_p); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) + garmin_clear(garmin_data_p); /* shutdown our urbs */ usb_kill_urb (port->read_urb); usb_kill_urb (port->write_urb); - if (noResponseFromAppLayer(garmin_data_p) || - ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) { - process_resetdev_request(port); - garmin_data_p->state = STATE_RESET; + if (!port->serial->disconnected) { + if (noResponseFromAppLayer(garmin_data_p) || + ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) { + process_resetdev_request(port); + garmin_data_p->state = STATE_RESET; + } else { + garmin_data_p->state = STATE_DISCONNECTED; + } } else { garmin_data_p->state = STATE_DISCONNECTED; } + mutex_unlock(&port->serial->disc_mutex); } diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index d41531139c55..97fa3c428435 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb_serial *serial) struct usb_serial_port *port; int i, c = 0, r; +#ifdef CONFIG_PM + /* + * If this is an autoresume, don't submit URBs. + * They will be submitted in the open function instead. + */ + if (serial->dev->auto_pm) + return 0; +#endif for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; if (port->open_count && port->read_urb) { diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index a5d2e115e167..3428ccc28da7 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -959,7 +959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) * * This function will block the close until one of the following: * 1. Response to our Chase comes from Edgeport - * 2. A timout of 10 seconds without activity has expired + * 2. A timeout of 10 seconds without activity has expired * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/ @@ -999,7 +999,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) return; } } else { - // Reset timout value back to 10 seconds + // Reset timeout value back to 10 seconds dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits); loop = 10; } @@ -1014,7 +1014,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) * This function will block the close until one of the following: * 1. TX count are 0 * 2. The edgeport has stopped - * 3. A timout of 3 seconds without activity has expired + * 3. A timeout of 3 seconds without activity has expired * ************************************************************************/ static void block_until_tx_empty (struct edgeport_port *edge_port) @@ -1050,7 +1050,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port) return; } } else { - // Reset timout value back to seconds + // Reset timeout value back to seconds loop = 30; } } diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b8670905bc3a..cd3405953f74 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -34,6 +34,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/serial.h> #include <linux/ioctl.h> #include <asm/uaccess.h> @@ -133,7 +134,7 @@ struct edgeport_serial { struct product_info product_info; u8 TI_I2C_Type; // Type of I2C in UMP u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode - struct semaphore es_sem; + struct mutex es_lock; int num_ports_open; struct usb_serial *serial; }; @@ -1978,7 +1979,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) } /* set up the port settings */ - edge_set_termios (port, NULL); + edge_set_termios (port, port->tty->termios); /* open up the port */ @@ -2044,7 +2045,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr); edge_serial = edge_port->edge_serial; - if (down_interruptible(&edge_serial->es_sem)) + if (mutex_lock_interruptible(&edge_serial->es_lock)) return -ERESTARTSYS; if (edge_serial->num_ports_open == 0) { /* we are the first port to be opened, let's post the interrupt urb */ @@ -2052,7 +2053,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) if (!urb) { dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__); status = -EINVAL; - goto up_es_sem; + goto release_es_lock; } urb->complete = edge_interrupt_callback; urb->context = edge_serial; @@ -2060,7 +2061,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) status = usb_submit_urb (urb, GFP_KERNEL); if (status) { dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); - goto up_es_sem; + goto release_es_lock; } } @@ -2092,13 +2093,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) dbg("%s - exited", __FUNCTION__); - goto up_es_sem; + goto release_es_lock; unlink_int_urb: if (edge_port->edge_serial->num_ports_open == 0) usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -up_es_sem: - up(&edge_serial->es_sem); +release_es_lock: + mutex_unlock(&edge_serial->es_lock); return status; } @@ -2137,14 +2138,14 @@ static void edge_close (struct usb_serial_port *port, struct file *filp) 0, NULL, 0); - down(&edge_serial->es_sem); + mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { /* last port is now closed, let's shut down our interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); edge_port->edge_serial->num_ports_open = 0; } - up(&edge_serial->es_sem); + mutex_unlock(&edge_serial->es_lock); edge_port->close_pending = 0; dbg("%s - exited", __FUNCTION__); @@ -2393,11 +2394,6 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi dbg("%s - port %d", __FUNCTION__, edge_port->port->number); tty = edge_port->port->tty; - if ((!tty) || - (!tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { @@ -2492,15 +2488,21 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi } } + tty->termios->c_cflag &= ~CMSPAR; + /* Round the baud rate */ baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */ baud = 9600; - } + } else + tty_encode_baud_rate(tty, baud, baud); + edge_port->baud_rate = baud; config->wBaudRate = (__u16)((461550L + baud/2) / baud); + /* FIXME: Recompute actual baud from divisor here */ + dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate); dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate)); @@ -2538,19 +2540,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old struct tty_struct *tty = port->tty; unsigned int cflag; - if (!port->tty || !port->tty->termios) { - dbg ("%s - no tty or termios", __FUNCTION__); - return; - } - cflag = tty->termios->c_cflag; dbg("%s - clfag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, tty->termios->c_iflag); - if (old_termios) { - dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, - old_termios->c_cflag, old_termios->c_iflag); - } + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, old_termios->c_iflag); dbg("%s - port %d", __FUNCTION__, port->number); @@ -2743,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial) dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - sema_init(&edge_serial->es_sem, 1); + mutex_init(&edge_serial->es_lock); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c new file mode 100644 index 000000000000..fde188e23ce1 --- /dev/null +++ b/drivers/usb/serial/iuu_phoenix.c @@ -0,0 +1,1217 @@ +/* + * Infinity Unlimited USB Phoenix driver + * + * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) + * + * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás) + * + * 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. + * + * And tested with help of WB Electronics + * + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include "iuu_phoenix.h" +#include <linux/random.h> + + +#ifdef CONFIG_USB_SERIAL_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.5" +#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" + +static struct usb_device_id id_table[] = { + {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver iuu_driver = { + .name = "iuu_phoenix", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +/* turbo parameter */ +static int boost = 100; +static int clockmode = 1; +static int cdmode = 1; +static int iuu_cardin; +static int iuu_cardout; +static int xmas; + +static void read_rxcmd_callback(struct urb *urb); + +struct iuu_private { + spinlock_t lock; /* store irq state */ + wait_queue_head_t delta_msr_wait; + u8 line_control; + u8 line_status; + u8 termios_initialized; + int tiostatus; /* store IUART SIGNAL for tiocmget call */ + u8 reset; /* if 1 reset is needed */ + int poll; /* number of poll */ + u8 *writebuf; /* buffer for writing to device */ + int writelen; /* num of byte to write to device */ + u8 *buf; /* used for initialize speed */ + u8 *dbgbuf; /* debug buffer */ + u8 len; +}; + + +static void iuu_free_buf(struct iuu_private *priv) +{ + kfree(priv->buf); + kfree(priv->dbgbuf); + kfree(priv->writebuf); +} + +static int iuu_alloc_buf(struct iuu_private *priv) +{ + priv->buf = kzalloc(256, GFP_KERNEL); + priv->dbgbuf = kzalloc(256, GFP_KERNEL); + priv->writebuf = kzalloc(256, GFP_KERNEL); + if (!priv->buf || !priv->dbgbuf || !priv->writebuf) { + iuu_free_buf(priv); + dbg("%s problem allocation buffer", __FUNCTION__); + return -ENOMEM; + } + dbg("%s - Privates buffers allocation success", __FUNCTION__); + return 0; +} + +static int iuu_startup(struct usb_serial *serial) +{ + struct iuu_private *priv; + priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); + dbg("%s- priv allocation success", __FUNCTION__); + if (!priv) + return -ENOMEM; + if (iuu_alloc_buf(priv)) { + kfree(priv); + return -ENOMEM; + } + spin_lock_init(&priv->lock); + init_waitqueue_head(&priv->delta_msr_wait); + usb_set_serial_port_data(serial->port[0], priv); + return 0; +} + +/* Shutdown function */ +static void iuu_shutdown(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + struct iuu_private *priv = usb_get_serial_port_data(port); + if (!port) + return; + + dbg("%s", __FUNCTION__); + + if (priv) { + iuu_free_buf(priv); + dbg("%s - I will free all", __FUNCTION__); + usb_set_serial_port_data(port, NULL); + + dbg("%s - priv is not anymore in port structure", __FUNCTION__); + kfree(priv); + + dbg("%s priv is now kfree", __FUNCTION__); + } +} + +static int iuu_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; + tty = port->tty; + + dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__, + port->number, set, clear); + if (set & TIOCM_RTS) + priv->tiostatus = TIOCM_RTS; + + if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) { + dbg("%s TIOCMSET RESET called !!!", __FUNCTION__); + priv->reset = 1; + return 0; + } + + return 0; +} + +/* This is used to provide a carrier detect mechanism + * When a card is present, the response is 0x00 + * When no card , the reader respond with TIOCM_CD + * This is known as CD autodetect mechanism + */ +static int iuu_tiocmget(struct usb_serial_port *port, struct file *file) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + return priv->tiostatus; +} + +static void iuu_rxcmd(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + + memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + read_rxcmd_callback, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + +static int iuu_reset(struct usb_serial_port *port, u8 wt) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + + /* Prepare the reset sequence */ + + *buf_ptr++ = IUU_RST_SET; + *buf_ptr++ = IUU_DELAY_MS; + *buf_ptr++ = wt; + *buf_ptr = IUU_RST_CLEAR; + + /* send the sequence */ + + usb_fill_bulk_urb(port->write_urb, + port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 4, iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + priv->reset = 0; + return result; +} + +/* Status Function + * Return value is + * 0x00 = no card + * 0x01 = smartcard + * 0x02 = sim card + */ +static void iuu_update_status_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct iuu_private *priv = usb_get_serial_port_data(port); + u8 *st; + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + st = urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + if (urb->actual_length == 1) { + switch (st[0]) { + case 0x1: + priv->tiostatus = iuu_cardout; + break; + case 0x0: + priv->tiostatus = iuu_cardin; + break; + default: + priv->tiostatus = iuu_cardin; + } + } + iuu_rxcmd(urb); +} + +static void iuu_status_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, 256, + iuu_update_status_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); +} + +static int iuu_status(struct usb_serial_port *port) +{ + int result; + + dbg("%s - enter", __FUNCTION__); + + memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + iuu_status_callback, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + return result; + +} + +static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) +{ + int status; + struct usb_serial *serial = port->serial; + int actual = 0; + + dbg("%s - enter", __FUNCTION__); + + /* send the data out the bulk port */ + + status = + usb_bulk_msg(serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), buf, + count, &actual, HZ * 1); + + if (status != IUU_OPERATION_OK) { + dbg("%s - error = %2x", __FUNCTION__, status); + } else { + dbg("%s - write OK !", __FUNCTION__); + } + return status; +} + +static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) +{ + int status; + struct usb_serial *serial = port->serial; + int actual = 0; + + dbg("%s - enter", __FUNCTION__); + + /* send the data out the bulk port */ + + status = + usb_bulk_msg(serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), buf, + count, &actual, HZ * 1); + + if (status != IUU_OPERATION_OK) { + dbg("%s - error = %2x", __FUNCTION__, status); + } else { + dbg("%s - read OK !", __FUNCTION__); + } + + return status; +} + +static int iuu_led(struct usb_serial_port *port, unsigned int R, + unsigned int G, unsigned int B, u8 f) +{ + int status; + u8 *buf; + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dbg("%s - enter", __FUNCTION__); + + buf[0] = IUU_SET_LED; + buf[1] = R & 0xFF; + buf[2] = (R >> 8) & 0xFF; + buf[3] = G & 0xFF; + buf[4] = (G >> 8) & 0xFF; + buf[5] = B & 0xFF; + buf[6] = (B >> 8) & 0xFF; + buf[7] = f; + status = bulk_immediate(port, buf, 8); + kfree(buf); + if (status != IUU_OPERATION_OK) + dbg("%s - led error status = %2x", __FUNCTION__, status); + else + dbg("%s - led OK !", __FUNCTION__); + return IUU_OPERATION_OK; +} + +static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1, + u8 b2, u8 freq) +{ + *buf++ = IUU_SET_LED; + *buf++ = r1; + *buf++ = r2; + *buf++ = g1; + *buf++ = g2; + *buf++ = b1; + *buf++ = b2; + *buf = freq; +} + +static void iuu_led_activity_on(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + *buf_ptr++ = IUU_SET_LED; + if (xmas == 1) { + get_random_bytes(buf_ptr, 6); + *(buf_ptr+7) = 1; + } else { + iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255); + } + + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 8 , + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + +static void iuu_led_activity_off(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + char *buf_ptr = port->write_urb->transfer_buffer; + if (xmas == 1) { + iuu_rxcmd(urb); + return; + } else { + *buf_ptr++ = IUU_SET_LED; + iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); + } + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 8 , + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); +} + + + +static int iuu_clk(struct usb_serial_port *port, int dwFrq) +{ + int status; + struct iuu_private *priv = usb_get_serial_port_data(port); + int Count = 0; + u8 FrqGenAdr = 0x69; + u8 DIV = 0; /* 8bit */ + u8 XDRV = 0; /* 8bit */ + u8 PUMP = 0; /* 3bit */ + u8 PBmsb = 0; /* 2bit */ + u8 PBlsb = 0; /* 8bit */ + u8 PO = 0; /* 1bit */ + u8 Q = 0; /* 7bit */ + /* 24bit = 3bytes */ + unsigned int P = 0; + unsigned int P2 = 0; + int frq = (int)dwFrq; + + dbg("%s - enter", __FUNCTION__); + + if (frq == 0) { + priv->buf[Count++] = IUU_UART_WRITE_I2C; + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x09; + priv->buf[Count++] = 0x00; + + status = bulk_immediate(port, (u8 *) priv->buf, Count); + if (status != 0) { + dbg("%s - write error ", __FUNCTION__); + return status; + } + } else if (frq == 3579000) { + DIV = 100; + P = 1193; + Q = 40; + XDRV = 0; + } else if (frq == 3680000) { + DIV = 105; + P = 161; + Q = 5; + XDRV = 0; + } else if (frq == 6000000) { + DIV = 66; + P = 66; + Q = 2; + XDRV = 0x28; + } else { + unsigned int result = 0; + unsigned int tmp = 0; + unsigned int check; + unsigned int check2; + char found = 0x00; + unsigned int lQ = 2; + unsigned int lP = 2055; + unsigned int lDiv = 4; + + for (lQ = 2; lQ <= 47 && !found; lQ++) + for (lP = 2055; lP >= 8 && !found; lP--) + for (lDiv = 4; lDiv <= 127 && !found; lDiv++) { + tmp = (12000000 / lDiv) * (lP / lQ); + if (abs((int)(tmp - frq)) < + abs((int)(frq - result))) { + check2 = (12000000 / lQ); + if (check2 < 250000) + continue; + check = (12000000 / lQ) * lP; + if (check > 400000000) + continue; + if (check < 100000000) + continue; + if (lDiv < 4 || lDiv > 127) + continue; + result = tmp; + P = lP; + DIV = lDiv; + Q = lQ; + if (result == frq) + found = 0x01; + } + } + } + P2 = ((P - PO) / 2) - 4; + DIV = DIV; + PUMP = 0x04; + PBmsb = (P2 >> 8 & 0x03); + PBlsb = P2 & 0xFF; + PO = (P >> 10) & 0x01; + Q = Q - 2; + + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x09; + priv->buf[Count++] = 0x20; /* Adr = 0x09 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x0C; + priv->buf[Count++] = DIV; /* Adr = 0x0C */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x12; + priv->buf[Count++] = XDRV; /* Adr = 0x12 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x13; + priv->buf[Count++] = 0x6B; /* Adr = 0x13 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x40; + priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) | + (PBmsb & 0x03); /* Adr = 0x40 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x41; + priv->buf[Count++] = PBlsb; /* Adr = 0x41 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x42; + priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x44; + priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x45; + priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x46; + priv->buf[Count++] = 0x7F; /* Adr = 0x46 */ + priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ + priv->buf[Count++] = FrqGenAdr << 1; + priv->buf[Count++] = 0x47; + priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */ + + status = bulk_immediate(port, (u8 *) priv->buf, Count); + if (status != IUU_OPERATION_OK) + dbg("%s - write error ", __FUNCTION__); + return status; +} + +static int iuu_uart_flush(struct usb_serial_port *port) +{ + int i; + int status; + u8 rxcmd = IUU_UART_RX; + struct iuu_private *priv = usb_get_serial_port_data(port); + + dbg("%s - enter", __FUNCTION__); + + if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) + return -EIO; + + for (i = 0; i < 2; i++) { + status = bulk_immediate(port, &rxcmd, 1); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_write error", __FUNCTION__); + return status; + } + + status = read_immediate(port, &priv->len, 1); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_read error", __FUNCTION__); + return status; + } + + if (priv->len > 0) { + dbg("%s - uart_flush datalen is : %i ", __FUNCTION__, + priv->len); + status = read_immediate(port, priv->buf, priv->len); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_flush_read error", __FUNCTION__); + return status; + } + } + } + dbg("%s - uart_flush_read OK!", __FUNCTION__); + iuu_led(port, 0, 0xF000, 0, 0xFF); + return status; +} + +static void read_buf_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + if (urb->status == -EPROTO) { + /* reschedule needed */ + } + return; + } + + dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length); + tty = port->tty; + if (data == NULL) + dbg("%s - data is NULL !!!", __FUNCTION__); + if (tty && urb->actual_length && data) { + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + iuu_led_activity_on(urb); +} + +static int iuu_bulk_write(struct usb_serial_port *port) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + int result; + int i; + char *buf_ptr = port->write_urb->transfer_buffer; + dbg("%s - enter", __FUNCTION__); + + *buf_ptr++ = IUU_UART_ESC; + *buf_ptr++ = IUU_UART_TX; + *buf_ptr++ = priv->writelen; + + memcpy(buf_ptr, priv->writebuf, + priv->writelen); + if (debug == 1) { + for (i = 0; i < priv->writelen; i++) + sprintf(priv->dbgbuf + i*2 , + "%02X", priv->writebuf[i]); + priv->dbgbuf[priv->writelen+i*2] = 0; + dbg("%s - writing %i chars : %s", __FUNCTION__, + priv->writelen, priv->dbgbuf); + } + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, priv->writelen + 3, + iuu_rxcmd, port); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + spin_lock_irqsave(&priv->lock, flags); + priv->writelen = 0; + spin_unlock_irqrestore(&priv->lock, flags); + usb_serial_port_softint(port); + return result; +} + +static int iuu_read_buf(struct usb_serial_port *port, int len) +{ + int result; + dbg("%s - enter", __FUNCTION__); + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, len, + read_buf_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + return result; +} + +static void iuu_uart_read_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + int status; + int error = 0; + int len = 0; + unsigned char *data = urb->transfer_buffer; + priv->poll++; + + dbg("%s - enter", __FUNCTION__); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + if (data == NULL) + dbg("%s - data is NULL !!!", __FUNCTION__); + + if (urb->actual_length == 1 && data != NULL) + len = (int) data[0]; + + if (urb->actual_length > 1) { + dbg("%s - urb->actual_length = %i", __FUNCTION__, + urb->actual_length); + error = 1; + return; + } + /* if len > 0 call readbuf */ + + if (len > 0 && error == 0) { + dbg("%s - call read buf - len to read is %i ", + __FUNCTION__, len); + status = iuu_read_buf(port, len); + return; + } + /* need to update status ? */ + if (priv->poll > 99) { + status = iuu_status(port); + priv->poll = 0; + return; + } + + /* reset waiting ? */ + + if (priv->reset == 1) { + status = iuu_reset(port, 0xC); + return; + } + /* Writebuf is waiting */ + spin_lock_irqsave(&priv->lock, flags); + if (priv->writelen > 0) { + spin_unlock_irqrestore(&priv->lock, flags); + status = iuu_bulk_write(port); + return; + } + spin_unlock_irqrestore(&priv->lock, flags); + /* if nothing to write call again rxcmd */ + dbg("%s - rxcmd recall", __FUNCTION__); + iuu_led_activity_off(urb); + return; +} + +static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf, + int count) +{ + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned int flags; + dbg("%s - enter", __FUNCTION__); + + if (count > 256) + return -ENOMEM; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->writelen > 0) { + /* buffer already filled but not commited */ + spin_unlock_irqrestore(&priv->lock, flags); + return (0); + } + /* fill the buffer */ + memcpy(priv->writebuf, buf, count); + priv->writelen = count; + spin_unlock_irqrestore(&priv->lock, flags); + + return (count); +} + +static void read_rxcmd_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + int result; + dbg("%s - enter", __FUNCTION__); + + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + + if (urb->status) { + dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + /* error stop all */ + return; + } + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, 256, + iuu_uart_read_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + dbg("%s - submit result = %d", __FUNCTION__, result); + return; +} + +static int iuu_uart_on(struct usb_serial_port *port) +{ + int status; + u8 *buf; + + buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + buf[0] = IUU_UART_ENABLE; + buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF); + buf[2] = (u8) (0x00FF & IUU_BAUD_9600); + buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN); + + status = bulk_immediate(port, buf, 4); + if (status != IUU_OPERATION_OK) { + dbg("%s - uart_on error", __FUNCTION__); + goto uart_enable_failed; + } + /* iuu_reset() the card after iuu_uart_on() */ + status = iuu_uart_flush(port); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_flush error", __FUNCTION__); +uart_enable_failed: + kfree(buf); + return status; +} + +/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */ +static int iuu_uart_off(struct usb_serial_port *port) +{ + int status; + u8 *buf; + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = IUU_UART_DISABLE; + + status = bulk_immediate(port, buf, 1); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_off error", __FUNCTION__); + + kfree(buf); + return status; +} + +static int iuu_uart_baud(struct usb_serial_port *port, u32 baud, + u32 *actual, u8 parity) +{ + int status; + u8 *dataout; + u8 DataCount = 0; + u8 T1Frekvens = 0; + u8 T1reload = 0; + unsigned int T1FrekvensHZ = 0; + + dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); + + if (!dataout) + return -ENOMEM; + + if (baud < 1200 || baud > 230400) { + kfree(dataout); + return IUU_INVALID_PARAMETER; + } + if (baud > 977) { + T1Frekvens = 3; + T1FrekvensHZ = 500000; + } + + if (baud > 3906) { + T1Frekvens = 2; + T1FrekvensHZ = 2000000; + } + + if (baud > 11718) { + T1Frekvens = 1; + T1FrekvensHZ = 6000000; + } + + if (baud > 46875) { + T1Frekvens = 0; + T1FrekvensHZ = 24000000; + } + + T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2)); + + /* magic number here: ENTER_FIRMWARE_UPDATE; */ + dataout[DataCount++] = IUU_UART_ESC; + /* magic number here: CHANGE_BAUD; */ + dataout[DataCount++] = IUU_UART_CHANGE; + dataout[DataCount++] = T1Frekvens; + dataout[DataCount++] = T1reload; + + *actual = (T1FrekvensHZ / (256 - T1reload)) / 2; + + switch (parity & 0x0F) { + case IUU_PARITY_NONE: + dataout[DataCount++] = 0x00; + break; + case IUU_PARITY_EVEN: + dataout[DataCount++] = 0x01; + break; + case IUU_PARITY_ODD: + dataout[DataCount++] = 0x02; + break; + case IUU_PARITY_MARK: + dataout[DataCount++] = 0x03; + break; + case IUU_PARITY_SPACE: + dataout[DataCount++] = 0x04; + break; + default: + kfree(dataout); + return IUU_INVALID_PARAMETER; + break; + } + + switch (parity & 0xF0) { + case IUU_ONE_STOP_BIT: + dataout[DataCount - 1] |= IUU_ONE_STOP_BIT; + break; + + case IUU_TWO_STOP_BITS: + dataout[DataCount - 1] |= IUU_TWO_STOP_BITS; + break; + default: + kfree(dataout); + return IUU_INVALID_PARAMETER; + break; + } + + status = bulk_immediate(port, dataout, DataCount); + if (status != IUU_OPERATION_OK) + dbg("%s - uart_off error", __FUNCTION__); + kfree(dataout); + return status; +} + +static int set_control_lines(struct usb_device *dev, u8 value) +{ + return 0; +} + +static void iuu_close(struct usb_serial_port *port, struct file *filp) +{ + /* iuu_led (port,255,0,0,0); */ + struct usb_serial *serial; + struct iuu_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + unsigned int c_cflag; + + serial = port->serial; + if (!serial) + return; + + dbg("%s - port %d", __FUNCTION__, port->number); + + iuu_uart_off(port); + if (serial->dev) { + if (port->tty) { + c_cflag = port->tty->termios->c_cflag; + if (c_cflag & HUPCL) { + /* drop DTR and RTS */ + priv = usb_get_serial_port_data(port); + spin_lock_irqsave(&priv->lock, flags); + priv->line_control = 0; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, 0); + } + } + /* free writebuf */ + /* shutdown our urbs */ + dbg("%s - shutting down urbs", __FUNCTION__); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); + msleep(1000); + /* wait one second to free all buffers */ + iuu_led(port, 0, 0, 0xF000, 0xFF); + msleep(1000); + usb_reset_device(port->serial->dev); + } +} + +static int iuu_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + u8 *buf; + int result; + u32 actual; + unsigned long flags; + struct iuu_private *priv = usb_get_serial_port_data(port); + + dbg("%s - port %d", __FUNCTION__, port->number); + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + + buf = kmalloc(10, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + /* fixup the endpoint buffer size */ + kfree(port->bulk_out_buffer); + port->bulk_out_buffer = kmalloc(512, GFP_KERNEL); + port->bulk_out_size = 512; + kfree(port->bulk_in_buffer); + port->bulk_in_buffer = kmalloc(512, GFP_KERNEL); + port->bulk_in_size = 512; + + if (!port->bulk_out_buffer || !port->bulk_in_buffer) { + kfree(port->bulk_out_buffer); + kfree(port->bulk_in_buffer); + kfree(buf); + return -ENOMEM; + } + + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->bulk_out_buffer, 512, + NULL, NULL); + + + usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, 512, + NULL, NULL); + + /* set the termios structure */ + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(port->tty->termios) = tty_std_termios; + port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + | TIOCM_CTS | CSTOPB | PARENB; + port->tty->termios->c_lflag = 0; + port->tty->termios->c_oflag = 0; + port->tty->termios->c_iflag = 0; + priv->termios_initialized = 1; + port->tty->low_latency = 1; + priv->poll = 0; + } + spin_unlock_irqrestore(&priv->lock, flags); + + /* initialize writebuf */ +#define FISH(a, b, c, d) do { \ + result = usb_control_msg(port->serial->dev, \ + usb_rcvctrlpipe(port->serial->dev, 0), \ + b, a, c, d, buf, 1, 1000); \ + dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \ + buf[0]); } while (0); + +#define SOUP(a, b, c, d) do { \ + result = usb_control_msg(port->serial->dev, \ + usb_sndctrlpipe(port->serial->dev, 0), \ + b, a, c, d, NULL, 0, 1000); \ + dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0) + + /* This is not UART related but IUU USB driver related or something */ + /* like that. Basically no IUU will accept any commands from the USB */ + /* host unless it has received the following message */ + /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ + + SOUP(0x03, 0x02, 0x02, 0x0); + kfree(buf); + iuu_led(port, 0xF000, 0xF000, 0, 0xFF); + iuu_uart_on(port); + if (boost < 100) + boost = 100; + switch (clockmode) { + case 2: /* 3.680 Mhz */ + iuu_clk(port, IUU_CLK_3680000 * boost / 100); + result = + iuu_uart_baud(port, 9600 * boost / 100, &actual, + IUU_PARITY_EVEN); + break; + case 3: /* 6.00 Mhz */ + iuu_clk(port, IUU_CLK_6000000 * boost / 100); + result = + iuu_uart_baud(port, 16457 * boost / 100, &actual, + IUU_PARITY_EVEN); + break; + default: /* 3.579 Mhz */ + iuu_clk(port, IUU_CLK_3579000 * boost / 100); + result = + iuu_uart_baud(port, 9600 * boost / 100, &actual, + IUU_PARITY_EVEN); + } + + /* set the cardin cardout signals */ + switch (cdmode) { + case 0: + iuu_cardin = 0; + iuu_cardout = 0; + break; + case 1: + iuu_cardin = TIOCM_CD; + iuu_cardout = 0; + break; + case 2: + iuu_cardin = 0; + iuu_cardout = TIOCM_CD; + break; + case 3: + iuu_cardin = TIOCM_DSR; + iuu_cardout = 0; + break; + case 4: + iuu_cardin = 0; + iuu_cardout = TIOCM_DSR; + break; + case 5: + iuu_cardin = TIOCM_CTS; + iuu_cardout = 0; + break; + case 6: + iuu_cardin = 0; + iuu_cardout = TIOCM_CTS; + break; + case 7: + iuu_cardin = TIOCM_RNG; + iuu_cardout = 0; + break; + case 8: + iuu_cardin = 0; + iuu_cardout = TIOCM_RNG; + } + + iuu_uart_flush(port); + + dbg("%s - initialization done", __FUNCTION__); + + memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, 1, + read_rxcmd_callback, port); + result = usb_submit_urb(port->write_urb, GFP_KERNEL); + + if (result) { + dev_err(&port->dev, "%s - failed submitting read urb," + " error %d\n", __FUNCTION__, result); + iuu_close(port, NULL); + return -EPROTO; + } else { + dbg("%s - rxcmd OK", __FUNCTION__); + } + return result; +} + +static struct usb_serial_driver iuu_device = { + .driver = { + .owner = THIS_MODULE, + .name = "iuu_phoenix", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = iuu_open, + .close = iuu_close, + .write = iuu_uart_write, + .read_bulk_callback = iuu_uart_read_callback, + .tiocmget = iuu_tiocmget, + .tiocmset = iuu_tiocmset, + .attach = iuu_startup, + .shutdown = iuu_shutdown, +}; + +static int __init iuu_init(void) +{ + int retval; + retval = usb_serial_register(&iuu_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&iuu_driver); + if (retval) + goto failed_usb_register; + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +failed_usb_register: + usb_serial_deregister(&iuu_device); +failed_usb_serial_register: + return retval; +} + +static void __exit iuu_exit(void) +{ + usb_deregister(&iuu_driver); + usb_serial_deregister(&iuu_device); +} + +module_init(iuu_init); +module_exit(iuu_exit); + +MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(DRIVER_VERSION); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +module_param(xmas, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(xmas, "xmas color enabled or not"); + +module_param(boost, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500"); + +module_param(clockmode, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz"); + +module_param(cdmode, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, " + "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING"); diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h new file mode 100644 index 000000000000..b82630a3b8fd --- /dev/null +++ b/drivers/usb/serial/iuu_phoenix.h @@ -0,0 +1,122 @@ +/* + * Infinity Unlimited USB Phoenix driver + * + * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) + * + * + * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás ) + * + * 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. + * + * And tested with help of WB Electronics + * + */ + +#define IUU_USB_VENDOR_ID 0x104f +#define IUU_USB_PRODUCT_ID 0x0004 +#define IUU_USB_OP_TIMEOUT 0x0200 + +/* Programmer commands */ + +#define IUU_NO_OPERATION 0x00 +#define IUU_GET_FIRMWARE_VERSION 0x01 +#define IUU_GET_PRODUCT_NAME 0x02 +#define IUU_GET_STATE_REGISTER 0x03 +#define IUU_SET_LED 0x04 +#define IUU_WAIT_MUS 0x05 +#define IUU_WAIT_MS 0x06 +#define IUU_GET_LOADER_VERSION 0x50 +#define IUU_RST_SET 0x52 +#define IUU_RST_CLEAR 0x53 +#define IUU_SET_VCC 0x59 +#define IUU_UART_ENABLE 0x49 +#define IUU_UART_DISABLE 0x4A +#define IUU_UART_WRITE_I2C 0x4C +#define IUU_UART_ESC 0x5E +#define IUU_UART_TRAP 0x54 +#define IUU_UART_TRAP_BREAK 0x5B +#define IUU_UART_RX 0x56 +#define IUU_AVR_ON 0x21 +#define IUU_AVR_OFF 0x22 +#define IUU_AVR_1CLK 0x23 +#define IUU_AVR_RESET 0x24 +#define IUU_AVR_RESET_PC 0x25 +#define IUU_AVR_INC_PC 0x26 +#define IUU_AVR_INCN_PC 0x27 +#define IUU_AVR_PREAD 0x29 +#define IUU_AVR_PREADN 0x2A +#define IUU_AVR_PWRITE 0x28 +#define IUU_AVR_DREAD 0x2C +#define IUU_AVR_DREADN 0x2D +#define IUU_AVR_DWRITE 0x2B +#define IUU_AVR_PWRITEN 0x2E +#define IUU_EEPROM_ON 0x37 +#define IUU_EEPROM_OFF 0x38 +#define IUU_EEPROM_WRITE 0x39 +#define IUU_EEPROM_WRITEX 0x3A +#define IUU_EEPROM_WRITE8 0x3B +#define IUU_EEPROM_WRITE16 0x3C +#define IUU_EEPROM_WRITEX32 0x3D +#define IUU_EEPROM_WRITEX64 0x3E +#define IUU_EEPROM_READ 0x3F +#define IUU_EEPROM_READX 0x40 +#define IUU_EEPROM_BREAD 0x41 +#define IUU_EEPROM_BREADX 0x42 +#define IUU_PIC_CMD 0x0A +#define IUU_PIC_CMD_LOAD 0x0B +#define IUU_PIC_CMD_READ 0x0C +#define IUU_PIC_ON 0x0D +#define IUU_PIC_OFF 0x0E +#define IUU_PIC_RESET 0x16 +#define IUU_PIC_INC_PC 0x0F +#define IUU_PIC_INCN_PC 0x10 +#define IUU_PIC_PWRITE 0x11 +#define IUU_PIC_PREAD 0x12 +#define IUU_PIC_PREADN 0x13 +#define IUU_PIC_DWRITE 0x14 +#define IUU_PIC_DREAD 0x15 +#define IUU_UART_NOP 0x00 +#define IUU_UART_CHANGE 0x02 +#define IUU_UART_TX 0x04 +#define IUU_DELAY_MS 0x06 + +#define IUU_OPERATION_OK 0x00 +#define IUU_DEVICE_NOT_FOUND 0x01 +#define IUU_INVALID_HANDLE 0x02 +#define IUU_INVALID_PARAMETER 0x03 +#define IUU_INVALID_voidERFACE 0x04 +#define IUU_INVALID_REQUEST_LENGTH 0x05 +#define IUU_UART_NOT_ENABLED 0x06 +#define IUU_WRITE_ERROR 0x07 +#define IUU_READ_ERROR 0x08 +#define IUU_TX_ERROR 0x09 +#define IUU_RX_ERROR 0x0A + +#define IUU_PARITY_NONE 0x00 +#define IUU_PARITY_EVEN 0x01 +#define IUU_PARITY_ODD 0x02 +#define IUU_PARITY_MARK 0x03 +#define IUU_PARITY_SPACE 0x04 +#define IUU_SC_INSERTED 0x01 +#define IUU_VERIFY_ERROR 0x02 +#define IUU_SIM_INSERTED 0x04 +#define IUU_TWO_STOP_BITS 0x00 +#define IUU_ONE_STOP_BIT 0x20 +#define IUU_BAUD_2400 0x0398 +#define IUU_BAUD_9600 0x0298 +#define IUU_BAUD_19200 0x0164 +#define IUU_BAUD_28800 0x0198 +#define IUU_BAUD_38400 0x01B2 +#define IUU_BAUD_57600 0x0030 +#define IUU_BAUD_115200 0x0098 +#define IUU_CLK_3579000 3579000 +#define IUU_CLK_3680000 3680000 +#define IUU_CLK_6000000 6000000 +#define IUU_FULLCARD_IN 0x01 +#define IUU_DEV_ERROR 0x02 +#define IUU_MINICARD_IN 0x04 +#define IUU_VCC_5V 0x00 +#define IUU_VCC_3V 0x01 diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7c069a02c1dd..ea7bba69f4da 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -838,7 +838,7 @@ static void usa49_indat_callback(struct urb *urb) port = (struct usb_serial_port *) urb->context; tty = port->tty; - if (urb->actual_length) { + if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { /* no error on any byte */ diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index be9ac20a8f10..b1fa5a376e96 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -303,7 +303,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port) } -static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) +static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud) { int rc; int bindex; @@ -319,7 +319,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) case 38400: bindex = 7; break; case 57600: bindex = 8; break; case 115200: bindex = 9; break; - default: return -EINVAL; + default: + bindex = 5; /* Default to 9600 */ + baud = 9600; } /* rather than figure out how to sleep while waiting for this @@ -334,7 +336,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) NULL, /* &data */ 0, /* size */ 2000); /* timeout */ - return(rc); + if (rc < 0) + return 0; + return baud; } @@ -366,7 +370,7 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; - unsigned int cflag = port->tty->termios->c_cflag; + speed_t speed; /* cflag specifies lots of stuff: number of stop bits, parity, number of data bits, baud. What can the device actually handle?: @@ -388,22 +392,18 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port, For now, just do baud. */ - switch (cflag & CBAUD) { - /* we could support more values here, just need to calculate - the necessary divisors in the firmware. <asm/termbits.h> - has the Bnnn constants. */ - case B110: keyspan_pda_setbaud(serial, 110); break; - case B300: keyspan_pda_setbaud(serial, 300); break; - case B1200: keyspan_pda_setbaud(serial, 1200); break; - case B2400: keyspan_pda_setbaud(serial, 2400); break; - case B4800: keyspan_pda_setbaud(serial, 4800); break; - case B9600: keyspan_pda_setbaud(serial, 9600); break; - case B19200: keyspan_pda_setbaud(serial, 19200); break; - case B38400: keyspan_pda_setbaud(serial, 38400); break; - case B57600: keyspan_pda_setbaud(serial, 57600); break; - case B115200: keyspan_pda_setbaud(serial, 115200); break; - default: dbg("can't handle requested baud rate"); break; + speed = tty_get_baud_rate(port->tty); + speed = keyspan_pda_setbaud(serial, speed); + + if (speed == 0) { + dbg("can't handle requested baud rate"); + /* It hasn't changed so.. */ + speed = tty_termios_baud_rate(old_termios); } + /* Only speed can change so copy the old h/w parameters + then encode the new speed */ + tty_termios_copy_hw(port->tty->termios, old_termios); + tty_encode_baud_rate(port->tty, speed, speed); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 90e3216abd1f..55736df7d2f4 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -461,17 +461,21 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp) dbg("%s port %d", __FUNCTION__, port->number); - /* send READ_OFF */ - rc = usb_control_msg (port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR | USB_DIR_OUT, - KL5KUSB105A_SIO_CONFIGURE_READ_OFF, - 0, /* index */ - NULL, 0, - KLSI_TIMEOUT); - if (rc < 0) - err("Disabling read failed (error = %d)", rc); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* send READ_OFF */ + rc = usb_control_msg (port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR | USB_DIR_OUT, + KL5KUSB105A_SIO_CONFIGURE_READ_OFF, + 0, /* index */ + NULL, 0, + KLSI_TIMEOUT); + if (rc < 0) + err("Disabling read failed (error = %d)", rc); + } + mutex_unlock(&port->serial->disc_mutex); /* shutdown our bulk reads and writes */ usb_kill_urb(port->write_urb); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index aee450246bfd..17b3baead4ad 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -114,6 +114,7 @@ static struct usb_serial_driver kobil_device = { .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = 0, .num_bulk_out = 0, .num_ports = 1, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 0dc99f75bb09..fc1cea4aba13 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -182,10 +182,11 @@ struct mct_u232_private { /* * Later day 2.6.0-test kernels have new baud rates like B230400 which * we do not know how to support. We ignore them for the moment. - * XXX Rate-limit the error message, it's user triggerable. */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value) +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result) { + *result = value; + if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) { switch (value) { @@ -200,11 +201,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value case 57600: return 0x0b; case 115200: return 0x0c; default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); + *result = 9600; return 0x08; } } else { + /* FIXME: Can we use any divider - should we do + divider = 115200/value; + real baud = 115200/divider */ switch (value) { case 300: break; case 600: break; @@ -217,9 +220,8 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value case 57600: break; case 115200: break; default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); value = 9600; + *result = 9600; } return 115200/value; } @@ -232,16 +234,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_p int rc; unsigned char zero_byte = 0; unsigned char cts_enable_byte = 0; + speed_t speed; - divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value)); + divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed)); rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_BAUD_RATE_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE, WDR_TIMEOUT); - if (rc < 0) + if (rc < 0) /*FIXME: What value speed results */ err("Set BAUD RATE %d failed (error = %d)", value, rc); + else + tty_encode_baud_rate(port->tty, speed, speed); dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor); /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which @@ -482,21 +487,22 @@ error: static void mct_u232_close (struct usb_serial_port *port, struct file *filp) { unsigned int c_cflag; - unsigned long flags; unsigned int control_state; struct mct_u232_private *priv = usb_get_serial_port_data(port); dbg("%s port %d", __FUNCTION__, port->number); if (port->tty) { c_cflag = port->tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_modem_ctrl(port->serial, control_state); + mutex_lock(&port->serial->disc_mutex); + if (c_cflag & HUPCL && !port->serial->disconnected) { + /* drop DTR and RTS */ + spin_lock_irq(&priv->lock); + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + control_state = priv->control_state; + spin_unlock_irq(&priv->lock); + mct_u232_set_modem_ctrl(port->serial, control_state); } + mutex_unlock(&port->serial->disc_mutex); } @@ -608,7 +614,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port, { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = port->tty->termios->c_cflag; + struct ktermios *termios = port->tty->termios; + unsigned int cflag = termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; unsigned int control_state; @@ -670,6 +677,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port, break; } + termios->c_cflag &= ~CMSPAR; + /* set the number of stop bits */ last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h index aae10c8174d6..07b6bec31dc8 100644 --- a/drivers/usb/serial/mct_u232.h +++ b/drivers/usb/serial/mct_u232.h @@ -79,7 +79,7 @@ * and "Intel solution". They are the regular MCT and "Sitecom" for us. * This is pointless to document in the header, see the code for the bits. */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value); +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result); /* * Line Control Register (LCR) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e02c198016b0..40f3a0188807 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp) } /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists */ - if (serial->dev) { - dbg("Shutdown bulk write"); - usb_kill_urb(port->write_urb); - dbg("Shutdown bulk read"); - usb_kill_urb(port->read_urb); + * and interrupt read if they exists, otherwise nop */ + dbg("Shutdown bulk write"); + usb_kill_urb(port->write_urb); + dbg("Shutdown bulk read"); + usb_kill_urb(port->read_urb); + + mutex_lock(&serial->disc_mutex); + /* these commands must not be issued if the device has + * been disconnected */ + if (!serial->disconnected) { + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x01, &data); } - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - 0x04, &data); - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - 0x01, &data); - + mutex_unlock(&serial->disc_mutex); mos7720_port->open = 0; dbg("Leaving %s", __FUNCTION__); @@ -1040,11 +1043,6 @@ static void change_port_settings(struct moschip_port *mos7720_port, tty = mos7720_port->port->tty; - if ((!tty) || (!tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - dbg("%s: Entering ..........", __FUNCTION__); lData = UART_LCR_WLEN8; @@ -1175,7 +1173,10 @@ static void change_port_settings(struct moschip_port *mos7720_port, dbg("%s - baud rate = %d", __FUNCTION__, baud); status = send_cmd_write_baud_rate(mos7720_port, baud); - + /* FIXME: needs to write actual resulting baud back not just + blindly do so */ + if (cflag & CBAUD) + tty_encode_baud_rate(tty, baud, baud); /* Enable Interrupts */ data = 0x0c; send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); @@ -1214,10 +1215,6 @@ static void mos7720_set_termios(struct usb_serial_port *port, tty = port->tty; - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty or termios", __FUNCTION__); - return; - } if (!mos7720_port->open) { dbg("%s - port not opened", __FUNCTION__); @@ -1228,19 +1225,13 @@ static void mos7720_set_termios(struct usb_serial_port *port, cflag = tty->termios->c_cflag; - if (!cflag) { - printk("%s %s\n",__FUNCTION__,"cflag is NULL"); - return; - } - - dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + dbg("%s - cflag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); - if (old_termios) - dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, - old_termios->c_cflag, - RELEVANT_IFLAG(old_termios->c_iflag)); + dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); dbg("%s - port %d", __FUNCTION__, port->number); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c29c91271133..869ecd374cb4 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1133,7 +1133,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port) * This function will block the close until one of the following: * 1. TX count are 0 * 2. The mos7840 has stopped - * 3. A timout of 3 seconds without activity has expired + * 3. A timeout of 3 seconds without activity has expired * ************************************************************************/ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port) @@ -1161,7 +1161,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port) dbg("%s - TIMEOUT", __FUNCTION__); return; } else { - /* Reset timout value back to seconds */ + /* Reset timeout value back to seconds */ wait = 30; } } @@ -1275,7 +1275,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp) * * This function will block the close until one of the following: * 1. Response to our Chase comes from mos7840 - * 2. A timout of 10 seconds without activity has expired + * 2. A timeout of 10 seconds without activity has expired * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/ @@ -1304,7 +1304,7 @@ static void mos7840_block_until_chase_response(struct moschip_port dbg("%s - TIMEOUT", __FUNCTION__); return; } else { - /* Reset timout value back to seconds */ + /* Reset timeout value back to seconds */ wait = 10; } } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d1185f53447b..5e8bf1bc1e50 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -180,6 +180,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */ + { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */ { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, @@ -640,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp) portdata->dtr_state = 0; if (serial->dev) { - option_send_setup(port); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + option_send_setup(port); + mutex_unlock(&serial->disc_mutex); /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index eea226ae37bd..a3847d6c946e 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -79,7 +79,7 @@ static int debug; #define PL2303_BUF_SIZE 1024 #define PL2303_TMP_BUF_SIZE 1024 -struct pl2303_buf { +struct oti6858_buf { unsigned int buf_size; char *buf_buf; char *buf_get; @@ -161,14 +161,14 @@ static int oti6858_startup(struct usb_serial *serial); static void oti6858_shutdown(struct usb_serial *serial); /* functions operating on buffers */ -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size); -static void pl2303_buf_free(struct pl2303_buf *pb); -static void pl2303_buf_clear(struct pl2303_buf *pb); -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, +static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); +static void oti6858_buf_free(struct oti6858_buf *pb); +static void oti6858_buf_clear(struct oti6858_buf *pb); +static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb); +static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb); +static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, unsigned int count); -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, +static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, unsigned int count); @@ -203,7 +203,7 @@ static struct usb_serial_driver oti6858_device = { struct oti6858_private { spinlock_t lock; - struct pl2303_buf *buf; + struct oti6858_buf *buf; struct oti6858_control_pkt status; struct { @@ -316,7 +316,7 @@ void send_data(struct work_struct *work) } priv->flags.write_urb_in_use = 1; - count = pl2303_buf_data_avail(priv->buf); + count = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); if (count > port->bulk_out_size) count = port->bulk_out_size; @@ -345,7 +345,7 @@ void send_data(struct work_struct *work) } spin_lock_irqsave(&priv->lock, flags); - pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count); + oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count); spin_unlock_irqrestore(&priv->lock, flags); port->write_urb->transfer_buffer_length = count; @@ -370,7 +370,7 @@ static int oti6858_startup(struct usb_serial *serial) priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); if (!priv) break; - priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); + priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE); if (priv->buf == NULL) { kfree(priv); break; @@ -391,7 +391,7 @@ static int oti6858_startup(struct usb_serial *serial) for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); - pl2303_buf_free(priv->buf); + oti6858_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -410,7 +410,7 @@ static int oti6858_write(struct usb_serial_port *port, return count; spin_lock_irqsave(&priv->lock, flags); - count = pl2303_buf_put(priv->buf, buf, count); + count = oti6858_buf_put(priv->buf, buf, count); spin_unlock_irqrestore(&priv->lock, flags); return count; @@ -425,7 +425,7 @@ static int oti6858_write_room(struct usb_serial_port *port) dbg("%s(port = %d)", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); - room = pl2303_buf_space_avail(priv->buf); + room = oti6858_buf_space_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); return room; @@ -440,7 +440,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port) dbg("%s(port = %d)", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); - chars = pl2303_buf_data_avail(priv->buf); + chars = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); return chars; @@ -458,7 +458,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, dbg("%s(port = %d)", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s(): no tty structures", __FUNCTION__); return; } @@ -468,6 +468,8 @@ static void oti6858_set_termios(struct usb_serial_port *port, *(port->tty->termios) = tty_std_termios; port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; priv->flags.termios_initialized = 1; + port->tty->termios->c_ispeed = 38400; + port->tty->termios->c_ospeed = 38400; } spin_unlock_irqrestore(&priv->lock, flags); @@ -504,19 +506,14 @@ static void oti6858_set_termios(struct usb_serial_port *port, br = tty_get_baud_rate(port->tty); if (br == 0) { divisor = 0; - } else if (br <= OTI6858_MAX_BAUD_RATE) { + } else { int real_br; + br = min(br, OTI6858_MAX_BAUD_RATE); divisor = (96000000 + 8 * br) / (16 * br); real_br = 96000000 / (16 * divisor); - if ((((real_br - br) * 100 + br - 1) / br) > 2) { - dbg("%s(): baud rate %d is invalid", __FUNCTION__, br); - return; - } divisor = cpu_to_le16(divisor); - } else { - dbg("%s(): baud rate %d is too high", __FUNCTION__, br); - return; + tty_encode_baud_rate(port->tty, real_br, real_br); } frame_fmt &= ~FMT_STOP_BITS_MASK; @@ -650,9 +647,9 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) dbg("%s(): entering wait loop", __FUNCTION__); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (pl2303_buf_data_avail(priv->buf) == 0 + if (oti6858_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->serial->interface)) /* disconnect */ + || port->serial->disconnected) break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); @@ -663,7 +660,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) dbg("%s(): after wait loop", __FUNCTION__); /* clear out any remaining data in the buffer */ - pl2303_buf_clear(priv->buf); + oti6858_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); /* wait for characters to drain from the device */ @@ -831,21 +828,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, return -EFAULT; return oti6858_tiocmset(port, NULL, 0, x); - case TIOCGSERIAL: - if (copy_to_user(user_arg, port->tty->termios, - sizeof(struct ktermios))) { - return -EFAULT; - } - return 0; - - case TIOCSSERIAL: - if (copy_from_user(port->tty->termios, user_arg, - sizeof(struct ktermios))) { - return -EFAULT; - } - oti6858_set_termios(port, NULL); - return 0; - case TIOCMIWAIT: dbg("%s(): TIOCMIWAIT", __FUNCTION__); return wait_modem_info(port, arg); @@ -887,7 +869,7 @@ static void oti6858_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); if (priv) { - pl2303_buf_free(priv->buf); + oti6858_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -987,7 +969,7 @@ static void oti6858_read_int_callback(struct urb *urb) spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use == 0 - && pl2303_buf_data_avail(priv->buf) != 0) { + && oti6858_buf_data_avail(priv->buf) != 0) { schedule_delayed_work(&priv->delayed_write_work,0); resubmit = 0; } @@ -1015,9 +997,8 @@ static void oti6858_read_bulk_callback(struct urb *urb) struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; - int i, result; int status = urb->status; - char tty_flag; + int result; dbg("%s(port = %d, status = %d)", __FUNCTION__, port->number, status); @@ -1045,27 +1026,9 @@ static void oti6858_read_bulk_callback(struct urb *urb) return; } - // get tty_flag from status - tty_flag = TTY_NORMAL; - -/* FIXME: probably, errors will be signalled using interrupt pipe! */ -/* - // break takes precedence over parity, - // which takes precedence over framing errors - if (status & UART_BREAK_ERROR ) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag); -*/ - tty = port->tty; if (tty != NULL && urb->actual_length > 0) { - tty_buffer_request_room(tty, urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) - tty_insert_flip_char(tty, data[i], tty_flag); + tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } @@ -1133,18 +1096,18 @@ static void oti6858_write_bulk_callback(struct urb *urb) /* - * pl2303_buf_alloc + * oti6858_buf_alloc * * Allocate a circular buffer and all associated memory. */ -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) +static struct oti6858_buf *oti6858_buf_alloc(unsigned int size) { - struct pl2303_buf *pb; + struct oti6858_buf *pb; if (size == 0) return NULL; - pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL); if (pb == NULL) return NULL; @@ -1161,11 +1124,11 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) } /* - * pl2303_buf_free + * oti6858_buf_free * * Free the buffer and all associated memory. */ -static void pl2303_buf_free(struct pl2303_buf *pb) +static void oti6858_buf_free(struct oti6858_buf *pb) { if (pb) { kfree(pb->buf_buf); @@ -1174,11 +1137,11 @@ static void pl2303_buf_free(struct pl2303_buf *pb) } /* - * pl2303_buf_clear + * oti6858_buf_clear * * Clear out all data in the circular buffer. */ -static void pl2303_buf_clear(struct pl2303_buf *pb) +static void oti6858_buf_clear(struct oti6858_buf *pb) { if (pb != NULL) { /* equivalent to a get of all data available */ @@ -1187,12 +1150,12 @@ static void pl2303_buf_clear(struct pl2303_buf *pb) } /* - * pl2303_buf_data_avail + * oti6858_buf_data_avail * * Return the number of bytes of data available in the circular * buffer. */ -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) +static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb) { if (pb == NULL) return 0; @@ -1200,12 +1163,12 @@ static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) } /* - * pl2303_buf_space_avail + * oti6858_buf_space_avail * * Return the number of bytes of space available in the circular * buffer. */ -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) +static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb) { if (pb == NULL) return 0; @@ -1213,14 +1176,14 @@ static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) } /* - * pl2303_buf_put + * oti6858_buf_put * * Copy data data from a user buffer and put it into the circular buffer. * Restrict to the amount of space available. * * Return the number of bytes copied. */ -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, +static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, unsigned int count) { unsigned int len; @@ -1228,7 +1191,7 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, if (pb == NULL) return 0; - len = pl2303_buf_space_avail(pb); + len = oti6858_buf_space_avail(pb); if (count > len) count = len; @@ -1252,14 +1215,14 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, } /* - * pl2303_buf_get + * oti6858_buf_get * * Get data from the circular buffer and copy to the given buffer. * Restrict to the amount of data available. * * Return the number of bytes copied. */ -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, +static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, unsigned int count) { unsigned int len; @@ -1267,7 +1230,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, if (pb == NULL) return 0; - len = pl2303_buf_data_avail(pb); + len = oti6858_buf_data_avail(pb); if (count > len) count = len; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 0da1df9c79bf..ae3ec1a64008 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, @@ -84,9 +85,10 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -97,7 +99,10 @@ static struct usb_driver pl2303_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, .no_dynamic_id = 1, + .supports_autosuspend = 1, }; #define SET_LINE_REQUEST_TYPE 0x21 @@ -310,12 +315,39 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, return count; } +static int pl2303_vendor_read(__u16 value, __u16 index, + struct usb_serial *serial, unsigned char *buf) +{ + int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, + value, index, buf, 1, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, + VENDOR_READ_REQUEST, value, index, res, buf[0]); + return res; +} + +static int pl2303_vendor_write(__u16 value, __u16 index, + struct usb_serial *serial) +{ + int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, + value, index, NULL, 0, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, + VENDOR_WRITE_REQUEST, value, index, res); + return res; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_private *priv; enum pl2303_type type = type_0; + unsigned char *buf; int i; + buf = kmalloc(10, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + if (serial->dev->descriptor.bDeviceClass == 0x02) type = type_0; else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) @@ -340,9 +372,27 @@ static int pl2303_startup(struct usb_serial *serial) priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } + + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 0, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 1, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_write(0, 1, serial); + pl2303_vendor_write(1, 0, serial); + if (type == HX) + pl2303_vendor_write(2, 0x44, serial); + else + pl2303_vendor_write(2, 0x24, serial); + + kfree(buf); return 0; cleanup: + kfree(buf); for (--i; i>=0; --i) { priv = usb_get_serial_port_data(serial->port[i]); pl2303_buf_free(priv->buf); @@ -582,24 +632,12 @@ static void pl2303_set_termios(struct usb_serial_port *port, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { - __u16 index; if (priv->type == HX) - index = 0x61; + pl2303_vendor_write(0x0, 0x61, serial); else - index = 0x41; - i = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, - VENDOR_WRITE_REQUEST_TYPE, - 0x0, index, NULL, 0, 100); - dbg("0x40:0x1:0x0:0x%x %d", index, i); + pl2303_vendor_write(0x0, 0x41, serial); } else { - i = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, - VENDOR_WRITE_REQUEST_TYPE, - 0x0, 0x0, NULL, 0, 100); - dbg ("0x40:0x1:0x0:0x0 %d", i); + pl2303_vendor_write(0x0, 0x0, serial); } /* FIXME: Need to read back resulting baud rate */ @@ -629,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp) set_current_state(TASK_INTERRUPTIBLE); if (pl2303_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) || - !usb_get_intfdata(port->serial->interface)) /* disconnect */ + port->serial->disconnected) break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); @@ -678,7 +716,6 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp) struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned char *buf; int result; dbg("%s - port %d", __FUNCTION__, port->number); @@ -686,45 +723,12 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp) if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - } - - buf = kmalloc(10, GFP_KERNEL); - if (buf==NULL) - return -ENOMEM; - -#define FISH(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ - b, a, c, d, buf, 1, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]); - -#define SOUP(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ - b, a, c, d, NULL, 0, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); - - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); - - if (priv->type == HX) { - /* HX chip */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); - /* reset upstream data pipes */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); } else { - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); + /* reset upstream data pipes */ + pl2303_vendor_write(8, 0, serial); + pl2303_vendor_write(9, 0, serial); } - kfree(buf); - /* Setup termios */ if (port->tty) { pl2303_set_termios(port, &tmp_termios); diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index d31f5d299989..237a41f6638a 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -35,6 +35,7 @@ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID 0xb000 +#define RATOC_PRODUCT_ID_USB60F 0xb020 #define TRIPP_VENDOR_ID 0x2478 #define TRIPP_PRODUCT_ID 0x2008 @@ -96,10 +97,6 @@ #define ALCOR_VENDOR_ID 0x058F #define ALCOR_PRODUCT_ID 0x9720 -/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */ -#define HUAWEI_VENDOR_ID 0x12d1 -#define HUAWEI_PRODUCT_ID 0x1001 - /* Willcom WS002IN Data Driver (by NetIndex Inc.) */ #define WS002IN_VENDOR_ID 0x11f6 #define WS002IN_PRODUCT_ID 0x2001 @@ -107,3 +104,11 @@ /* Corega CG-USBRS232R Serial Adapter */ #define COREGA_VENDOR_ID 0x07aa #define COREGA_PRODUCT_ID 0x002a + +/* HL HL-340 (ID: 4348:5523) */ +#define HL340_VENDOR_ID 0x4348 +#define HL340_PRODUCT_ID 0x5523 + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index c295d0495f96..4c925e3e8a63 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,7 +1,7 @@ /* USB Driver for Sierra Wireless - Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com> + Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com> IMPORTANT DISCLAIMER: This driver is not commercially supported by Sierra Wireless. Use at your own risk. @@ -14,7 +14,7 @@ Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> */ -#define DRIVER_VERSION "v.1.2.5b" +#define DRIVER_VERSION "v.1.2.7" #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -26,10 +26,12 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/usb/ch9.h> +#define SWIMS_USB_REQUEST_SetPower 0x00 +#define SWIMS_USB_REQUEST_SetNmea 0x07 #define SWIMS_USB_REQUEST_SetMode 0x0B -#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40 -#define SWIMS_USB_INDEX_SetMode 0x0000 +#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40 #define SWIMS_SET_MODE_Modem 0x0001 /* per port private data */ @@ -38,6 +40,8 @@ #define IN_BUFLEN 4096 static int debug; +static int nmea; +static int truinstall = 1; enum devicetype { DEVICE_3_PORT = 0, @@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) int result; dev_dbg(&udev->dev, "%s", "SET POWER STATE\n"); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x00, /* __u8 request */ - 0x40, /* __u8 request type */ - swiState, /* __u16 value */ - 0, /* __u16 index */ - NULL, /* void *data */ - 0, /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ + SWIMS_USB_REQUEST_SetPower, /* __u8 request */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + swiState, /* __u16 value */ + 0, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ return result; } -static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode) +static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode) { int result; dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n"); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetMode, /* __u8 request */ - SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */ - eSocMode, /* __u16 value */ - SWIMS_USB_INDEX_SetMode, /* __u16 index */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + eSWocMode, /* __u16 value */ + 0x0000, /* __u16 index */ NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ return result; } -static int sierra_probe(struct usb_interface *iface, - const struct usb_device_id *id) +static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) +{ + int result; + dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n"); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ + SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ + enable, /* __u16 value */ + 0x0000, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ + return result; +} + +static int sierra_calc_num_ports(struct usb_serial *serial) { int result; + int *num_ports = usb_get_serial_data(serial); + + result = *num_ports; + + if (result) { + kfree(num_ports); + usb_set_serial_data(serial, NULL); + } + + return result; +} + +static int sierra_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + int result = 0; struct usb_device *udev; + int *num_ports; + u8 ifnum; + + num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL); + if (!num_ports) + return -ENOMEM; - udev = usb_get_dev(interface_to_usbdev(iface)); + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + udev = serial->dev; /* Check if in installer mode */ - if (id->driver_info == DEVICE_INSTALLER) { - dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n"); + if (truinstall && id->driver_info == DEVICE_INSTALLER) { + dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n"); result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); - /*We do not want to bind to the device when in installer mode*/ + /* Don't bind to the device when in installer mode */ + kfree(num_ports); return -EIO; - } + } else if (id->driver_info == DEVICE_1_PORT) + *num_ports = 1; + else if (ifnum == 0x99) + *num_ports = 0; + else + *num_ports = 3; + /* + * save off our num_ports info so that we can use it in the + * calc_num_ports callback + */ + usb_set_serial_data(serial, (void *)num_ports); - return usb_serial_probe(iface, id); + return result; } static struct usb_device_id id_table [] = { @@ -104,6 +156,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ + { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ @@ -117,56 +170,29 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */ + { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */ + { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */ + + { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */ + { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */ { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */ { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */ + { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */ { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER}, { } }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_device_id id_table_1port [] = { - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ - { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ - { } -}; - -static struct usb_device_id id_table_3port [] = { - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ - { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/ - - { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ - { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */ - { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ - { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ - { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ - { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ - { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */ - { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */ - { } -}; - static struct usb_driver sierra_driver = { .name = "sierra", - .probe = sierra_probe, + .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, .no_dynamic_id = 1, }; - struct sierra_port_private { spinlock_t lock; /* lock the structure */ int outstanding_urbs; /* number of out urbs in flight */ @@ -188,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; + __u16 interface = 0; dbg("%s", __FUNCTION__); @@ -200,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port) if (portdata->rts_state) val |= 0x02; + /* Determine which port is targeted */ + if (port->bulk_out_endpointAddress == 2) + interface = 0; + else if (port->bulk_out_endpointAddress == 4) + interface = 1; + else if (port->bulk_out_endpointAddress == 5) + interface = 2; + return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + 0x22, 0x21, val, interface, + NULL, 0, USB_CTRL_SET_TIMEOUT); } return 0; @@ -561,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp) portdata->dtr_state = 0; if (serial->dev) { - sierra_send_setup(port); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + sierra_send_setup(port); + mutex_unlock(&serial->disc_mutex); /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) @@ -583,9 +622,13 @@ static int sierra_startup(struct usb_serial *serial) dbg("%s", __FUNCTION__); - /*Set Device mode to D0 */ + /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); + /* Check NMEA and set */ + if (nmea) + sierra_vsc_set_nmea(serial->dev, 1); + /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -646,47 +689,19 @@ static void sierra_shutdown(struct usb_serial *serial) } } -static struct usb_serial_driver sierra_1port_device = { +static struct usb_serial_driver sierra_device = { .driver = { .owner = THIS_MODULE, .name = "sierra1", }, - .description = "Sierra USB modem (1 port)", - .id_table = id_table_1port, - .usb_driver = &sierra_driver, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = sierra_open, - .close = sierra_close, - .write = sierra_write, - .write_room = sierra_write_room, - .chars_in_buffer = sierra_chars_in_buffer, - .throttle = sierra_rx_throttle, - .unthrottle = sierra_rx_unthrottle, - .ioctl = sierra_ioctl, - .set_termios = sierra_set_termios, - .break_ctl = sierra_break_ctl, - .tiocmget = sierra_tiocmget, - .tiocmset = sierra_tiocmset, - .attach = sierra_startup, - .shutdown = sierra_shutdown, - .read_int_callback = sierra_instat_callback, -}; - -static struct usb_serial_driver sierra_3port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sierra3", - }, - .description = "Sierra USB modem (3 port)", - .id_table = id_table_3port, + .description = "Sierra USB modem", + .id_table = id_table, .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 3, - .num_bulk_out = 3, - .num_ports = 3, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .calc_num_ports = sierra_calc_num_ports, + .probe = sierra_probe, .open = sierra_open, .close = sierra_close, .write = sierra_write, @@ -708,12 +723,9 @@ static struct usb_serial_driver sierra_3port_device = { static int __init sierra_init(void) { int retval; - retval = usb_serial_register(&sierra_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_serial_register(&sierra_3port_device); + retval = usb_serial_register(&sierra_device); if (retval) - goto failed_3port_device_register; + goto failed_device_register; retval = usb_register(&sierra_driver); @@ -725,18 +737,15 @@ static int __init sierra_init(void) return 0; failed_driver_register: - usb_serial_deregister(&sierra_3port_device); -failed_3port_device_register: - usb_serial_deregister(&sierra_1port_device); -failed_1port_device_register: + usb_serial_deregister(&sierra_device); +failed_device_register: return retval; } static void __exit sierra_exit(void) { usb_deregister (&sierra_driver); - usb_serial_deregister(&sierra_1port_device); - usb_serial_deregister(&sierra_3port_device); + usb_serial_deregister(&sierra_device); } module_init(sierra_init); @@ -747,6 +756,12 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); +module_param(truinstall, bool, 0); +MODULE_PARM_DESC(truinstall, "TRU-Install support"); + +module_param(nmea, bool, 0); +MODULE_PARM_DESC(nmea, "NMEA streaming"); + #ifdef CONFIG_USB_DEBUG module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 1f0149495fb4..b517f93352ec 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -80,6 +80,7 @@ #include <linux/ioctl.h> #include <linux/serial.h> #include <linux/circ_buf.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #include <linux/usb.h> @@ -139,7 +140,7 @@ struct ti_port { }; struct ti_device { - struct semaphore td_open_close_sem; + struct mutex td_open_close_lock; int td_open_port_count; struct usb_serial *td_serial; int td_is_3410; @@ -424,7 +425,7 @@ static int ti_startup(struct usb_serial *serial) dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } - sema_init(&tdev->td_open_close_sem, 1); + mutex_init(&tdev->td_open_close_lock); tdev->td_serial = serial; usb_set_serial_data(serial, tdev); @@ -547,7 +548,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) tdev = tport->tp_tdev; /* only one open on any port on a device at a time */ - if (down_interruptible(&tdev->td_open_close_sem)) + if (mutex_lock_interruptible(&tdev->td_open_close_lock)) return -ERESTARTSYS; if (port->tty) @@ -568,7 +569,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) if (!urb) { dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__); status = -EINVAL; - goto up_sem; + goto release_lock; } urb->complete = ti_interrupt_callback; urb->context = tdev; @@ -576,11 +577,11 @@ static int ti_open(struct usb_serial_port *port, struct file *file) status = usb_submit_urb(urb, GFP_KERNEL); if (status) { dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status); - goto up_sem; + goto release_lock; } } - ti_set_termios(port, NULL); + ti_set_termios(port, port->tty->termios); dbg("%s - sending TI_OPEN_PORT", __FUNCTION__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -617,7 +618,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file) usb_clear_halt(dev, port->write_urb->pipe); usb_clear_halt(dev, port->read_urb->pipe); - ti_set_termios(port, NULL); + ti_set_termios(port, port->tty->termios); dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -656,13 +657,13 @@ static int ti_open(struct usb_serial_port *port, struct file *file) tport->tp_is_open = 1; ++tdev->td_open_port_count; - goto up_sem; + goto release_lock; unlink_int_urb: if (tdev->td_open_port_count == 0) usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -up_sem: - up(&tdev->td_open_close_sem); +release_lock: + mutex_unlock(&tdev->td_open_close_lock); dbg("%s - exit %d", __FUNCTION__, status); return status; } @@ -674,7 +675,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file) struct ti_port *tport; int port_number; int status; - int do_up; + int do_unlock; dbg("%s - port %d", __FUNCTION__, port->number); @@ -699,16 +700,16 @@ static void ti_close(struct usb_serial_port *port, struct file *file) if (status) dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status); - /* if down is interrupted, continue anyway */ - do_up = !down_interruptible(&tdev->td_open_close_sem); + /* if mutex_lock is interrupted, continue anyway */ + do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); --tport->tp_tdev->td_open_port_count; if (tport->tp_tdev->td_open_port_count <= 0) { /* last port is closed, shut down interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); tport->tp_tdev->td_open_port_count = 0; } - if (do_up) - up(&tdev->td_open_close_sem); + if (do_unlock) + mutex_unlock(&tdev->td_open_close_lock); dbg("%s - exit", __FUNCTION__); } @@ -896,24 +897,11 @@ static void ti_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!tty || !tty->termios) { - dbg("%s - no tty or termios", __FUNCTION__); - return; - } - cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; - if (old_termios && cflag == old_termios->c_cflag - && iflag == old_termios->c_iflag) { - dbg("%s - nothing to change", __FUNCTION__); - return; - } - - dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag); - - if (old_termios) - dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag); + dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag); + dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag); if (tport == NULL) return; @@ -947,6 +935,9 @@ static void ti_set_termios(struct usb_serial_port *port, break; } + /* CMSPAR isn't supported by this driver */ + tty->termios->c_cflag &= ~CMSPAR; + if (cflag & PARENB) { if (cflag & PARODD) { config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; @@ -989,12 +980,17 @@ static void ti_set_termios(struct usb_serial_port *port, } baud = tty_get_baud_rate(tty); - if (!baud) baud = 9600; + if (!baud) + baud = 9600; if (tport->tp_tdev->td_is_3410) config->wBaudRate = (__u16)((923077 + baud/2) / baud); else config->wBaudRate = (__u16)((461538 + baud/2) / baud); + /* FIXME: Should calculate resulting baud here and report it back */ + if ((cflag & CBAUD) != B0) + tty_encode_baud_rate(tty, baud, baud); + dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", __FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); @@ -1497,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) struct ti_device *tdev = tport->tp_tdev; struct usb_serial_port *port = tport->tp_port; wait_queue_t wait; - unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); - spin_lock_irqsave(&tport->tp_lock, flags); + spin_lock_irq(&tport->tp_lock); /* wait for data to drain from the buffer */ tdev->td_urb_error = 0; @@ -1512,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) if (ti_buf_data_avail(tport->tp_write_buf) == 0 || timeout == 0 || signal_pending(current) || tdev->td_urb_error - || !usb_get_intfdata(port->serial->interface)) /* disconnect */ + || port->serial->disconnected) /* disconnect */ break; - spin_unlock_irqrestore(&tport->tp_lock, flags); + spin_unlock_irq(&tport->tp_lock); timeout = schedule_timeout(timeout); - spin_lock_irqsave(&tport->tp_lock, flags); + spin_lock_irq(&tport->tp_lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&tport->tp_write_wait, &wait); @@ -1525,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) if (flush) ti_buf_clear(tport->tp_write_buf); - spin_unlock_irqrestore(&tport->tp_lock, flags); + spin_unlock_irq(&tport->tp_lock); + mutex_lock(&port->serial->disc_mutex); /* wait for data to drain from the device */ /* wait for empty tx register, plus 20 ms */ timeout += jiffies; tport->tp_lsr &= ~TI_LSR_TX_EMPTY; while ((long)(jiffies - timeout) < 0 && !signal_pending(current) && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error - && usb_get_intfdata(port->serial->interface)) { /* not disconnected */ + && !port->serial->disconnected) { if (ti_get_lsr(tport)) break; + mutex_unlock(&port->serial->disc_mutex); msleep_interruptible(20); + mutex_lock(&port->serial->disc_mutex); } + mutex_unlock(&port->serial->disc_mutex); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 497e29a700ca..3ce98e8d7bce 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp) goto bailout_mutex_unlock; } + retval = usb_autopm_get_interface(serial->interface); + if (retval) + goto bailout_module_put; /* only call the device specific open if this * is the first time the port is opened */ retval = serial->type->open(port, filp); if (retval) - goto bailout_module_put; + goto bailout_interface_put; } mutex_unlock(&port->mutex); return 0; +bailout_interface_put: + usb_autopm_put_interface(serial->interface); bailout_module_put: module_put(serial->type->driver.owner); bailout_mutex_unlock: @@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp) } --port->open_count; - if (port->open_count == 0) { + if (port->open_count == 0) /* only call the device specific close if this * port is being closed by the last owner */ port->serial->type->close(port, filp); + if (port->open_count == (port->console? 1 : 0)) { if (port->tty) { if (port->tty->driver_data) port->tty->driver_data = NULL; port->tty = NULL; } + } + if (port->open_count == 0) { + usb_autopm_put_interface(port->serial->interface); module_put(port->serial->type->driver.owner); } @@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, serial->type = driver; serial->interface = interface; kref_init(&serial->kref); + mutex_init(&serial->disc_mutex); return serial; } @@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface) usb_serial_console_disconnect(serial); dbg ("%s", __FUNCTION__); + mutex_lock(&serial->disc_mutex); usb_set_intfdata (interface, NULL); - if (serial) { - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - if (port->tty) - tty_hangup(port->tty); - kill_traffic(port); - } + /* must set a flag, to signal subdrivers */ + serial->disconnected = 1; + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); } - /* let the last holder of this object - * cause it to be cleaned up */ - usb_serial_put(serial); } + /* let the last holder of this object + * cause it to be cleaned up */ + mutex_unlock(&serial->disc_mutex); + usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } @@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) struct usb_serial_port *port; int i, r = 0; - if (!serial) /* device has been disconnected */ - return 0; - for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) @@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); set_to_generic_if_null(device, shutdown); + set_to_generic_if_null(device, resume); } int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 7ee087fed913..22b3f78a388c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); - /* Try to send shutdown message, if the device is gone, this will just fail. */ - transfer_buffer = kmalloc (0x12, GFP_KERNEL); - if (transfer_buffer) { - usb_control_msg (port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - VISOR_CLOSE_NOTIFICATION, 0xc2, - 0x0000, 0x0000, - transfer_buffer, 0x12, 300); - kfree (transfer_buffer); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Try to send shutdown message, unless the device is gone */ + transfer_buffer = kmalloc (0x12, GFP_KERNEL); + if (transfer_buffer) { + usb_control_msg (port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0), + VISOR_CLOSE_NOTIFICATION, 0xc2, + 0x0000, 0x0000, + transfer_buffer, 0x12, 300); + kfree (transfer_buffer); + } } + mutex_unlock(&port->serial->disc_mutex); if (stats) dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n", diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index ee5dd8b5a713..38726ef3132b 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -610,8 +610,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) if (retval) goto exit; - if (port->tty) - port->tty->low_latency = 1; + port->tty->low_latency = 1; /* send an open port command */ retval = firm_open(port); @@ -659,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) struct list_head *tmp2; dbg("%s - port %d", __FUNCTION__, port->number); - + + mutex_lock(&port->serial->disc_mutex); /* filp is NULL when called from usb_serial_disconnect */ - if (filp && (tty_hung_up_p(filp))) { + if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) { + mutex_unlock(&port->serial->disc_mutex); return; } + mutex_unlock(&port->serial->disc_mutex); port->tty->closing = 1; diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index ee5b42aa5363..187dd1e01093 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -66,7 +66,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf; - int res, partial; + int res; + unsigned int partial; static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS"; US_DEBUGP("Sending UCR-61S2B initialization packet...\n"); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 0db488624ab1..2ae1e8673b19 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -48,7 +48,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/hdreg.h> -#include <linux/ide.h> #include <linux/scatterlist.h> #include <scsi/scsi.h> @@ -110,6 +109,12 @@ #define REG_STATUS 0x80 #define REG_COMMAND 0x80 +/* ATA registers offset definitions */ +#define ATA_REG_ERROR_OFFSET 1 +#define ATA_REG_LCYL_OFFSET 4 +#define ATA_REG_HCYL_OFFSET 5 +#define ATA_REG_STATUS_OFFSET 7 + /* ATA error definitions not in <linux/hdreg.h> */ #define ATA_ERROR_MEDIA_CHANGE 0x20 @@ -360,7 +365,7 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; - unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; + unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET]; if(error & ATA_ERROR_MEDIA_CHANGE) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; @@ -549,8 +554,8 @@ static int isd200_read_regs( struct us_data *us ) retStatus = ISD200_ERROR; } else { memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); - US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", - info->ATARegs[IDE_ERROR_OFFSET]); + US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", + info->ATARegs[ATA_REG_ERROR_OFFSET]); } return retStatus; @@ -892,7 +897,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, break; if (!detect) { - if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) { + if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) { US_DEBUGP(" %s status is still BSY, try again...\n",mstr); } else { US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); @@ -902,12 +907,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* check for BUSY_STAT and */ /* WRERR_STAT (workaround ATA Zip drive) and */ /* ERR_STAT (workaround for Archos CD-ROM) */ - else if (regs[IDE_STATUS_OFFSET] & + else if (regs[ATA_REG_STATUS_OFFSET] & (BUSY_STAT | WRERR_STAT | ERR_STAT )) { US_DEBUGP(" Status indicates it is not ready, try again...\n"); } /* check for DRDY, ATA devices set DRDY after SRST */ - else if (regs[IDE_STATUS_OFFSET] & READY_STAT) { + else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) { US_DEBUGP(" Identified ATA device\n"); info->DeviceFlags |= DF_ATA_DEVICE; info->DeviceHead = master_slave; @@ -916,8 +921,8 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* check Cylinder High/Low to determine if it is an ATAPI device */ - else if ((regs[IDE_HCYL_OFFSET] == 0xEB) && - (regs[IDE_LCYL_OFFSET] == 0x14)) { + else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && + regs[ATA_REG_LCYL_OFFSET] == 0x14) { /* It seems that the RICOH MP6200A CD/RW drive will report itself okay as a @@ -1001,12 +1006,6 @@ static int isd200_manual_enum(struct us_data *us) return(retStatus); } -/* - * We are the last non IDE user of the legacy IDE ident structures - * and we thus want to keep a private copy of this function so the - * driver can be used without the obsolete drivers/ide layer - */ - static void isd200_fix_driveid (struct hd_driveid *id) { #ifndef __LITTLE_ENDIAN diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 6d6108b3993b..fe12737e0e2b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -86,6 +86,14 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, US_SC_8070, US_PR_USBAT, init_usbat_cd, 0), #endif +/* Reported by Grant Grundler <grundler@parisc-linux.org> + * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware. + */ +UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001, + "HP", + "PhotoSmart R707", + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), + /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product) * for USB floppies that need the SINGLE_LUN enforcement. diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index d53bf6945f0c..9b05da6268f7 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -39,12 +39,7 @@ #include <linux/spinlock.h> #ifdef CONFIG_COMPAT -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10) -#include <linux/ioctl32.h> -#define SIS_OLD_CONFIG_COMPAT -#else #define SIS_NEW_CONFIG_COMPAT -#endif #endif /* CONFIG_COMPAT */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) @@ -607,9 +602,6 @@ struct sis_video_info { int haveXGIROM; int registered; int warncount; -#ifdef SIS_OLD_CONFIG_COMPAT - int ioctl32registered; -#endif int sisvga_engine; int hwcursor_size; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 37bd24b8d83b..93ae747440cb 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -5805,9 +5805,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ivideo->pcifunc = PCI_FUNC(pdev->devfn); ivideo->subsysvendor = pdev->subsystem_vendor; ivideo->subsysdevice = pdev->subsystem_device; -#ifdef SIS_OLD_CONFIG_COMPAT - ivideo->ioctl32registered = 0; -#endif #ifndef MODULE if(sisfb_mode_idx == -1) { @@ -6420,30 +6417,6 @@ error_3: vfree(ivideo->bios_abase); ivideo->next = card_list; card_list = ivideo; -#ifdef SIS_OLD_CONFIG_COMPAT - { - int ret; - /* Our ioctls are all "32/64bit compatible" */ - ret = register_ioctl32_conversion(FBIO_ALLOC, NULL); - ret |= register_ioctl32_conversion(FBIO_FREE, NULL); - ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL); - ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL); - ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL); - if(ret) - printk(KERN_ERR - "sisfb: Error registering ioctl32 translations\n"); - else - ivideo->ioctl32registered = 1; - } -#endif - printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n", ivideo->sisfb_accel ? "enabled" : "disabled", ivideo->sisfb_ypan ? @@ -6473,27 +6446,6 @@ static void __devexit sisfb_remove(struct pci_dev *pdev) int registered = ivideo->registered; int modechanged = ivideo->modechanged; -#ifdef SIS_OLD_CONFIG_COMPAT - if(ivideo->ioctl32registered) { - int ret; - ret = unregister_ioctl32_conversion(FBIO_ALLOC); - ret |= unregister_ioctl32_conversion(FBIO_FREE); - ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK); - ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE); - ret |= unregister_ioctl32_conversion(SISFB_GET_INFO); - ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET); - ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET); - ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK); - ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS); - ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE); - ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE); - ret |= unregister_ioctl32_conversion(SISFB_COMMAND); - if(ret) - printk(KERN_ERR - "sisfb: Error unregistering ioctl32 translations\n"); - } -#endif - /* Unmap */ iounmap(ivideo->mmio_vbase); iounmap(ivideo->video_vbase); |