diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index 62f32e7247bc498faf14007b301eb9954aefade4..fab37c46bbca1affc7ff6e108e8a50b88777de4d 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -92,10 +92,7 @@ Technical changes: i2c_get_clientdata(client) instead. * [Interface] Init function should not print anything. Make sure - there is a MODULE_LICENSE() line. MODULE_PARM() is replaced - by module_param(). Note that module_param has a third parameter, - that you should set to 0 by default. See include/linux/moduleparam.h - for details. + there is a MODULE_LICENSE() line. Coding policy: diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 95f77b1dfa117db9693076cb4ba57b8cb6d3fcb6..6cb14f493cd9f05f74ef953564063e8f9f1b82ff 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1,7 +1,7 @@ /* * Architecture-specific unaligned trap handling. * - * Copyright (C) 1999-2002 Hewlett-Packard Co + * Copyright (C) 1999-2002, 2004 Hewlett-Packard Co * Stephane Eranian <eranian@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com> * @@ -1328,7 +1328,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) * handler into reading an arbitrary kernel addresses... */ if (!user_mode(regs)) - eh = SEARCH_EXCEPTION_TABLE(regs); + eh = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri); if (user_mode(regs) || eh) { if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0) goto force_sigbus; diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c index 7f7955395173d5ec446699e4ca5efc40001c6bac..58ef7a74601235d56d49fea66267fe0d7c748644 100644 --- a/arch/ia64/mm/extable.c +++ b/arch/ia64/mm/extable.c @@ -1,7 +1,7 @@ /* * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * - * Copyright (C) 1998, 1999, 2001-2002 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001-2002, 2004 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> */ @@ -10,9 +10,51 @@ #include <asm/uaccess.h> #include <asm/module.h> -void sort_extable(struct exception_table_entry *start, - struct exception_table_entry *finish) +static inline int +compare_entries (struct exception_table_entry *l, struct exception_table_entry *r) { + u64 lip = (u64) &l->addr + l->addr; + u64 rip = (u64) &r->addr + r->addr; + + if (lip < rip) + return -1; + if (lip == rip) + return 0; + else + return 1; +} + +static inline void +swap_entries (struct exception_table_entry *l, struct exception_table_entry *r) +{ + u64 delta = (u64) r - (u64) l; + struct exception_table_entry tmp; + + tmp = *l; + l->addr = r->addr + delta; + l->cont = r->cont + delta; + r->addr = tmp.addr - delta; + r->cont = tmp.cont - delta; +} + +/* + * Sort the exception table. It's usually already sorted, but there may be unordered + * entries due to multiple text sections (such as the .init text section). Note that the + * exception-table-entries contain location-relative addresses, which requires a bit of + * care during sorting to avoid overflows in the offset members (e.g., it would not be + * safe to make a temporary copy of an exception-table entry on the stack, because the + * stack may be more than 2GB away from the exception-table). + */ +void +sort_extable (struct exception_table_entry *start, struct exception_table_entry *finish) +{ + struct exception_table_entry *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) + /* start .. p-1 is sorted; push p down to it's proper place */ + for (q = p; q > start && compare_entries(&q[0], &q[-1]) < 0; --q) + swap_entries(&q[0], &q[-1]); } const struct exception_table_entry * diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index fa66ec8b4cfb4beb8f7ab1517f47b91ecf834645..9584a1b2248ab54e943fa78634439d42848d3b33 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -58,7 +58,7 @@ mapped_kernel_page_is_present (unsigned long address) if (pgd_none(*pgd) || pgd_bad(*pgd)) return 0; - pmd = pmd_offset(pgd,address); + pmd = pmd_offset(pgd, address); if (pmd_none(*pmd) || pmd_bad(*pmd)) return 0; diff --git a/arch/x86_64/mm/extable.c b/arch/x86_64/mm/extable.c index 39f7d6df69785ee515c8b551865bc6d2e2ec876c..7e039db623a036a187012c120f2dc9cee34708da 100644 --- a/arch/x86_64/mm/extable.c +++ b/arch/x86_64/mm/extable.c @@ -55,5 +55,4 @@ void sort_extable(struct exception_table_entry *start, } } } while (change != 0); - return 0; } diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c index 37f31b397d7b600bbdb73b62170372be72207587..2f909cd0d65a9b9f0f047b21d99a56cc0d283bc7 100644 --- a/arch/x86_64/mm/k8topology.c +++ b/arch/x86_64/mm/k8topology.c @@ -75,7 +75,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) continue; } if (nodeid >= numnodes) { - printk("Ignoring excess node %d (%x:%x)\n", nodeid, + printk("Ignoring excess node %d (%lx:%lx)\n", nodeid, base, limit); continue; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 25ba41b0f6a7f28c0c1bb8a0c30f8b1470e823c6..f2b73f078eef6103e36fce6c6ad9ed497c5c5597 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -868,7 +868,7 @@ int cpufreq_update_policy(unsigned int cpu) down(&data->lock); memcpy(&policy, - &data, + data, sizeof(struct cpufreq_policy)); policy.min = data->user_policy.min; policy.max = data->user_policy.max; diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index 8db6be015a38878961bc6b7a9c033bd28887b88b..1f0441e42d6ba2c4c67023d07d1f8dcccd9543b1 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -67,12 +67,13 @@ static struct adapter_parm adapter_parm[] = { .getsda = { 0x40, STAT, 1 }, .getscl = { 0x08, STAT, 1 }, }, - /* type 4: ADM 1032 evaluation board */ + /* type 4: ADM1025 and ADM1032 evaluation boards */ { .setsda = { 0x02, DATA, 1 }, .setscl = { 0x01, DATA, 1 }, .getsda = { 0x10, STAT, 1 }, - .init = { 0xf0, DATA, 0 }, + .init = { 0xf0, DATA, 0 }, /* ADM1025 doesn't need this, + but it doesn't hurt */ }, }; @@ -84,4 +85,4 @@ MODULE_PARM_DESC(type, " 1 = home brew teletext adapter\n" " 2 = Velleman K8000 adapter\n" " 3 = ELV adapter\n" - " 4 = ADM 1032 evalulation board\n"); + " 4 = ADM1025 and ADM1032 evaluation boards\n"); diff --git a/drivers/i2c/busses/i2c-philips-par.c b/drivers/i2c/busses/i2c-philips-par.c index 583efdb6001f55da57618e1ef193dad79d76e10d..f1bbb148e11a1b0be4635d13a5fe50692b548ba5 100644 --- a/drivers/i2c/busses/i2c-philips-par.c +++ b/drivers/i2c/busses/i2c-philips-par.c @@ -184,8 +184,8 @@ static void i2c_parport_attach (struct parport *port) return; } /* reset hardware to sane state */ - bit_lp_setsda(port, 1); - bit_lp_setscl(port, 1); + adapter->bit_lp_data.setsda(port, 1); + adapter->bit_lp_data.setscl(port, 1); parport_release(adapter->pdev); if (i2c_bit_add_bus(&adapter->adapter) < 0) { diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 1fbaac9d80d985882b5d46f91bf54d2e3269dfa5..c0aeaba29467f5b39905b600d91cf9b3f0eb979b 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -68,6 +68,9 @@ struct sd { #define SMBSLVEVT (0xA + piix4_smba) #define SMBSLVDAT (0xC + piix4_smba) +/* count for request_region */ +#define SMBIOSIZE 8 + /* PCI Address Constants */ #define SMBBA 0x090 #define SMBHSTCFG 0x0D2 @@ -112,14 +115,13 @@ MODULE_PARM_DESC(fix_hstcfg, static int piix4_transaction(void); - static unsigned short piix4_smba = 0; static struct i2c_adapter piix4_adapter; /* * Get DMI information. */ -static int ibm_dmi_probe(void) +static int __devinit ibm_dmi_probe(void) { #ifdef CONFIG_X86 extern int is_unsafe_smbus; @@ -129,9 +131,9 @@ static int ibm_dmi_probe(void) #endif } -static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) +static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, + const struct pci_device_id *id) { - int error_return = 0; unsigned char temp; /* match up the function */ @@ -144,8 +146,7 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module " "may corrupt your serial eeprom! Refusing to load " "module!\n"); - error_return = -EPERM; - goto END; + return -EPERM; } /* Determine the address of the SMBus areas */ @@ -163,11 +164,10 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id } } - if (!request_region(piix4_smba, 8, "piix4-smbus")) { + if (!request_region(piix4_smba, SMBIOSIZE, "piix4-smbus")) { dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", piix4_smba); - error_return = -ENODEV; - goto END; + return -ENODEV; } pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); @@ -214,8 +214,9 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id } else { dev_err(&PIIX4_dev->dev, "Host SMBus controller not enabled!\n"); - error_return = -ENODEV; - goto END; + release_region(piix4_smba, SMBIOSIZE); + piix4_smba = 0; + return -ENODEV; } } @@ -231,8 +232,7 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba); -END: - return error_return; + return 0; } /* Another internally used function */ @@ -465,7 +465,8 @@ static struct pci_device_id piix4_ids[] = { { 0, } }; -static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int __devinit piix4_probe(struct pci_dev *dev, + const struct pci_device_id *id) { int retval; @@ -479,17 +480,24 @@ static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id snprintf(piix4_adapter.name, I2C_NAME_SIZE, "SMBus PIIX4 adapter at %04x", piix4_smba); - retval = i2c_add_adapter(&piix4_adapter); + if ((retval = i2c_add_adapter(&piix4_adapter))) { + dev_err(&dev->dev, "Couldn't register adapter!\n"); + release_region(piix4_smba, SMBIOSIZE); + piix4_smba = 0; + } return retval; } static void __devexit piix4_remove(struct pci_dev *dev) { - i2c_del_adapter(&piix4_adapter); + if (piix4_smba) { + i2c_del_adapter(&piix4_adapter); + release_region(piix4_smba, SMBIOSIZE); + piix4_smba = 0; + } } - static struct pci_driver piix4_driver = { .name = "piix4-smbus", .id_table = piix4_ids, @@ -502,15 +510,13 @@ static int __init i2c_piix4_init(void) return pci_module_init(&piix4_driver); } - static void __exit i2c_piix4_exit(void) { pci_unregister_driver(&piix4_driver); - release_region(piix4_smba, 8); } -MODULE_AUTHOR - ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>"); +MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " + "Philip Edelbrock <phil@netroedge.com>"); MODULE_DESCRIPTION("PIIX4 SMBus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index 337f9a32b08e7ad498f119cd992a75adf6f16939..c1488261677ea09d44368098d10cdd0fab1bb69c 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -104,9 +104,9 @@ static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ set(temp_max, LM75_REG_TEMP_OS); set(temp_hyst, LM75_REG_TEMP_HYST); -static DEVICE_ATTR(temp_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp_input, S_IRUGO, show_temp_input, NULL); +static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp_hyst1, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input, NULL); static int lm75_attach_adapter(struct i2c_adapter *adapter) { @@ -197,9 +197,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) lm75_init_client(new_client); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp_hyst); - device_create_file(&new_client->dev, &dev_attr_temp_input); + device_create_file(&new_client->dev, &dev_attr_temp_max1); + device_create_file(&new_client->dev, &dev_attr_temp_hyst1); + device_create_file(&new_client->dev, &dev_attr_temp_input1); return 0; diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index f5925c28383332f27b96e10803365fc57a34b827..e33cd233234da2bf1929b1dc481fc298b128a1e4 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -369,10 +369,10 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) return count; } -static DEVICE_ATTR(temp_input, S_IRUGO, show_temp, NULL) -static DEVICE_ATTR(temp_max, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp, NULL) +static DEVICE_ATTR(temp_max1, S_IRUGO | S_IWUSR, show_temp_over, set_temp_over) -static DEVICE_ATTR(temp_hyst, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(temp_hyst1, S_IRUGO | S_IWUSR, show_temp_hyst, set_temp_hyst) /* 3 Fans */ @@ -678,9 +678,9 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_in_input6); device_create_file(&new_client->dev, &dev_attr_in_min6); device_create_file(&new_client->dev, &dev_attr_in_max6); - device_create_file(&new_client->dev, &dev_attr_temp_input); - device_create_file(&new_client->dev, &dev_attr_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp_hyst); + device_create_file(&new_client->dev, &dev_attr_temp_input1); + device_create_file(&new_client->dev, &dev_attr_temp_max1); + device_create_file(&new_client->dev, &dev_attr_temp_hyst1); device_create_file(&new_client->dev, &dev_attr_fan_input1); device_create_file(&new_client->dev, &dev_attr_fan_min1); device_create_file(&new_client->dev, &dev_attr_fan_div1); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index 6ac26d84e665f898734d8e40060aff7b5e59efa9..36c09df60da6925bdfc81770a8f1b828d9896b7e 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -48,9 +48,6 @@ static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ SENSORS_INSMOD_4(lm85b, lm85c, adm1027, adt7463); -/* Enable debug if true */ -static int lm85debug = 0; - /* The LM85 registers */ #define LM85_REG_IN(nr) (0x20 + (nr)) @@ -802,19 +799,15 @@ int lm85_detect(struct i2c_adapter *adapter, int address, company = lm85_read_value(new_client, LM85_REG_COMPANY); verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); - if (lm85debug) { - printk("lm85: Detecting device at %d,0x%02x with" + dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", i2c_adapter_id(new_client->adapter), new_client->addr, company, verstep); - } /* If auto-detecting, Determine the chip type. */ if (kind <= 0) { - if (lm85debug) { - printk("lm85: Autodetecting device at %d,0x%02x ...\n", + dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", i2c_adapter_id(adapter), address ); - } if( company == LM85_COMPANY_NATIONAL && verstep == LM85_VERSTEP_LM85C ) { kind = lm85c ; @@ -823,8 +816,8 @@ int lm85_detect(struct i2c_adapter *adapter, int address, kind = lm85b ; } else if( company == LM85_COMPANY_NATIONAL && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) { - printk("lm85: Unrecgonized version/stepping 0x%02x" - " Defaulting to LM85.\n", verstep ); + dev_err(&adapter->dev, "Unrecgonized version/stepping 0x%02x" + " Defaulting to LM85.\n", verstep); kind = any_chip ; } else if( company == LM85_COMPANY_ANALOG_DEV && verstep == LM85_VERSTEP_ADM1027 ) { @@ -834,21 +827,19 @@ int lm85_detect(struct i2c_adapter *adapter, int address, kind = adt7463 ; } else if( company == LM85_COMPANY_ANALOG_DEV && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) { - printk("lm85: Unrecgonized version/stepping 0x%02x" - " Defaulting to ADM1027.\n", verstep ); + dev_err(&adapter->dev, "Unrecgonized version/stepping 0x%02x" + " Defaulting to ADM1027.\n", verstep); kind = adm1027 ; } else if( kind == 0 && (verstep & 0xf0) == 0x60) { - printk("lm85: Generic LM85 Version 6 detected\n"); + dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); /* Leave kind as "any_chip" */ } else { - if (lm85debug) { - printk("lm85: Autodetection failed\n"); - } + dev_dbg(&adapter->dev, "Autodetection failed\n"); /* Not an LM85 ... */ if( kind == 0 ) { /* User used force=x,y */ - printk("lm85: Generic LM85 Version 6 not" - " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); + dev_err(&adapter->dev, "Generic LM85 Version 6 not" + " found at %d,0x%02x. Try force_lm85c.\n", + i2c_adapter_id(adapter), address ); } err = 0 ; goto ERROR1; @@ -879,12 +870,10 @@ int lm85_detect(struct i2c_adapter *adapter, int address, data->valid = 0; init_MUTEX(&data->update_lock); - if (lm85debug) { - printk("lm85: Assigning ID %d to %s at %d,0x%02x\n", + dev_dbg(&adapter->dev, "Assigning ID %d to %s at %d,0x%02x\n", new_client->id, new_client->name, i2c_adapter_id(new_client->adapter), new_client->addr); - } /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) @@ -1021,31 +1010,24 @@ void lm85_init_client(struct i2c_client *client) int value; struct lm85_data *data = i2c_get_clientdata(client); - if (lm85debug) { - printk("lm85(%d): Initializing device\n", client->id); - } + dev_dbg(&client->dev, "Initializing device\n"); /* Warn if part was not "READY" */ value = lm85_read_value(client, LM85_REG_CONFIG); - if (lm85debug) { - printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value ); - } + dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); if( value & 0x02 ) { - printk("lm85(%d): Client (%d,0x%02x) config is locked.\n", - client->id, + dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", i2c_adapter_id(client->adapter), client->addr ); }; if( ! (value & 0x04) ) { - printk("lm85(%d): Client (%d,0x%02x) is not ready.\n", - client->id, + dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", i2c_adapter_id(client->adapter), client->addr ); }; if( value & 0x10 && ( data->type == adm1027 || data->type == adt7463 ) ) { - printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. " + dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " "Please report this to the lm85 maintainer.\n", - client->id, i2c_adapter_id(client->adapter), client->addr ); }; @@ -1061,11 +1043,8 @@ void lm85_init_client(struct i2c_client *client) value = lm85_read_value(client, LM85_REG_CONFIG); /* Try to clear LOCK, Set START, save everything else */ value = (value & ~ 0x02) | 0x01 ; - if (lm85debug) { - printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); - } + dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); lm85_write_value(client, LM85_REG_CONFIG, value); - } void lm85_update_client(struct i2c_client *client) @@ -1078,10 +1057,8 @@ void lm85_update_client(struct i2c_client *client) if ( !data->valid || (jiffies - data->last_reading > LM85_DATA_INTERVAL ) ) { /* Things that change quickly */ - - if (lm85debug) { - printk("lm85(%d): Reading sensor values\n", client->id); - } + dev_dbg(&client->dev, "Reading sensor values\n"); + /* Have to read extended bits first to "freeze" the * more significant bits that are read later. */ @@ -1125,10 +1102,8 @@ void lm85_update_client(struct i2c_client *client) if ( !data->valid || (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) { /* Things that don't change often */ + dev_dbg(&client->dev, "Reading config values\n"); - if (lm85debug) { - printk("lm85(%d): Reading config values\n", client->id); - } for (i = 0; i <= 4; ++i) { data->in_min[i] = lm85_read_value(client, LM85_REG_IN_MIN(i)); @@ -1234,8 +1209,6 @@ static void __exit sm_lm85_exit(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, Margit Schubert-While <margitsw@t-online.de>"); MODULE_DESCRIPTION("LM85-B, LM85-C driver"); -MODULE_PARM(lm85debug, "i"); -MODULE_PARM_DESC(lm85debug, "Enable debugging statements"); module_init(sm_lm85_init); module_exit(sm_lm85_exit); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7beca18247b176a2926ffdfd1119a7c74b8ae6df..27a2e91313bd5371ed8bad147353ac5175fcbf4e 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -7,7 +7,7 @@ menu "USB support" # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB tristate "Support for USB" - depends on PCI || SA1111 + depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 99553a58bfaec2475b474005913a3142f53ba0ca..c28626d2e4d4e75eca3113eee7e08b3f7b543a65 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -31,6 +31,7 @@ #include <asm/uaccess.h> #include <asm/byteorder.h> +#include "usb.h" #include "hcd.h" #include "hub.h" @@ -1316,8 +1317,8 @@ int usb_physical_reset_device(struct usb_device *dev) kfree(descriptor); usb_destroy_configuration(dev); - ret = usb_get_device_descriptor(dev); - if (ret < sizeof(dev->descriptor)) { + ret = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); + if (ret != sizeof(dev->descriptor)) { if (ret < 0) err("unable to get device %s descriptor " "(error=%d)", dev->devpath, ret); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 04d08713e2bf430fd57ed0c10903e43c423fdf93..430c5b15f91d4a2ca221837d697fc76a66ba2e6e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -546,10 +546,10 @@ void usb_sg_cancel (struct usb_sg_request *io) * * Gets a USB descriptor. Convenience functions exist to simplify * getting some types of descriptors. Use - * usb_get_device_descriptor() for USB_DT_DEVICE, + * usb_get_device_descriptor() for USB_DT_DEVICE (not exported), * and usb_get_string() or usb_string() for USB_DT_STRING. - * Configuration descriptors (USB_DT_CONFIG) are part of the device - * structure, at least for the current configuration. + * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG) + * are part of the device structure. * In addition to a number of USB-standard descriptors, some * devices also use class-specific or vendor-specific descriptors. * @@ -610,6 +610,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char /** * usb_get_device_descriptor - (re)reads the device descriptor * @dev: the device whose device descriptor is being updated + * @size: how much of the descriptor to read * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, @@ -618,24 +619,35 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char * vendors product and version fields (idVendor, idProduct, and bcdDevice). * That lets device drivers compare against non-byteswapped constants. * - * There's normally no need to use this call, although some devices - * will change their descriptors after events like updating firmware. + * Not exported, only for use by the core. If drivers really want to read + * the device descriptor directly, they can call usb_get_descriptor() with + * type = USB_DT_DEVICE and index = 0. * * This call is synchronous, and may not be used in an interrupt context. * * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_device_descriptor(struct usb_device *dev) +int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) { - int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, - sizeof(dev->descriptor)); + struct usb_device_descriptor *desc; + int ret; + + if (size > sizeof(*desc)) + return -EINVAL; + desc = kmalloc(sizeof(*desc), GFP_NOIO); + if (!desc) + return -ENOMEM; + + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); if (ret >= 0) { - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); + le16_to_cpus(&desc->bcdUSB); + le16_to_cpus(&desc->idVendor); + le16_to_cpus(&desc->idProduct); + le16_to_cpus(&desc->bcdDevice); + memcpy(&dev->descriptor, desc, size); } + kfree(desc); return ret; } @@ -1241,7 +1253,6 @@ EXPORT_SYMBOL(usb_sg_wait); // synchronous control message convenience routines EXPORT_SYMBOL(usb_get_descriptor); -EXPORT_SYMBOL(usb_get_device_descriptor); EXPORT_SYMBOL(usb_get_status); EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 05a7a9f8fa551c944bf8eb112cd4581131181807..e3b10d895a51cab9eb7825c2ef2787c57cf64c44 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -206,12 +206,15 @@ void usb_deregister(struct usb_driver *driver) */ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) { + struct usb_host_config *config = dev->actconfig; int i; - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) - if (dev->actconfig->interface[i]->altsetting[0] + if (!config) + return NULL; + for (i = 0; i < config->desc.bNumInterfaces; i++) + if (config->interface[i]->altsetting[0] .desc.bInterfaceNumber == ifnum) - return dev->actconfig->interface[i]; + return config->interface[i]; return NULL; } @@ -233,14 +236,17 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) struct usb_endpoint_descriptor * usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) { + struct usb_host_config *config = dev->actconfig; int i, k; - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + if (!config) + return NULL; + for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf; struct usb_host_interface *alt; - /* only endpoints in current altseting are active */ - intf = dev->actconfig->interface[i]; + /* only endpoints in current altsetting are active */ + intf = config->interface[i]; alt = intf->altsetting + intf->act_altsetting; for (k = 0; k < alt->desc.bNumEndpoints; k++) @@ -1059,7 +1065,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent) wait_ms(10); /* Let the SET_ADDRESS settle */ /* high and low speed devices don't need this... */ - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); + err = usb_get_device_descriptor(dev, 8); if (err >= 8) break; wait_ms(100); @@ -1079,8 +1085,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent) /* USB device state == addressed ... still not usable */ - err = usb_get_device_descriptor(dev); - if (err < (signed)sizeof(dev->descriptor)) { + err = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); + if (err != (signed)sizeof(dev->descriptor)) { dev_err(&dev->dev, "device descriptor read/all, error %d\n", err); goto fail; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 5f03c160036ac85b9b8439002c4e85bbe9ab9012..ea0336fd58544ccf45b68aa1a8c79f405da9a2c8 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -14,3 +14,6 @@ extern void usb_enable_endpoint (struct usb_device *dev, struct usb_endpoint_descriptor *epd); extern void usb_enable_interface (struct usb_device *dev, struct usb_interface *intf); + +extern int usb_get_device_descriptor(struct usb_device *dev, + unsigned int size); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 77a7eef3647722ce3d8af31960eb0d5306bd9f5a..38e9f6a2a2bf0e4023362f27ead7dd90019d59f8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -3,12 +3,10 @@ # (a) a peripheral controller, and # (b) the gadget driver using it. # -# for 2.5 kbuild, drivers/usb/gadget/Kconfig -# source this at the end of drivers/usb/Kconfig -# -menuconfig USB_GADGET +menu "USB Gadget Support" + +config USB_GADGET tristate "Support for USB Gadgets" - depends on EXPERIMENTAL help USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. @@ -36,12 +34,15 @@ menuconfig USB_GADGET # USB Peripheral Controller Support # choice - prompt "USB Peripheral Controller Support" + prompt "USB Peripheral Controller" depends on USB_GADGET + help + A USB device uses a controller to talk to its host. + Systems should have only one such upstream link. -config USB_NET2280 - tristate "NetChip 2280 USB Peripheral Controller" - depends on PCI && USB_GADGET +config USB_GADGET_NET2280 + boolean "NetChip 2280" + depends on PCI help NetChip 2280 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. @@ -54,21 +55,91 @@ config USB_NET2280 dynamically linked module called "net2280" and force all gadget drivers to also be dynamically linked. +config USB_NET2280 + tristate + depends on USB_GADGET_NET2280 + default USB_GADGET + +config USB_GADGET_PXA2XX + boolean "PXA 2xx or IXP 42x" + depends on ARCH_PXA || ARCH_IXP425 + help + Intel's PXA 2xx series XScale ARM-5TE processors include + an integrated full speed USB 1.1 device controller. The + controller in the IXP 4xx series is register-compatible. + + It has fifteen fixed-function endpoints, as well as endpoint + zero (for control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "pxa2xx_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_PXA2XX + tristate + depends on USB_GADGET_PXA2XX + default USB_GADGET + +# if there's only one gadget driver, using only two bulk endpoints, +# don't waste memory for the other endpoints +config USB_PXA2XX_SMALL + depends on USB_GADGET_PXA2XX + bool + default y if USB_ZERO + default y if USB_ETH + default y if USB_G_SERIAL + +config USB_GADGET_GOKU + boolean "Toshiba TC86C001 'Goku-S'" + depends on PCI + help + The Toshiba TC86C001 is a PCI device which includes controllers + for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI). + + The device controller has three configurable (bulk or interrupt) + endpoints, plus endpoint zero (for control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "goku_udc" and to force all + gadget drivers to also be dynamically linked. + +config USB_GOKU + tristate + depends on USB_GADGET_GOKU + default USB_GADGET + +# this could be built elsewhere (doesn't yet exist) +config USB_GADGET_SA1100 + boolean "SA 1100" + depends on ARCH_SA1100 + help + Intel's SA-1100 is an ARM-4 processor with an integrated + full speed USB 1.1 device controller. + + It has two fixed-function endpoints, as well as endpoint + zero (for control transfers). + +config USB_SA1100 + tristate + depends on USB_GADGET_SA1100 + default USB_GADGET + endchoice + # # USB Gadget Drivers # choice - prompt "USB Gadget Drivers" + tristate "USB Gadget Drivers" depends on USB_GADGET default USB_ETH -# FIXME want a cleaner dependency/config approach for drivers. +# this first set of drivers all depend on bulk-capable hardware. config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" - depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX || USB_SA1100) + depends on EXPERIMENTAL help Gadget Zero is a two-configuration device. It either sinks and sources bulk data; or it loops back a configurable number of @@ -91,26 +162,9 @@ config USB_ZERO Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_zero". -config USB_ZERO_NET2280 - bool - # for now, treat the "dummy" hcd as if it were a net2280 - depends on USB_ZERO && (USB_NET2280 || USB_DUMMY_HCD) - default y - -config USB_ZERO_PXA2XX - bool - depends on USB_ZERO && USB_PXA2XX - default y - -config USB_ZERO_SA1100 - bool - depends on USB_ZERO && USB_SA1100 - default y - - config USB_ETH tristate "Ethernet Gadget" - depends on USB_GADGET && NET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX || USB_SA1100) + depends on NET help This driver implements Ethernet style communication, in either of two ways: @@ -136,26 +190,9 @@ config USB_ETH Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_ether". - -config USB_ETH_NET2280 - bool - # for now, treat the "dummy" hcd as if it were a net2280 - depends on USB_ETH && (USB_NET2280 || USB_DUMMY_HCD) - default y - -config USB_ETH_PXA2XX - bool - depends on USB_ETH && USB_PXA2XX - default y - -config USB_ETH_SA1100 - bool - depends on USB_ETH && USB_SA1100 - default y - config USB_GADGETFS tristate "Gadget Filesystem (EXPERIMENTAL)" - depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX) && EXPERIMENTAL + depends on EXPERIMENTAL help This driver provides a filesystem based API that lets user mode programs implement a single-configuration USB device, including @@ -166,38 +203,44 @@ config USB_GADGETFS Say "y" to link the driver statically, or "m" to build a dynamically linked module called "gadgetfs". -config USB_GADGETFS_NET2280 - bool - # for now, treat the "dummy" hcd as if it were a net2280 - depends on USB_GADGETFS && (USB_NET2280 || USB_DUMMY_HCD) - default y +config USB_FILE_STORAGE + tristate "File-backed Storage Gadget (DEVELOPMENT)" + # we don't support the SA1100 because of its limitations + depends on USB_GADGET_SA1100 = n + help + The File-backed Storage Gadget acts as a USB Mass Storage + disk drive. As its storage repository it can use a regular + file or a block device (in much the same way as the "loop" + device driver), specified as a module parameter. -config USB_GADGETFS_PXA2XX - bool - depends on USB_GADGETFS && USB_PXA2XX - default y + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_file_storage". + +config USB_FILE_STORAGE_TEST + bool "File-backed Storage Gadget test version" + depends on USB_FILE_STORAGE + default n + help + Say "y" to generate the larger testing version of the + File-backed Storage Gadget, useful for probing the + behavior of USB Mass Storage hosts. Not needed for + normal operation. config USB_G_SERIAL - tristate "serial Gadget" - depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX || USB_SA1100) + tristate "Serial Gadget" + help + The Serial Gadget talks to the Linux-USB generic serial driver. -config USB_G_SERIAL_NET2280 - bool - # for now, treat the "dummy" hcd as if it were a net2280 - depends on USB_G_SERIAL && (USB_NET2280 || USB_DUMMY_HCD) - default y + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_serial". -config USB_G_SERIAL_PXA2XX - bool - depends on USB_G_SERIAL && USB_PXA2XX - default y -config USB_G_SERIAL_SA1100 - bool - depends on USB_G_SERIAL && USB_SA1100 - default y +# put drivers that need isochronous transfer support (for audio +# or video class gadget drivers), or specific hardware, here. + +# - none yet endchoice -# endmenuconfig +endmenu diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index dca74c3b1bab9f62c2a558af287bfda85b91af14..8c332a4dee102f81a96e485c135c6e1a0e193ce4 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -2,6 +2,8 @@ # USB peripheral controller drivers # obj-$(CONFIG_USB_NET2280) += net2280.o +obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o +obj-$(CONFIG_USB_GOKU) += goku_udc.o # # USB gadget drivers @@ -10,8 +12,11 @@ g_zero-objs := zero.o usbstring.o g_ether-objs := ether.o usbstring.o g_serial-objs := serial.o usbstring.o gadgetfs-objs := inode.o usbstring.o +g_file_storage-objs := file_storage.o usbstring.o obj-$(CONFIG_USB_ZERO) += g_zero.o 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 + diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 131ee14bc56872214914a0b5f47384cfb47c7520..7d64b7cbe88f16f280ed764a0a767070661c513e 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -122,12 +122,9 @@ struct eth_dev { * * CHIP ... hardware identifier * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP0_MAXPACKET ... controls packetization of control requests * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER * WAKEUP ... if hardware supports remote wakeup AND we will issue the * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * @@ -143,6 +140,9 @@ struct eth_dev { /* #undef on hardware that can't implement CDC */ #define DEV_CONFIG_CDC +/* undef on bus-powered hardware, and #define MAX_USB_POWER */ +#define SELFPOWER + /* * NetChip 2280, PCI based. * @@ -152,11 +152,10 @@ struct eth_dev { * performance note: only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f) * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help. */ -#ifdef CONFIG_USB_ETH_NET2280 +#ifdef CONFIG_USB_GADGET_NET2280 #define CHIP "net2280" #define DEFAULT_QLEN 4 /* has dma chaining */ #define DRIVER_VERSION_NUM 0x0101 -#define EP0_MAXPACKET 64 static const char EP_OUT_NAME [] = "ep-a"; #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep-b"; @@ -164,8 +163,6 @@ static const char EP_IN_NAME [] = "ep-b"; static const char EP_STATUS_NAME [] = "ep-f"; #define EP_STATUS_NUM 3 #define HIGHSPEED -/* specific hardware configs could be bus-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* supports remote wakeup, but this driver doesn't */ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); @@ -186,17 +183,14 @@ static inline void hw_optimize (struct usb_gadget *gadget) * multiple interfaces (or altsettings) aren't usable. so this hardware * can't implement CDC, which needs both capabilities. */ -#ifdef CONFIG_USB_ETH_PXA2XX +#ifdef CONFIG_USB_GADGET_PXA2XX #undef DEV_CONFIG_CDC #define CHIP "pxa2xx" #define DRIVER_VERSION_NUM 0x0103 -#define EP0_MAXPACKET 16 static const char EP_OUT_NAME [] = "ep2out-bulk"; #define EP_OUT_NUM 2 static const char EP_IN_NAME [] = "ep1in-bulk"; #define EP_IN_NUM 1 -/* doesn't support bus-powered operation */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* supports remote wakeup, but this driver doesn't */ /* no hw optimizations to apply */ @@ -209,17 +203,14 @@ static const char EP_IN_NAME [] = "ep1in-bulk"; * can't have a notification endpoint, since there are only the two * bulk-capable ones. the CDC spec allows that. */ -#ifdef CONFIG_USB_ETH_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 #define CHIP "sa1100" #define DRIVER_VERSION_NUM 0x0105 -#define EP0_MAXPACKET 8 static const char EP_OUT_NAME [] = "ep1out-bulk"; #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2in-bulk"; #define EP_IN_NUM 2 // EP_STATUS_NUM is undefined -/* doesn't support bus-powered operation */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* doesn't support remote wakeup? */ /* no hw optimizations to apply */ @@ -231,25 +222,43 @@ static const char EP_IN_NAME [] = "ep2in-bulk"; * * This has three semi-configurable full speed bulk/interrupt endpoints. */ -#ifdef CONFIG_USB_ETH_GOKU +#ifdef CONFIG_USB_GADGET_GOKU #define CHIP "goku" #define DRIVER_VERSION_NUM 0x0106 -#define EP0_MAXPACKET 8 static const char EP_OUT_NAME [] = "ep1-bulk"; #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2-bulk"; #define EP_IN_NUM 2 static const char EP_STATUS_NAME [] = "ep3-bulk"; #define EP_STATUS_NUM 3 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* doesn't support remote wakeup */ #define hw_optimize(g) do {} while (0) #endif +/* + * SuperH UDC: UDC built-in to some Renesas SH processors. + * + * This has three semi-configurable full speed bulk/interrupt endpoints. + * + * Only one configuration and interface is supported. So this hardware + * can't implement CDC. + */ +#ifdef CONFIG_USB_GADGET_SUPERH +#undef DEV_CONFIG_CDC +#define CHIP "superh" +#define DRIVER_VERSION_NUM 0x0107 +static const char EP_OUT_NAME[] = "ep1out-bulk"; +#define EP_OUT_NUM 1 +static const char EP_IN_NAME[] = "ep2in-bulk"; +#define EP_IN_NUM 2 + +#define hw_optimize(g) do {} while (0) +#endif + /*-------------------------------------------------------------------------*/ -#ifndef EP0_MAXPACKET +#ifndef CHIP # error Configure some USB peripheral controller driver! #endif @@ -280,19 +289,15 @@ static const char EP_STATUS_NAME [] = "ep3-bulk"; * hardware that supports remote wakeup defaults to disabling it. */ -#ifndef SELFPOWER -/* default: say we rely on bus power */ -#define SELFPOWER 0 -/* else: - * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER - * - MAX_USB_POWER may be nonzero. - */ -#endif - #ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ +#ifdef SELFPOWER +/* some hosts are confused by 0mA */ +#define MAX_USB_POWER 2 /* mA */ +#else +/* bus powered */ +#error Define your bus power consumption! #endif +#endif /* MAX_USB_POWER */ #ifndef WAKEUP /* default: this driver won't do remote wakeup */ @@ -376,7 +381,7 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); /* * This device advertises one configuration. */ -static const struct usb_device_descriptor +static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, @@ -386,7 +391,6 @@ device_desc = { .bDeviceClass = DEV_CONFIG_CLASS, .bDeviceSubClass = 0, .bDeviceProtocol = 0, - .bMaxPacketSize0 = EP0_MAXPACKET, .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), @@ -396,7 +400,7 @@ device_desc = { .bNumConfigurations = 1, }; -static const struct usb_config_descriptor +static struct usb_config_descriptor eth_config = { .bLength = sizeof eth_config, .bDescriptorType = USB_DT_CONFIG, @@ -409,7 +413,7 @@ eth_config = { #endif .bConfigurationValue = DEV_CONFIG_VALUE, .iConfiguration = STRING_PRODUCT, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, + .bmAttributes = USB_CONFIG_ATT_ONE | WAKEUP, .bMaxPower = (MAX_USB_POWER + 1) / 2, }; @@ -645,7 +649,7 @@ hs_sink_desc = { .bInterval = 1, }; -static const struct usb_qualifier_descriptor +static struct usb_qualifier_descriptor dev_qualifier = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, @@ -653,12 +657,10 @@ dev_qualifier = { .bcdUSB = __constant_cpu_to_le16 (0x0200), .bDeviceClass = DEV_CONFIG_CLASS, - /* assumes ep0 uses the same value for both speeds ... */ - .bMaxPacketSize0 = EP0_MAXPACKET, - .bNumConfigurations = 1, }; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -959,7 +961,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) if (number == dev->config) return 0; -#ifdef CONFIG_USB_ETH_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 if (dev->config && atomic_read (&dev->tx_qlen) != 0) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); @@ -1006,6 +1008,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) /* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */ #define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */ +#define CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 /* optional; 6.3.2 */ #define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */ struct cdc_notification { @@ -1123,6 +1126,8 @@ static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req) /* see section 3.8.2 table 10 of the CDC spec for more ethernet * requests, mostly for filters (multicast, pm) and statistics */ +#define CDC_SEND_ENCAPSULATED_REQUEST 0x00 /* optional */ +#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */ #define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ /* @@ -1188,7 +1193,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); break; -#ifdef CONFIG_USB_ETH_PXA2XX +#ifdef CONFIG_USB_GADGET_PXA2XX /* PXA UDC prevents us from using SET_INTERFACE in normal ways. * And it hides GET_CONFIGURATION and GET_INTERFACE too. */ @@ -1638,7 +1643,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->context = skb; req->complete = tx_complete; -#ifdef CONFIG_USB_ETH_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 /* don't demand zlp (req->zero) support from all hardware */ if ((length % dev->in_ep->maxpacket) == 0) length++; @@ -1770,6 +1775,17 @@ eth_bind (struct usb_gadget *gadget) return -ENODEV; #endif + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; +#ifdef HIGHSPEED + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; +#endif + +#ifdef SELFPOWERED + eth_config.bmAttributes |= USB_CONFIG_ATT_SELFPOWERED; + usb_gadget_set_selfpowered (gadget); +#endif + net = alloc_etherdev (sizeof *dev); if (!net) return status; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c new file mode 100644 index 0000000000000000000000000000000000000000..5c34452c0654e8efa4ae0b1da5e3bfaa1aa9120d --- /dev/null +++ b/drivers/usb/gadget/file_storage.c @@ -0,0 +1,4169 @@ +/* + * file_storage.c -- File-backed USB Storage Gadget, for USB development + * + * Copyright (C) 2003 Alan Stern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * The File-backed Storage Gadget acts as a USB Mass Storage device, + * appearing to the host as a disk drive. In addition to providing an + * example of a genuinely useful gadget driver for a USB device, it also + * illustrates a technique of double-buffering for increased throughput. + * Last but not least, it gives an easy way to probe the behavior of the + * Mass Storage drivers in a USB host. + * + * Backing storage is provided by a regular file or a block device, specified + * by the "file" module parameter. Access can be limited to read-only by + * setting the optional "ro" module parameter. + * + * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), + * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected + * by the optional "transport" module parameter. It also supports the + * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), + * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by + * the optional "protocol" module parameter. For testing purposes the + * gadget will indicate that it has removable media if the optional + * "removable" module parameter is set. In addition, the default Vendor ID, + * Product ID, and release number can be overridden. + * + * There is support for multiple logical units (LUNs), each of which has + * its own backing file. The number of LUNs can be set using the optional + * "luns" module parameter (anywhere from 1 to 8), and the corresponding + * files are specified using comma-separated lists for "file" and "ro". + * The default number of LUNs is taken from the number of "file" elements; + * it is 1 if "file" is not given. If "removable" is not set then a backing + * file must be specified for each LUN. If it is set, then an unspecified + * or empty backing filename means the LUN's medium is not loaded. + * + * Requirements are modest; only a bulk-in and a bulk-out endpoint are + * needed (an interrupt-out endpoint is also needed for CBI). The memory + * requirement amounts to two 16K buffers, size configurable by a parameter. + * Support is included for both full-speed and high-speed operation. + * + * Module options: + * + * file=filename[,filename...] + * Required if "removable" is not set, names of + * the files or block devices used for + * backing storage + * ro=b[,b...] Default false, booleans for read-only access + * luns=N Default N = number of filenames, number of + * LUNs to support + * transport=XXX Default BBB, transport name (CB, CBI, or BBB) + * protocol=YYY Default SCSI, protocol name (RBC, 8020 or + * ATAPI, QIC, UFI, 8070, or SCSI; + * also 1 - 6) + * removable Default false, boolean for removable media + * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID + * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID + * release=0xRRRR Override the USB release number (bcdDevice) + * buflen=N Default N=16384, buffer size used (will be + * rounded down to a multiple of + * PAGE_CACHE_SIZE) + * stall Default determined according to the type of + * USB device controller (usually true), + * boolean to permit the driver to halt + * bulk endpoints + * + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" + * options are available; default values are used for everything else. + * + * The pathnames of the backing files and the ro settings are available in + * the attribute files "file" and "ro" in the lun<n> subdirectory of the + * gadget's sysfs directory. If CONFIG_USB_FILE_STORAGE_TEST and the + * "removable" option are both set, writing to these files will simulate + * ejecting/loading the medium (writing an empty line means eject) and + * adjusting a write-enable tab. Changes to the ro setting are not allowed + * when the medium is loaded. + * + * This gadget driver is heavily based on "Gadget Zero" by David Brownell. + */ + + +/* + * Driver Design + * + * The FSG driver is fairly straightforward. There is a main kernel + * thread that handles most of the work. Interrupt routines field + * callbacks from the controller driver: bulk- and interrupt-request + * completion notifications, endpoint-0 events, and disconnect events. + * Completion events are passed to the main thread by wakeup calls. Many + * ep0 requests are handled at interrupt time, but SetInterface, + * SetConfiguration, and device reset requests are forwarded to the + * thread in the form of "exceptions" using SIGUSR1 signals (since they + * should interrupt any ongoing file I/O operations). + * + * The thread's main routine implements the standard command/data/status + * parts of a SCSI interaction. It and its subroutines are full of tests + * for pending signals/exceptions -- all this polling is necessary since + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an + * indication that the driver really wants to be running in userspace.) + * An important point is that so long as the thread is alive it keeps an + * open reference to the backing file. This will prevent unmounting + * the backing file's underlying filesystem and could cause problems + * during system shutdown, for example. To prevent such problems, the + * thread catches INT, TERM, and KILL signals and converts them into + * an EXIT exception. + * + * In normal operation the main thread is started during the gadget's + * fsg_bind() callback and stopped during fsg_unbind(). But it can also + * exit when it receives a signal, and there's no point leaving the + * gadget running when the thread is dead. So just before the thread + * exits, it deregisters the gadget driver. This makes things a little + * tricky: The driver is deregistered at two places, and the exiting + * thread can indirectly call fsg_unbind() which in turn can tell the + * thread to exit. The first problem is resolved through the use of the + * REGISTERED atomic bitflag; the driver will only be deregistered once. + * The second problem is resolved by having fsg_unbind() check + * fsg->state; it won't try to stop the thread if the state is already + * FSG_STATE_TERMINATED. + * + * To provide maximum throughput, the driver uses a circular pipeline of + * buffer heads (struct fsg_buffhd). In principle the pipeline can be + * arbitrarily long; in practice the benefits don't justify having more + * than 2 stages (i.e., double buffering). But it helps to think of the + * pipeline as being a long one. Each buffer head contains a bulk-in and + * a bulk-out request pointer (since the buffer can be used for both + * output and input -- directions always are given from the host's + * point of view) as well as a pointer to the buffer and various state + * variables. + * + * Use of the pipeline follows a simple protocol. There is a variable + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. + * At any time that buffer head may still be in use from an earlier + * request, so each buffer head has a state variable indicating whether + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the + * buffer head to be EMPTY, filling the buffer either by file I/O or by + * USB I/O (during which the buffer head is BUSY), and marking the buffer + * head FULL when the I/O is complete. Then the buffer will be emptied + * (again possibly by USB I/O, during which it is marked BUSY) and + * finally marked EMPTY again (possibly by a completion routine). + * + * A module parameter tells the driver to avoid stalling the bulk + * endpoints wherever the transport specification allows. This is + * necessary for some UDCs like the SuperH, which cannot reliably clear a + * halt on a bulk endpoint. However, under certain circumstances the + * Bulk-only specification requires a stall. In such cases the driver + * will halt the endpoint and set a flag indicating that it should clear + * the halt in software during the next device reset. Hopefully this + * will permit everything to work correctly. + * + * One subtle point concerns sending status-stage responses for ep0 + * requests. Some of these requests, such as device reset, can involve + * interrupting an ongoing file I/O operation, which might take an + * arbitrarily long time. During that delay the host might give up on + * the original ep0 request and issue a new one. When that happens the + * driver should not notify the host about completion of the original + * request, as the host will no longer be waiting for it. So the driver + * assigns to each ep0 request a unique tag, and it keeps track of the + * tag value of the request associated with a long-running exception + * (device-reset, interface-change, or configuration-change). When the + * exception handler is finished, the status-stage response is submitted + * only if the current ep0 request tag is equal to the exception request + * tag. Thus only the most recently received ep0 request will get a + * status-stage response. + * + * Warning: This driver source file is too long. It ought to be split up + * into a header file plus about 3 separate .c files, to handle the details + * of the Gadget, USB Mass Storage, and SCSI protocols. + */ + + +#undef DEBUG +#undef VERBOSE +#undef DUMP_MSGS + +#include <linux/config.h> + +#include <asm/system.h> +#include <asm/uaccess.h> + +#include <linux/bitops.h> +#include <linux/blkdev.h> +#include <linux/compiler.h> +#include <linux/completion.h> +#include <linux/dcache.h> +#include <linux/device.h> +#include <linux/fcntl.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/limits.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/pagemap.h> +#include <linux/rwsem.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/uts.h> +#include <linux/version.h> +#include <linux/wait.h> + +#include <linux/usb_ch9.h> +#include <linux/usb_gadget.h> + + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_DESC "File-backed Storage Gadget" +#define DRIVER_NAME "g_file_storage" +#define DRIVER_VERSION "14 January 2004" + +static const char longname[] = DRIVER_DESC; +static const char shortname[] = DRIVER_NAME; + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("Dual BSD/GPL"); + +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. */ +#define DRIVER_VENDOR_ID 0x0525 // NetChip +#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget + + +/*-------------------------------------------------------------------------*/ + +/* + * Hardware-specific configuration, controlled by which device + * controller driver was configured. + * + * CHIP ... hardware identifier + * DRIVER_VERSION_NUM ... alerts the host side driver to differences + * EP_*_NAME ... which endpoints do we use for which purpose? + * EP_*_NUM ... numbers for them (often limited by hardware) + * FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep + * FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep + * HIGHSPEED ... define if ep0 and descriptors need high speed support + * MAX_USB_POWER ... define if we use other than 100 mA bus current + * SELFPOWER ... if we can run on bus power, zero + * NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them + */ + + +/* + * NetChip 2280, PCI based. + * + * This has half a dozen configurable endpoints, four with dedicated + * DMA channels to manage their FIFOs. It supports high speed. + * Those endpoints can be arranged in any desired configuration. + */ +#ifdef CONFIG_USB_GADGET_NET2280 +#define CHIP "net2280" +#define DRIVER_VERSION_NUM 0x0201 +static const char EP_BULK_IN_NAME[] = "ep-a"; +#define EP_BULK_IN_NUM 1 +#define FS_BULK_IN_MAXPACKET 64 +static const char EP_BULK_OUT_NAME[] = "ep-b"; +#define EP_BULK_OUT_NUM 2 +#define FS_BULK_OUT_MAXPACKET 64 +static const char EP_INTR_IN_NAME[] = "ep-e"; +#define EP_INTR_IN_NUM 5 +#define HIGHSPEED +#endif + + +/* + * Dummy_hcd, software-based loopback controller. + * + * This imitates the abilities of the NetChip 2280, so we will use + * the same configuration. + */ +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define CHIP "dummy" +#define DRIVER_VERSION_NUM 0x0202 +static const char EP_BULK_IN_NAME[] = "ep-a"; +#define EP_BULK_IN_NUM 1 +#define FS_BULK_IN_MAXPACKET 64 +static const char EP_BULK_OUT_NAME[] = "ep-b"; +#define EP_BULK_OUT_NUM 2 +#define FS_BULK_OUT_MAXPACKET 64 +static const char EP_INTR_IN_NAME[] = "ep-e"; +#define EP_INTR_IN_NUM 5 +#define HIGHSPEED +#endif + + +/* + * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. + * + * This has fifteen fixed-function full speed endpoints, and it + * can support all USB transfer types. + * + * These supports three or four configurations, with fixed numbers. + * The hardware interprets SET_INTERFACE, net effect is that you + * can't use altsettings or reset the interfaces independently. + * So stick to a single interface. + */ +#ifdef CONFIG_USB_GADGET_PXA2XX +#define CHIP "pxa2xx" +#define DRIVER_VERSION_NUM 0x0203 +static const char EP_BULK_IN_NAME[] = "ep1in-bulk"; +#define EP_BULK_IN_NUM 1 +#define FS_BULK_IN_MAXPACKET 64 +static const char EP_BULK_OUT_NAME[] = "ep2out-bulk"; +#define EP_BULK_OUT_NUM 2 +#define FS_BULK_OUT_MAXPACKET 64 +static const char EP_INTR_IN_NAME[] = "ep6in-bulk"; +#define EP_INTR_IN_NUM 6 +#endif + + +/* + * SuperH UDC: UDC built-in to some Renesas SH processors. + * + * This has three fixed-function full speed bulk/interrupt endpoints. + * + * Only one configuration and interface is supported (SET_CONFIGURATION + * and SET_INTERFACE are handled completely by the hardware). + */ +#ifdef CONFIG_USB_GADGET_SUPERH +#define CHIP "superh" +#define DRIVER_VERSION_NUM 0x0205 +static const char EP_BULK_IN_NAME[] = "ep2in-bulk"; +#define EP_BULK_IN_NUM 2 +#define FS_BULK_IN_MAXPACKET 64 +static const char EP_BULK_OUT_NAME[] = "ep1out-bulk"; +#define EP_BULK_OUT_NUM 1 +#define FS_BULK_OUT_MAXPACKET 64 +static const char EP_INTR_IN_NAME[] = "ep3in-bulk"; +#define EP_INTR_IN_NUM 3 +#define NO_BULK_STALL +#endif + + +/* + * Toshiba TC86C001 ("Goku-S") UDC + * + * This has three semi-configurable full speed bulk/interrupt endpoints. + */ +#ifdef CONFIG_USB_GADGET_GOKU +#define CHIP "goku" +#define DRIVER_VERSION_NUM 0x0206 +static const char EP_BULK_OUT_NAME [] = "ep1-bulk"; +#define EP_BULK_OUT_NUM 1 +#define FS_BULK_IN_MAXPACKET 64 +static const char EP_BULK_IN_NAME [] = "ep2-bulk"; +#define EP_BULK_IN_NUM 2 +#define FS_BULK_OUT_MAXPACKET 64 +static const char EP_INTR_IN_NAME [] = "ep3-bulk"; +#define EP_INTR_IN_NUM 3 +#endif + + +/*-------------------------------------------------------------------------*/ + +#ifndef CHIP +# error Configure some USB peripheral controller driver! +#endif + +/* Power usage is config specific. + * Hardware that supports remote wakeup defaults to disabling it. + */ +#ifndef SELFPOWER +/* default: say we're self-powered */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* else: + * - SELFPOWER value must be zero + * - MAX_USB_POWER may be nonzero. + */ +#endif + +#ifndef MAX_USB_POWER +/* Any hub supports this steady state bus power consumption */ +#define MAX_USB_POWER 100 /* mA */ +#endif + +/* We don't support remote wake-up */ + +#ifdef NO_BULK_STALL +#define CAN_STALL 0 +#else +#define CAN_STALL 1 +#endif + + +/*-------------------------------------------------------------------------*/ + +#define xprintk(f,level,fmt,args...) \ + dev_printk(level , &(f)->gadget->dev , fmt , ## args) +#define yprintk(l,level,fmt,args...) \ + dev_printk(level , &(l)->dev , fmt , ## args) + +#ifdef DEBUG +#define DBG(fsg,fmt,args...) \ + xprintk(fsg , KERN_DEBUG , fmt , ## args) +#define LDBG(lun,fmt,args...) \ + yprintk(lun , KERN_DEBUG , fmt , ## args) +#define MDBG(fmt,args...) \ + printk(KERN_DEBUG DRIVER_NAME ": " fmt, ## args) +#else +#define DBG(fsg,fmt,args...) \ + do { } while (0) +#define LDBG(lun,fmt,args...) \ + do { } while (0) +#define MDBG(fmt,args...) \ + do { } while (0) +#undef VERBOSE +#undef DUMP_MSGS +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG DBG +#define VLDBG LDBG +#else +#define VDBG(fsg,fmt,args...) \ + do { } while (0) +#define VLDBG(lun,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(fsg,fmt,args...) \ + xprintk(fsg , KERN_ERR , fmt , ## args) +#define LERROR(lun,fmt,args...) \ + yprintk(lun , KERN_ERR , fmt , ## args) + +#define WARN(fsg,fmt,args...) \ + xprintk(fsg , KERN_WARNING , fmt , ## args) +#define LWARN(lun,fmt,args...) \ + yprintk(lun , KERN_WARNING , fmt , ## args) + +#define INFO(fsg,fmt,args...) \ + xprintk(fsg , KERN_INFO , fmt , ## args) +#define LINFO(lun,fmt,args...) \ + yprintk(lun , KERN_INFO , fmt , ## args) + +#define MINFO(fmt,args...) \ + printk(KERN_INFO DRIVER_NAME ": " fmt, ## args) + + +/*-------------------------------------------------------------------------*/ + +/* Encapsulate the module parameter settings */ + +#define MAX_LUNS 8 + + /* Arggh! There should be a module_param_array_named macro! */ +static char *file[MAX_LUNS] = {NULL, }; +static int ro[MAX_LUNS] = {0, }; + +static struct { + int num_filenames; + int num_ros; + unsigned int nluns; + + char *transport_parm; + char *protocol_parm; + int removable; + unsigned short vendor; + unsigned short product; + unsigned short release; + unsigned int buflen; + int can_stall; + + int transport_type; + char *transport_name; + int protocol_type; + char *protocol_name; + +} mod_data = { // Default values + .transport_parm = "BBB", + .protocol_parm = "SCSI", + .removable = 0, + .vendor = DRIVER_VENDOR_ID, + .product = DRIVER_PRODUCT_ID, + .release = DRIVER_VERSION_NUM, + .buflen = 16384, + .can_stall = CAN_STALL, + }; + + +module_param_array(file, charp, mod_data.num_filenames, S_IRUGO); +MODULE_PARM_DESC(file, "names of backing files or devices"); + +module_param_array(ro, bool, mod_data.num_ros, S_IRUGO); +MODULE_PARM_DESC(ro, "true to force read-only"); + + +/* In the non-TEST version, only the file and ro module parameters + * are available. */ +#ifdef CONFIG_USB_FILE_STORAGE_TEST + +module_param_named(luns, mod_data.nluns, uint, S_IRUGO); +MODULE_PARM_DESC(luns, "number of LUNs"); + +module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); +MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); + +module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); +MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " + "8070, or SCSI)"); + +module_param_named(removable, mod_data.removable, bool, S_IRUGO); +MODULE_PARM_DESC(removable, "true to simulate removable media"); + +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); +MODULE_PARM_DESC(vendor, "USB Vendor ID"); + +module_param_named(product, mod_data.product, ushort, S_IRUGO); +MODULE_PARM_DESC(product, "USB Product ID"); + +module_param_named(release, mod_data.release, ushort, S_IRUGO); +MODULE_PARM_DESC(release, "USB release number"); + +module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); +MODULE_PARM_DESC(buflen, "I/O buffer size"); + +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); +MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); + +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + + +/*-------------------------------------------------------------------------*/ + +/* USB protocol value = the transport method */ +#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt +#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt +#define USB_PR_BULK 0x50 // Bulk-only + +/* USB subclass value = the protocol encapsulation */ +#define USB_SC_RBC 0x01 // Reduced Block Commands (flash) +#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM) +#define USB_SC_QIC 0x03 // QIC-157 (tape) +#define USB_SC_UFI 0x04 // UFI (floppy) +#define USB_SC_8070 0x05 // SFF-8070i (removable) +#define USB_SC_SCSI 0x06 // Transparent SCSI + +/* Bulk-only data structures */ + +/* Command Block Wrapper */ +struct bulk_cb_wrap { + u32 Signature; // Contains 'USBC' + u32 Tag; // Unique per command id + u32 DataTransferLength; // Size of the data + u8 Flags; // Direction in bit 7 + u8 Lun; // LUN (normally 0) + u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE + u8 CDB[16]; // Command Data Block +}; + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC +#define USB_BULK_IN_FLAG 0x80 + +/* Command Status Wrapper */ +struct bulk_cs_wrap { + u32 Signature; // Should = 'USBS' + u32 Tag; // Same as original command + u32 Residue; // Amount not transferred + u8 Status; // See below +}; + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS' +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +/* Bulk-only class specific requests */ +#define USB_BULK_RESET_REQUEST 0xff +#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe + + +/* CBI Interrupt data structure */ +struct interrupt_data { + u8 bType; + u8 bValue; +}; + +#define CBI_INTERRUPT_DATA_LEN 2 + +/* CBI Accept Device-Specific Command request */ +#define USB_CBI_ADSC_REQUEST 0x00 + + +#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block + +/* SCSI commands that we recognize */ +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1a +#define SC_MODE_SENSE_10 0x5a +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xa8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1d +#define SC_START_STOP_UNIT 0x1b +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2f +#define SC_WRITE_6 0x0a +#define SC_WRITE_10 0x2a +#define SC_WRITE_12 0xaa + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 + +#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + + +/*-------------------------------------------------------------------------*/ + +/* + * These definitions will permit the compiler to avoid generating code for + * parts of the driver that aren't used in the non-TEST version. Even gcc + * can recognize when a test of a constant expression yields a dead code + * path. + * + * Also, in the non-TEST version, open_backing_file() is only used during + * initialization and the sysfs attribute store_xxx routines aren't used + * at all. We will define NORMALLY_INIT to mark them as __init so they + * don't occupy kernel code space unnecessarily. + */ + +#ifdef CONFIG_USB_FILE_STORAGE_TEST + +#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) +#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) +#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) +#define NORMALLY_INIT + +#else + +#define transport_is_bbb() 1 +#define transport_is_cbi() 0 +#define protocol_is_scsi() 1 +#define backing_file_is_open(curlun) 1 +#define NORMALLY_INIT __init + +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + + +struct lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; + + unsigned int ro : 1; + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; + + struct device dev; +}; + +static inline struct lun *dev_to_lun(struct device *dev) +{ + return container_of(dev, struct lun, dev); +} + + +/* Big enough to hold our biggest descriptor */ +#define EP0_BUFSIZE 256 +#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value + +/* Number of buffers we will use. 2 is enough for double-buffering */ +#define NUM_BUFFERS 2 + +enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +struct fsg_buffhd { + void *buf; + dma_addr_t dma; + volatile enum fsg_buffer_state state; + struct fsg_buffhd *next; + + /* The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. + * So we will record the intended request length here. */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; + volatile int inreq_busy; + struct usb_request *outreq; + volatile int outreq_busy; +}; + +enum fsg_state { + FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere + FSG_STATE_DATA_PHASE, + FSG_STATE_STATUS_PHASE, + + FSG_STATE_IDLE = 0, + FSG_STATE_ABORT_BULK_OUT, + FSG_STATE_RESET, + FSG_STATE_INTERFACE_CHANGE, + FSG_STATE_CONFIG_CHANGE, + FSG_STATE_DISCONNECT, + FSG_STATE_EXIT, + FSG_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +struct fsg_dev { + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ + spinlock_t lock; + struct usb_gadget *gadget; + + /* filesem protects: backing files in use */ + struct rw_semaphore filesem; + + struct usb_ep *ep0; // Handy copy of gadget->ep0 + struct usb_request *ep0req; // For control responses + volatile unsigned int ep0_req_tag; + const char *ep0req_name; + + struct usb_request *intreq; // For interrupt responses + volatile int intreq_busy; + struct fsg_buffhd *intr_buffhd; + + unsigned int bulk_out_maxpacket; + enum fsg_state state; // For exception handling + unsigned int exception_req_tag; + + u8 config, new_config; + + unsigned int running : 1; + unsigned int bulk_in_enabled : 1; + unsigned int bulk_out_enabled : 1; + unsigned int intr_in_enabled : 1; + unsigned int phase_error : 1; + unsigned int short_packet_received : 1; + unsigned int bad_lun_okay : 1; + + unsigned long atomic_bitflags; +#define REGISTERED 0 +#define CLEAR_BULK_HALTS 1 + + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; + struct usb_ep *intr_in; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd buffhds[NUM_BUFFERS]; + + wait_queue_head_t thread_wqh; + int thread_wakeup_needed; + struct completion thread_notifier; + int thread_pid; + struct task_struct *thread_task; + sigset_t thread_signal_mask; + + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + unsigned int lun; + u32 residue; + u32 usb_amount_left; + + /* The CB protocol offers no way for a host to know when a command + * has completed. As a result the next command may arrive early, + * and we will still have to handle it. For that reason we need + * a buffer to store new commands when using CB (or CBI, which + * does not oblige a host to wait for command completion either). */ + int cbbuf_cmnd_size; + u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; + + unsigned int nluns; + struct lun *luns; + struct lun *curlun; +}; + +typedef void (*fsg_routine_t)(struct fsg_dev *); + +static int inline exception_in_progress(struct fsg_dev *fsg) +{ + return (fsg->state > FSG_STATE_IDLE); +} + +/* Make bulk-out requests be divisible by the maxpacket size */ +static void inline set_bulk_out_req_length(struct fsg_dev *fsg, + struct fsg_buffhd *bh, unsigned int length) +{ + unsigned int rem; + + bh->bulk_out_intended_length = length; + rem = length % fsg->bulk_out_maxpacket; + if (rem > 0) + length += fsg->bulk_out_maxpacket - rem; + bh->outreq->length = length; +} + +static struct fsg_dev *the_fsg; +static struct usb_gadget_driver fsg_driver; + +static void close_backing_file(struct lun *curlun); +static void close_all_backing_files(struct fsg_dev *fsg); + + +/*-------------------------------------------------------------------------*/ + +#ifdef DUMP_MSGS + +static void dump_msg(struct fsg_dev *fsg, const char *label, + const u8 *buf, unsigned int length) +{ + unsigned int start, num, i; + char line[52], *p; + + if (length >= 512) + return; + DBG(fsg, "%s, length %u:\n", label, length); + + start = 0; + while (length > 0) { + num = min(length, 16u); + p = line; + for (i = 0; i < num; ++i) { + if (i == 8) + *p++ = ' '; + sprintf(p, " %02x", buf[i]); + p += 3; + } + *p = 0; + printk(KERN_DEBUG "%6x: %s\n", start, line); + buf += num; + start += num; + length -= num; + } +} + +static void inline dump_cdb(struct fsg_dev *fsg) +{} + +#else + +static void inline dump_msg(struct fsg_dev *fsg, const char *label, + const u8 *buf, unsigned int length) +{} + +static void inline dump_cdb(struct fsg_dev *fsg) +{ + int i; + char cmdbuf[3*MAX_COMMAND_SIZE + 1]; + + for (i = 0; i < fsg->cmnd_size; ++i) + sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); + VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +} + +#endif /* DUMP_MSGS */ + + +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) +{ + const char *name; + + if (ep == fsg->bulk_in) + name = "bulk-in"; + else if (ep == fsg->bulk_out) + name = "bulk-out"; + else + name = ep->name; + DBG(fsg, "%s set halt\n", name); + return usb_ep_set_halt(ep); +} + + +/*-------------------------------------------------------------------------*/ + +/* Routines for unaligned data access */ + +static u16 inline get_be16(u8 *buf) +{ + return ((u16) buf[0] << 8) | ((u16) buf[1]); +} + +static u32 inline get_be32(u8 *buf) +{ + return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | + ((u32) buf[2] << 8) | ((u32) buf[3]); +} + +static void inline put_be16(u8 *buf, u16 val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static void inline put_be32(u8 *buf, u32 val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. Also the (static) config and interface + * descriptors are adjusted during fsg_bind(). + */ +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIAL 3 + +/* There is only one configuration. */ +#define CONFIG_VALUE 1 + +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, + + /* The next three values can be overridden by module parameters */ + .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), + .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), + .bcdDevice = __constant_cpu_to_le16(DRIVER_VERSION_NUM), + + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIAL, + .bNumConfigurations = 1, +}; + +static struct usb_config_descriptor +config_desc = { + .bLength = sizeof config_desc, + .bDescriptorType = USB_DT_CONFIG, + + /* wTotalLength adjusted during bind() */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_VALUE, + .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER, + .bMaxPower = (MAX_USB_POWER + 1) / 2, +}; + +/* There is only one interface. */ + +static struct usb_interface_descriptor +intf_desc = { + .bLength = sizeof intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, // Adjusted during bind() + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during bind() + .bInterfaceProtocol = USB_PR_BULK, // Adjusted during bind() +}; + +/* Three full-speed endpoint descriptors: bulk-in, bulk-out, + * and interrupt-in. */ + +static const struct usb_endpoint_descriptor +fs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_IN_MAXPACKET), +}; + +static const struct usb_endpoint_descriptor +fs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_BULK_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_OUT_MAXPACKET), +}; + +static const struct usb_endpoint_descriptor +fs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(2), + .bInterval = 32, // frames -> 32 ms +}; + +#ifdef HIGHSPEED + +/* + * USB 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + * + * That means alternate endpoint descriptors (bigger packets) + * and a "device qualifier" ... plus more construction options + * for the config descriptor. + */ +static const struct usb_endpoint_descriptor +hs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static const struct usb_endpoint_descriptor +hs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_BULK_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), + .bInterval = 1, // NAK every 1 uframe +}; + +static const struct usb_endpoint_descriptor +hs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(2), + .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms +}; + +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_PER_INTERFACE, + + .bNumConfigurations = 1, +}; + +/* Maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) + +#else + +/* If there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,fs,hs) fs + +#endif /* !HIGHSPEED */ + + +/* The CBI specification limits the serial string to 12 uppercase hexadecimal + * characters. */ +static char serial[13]; + +/* Static strings, in ISO 8859/1 */ +static struct usb_string strings[] = { + { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_PRODUCT, longname, }, + { STRING_SERIAL, serial, }, + { } // end of list +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, // en-us + .strings = strings, +}; + + +/* + * Config descriptors are handcrafted. They must agree with the code + * that sets configurations and with code managing interfaces and their + * altsettings. They must also handle different speeds and other-speed + * requests. + */ +static int populate_config_buf(enum usb_device_speed speed, + u8 *buf0, u8 type, unsigned index) +{ + u8 *buf = buf0; +#ifdef HIGHSPEED + int hs; +#endif + + if (index > 0) + return -EINVAL; + if (config_desc.wTotalLength > EP0_BUFSIZE) + return -EDOM; + + /* Config (or other speed config) */ + memcpy(buf, &config_desc, USB_DT_CONFIG_SIZE); + buf[1] = type; + buf += USB_DT_CONFIG_SIZE; + + /* Interface */ + memcpy(buf, &intf_desc, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; + + /* The endpoints in the interface (at that speed) */ +#ifdef HIGHSPEED + hs = (speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + if (hs) { + memcpy(buf, &hs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy(buf, &hs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + if (transport_is_cbi()) { + memcpy(buf, &hs_intr_in_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } + } else +#endif + { + memcpy(buf, &fs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy(buf, &fs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + if (transport_is_cbi()) { + memcpy(buf, &fs_intr_in_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } + } + + return buf - buf0; +} + + +/*-------------------------------------------------------------------------*/ + +/* These routines may be called in process context or in_irq */ + +static void wakeup_thread(struct fsg_dev *fsg) +{ + /* Tell the main thread that something has happened */ + fsg->thread_wakeup_needed = 1; + wake_up_all(&fsg->thread_wqh); +} + + +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) +{ + unsigned long flags; + struct task_struct *thread_task; + + /* Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. */ + spin_lock_irqsave(&fsg->lock, flags); + if (fsg->state <= new_state) { + fsg->exception_req_tag = fsg->ep0_req_tag; + fsg->state = new_state; + thread_task = fsg->thread_task; + if (thread_task) + send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task); + } + spin_unlock_irqrestore(&fsg->lock, flags); +} + + +/*-------------------------------------------------------------------------*/ + +/* The disconnect callback and ep0 routines. These always run in_irq, + * except that ep0_queue() is called in the main thread to acknowledge + * completion of various requests: set config, set interface, and + * Bulk-only device reset. */ + +static void fsg_disconnect(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "disconnect or port reset\n"); + raise_exception(fsg, FSG_STATE_DISCONNECT); +} + + +static int ep0_queue(struct fsg_dev *fsg) +{ + int rc; + + rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); + if (rc != 0 && rc != -ESHUTDOWN) { + + /* We can't do much more than wait for a reset */ + WARN(fsg, "error in submission: %s --> %d\n", + fsg->ep0->name, rc); + } + return rc; +} + +static void ep0_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + + if (req->actual > 0) + dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); + if (req->status || req->actual != req->length) + DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, + req->status, req->actual, req->length); + if (req->status == -ECONNRESET) // Request was cancelled + usb_ep_fifo_flush(ep); + + if (req->status == 0 && req->context) + ((fsg_routine_t) (req->context))(fsg); +} + + +/*-------------------------------------------------------------------------*/ + +/* Bulk and interrupt endpoint completion handlers. + * These always run in_irq. */ + +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + + if (req->status || req->actual != req->length) + DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, + req->status, req->actual, req->length); + if (req->status == -ECONNRESET) // Request was cancelled + usb_ep_fifo_flush(ep); + + /* Hold the lock while we update the request and buffer states */ + spin_lock(&fsg->lock); + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + spin_unlock(&fsg->lock); + wakeup_thread(fsg); +} + +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + + dump_msg(fsg, "bulk-out", req->buf, req->actual); + if (req->status || req->actual != bh->bulk_out_intended_length) + DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, + req->status, req->actual, + bh->bulk_out_intended_length); + if (req->status == -ECONNRESET) // Request was cancelled + usb_ep_fifo_flush(ep); + + /* Hold the lock while we update the request and buffer states */ + spin_lock(&fsg->lock); + bh->outreq_busy = 0; + bh->state = BUF_STATE_FULL; + spin_unlock(&fsg->lock); + wakeup_thread(fsg); +} + +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +{ +#ifdef CONFIG_USB_FILE_STORAGE_TEST + struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + + if (req->status || req->actual != req->length) + DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, + req->status, req->actual, req->length); + if (req->status == -ECONNRESET) // Request was cancelled + usb_ep_fifo_flush(ep); + + /* Hold the lock while we update the request and buffer states */ + spin_lock(&fsg->lock); + fsg->intreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + spin_unlock(&fsg->lock); + wakeup_thread(fsg); +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +} + + +/*-------------------------------------------------------------------------*/ + +/* Ep0 class-specific handlers. These always run in_irq. */ + +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ +#ifdef CONFIG_USB_FILE_STORAGE_TEST + struct usb_request *req = fsg->ep0req; + static u8 cbi_reset_cmnd[6] = { + SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; + + /* Error in command transfer? */ + if (req->status || req->length != req->actual || + req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { + + /* Not all controllers allow a protocol stall after + * receiving control-out data, but we'll try anyway. */ + fsg_set_halt(fsg, fsg->ep0); + return; // Wait for reset + } + + /* Is it the special reset command? */ + if (req->actual >= sizeof cbi_reset_cmnd && + memcmp(req->buf, cbi_reset_cmnd, + sizeof cbi_reset_cmnd) == 0) { + + /* Raise an exception to stop the current operation + * and reinitialize our state. */ + DBG(fsg, "cbi reset request\n"); + raise_exception(fsg, FSG_STATE_RESET); + return; + } + + VDBG(fsg, "CB[I] accept device-specific command\n"); + spin_lock(&fsg->lock); + + /* Save the command for later */ + if (fsg->cbbuf_cmnd_size) + WARN(fsg, "CB[I] overwriting previous command\n"); + fsg->cbbuf_cmnd_size = req->actual; + memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); + + spin_unlock(&fsg->lock); + wakeup_thread(fsg); +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +} + + +static int class_setup_req(struct fsg_dev *fsg, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_request *req = fsg->ep0req; + int value = -EOPNOTSUPP; + + if (!fsg->config) + return value; + + /* Handle Bulk-only class-specific requests */ + if (transport_is_bbb()) { + switch (ctrl->bRequest) { + + case USB_BULK_RESET_REQUEST: + if (ctrl->bRequestType != (USB_DIR_OUT | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + + /* Raise an exception to stop the current operation + * and reinitialize our state. */ + DBG(fsg, "bulk reset request\n"); + raise_exception(fsg, FSG_STATE_RESET); + value = DELAYED_STATUS; + break; + + case USB_BULK_GET_MAX_LUN_REQUEST: + if (ctrl->bRequestType != (USB_DIR_IN | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + VDBG(fsg, "get max LUN\n"); + *(u8 *) req->buf = fsg->nluns - 1; + value = min(ctrl->wLength, (u16) 1); + break; + } + } + + /* Handle CBI class-specific requests */ + else { + switch (ctrl->bRequest) { + + case USB_CBI_ADSC_REQUEST: + if (ctrl->bRequestType != (USB_DIR_OUT | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + if (ctrl->wLength > MAX_COMMAND_SIZE) { + value = -EOVERFLOW; + break; + } + value = ctrl->wLength; + fsg->ep0req->context = received_cbi_adsc; + break; + } + } + + if (value == -EOPNOTSUPP) + VDBG(fsg, + "unknown class-specific control req " + "%02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + return value; +} + + +/*-------------------------------------------------------------------------*/ + +/* Ep0 standard request handlers. These always run in_irq. */ + +static int standard_setup_req(struct fsg_dev *fsg, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_request *req = fsg->ep0req; + int value = -EOPNOTSUPP; + + /* Usually this just stores reply data in the pre-allocated ep0 buffer, + * but config change events will also reconfigure hardware. */ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + switch (ctrl->wValue >> 8) { + + case USB_DT_DEVICE: + VDBG(fsg, "get device descriptor\n"); + value = min(ctrl->wLength, (u16) sizeof device_desc); + memcpy(req->buf, &device_desc, value); + break; +#ifdef HIGHSPEED + case USB_DT_DEVICE_QUALIFIER: + VDBG(fsg, "get device qualifier\n"); + value = min(ctrl->wLength, (u16) sizeof dev_qualifier); + memcpy(req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + VDBG(fsg, "get other-speed config descriptor\n"); + goto get_config; +#endif /* HIGHSPEED */ + case USB_DT_CONFIG: + VDBG(fsg, "get configuration descriptor\n"); +#ifdef HIGHSPEED + get_config: +#endif /* HIGHSPEED */ + value = populate_config_buf(fsg->gadget->speed, + req->buf, + ctrl->wValue >> 8, + ctrl->wValue & 0xff); + if (value >= 0) + value = min(ctrl->wLength, (u16) value); + break; + + case USB_DT_STRING: + VDBG(fsg, "get string descriptor\n"); + + /* wIndex == language code */ + value = usb_gadget_get_string(&stringtab, + ctrl->wValue & 0xff, req->buf); + if (value >= 0) + value = min(ctrl->wLength, (u16) value); + break; + } + break; + + /* One config, two speeds */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + VDBG(fsg, "set configuration\n"); + if (ctrl->wValue == CONFIG_VALUE || ctrl->wValue == 0) { + fsg->new_config = ctrl->wValue; + + /* Raise an exception to wipe out previous transaction + * state (queued bufs, etc) and set the new config. */ + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); + value = DELAYED_STATUS; + } + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + VDBG(fsg, "get configuration\n"); + *(u8 *) req->buf = fsg->config; + value = min(ctrl->wLength, (u16) 1); + break; + + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | + USB_RECIP_INTERFACE)) + break; + if (fsg->config && ctrl->wIndex == 0) { + + /* Raise an exception to wipe out previous transaction + * state (queued bufs, etc) and install the new + * interface altsetting. */ + raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); + value = DELAYED_STATUS; + } + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | + USB_RECIP_INTERFACE)) + break; + if (!fsg->config) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + VDBG(fsg, "get interface\n"); + *(u8 *) req->buf = 0; + value = min(ctrl->wLength, (u16) 1); + break; + + default: + VDBG(fsg, + "unknown control req %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + } + + return value; +} + + +static int fsg_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + int rc; + + ++fsg->ep0_req_tag; // Record arrival of a new request + fsg->ep0req->context = NULL; + fsg->ep0req->length = 0; + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); + + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) + rc = class_setup_req(fsg, ctrl); + else + rc = standard_setup_req(fsg, ctrl); + + /* Respond with data/status or defer until later? */ + if (rc >= 0 && rc != DELAYED_STATUS) { + fsg->ep0req->length = rc; + fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? + "ep0-in" : "ep0-out"); + rc = ep0_queue(fsg); + } + + /* Device either stalls (rc < 0) or reports success */ + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +/* All the following routines run in process context */ + + +/* Use this for bulk or interrupt transfers, not ep0 */ +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, + struct usb_request *req, volatile int *pbusy, + volatile enum fsg_buffer_state *state) +{ + int rc; + + if (ep == fsg->bulk_in) + dump_msg(fsg, "bulk-in", req->buf, req->length); + else if (ep == fsg->intr_in) + dump_msg(fsg, "intr-in", req->buf, req->length); + *pbusy = 1; + *state = BUF_STATE_BUSY; + rc = usb_ep_queue(ep, req, GFP_KERNEL); + if (rc != 0) { + *pbusy = 0; + *state = BUF_STATE_EMPTY; + + /* We can't do much more than wait for a reset */ + + /* Note: currently the net2280 driver fails zero-length + * submissions if DMA is enabled. */ + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && + req->length == 0)) + WARN(fsg, "error in submission: %s --> %d\n", + ep->name, rc); + } +} + + +static int sleep_thread(struct fsg_dev *fsg) +{ + int rc; + + /* Wait until a signal arrives or we are woken up */ + rc = wait_event_interruptible(fsg->thread_wqh, + fsg->thread_wakeup_needed); + fsg->thread_wakeup_needed = 0; + return (rc ? -EINTR : 0); +} + + +/*-------------------------------------------------------------------------*/ + +static int do_read(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; + u32 amount_left; + loff_t file_offset, file_offset_tmp; + unsigned int amount; + unsigned int partial_page; + ssize_t nread; + + /* Get the starting Logical Block Address and check that it's + * not too big */ + if (fsg->cmnd[0] == SC_READ_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + else { + lba = get_be32(&fsg->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = don't read from the + * cache), but we don't implement them. */ + if ((fsg->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + file_offset = ((loff_t) lba) << 9; + + /* Carry out the file reads */ + amount_left = fsg->data_size_from_cmnd; + if (unlikely(amount_left == 0)) + return -EIO; // No default reply + + for (;;) { + + /* Figure out how much we need to read: + * Try to read the remaining amount. + * But don't read more than the buffer size. + * And don't try to read past the end of the file. + * Finally, if we're not at a page boundary, don't read past + * the next page. + * If this means reading 0 then we were asked to read past + * the end of file. */ + amount = min((unsigned int) amount_left, mod_data.buflen); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + partial_page = file_offset & (PAGE_CACHE_SIZE - 1); + if (partial_page > 0) + amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - + partial_page); + + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + /* If we were asked to read past the end of file, + * end with an empty buffer. */ + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = file_offset >> 9; + bh->inreq->length = 0; + bh->state = BUF_STATE_FULL; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; + nread = vfs_read(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file read: %d\n", + (int) nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file read: %d/%u\n", + (int) nread, amount); + nread -= (nread & 511); // Round down to a block + } + file_offset += nread; + amount_left -= nread; + fsg->residue -= nread; + bh->inreq->length = nread; + bh->state = BUF_STATE_FULL; + + /* If an error occurred, report it and its position */ + if (nread < amount) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = file_offset >> 9; + break; + } + + if (amount_left == 0) + break; // No more left to read + + /* Send this buffer and go read some more */ + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + } + + return -EIO; // No default reply +} + + +/*-------------------------------------------------------------------------*/ + +static int do_write(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; + u32 amount_left_to_req, amount_left_to_write; + loff_t usb_offset, file_offset, file_offset_tmp; + unsigned int amount; + unsigned int partial_page; + ssize_t nwritten; + int rc; + + if (curlun->ro) { + curlun->sense_data = SS_WRITE_PROTECTED; + return -EINVAL; + } + curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait + + /* Get the starting Logical Block Address and check that it's + * not too big */ + if (fsg->cmnd[0] == SC_WRITE_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + else { + lba = get_be32(&fsg->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = write directly to the + * medium). We don't implement DPO; we implement FUA by + * performing synchronous output. */ + if ((fsg->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + if (fsg->cmnd[1] & 0x08) // FUA + curlun->filp->f_flags |= O_SYNC; + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* Carry out the file writes */ + get_some_more = 1; + file_offset = usb_offset = ((loff_t) lba) << 9; + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; + + while (amount_left_to_write > 0) { + + /* Queue a request for more data from the host */ + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && get_some_more) { + + /* Figure out how much we want to get: + * Try to get the remaining amount. + * But don't get more than the buffer size. + * And don't try to go past the end of the file. + * If we're not at a page boundary, + * don't go past the next page. + * If this means getting 0, then we were asked + * to write past the end of file. + * Finally, round down to a block boundary. */ + amount = min(amount_left_to_req, mod_data.buflen); + amount = min((loff_t) amount, curlun->file_length - + usb_offset); + partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); + if (partial_page > 0) + amount = min(amount, + (unsigned int) PAGE_CACHE_SIZE - partial_page); + + if (amount == 0) { + get_some_more = 0; + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = usb_offset >> 9; + continue; + } + amount -= (amount & 511); + if (amount == 0) { + + /* Why were we were asked to transfer a + * partial block? */ + get_some_more = 0; + continue; + } + + /* Get the next buffer */ + usb_offset += amount; + fsg->usb_amount_left -= amount; + amount_left_to_req -= amount; + if (amount_left_to_req == 0) + get_some_more = 0; + + /* amount is always divisible by 512, hence by + * the bulk-out maxpacket size */ + bh->outreq->length = bh->bulk_out_intended_length = + amount; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + continue; + } + + /* Write the received data to the backing file */ + bh = fsg->next_buffhd_to_drain; + if (bh->state == BUF_STATE_EMPTY && !get_some_more) + break; // We stopped early + if (bh->state == BUF_STATE_FULL) { + fsg->next_buffhd_to_drain = bh->next; + bh->state = BUF_STATE_EMPTY; + + /* Did something go wrong with the transfer? */ + if (bh->outreq->status != 0) { + curlun->sense_data = SS_COMMUNICATION_FAILURE; + curlun->sense_data_info = file_offset >> 9; + break; + } + + amount = bh->outreq->actual; + if (curlun->file_length - file_offset < amount) { + LERROR(curlun, + "write %u @ %llu beyond end %llu\n", + amount, (unsigned long long) file_offset, + (unsigned long long) curlun->file_length); + amount = curlun->file_length - file_offset; + } + + /* Perform the write */ + file_offset_tmp = file_offset; + nwritten = vfs_write(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nwritten); + if (signal_pending(current)) + return -EINTR; // Interrupted! + + if (nwritten < 0) { + LDBG(curlun, "error in file write: %d\n", + (int) nwritten); + nwritten = 0; + } else if (nwritten < amount) { + LDBG(curlun, "partial file write: %d/%u\n", + (int) nwritten, amount); + nwritten -= (nwritten & 511); + // Round down to a block + } + file_offset += nwritten; + amount_left_to_write -= nwritten; + fsg->residue -= nwritten; + + /* If an error occurred, report it and its position */ + if (nwritten < amount) { + curlun->sense_data = SS_WRITE_ERROR; + curlun->sense_data_info = file_offset >> 9; + break; + } + + /* Did the host decide to stop early? */ + if (bh->outreq->actual != bh->outreq->length) { + fsg->short_packet_received = 1; + break; + } + continue; + } + + /* Wait for something to happen */ + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + return -EIO; // No default reply +} + + +/*-------------------------------------------------------------------------*/ + +/* Sync the file data, don't bother with the metadata. + * This code was copied from fs/buffer.c:sys_fdatasync(). */ +static int fsync_sub(struct lun *curlun) +{ + struct file *filp = curlun->filp; + struct inode *inode; + int rc, err; + + if (curlun->ro || !filp) + return 0; + if (!filp->f_op->fsync) + return -EINVAL; + + inode = filp->f_dentry->d_inode; + down(&inode->i_sem); + current->flags |= PF_SYNCWRITE; + rc = filemap_fdatawrite(inode->i_mapping); + err = filp->f_op->fsync(filp, filp->f_dentry, 1); + if (!rc) + rc = err; + err = filemap_fdatawait(inode->i_mapping); + if (!rc) + rc = err; + current->flags &= ~PF_SYNCWRITE; + up(&inode->i_sem); + VLDBG(curlun, "fdatasync -> %d\n", rc); + return rc; +} + +static void fsync_all(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + fsync_sub(&fsg->luns[i]); +} + +static int do_synchronize_cache(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int rc; + + /* We ignore the requested LBA and write out all file's + * dirty data buffers. */ + rc = fsync_sub(curlun); + if (rc) + curlun->sense_data = SS_WRITE_ERROR; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static void invalidate_sub(struct lun *curlun) +{ + struct file *filp = curlun->filp; + struct inode *inode = filp->f_dentry->d_inode; + unsigned long rc; + + rc = invalidate_inode_pages(inode->i_mapping); + VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); +} + +static int do_verify(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + u32 verification_length; + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + loff_t file_offset, file_offset_tmp; + u32 amount_left; + unsigned int amount; + ssize_t nread; + + /* Get the starting Logical Block Address and check that it's + * not too big */ + lba = get_be32(&fsg->cmnd[2]); + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) but we don't implement it. */ + if ((fsg->cmnd[1] & ~0x10) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + verification_length = get_be16(&fsg->cmnd[7]); + if (unlikely(verification_length == 0)) + return -EIO; // No default reply + + /* Prepare to carry out the file verify */ + amount_left = verification_length << 9; + file_offset = ((loff_t) lba) << 9; + + /* Write out all the dirty buffers before invalidating them */ + fsync_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + invalidate_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + /* Just try to read the requested blocks */ + while (amount_left > 0) { + + /* Figure out how much we need to read: + * Try to read the remaining amount, but not more than + * the buffer size. + * And don't try to read past the end of the file. + * If this means reading 0 then we were asked to read + * past the end of file. */ + amount = min((unsigned int) amount_left, mod_data.buflen); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = file_offset >> 9; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; + nread = vfs_read(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file verify: %d\n", + (int) nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file verify: %d/%u\n", + (int) nread, amount); + nread -= (nread & 511); // Round down to a sector + } + if (nread == 0) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = file_offset >> 9; + break; + } + file_offset += nread; + amount_left -= nread; + } + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + u8 *buf = (u8 *) bh->buf; + + static char vendor_id[] = "Linux "; + static char product_id[] = "File-Stor Gadget"; + + if (!fsg->curlun) { // Unsupported LUNs are okay + fsg->bad_lun_okay = 1; + memset(buf, 0, 36); + buf[0] = 0x7f; // Unsupported, no device-type + return 36; + } + + memset(buf, 0, 8); // Non-removable, direct-access device + if (mod_data.removable) + buf[1] = 0x80; + buf[2] = 2; // ANSI SCSI level 2 + buf[3] = 2; // SCSI-2 INQUIRY data format + buf[4] = 31; // Additional length + // No special options + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id, + DRIVER_VERSION_NUM); + return 36; +} + + +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + + /* + * From the SCSI-2 spec., section 7.9 (Unit attention condition): + * + * If a REQUEST SENSE command is received from an initiator + * with a pending unit attention condition (before the target + * generates the contingent allegiance condition), then the + * target shall either: + * a) report any pending sense data and preserve the unit + * attention condition on the logical unit, or, + * b) report the unit attention condition, may discard any + * pending sense data, and clear the unit attention + * condition on the logical unit for that initiator. + * + * FSG normally uses option a); enable this code to use option b). + */ +#if 0 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + } +#endif + + if (!curlun) { // Unsupported LUNs are okay + fsg->bad_lun_okay = 1; + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + sdinfo = 0; + } else { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + } + + memset(buf, 0, 18); + buf[0] = 0x80 | 0x70; // Valid, current error + buf[2] = SK(sd); + put_be32(&buf[3], sdinfo); // Sense information + buf[7] = 18 - 7; // Additional sense length + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + return 18; +} + + +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u32 lba = get_be32(&fsg->cmnd[2]); + int pmi = fsg->cmnd[8]; + u8 *buf = (u8 *) bh->buf; + + /* Check the PMI and LBA fields */ + if (pmi > 1 || (pmi == 0 && lba != 0)) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + put_be32(&buf[0], curlun->num_sectors - 1); // Max logical block + put_be32(&buf[4], 512); // Block length + return 8; +} + + +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + int mscmnd = fsg->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; + int pc, page_code; + int changeable_values, all_pages; + int valid_page = 0; + int len, limit; + + if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + pc = fsg->cmnd[2] >> 6; + page_code = fsg->cmnd[2] & 0x3f; + if (pc == 3) { + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + return -EINVAL; + } + changeable_values = (pc == 1); + all_pages = (page_code == 0x3f); + + /* Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. */ + memset(buf, 0, 8); + if (mscmnd == SC_MODE_SENSE_6) { + buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA + buf += 4; + limit = 255; + } else { // SC_MODE_SENSE_10 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA + buf += 8; + limit = 65535; // Should really be mod_data.buflen + } + + /* No block descriptors */ + + /* The mode pages, in numerical order. The only page we support + * is the Caching page. */ + if (page_code == 0x08 || all_pages) { + valid_page = 1; + buf[0] = 0x08; // Page code + buf[1] = 10; // Page length + memset(buf+2, 0, 10); // None of the fields are changeable + + if (!changeable_values) { + buf[2] = 0x04; // Write cache enable, + // Read cache not disabled + // No cache retention priorities + put_be16(&buf[4], 0xffff); // Don't disable prefetch + // Minimum prefetch = 0 + put_be16(&buf[8], 0xffff); // Maximum prefetch + put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling + } + buf += 12; + } + + /* Check that a valid page was requested and the mode data length + * isn't too long. */ + len = buf - buf0; + if (!valid_page || len > limit) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + /* Store the mode data length */ + if (mscmnd == SC_MODE_SENSE_6) + buf0[0] = len - 1; + else + put_be16(buf0, len - 2); + return len; +} + + +static int do_start_stop(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int loej, start; + + if (!mod_data.removable) { + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } + + // int immed = fsg->cmnd[1] & 0x01; + loej = fsg->cmnd[4] & 0x02; + start = fsg->cmnd[4] & 0x01; + +#ifdef CONFIG_USB_FILE_STORAGE_TEST + if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed + (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + if (!start) { + + /* Are we allowed to unload the media? */ + if (curlun->prevent_medium_removal) { + LDBG(curlun, "unload attempt prevented\n"); + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; + return -EINVAL; + } + if (loej) { // Simulate an unload/eject + up_read(&fsg->filesem); + down_write(&fsg->filesem); + close_backing_file(curlun); + up_write(&fsg->filesem); + down_read(&fsg->filesem); + } + } else { + + /* Our emulation doesn't support mounting; the medium is + * available for use as soon as it is loaded. */ + if (!backing_file_is_open(curlun)) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } + } +#endif + return 0; +} + + +static int do_prevent_allow(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int prevent; + + if (!mod_data.removable) { + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } + + prevent = fsg->cmnd[4] & 0x01; + if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + if (curlun->prevent_medium_removal && !prevent) + fsync_sub(curlun); + curlun->prevent_medium_removal = prevent; + return 0; +} + + +static int do_read_format_capacities(struct fsg_dev *fsg, + struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor + buf += 4; + + put_be32(&buf[0], curlun->num_sectors); // Number of blocks + put_be32(&buf[4], 512); // Block length + buf[4] = 0x02; // Current capacity + return 12; +} + + +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + + /* We don't support MODE SELECT */ + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; +} + + +/*-------------------------------------------------------------------------*/ + +static int halt_bulk_in_endpoint(struct fsg_dev *fsg) +{ + int rc; + + rc = fsg_set_halt(fsg, fsg->bulk_in); + if (rc == -EAGAIN) + VDBG(fsg, "delayed bulk-in endpoint halt\n"); + while (rc != 0) { + if (rc != -EAGAIN) { + WARN(fsg, "usb_ep_set_halt -> %d\n", rc); + rc = 0; + break; + } + + /* Wait for a short time and then try again */ + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(HZ / 10) != 0) + return -EINTR; + rc = usb_ep_set_halt(fsg->bulk_in); + } + return rc; +} + +static int pad_with_zeros(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + u32 nkeep = bh->inreq->length; + u32 nsend; + int rc; + + bh->state = BUF_STATE_EMPTY; // For the first iteration + fsg->usb_amount_left = nkeep + fsg->residue; + while (fsg->usb_amount_left > 0) { + + /* Wait for the next buffer to be free */ + while (bh->state != BUF_STATE_EMPTY) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen); + memset(bh->buf + nkeep, 0, nsend - nkeep); + bh->inreq->length = nsend; + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + bh = fsg->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= nsend; + nkeep = 0; + } + return 0; +} + +static int throw_away_data(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + u32 amount; + int rc; + + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || + fsg->usb_amount_left > 0) { + + /* Throw away the data in a filled buffer */ + if (bh->state == BUF_STATE_FULL) { + bh->state = BUF_STATE_EMPTY; + fsg->next_buffhd_to_drain = bh->next; + + /* A short packet or an error ends everything */ + if (bh->outreq->actual != bh->outreq->length || + bh->outreq->status != 0) { + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + return -EINTR; + } + continue; + } + + /* Try to submit another request if we need one */ + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { + amount = min(fsg->usb_amount_left, + (u32) mod_data.buflen); + + /* amount is always divisible by 512, hence by + * the bulk-out maxpacket size */ + bh->outreq->length = bh->bulk_out_intended_length = + amount; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= amount; + continue; + } + + /* Otherwise wait for something to happen */ + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + return 0; +} + + +static int finish_reply(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + int rc = 0; + + switch (fsg->data_dir) { + case DATA_DIR_NONE: + break; // Nothing to send + + /* If we don't know whether the host wants to read or write, + * this must be CB or CBI with an unknown command. We mustn't + * try to send or receive any data. So stall both bulk pipes + * if we can and wait for a reset. */ + case DATA_DIR_UNKNOWN: + if (mod_data.can_stall) { + fsg_set_halt(fsg, fsg->bulk_out); + rc = halt_bulk_in_endpoint(fsg); + } + break; + + /* All but the last buffer of data must have already been sent */ + case DATA_DIR_TO_HOST: + if (fsg->data_size == 0) + ; // Nothing to send + + /* If there's no residue, simply send the last buffer */ + else if (fsg->residue == 0) { + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + } + + /* There is a residue. For CB and CBI, simply mark the end + * of the data with a short packet. However, if we are + * allowed to stall, there was no data at all (residue == + * data_size), and the command failed (invalid LUN or + * sense data is set), then halt the bulk-in endpoint + * instead. */ + else if (!transport_is_bbb()) { + if (mod_data.can_stall && + fsg->residue == fsg->data_size && + (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { + bh->state = BUF_STATE_EMPTY; + rc = halt_bulk_in_endpoint(fsg); + } else { + bh->inreq->zero = 1; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + } + } + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't + * stall, pad out the remaining data with 0's. */ + else { + if (mod_data.can_stall) { + bh->inreq->zero = 1; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + rc = halt_bulk_in_endpoint(fsg); + } else + rc = pad_with_zeros(fsg); + } + break; + + /* We have processed all we want from the data the host has sent. + * There may still be outstanding bulk-out requests. */ + case DATA_DIR_FROM_HOST: + if (fsg->residue == 0) + ; // Nothing to receive + + /* Did the host stop sending unexpectedly early? */ + else if (fsg->short_packet_received) { + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; + } + + /* We haven't processed all the incoming data. If we are + * allowed to stall, halt the bulk-out endpoint and cancel + * any outstanding requests. */ + else if (mod_data.can_stall) { + fsg_set_halt(fsg, fsg->bulk_out); + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; + } + + /* We can't stall. Read in the excess data and throw it + * all away. */ + else + rc = throw_away_data(fsg); + break; + } + return rc; +} + + +static int send_status(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + struct fsg_buffhd *bh; + int rc; + u8 status = USB_STATUS_PASS; + u32 sd, sdinfo = 0; + + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + if (curlun) { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + } else if (fsg->bad_lun_okay) + sd = SS_NO_SENSE; + else + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + + if (fsg->phase_error) { + DBG(fsg, "sending phase-error status\n"); + status = USB_STATUS_PHASE_ERROR; + sd = SS_INVALID_COMMAND; + } else if (sd != SS_NO_SENSE) { + DBG(fsg, "sending command-failure status\n"); + status = USB_STATUS_FAIL; + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" + " info x%x\n", + SK(sd), ASC(sd), ASCQ(sd), sdinfo); + } + + if (transport_is_bbb()) { + struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; + + /* Store and send the Bulk-only CSW */ + csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); + csw->Tag = fsg->tag; + csw->Residue = fsg->residue; + csw->Status = status; + + bh->inreq->length = USB_BULK_CS_WRAP_LEN; + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + + } else if (mod_data.transport_type == USB_PR_CB) { + + /* Control-Bulk transport has no status stage! */ + return 0; + + } else { // USB_PR_CBI + struct interrupt_data *buf = (struct interrupt_data *) + bh->buf; + + /* Store and send the Interrupt data. UFI sends the ASC + * and ASCQ bytes. Everything else sends a Type (which + * is always 0) and the status Value. */ + if (mod_data.protocol_type == USB_SC_UFI) { + buf->bType = ASC(sd); + buf->bValue = ASCQ(sd); + } else { + buf->bType = 0; + buf->bValue = status; + } + fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; + + fsg->intr_buffhd = bh; // Point to the right buffhd + fsg->intreq->buf = bh->inreq->buf; + fsg->intreq->dma = bh->inreq->dma; + fsg->intreq->context = bh; + start_transfer(fsg, fsg->intr_in, fsg->intreq, + &fsg->intreq_busy, &bh->state); + } + + fsg->next_buffhd_to_fill = bh->next; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* Check whether the command is properly formed and whether its data size + * and direction agree with the values we already have. */ +static int check_command(struct fsg_dev *fsg, int cmnd_size, + enum data_direction data_dir, unsigned int mask, + int needs_medium, const char *name) +{ + int i; + int lun = fsg->cmnd[1] >> 5; + static const char dirletter[4] = {'u', 'o', 'i', 'n'}; + char hdlen[20]; + struct lun *curlun; + + /* Adjust the expected cmnd_size for protocol encapsulation padding. + * Transparent SCSI doesn't pad. */ + if (protocol_is_scsi()) + ; + + /* There's some disagreement as to whether RBC pads commands or not. + * We'll play it safe and accept either form. */ + else if (mod_data.protocol_type == USB_SC_RBC) { + if (fsg->cmnd_size == 12) + cmnd_size = 12; + + /* All the other protocols pad to 12 bytes */ + } else + cmnd_size = 12; + + hdlen[0] = 0; + if (fsg->data_dir != DATA_DIR_UNKNOWN) + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], + fsg->data_size); + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); + + /* We can't reply at all until we know the correct data direction + * and size. */ + if (fsg->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI + fsg->data_dir = data_dir; + fsg->data_size = fsg->data_size_from_cmnd; + + } else { // Bulk-only + if (fsg->data_size < fsg->data_size_from_cmnd) { + + /* Host data size < Device data size is a phase error. + * Carry out the command, but only transfer as much + * as we are allowed. */ + fsg->data_size_from_cmnd = fsg->data_size; + fsg->phase_error = 1; + } + } + fsg->residue = fsg->usb_amount_left = fsg->data_size; + + /* Conflicting data directions is a phase error */ + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) + goto phase_error; + + /* Verify the length of the command itself */ + if (cmnd_size != fsg->cmnd_size) { + + /* Special case workaround: MS-Windows issues REQUEST SENSE + * with cbw->Length == 12 (it should be 6). */ + if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) + cmnd_size = fsg->cmnd_size; + else + goto phase_error; + } + + /* Check that the LUN values are oonsistent */ + if (transport_is_bbb()) { + if (fsg->lun != lun) + DBG(fsg, "using LUN %d from CBW, " + "not LUN %d from CDB\n", + fsg->lun, lun); + } else + fsg->lun = lun; // Use LUN from the command + + /* Check the LUN */ + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { + fsg->curlun = curlun = &fsg->luns[fsg->lun]; + if (fsg->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + } + } else { + fsg->curlun = curlun = NULL; + fsg->bad_lun_okay = 0; + + /* INQUIRY and REQUEST SENSE commands are explicitly allowed + * to use unsupported LUNs; all others may not. */ + if (fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { + DBG(fsg, "unsupported LUN %d\n", fsg->lun); + return -EINVAL; + } + } + + /* If a unit attention condition exists, only INQUIRY and + * REQUEST SENSE commands are allowed; anything else must fail. */ + if (curlun && curlun->unit_attention_data != SS_NO_SENSE && + fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + return -EINVAL; + } + + /* Check that only command bytes listed in the mask are non-zero */ + fsg->cmnd[1] &= 0x1f; // Mask away the LUN + for (i = 1; i < cmnd_size; ++i) { + if (fsg->cmnd[i] && !(mask & (1 << i))) { + if (curlun) + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + } + + /* If the medium isn't mounted and the command needs to access + * it, return an error. */ + if (curlun && !backing_file_is_open(curlun) && needs_medium) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } + + return 0; + +phase_error: + fsg->phase_error = 1; + return -EINVAL; +} + + +static int do_scsi_command(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc; + int reply = -EINVAL; + int i; + static char unknown[16]; + + dump_cdb(fsg); + + /* Wait for the next buffer to become available for data or status */ + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + fsg->phase_error = 0; + fsg->short_packet_received = 0; + + down_read(&fsg->filesem); // We're using the backing file + switch (fsg->cmnd[0]) { + + case SC_INQUIRY: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "INQUIRY")) == 0) + reply = do_inquiry(fsg, bh); + break; + + case SC_MODE_SELECT_6: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (1<<1) | (1<<4), 0, + "MODE SELECT(6)")) == 0) + reply = do_mode_select(fsg, bh); + break; + + case SC_MODE_SELECT_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (3<<7), 0, + "MODE SELECT(10)")) == 0) + reply = do_mode_select(fsg, bh); + break; + + case SC_MODE_SENSE_6: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (1<<4), 0, + "MODE SENSE(6)")) == 0) + reply = do_mode_sense(fsg, bh); + break; + + case SC_MODE_SENSE_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (3<<7), 0, + "MODE SENSE(10)")) == 0) + reply = do_mode_sense(fsg, bh); + break; + + case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<4), 0, + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) + reply = do_prevent_allow(fsg); + break; + + case SC_READ_6: + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (7<<1) | (1<<4), 1, + "READ(6)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "READ(10)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_12: + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "READ(12)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_CAPACITY: + fsg->data_size_from_cmnd = 8; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (0xf<<2) | (1<<8), 1, + "READ CAPACITY")) == 0) + reply = do_read_capacity(fsg, bh); + break; + + case SC_READ_FORMAT_CAPACITIES: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7), 1, + "READ FORMAT CAPACITIES")) == 0) + reply = do_read_format_capacities(fsg, bh); + break; + + case SC_REQUEST_SENSE: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "REQUEST SENSE")) == 0) + reply = do_request_sense(fsg, bh); + break; + + case SC_START_STOP_UNIT: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<1) | (1<<4), 0, + "START-STOP UNIT")) == 0) + reply = do_start_stop(fsg); + break; + + case SC_SYNCHRONIZE_CACHE: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (0xf<<2) | (3<<7), 1, + "SYNCHRONIZE CACHE")) == 0) + reply = do_synchronize_cache(fsg); + break; + + case SC_TEST_UNIT_READY: + fsg->data_size_from_cmnd = 0; + reply = check_command(fsg, 6, DATA_DIR_NONE, + 0, 1, + "TEST UNIT READY"); + break; + + /* Although optional, this command is used by MS-Windows. We + * support a minimal version: BytChk must be 0. */ + case SC_VERIFY: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (1<<1) | (0xf<<2) | (3<<7), 1, + "VERIFY")) == 0) + reply = do_verify(fsg); + break; + + case SC_WRITE_6: + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (7<<1) | (1<<4), 1, + "WRITE(6)")) == 0) + reply = do_write(fsg); + break; + + case SC_WRITE_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "WRITE(10)")) == 0) + reply = do_write(fsg); + break; + + case SC_WRITE_12: + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "WRITE(12)")) == 0) + reply = do_write(fsg); + break; + + /* Some mandatory commands that we recognize but don't implement. + * They don't mean much in this setting. It's left as an exercise + * for anyone interested to implement RESERVE and RELEASE in terms + * of Posix locks. */ + case SC_FORMAT_UNIT: + case SC_RELEASE: + case SC_RESERVE: + case SC_SEND_DIAGNOSTIC: + // Fall through + + default: + fsg->data_size_from_cmnd = 0; + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); + if ((reply = check_command(fsg, fsg->cmnd_size, + DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { + fsg->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } + break; + } + up_read(&fsg->filesem); + + if (reply == -EINTR || signal_pending(current)) + return -EINTR; + + /* Set up the single reply buffer for finish_reply() */ + if (reply == -EINVAL) + reply = 0; // Error reply length + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { + reply = min((u32) reply, fsg->data_size_from_cmnd); + bh->inreq->length = reply; + bh->state = BUF_STATE_FULL; + fsg->residue -= reply; + } // Otherwise it's already set + + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct usb_request *req = bh->outreq; + struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; + + /* Was this a real packet? */ + if (req->status) + return -EINVAL; + + /* Is the CBW valid? */ + if (req->actual != USB_BULK_CB_WRAP_LEN || + cbw->Signature != __constant_cpu_to_le32( + USB_BULK_CB_SIG)) { + DBG(fsg, "invalid CBW: len %u sig 0x%x\n", + req->actual, + le32_to_cpu(cbw->Signature)); + + /* The Bulk-only spec says we MUST stall the bulk pipes! + * If we want to avoid stalls, set a flag so that we will + * clear the endpoint halts at the next reset. */ + if (!mod_data.can_stall) + set_bit(CLEAR_BULK_HALTS, &fsg->atomic_bitflags); + fsg_set_halt(fsg, fsg->bulk_out); + halt_bulk_in_endpoint(fsg); + return -EINVAL; + } + + /* Is the CBW meaningful? */ + if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " + "cmdlen %u\n", + cbw->Lun, cbw->Flags, cbw->Length); + + /* We can do anything we want here, so let's stall the + * bulk pipes if we are allowed to. */ + if (mod_data.can_stall) { + fsg_set_halt(fsg, fsg->bulk_out); + halt_bulk_in_endpoint(fsg); + } + return -EINVAL; + } + + /* Save the command for later */ + fsg->cmnd_size = cbw->Length; + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); + if (cbw->Flags & USB_BULK_IN_FLAG) + fsg->data_dir = DATA_DIR_TO_HOST; + else + fsg->data_dir = DATA_DIR_FROM_HOST; + fsg->data_size = cbw->DataTransferLength; + if (fsg->data_size == 0) + fsg->data_dir = DATA_DIR_NONE; + fsg->lun = cbw->Lun; + fsg->tag = cbw->Tag; + return 0; +} + + +static int get_next_command(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc = 0; + + if (transport_is_bbb()) { + + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + /* Queue a request to read a Bulk-only CBW */ + set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + + /* We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. */ + + /* Wait for the CBW to arrive */ + while (bh->state != BUF_STATE_FULL) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + rc = received_cbw(fsg, bh); + bh->state = BUF_STATE_EMPTY; + + } else { // USB_PR_CB or USB_PR_CBI + + /* Wait for the next command to arrive */ + while (fsg->cbbuf_cmnd_size == 0) { + if ((rc = sleep_thread(fsg)) != 0) + return rc; + } + + /* Is the previous status interrupt request still busy? + * The host is allowed to skip reading the status, + * so we must cancel it. */ + if (fsg->intreq_busy) + usb_ep_dequeue(fsg->intr_in, fsg->intreq); + + /* Copy the command and mark the buffer empty */ + fsg->data_dir = DATA_DIR_UNKNOWN; + spin_lock_irq(&fsg->lock); + fsg->cmnd_size = fsg->cbbuf_cmnd_size; + memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); + fsg->cbbuf_cmnd_size = 0; + spin_unlock_irq(&fsg->lock); + } + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, + const struct usb_endpoint_descriptor *d) +{ + int rc; + + ep->driver_data = fsg; + rc = usb_ep_enable(ep, d); + if (rc) + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); + return rc; +} + +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, + struct usb_request **preq) +{ + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (*preq) + return 0; + ERROR(fsg, "can't allocate request for %s\n", ep->name); + return -ENOMEM; +} + +/* + * Reset interface setting and re-init endpoint state (toggle etc). + * Call with altsetting < 0 to disable the interface. The only other + * available altsetting is 0, which enables the interface. + */ +static int do_set_interface(struct fsg_dev *fsg, int altsetting) +{ + int rc = 0; + int i; + const struct usb_endpoint_descriptor *d; + + if (fsg->running) + DBG(fsg, "reset interface\n"); + +reset: + /* Deallocate the requests */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if (bh->inreq) { + usb_ep_free_request(fsg->bulk_in, bh->inreq); + bh->inreq = NULL; + } + if (bh->outreq) { + usb_ep_free_request(fsg->bulk_out, bh->outreq); + bh->outreq = NULL; + } + } + if (fsg->intreq) { + usb_ep_free_request(fsg->intr_in, fsg->intreq); + fsg->intreq = NULL; + } + + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + if (fsg->intr_in_enabled) { + usb_ep_disable(fsg->intr_in); + fsg->intr_in_enabled = 0; + } + + fsg->running = 0; + if (altsetting < 0 || rc != 0) + return rc; + + DBG(fsg, "set interface %d\n", altsetting); + + /* Enable the endpoints */ + d = ep_desc(fsg->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) + goto reset; + fsg->bulk_in_enabled = 1; + + d = ep_desc(fsg->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) + goto reset; + fsg->bulk_out_enabled = 1; + + if (transport_is_cbi()) { + d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) + goto reset; + fsg->intr_in_enabled = 1; + } + + /* Allocate the requests */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) + goto reset; + if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) + goto reset; + bh->inreq->buf = bh->outreq->buf = bh->buf; + bh->inreq->dma = bh->outreq->dma = bh->dma; + bh->inreq->context = bh->outreq->context = bh; + bh->inreq->complete = bulk_in_complete; + bh->outreq->complete = bulk_out_complete; + } + if (transport_is_cbi()) { + if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) + goto reset; + fsg->intreq->complete = intr_in_complete; + } + + fsg->running = 1; + for (i = 0; i < fsg->nluns; ++i) + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; + return rc; +} + + +/* + * Change our operational configuration. This code must agree with the code + * that returns config descriptors, and with interface altsetting code. + * + * It's also responsible for power management interactions. Some + * configurations might not work with our current power sources. + * For now we just assume the gadget is always self-powered. + */ +static int do_set_config(struct fsg_dev *fsg, u8 new_config) +{ + int rc = 0; + + /* Disable the single interface */ + if (fsg->config != 0) { + DBG(fsg, "reset config\n"); + fsg->config = 0; + rc = do_set_interface(fsg, -1); + } + + /* Enable the interface */ + if (new_config != 0) { + fsg->config = new_config; + if ((rc = do_set_interface(fsg, 0)) != 0) + fsg->config = 0; // Reset on errors + else { + char *speed; + + switch (fsg->gadget->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + default: speed = "?"; break; + } + INFO(fsg, "%s speed config #%d\n", speed, fsg->config); + } + } + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static void handle_exception(struct fsg_dev *fsg) +{ + siginfo_t info; + int sig; + int i; + int num_active; + struct fsg_buffhd *bh; + enum fsg_state old_state; + u8 new_config; + struct lun *curlun; + unsigned int exception_req_tag; + int rc; + + /* Clear the existing signals. Anything but SIGUSR1 is converted + * into a high-priority EXIT exception. */ + for (;;) { + sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, + &info); + if (!sig) + break; + if (sig != SIGUSR1) { + if (fsg->state < FSG_STATE_EXIT) + DBG(fsg, "Main thread exiting on signal\n"); + raise_exception(fsg, FSG_STATE_EXIT); + } + } + + /* Cancel all the pending transfers */ + if (fsg->intreq_busy) + usb_ep_dequeue(fsg->intr_in, fsg->intreq); + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + if (bh->inreq_busy) + usb_ep_dequeue(fsg->bulk_in, bh->inreq); + if (bh->outreq_busy) + usb_ep_dequeue(fsg->bulk_out, bh->outreq); + } + + /* Wait until everything is idle */ + for (;;) { + num_active = fsg->intreq_busy; + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; + } + if (num_active == 0) + break; + if (sleep_thread(fsg)) + return; + } + + /* Clear out the controller's fifos */ + if (fsg->bulk_in_enabled) + usb_ep_fifo_flush(fsg->bulk_in); + if (fsg->bulk_out_enabled) + usb_ep_fifo_flush(fsg->bulk_out); + if (fsg->intr_in_enabled) + usb_ep_fifo_flush(fsg->intr_in); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ + spin_lock_irq(&fsg->lock); + + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + bh->state = BUF_STATE_EMPTY; + } + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = + &fsg->buffhds[0]; + + exception_req_tag = fsg->exception_req_tag; + new_config = fsg->new_config; + old_state = fsg->state; + + if (old_state == FSG_STATE_ABORT_BULK_OUT) + fsg->state = FSG_STATE_STATUS_PHASE; + else { + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + curlun->prevent_medium_removal = 0; + curlun->sense_data = curlun->unit_attention_data = + SS_NO_SENSE; + curlun->sense_data_info = 0; + } + fsg->state = FSG_STATE_IDLE; + } + spin_unlock_irq(&fsg->lock); + + /* Carry out any extra actions required for the exception */ + switch (old_state) { + default: + break; + + case FSG_STATE_ABORT_BULK_OUT: + send_status(fsg); + spin_lock_irq(&fsg->lock); + if (fsg->state == FSG_STATE_STATUS_PHASE) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irq(&fsg->lock); + break; + + case FSG_STATE_RESET: + /* In case we were forced against our will to halt a + * bulk endpoint, clear the halt now. (The SuperH UDC + * requires this.) */ + if (test_and_clear_bit(CLEAR_BULK_HALTS, + &fsg->atomic_bitflags)) { + usb_ep_clear_halt(fsg->bulk_in); + usb_ep_clear_halt(fsg->bulk_out); + } + + if (transport_is_bbb()) { + if (fsg->ep0_req_tag == exception_req_tag) + ep0_queue(fsg); // Complete the status stage + + } else if (transport_is_cbi()) + send_status(fsg); // Status by interrupt pipe + + /* Technically this should go here, but it would only be + * a waste of time. Ditto for the INTERFACE_CHANGE and + * CONFIG_CHANGE cases. */ + // for (i = 0; i < fsg->nluns; ++i) + // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; + break; + + case FSG_STATE_INTERFACE_CHANGE: + rc = do_set_interface(fsg, 0); + if (fsg->ep0_req_tag != exception_req_tag) + break; + if (rc != 0) // STALL on errors + fsg_set_halt(fsg, fsg->ep0); + else // Complete the status stage + ep0_queue(fsg); + break; + + case FSG_STATE_CONFIG_CHANGE: + rc = do_set_config(fsg, new_config); + if (fsg->ep0_req_tag != exception_req_tag) + break; + if (rc != 0) // STALL on errors + fsg_set_halt(fsg, fsg->ep0); + else // Complete the status stage + ep0_queue(fsg); + break; + + case FSG_STATE_DISCONNECT: + fsync_all(fsg); + do_set_config(fsg, 0); // Unconfigured state + break; + + case FSG_STATE_EXIT: + case FSG_STATE_TERMINATED: + do_set_config(fsg, 0); // Free resources + spin_lock_irq(&fsg->lock); + fsg->state = FSG_STATE_TERMINATED; // Stop the thread + spin_unlock_irq(&fsg->lock); + break; + } +} + + +/*-------------------------------------------------------------------------*/ + +static int fsg_main_thread(void *fsg_) +{ + struct fsg_dev *fsg = (struct fsg_dev *) fsg_; + + fsg->thread_task = current; + + /* Release all our userspace resources */ + daemonize("file-storage-gadget"); + + /* Allow the thread to be killed by a signal, but set the signal mask + * to block everything but INT, TERM, KILL, and USR1. */ + siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | + sigmask(SIGTERM) | sigmask(SIGKILL) | + sigmask(SIGUSR1)); + sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL); + + /* Arrange for userspace references to be interpreted as kernel + * pointers. That way we can pass a kernel pointer to a routine + * that expects a __user pointer and it will work okay. */ + set_fs(get_ds()); + + /* Wait for the gadget registration to finish up */ + wait_for_completion(&fsg->thread_notifier); + + /* The main loop */ + while (fsg->state != FSG_STATE_TERMINATED) { + if (exception_in_progress(fsg) || signal_pending(current)) { + handle_exception(fsg); + continue; + } + + if (!fsg->running) { + sleep_thread(fsg); + continue; + } + + if (get_next_command(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_DATA_PHASE; + spin_unlock_irq(&fsg->lock); + + if (do_scsi_command(fsg) || finish_reply(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_STATUS_PHASE; + spin_unlock_irq(&fsg->lock); + + if (send_status(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irq(&fsg->lock); + } + + fsg->thread_task = NULL; + flush_signals(current); + + /* In case we are exiting because of a signal, unregister the + * gadget driver and close the backing file. */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) { + usb_gadget_unregister_driver(&fsg_driver); + close_all_backing_files(fsg); + } + + /* Let the unbind and cleanup routines know the thread has exited */ + complete_and_exit(&fsg->thread_notifier, 0); +} + + +/*-------------------------------------------------------------------------*/ + +/* If the next two routines are called while the gadget is registered, + * the caller must own fsg->filesem for writing. */ + +static int NORMALLY_INIT open_backing_file(struct lun *curlun, + const char *filename) +{ + int ro; + struct file *filp = NULL; + int rc = -EINVAL; + struct inode *inode = NULL; + loff_t size; + loff_t num_sectors; + + /* R/W if we can, R/O if we must */ + ro = curlun->ro; + if (!ro) { + filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); + if (-EROFS == PTR_ERR(filp)) + ro = 1; + } + if (ro) + filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + LINFO(curlun, "unable to open backing file: %s\n", filename); + return PTR_ERR(filp); + } + + if (!(filp->f_mode & FMODE_WRITE)) + ro = 1; + + if (filp->f_dentry) + inode = filp->f_dentry->d_inode; + if (inode && S_ISBLK(inode->i_mode)) { + if (bdev_read_only(inode->i_bdev)) + ro = 1; + } else if (!inode || !S_ISREG(inode->i_mode)) { + LINFO(curlun, "invalid file type: %s\n", filename); + goto out; + } + + /* If we can't read the file, it's no good. + * If we can't write the file, use it read-only. */ + if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { + LINFO(curlun, "file not readable: %s\n", filename); + goto out; + } + if (!(filp->f_op->write || filp->f_op->aio_write)) + ro = 1; + + size = i_size_read(inode->i_mapping->host); + if (size < 0) { + LINFO(curlun, "unable to find file size: %s\n", filename); + rc = (int) size; + goto out; + } + num_sectors = size >> 9; // File size in 512-byte sectors + if (num_sectors == 0) { + LINFO(curlun, "file too small: %s\n", filename); + rc = -ETOOSMALL; + goto out; + } + + get_file(filp); + curlun->ro = ro; + curlun->filp = filp; + curlun->file_length = size; + curlun->num_sectors = num_sectors; + LDBG(curlun, "open backing file: %s\n", filename); + rc = 0; + +out: + filp_close(filp, current->files); + return rc; +} + + +static void close_backing_file(struct lun *curlun) +{ + if (curlun->filp) { + LDBG(curlun, "close backing file\n"); + fput(curlun->filp); + curlun->filp = NULL; + } +} + +static void close_all_backing_files(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + close_backing_file(&fsg->luns[i]); +} + + +static ssize_t show_ro(struct device *dev, char *buf) +{ + struct lun *curlun = dev_to_lun(dev); + + return sprintf(buf, "%d\n", curlun->ro); +} + +static ssize_t show_file(struct device *dev, char *buf) +{ + struct lun *curlun = dev_to_lun(dev); + struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + char *p; + ssize_t rc; + + down_read(&fsg->filesem); + if (backing_file_is_open(curlun)) { // Get the complete pathname + p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt, + buf, PAGE_SIZE - 1); + if (IS_ERR(p)) + rc = PTR_ERR(p); + else { + rc = strlen(p); + memmove(buf, p, rc); + buf[rc] = '\n'; // Add a newline + buf[++rc] = 0; + } + } else { // No file, return 0 bytes + *buf = 0; + rc = 0; + } + up_read(&fsg->filesem); + return rc; +} + + +ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, + size_t count) +{ + ssize_t rc = count; + struct lun *curlun = dev_to_lun(dev); + struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + int i; + + if (sscanf(buf, "%d", &i) != 1) + return -EINVAL; + + /* Allow the write-enable status to change only while the backing file + * is closed. */ + down_read(&fsg->filesem); + if (backing_file_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { + curlun->ro = !!i; + LDBG(curlun, "read-only status set to %d\n", curlun->ro); + } + up_read(&fsg->filesem); + return rc; +} + +ssize_t NORMALLY_INIT store_file(struct device *dev, const char *buf, + size_t count) +{ + struct lun *curlun = dev_to_lun(dev); + struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + int rc = 0; + + if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; // "Door is locked" + } + + /* Remove a trailing newline */ + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; // Ugh! + + /* Eject current medium */ + down_write(&fsg->filesem); + if (backing_file_is_open(curlun)) { + close_backing_file(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + + /* Load new medium */ + if (count > 0 && buf[0]) { + rc = open_backing_file(curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; + } + up_write(&fsg->filesem); + return (rc < 0 ? rc : count); +} + + +/* The write permissions and store_xxx pointers are set in fsg_bind() */ +static DEVICE_ATTR(ro, 0444, show_ro, NULL); +static DEVICE_ATTR(file, 0444, show_file, NULL); + + +/*-------------------------------------------------------------------------*/ + +static void fsg_unbind(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + int i; + struct lun *curlun; + struct usb_request *req = fsg->ep0req; + + DBG(fsg, "unbind\n"); + clear_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Unregister the sysfs attribute files and the LUNs */ + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_ro); + device_remove_file(&curlun->dev, &dev_attr_file); + device_unregister_wait(&curlun->dev); + curlun->registered = 0; + } + } + + /* If the thread isn't already dead, tell it to exit now */ + if (fsg->state != FSG_STATE_TERMINATED) { + raise_exception(fsg, FSG_STATE_EXIT); + wait_for_completion(&fsg->thread_notifier); + + /* The cleanup routine waits for this completion also */ + complete(&fsg->thread_notifier); + } + + /* Free the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if (bh->buf) + usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma, + mod_data.buflen); + } + + /* Free the request and buffer for endpoint 0 */ + if (req) { + if (req->buf) + usb_ep_free_buffer(fsg->ep0, req->buf, + req->dma, EP0_BUFSIZE); + usb_ep_free_request(fsg->ep0, req); + } + + set_gadget_data(gadget, 0); +} + + +static int __init check_parameters(struct fsg_dev *fsg) +{ + int prot; + + /* Store the default values */ + mod_data.transport_type = USB_PR_BULK; + mod_data.transport_name = "Bulk-only"; + mod_data.protocol_type = USB_SC_SCSI; + mod_data.protocol_name = "Transparent SCSI"; + + prot = simple_strtol(mod_data.protocol_parm, NULL, 0); + +#ifdef CONFIG_USB_FILE_STORAGE_TEST + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { + ; // Use default setting + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { + mod_data.transport_type = USB_PR_CB; + mod_data.transport_name = "Control-Bulk"; + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { + mod_data.transport_type = USB_PR_CBI; + mod_data.transport_name = "Control-Bulk-Interrupt"; + } else { + INFO(fsg, "invalid transport: %s\n", mod_data.transport_parm); + return -EINVAL; + } + + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || + prot == USB_SC_SCSI) { + ; // Use default setting + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || + prot == USB_SC_RBC) { + mod_data.protocol_type = USB_SC_RBC; + mod_data.protocol_name = "RBC"; + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || + prot == USB_SC_8020) { + mod_data.protocol_type = USB_SC_8020; + mod_data.protocol_name = "8020i (ATAPI)"; + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || + prot == USB_SC_QIC) { + mod_data.protocol_type = USB_SC_QIC; + mod_data.protocol_name = "QIC-157"; + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || + prot == USB_SC_UFI) { + mod_data.protocol_type = USB_SC_UFI; + mod_data.protocol_name = "UFI"; + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || + prot == USB_SC_8070) { + mod_data.protocol_type = USB_SC_8070; + mod_data.protocol_name = "8070i"; + } else { + INFO(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); + return -EINVAL; + } + + mod_data.buflen &= PAGE_CACHE_MASK; + if (mod_data.buflen <= 0) { + INFO(fsg, "invalid buflen\n"); + return -ETOOSMALL; + } +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + + return 0; +} + + +static int __init fsg_bind(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = the_fsg; + int rc; + int i; + struct lun *curlun; + struct usb_ep *ep; + struct usb_request *req; + char *pathbuf, *p; + + fsg->gadget = gadget; + set_gadget_data(gadget, fsg); + fsg->ep0 = gadget->ep0; + fsg->ep0->driver_data = fsg; + + if ((rc = check_parameters(fsg)) != 0) + goto out; + + if (mod_data.removable) { // Enable the store_xxx attributes + dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644; + dev_attr_ro.store = store_ro; + dev_attr_file.store = store_file; + } + + /* Find out how many LUNs there should be */ + i = mod_data.nluns; + if (i == 0) + i = max(mod_data.num_filenames, 1); + if (i > MAX_LUNS) { + INFO(fsg, "invalid number of LUNs: %d\n", i); + rc = -EINVAL; + goto out; + } + + /* Create the LUNs and open their backing files. We can't register + * the LUN devices until the gadget itself is registered, which + * doesn't happen until after fsg_bind() returns. */ + fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); + if (!fsg->luns) { + rc = -ENOMEM; + goto out; + } + memset(fsg->luns, 0, i * sizeof(struct lun)); + fsg->nluns = i; + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + curlun->ro = ro[i]; + curlun->dev.parent = &gadget->dev; + curlun->dev.driver = &fsg_driver.driver; + dev_set_drvdata(&curlun->dev, fsg); + snprintf(curlun->dev.bus_id, BUS_ID_SIZE, + "%s-lun%d", gadget->dev.bus_id, i); + + if (file[i] && *file[i]) { + if ((rc = open_backing_file(curlun, file[i])) != 0) + goto out; + } else if (!mod_data.removable) { + INFO(fsg, "no file given for LUN%d\n", i); + rc = -EINVAL; + goto out; + } + } + + /* Fix up the descriptors */ + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; +#ifdef HIGHSPEED + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; // ??? +#endif + device_desc.idVendor = cpu_to_le16(mod_data.vendor); + device_desc.idProduct = cpu_to_le16(mod_data.product); + device_desc.bcdDevice = cpu_to_le16(mod_data.release); + + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints + config_desc.wTotalLength = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + + USB_DT_ENDPOINT_SIZE * i; + intf_desc.bNumEndpoints = i; + intf_desc.bInterfaceSubClass = mod_data.protocol_type; + intf_desc.bInterfaceProtocol = mod_data.transport_type; + + /* Find all the endpoints we will use */ + gadget_for_each_ep(ep, gadget) { + if (strcmp(ep->name, EP_BULK_IN_NAME) == 0) + fsg->bulk_in = ep; + else if (strcmp(ep->name, EP_BULK_OUT_NAME) == 0) + fsg->bulk_out = ep; + else if (strcmp(ep->name, EP_INTR_IN_NAME) == 0) + fsg->intr_in = ep; + } + if (!fsg->bulk_in || !fsg->bulk_out || + (transport_is_cbi() && !fsg->intr_in)) { + DBG(fsg, "unable to find all endpoints\n"); + rc = -ENOTSUPP; + goto out; + } + fsg->bulk_out_maxpacket = (gadget->speed == USB_SPEED_HIGH ? 512 : + FS_BULK_OUT_MAXPACKET); + + rc = -ENOMEM; + + /* Allocate the request and buffer for endpoint 0 */ + fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); + if (!req) + goto out; + req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE, + &req->dma, GFP_KERNEL); + if (!req->buf) + goto out; + req->complete = ep0_complete; + + /* Allocate the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, + &bh->dma, GFP_KERNEL); + if (!bh->buf) + goto out; + bh->next = bh + 1; + } + fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + + /* This should reflect the actual gadget power source */ + usb_gadget_set_selfpowered(gadget); + + /* On a real device, serial[] would be loaded from permanent + * storage. We just encode it from the driver version string. */ + for (i = 0; i < sizeof(serial) - 2; i += 2) { + unsigned char c = DRIVER_VERSION[i / 2]; + + if (!c) + break; + sprintf(&serial[i], "%02X", c); + } + + if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS | + CLONE_FILES))) < 0) + goto out; + fsg->thread_pid = rc; + + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if (backing_file_is_open(curlun)) { + p = NULL; + if (pathbuf) { + p = d_path(curlun->filp->f_dentry, + curlun->filp->f_vfsmnt, + pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = NULL; + } + LINFO(curlun, "ro=%d, file: %s\n", + curlun->ro, (p ? p : "(error)")); + } + } + kfree(pathbuf); + + DBG(fsg, "transport=%s (x%02x)\n", + mod_data.transport_name, mod_data.transport_type); + DBG(fsg, "protocol=%s (x%02x)\n", + mod_data.protocol_name, mod_data.protocol_type); + DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", + mod_data.vendor, mod_data.product, mod_data.release); + DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", + mod_data.removable, mod_data.can_stall, + mod_data.buflen); + DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); + return 0; + +out: + fsg->state = FSG_STATE_TERMINATED; // The thread is dead + fsg_unbind(gadget); + close_all_backing_files(fsg); + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver fsg_driver = { +#ifdef HIGHSPEED + .speed = USB_SPEED_HIGH, +#else + .speed = USB_SPEED_FULL, +#endif + .function = (char *) longname, + .bind = fsg_bind, + .unbind = fsg_unbind, + .disconnect = fsg_disconnect, + .setup = fsg_setup, + + .driver = { + .name = (char *) shortname, + // .release = ... + // .suspend = ... + // .resume = ... + }, +}; + + +static int __init fsg_alloc(void) +{ + struct fsg_dev *fsg; + + fsg = kmalloc(sizeof *fsg, GFP_KERNEL); + if (!fsg) + return -ENOMEM; + memset(fsg, 0, sizeof *fsg); + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->filesem); + init_waitqueue_head(&fsg->thread_wqh); + init_completion(&fsg->thread_notifier); + + the_fsg = fsg; + return 0; +} + + +static void fsg_free(struct fsg_dev *fsg) +{ + kfree(fsg->luns); + kfree(fsg); +} + + +static int __init fsg_init(void) +{ + int rc; + struct fsg_dev *fsg; + int i; + struct lun *curlun; + + if ((rc = fsg_alloc()) != 0) + return rc; + fsg = the_fsg; + if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) { + fsg_free(fsg); + return rc; + } + set_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Register the LUN devices and their attribute files */ + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if ((rc = device_register(&curlun->dev)) != 0) + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + else { + curlun->registered = 1; + device_create_file(&curlun->dev, &dev_attr_ro); + device_create_file(&curlun->dev, &dev_attr_file); + } + } + + /* Tell the thread to start working */ + complete(&fsg->thread_notifier); + return 0; +} +module_init(fsg_init); + + +static void __exit fsg_cleanup(void) +{ + struct fsg_dev *fsg = the_fsg; + + /* Unregister the driver iff the thread hasn't already done so */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) + usb_gadget_unregister_driver(&fsg_driver); + + /* Wait for the thread to finish up */ + wait_for_completion(&fsg->thread_notifier); + + close_all_backing_files(fsg); + fsg_free(fsg); +} +module_exit(fsg_cleanup); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 96bddf7b525de3c230c95f7e7527832912c6865c..8d4a76751411e8d3adfee6e845a57cc3698807a2 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -232,18 +232,27 @@ static void put_ep (struct ep_data *data) * the usb controller exposes. */ -#ifdef CONFIG_USB_GADGETFS_NET2280 +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +/* act (mostly) like a net2280 */ +#define CONFIG_USB_GADGET_NET2280 +#endif + +#ifdef CONFIG_USB_GADGET_NET2280 #define CHIP "net2280" #define HIGHSPEED #endif -#ifdef CONFIG_USB_GADGETFS_PXA2XX +#ifdef CONFIG_USB_GADGET_PXA2XX #define CHIP "pxa2xx_udc" /* earlier hardware doesn't have UDCCFR, races set_{config,interface} */ #warning works best with pxa255 or newer #endif -#ifdef CONFIG_USB_GADGETFS_SA1100 +#ifdef CONFIG_USB_GADGET_GOKU +#define CHIP "goku_udc" +#endif + +#ifdef CONFIG_USB_GADGET_SA1100 #define CHIP "sa1100" #endif @@ -397,7 +406,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) /* handle a synchronous OUT bulk/intr/iso transfer */ static ssize_t -ep_read (struct file *fd, char *buf, size_t len, loff_t *ptr) +ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) { struct ep_data *data = fd->private_data; void *kbuf; @@ -441,7 +450,7 @@ ep_read (struct file *fd, char *buf, size_t len, loff_t *ptr) /* handle a synchronous IN bulk/intr/iso transfer */ static ssize_t -ep_write (struct file *fd, const char *buf, size_t len, loff_t *ptr) +ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) { struct ep_data *data = fd->private_data; void *kbuf; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 60b294c2b9441428490b74a550a7c5e4e4f25eeb..915b1645a1de3f2e240ded0da3740395a6a48be9 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -25,9 +25,6 @@ * rev1 chips. Rev1a silicon (0110) fixes almost all of them. */ -#define USE_DMA_CHAINING - - /* * Copyright (C) 2003 David Brownell * Copyright (C) 2003 NetChip Technologies @@ -47,8 +44,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define DEBUG 1 -// #define VERBOSE /* extra debug messages (success too) */ +#undef DEBUG /* messages on error and most fault paths */ +#undef VERBOSE /* extra debug messages (success too) */ #include <linux/config.h> #include <linux/module.h> @@ -77,7 +74,7 @@ #define DRIVER_DESC "NetChip 2280 USB Peripheral Controller" -#define DRIVER_VERSION "Bastille Day 2003" +#define DRIVER_VERSION "2004 Jan 14" #define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ @@ -96,10 +93,21 @@ static const char *ep_name [] = { "ep-e", "ep-f", }; +/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO) + * use_dma_chaining -- dma descriptor queueing gives even more irq reduction + * + * The net2280 DMA engines are not tightly integrated with their FIFOs; + * not all cases are (yet) handled well in this driver or the silicon. + * Some gadget drivers work better with the dma support here than others. + * These two parameters let you use PIO or more aggressive DMA. + */ static int use_dma = 1; +static int use_dma_chaining = 0; /* "modprobe net2280 use_dma=n" etc */ -module_param (use_dma, bool, S_IRUGO|S_IWUSR); +module_param (use_dma, bool, S_IRUGO); +module_param (use_dma_chaining, bool, S_IRUGO); + /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable @@ -110,6 +118,7 @@ static ushort fifo_mode = 0; /* "modprobe net2280 fifo_mode=1" etc */ module_param (fifo_mode, ushort, 0644); + #define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") #if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG) @@ -162,6 +171,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* ep_reset() has already been called */ ep->stopped = 0; + ep->out_overflow = 0; /* set speed-dependent max packet; may kick in high bandwidth */ set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max); @@ -169,8 +179,8 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* FIFO lines can't go to different packets. PIO is ok, so * use it instead of troublesome (non-bulk) multi-packet DMA. */ - if (ep->is_in && ep->dma && (max % 4) != 0) { - DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n", + if (ep->dma && (max % 4) != 0 && use_dma_chaining) { + DEBUG (ep->dev, "%s, no dma for maxpacket %d\n", ep->ep.name, ep->ep.maxpacket); ep->dma = 0; } @@ -179,17 +189,21 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); if (tmp == USB_ENDPOINT_XFER_INT) { - /* not just because of erratum 0105; avoid ever - * kicking in the "toggle-irrelevant" mode. - */ - tmp = USB_ENDPOINT_XFER_BULK; + /* erratum 0105 workaround prevents hs NYET */ + if (dev->chiprev == 0100 + && dev->gadget.speed == USB_SPEED_HIGH + && !(desc->bEndpointAddress & USB_DIR_IN)) + writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE), + &ep->regs->ep_rsp); } else if (tmp == USB_ENDPOINT_XFER_BULK) { /* catch some particularly blatant driver bugs */ if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) + && max > 64)) { + spin_unlock_irqrestore (&dev->lock, flags); return -ERANGE; + } } ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; tmp <<= ENDPOINT_TYPE; @@ -205,11 +219,6 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) writel (tmp, &ep->regs->ep_cfg); -#ifdef NET2280_DMA_OUT_WORKAROUND - if (!ep->is_in) - ep->dma = 0; -#endif - /* enable irqs */ if (!ep->dma) { /* pio, per-packet */ tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); @@ -388,6 +397,7 @@ net2280_alloc_request (struct usb_ep *_ep, int gfp_flags) } td->dmacount = 0; /* not VALID */ td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID); + td->dmadesc = td->dmaaddr; req->td = td; } return &req->req; @@ -541,8 +551,11 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) count -= 4; } - /* last fifo entry is "short" unless we wrote a full packet */ - if (total < ep->ep.maxpacket) { + /* last fifo entry is "short" unless we wrote a full packet. + * also explicitly validate last word in (periodic) transfers + * when maxpacket is not a multiple of 4 bytes. + */ + if (count || total < ep->ep.maxpacket) { tmp = count ? get_unaligned ((u32 *)buf) : count; cpu_to_le32s (&tmp); set_fifo_bytecount (ep, count & 0x03); @@ -555,6 +568,9 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) /* work around erratum 0106: PCI and USB race over the OUT fifo. * caller guarantees chiprev 0100, out endpoint is NAKing, and * there's no real data in the fifo. + * + * NOTE: also used in cases where that erratum doesn't apply: + * where the host wrote "too much" data to us. */ static void out_flush (struct net2280_ep *ep) { @@ -599,13 +615,13 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) /* erratum 0106 ... packets coming in during fifo reads might * be incompletely rejected. not all cases have workarounds. */ - if (ep->dev->chiprev == 0x0100) { + if (ep->dev->chiprev == 0x0100 + && ep->dev->gadget.speed == USB_SPEED_FULL) { + udelay (1); tmp = readl (&ep->regs->ep_stat); if ((tmp & (1 << NAK_OUT_PACKETS))) - /* cleanup = 1 */; - else if ((tmp & (1 << FIFO_FULL)) - /* don't break hs PING protocol ... */ - || ep->dev->gadget.speed == USB_SPEED_FULL) { + cleanup = 1; + else if ((tmp & (1 << FIFO_FULL))) { start_out_naking (ep); prevent = 1; } @@ -617,6 +633,15 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) */ prefetchw (buf); count = readl (®s->ep_avail); + if (unlikely (count == 0)) { + udelay (1); + tmp = readl (&ep->regs->ep_stat); + count = readl (®s->ep_avail); + /* handled that data already? */ + if (count == 0 && (tmp & (1 << NAK_OUT_PACKETS)) == 0) + return 0; + } + tmp = req->req.length - req->req.actual; if (count > tmp) { /* as with DMA, data overflow gets flushed */ @@ -626,7 +651,10 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) ep->ep.name, count, tmp); req->req.status = -EOVERFLOW; cleanup = 1; - } + /* NAK_OUT_PACKETS will be set, so flushing is safe; + * the next read will start with the next packet + */ + } /* else it's a ZLP, no worries */ count = tmp; } req->req.actual += count; @@ -665,7 +693,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) } /* fill out dma descriptor to match a given request */ -static inline void +static void fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) { struct net2280_dma *td = req->td; @@ -678,15 +706,13 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) */ if (ep->is_in) dmacount |= (1 << DMA_DIRECTION); - else + else if ((dmacount % ep->ep.maxpacket) != 0) dmacount |= (1 << END_OF_CHAIN); req->valid = valid; if (valid) dmacount |= (1 << VALID_BIT); -#ifdef USE_DMA_CHAINING - if (!req->req.no_interrupt) -#endif + if (likely(!req->req.no_interrupt || !use_dma_chaining)) dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE); /* td->dmadesc = previously set by caller */ @@ -698,7 +724,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) } static const u32 dmactl_default = - (1 << DMA_CLEAR_COUNT_ENABLE) + (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) + | (1 << DMA_CLEAR_COUNT_ENABLE) /* erratum 0116 workaround part 1 (use POLLING) */ | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) | (1 << DMA_VALID_BIT_POLLING_ENABLE) @@ -714,18 +741,41 @@ static inline void spin_stop_dma (struct net2280_dma_regs *dma) static inline void stop_dma (struct net2280_dma_regs *dma) { - writel (dmactl_default & ~(1 << DMA_ENABLE), &dma->dmactl); + writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl); spin_stop_dma (dma); } +static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) +{ + struct net2280_dma_regs *dma = ep->dma; + + writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), + &dma->dmacount); + writel (readl (&dma->dmastat), &dma->dmastat); + + writel (td_dma, &dma->dmadesc); + writel (dmactl, &dma->dmactl); + + /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ + (void) readl (&ep->dev->pci->pcimstctl); + + writel ((1 << DMA_START), &dma->dmastat); + + if (!ep->is_in) + stop_out_naking (ep); +} + static void start_dma (struct net2280_ep *ep, struct net2280_request *req) { u32 tmp; - int clear_nak = 0; struct net2280_dma_regs *dma = ep->dma; /* FIXME can't use DMA for ZLPs */ + /* on this path we "know" there's no dma active (yet) */ + WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE)); + writel (0, &ep->dma->dmactl); + /* previous OUT packet might have been short */ if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) & (1 << NAK_OUT_PACKETS)) != 0) { @@ -733,9 +783,9 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) &ep->regs->ep_stat); tmp = readl (&ep->regs->ep_avail); - if (tmp == 0) - clear_nak = 1; - else { + if (tmp) { + writel (readl (&dma->dmastat), &dma->dmastat); + /* transfer all/some fifo data */ writel (req->req.dma, &dma->dmaaddr); tmp = min (tmp, req->req.length); @@ -744,6 +794,8 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) req->td->dmacount = cpu_to_le32 (req->req.length - tmp); writel ((1 << DMA_DONE_INTERRUPT_ENABLE) | tmp, &dma->dmacount); + req->td->dmadesc = 0; + req->valid = 1; writel ((1 << DMA_ENABLE), &dma->dmactl); writel ((1 << DMA_START), &dma->dmastat); @@ -751,8 +803,6 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) } } - /* on this path we know there's no dma queue (yet) */ - WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE)); tmp = dmactl_default; /* force packet boundaries between dma requests, but prevent the @@ -772,25 +822,10 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) req->td->dmadesc = cpu_to_le32 (ep->td_dma); fill_dma_desc (ep, req, 1); -#ifdef USE_DMA_CHAINING - writel ( (1 << VALID_BIT) - | (ep->is_in << DMA_DIRECTION) - | 0, &dma->dmacount); -#else - req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN); -#endif - - writel (req->td_dma, &dma->dmadesc); - writel (tmp, &dma->dmactl); + if (!use_dma_chaining) + req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN); - /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ - (void) readl (&ep->dev->pci->pcimstctl); - - writel ((1 << DMA_START), &dma->dmastat); - - /* recover from previous short read; erratum 0112 workaround #1 */ - if (clear_nak) - writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + start_queue (ep, tmp, req->td_dma); } static inline void @@ -893,7 +928,6 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) _req->status = -EINPROGRESS; _req->actual = 0; - req->dma_done = 0; /* kickstart this i/o queue? */ if (list_empty (&ep->queue) && !ep->stopped) { @@ -977,10 +1011,11 @@ dma_done ( ) { req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount); - rmb (); done (ep, req, status); } +static void restart_dma (struct net2280_ep *ep); + static void scan_dma_completions (struct net2280_ep *ep) { /* only look at descriptors that were "naturally" retired, @@ -1000,14 +1035,37 @@ static void scan_dma_completions (struct net2280_ep *ep) break; /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short" - * packets, including overruns, even when the transfer was - * exactly the length requested (dmacount now zero). - * FIXME there's an overrun case here too, where we expect - * a short packet but receive a max length one (won't NAK). + * cases where DMA must be aborted; this code handles + * all non-abort DMA completions. */ - if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { - req->dma_done = 1; + if (unlikely (req->td->dmadesc == 0)) { + /* paranoia */ + tmp = readl (&ep->dma->dmacount); + if (tmp & DMA_BYTE_COUNT_MASK) + break; + /* single transfer mode */ + dma_done (ep, req, tmp, 0); break; + } else if (!ep->is_in + && (req->req.length % ep->ep.maxpacket) != 0) { + tmp = readl (&ep->regs->ep_stat); + + /* AVOID TROUBLE HERE by not issuing short reads from + * your gadget driver. That helps avoids errata 0121, + * 0122, and 0124; not all cases trigger the warning. + */ + if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { + WARN (ep->dev, "%s lost packet sync!\n", + ep->ep.name); + req->req.status = -EOVERFLOW; + } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) { + /* fifo gets flushed later */ + ep->out_overflow = 1; + DEBUG (ep->dev, "%s dma, discard %d len %d\n", + ep->ep.name, tmp, + req->req.length); + req->req.status = -EOVERFLOW; + } } dma_done (ep, req, tmp, 0); } @@ -1016,41 +1074,50 @@ static void scan_dma_completions (struct net2280_ep *ep) static void restart_dma (struct net2280_ep *ep) { struct net2280_request *req; + u32 dmactl = dmactl_default; if (ep->stopped) return; req = list_entry (ep->queue.next, struct net2280_request, queue); -#ifdef USE_DMA_CHAINING + if (!use_dma_chaining) { + start_dma (ep, req); + return; + } + /* the 2280 will be processing the queue unless queue hiccups after * the previous transfer: * IN: wanted automagic zlp, head doesn't (or vice versa) + * DMA_FIFO_VALIDATE doesn't init from dma descriptors. * OUT: was "usb-short", we must restart. */ - if (!req->valid) { + if (ep->is_in && !req->valid) { struct net2280_request *entry, *prev = 0; - int qmode, reqmode, done = 0; + int reqmode, done = 0; DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); - qmode = likely (req->req.zero + ep->in_fifo_validate = likely (req->req.zero || (req->req.length % ep->ep.maxpacket) != 0); + if (ep->in_fifo_validate) + dmactl |= (1 << DMA_FIFO_VALIDATE); list_for_each_entry (entry, &ep->queue, queue) { u32 dmacount; - if (entry != req) + if (entry == req) continue; dmacount = entry->td->dmacount; if (!done) { reqmode = likely (entry->req.zero || (entry->req.length % ep->ep.maxpacket) != 0); - if (reqmode == qmode) { + if (reqmode == ep->in_fifo_validate) { entry->valid = 1; dmacount |= valid_bit; entry->td->dmacount = dmacount; prev = entry; continue; } else { + /* force a hiccup */ prev->td->dmacount |= dma_done_ie; done = 1; } @@ -1062,22 +1129,21 @@ static void restart_dma (struct net2280_ep *ep) entry->td->dmacount = dmacount; prev = entry; } - start_dma (ep, req); - } else if (!ep->is_in - && (readl (&ep->regs->ep_stat) - & (1 << NAK_OUT_PACKETS)) != 0) - start_dma (ep, req); -#else - start_dma (ep, req); -#endif + } + + writel (0, &ep->dma->dmactl); + start_queue (ep, dmactl, req->td_dma); } -static inline void abort_dma (struct net2280_ep *ep) +static void abort_dma (struct net2280_ep *ep) { /* abort the current transfer */ - writel ((1 << DMA_ABORT), &ep->dma->dmastat); - - /* collect completed transfers (except the current one) */ + if (likely (!list_empty (&ep->queue))) { + /* FIXME work around errata 0121, 0122, 0124 */ + writel ((1 << DMA_ABORT), &ep->dma->dmastat); + spin_stop_dma (ep->dma); + } else + stop_dma (ep->dma); scan_dma_completions (ep); } @@ -1108,43 +1174,53 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) int stopped; ep = container_of (_ep, struct net2280_ep, ep); - req = container_of (_req, struct net2280_request, req); if (!_ep || (!ep->desc && ep->num != 0) || !_req) return -EINVAL; spin_lock_irqsave (&ep->dev->lock, flags); stopped = ep->stopped; - /* pause dma while we scan the queue */ + /* quiesce dma while we patch the queue */ dmactl = 0; ep->stopped = 1; if (ep->dma) { dmactl = readl (&ep->dma->dmactl); - writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl); - /* force synch, clean any completed requests */ - spin_stop_dma (ep->dma); + /* WARNING erratum 0127 may kick in ... */ + stop_dma (ep->dma); scan_dma_completions (ep); } + /* make sure it's still queued on this endpoint */ + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore (&ep->dev->lock, flags); + return -EINVAL; + } + /* queue head may be partially complete. */ if (ep->queue.next == &req->queue) { if (ep->dma) { DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name); _req->status = -ECONNRESET; abort_dma (ep); - if (likely (ep->queue.next == &req->queue)) + if (likely (ep->queue.next == &req->queue)) { + // NOTE: misreports single-transfer mode + req->td->dmacount = 0; /* invalidate */ dma_done (ep, req, - le32_to_cpup (&req->td->dmacount), + readl (&ep->dma->dmacount), -ECONNRESET); + } } else { DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name); done (ep, req, -ECONNRESET); } req = 0; -#ifdef USE_DMA_CHAINING /* patch up hardware chaining data */ - } else if (ep->dma) { + } else if (ep->dma && use_dma_chaining) { if (req->queue.prev == ep->queue.next) { writel (le32_to_cpu (req->td->dmadesc), &ep->dma->dmadesc); @@ -1161,7 +1237,6 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) if (req->td->dmacount & dma_done_ie) prev->td->dmacount |= dma_done_ie; } -#endif } if (req) @@ -1188,10 +1263,14 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) /*-------------------------------------------------------------------------*/ +static int net2280_fifo_status (struct usb_ep *_ep); + static int net2280_set_halt (struct usb_ep *_ep, int value) { struct net2280_ep *ep; + unsigned long flags; + int retval = 0; ep = container_of (_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) @@ -1202,19 +1281,27 @@ net2280_set_halt (struct usb_ep *_ep, int value) == USB_ENDPOINT_XFER_ISOC) return -EINVAL; - VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear"); - - /* set/clear, then synch memory views with the device */ - if (value) { - if (ep->num == 0) - ep->dev->protocol_stall = 1; - else - set_halt (ep); - } else - clear_halt (ep); - (void) readl (&ep->regs->ep_rsp); + spin_lock_irqsave (&ep->dev->lock, flags); + if (!list_empty (&ep->queue)) + retval = -EAGAIN; + else if (ep->is_in && value && net2280_fifo_status (_ep) != 0) + retval = -EAGAIN; + else { + VDEBUG (ep->dev, "%s %s halt\n", _ep->name, + value ? "set" : "clear"); + /* set/clear, then synch memory views with the device */ + if (value) { + if (ep->num == 0) + ep->dev->protocol_stall = 1; + else + set_halt (ep); + } else + clear_halt (ep); + (void) readl (&ep->regs->ep_rsp); + } + spin_unlock_irqrestore (&ep->dev->lock, flags); - return 0; + return retval; } static int @@ -1290,21 +1377,49 @@ static int net2280_get_frame (struct usb_gadget *_gadget) static int net2280_wakeup (struct usb_gadget *_gadget) { struct net2280 *dev; + u32 tmp; + unsigned long flags; if (!_gadget) return 0; dev = container_of (_gadget, struct net2280, gadget); - writel (1 << GENERATE_RESUME, &dev->usb->usbstat); + + spin_lock_irqsave (&dev->lock, flags); + tmp = readl (&dev->usb->usbctl); + if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE)) + writel (1 << GENERATE_RESUME, &dev->usb->usbstat); + spin_unlock_irqrestore (&dev->lock, flags); /* pci writes may still be posted */ return 0; } +static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) +{ + struct net2280 *dev; + u32 tmp; + unsigned long flags; + + if (!_gadget) + return 0; + dev = container_of (_gadget, struct net2280, gadget); + + spin_lock_irqsave (&dev->lock, flags); + tmp = readl (&dev->usb->usbctl); + if (value) + tmp |= (1 << SELF_POWERED_STATUS); + else + tmp &= ~(1 << SELF_POWERED_STATUS); + writel (tmp, &dev->usb->usbctl); + spin_unlock_irqrestore (&dev->lock, flags); + + return 0; +} + static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, - - // .set_selfpowered = net2280_set_selfpowered, + .set_selfpowered = net2280_set_selfpowered, }; /*-------------------------------------------------------------------------*/ @@ -1348,11 +1463,14 @@ show_registers (struct device *_dev, char *buf) /* Main Control Registers */ t = snprintf (next, size, "%s version " DRIVER_VERSION - ", chiprev %04x\n" + ", chiprev %04x, dma %s\n\n" "devinit %03x fifoctl %08x gadget '%s'\n" "pci irqenb0 %02x irqenb1 %08x " "irqstat0 %04x irqstat1 %08x\n", driver_name, dev->chiprev, + use_dma + ? (use_dma_chaining ? "chaining" : "enabled") + : "disabled", readl (&dev->regs->devinit), readl (&dev->regs->fifoctl), s, @@ -1399,7 +1517,7 @@ show_registers (struct device *_dev, char *buf) t1 = readl (&ep->regs->ep_cfg); t2 = readl (&ep->regs->ep_rsp) & 0xff; t = snprintf (next, size, - "%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" + "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" "irqenb %02x\n", ep->ep.name, t1, t2, (t2 & (1 << CLEAR_NAK_OUT_PACKETS)) @@ -1453,7 +1571,7 @@ show_registers (struct device *_dev, char *buf) // none yet /* Statistics */ - t = snprintf (next, size, "irqs: "); + t = snprintf (next, size, "\nirqs: "); size -= t; next += t; for (i = 0; i < 7; i++) { @@ -1462,7 +1580,7 @@ show_registers (struct device *_dev, char *buf) ep = &dev->ep [i]; if (i && !ep->irqs) continue; - t = snprintf (next, size, " %s/%ld", ep->ep.name, ep->irqs); + t = snprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs); size -= t; next += t; @@ -1504,7 +1622,7 @@ show_queues (struct device *_dev, char *buf) continue; t = d->bEndpointAddress; t = snprintf (next, size, - "%s (ep%d%s-%s) max %04x %s\n", + "\n%s (ep%d%s-%s) max %04x %s fifo %d\n", ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, (t & USB_DIR_IN) ? "in" : "out", ({ char *val; @@ -1517,7 +1635,7 @@ show_queues (struct device *_dev, char *buf) val = "iso"; break; }; val; }), le16_to_cpu (d->wMaxPacketSize) & 0x1fff, - ep->dma ? "dma" : "pio" + ep->dma ? "dma" : "pio", ep->fifo_size ); } else /* ep0 should only have one transfer queued */ t = snprintf (next, size, "ep0 max 64 pio %s\n", @@ -1552,6 +1670,20 @@ show_queues (struct device *_dev, char *buf) goto done; size -= t; next += t; + + if (ep->dma) { + struct net2280_dma *td; + + td = req->td; + t = snprintf (next, size, "\t td %08x " + " count %08x buf %08x desc %08x\n", + req->td_dma, td->dmacount, + td->dmaaddr, td->dmadesc); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + } } } @@ -1686,8 +1818,10 @@ static void usb_reset (struct net2280 *dev) /* clear old dma and irq state */ for (tmp = 0; tmp < 4; tmp++) { - writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat); - stop_dma (&dev->dma [tmp]); + struct net2280_ep *ep = &dev->ep [tmp + 1]; + + if (ep->dma) + abort_dma (ep); } writel (~0, &dev->regs->irqstat0), writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), @@ -1767,7 +1901,7 @@ static void ep0_start (struct net2280 *dev) | (1 << SELF_POWERED_USB_DEVICE) | (1 << REMOTE_WAKEUP_SUPPORT) | (1 << USB_DETECT_ENABLE) - | (1 << DEVICE_REMOTE_WAKEUP_ENABLE) + | (1 << SELF_POWERED_STATUS) , &dev->usb->usbctl); /* enable irqs so we can see ep0 and general operation */ @@ -1889,6 +2023,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 = 0; dev->driver = 0; net2280_led_active (dev, 0); @@ -1947,6 +2082,8 @@ static void handle_ep_small (struct net2280_ep *ep) ep->stopped = 1; set_halt (ep); } + if (!req) + allow_status (ep); mode = 2; /* reply to extra IN data tokens with a zlp */ } else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { @@ -1987,41 +2124,62 @@ static void handle_ep_small (struct net2280_ep *ep) if (likely (ep->dma != 0)) { if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { u32 count; + int stopped = ep->stopped; /* TRANSFERRED works around OUT_DONE erratum 0112. * we expect (N <= maxpacket) bytes; host wrote M. * iff (M < N) we won't ever see a DMA interrupt. */ - count = readl (&ep->dma->dmacount); - count &= DMA_BYTE_COUNT_MASK; - if (!req->dma_done) { - /* dma can finish with the FIFO non-empty, - * on (M > N) errors. + ep->stopped = 1; + for (count = 0; ; t = readl (&ep->regs->ep_stat)) { + + /* any preceding dma transfers must finish. + * dma handles (M >= N), may empty the queue + */ + scan_dma_completions (ep); + if (unlikely (list_empty (&ep->queue) + || ep->out_overflow)) { + req = 0; + break; + } + req = list_entry (ep->queue.next, + struct net2280_request, queue); + + /* here either (M < N), a "real" short rx; + * or (M == N) and the queue didn't empty */ - while (count && (t & (1 << FIFO_EMPTY)) == 0) { - cpu_relax (); - t = readl (&ep->regs->ep_stat); + if (likely (t & (1 << FIFO_EMPTY))) { count = readl (&ep->dma->dmacount); count &= DMA_BYTE_COUNT_MASK; + if (readl (&ep->dma->dmadesc) + != req->td_dma) + req = 0; + break; } + udelay(1); } /* stop DMA, leave ep NAKing */ writel ((1 << DMA_ABORT), &ep->dma->dmastat); spin_stop_dma (ep->dma); - /* buffer might have been too small */ - t = readl (&ep->regs->ep_avail); - if (t != 0) - DEBUG (ep->dev, "%s dma, discard %d len %d\n", - ep->ep.name, t, count); - dma_done (ep, req, count, t ? -EOVERFLOW : 0); + if (likely (req)) { + req->td->dmacount = 0; + t = readl (&ep->regs->ep_avail); + dma_done (ep, req, count, t); + } /* also flush to prevent erratum 0106 trouble */ - if (t || ep->dev->chiprev == 0x0100) + if (unlikely (ep->out_overflow + || (ep->dev->chiprev == 0x0100 + && ep->dev->gadget.speed + == USB_SPEED_FULL))) { out_flush (ep); + ep->out_overflow = 0; + } - /* restart dma (still NAKing OUT!) if needed */ + /* (re)start dma if needed, stop NAKing */ + ep->stopped = stopped; if (!list_empty (&ep->queue)) restart_dma (ep); } else @@ -2192,11 +2350,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) * that'll mean a lot less irqs for some drivers. */ ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; - if (ep->is_in) + if (ep->is_in) { scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | (1 << DATA_IN_TOKEN_INTERRUPT); - else + stop_out_naking (ep); + } else scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT) | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | (1 << DATA_IN_TOKEN_INTERRUPT); @@ -2398,18 +2557,18 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) tmp = readl (&dma->dmastat); writel (tmp, &dma->dmastat); -#ifdef USE_DMA_CHAINING - /* chaining should stop only on error (which?) + /* chaining should stop on abort, short OUT from fifo, * or (stat0 codepath) short OUT transfer. */ -#else - if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) { - DEBUG (ep->dev, "%s no xact done? %08x\n", - ep->ep.name, tmp); - continue; + if (!use_dma_chaining) { + if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) + == 0) { + DEBUG (ep->dev, "%s no xact done? %08x\n", + ep->ep.name, tmp); + continue; + } + stop_dma (ep->dma); } - stop_dma (ep->dma); -#endif /* OUT transfers terminate when the data from the * host is in our memory. Process whatever's done. @@ -2425,16 +2584,14 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) /* disable dma on inactive queues; else maybe restart */ if (list_empty (&ep->queue)) { -#ifdef USE_DMA_CHAINING - stop_dma (ep->dma); -#endif + if (use_dma_chaining) + stop_dma (ep->dma); } else { tmp = readl (&dma->dmactl); - if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0 + if (!use_dma_chaining || (tmp & (1 << DMA_ENABLE)) == 0) restart_dma (ep); -#ifdef USE_DMA_CHAINING - else if (ep->desc->bEndpointAddress & USB_DIR_IN) { + else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; u32 dmacount; @@ -2449,12 +2606,9 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) dmacount &= __constant_cpu_to_le32 ( (1 << VALID_BIT) | DMA_BYTE_COUNT_MASK); - if (dmacount && (dmacount & valid_bit) == 0) { - stop_dma (ep->dma); + if (dmacount && (dmacount & valid_bit) == 0) restart_dma (ep); - } } -#endif } ep->irqs++; } @@ -2505,7 +2659,7 @@ static void gadget_release (struct device *_dev) /* tear down the binding between this driver and the pci device */ -static void net2280_remove (struct pci_dev *pdev) +static void __exit net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); @@ -2665,12 +2819,14 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } td->dmacount = 0; /* not VALID */ td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID); + td->dmadesc = td->dmaaddr; dev->ep [i].dummy = td; } /* enable lower-overhead pci memory bursts during DMA */ - writel ((1 << PCI_RETRY_ABORT_ENABLE) - | (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) + writel ( (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) + // 256 write retries may not be enough... + // | (1 << PCI_RETRY_ABORT_ENABLE) | (1 << DMA_READ_MULTIPLE_ENABLE) | (1 << DMA_READ_LINE_ENABLE) , &dev->pci->pcimstctl); @@ -2686,15 +2842,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) INFO (dev, "%s\n", driver_desc); INFO (dev, "irq %s, pci mem %p, chip rev %04x\n", bufp, base, dev->chiprev); - bufp = DRIVER_VERSION -#ifndef USE_DMA_CHAINING - " (no dma chain)" -#endif -#ifdef NET2280_DMA_OUT_WORKAROUND - " (no dma out)" -#endif - ; - INFO (dev, "version: %s\n", bufp); + INFO (dev, "version: " DRIVER_VERSION "; dma %s\n", + use_dma + ? (use_dma_chaining ? "chaining" : "enabled") + : "disabled"); the_controller = dev; device_register (&dev->gadget.dev); @@ -2729,7 +2880,7 @@ static struct pci_driver net2280_pci_driver = { .id_table = pci_ids, .probe = net2280_probe, - .remove = net2280_remove, + .remove = __exit_p(net2280_remove), /* FIXME add power management support */ }; @@ -2740,6 +2891,8 @@ MODULE_LICENSE ("GPL"); static int __init init (void) { + if (!use_dma) + use_dma_chaining = 0; return pci_module_init (&net2280_pci_driver); } module_init (init); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index d6af2e86bdf86cad2277e3f30eff725feb1653be..ec9d6f7e7cfcd90503dbd1223d1c4fb1a029141b 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -520,6 +520,7 @@ struct net2280_ep { unsigned num : 8, fifo_size : 12, in_fifo_validate : 1, + out_overflow : 1, stopped : 1, is_in : 1, is_iso : 1; @@ -529,6 +530,7 @@ static inline void allow_status (struct net2280_ep *ep) { /* ep0 only */ writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + | (1 << CLEAR_NAK_OUT_PACKETS) | (1 << CLEAR_NAK_OUT_PACKETS_MODE) , &ep->regs->ep_rsp); ep->stopped = 1; @@ -546,7 +548,6 @@ struct net2280_request { dma_addr_t td_dma; struct list_head queue; unsigned mapped : 1, - dma_done : 1, valid : 1; }; @@ -559,8 +560,7 @@ struct net2280 { unsigned enabled : 1, protocol_stall : 1, got_irq : 1, - region : 1, - selfpowered : 1; + region : 1; u16 chiprev; /* pci state used to access those endpoints */ diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 3ac41bbdfa67bda6f7180ebf7377b1878104ab84..158ebd8e1dd4824a7fa9278201e297ca3cbd42d5 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -135,9 +135,6 @@ do { \ #define GS_NUM_PORTS 16 -#define GS_VENDOR_ID 0x05F9 -#define GS_PRODUCT_ID 0xFFFF - #define GS_NUM_CONFIGS 1 #define GS_NO_CONFIG_ID 0 #define GS_BULK_CONFIG_ID 2 @@ -187,7 +184,7 @@ static int debug = G_SERIAL_DEBUG; * DMA channels to manage their FIFOs. It supports high speed. * Those endpoints can be arranged in any desired configuration. */ -#ifdef CONFIG_USB_G_SERIAL_NET2280 +#ifdef CONFIG_USB_GADGET_NET2280 #define CHIP "net2280" #define EP0_MAXPACKET 64 static const char EP_OUT_NAME[] = "ep-a"; @@ -220,13 +217,13 @@ static inline void hw_optimize(struct usb_gadget *gadget) * can't use altsettings or reset the interfaces independently. * So stick to a single interface. */ -#ifdef CONFIG_USB_G_SERIAL_PXA2XX +#ifdef CONFIG_USB_GADGET_PXA2XX #define CHIP "pxa2xx" #define EP0_MAXPACKET 16 -static const char EP_OUT_NAME[] = "ep12out-bulk"; -#define EP_OUT_NUM 12 -static const char EP_IN_NAME[] = "ep11in-bulk"; -#define EP_IN_NUM 11 +static const char EP_OUT_NAME[] = "ep2out-bulk"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME[] = "ep1in-bulk"; +#define EP_IN_NUM 1 #define SELFPOWER USB_CONFIG_ATT_SELFPOWER /* no hw optimizations to apply */ @@ -245,7 +242,7 @@ static const char EP_IN_NAME[] = "ep11in-bulk"; * in special situations. So this is a case of "choose it right * during enumeration" ... */ -#ifdef CONFIG_USB_G_SERIAL_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 #define CHIP "sa1100" #define EP0_MAXPACKET 8 static const char EP_OUT_NAME[] = "ep1out-bulk"; @@ -264,7 +261,7 @@ static const char EP_IN_NAME [] = "ep2in-bulk"; * * This has three semi-configurable full speed bulk/interrupt endpoints. */ -#ifdef CONFIG_USB_G_SERIAL_GOKU +#ifdef CONFIG_USB_GADGET_GOKU #define CHIP "goku" #define DRIVER_VERSION_NUM 0x0116 #define EP0_MAXPACKET 8 @@ -302,6 +299,14 @@ static const char EP_IN_NAME [] = "ep2-bulk"; /* else value must be USB_CONFIG_ATT_WAKEUP */ #endif +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define GS_VENDOR_ID 0x0525 /* NetChip */ +#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */ + /* Structures */ diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index e5e6f4b5b1d48bc8d9129eb3b3fedaf3d9e159eb..704183437a76ffa652b100396de1347233267375 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -131,7 +131,7 @@ static const char loopback [] = "loop input to output"; * DMA channels to manage their FIFOs. It supports high speed. * Those endpoints can be arranged in any desired configuration. */ -#ifdef CONFIG_USB_ZERO_NET2280 +#if defined(CONFIG_USB_GADGET_NET2280) || defined(CONFIG_USB_GADGET_DUMMY_HCD) #define CHIP "net2280" #define DRIVER_VERSION_NUM 0x0101 static const char EP_OUT_NAME [] = "ep-a"; @@ -154,7 +154,7 @@ static const char EP_IN_NAME [] = "ep-b"; * can't use altsettings or reset the interfaces independently. * So stick to a single interface. */ -#ifdef CONFIG_USB_ZERO_PXA2XX +#ifdef CONFIG_USB_GADGET_PXA2XX #define CHIP "pxa2xx" #define DRIVER_VERSION_NUM 0x0103 static const char EP_OUT_NAME [] = "ep12out-bulk"; @@ -176,7 +176,7 @@ static const char EP_IN_NAME [] = "ep11in-bulk"; * in special situations. So this is a case of "choose it right * during enumeration" ... */ -#ifdef CONFIG_USB_ZERO_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 #define CHIP "sa1100" #define DRIVER_VERSION_NUM 0x0105 static const char EP_OUT_NAME [] = "ep1out-bulk"; @@ -192,7 +192,7 @@ static const char EP_IN_NAME [] = "ep2in-bulk"; * * This has three semi-configurable full speed bulk/interrupt endpoints. */ -#ifdef CONFIG_USB_ZERO_GOKU +#ifdef CONFIG_USB_GADGET_GOKU #define CHIP "goku" #define DRIVER_VERSION_NUM 0x0106 static const char EP_OUT_NAME [] = "ep1-bulk"; @@ -936,7 +936,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) if (number == dev->config) return 0; -#ifdef CONFIG_USB_ZERO_SA1100 +#ifdef CONFIG_USB_GADGET_SA1100 if (dev->config) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 83076a7801ddab9312a87e065670c1d21ecbf830..168c9e9edcc4ae6a3044cea33dcbfc0f10b4ed05 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -684,6 +684,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-sa1111.c" #endif -#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111)) +#ifdef CONFIG_ARCH_OMAP +#include "ohci-omap.c" +#endif + +#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111) || defined(CONFIG_ARCH_OMAP)) #error "missing bus glue for ohci-hcd" #endif diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c new file mode 100644 index 0000000000000000000000000000000000000000..d664ed24f9873fbc9ee211fc58cfaacad9954e96 --- /dev/null +++ b/drivers/usb/host/ohci-omap.c @@ -0,0 +1,673 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> + * (C) Copyright 2002 Hewlett-Packard Company + * + * OMAP Bus Glue + * + * Written by Christopher Hoover <ch@hpl.hp.com> + * Based on fragments of previous driver by Rusell King et al. + * + * Modified for OMAP from ohci-sa1111.c by Tony Lindgren <tony@atomide.com> + * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc. + * + * This file is licenced under the GPL. + */ + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/io.h> + +#include <asm/arch/bus.h> +#include <asm/arch/hardware.h> +#include <asm/arch/mux.h> +#include <asm/arch/irqs.h> + +#include "ohci-omap.h" + +#ifndef CONFIG_ARCH_OMAP +#error "This file is OMAP bus glue. CONFIG_OMAP must be defined." +#endif + +extern int usb_disabled(void); +extern int ocpi_enable(void); + +/* + * Use the first port only by default. Override with hmc_mode option. + * + * NOTE: Many OMAP-1510 Innovators supposedly have bad wiring for the USB ports + * 1 & 2, so only port 0 will work. To use the OHCI on the first port, use + * the Innovator USB client cable with a client-to-client connector and modify + * either the cable or the hub to feed 5V VBUS back to Innovator. VBUS should + * be the red lead in the cable. + * + * To mount USB hard disk as root, see the patch for do_mounts.c that tries + * remounting the root, and use root=0801 if your root is on sda1. Does not + * work with devfs. + */ +static int default_hmc_mode = 16; +static int hmc_mode = 1234; + +/* + * Set the USB host pin multiplexing and the selected HMC mode + */ +static int omap_usb_set_hmc_mode(int hmc_mode) +{ + unsigned int val; + + switch (hmc_mode) { + case 0: + /* 0: function, 1: disabled, 2: disabled */ + omap_cfg_reg(W4_USB_PUEN); + omap_cfg_reg(R18_1510_USB_GPIO0); + break; + case 4: + /* 0: function 1: host 2: host */ + omap_cfg_reg(usb1_speed); + omap_cfg_reg(usb1_susp); + omap_cfg_reg(usb1_seo); + omap_cfg_reg(usb1_txen); + omap_cfg_reg(usb1_txd); + omap_cfg_reg(usb1_vp); + omap_cfg_reg(usb1_vm); + omap_cfg_reg(usb1_rcv); + omap_cfg_reg(usb2_susp); + omap_cfg_reg(usb2_seo); + omap_cfg_reg(usb2_txen); + omap_cfg_reg(usb2_txd); + omap_cfg_reg(usb2_vp); + omap_cfg_reg(usb2_vm); + omap_cfg_reg(usb2_rcv); + break; + case 16: + /* 0: host, 1: disabled, 2: disabled */ + omap_cfg_reg(W9_USB0_TXEN); + omap_cfg_reg(AA9_USB0_VP); + omap_cfg_reg(Y5_USB0_RCV); + omap_cfg_reg(R9_USB0_VM); + omap_cfg_reg(V6_USB0_TXD); + omap_cfg_reg(W5_USB0_SE0); + break; + default: + printk("Unknown USB host configuration: %i\n", hmc_mode); + return -ENODEV; + } + + /* Write the selected HMC mode */ + val = readl(MOD_CONF_CTRL_0) & ~HMC_CLEAR; + val |= (hmc_mode << 1); + writel(val, MOD_CONF_CTRL_0); + + return 0; +} + +/* + * OHCI clock initialization for OMAP-1510 and 1610 + */ +static int omap_ohci_clock_power(int on) +{ + if (on) { + if (cpu_is_omap_1510()) { + /* Use DPLL, not APLL */ + writel(readl(ULPD_APLL_CTRL_REG) & ~APLL_NDPLL_SWITCH, + ULPD_APLL_CTRL_REG); + + /* Enable DPLL */ + writel(readl(ULPD_DPLL_CTRL_REG) | DPLL_PLL_ENABLE, + ULPD_DPLL_CTRL_REG); + + /* Software request for USB 48MHz clock */ + writel(readl(ULPD_SOFT_REQ_REG) | SOFT_REQ_REG_REQ, + ULPD_SOFT_REQ_REG); + + while (!(readl(ULPD_DPLL_CTRL_REG) & DPLL_LOCK)); + } + + if (cpu_is_omap_1610()) { + /* Enable OHCI */ + writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_OTG_REQ, + ULPD_SOFT_REQ_REG); + + /* USB host clock request if not using OTG */ + writel(readl(ULPD_SOFT_REQ_REG) | SOFT_USB_REQ, + ULPD_SOFT_REQ_REG); + + outl(inl(ULPD_STATUS_REQ_REG) | USB_HOST_DPLL_REQ, + ULPD_STATUS_REQ_REG); + } + + /* Enable 48MHz clock to USB */ + writel(readl(ULPD_CLOCK_CTRL_REG) | USB_MCLK_EN, + ULPD_CLOCK_CTRL_REG); + + writel(readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), + ARM_IDLECT2); + + writel(readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, + MOD_CONF_CTRL_0); + } else { + /* Disable 48MHz clock to USB */ + writel(readl(ULPD_CLOCK_CTRL_REG) & ~USB_MCLK_EN, + ULPD_CLOCK_CTRL_REG); + + /* FIXME: The DPLL stays on for now */ + } + + return 0; +} + +/* + * Hardware specific transceiver power on/off + */ +static int omap_ohci_transceiver_power(int on) +{ + if (on) { + if (omap_is_innovator()) + writel(readl(OMAP1510_FPGA_HOST_CTRL) | 0x20, + OMAP1510_FPGA_HOST_CTRL); + } else { + if (omap_is_innovator()) + writel(readl(OMAP1510_FPGA_HOST_CTRL) & ~0x20, + OMAP1510_FPGA_HOST_CTRL); + } + + return 0; +} + +/* + * OMAP-1510 specific Local Bus clock on/off + */ +static int omap_1510_local_bus_power(int on) +{ + if (on) { + writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); + udelay(200); + } else { + writel(0, OMAP1510_LB_MMU_CTL); + } + + return 0; +} + +/* + * OMAP-1510 specific Local Bus initialization + * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. + * See also arch/mach-omap/memory.h for __virt_to_bus() and + * __bus_to_virt() which need to match with the physical + * Local Bus address below. + */ +static int omap_1510_local_bus_init(void) +{ + unsigned int tlb; + unsigned long lbaddr, physaddr; + + writel((readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, + OMAP1510_LB_CLOCK_DIV); + + /* Configure the Local Bus MMU table */ + for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { + lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; + physaddr = tlb * 0x00100000 + PHYS_OFFSET; + writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); + writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, + OMAP1510_LB_MMU_CAM_L); + writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); + writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); + writel(tlb << 4, OMAP1510_LB_MMU_LCK); + writel(0x1, OMAP1510_LB_MMU_LD_TLB); + } + + /* Enable the walking table */ + writel(readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); + udelay(200); + + return 0; +} + +/* + * OMAP-1610 specific hardware initialization + * + * Intended to configure OMAP-1610 USB host and OTG ports depending on + * the HMC mode selected. + * + * FIXME: Currently only supports alternate ping group 2 mode, should + * be easy to modify for other configurations once there is some + * hardware to test with. + */ +static int omap_1610_usb_init(int mode) +{ + u_int val = 0; + + /* Configure the OMAP transceiver settings */ + val |= (1 << 8); /* CONF_USB2_UNI TRM p 15-205*/ + val |= (4 << 4); /* TRM p 5-59, p 15-157 (1224) */ + + //val |= (1 << 3); /* Isolate integrated transceiver from port 0 */ + val |= (1 << 2); /* Disable pulldown on integrated transceiver DM */ + val |= (1 << 1); /* Disable pulldown on integraded transceiver DP */ + + outl(val, USB_TRANSCEIVER_CTRL); + + /* Set the USB0_TRX_MODE */ + val = 0; + val &= ~OTG_IDLE_EN; + val &= ~DEV_IDLE_EN; + val &= ~(7 << 16); /* Clear USB0_TRX_MODE */ + val |= (3 << 16); /* 0 or 3, 6-wire DAT/SE0, TRM p 15-159 */ + outl(val, OTG_SYSCON_1); + + /* + * Control via OTG, see TRM p 15-163 + */ + val = 0; + //val |= 1; /* REVISIT: Enable OTG = 1 */ + + /* Control via OTG */ + val &= ~HMC_PADEN; + val &= ~OTG_PADEN; + val |= UHOST_EN; + + val &= ~0x3f; /* Clear HMC mode */ + val |= mode; /* Set HMC mode */ + val &= ~(7 << 16); /* Clear ASE0_BRST */ + val |= (4 << 16); /* Must be 4 */ + val |= USBX_SYNCHRO; /* Must be set */ + val |= SRP_VBUS; + outl(val, OTG_SYSCON_2); + + /* Enable OTG idle */ + //outl(inl(OTG_SYSCON_1) | OTG_IDLE_EN, OTG_SYSCON_1); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void omap_start_hc(struct omap_dev *dev) +{ + printk(KERN_DEBUG __FILE__ + ": starting OMAP OHCI USB Controller\n"); + + /* + * Set the HMC mode for the USB ports + */ +#if 0 + /* See note about the Innovator wiring above */ + if (omap_is_innovator()) + hmc_mode = 4; /* 0: function 1: host 2: host */ +#endif + + if (cpu_is_omap_1610()) + ocpi_enable(); + + omap_usb_set_hmc_mode(hmc_mode); + + omap_ohci_clock_power(1); + omap_ohci_transceiver_power(1); + + if (cpu_is_omap_1510()) { + omap_1510_local_bus_power(1); + omap_1510_local_bus_init(); + } + + if (cpu_is_omap_1610()) + omap_1610_usb_init(hmc_mode); + + //omap_enable_device(dev); +} + +static void omap_stop_hc(struct omap_dev *dev) +{ + printk(KERN_DEBUG __FILE__ + ": stopping OMAP OHCI USB Controller\n"); + + /* + * FIXME: Put the USB host controller into reset. + */ + + /* + * FIXME: Stop the USB clock. + */ + //omap_disable_device(dev); + +} + + +/*-------------------------------------------------------------------------*/ + +static irqreturn_t usb_hcd_omap_hcim_irq (int irq, void *__hcd, struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + + return usb_hcd_irq(irq, hcd, r); +} + +/*-------------------------------------------------------------------------*/ + +void usb_hcd_omap_remove (struct usb_hcd *, struct omap_dev *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_omap_probe - initialize OMAP-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_omap_probe (const struct hc_driver *driver, + struct usb_hcd **hcd_out, + struct omap_dev *dev) +{ + int retval; + struct usb_hcd *hcd = 0; + + if (!request_mem_region(dev->res.start, + dev->res.end - dev->res.start + 1, hcd_name)) { + dbg("request_mem_region failed"); + return -EBUSY; + } + + omap_start_hc(dev); + + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd_alloc failed"); + retval = -ENOMEM; + goto err1; + } + + hcd->driver = (struct hc_driver *) driver; + hcd->description = driver->description; + hcd->irq = dev->irq[0]; + hcd->regs = dev->mapbase; + hcd->pdev = OMAP_FAKE_PCIDEV; + hcd->self.controller = &dev->dev; + hcd->controller = hcd->self.controller; + + retval = hcd_buffer_create (hcd); + if (retval != 0) { + dbg ("pool alloc fail"); + goto err1; + } + + retval = request_irq (hcd->irq, + usb_hcd_omap_hcim_irq, + SA_INTERRUPT, hcd->description, hcd); + if (retval != 0) { + dbg("request_irq failed"); + retval = -EBUSY; + goto err2; + } + + info ("%s (OMAP) at 0x%p, irq %d\n", + hcd->description, hcd->regs, hcd->irq); + + usb_bus_init (&hcd->self); + hcd->self.op = &usb_hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->self.bus_name = "omap"; + hcd->product_desc = "OMAP OHCI"; + + INIT_LIST_HEAD (&hcd->dev_list); + usb_register_bus (&hcd->self); + + if ((retval = driver->start (hcd)) < 0) + { + usb_hcd_omap_remove(hcd, dev); + return retval; + } + + *hcd_out = hcd; + return 0; + + err2: + hcd_buffer_destroy (hcd); + if (hcd) + driver->hcd_free(hcd); + err1: + omap_stop_hc(dev); + + release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); + + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_omap_remove - shutdown processing for OMAP-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_omap_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_omap_remove (struct usb_hcd *hcd, struct omap_dev *dev) +{ + struct usb_device *hub; + void *base; + + info ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + + if (in_interrupt ()) + BUG (); + + hub = hcd->self.root_hub; + hcd->state = USB_STATE_QUIESCING; + + dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); + usb_disconnect (&hub); + + hcd->driver->stop (hcd); + hcd_buffer_destroy (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + + usb_deregister_bus (&hcd->self); + + base = hcd->regs; + hcd->driver->hcd_free (hcd); + + omap_stop_hc(dev); + + release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_omap_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + if (hcd->pdev) { + ohci->hcca = pci_alloc_consistent (hcd->pdev, + sizeof *ohci->hcca, &ohci->hcca_dma); + if (!ohci->hcca) + return -ENOMEM; + } + + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + if ((ret = ohci_mem_init (ohci)) < 0) { + ohci_stop (hcd); + return ret; + } + ohci->regs = hcd->regs; + if (hc_reset (ohci) < 0) { + ohci_stop (hcd); + return -ENODEV; + } + + if (hc_start (ohci) < 0) { + err ("can't start %s", ohci->hcd.self.bus_name); + ohci_stop (hcd); + return -EBUSY; + } + create_debug_files (ohci); + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_omap_hc_driver = { + .description = hcd_name, + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_omap_start, +#ifdef CONFIG_PM + /* suspend: ohci_omap_suspend, -- tbd */ + /* resume: ohci_omap_resume, -- tbd */ +#endif + .stop = ohci_stop, + + /* + * memory lifecycle (except per-request) + */ + .hcd_alloc = ohci_hcd_alloc, + .hcd_free = ohci_hcd_free, + + /* + * 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, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_omap_drv_probe(struct omap_dev *dev) +{ + struct usb_hcd *hcd = NULL; + int ret; + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_omap_probe(&ohci_omap_hc_driver, &hcd, dev); + + if (ret == 0) + omap_set_drvdata(dev, hcd); + + return ret; +} + +static int ohci_hcd_omap_drv_remove(struct omap_dev *dev) +{ + struct usb_hcd *hcd = omap_get_drvdata(dev); + + usb_hcd_omap_remove(hcd, dev); + + omap_set_drvdata(dev, NULL); + + return 0; +} + +/* + * Driver definition to register with the OMAP bus + */ +static struct omap_driver ohci_hcd_omap_driver = { + .drv = { + .name = OMAP_OHCI_NAME, + }, + .devid = OMAP_OCP_DEVID_USB, + .busid = OMAP_BUS_OCP, + .clocks = 0, + .probe = ohci_hcd_omap_drv_probe, + .remove = ohci_hcd_omap_drv_remove, +}; + +/* Any dma_mask must be set for OHCI to work */ +static u64 omap_dmamask = 0xffffffffUL; + +/* + * Device definition to match the driver above + */ +static struct omap_dev ohci_hcd_omap_device = { + .name = OMAP_OHCI_NAME, + .devid = OMAP_OCP_DEVID_USB, + .busid = OMAP_BUS_OCP, + .mapbase = (void *)OMAP_OHCI_BASE, + .dma_mask = &omap_dmamask, /* Needed only for OHCI */ + .res = { + .start = OMAP_OHCI_BASE, + .end = OMAP_OHCI_BASE + OMAP_OHCI_SIZE, + }, + .irq = { + INT_OHCI, + }, +}; + +static int __init ohci_hcd_omap_init (void) +{ + int ret; + + dbg (DRIVER_INFO " (OMAP)"); + dbg ("block sizes: ed %d td %d\n", + sizeof (struct ed), sizeof (struct td)); + + if (hmc_mode < 0 || hmc_mode > 25) + hmc_mode = default_hmc_mode; + + /* Register the driver with OMAP bus */ + ret = omap_driver_register(&ohci_hcd_omap_driver); + if (ret != 0) + return -ENODEV; + + /* Register the device with OMAP bus */ + ret = omap_device_register(&ohci_hcd_omap_device); + if (ret != 0) { + omap_driver_unregister(&ohci_hcd_omap_driver); + return -ENODEV; + } + + return ret; +} + +MODULE_PARM(hmc_mode, "hmc_mode"); + +static void __exit ohci_hcd_omap_cleanup (void) +{ + omap_device_unregister(&ohci_hcd_omap_device); + omap_driver_unregister(&ohci_hcd_omap_driver); +} + +module_init (ohci_hcd_omap_init); +module_exit (ohci_hcd_omap_cleanup); diff --git a/drivers/usb/host/ohci-omap.h b/drivers/usb/host/ohci-omap.h new file mode 100644 index 0000000000000000000000000000000000000000..58ae2b40008f667cb02a25e4ea94e59485facef6 --- /dev/null +++ b/drivers/usb/host/ohci-omap.h @@ -0,0 +1,57 @@ +/* + * linux/drivers/usb/host/ohci-omap.h + * + * OMAP OHCI USB controller specific defines + */ + +/* OMAP USB OHCI common defines */ +#define OMAP_OHCI_NAME "omap-ohci" +#define OMAP_OHCI_BASE 0xfffba000 +#define OMAP_OHCI_SIZE 4096 + +#define HMC_CLEAR (0x3f << 1) +#define APLL_NDPLL_SWITCH 0x0001 +#define DPLL_PLL_ENABLE 0x0010 +#define DPLL_LOCK 0x0001 +#define SOFT_REQ_REG_REQ 0x0001 +#define USB_MCLK_EN 0x0010 +#define USB_HOST_HHC_UHOST_EN 0x00000200 +#define SOFT_USB_OTG_REQ (1 << 8) +#define SOFT_USB_REQ (1 << 3) +#define STATUS_REQ_REG 0xfffe0840 +#define USB_HOST_DPLL_REQ (1 << 8) +#define SOFT_DPLL_REQ (1 << 0) + +/* OMAP-1510 USB OHCI defines */ +#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ +#define OMAP1510_LB_CLOCK_DIV 0xfffec10c +#define OMAP1510_LB_MMU_CTL 0xfffec208 +#define OMAP1510_LB_MMU_LCK 0xfffec224 +#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 +#define OMAP1510_LB_MMU_CAM_H 0xfffec22c +#define OMAP1510_LB_MMU_CAM_L 0xfffec230 +#define OMAP1510_LB_MMU_RAM_H 0xfffec234 +#define OMAP1510_LB_MMU_RAM_L 0xfffec238 + +/* OMAP-1610 USB OHCI defines */ +#define USB_TRANSCEIVER_CTRL 0xfffe1064 +#define OTG_REV 0xfffb0400 + +#define OTG_SYSCON_1 0xfffb0404 +#define OTG_IDLE_EN (1 << 15) +#define DEV_IDLE_EN (1 << 13) + +#define OTG_SYSCON_2 0xfffb0408 +#define OTG_CTRL 0xfffb040c +#define OTG_IRQ_EN 0xfffb0410 +#define OTG_IRQ_SRC 0xfffb0414 + +#define OTG_EN (1 << 31) +#define USBX_SYNCHRO (1 << 30) +#define SRP_VBUS (1 << 12) +#define OTG_PADEN (1 << 10) +#define HMC_PADEN (1 << 9) +#define UHOST_EN (1 << 8) + +/* Hardware specific defines */ +#define OMAP1510_FPGA_HOST_CTRL 0xe800020c diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index cce0dbb55b7d1dde4f840f0109baf7b0eb273f66..4510ace39d2a4f9306e0c0fbd4a3b9b2c74fcff2 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -781,17 +781,25 @@ static int dabusb_probe (struct usb_interface *intf, static void dabusb_disconnect (struct usb_interface *intf) { + wait_queue_t __wait; pdabusb_t s = usb_get_intfdata (intf); dbg("dabusb_disconnect"); - + + init_waitqueue_entry(&__wait, current); + usb_set_intfdata (intf, NULL); if (s) { usb_deregister_dev (intf, &dabusb_class); s->remove_pending = 1; wake_up (&s->wait); + add_wait_queue(&s->remove_ok, &__wait); + set_current_state(TASK_UNINTERRUPTIBLE); if (s->state == _started) - sleep_on (&s->remove_ok); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&s->remove_ok, &__wait); + s->usbdev = NULL; s->overruns = 0; } diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4b43ea5972d11940616570256068a3ce11288906..521597f375c0e1934a5138dd73a6cec6f52ae766 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -6,6 +6,7 @@ comment "USB Miscellaneous drivers" config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" + depends on USB ---help--- This driver loads firmware to Emagic EMI 6|2m low latency USB Audio and Midi interface. @@ -20,6 +21,7 @@ config USB_EMI62 config USB_EMI26 tristate "EMI 2|6 USB Audio interface support" + depends on USB ---help--- This driver loads firmware to Emagic EMI 2|6 low latency USB Audio interface. diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index a8f581e58df576cf300debbc44cf77bfe01de8f7..b137da951670e9e2b3791b3ca2bb8b9199f6eede 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1927,7 +1927,6 @@ static int auerswald_probe (struct usb_interface *intf, { struct usb_device *usbdev = interface_to_usbdev(intf); pauerswald_t cp = NULL; - DECLARE_WAIT_QUEUE_HEAD (wqh); unsigned int u = 0; char *pbuf; int ret; @@ -1975,7 +1974,8 @@ static int auerswald_probe (struct usb_interface *intf, dbg ("Version is %X", cp->version); /* allow some time to settle the device */ - sleep_on_timeout (&wqh, HZ / 3 ); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/3); /* Try to get a suitable textual description of the device */ /* Device name:*/ diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c index 5ee81f7d95774944ab36348e4e0cc78018860ebf..85c32711e768d36a9a22cbb3e3752bc52d833942 100644 --- a/drivers/usb/misc/tiglusb.c +++ b/drivers/usb/misc/tiglusb.c @@ -161,7 +161,7 @@ tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos) int bytes_to_read = 0; int bytes_read = 0; int result = 0; - char buffer[BULK_RCV_MAX]; + char *buffer; unsigned int pipe; if (*f_pos) @@ -173,6 +173,10 @@ tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos) if (!s->dev) return -EIO; + buffer = kmalloc(BULK_RCV_MAX, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count; pipe = usb_rcvbulkpipe (s->dev, 1); @@ -203,6 +207,7 @@ tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos) } out: + kfree(buffer); return ret ? ret : bytes_read; } @@ -214,7 +219,7 @@ tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * int bytes_to_write = 0; int bytes_written = 0; int result = 0; - char buffer[BULK_SND_MAX]; + char *buffer; unsigned int pipe; if (*f_pos) @@ -226,6 +231,10 @@ tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * if (!s->dev) return -EIO; + buffer = kmalloc(BULK_SND_MAX, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count; if (copy_from_user (buffer, buf, bytes_to_write)) { ret = -EFAULT; @@ -258,6 +267,7 @@ tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * } out: + kfree(buffer); return ret ? ret : bytes_written; } @@ -387,7 +397,11 @@ tiglusb_probe (struct usb_interface *intf, static void tiglusb_disconnect (struct usb_interface *intf) { + wait_queue_t __wait; ptiglusb_t s = usb_get_intfdata (intf); + + init_waitqueue_entry(&__wait, current); + usb_set_intfdata (intf, NULL); if (!s || !s->dev) { @@ -397,8 +411,12 @@ tiglusb_disconnect (struct usb_interface *intf) s->remove_pending = 1; wake_up (&s->wait); + add_wait_queue(&s->wait, &__wait); + set_current_state(TASK_UNINTERRUPTIBLE); if (s->state == _started) - sleep_on (&s->remove_ok); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&s->wait, &__wait); down (&s->mutex); s->dev = NULL; s->opened = 0; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index cb588ec79c5a055e3db3b0e94ed2ddc567c3954f..2bf6eb109524bffcb30d049354cf98203548a88f 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -651,7 +651,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, return 0; case TCSETS: // 0x5402 - if (! &port->tty->termios) { + if (!(port->tty->termios)) { dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); return -ENOTTY; } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index c398585976f7a486a0c7799dcb07b44f36e5bc83..412d2173d521a6891dd4f341b54bd2a9c45b053c 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -353,8 +353,8 @@ static int whiteheat_attach (struct usb_serial *serial) int pipe; int ret; int alen; - __u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 }; - __u8 result[sizeof(*hw_info) + 1]; + __u8 *command; + __u8 *result; int i; int j; struct urb *urb; @@ -365,13 +365,22 @@ static int whiteheat_attach (struct usb_serial *serial) command_port = serial->port[COMMAND_PORT]; pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress); + command = kmalloc(2, GFP_KERNEL); + if (!command) + goto no_command_buffer; + command[0] = WHITEHEAT_GET_HW_INFO; + command[1] = 0; + + result = kmalloc(sizeof(*hw_info) + 1, GFP_KERNEL); + if (!result) + goto no_result_buffer; /* * When the module is reloaded the firmware is still there and * the endpoints are still in the usb core unchanged. This is the * unlinking bug in disguise. Same for the call below. */ usb_clear_halt(serial->dev, pipe); - ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT); + ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't send command [%d]", serial->type->name, ret); goto no_firmware; @@ -383,7 +392,7 @@ static int whiteheat_attach (struct usb_serial *serial) pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress); /* See the comment on the usb_clear_halt() above */ usb_clear_halt(serial->dev, pipe); - ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT); + ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't get results [%d]", serial->type->name, ret); goto no_firmware; @@ -485,6 +494,8 @@ static int whiteheat_attach (struct usb_serial *serial) usb_set_serial_port_data(command_port, command_info); command_port->write_urb->complete = command_port_write_callback; command_port->read_urb->complete = command_port_read_callback; + kfree(result); + kfree(command); return 0; @@ -526,6 +537,10 @@ static int whiteheat_attach (struct usb_serial *serial) no_private: ; } + kfree(result); +no_result_buffer: + kfree(command); +no_command_buffer: return -ENOMEM; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 10d012e386ce365bbe9f0519ece27e0b42d19565..6f1ea41d83a86ac52d792a4cd662ea49b317dd7a 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -309,44 +309,6 @@ static int proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off * Sysfs interface ***********************************************************************/ -/* Output routine for the sysfs info file */ -static ssize_t show_info(struct device *dev, char *buffer) -{ - char *pos = buffer; - const int length = PAGE_SIZE; - - struct scsi_device *sdev = to_scsi_device(dev); - struct us_data *us = (struct us_data*)sdev->host->hostdata[0]; - - /* print the controller name */ - SPRINTF(" Host scsi%d: usb-storage\n", sdev->host->host_no); - - /* print product, vendor, and serial number strings */ - SPRINTF(" Vendor: %s\n", us->vendor); - SPRINTF(" Product: %s\n", us->product); - SPRINTF("Serial Number: %s\n", us->serial); - - /* show the protocol and transport */ - SPRINTF(" Protocol: %s\n", us->protocol_name); - SPRINTF(" Transport: %s\n", us->transport_name); - - /* show the device flags */ - if (pos < buffer + length) { - pos += sprintf(pos, " Quirks:"); - - DO_FLAG(SINGLE_LUN); - DO_FLAG(SCM_MULT_TARG); - DO_FLAG(FIX_INQUIRY); - DO_FLAG(FIX_CAPACITY); - - *(pos++) = '\n'; - } - - return (pos - buffer); -} - -static DEVICE_ATTR(info, S_IRUGO, show_info, NULL); - /* Output routine for the sysfs max_sectors file */ static ssize_t show_max_sectors(struct device *dev, char *buf) { @@ -373,7 +335,6 @@ static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors, store_max_sectors); static struct device_attribute *sysfs_device_attr_list[] = { - &dev_attr_info, &dev_attr_max_sectors, NULL, }; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index bcedc902b7b55fb443292948bae645db5e580961..924fdc3b04f704d123e4073dbf38fa9878417539 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -115,6 +115,13 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, "DVD-CAM DZ-MV100A Camcorder", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), +/* Reported by Simon Levitt <simon@whattf.com> + * This entry needs Sub and Proto fields */ +UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100, + "Epson", + "875DC Storage", + US_SC_SCSI, US_PR_CB, NULL, US_FL_FIX_INQUIRY), + /* Reported by Khalid Aziz <khalid@gonehiking.org> * This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, @@ -482,11 +489,6 @@ UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, "Freecom", "USB-IDE", US_SC_QIC, US_PR_FREECOM, freecom_init, 0), - -UNUSUAL_DEV( 0x07ab, 0xfc84, 0x0000, 0x9999, - "Freecom", - "FX-5/FX-50", - US_SC_QIC, US_PR_FREECOM, freecom_init, 0), #endif UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, diff --git a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h index add46cb74d48a13f9e5cf1740bc4244b97879a58..60e77a780790457deea6e178d39fa88b11243ebd 100644 --- a/include/asm-ia64/uaccess.h +++ b/include/asm-ia64/uaccess.h @@ -28,7 +28,7 @@ * * Based on <asm-alpha/uaccess.h>. * - * Copyright (C) 1998, 1999, 2001-2003 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001-2004 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> */ @@ -283,24 +283,23 @@ extern unsigned long __strnlen_user (const char *, long); __su_ret; \ }) +/* Generic code can't deal with the location-relative format that we use for compactness. */ #define ARCH_HAS_SORT_EXTABLE #define ARCH_HAS_SEARCH_EXTABLE struct exception_table_entry { - int addr; /* gp-relative address of insn this fixup is for */ - int cont; /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */ + int addr; /* location-relative address of insn this fixup is for */ + int cont; /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */ }; extern void handle_exception (struct pt_regs *regs, const struct exception_table_entry *e); extern const struct exception_table_entry *search_exception_tables (unsigned long addr); -# define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri) - static inline int done_with_exception (struct pt_regs *regs) { const struct exception_table_entry *e; - e = SEARCH_EXCEPTION_TABLE(regs); + e = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri); if (e) { handle_exception(regs, e); return 1; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5e49f861230d745f16216e7f64b9a8d064896883..c405f81be7658eddf0051fba0a35d2baf90864cd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -856,7 +856,6 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, /* wrappers around usb_control_msg() for the most common standard requests */ extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size); -extern int usb_get_device_descriptor(struct usb_device *dev); extern int usb_get_status(struct usb_device *dev, int type, int target, void *data); extern int usb_get_string(struct usb_device *dev, diff --git a/kernel/power/pmdisk.c b/kernel/power/pmdisk.c index 449d3e57cfdb07060ca368ea831282dbb2cce477..ef35bd28505def68e66b6baabda71988d02bf17e 100644 --- a/kernel/power/pmdisk.c +++ b/kernel/power/pmdisk.c @@ -28,6 +28,7 @@ #include <linux/device.h> #include <linux/swapops.h> #include <linux/bootmem.h> +#include <linux/utsname.h> #include <asm/mmu_context.h> diff --git a/kernel/sched.c b/kernel/sched.c index 574327cd2e4828cc0183cf1a28a2a47a1df9563e..141e0c348758a32ffbf269194771cab7e234694e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -124,9 +124,6 @@ (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / \ MAX_SLEEP_AVG) -/* spinlock debugging needs this, even on !CONFIG_SMP */ -spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; - #ifdef CONFIG_SMP #define TIMESLICE_GRANULARITY(p) (MIN_TIMESLICE * \ (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1)) * \ @@ -2859,7 +2856,6 @@ __init int migration_init(void) #endif -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) /* * The 'big kernel lock' * @@ -2869,10 +2865,11 @@ __init int migration_init(void) * been migrated to a proper locking design yet. * * Don't use in new code. + * + * Note: spinlock debugging needs this even on !CONFIG_SMP. */ - +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(kernel_flag); -#endif static void kstat_init_cpu(int cpu) { diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 480292321923509311a044051fb5108495df7cdb..f6926ed69d37954f9296c0df70f609ad5488d53d 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/usb.h> +#include <linux/usb_ch9.h> #include <sound/core.h> #include <sound/info.h> #include <sound/pcm.h> @@ -2560,9 +2561,10 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac err = usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ); if (err < 0) snd_printdd("error sending boot message: %d\n", err); - err = usb_get_device_descriptor(dev); + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, + &dev->descriptor, sizeof(dev->descriptor)); config = dev->actconfig; - if (err < 0) snd_printdd("error usb_get_device_descriptor: %d\n", err); + if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err); err = usb_reset_configuration(dev); if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err); snd_printdd("extigy_boot: new boot length = %d\n", get_cfg_desc(config)->wTotalLength);