diff options
112 files changed, 2702 insertions, 1111 deletions
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 1af0f2d5022..2ffb0d62f0f 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -33,7 +33,9 @@ pci_alloc_consistent(struct pci_dev *dev, size_t size, Consistent memory is memory for which a write by either the device or the processor can immediately be read by the processor or device -without having to worry about caching effects. +without having to worry about caching effects. (You may however need +to make sure to flush the processor's write buffers before telling +devices to read that memory.) This routine allocates a region of <size> bytes of consistent memory. it also returns a <dma_handle> which may be cast to an unsigned @@ -304,12 +306,12 @@ dma address with dma_mapping_error(). A non zero return value means the mapping could not be created and the driver should take appropriate action (eg reduce current DMA mapping usage or delay and try again later). -int -dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -int -pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) + int + dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) + int + pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) Maps a scatter gather list from the block layer. @@ -327,12 +329,33 @@ critical that the driver do something, in the case of a block driver aborting the request or even oopsing is better than doing nothing and corrupting the filesystem. -void -dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -void -pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) +With scatterlists, you use the resulting mapping like this: + + int i, count = dma_map_sg(dev, sglist, nents, direction); + struct scatterlist *sg; + + for (i = 0, sg = sglist; i < count; i++, sg++) { + hw_address[i] = sg_dma_address(sg); + hw_len[i] = sg_dma_len(sg); + } + +where nents is the number of entries in the sglist. + +The implementation is free to merge several consecutive sglist entries +into one (e.g. with an IOMMU, or if several pages just happen to be +physically contiguous) and returns the actual number of sg entries it +mapped them to. On failure 0, is returned. + +Then you should loop count times (note: this can be less than nents times) +and use sg_dma_address() and sg_dma_len() macros where you previously +accessed sg->address and sg->length as shown above. + + void + dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, enum dma_data_direction direction) + void + pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) unmap the previously mapped scatter/gather list. All the parameters must be the same as those and passed in to the scatter/gather mapping diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt index 10bf4deb96a..7c717699032 100644 --- a/Documentation/DMA-mapping.txt +++ b/Documentation/DMA-mapping.txt @@ -58,11 +58,15 @@ translating each of those pages back to a kernel address using something like __va(). [ EDIT: Update this when we integrate Gerd Knorr's generic code which does this. ] -This rule also means that you may not use kernel image addresses -(ie. items in the kernel's data/text/bss segment, or your driver's) -nor may you use kernel stack addresses for DMA. Both of these items -might be mapped somewhere entirely different than the rest of physical -memory. +This rule also means that you may use neither kernel image addresses +(items in data/text/bss segments), nor module image addresses, nor +stack addresses for DMA. These could all be mapped somewhere entirely +different than the rest of physical memory. Even if those classes of +memory could physically work with DMA, you'd need to ensure the I/O +buffers were cacheline-aligned. Without that, you'd see cacheline +sharing problems (data corruption) on CPUs with DMA-incoherent caches. +(The CPU could write to one word, DMA would write to a different one +in the same cache line, and one of them could be overwritten.) Also, this means that you cannot take the return of a kmap() call and DMA to/from that. This is similar to vmalloc(). @@ -284,6 +288,11 @@ There are two types of DMA mappings: in order to get correct behavior on all platforms. + Also, on some platforms your driver may need to flush CPU write + buffers in much the same way as it needs to flush write buffers + found in PCI bridges (such as by reading a register's value + after writing it). + - Streaming DMA mappings which are usually mapped for one DMA transfer, unmapped right after it (unless you use pci_dma_sync_* below) and for which hardware can optimize for sequential accesses. @@ -303,6 +312,9 @@ There are two types of DMA mappings: Neither type of DMA mapping has alignment restrictions that come from PCI, although some devices may have such restrictions. +Also, systems with caches that aren't DMA-coherent will work better +when the underlying buffers don't share cache lines with other data. + Using Consistent DMA mappings. diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index d9f23c0763f..77b995dfca2 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -12,18 +12,22 @@ meant as a replacement for the older, individual drivers: teletext adapters) It currently supports the following devices: - * Philips adapter - * home brew teletext adapter - * Velleman K8000 adapter - * ELV adapter - * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032) - * Barco LPT->DVI (K5800236) adapter + * (type=0) Philips adapter + * (type=1) home brew teletext adapter + * (type=2) Velleman K8000 adapter + * (type=3) ELV adapter + * (type=4) Analog Devices ADM1032 evaluation board + * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 + * (type=6) Barco LPT->DVI (K5800236) adapter These devices use different pinout configurations, so you have to tell the driver what you have, using the type module parameter. There is no way to autodetect the devices. Support for different pinout configurations can be easily added when needed. +Earlier kernels defaulted to type=0 (Philips). But now, if the type +parameter is missing, the driver will simply fail to initialize. + Building your own adapter ------------------------- diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 5b9ed21216c..96fb8a020af 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ + pci-dma.o i386_ksyms.o i387.o bootflag.o \ quirks.o i8237.o topology.o alternative.o obj-y += cpu/ diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 4f58b9c0efe..f48bef15b4f 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -314,3 +314,4 @@ ENTRY(sys_call_table) .long sys_get_robust_list .long sys_splice .long sys_sync_file_range + .long sys_tee /* 315 */ diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 3ca59cad05f..73235443fda 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -588,7 +588,10 @@ static __init int via_router_probe(struct irq_router *r, case PCI_DEVICE_ID_VIA_82C596: case PCI_DEVICE_ID_VIA_82C686: case PCI_DEVICE_ID_VIA_8231: + case PCI_DEVICE_ID_VIA_8233A: case PCI_DEVICE_ID_VIA_8235: + case PCI_DEVICE_ID_VIA_8237: + case PCI_DEVICE_ID_VIA_8237_SATA: /* FIXME: add new ones for 8233/5 */ r->name = "VIA"; r->get = pirq_via_get; diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 59e871dae74..09a0dbc17fb 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ - unwind.o mca.o mca_asm.o topology.o dmi_scan.o + unwind.o mca.o mca_asm.o topology.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o @@ -30,7 +30,6 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o mca_recovery-y += mca_drv.o mca_drv_asm.o -dmi_scan-y += ../../i386/kernel/dmi_scan.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 6e16f6b35bd..e3079881121 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1609,5 +1609,6 @@ sys_call_table: data8 sys_set_robust_list data8 sys_get_robust_list data8 sys_sync_file_range // 1300 + data8 sys_tee .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 5e6fdbe78bc..6a0880639bc 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -963,7 +963,7 @@ no_mod: */ static void -ia64_wait_for_slaves(int monarch) +ia64_wait_for_slaves(int monarch, const char *type) { int c, wait = 0, missing = 0; for_each_online_cpu(c) { @@ -989,7 +989,7 @@ ia64_wait_for_slaves(int monarch) } if (!missing) goto all_in; - printk(KERN_INFO "OS MCA slave did not rendezvous on cpu"); + printk(KERN_INFO "OS %s slave did not rendezvous on cpu", type); for_each_online_cpu(c) { if (c == monarch) continue; @@ -1000,7 +1000,7 @@ ia64_wait_for_slaves(int monarch) return; all_in: - printk(KERN_INFO "All OS MCA slaves have reached rendezvous\n"); + printk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type); return; } @@ -1038,7 +1038,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - ia64_wait_for_slaves(cpu); + ia64_wait_for_slaves(cpu, "MCA"); /* Wakeup all the processors which are spinning in the rendezvous loop. * They will leave SAL, then spin in the OS with interrupts disabled @@ -1429,7 +1429,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, */ printk("Delaying for 5 seconds...\n"); udelay(5*1000000); - ia64_wait_for_slaves(cpu); + ia64_wait_for_slaves(cpu, "INIT"); /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through * to default_monarch_init_process() above and just print all the * tasks. diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index ec9eeb89975..b6bcc9fa360 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -519,6 +519,68 @@ void __cpuinit *per_cpu_init(void) } #endif /* CONFIG_SMP */ +#ifdef CONFIG_VIRTUAL_MEM_MAP +static inline int find_next_valid_pfn_for_pgdat(pg_data_t *pgdat, int i) +{ + unsigned long end_address, hole_next_pfn; + unsigned long stop_address; + + end_address = (unsigned long) &vmem_map[pgdat->node_start_pfn + i]; + end_address = PAGE_ALIGN(end_address); + + stop_address = (unsigned long) &vmem_map[ + pgdat->node_start_pfn + pgdat->node_spanned_pages]; + + do { + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset_k(end_address); + if (pgd_none(*pgd)) { + end_address += PGDIR_SIZE; + continue; + } + + pud = pud_offset(pgd, end_address); + if (pud_none(*pud)) { + end_address += PUD_SIZE; + continue; + } + + pmd = pmd_offset(pud, end_address); + if (pmd_none(*pmd)) { + end_address += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, end_address); +retry_pte: + if (pte_none(*pte)) { + end_address += PAGE_SIZE; + pte++; + if ((end_address < stop_address) && + (end_address != ALIGN(end_address, 1UL << PMD_SHIFT))) + goto retry_pte; + continue; + } + /* Found next valid vmem_map page */ + break; + } while (end_address < stop_address); + + end_address = min(end_address, stop_address); + end_address = end_address - (unsigned long) vmem_map + sizeof(struct page) - 1; + hole_next_pfn = end_address / sizeof(struct page); + return hole_next_pfn - pgdat->node_start_pfn; +} +#else +static inline int find_next_valid_pfn_for_pgdat(pg_data_t *pgdat, int i) +{ + return i + 1; +} +#endif + /** * show_mem - give short summary of memory stats * @@ -547,8 +609,10 @@ void show_mem(void) struct page *page; if (pfn_valid(pgdat->node_start_pfn + i)) page = pfn_to_page(pgdat->node_start_pfn + i); - else + else { + i = find_next_valid_pfn_for_pgdat(pgdat, i) - 1; continue; + } if (PageReserved(page)) reserved++; else if (PageSwapCache(page)) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 1424eab450e..a14c9640384 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -323,3 +323,4 @@ COMPAT_SYS(pselect6) COMPAT_SYS(ppoll) SYSCALL(unshare) SYSCALL(splice) +SYSCALL(tee) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index a098a11e775..059c88313f4 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - dmi_scan.o pci-dma.o pci-nommu.o + pci-dma.o pci-nommu.o obj-$(CONFIG_X86_MCE) += mce.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o @@ -49,5 +49,3 @@ intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o -dmi_scan-y += ../../i386/kernel/dmi_scan.o - diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 48718b7f4fa..76656acd00d 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device_driver *drv, up(&dev->sem); if (dev->parent) up(&dev->parent->sem); + + if (err > 0) /* success */ + err = count; + else if (err == 0) /* driver didn't accept device */ + err = -ENODEV; } put_device(dev); put_bus(bus); diff --git a/drivers/base/class.c b/drivers/base/class.c index df7fdabd073..0e71dff327c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -562,14 +562,13 @@ int class_device_add(struct class_device *class_dev) kobject_uevent(&class_dev->kobj, KOBJ_ADD); /* notify any interfaces this device is now here */ - if (parent_class) { - down(&parent_class->sem); - list_add_tail(&class_dev->node, &parent_class->children); - list_for_each_entry(class_intf, &parent_class->interfaces, node) - if (class_intf->add) - class_intf->add(class_dev, class_intf); - up(&parent_class->sem); + down(&parent_class->sem); + list_add_tail(&class_dev->node, &parent_class->children); + list_for_each_entry(class_intf, &parent_class->interfaces, node) { + if (class_intf->add) + class_intf->add(class_dev, class_intf); } + up(&parent_class->sem); register_done: if (error) { diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 730a9ce0a14..889c7111123 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -209,7 +209,7 @@ static void __device_release_driver(struct device * dev) sysfs_remove_link(&dev->kobj, "driver"); klist_remove(&dev->knode_driver); - if (dev->bus->remove) + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index bdb60663f2e..662209d3f42 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -10,6 +10,8 @@ #include <linux/vt_kern.h> #include <linux/device.h> +#include <linux/kallsyms.h> +#include <linux/pm.h> #include "../base.h" #include "power.h" @@ -58,6 +60,7 @@ int suspend_device(struct device * dev, pm_message_t state) if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { dev_dbg(dev, "suspending\n"); error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); } up(&dev->sem); return error; @@ -169,3 +172,12 @@ int device_power_down(pm_message_t state) EXPORT_SYMBOL_GPL(device_power_down); +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f70a47eadb5..841f0bd3eaa 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2734,7 +2734,7 @@ static void __do_SAK(void *arg) printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", p->pid, p->comm, i); - send_sig(SIGKILL, p, 1); + force_sig(SIGKILL, p); break; } } diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 85429979d0d..98e395f4bb2 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -1,7 +1,8 @@ # # Makefile for the linux kernel. # -obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_DMI) += dmi_scan.o +obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_DELL_RBU) += dell_rbu.o diff --git a/arch/i386/kernel/dmi_scan.c b/drivers/firmware/dmi_scan.c index 5efceebc48d..948bd7e1445 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -27,7 +27,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s) else printk(KERN_ERR "dmi_string: out of memory.\n"); } - } + } return str; } @@ -41,7 +41,7 @@ static int __init dmi_table(u32 base, int len, int num, { u8 *buf, *data; int i = 0; - + buf = dmi_ioremap(base, len); if (buf == NULL) return -1; @@ -49,9 +49,9 @@ static int __init dmi_table(u32 base, int len, int num, data = buf; /* - * Stop when we see all the items the table claimed to have - * OR we run off the end of the table (also happens) - */ + * Stop when we see all the items the table claimed to have + * OR we run off the end of the table (also happens) + */ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { struct dmi_header *dm = (struct dmi_header *)data; /* @@ -75,7 +75,7 @@ static int __init dmi_checksum(u8 *buf) { u8 sum = 0; int a; - + for (a = 0; a < 15; a++) sum += buf[a]; diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 6865c64d8a5..958602e2841 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1161,7 +1161,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) bank. */ if (kind < 0) { if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) { - dev_warn(dev, "Detection failed at step 3\n"); + dev_dbg(dev, "Detection failed at step 1\n"); goto ERROR1; } val1 = w83792d_read_value(client, W83792D_REG_BANK); @@ -1170,6 +1170,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) if (!(val1 & 0x07)) { /* is Bank0 */ if (((!(val1 & 0x80)) && (val2 != 0xa3)) || ((val1 & 0x80) && (val2 != 0x5c))) { + dev_dbg(dev, "Detection failed at step 2\n"); goto ERROR1; } } @@ -1177,7 +1178,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) should match */ if (w83792d_read_value(client, W83792D_REG_I2C_ADDR) != address) { - dev_warn(dev, "Detection failed at step 5\n"); + dev_dbg(dev, "Detection failed at step 3\n"); goto ERROR1; } } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 089c6f5b24d..d6d44946a28 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -286,7 +286,10 @@ config I2C_PARPORT This driver is a replacement for (and was inspired by) an older driver named i2c-philips-par. The new driver supports more devices, and makes it easier to add support for new devices. - + + An adapter type parameter is now mandatory. Please read the file + Documentation/i2c/busses/i2c-parport for details. + Another driver exists, named i2c-parport-light, which doesn't depend on the parport driver. This is meant for embedded systems. Don't say Y here if you intend to say Y or M there. diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index c63025a4c86..e09ebbb2f9f 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -121,9 +121,14 @@ static struct i2c_adapter parport_adapter = { static int __init i2c_parport_init(void) { - if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { + if (type < 0) { + printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + return -ENODEV; + } + + if (type >= ARRAY_SIZE(adapter_parm)) { printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); - type = 0; + return -ENODEV; } if (base == 0) { diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 7e2e8cd1c14..934bd55bae1 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -241,9 +241,14 @@ static struct parport_driver i2c_parport_driver = { static int __init i2c_parport_init(void) { - if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { + if (type < 0) { + printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + return -ENODEV; + } + + if (type >= ARRAY_SIZE(adapter_parm)) { printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); - type = 0; + return -ENODEV; } return parport_register_driver(&i2c_parport_driver); diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index d702e5e0388..9ddd816d5d0 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -90,7 +90,7 @@ static struct adapter_parm adapter_parm[] = { }, }; -static int type; +static int type = -1; module_param(type, int, 0); MODULE_PARM_DESC(type, "Type of adapter:\n" diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3024907cdaf..1a73c0532fc 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -43,13 +43,6 @@ #include <linux/init.h> #include <asm/io.h> -/* - HISTORY: - 2003-05-11 1.0.0 Updated from lm_sensors project for kernel 2.5 - (was i2c-sis645.c from lm_sensors 2.7.0) -*/ -#define SIS96x_VERSION "1.0.0" - /* base address register in PCI config space */ #define SIS96x_BAR 0x04 @@ -337,7 +330,6 @@ static struct pci_driver sis96x_driver = { static int __init i2c_sis96x_init(void) { - printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION); return pci_register_driver(&sis96x_driver); } diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 03d09ed5ec2..4630f1969a0 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -27,6 +27,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #define DS1374_REG_TOD0 0x00 #define DS1374_REG_TOD1 0x01 @@ -139,7 +140,7 @@ ulong ds1374_get_rtc_time(void) return t1; } -static void ds1374_set_tlet(ulong arg) +static void ds1374_set_work(void *arg) { ulong t1, t2; int limit = 10; /* arbitrary retry limit */ @@ -168,17 +169,18 @@ static void ds1374_set_tlet(ulong arg) static ulong new_time; -static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, - (ulong) & new_time); +static struct workqueue_struct *ds1374_workqueue; + +static DECLARE_WORK(ds1374_work, ds1374_set_work, &new_time); int ds1374_set_rtc_time(ulong nowtime) { new_time = nowtime; if (in_interrupt()) - tasklet_schedule(&ds1374_tasklet); + queue_work(ds1374_workqueue, &ds1374_work); else - ds1374_set_tlet((ulong) & new_time); + ds1374_set_work(&new_time); return 0; } @@ -204,6 +206,8 @@ static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) client->adapter = adap; client->driver = &ds1374_driver; + ds1374_workqueue = create_singlethread_workqueue("ds1374"); + if ((rc = i2c_attach_client(client)) != 0) { kfree(client); return rc; @@ -227,7 +231,7 @@ static int ds1374_detach(struct i2c_client *client) if ((rc = i2c_detach_client(client)) == 0) { kfree(i2c_get_clientdata(client)); - tasklet_kill(&ds1374_tasklet); + destroy_workqueue(ds1374_workqueue); } return rc; } diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index b5aabe7cf79..27fc9ff2961 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -25,6 +25,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <asm/time.h> #include <asm/rtc.h> @@ -111,7 +112,7 @@ m41t00_get_rtc_time(void) } static void -m41t00_set_tlet(ulong arg) +m41t00_set(void *arg) { struct rtc_time tm; ulong nowtime = *(ulong *)arg; @@ -145,9 +146,9 @@ m41t00_set_tlet(ulong arg) return; } -static ulong new_time; - -DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time); +static ulong new_time; +static struct workqueue_struct *m41t00_wq; +static DECLARE_WORK(m41t00_work, m41t00_set, &new_time); int m41t00_set_rtc_time(ulong nowtime) @@ -155,9 +156,9 @@ m41t00_set_rtc_time(ulong nowtime) new_time = nowtime; if (in_interrupt()) - tasklet_schedule(&m41t00_tasklet); + queue_work(m41t00_wq, &m41t00_work); else - m41t00_set_tlet((ulong)&new_time); + m41t00_set(&new_time); return 0; } @@ -189,6 +190,7 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) return rc; } + m41t00_wq = create_singlethread_workqueue("m41t00"); save_client = client; return 0; } @@ -206,7 +208,7 @@ m41t00_detach(struct i2c_client *client) if ((rc = i2c_detach_client(client)) == 0) { kfree(client); - tasklet_kill(&m41t00_tasklet); + destroy_workqueue(m41t00_wq); } return rc; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 1ed5152db45..434ca39d19c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -163,6 +163,7 @@ void md_new_event(mddev_t *mddev) { atomic_inc(&md_event_count); wake_up(&md_event_waiters); + sysfs_notify(&mddev->kobj, NULL, "sync_action"); } EXPORT_SYMBOL_GPL(md_new_event); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 6e79f5675b0..63800454670 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -360,9 +360,6 @@ static int __init rpaphp_init(void) while ((dn = of_find_node_by_type(dn, "pci"))) rpaphp_add_slot(dn); - if (!num_slots) - return -ENODEV; - return 0; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a77e79c8c82..2087a397ef1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -504,6 +504,201 @@ void pci_scan_msi_device(struct pci_dev *dev) nr_reserved_vectors++; } +#ifdef CONFIG_PM +int pci_save_msi_state(struct pci_dev *dev) +{ + int pos, i = 0; + u16 control; + struct pci_cap_saved_state *save_state; + u32 *cap; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos <= 0 || dev->no_msi) + return 0; + + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (!(control & PCI_MSI_FLAGS_ENABLE)) + return 0; + + save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, + GFP_KERNEL); + if (!save_state) { + printk(KERN_ERR "Out of memory in pci_save_msi_state\n"); + return -ENOMEM; + } + cap = &save_state->data[0]; + + pci_read_config_dword(dev, pos, &cap[i++]); + control = cap[0] >> 16; + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]); + pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]); + } else + pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); + disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + save_state->cap_nr = PCI_CAP_ID_MSI; + pci_add_saved_cap(dev, save_state); + return 0; +} + +void pci_restore_msi_state(struct pci_dev *dev) +{ + int i = 0, pos; + u16 control; + struct pci_cap_saved_state *save_state; + u32 *cap; + + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (!save_state || pos <= 0) + return; + cap = &save_state->data[0]; + + control = cap[i++] >> 16; + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); + pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]); + } else + pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + pci_remove_saved_cap(save_state); + kfree(save_state); +} + +int pci_save_msix_state(struct pci_dev *dev) +{ + int pos; + u16 control; + struct pci_cap_saved_state *save_state; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos <= 0 || dev->no_msi) + return 0; + + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (!(control & PCI_MSIX_FLAGS_ENABLE)) + return 0; + save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), + GFP_KERNEL); + if (!save_state) { + printk(KERN_ERR "Out of memory in pci_save_msix_state\n"); + return -ENOMEM; + } + *((u16 *)&save_state->data[0]) = control; + + disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); + save_state->cap_nr = PCI_CAP_ID_MSIX; + pci_add_saved_cap(dev, save_state); + return 0; +} + +void pci_restore_msix_state(struct pci_dev *dev) +{ + u16 save; + int pos; + int vector, head, tail = 0; + void __iomem *base; + int j; + struct msg_address address; + struct msg_data data; + struct msi_desc *entry; + int temp; + struct pci_cap_saved_state *save_state; + + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); + if (!save_state) + return; + save = *((u16 *)&save_state->data[0]); + pci_remove_saved_cap(save_state); + kfree(save_state); + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos <= 0) + return; + + /* route the table */ + temp = dev->irq; + if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) + return; + vector = head = dev->irq; + while (head != tail) { + entry = msi_desc[vector]; + base = entry->mask_base; + j = entry->msi_attrib.entry_nr; + + msi_address_init(&address); + msi_data_init(&data, vector); + + address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; + address.lo_address.value |= entry->msi_attrib.current_cpu << + MSI_TARGET_CPU_SHIFT; + + writel(address.lo_address.value, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + writel(address.hi_address, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + writel(*(u32*)&data, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_DATA_OFFSET); + + tail = msi_desc[vector]->link.tail; + vector = tail; + } + dev->irq = temp; + + pci_write_config_word(dev, msi_control_reg(pos), save); + enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); +} +#endif + +static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +{ + struct msg_address address; + struct msg_data data; + int pos, vector = dev->irq; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + pci_read_config_word(dev, msi_control_reg(pos), &control); + /* Configure MSI capability structure */ + msi_address_init(&address); + msi_data_init(&data, vector); + entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> + MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); + pci_write_config_dword(dev, msi_lower_address_reg(pos), + address.lo_address.value); + if (is_64bit_address(control)) { + pci_write_config_dword(dev, + msi_upper_address_reg(pos), address.hi_address); + pci_write_config_word(dev, + msi_data_reg(pos, 1), *((u32*)&data)); + } else + pci_write_config_word(dev, + msi_data_reg(pos, 0), *((u32*)&data)); + if (entry->msi_attrib.maskbit) { + unsigned int maskbits, temp; + /* All MSIs are unmasked by default, Mask them all */ + pci_read_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + &maskbits); + temp = (1 << multi_msi_capable(control)); + temp = ((temp - 1) & ~temp); + maskbits |= temp; + pci_write_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + maskbits); + } +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -516,8 +711,6 @@ void pci_scan_msi_device(struct pci_dev *dev) static int msi_capability_init(struct pci_dev *dev) { struct msi_desc *entry; - struct msg_address address; - struct msg_data data; int pos, vector; u16 control; @@ -549,33 +742,8 @@ static int msi_capability_init(struct pci_dev *dev) /* Replace with MSI handler */ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - pci_write_config_dword(dev, msi_lower_address_reg(pos), - address.lo_address.value); - if (is_64bit_address(control)) { - pci_write_config_dword(dev, - msi_upper_address_reg(pos), address.hi_address); - pci_write_config_word(dev, - msi_data_reg(pos, 1), *((u32*)&data)); - } else - pci_write_config_word(dev, - msi_data_reg(pos, 0), *((u32*)&data)); - if (entry->msi_attrib.maskbit) { - unsigned int maskbits, temp; - /* All MSIs are unmasked by default, Mask them all */ - pci_read_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - &maskbits); - temp = (1 << multi_msi_capable(control)); - temp = ((temp - 1) & ~temp); - maskbits |= temp; - pci_write_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - maskbits); - } + msi_register_init(dev, entry); + attach_msi_entry(entry, vector); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -731,6 +899,7 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); + msi_register_init(dev, msi_desc[dev->irq]); enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); return 0; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f22f69ac644..1456759936c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -271,10 +271,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state) struct pci_driver * drv = pci_dev->driver; int i = 0; - if (drv && drv->suspend) + if (drv && drv->suspend) { i = drv->suspend(pci_dev, state); - else + suspend_report_result(drv->suspend, i); + } else { pci_save_state(pci_dev); + } return i; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bea1ad1ad5b..2329f941a0d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -307,9 +307,11 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state */ - if (state != PCI_D0 && dev->current_state > state) + if (state != PCI_D0 && dev->current_state > state) { + printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n", + __FUNCTION__, pci_name(dev), state, dev->current_state); return -EINVAL; - else if (dev->current_state == state) + } else if (dev->current_state == state) return 0; /* we're already there */ /* find PCI PM capability in list */ @@ -444,6 +446,10 @@ pci_save_state(struct pci_dev *dev) /* XXX: 100% dword access ok here? */ for (i = 0; i < 16; i++) pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); + if ((i = pci_save_msi_state(dev)) != 0) + return i; + if ((i = pci_save_msix_state(dev)) != 0) + return i; return 0; } @@ -458,6 +464,8 @@ pci_restore_state(struct pci_dev *dev) for (i = 0; i < 16; i++) pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]); + pci_restore_msi_state(dev); + pci_restore_msix_state(dev); return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8f3fb47ea67..30630cbe2fe 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -55,6 +55,17 @@ void pci_no_msi(void); static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif +#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) +int pci_save_msi_state(struct pci_dev *dev); +int pci_save_msix_state(struct pci_dev *dev); +void pci_restore_msi_state(struct pci_dev *dev); +void pci_restore_msix_state(struct pci_dev *dev); +#else +static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } +static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } +static inline void pci_restore_msi_state(struct pci_dev *dev) {} +static inline void pci_restore_msix_state(struct pci_dev *dev) {} +#endif extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4970f47be72..827550d25c9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -592,7 +592,7 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) pci_write_config_byte( dev, AMD8131_MISC, tmp); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, quirk_amd_8131_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); static void __init quirk_svw_msi(struct pci_dev *dev) { @@ -921,6 +921,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { switch (dev->subsystem_device) { case 0x1882: /* M6V notebook */ + case 0x1977: /* A6VA notebook */ asus_hides_smbus = 1; } } @@ -999,6 +1000,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc ); static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 830d2c98267..b38990adf1c 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -68,7 +68,7 @@ #include "usbatm.h" -#define EAGLEUSBVERSION "ueagle 1.2" +#define EAGLEUSBVERSION "ueagle 1.3" /* @@ -243,7 +243,7 @@ enum { #define BULK_TIMEOUT 300 #define CTRL_TIMEOUT 1000 -#define ACK_TIMEOUT msecs_to_jiffies(1500) +#define ACK_TIMEOUT msecs_to_jiffies(3000) #define UEA_INTR_IFACE_NO 0 #define UEA_US_IFACE_NO 1 @@ -314,6 +314,10 @@ struct cmv { ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) +#define GETSA1(a) ((a >> 8) & 0xff) +#define GETSA2(a) (a & 0xff) +#define GETSA3(a) ((a >> 24) & 0xff) +#define GETSA4(a) ((a >> 16) & 0xff) #define SA_CNTL MAKESA('C', 'N', 'T', 'L') #define SA_DIAG MAKESA('D', 'I', 'A', 'G') @@ -728,11 +732,12 @@ bad2: uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", i); return; bad1: - uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n",pageno); + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } static inline void wake_up_cmv_ack(struct uea_softc *sc) { + BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; wake_up(&sc->cmv_ack_wait); } @@ -743,6 +748,9 @@ static inline int wait_cmv_ack(struct uea_softc *sc) sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; + uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", + jiffies_to_msecs(ret)); + if (ret < 0) return ret; @@ -791,6 +799,12 @@ static int uea_cmv(struct uea_softc *sc, struct cmv cmv; int ret; + uea_enters(INS_TO_USBDEV(sc)); + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " + "offset : 0x%04x, data : 0x%08x\n", + FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), + GETSA1(address), GETSA2(address), GETSA3(address), + GETSA4(address), offset, data); /* we send a request, but we expect a reply */ sc->cmv_function = function | 0x2; sc->cmv_idx++; @@ -808,7 +822,9 @@ static int uea_cmv(struct uea_softc *sc, ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); if (ret < 0) return ret; - return wait_cmv_ack(sc); + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; } static inline int uea_read_cmv(struct uea_softc *sc, @@ -922,7 +938,7 @@ static int uea_stat(struct uea_softc *sc) * we check the status again in order to detect the failure earlier */ if (sc->stats.phy.flags) { - uea_dbg(INS_TO_USBDEV(sc), "Stat flag = %d\n", + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", sc->stats.phy.flags); return 0; } @@ -1063,7 +1079,13 @@ static int uea_start_reset(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); + /* mask interrupt */ sc->booting = 1; + /* We need to set this here because, a ack timeout could have occured, + * but before we start the reboot, the ack occurs and set this to 1. + * So we will failed to wait Ready CMV. + */ + sc->cmv_ack = 0; UPDATE_ATM_STAT(signal, ATM_PHY_SIG_LOST); /* reset statistics */ @@ -1089,6 +1111,7 @@ static int uea_start_reset(struct uea_softc *sc) msleep(1000); sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); + /* demask interrupt */ sc->booting = 0; /* start loading DSP */ @@ -1101,6 +1124,8 @@ static int uea_start_reset(struct uea_softc *sc) if (ret < 0) return ret; + uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); + /* Enter in R-IDLE (cmv) until instructed otherwise */ ret = uea_write_cmv(sc, SA_CNTL, 0, 1); if (ret < 0) @@ -1121,6 +1146,7 @@ static int uea_start_reset(struct uea_softc *sc) } /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); out: release_firmware(cmvs_fw); sc->reset = 0; @@ -1235,6 +1261,7 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); return; } @@ -1249,6 +1276,7 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) sc->data = sc->data << 16 | sc->data >> 16; wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); return; bad2: @@ -1256,12 +1284,14 @@ bad2: "Function : %d, Subfunction : %d\n", FUNCTION_TYPE(cmv->bFunction), FUNCTION_SUBTYPE(cmv->bFunction)); + uea_leaves(INS_TO_USBDEV(sc)); return; bad1: uea_err(INS_TO_USBDEV(sc), "invalid cmv received, " "wPreamble %d, bDirection %d\n", le16_to_cpu(cmv->wPreamble), cmv->bDirection); + uea_leaves(INS_TO_USBDEV(sc)); } /* @@ -1346,7 +1376,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err1; + goto err; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -1360,10 +1390,10 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err1: - kfree(intr); err: usb_free_urb(sc->urb_int); + sc->urb_int = NULL; + kfree(intr); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -1508,7 +1538,7 @@ static ssize_t read_##name(struct device *dev, \ int ret = -ENODEV; \ struct uea_softc *sc; \ \ - mutex_lock(&uea_mutex); \ + mutex_lock(&uea_mutex); \ sc = dev_to_uea(dev); \ if (!sc) \ goto out; \ @@ -1516,7 +1546,7 @@ static ssize_t read_##name(struct device *dev, \ if (reset) \ sc->stats.phy.name = 0; \ out: \ - mutex_unlock(&uea_mutex); \ + mutex_unlock(&uea_mutex); \ return ret; \ } \ \ @@ -1643,7 +1673,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); if (!sc) { - uea_err(INS_TO_USBDEV(sc), "uea_init: not enough memory !\n"); + uea_err(usb, "uea_init: not enough memory !\n"); return -ENOMEM; } diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index ff03184da40..a08787e253a 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -99,4 +99,11 @@ config USB_OTG_WHITELIST normal Linux-USB hosts do (other than the warning), and is convenient for many stages of product development. +config USB_OTG_BLACKLIST_HUB + bool "Disable external hubs" + depends on USB_OTG + help + If you say Y here, then Linux will refuse to enumerate + external hubs. OTG hosts are allowed to reduce hardware + and software costs by not supporting external hubs. diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 0d2193b6923..66b78404ab3 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -213,11 +213,9 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) if (hcd->driver->suspend) { retval = hcd->driver->suspend(hcd, message); - if (retval) { - dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n", - retval); + suspend_report_result(hcd->driver->suspend, retval); + if (retval) goto done; - } } synchronize_irq(dev->irq); @@ -263,6 +261,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) * some device state (e.g. as part of clock reinit). */ retval = pci_set_power_state (dev, PCI_D3hot); + suspend_report_result(pci_set_power_state, retval); if (retval == 0) { int wake = device_can_wakeup(&hcd->self.root_hub->dev); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8e65f7a237e..0c87f73f293 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -836,6 +836,13 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); +#ifdef CONFIG_USB_OTG_BLACKLIST_HUB + if (hdev->parent) { + dev_warn(&intf->dev, "ignoring external hub\n"); + return -ENODEV; + } +#endif + /* Some hubs have a subclass of 1, which AFAICT according to the */ /* specs is not defined, but it works */ if ((desc->desc.bInterfaceSubClass != 0) && @@ -1022,7 +1029,6 @@ void usb_set_device_state(struct usb_device *udev, recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } -EXPORT_SYMBOL(usb_set_device_state); #ifdef CONFIG_PM diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d7352aa73b5..b7fdc1cd134 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1194,7 +1194,6 @@ EXPORT_SYMBOL(usb_disabled); EXPORT_SYMBOL_GPL(usb_get_intf); EXPORT_SYMBOL_GPL(usb_put_intf); -EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); EXPORT_SYMBOL(usb_hub_tt_clear_buffer); @@ -1208,7 +1207,6 @@ EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_altnum_to_altsetting); EXPORT_SYMBOL(usb_reset_device); -EXPORT_SYMBOL(usb_disconnect); EXPORT_SYMBOL(__usb_get_extra_descriptor); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d80f71877d6..363b2ad74ae 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -69,11 +69,11 @@ choice often need board-specific hooks. config USB_GADGET_NET2280 - boolean "NetChip 2280" + boolean "NetChip 228x" depends on PCI select USB_GADGET_DUALSPEED help - NetChip 2280 is a PCI based USB peripheral controller which + NetChip 2280 / 2282 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. It has six configurable endpoints, as well as endpoint zero diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 865858cfd1c..b8d0b7825bf 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1709,7 +1709,7 @@ static int __devexit at91udc_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level) +static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg) { struct at91_udc *udc = platform_get_drvdata(dev); @@ -1731,7 +1731,7 @@ static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level) return 0; } -static int at91udc_resume(struct platform_device *dev, u32 level) +static int at91udc_resume(struct platform_device *dev) { struct at91_udc *udc = platform_get_drvdata(dev); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index c3d8e5c5bf2..9c4422ac9de 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2338,6 +2338,9 @@ autoconf_fail: hs_subset_descriptors(); } + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + usb_gadget_set_selfpowered (gadget); + /* For now RNDIS is always a second config */ if (rndis) device_desc.bNumConfigurations = 2; @@ -2361,9 +2364,6 @@ autoconf_fail: #endif #endif /* DUALSPEED */ - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - usb_gadget_set_selfpowered (gadget); - if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index cf3be299e35..6f887478b14 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -71,6 +71,12 @@ * requirement amounts to two 16K buffers, size configurable by a parameter. * Support is included for both full-speed and high-speed operation. * + * Note that the driver is slightly non-portable in that it assumes a + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and + * interrupt-in endpoints. With most device controllers this isn't an + * issue, but there may be some with hardware restrictions that prevent + * a buffer from being used by more than one endpoint. + * * Module options: * * file=filename[,filename...] @@ -108,6 +114,14 @@ * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. + * The driver's SCSI command interface was based on the "Information + * technology - Small Computer System Interface - 2" document from + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at + * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the + * "Universal Serial Bus Mass Storage Class UFI Command Specification" + * document, Revision 1.0, December 14, 1998, available at + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. */ @@ -334,11 +348,9 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MAX_LUNS 8 - /* Arggh! There should be a module_param_array_named macro! */ -static char *file[MAX_LUNS]; -static int ro[MAX_LUNS]; - static struct { + char *file[MAX_LUNS]; + int ro[MAX_LUNS]; int num_filenames; int num_ros; unsigned int nluns; @@ -370,10 +382,11 @@ static struct { }; -module_param_array(file, charp, &mod_data.num_filenames, S_IRUGO); +module_param_array_named(file, mod_data.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_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); module_param_named(luns, mod_data.nluns, uint, S_IRUGO); @@ -1795,6 +1808,7 @@ static int do_write(struct fsg_dev *fsg) * the bulk-out maxpacket size */ bh->outreq->length = bh->bulk_out_intended_length = amount; + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -2398,6 +2412,7 @@ static int throw_away_data(struct fsg_dev *fsg) * the bulk-out maxpacket size */ bh->outreq->length = bh->bulk_out_intended_length = amount; + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -3029,6 +3044,7 @@ static int get_next_command(struct fsg_dev *fsg) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); @@ -3859,7 +3875,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; - curlun->ro = ro[i]; + curlun->ro = mod_data.ro[i]; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; dev_set_drvdata(&curlun->dev, fsg); @@ -3876,8 +3892,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) kref_get(&fsg->ref); } - if (file[i] && *file[i]) { - if ((rc = open_backing_file(curlun, file[i])) != 0) + if (mod_data.file[i] && *mod_data.file[i]) { + if ((rc = open_backing_file(curlun, + mod_data.file[i])) != 0) goto out; } else if (!mod_data.removable) { ERROR(fsg, "no file given for LUN%d\n", i); @@ -3953,6 +3970,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < NUM_BUFFERS; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and + * interrupt-in) endpoint. */ bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, &bh->dma, GFP_KERNEL); if (!bh->buf) diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index c4081407171..aa80f091072 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -100,9 +100,9 @@ #define gadget_is_musbhsfc(g) 0 #endif -/* Mentor high speed "dual role" controller, peripheral mode */ -#ifdef CONFIG_USB_GADGET_MUSBHDRC -#define gadget_is_musbhdrc(g) !strcmp("musbhdrc_udc", (g)->name) +/* Mentor high speed "dual role" controller, in peripheral role */ +#ifdef CONFIG_USB_GADGET_MUSB_HDRC +#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name) #else #define gadget_is_musbhdrc(g) 0 #endif diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3f618ce6998..42b457030b0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -810,7 +810,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (value == 0) data->state = STATE_EP_ENABLED; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ value = usb_ep_enable (ep, &data->hs_desc); @@ -982,7 +982,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (dev->gadget->speed == USB_SPEED_HIGH) power = dev->hs_config->bMaxPower; else @@ -1262,7 +1262,7 @@ static struct file_operations ep0_io_operations = { * Unrecognized ep0 requests may be handled in user space. */ -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED static void make_qualifier (struct dev_data *dev) { struct usb_qualifier_descriptor qual; @@ -1291,7 +1291,7 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED int hs; #endif @@ -1299,7 +1299,7 @@ config_buf (struct dev_data *dev, u8 type, unsigned index) if (index > 0) return -EINVAL; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED hs = (dev->gadget->speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; @@ -1335,12 +1335,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->state = STATE_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); @@ -1352,11 +1352,11 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* ... down_trylock (&data->lock) ... */ if (data->state != STATE_EP_DEFER_ENABLE) continue; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH) value = usb_ep_enable (ep, &data->hs_desc); else -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ value = usb_ep_enable (ep, &data->desc); if (value) { ERROR (dev, "deferred %s enable --> %d\n", @@ -1391,7 +1391,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof *dev->dev); req->buf = dev->dev; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!dev->hs_config) break; @@ -1428,7 +1428,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; @@ -1728,7 +1728,7 @@ gadgetfs_suspend (struct usb_gadget *gadget) } static struct usb_gadget_driver gadgetfs_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index fb73dc10053..6a4b93ad108 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -26,6 +26,8 @@ * Copyright (C) 2003 David Brownell * Copyright (C) 2003-2005 PLX Technology, Inc. * + * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -71,8 +73,8 @@ #include <asm/unaligned.h> -#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller" -#define DRIVER_VERSION "2005 Feb 03" +#define DRIVER_DESC "PLX NET228x USB Peripheral Controller" +#define DRIVER_VERSION "2005 Sept 27" #define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ @@ -118,7 +120,7 @@ module_param (fifo_mode, ushort, 0644); /* enable_suspend -- When enabled, the driver will respond to * USB suspend requests by powering down the NET2280. Otherwise, * USB suspend requests will be ignored. This is acceptible for - * self-powered devices, and helps avoid some quirks. + * self-powered devices */ static int enable_suspend = 0; @@ -223,6 +225,11 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->is_in = (tmp & USB_DIR_IN) != 0; if (!ep->is_in) writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + else if (dev->pdev->device != 0x2280) { + /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */ + writel ((1 << CLEAR_NAK_OUT_PACKETS) + | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); + } writel (tmp, &ep->regs->ep_cfg); @@ -232,8 +239,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) writel (tmp, &dev->regs->pciirqenb0); tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | readl (&ep->regs->ep_irqenb); + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); + if (dev->pdev->device == 0x2280) + tmp |= readl (&ep->regs->ep_irqenb); writel (tmp, &ep->regs->ep_irqenb); } else { /* dma, per-request */ tmp = (1 << (8 + ep->num)); /* completion */ @@ -314,10 +322,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - tmp = (1 << SET_NAK_OUT_PACKETS_MODE) + if (!ep->is_in || ep->dev->pdev->device == 0x2280) { + tmp = (1 << SET_NAK_OUT_PACKETS_MODE) | (1 << SET_NAK_OUT_PACKETS) | (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_INTERRUPT_MODE); + } else { + /* added for 2282 */ + tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE) + | (1 << CLEAR_NAK_OUT_PACKETS) + | (1 << CLEAR_EP_HIDE_STATUS_PHASE) + | (1 << CLEAR_INTERRUPT_MODE); + } if (ep->num != 0) { tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) @@ -326,14 +342,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ - writel ( (1 << TIMEOUT) + if (ep->dev->pdev->device == 0x2280) + tmp = (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW); + else + tmp = 0; + + writel (tmp | (1 << TIMEOUT) | (1 << USB_STALL_SENT) | (1 << USB_IN_NAK_SENT) | (1 << USB_IN_ACK_RCVD) | (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW) | (1 << FIFO_FLUSH) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) @@ -718,7 +738,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) */ if (ep->is_in) dmacount |= (1 << DMA_DIRECTION); - else if ((dmacount % ep->ep.maxpacket) != 0) + if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280) dmacount |= (1 << END_OF_CHAIN); req->valid = valid; @@ -760,9 +780,12 @@ static inline void stop_dma (struct net2280_dma_regs __iomem *dma) static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) { struct net2280_dma_regs __iomem *dma = ep->dma; + unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION); - writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), - &dma->dmacount); + if (ep->dev->pdev->device != 0x2280) + tmp |= (1 << END_OF_CHAIN); + + writel (tmp, &dma->dmacount); writel (readl (&dma->dmastat), &dma->dmastat); writel (td_dma, &dma->dmadesc); @@ -2110,7 +2133,11 @@ static void handle_ep_small (struct net2280_ep *ep) VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", ep->ep.name, t, req ? &req->req : 0); #endif - writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + if (!ep->is_in || ep->dev->pdev->device == 0x2280) + writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + else + /* Added for 2282 */ + writel (t, &ep->regs->ep_stat); /* for ep0, monitor token irqs to catch data stage length errors * and to synchronize on status. @@ -2214,7 +2241,8 @@ static void handle_ep_small (struct net2280_ep *ep) if (likely (req)) { req->td->dmacount = 0; t = readl (&ep->regs->ep_avail); - dma_done (ep, req, count, t); + dma_done (ep, req, count, + (ep->out_overflow || t) ? -EOVERFLOW : 0); } /* also flush to prevent erratum 0106 trouble */ @@ -2337,7 +2365,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) u32 raw [2]; struct usb_ctrlrequest r; } u; - int tmp = 0; + int tmp; struct net2280_request *req; if (dev->gadget.speed == USB_SPEED_UNKNOWN) { @@ -2364,14 +2392,19 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; - writel ( (1 << TIMEOUT) + + if (ep->dev->pdev->device == 0x2280) + tmp = (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW); + else + tmp = 0; + + writel (tmp | (1 << TIMEOUT) | (1 << USB_STALL_SENT) | (1 << USB_IN_NAK_SENT) | (1 << USB_IN_ACK_RCVD) | (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | (1 << DATA_PACKET_RECEIVED_INTERRUPT) @@ -2385,6 +2418,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); + tmp = 0; + #define w_value le16_to_cpup (&u.r.wValue) #define w_index le16_to_cpup (&u.r.wIndex) #define w_length le16_to_cpup (&u.r.wLength) @@ -2594,10 +2629,17 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) writel (stat, &dev->regs->irqstat1); /* some status we can just ignore */ - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_INTERRUPT)); + if (dev->pdev->device == 0x2280) + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << SUSPEND_REQUEST_INTERRUPT) + | (1 << RESUME_INTERRUPT) + | (1 << SOF_INTERRUPT)); + else + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << RESUME_INTERRUPT) + | (1 << SOF_DOWN_INTERRUPT) + | (1 << SOF_INTERRUPT)); + if (!stat) return; // DEBUG (dev, "irqstat1 %08x\n", stat); @@ -2939,6 +2981,13 @@ static struct pci_device_id pci_ids [] = { { .device = 0x2280, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, +}, { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x17cc, + .device = 0x2282, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index fff4509cf34..957d6df3401 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -22,420 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/*-------------------------------------------------------------------------*/ - -/* NET2280 MEMORY MAPPED REGISTERS - * - * The register layout came from the chip documentation, and the bit - * number definitions were extracted from chip specification. - * - * Use the shift operator ('<<') to build bit masks, with readl/writel - * to access the registers through PCI. - */ - -/* main registers, BAR0 + 0x0000 */ -struct net2280_regs { - // offset 0x0000 - u32 devinit; -#define LOCAL_CLOCK_FREQUENCY 8 -#define FORCE_PCI_RESET 7 -#define PCI_ID 6 -#define PCI_ENABLE 5 -#define FIFO_SOFT_RESET 4 -#define CFG_SOFT_RESET 3 -#define PCI_SOFT_RESET 2 -#define USB_SOFT_RESET 1 -#define M8051_RESET 0 - u32 eectl; -#define EEPROM_ADDRESS_WIDTH 23 -#define EEPROM_CHIP_SELECT_ACTIVE 22 -#define EEPROM_PRESENT 21 -#define EEPROM_VALID 20 -#define EEPROM_BUSY 19 -#define EEPROM_CHIP_SELECT_ENABLE 18 -#define EEPROM_BYTE_READ_START 17 -#define EEPROM_BYTE_WRITE_START 16 -#define EEPROM_READ_DATA 8 -#define EEPROM_WRITE_DATA 0 - u32 eeclkfreq; - u32 _unused0; - // offset 0x0010 - - u32 pciirqenb0; /* interrupt PCI master ... */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - u32 pciirqenb1; -#define PCI_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - u32 cpu_irqenb0; /* ... or onboard 8051 */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - u32 cpu_irqenb1; -#define CPU_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - - // offset 0x0020 - u32 _unused1; - u32 usbirqenb1; -#define USB_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - u32 irqstat0; -#define INTA_ASSERTED 12 -#define SETUP_PACKET_INTERRUPT 7 -#define ENDPOINT_F_INTERRUPT 6 -#define ENDPOINT_E_INTERRUPT 5 -#define ENDPOINT_D_INTERRUPT 4 -#define ENDPOINT_C_INTERRUPT 3 -#define ENDPOINT_B_INTERRUPT 2 -#define ENDPOINT_A_INTERRUPT 1 -#define ENDPOINT_0_INTERRUPT 0 - u32 irqstat1; -#define POWER_STATE_CHANGE_INTERRUPT 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 -#define PCI_PARITY_ERROR_INTERRUPT 25 -#define PCI_INTA_INTERRUPT 24 -#define PCI_PME_INTERRUPT 23 -#define PCI_SERR_INTERRUPT 22 -#define PCI_PERR_INTERRUPT 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 -#define PCI_RETRY_ABORT_INTERRUPT 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 -#define GPIO_INTERRUPT 13 -#define DMA_D_INTERRUPT 12 -#define DMA_C_INTERRUPT 11 -#define DMA_B_INTERRUPT 10 -#define DMA_A_INTERRUPT 9 -#define EEPROM_DONE_INTERRUPT 8 -#define VBUS_INTERRUPT 7 -#define CONTROL_STATUS_INTERRUPT 6 -#define ROOT_PORT_RESET_INTERRUPT 4 -#define SUSPEND_REQUEST_INTERRUPT 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 -#define RESUME_INTERRUPT 1 -#define SOF_INTERRUPT 0 - // offset 0x0030 - u32 idxaddr; - u32 idxdata; - u32 fifoctl; -#define PCI_BASE2_RANGE 16 -#define IGNORE_FIFO_AVAILABILITY 3 -#define PCI_BASE2_SELECT 2 -#define FIFO_CONFIGURATION_SELECT 0 - u32 _unused2; - // offset 0x0040 - u32 memaddr; -#define START 28 -#define DIRECTION 27 -#define FIFO_DIAGNOSTIC_SELECT 24 -#define MEMORY_ADDRESS 0 - u32 memdata0; - u32 memdata1; - u32 _unused3; - // offset 0x0050 - u32 gpioctl; -#define GPIO3_LED_SELECT 12 -#define GPIO3_INTERRUPT_ENABLE 11 -#define GPIO2_INTERRUPT_ENABLE 10 -#define GPIO1_INTERRUPT_ENABLE 9 -#define GPIO0_INTERRUPT_ENABLE 8 -#define GPIO3_OUTPUT_ENABLE 7 -#define GPIO2_OUTPUT_ENABLE 6 -#define GPIO1_OUTPUT_ENABLE 5 -#define GPIO0_OUTPUT_ENABLE 4 -#define GPIO3_DATA 3 -#define GPIO2_DATA 2 -#define GPIO1_DATA 1 -#define GPIO0_DATA 0 - u32 gpiostat; -#define GPIO3_INTERRUPT 3 -#define GPIO2_INTERRUPT 2 -#define GPIO1_INTERRUPT 1 -#define GPIO0_INTERRUPT 0 -} __attribute__ ((packed)); - -/* usb control, BAR0 + 0x0080 */ -struct net2280_usb_regs { - // offset 0x0080 - u32 stdrsp; -#define STALL_UNSUPPORTED_REQUESTS 31 -#define SET_TEST_MODE 16 -#define GET_OTHER_SPEED_CONFIGURATION 15 -#define GET_DEVICE_QUALIFIER 14 -#define SET_ADDRESS 13 -#define ENDPOINT_SET_CLEAR_HALT 12 -#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 -#define GET_STRING_DESCRIPTOR_2 10 -#define GET_STRING_DESCRIPTOR_1 9 -#define GET_STRING_DESCRIPTOR_0 8 -#define GET_SET_INTERFACE 6 -#define GET_SET_CONFIGURATION 5 -#define GET_CONFIGURATION_DESCRIPTOR 4 -#define GET_DEVICE_DESCRIPTOR 3 -#define GET_ENDPOINT_STATUS 2 -#define GET_INTERFACE_STATUS 1 -#define GET_DEVICE_STATUS 0 - u32 prodvendid; -#define PRODUCT_ID 16 -#define VENDOR_ID 0 - u32 relnum; - u32 usbctl; -#define SERIAL_NUMBER_INDEX 16 -#define PRODUCT_ID_STRING_ENABLE 13 -#define VENDOR_ID_STRING_ENABLE 12 -#define USB_ROOT_PORT_WAKEUP_ENABLE 11 -#define VBUS_PIN 10 -#define TIMED_DISCONNECT 9 -#define SUSPEND_IMMEDIATELY 7 -#define SELF_POWERED_USB_DEVICE 6 -#define REMOTE_WAKEUP_SUPPORT 5 -#define PME_POLARITY 4 -#define USB_DETECT_ENABLE 3 -#define PME_WAKEUP_ENABLE 2 -#define DEVICE_REMOTE_WAKEUP_ENABLE 1 -#define SELF_POWERED_STATUS 0 - // offset 0x0090 - u32 usbstat; -#define HIGH_SPEED 7 -#define FULL_SPEED 6 -#define GENERATE_RESUME 5 -#define GENERATE_DEVICE_REMOTE_WAKEUP 4 - u32 xcvrdiag; -#define FORCE_HIGH_SPEED_MODE 31 -#define FORCE_FULL_SPEED_MODE 30 -#define USB_TEST_MODE 24 -#define LINE_STATE 16 -#define TRANSCEIVER_OPERATION_MODE 2 -#define TRANSCEIVER_SELECT 1 -#define TERMINATION_SELECT 0 - u32 setup0123; - u32 setup4567; - // offset 0x0090 - u32 _unused0; - u32 ouraddr; -#define FORCE_IMMEDIATE 7 -#define OUR_USB_ADDRESS 0 - u32 ourconfig; -} __attribute__ ((packed)); - -/* pci control, BAR0 + 0x0100 */ -struct net2280_pci_regs { - // offset 0x0100 - u32 pcimstctl; -#define PCI_ARBITER_PARK_SELECT 13 -#define PCI_MULTI LEVEL_ARBITER 12 -#define PCI_RETRY_ABORT_ENABLE 11 -#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 -#define DMA_READ_MULTIPLE_ENABLE 9 -#define DMA_READ_LINE_ENABLE 8 -#define PCI_MASTER_COMMAND_SELECT 6 -#define MEM_READ_OR_WRITE 0 -#define IO_READ_OR_WRITE 1 -#define CFG_READ_OR_WRITE 2 -#define PCI_MASTER_START 5 -#define PCI_MASTER_READ_WRITE 4 -#define PCI_MASTER_WRITE 0 -#define PCI_MASTER_READ 1 -#define PCI_MASTER_BYTE_WRITE_ENABLES 0 - u32 pcimstaddr; - u32 pcimstdata; - u32 pcimststat; -#define PCI_ARBITER_CLEAR 2 -#define PCI_EXTERNAL_ARBITER 1 -#define PCI_HOST_MODE 0 -} __attribute__ ((packed)); - -/* dma control, BAR0 + 0x0180 ... array of four structs like this, - * for channels 0..3. see also struct net2280_dma: descriptor - * that can be loaded into some of these registers. - */ -struct net2280_dma_regs { /* [11.7] */ - // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, - u32 dmactl; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 -#define DMA_CLEAR_COUNT_ENABLE 21 -#define DESCRIPTOR_POLLING_RATE 19 -#define POLL_CONTINUOUS 0 -#define POLL_1_USEC 1 -#define POLL_100_USEC 2 -#define POLL_1_MSEC 3 -#define DMA_VALID_BIT_POLLING_ENABLE 18 -#define DMA_VALID_BIT_ENABLE 17 -#define DMA_SCATTER_GATHER_ENABLE 16 -#define DMA_OUT_AUTO_START_ENABLE 4 -#define DMA_PREEMPT_ENABLE 3 -#define DMA_FIFO_VALIDATE 2 -#define DMA_ENABLE 1 -#define DMA_ADDRESS_HOLD 0 - u32 dmastat; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 -#define DMA_TRANSACTION_DONE_INTERRUPT 24 -#define DMA_ABORT 1 -#define DMA_START 0 - u32 _unused0 [2]; - // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, - u32 dmacount; -#define VALID_BIT 31 -#define DMA_DIRECTION 30 -#define DMA_DONE_INTERRUPT_ENABLE 29 -#define END_OF_CHAIN 28 -#define DMA_BYTE_COUNT_MASK ((1<<24)-1) -#define DMA_BYTE_COUNT 0 - u32 dmaaddr; - u32 dmadesc; - u32 _unused1; -} __attribute__ ((packed)); - -/* dedicated endpoint registers, BAR0 + 0x0200 */ - -struct net2280_dep_regs { /* [11.8] */ - // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 - u32 dep_cfg; - // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 - u32 dep_rsp; - u32 _unused [2]; -} __attribute__ ((packed)); - -/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs - * like this, for ep0 then the configurable endpoints A..F - * ep0 reserved for control; E and F have only 64 bytes of fifo - */ -struct net2280_ep_regs { /* [11.9] */ - // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 - u32 ep_cfg; -#define ENDPOINT_BYTE_COUNT 16 -#define ENDPOINT_ENABLE 10 -#define ENDPOINT_TYPE 8 -#define ENDPOINT_DIRECTION 7 -#define ENDPOINT_NUMBER 0 - u32 ep_rsp; -#define SET_NAK_OUT_PACKETS 15 -#define SET_EP_HIDE_STATUS_PHASE 14 -#define SET_EP_FORCE_CRC_ERROR 13 -#define SET_INTERRUPT_MODE 12 -#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 -#define SET_NAK_OUT_PACKETS_MODE 10 -#define SET_ENDPOINT_TOGGLE 9 -#define SET_ENDPOINT_HALT 8 -#define CLEAR_NAK_OUT_PACKETS 7 -#define CLEAR_EP_HIDE_STATUS_PHASE 6 -#define CLEAR_EP_FORCE_CRC_ERROR 5 -#define CLEAR_INTERRUPT_MODE 4 -#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 -#define CLEAR_NAK_OUT_PACKETS_MODE 2 -#define CLEAR_ENDPOINT_TOGGLE 1 -#define CLEAR_ENDPOINT_HALT 0 - u32 ep_irqenb; -#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 -#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 -#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 - u32 ep_stat; -#define FIFO_VALID_COUNT 24 -#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 -#define TIMEOUT 21 -#define USB_STALL_SENT 20 -#define USB_IN_NAK_SENT 19 -#define USB_IN_ACK_RCVD 18 -#define USB_OUT_PING_NAK_SENT 17 -#define USB_OUT_ACK_SENT 16 -#define FIFO_OVERFLOW 13 -#define FIFO_UNDERFLOW 12 -#define FIFO_FULL 11 -#define FIFO_EMPTY 10 -#define FIFO_FLUSH 9 -#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 -#define NAK_OUT_PACKETS 4 -#define DATA_PACKET_RECEIVED_INTERRUPT 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT 1 -#define DATA_IN_TOKEN_INTERRUPT 0 - // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 - u32 ep_avail; - u32 ep_data; - u32 _unused0 [2]; -} __attribute__ ((packed)); +#include <linux/usb/net2280.h> /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 51424f66a76..68e3d8f5da8 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -572,9 +572,10 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { case 0: /* normal completion? */ - if (ep == dev->out_ep) + if (ep == dev->out_ep) { check_read_data (dev, ep, req); - else + memset (req->buf, 0x55, req->length); + } else reinit_write_data (dev, ep, req); break; @@ -626,6 +627,8 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) if (strcmp (ep->name, EP_IN_NAME) == 0) reinit_write_data (ep->driver_data, ep, req); + else + memset (req->buf, 0x55, req->length); status = usb_ep_queue (ep, req, gfp_flags); if (status) { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 980030d684d..6b7350b5241 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -20,7 +20,7 @@ #include <asm/arch/board.h> #ifndef CONFIG_ARCH_AT91RM9200 -#error "This file is AT91RM9200 bus glue. CONFIG_ARCH_AT91RM9200 must be defined." +#error "CONFIG_ARCH_AT91RM9200 must be defined." #endif /* interface and function clocks */ @@ -84,8 +84,6 @@ static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); * 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_at91_probe (const struct hc_driver *driver, struct platform_device *pdev) { @@ -148,7 +146,6 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device * } -/* may be called without controller electrically present */ /* may be called with controller, bus, and devices active */ /** @@ -166,11 +163,11 @@ static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pde usb_remove_hcd(hcd); at91_stop_hc(pdev); iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - clk_put(fclk); - clk_put(iclk); - fclk = iclk = NULL; + clk_put(fclk); + clk_put(iclk); + fclk = iclk = NULL; dev_set_drvdata(&pdev->dev, NULL); return 0; @@ -235,8 +232,8 @@ static const struct hc_driver ohci_at91_hc_driver = { .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; @@ -254,21 +251,21 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level) -{ - printk("%s(%s:%d): not implemented yet\n", - __func__, __FILE__, __LINE__); +/* REVISIT suspend/resume look "too" simple here */ + +static int +ohci_hcd_at91_drv_suspend(struct platform_device *dev, pm_message_t mesg) +{ clk_disable(fclk); + clk_disable(iclk); return 0; } -static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state) +static int ohci_hcd_at91_drv_resume(struct platform_device *dev) { - printk("%s(%s:%d): not implemented yet\n", - __func__, __FILE__, __LINE__); - + clk_enable(iclk); clk_enable(fclk); return 0; @@ -278,6 +275,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state) #define ohci_hcd_at91_drv_resume NULL #endif +MODULE_ALIAS("at91rm9200-ohci"); + static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, .remove = ohci_hcd_at91_drv_remove, diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 682bf221566..1da5de573a6 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -30,6 +30,7 @@ /* clock device associated with the hcd */ static struct clk *clk; +static struct clk *usb_clk; /* forward definitions */ @@ -37,7 +38,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); /* conversion functions */ -struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) +static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) { return hcd->self.controller->platform_data; } @@ -47,6 +48,10 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) struct s3c2410_hcd_info *info = dev->dev.platform_data; dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); + + clk_enable(usb_clk); + mdelay(2); /* let the bus clock stabilise */ + clk_enable(clk); if (info != NULL) { @@ -75,6 +80,7 @@ static void s3c2410_stop_hc(struct platform_device *dev) } clk_disable(clk); + clk_disable(usb_clk); } /* ohci_s3c2410_hub_status_data @@ -316,7 +322,8 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) * */ -void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) +static void +usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) { usb_remove_hcd(hcd); s3c2410_stop_hc(dev); @@ -334,8 +341,8 @@ void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) * through the hotplug entry's driver_data. * */ -int usb_hcd_s3c2410_probe (const struct hc_driver *driver, - struct platform_device *dev) +static int usb_hcd_s3c2410_probe (const struct hc_driver *driver, + struct platform_device *dev) { struct usb_hcd *hcd = NULL; int retval; @@ -353,14 +360,21 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_err(&dev->dev, "request_mem_region failed"); retval = -EBUSY; - goto err0; + goto err_put; } - clk = clk_get(NULL, "usb-host"); + clk = clk_get(&dev->dev, "usb-host"); if (IS_ERR(clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = -ENOENT; - goto err1; + goto err_mem; + } + + usb_clk = clk_get(&dev->dev, "upll"); + if (IS_ERR(usb_clk)) { + dev_err(&dev->dev, "cannot get usb-host clock\n"); + retval = -ENOENT; + goto err_clk; } s3c2410_start_hc(dev, hcd); @@ -369,26 +383,29 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, if (!hcd->regs) { dev_err(&dev->dev, "ioremap failed\n"); retval = -ENOMEM; - goto err2; + goto err_ioremap; } ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); if (retval != 0) - goto err2; + goto err_ioremap; return 0; - err2: + err_ioremap: s3c2410_stop_hc(dev); iounmap(hcd->regs); + clk_put(usb_clk); + + err_clk: clk_put(clk); - err1: + err_mem: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err0: + err_put: usb_put_hcd(hcd); return retval; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 9e81c26313f..1045f846fbe 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/acpi.h> +#include "pci-quirks.h" #define UHCI_USBLEGSUP 0xc0 /* legacy support */ diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h new file mode 100644 index 00000000000..1564edfff6f --- /dev/null +++ b/drivers/usb/host/pci-quirks.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_USB_PCI_QUIRKS_H +#define __LINUX_USB_PCI_QUIRKS_H + +void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); +int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); + +#endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4edb8330c44..c0c4db78b59 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -50,6 +50,7 @@ #include "../core/hcd.h" #include "uhci-hcd.h" +#include "pci-quirks.h" /* * Version Information @@ -100,9 +101,6 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); #include "uhci-q.c" #include "uhci-hub.c" -extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); -extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); - /* * Finish up a host controller reset and update the recorded state. */ @@ -117,8 +115,7 @@ static void finish_reset(struct uhci_hcd *uhci) for (port = 0; port < uhci->rh_numports; ++port) outw(0, uhci->io_addr + USBPORTSC1 + (port * 2)); - uhci->port_c_suspend = uhci->suspended_ports = - uhci->resuming_ports = 0; + uhci->port_c_suspend = uhci->resuming_ports = 0; uhci->rh_state = UHCI_RH_RESET; uhci->is_stopped = UHCI_IS_STOPPED; uhci_to_hcd(uhci)->state = HC_STATE_HALT; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 4a69c7eb09b..d5c8f4d9282 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -415,7 +415,6 @@ struct uhci_hcd { /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ - unsigned long suspended_ports; unsigned long resuming_ports; unsigned long ports_timeout; /* Time to stop signalling */ diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 152971d1676..c8451d9578f 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -85,11 +85,10 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, { int status; - if (test_bit(port, &uhci->suspended_ports)) { + if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); - clear_bit(port, &uhci->suspended_ports); - clear_bit(port, &uhci->resuming_ports); - set_bit(port, &uhci->port_c_suspend); + if (test_bit(port, &uhci->resuming_ports)) + set_bit(port, &uhci->port_c_suspend); /* The controller won't actually turn off the RD bit until * it has had a chance to send a low-speed EOP sequence, @@ -97,6 +96,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, * slightly longer for good luck. */ udelay(4); } + clear_bit(port, &uhci->resuming_ports); } /* Wait for the UHCI controller in HP's iLO2 server management chip. @@ -265,8 +265,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wPortChange |= USB_PORT_STAT_C_SUSPEND; lstatus |= 1; } - if (test_bit(port, &uhci->suspended_ports)) - lstatus |= 2; if (test_bit(port, &uhci->resuming_ports)) lstatus |= 4; @@ -309,7 +307,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_SUSPEND: - set_bit(port, &uhci->suspended_ports); SET_RH_PORTSTAT(USBPORTSC_SUSP); OK(0); case USB_PORT_FEAT_RESET: @@ -343,8 +340,11 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, CLR_RH_PORTSTAT(USBPORTSC_PEC); OK(0); case USB_PORT_FEAT_SUSPEND: - if (test_bit(port, &uhci->suspended_ports) && - !test_and_set_bit(port, + if (!(inw(port_addr) & USBPORTSC_SUSP)) { + + /* Make certain the port isn't suspended */ + uhci_finish_suspend(uhci, port, port_addr); + } else if (!test_and_set_bit(port, &uhci->resuming_ports)) { SET_RH_PORTSTAT(USBPORTSC_RD); diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 5246b35301d..650103bc961 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -200,45 +200,41 @@ config USB_POWERMATE To compile this driver as a module, choose M here: the module will be called powermate. -config USB_MTOUCH - tristate "MicroTouch USB Touchscreen Driver" +config USB_TOUCHSCREEN + tristate "USB Touchscreen Driver" depends on USB && INPUT ---help--- - Say Y here if you want to use a MicroTouch (Now 3M) USB - Touchscreen controller. + USB Touchscreen driver for: + - eGalax Touchkit USB + - PanJit TouchSet USB + - 3M MicroTouch USB + - ITM - See <file:Documentation/usb/mtouch.txt> for additional information. - - To compile this driver as a module, choose M here: the - module will be called mtouchusb. - -config USB_ITMTOUCH - tristate "ITM Touch USB Touchscreen Driver" - depends on USB && INPUT - ---help--- - Say Y here if you want to use a ITM Touch USB - Touchscreen controller. - - This touchscreen is used in LG 1510SF monitors. + Have a look at <http://linux.chapter7.ch/touchkit/> for + a usage description and the required user-space stuff. To compile this driver as a module, choose M here: the - module will be called itmtouch. + module will be called usbtouchscreen. -config USB_EGALAX - tristate "eGalax TouchKit USB Touchscreen Driver" - depends on USB && INPUT - ---help--- - Say Y here if you want to use a eGalax TouchKit USB - Touchscreen controller. +config USB_TOUCHSCREEN_EGALAX + default y + bool "eGalax device support" if EMBEDDED + depends on USB_TOUCHSCREEN - The driver has been tested on a Xenarc 700TSV monitor - with eGalax touchscreen. +config USB_TOUCHSCREEN_PANJIT + default y + bool "PanJit device support" if EMBEDDED + depends on USB_TOUCHSCREEN - Have a look at <http://linux.chapter7.ch/touchkit/> for - a usage description and the required user-space stuff. +config USB_TOUCHSCREEN_3M + default y + bool "3M/Microtouch device support" if EMBEDDED + depends on USB_TOUCHSCREEN - To compile this driver as a module, choose M here: the - module will be called touchkitusb. +config USB_TOUCHSCREEN_ITM + default y + bool "ITM device support" if EMBEDDED + depends on USB_TOUCHSCREEN config USB_YEALINK tristate "Yealink usb-p1k voip phone" diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index d512d9f488f..764114529c5 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o +obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_ACECAD) += acecad.o diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index d4bf1701046..f419bd82ab7 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1372,6 +1372,11 @@ void hid_close(struct hid_device *hid) usb_kill_urb(hid->urbin); } +#define USB_VENDOR_ID_PANJIT 0x134c + +#define USB_VENDOR_ID_SILVERCREST 0x062a +#define USB_DEVICE_ID_SILVERCREST_KB 0x0201 + /* * Initialize all reports */ @@ -1655,9 +1660,12 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, @@ -1675,6 +1683,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, @@ -1701,6 +1710,11 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { 0, 0 } }; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 72e698658b5..d5c91ee6799 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -34,12 +34,6 @@ #include "hid.h" -/* Drivers' initializing functions */ -extern int hid_lgff_init(struct hid_device* hid); -extern int hid_lg3d_init(struct hid_device* hid); -extern int hid_pid_init(struct hid_device* hid); -extern int hid_tmff_init(struct hid_device* hid); - /* * This table contains pointers to initializers. To add support for new * devices, you need to add the USB vendor and product ids here. diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 4e1b784fe52..9c62837b5b8 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -533,3 +533,8 @@ static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input, return hid->ff_event(hid, input, type, code, value); return -ENOSYS; } + +int hid_lgff_init(struct hid_device* hid); +int hid_tmff_init(struct hid_device* hid); +int hid_pid_init(struct hid_device* hid); + diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index b4a051b549d..3d911976f37 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -297,6 +297,8 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) remote->data.bits_left -= 6; } else { err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + remote->stage = 0; + return; } keyspan_load_tester(remote, 5); diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c new file mode 100644 index 00000000000..e9a07c1e905 --- /dev/null +++ b/drivers/usb/input/usbtouchscreen.c @@ -0,0 +1,605 @@ +/****************************************************************************** + * usbtouchscreen.c + * Driver for USB Touchscreens, supporting those devices: + * - eGalax Touchkit + * - 3M/Microtouch + * - ITM + * - PanJit TouchSet + * + * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> + * Copyright (C) by Todd E. Johnson (mtouchusb.c) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Driver is based on touchkitusb.c + * - ITM parts are from itmtouch.c + * - 3M parts are from mtouchusb.c + * - PanJit parts are from an unmerged driver by Lanslott Gish + * + *****************************************************************************/ + +//#define DEBUG + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb_input.h> + + +#define DRIVER_VERSION "v0.3" +#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>" +#define DRIVER_DESC "USB Touchscreen Driver" + +static int swap_xy; +module_param(swap_xy, bool, 0644); +MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); + +/* device specifc data/functions */ +struct usbtouch_usb; +struct usbtouch_device_info { + int min_xc, max_xc; + int min_yc, max_yc; + int min_press, max_press; + int rept_size; + int flags; + + void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len); + int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press); + int (*init) (struct usbtouch_usb *usbtouch); +}; + +#define USBTOUCH_FLG_BUFFER 0x01 + + +/* a usbtouch device */ +struct usbtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + unsigned char *buffer; + int buf_len; + struct urb *irq; + struct usb_device *udev; + struct input_dev *input; + struct usbtouch_device_info *type; + char name[128]; + char phys[64]; +}; + +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + struct pt_regs *regs, unsigned char *pkt, int len); + +/* device types */ +enum { + DEVTPYE_DUMMY = -1, + DEVTYPE_EGALAX, + DEVTYPE_PANJIT, + DEVTYPE_3M, + DEVTYPE_ITM, +}; + +static struct usb_device_id usbtouch_devices[] = { +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT + {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_3M + {USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_ITM + {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM}, +#endif + + {} +}; + + +/***************************************************************************** + * eGalax part + */ + +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + +#define EGALAX_PKT_TYPE_MASK 0xFE +#define EGALAX_PKT_TYPE_REPT 0x80 +#define EGALAX_PKT_TYPE_DIAG 0x0A + +static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) + return 0; + + *x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); + *y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); + *touch = pkt[0] & 0x01; + + return 1; + +} + +static int egalax_get_pkt_len(unsigned char *buf) +{ + switch (buf[0] & EGALAX_PKT_TYPE_MASK) { + case EGALAX_PKT_TYPE_REPT: + return 5; + + case EGALAX_PKT_TYPE_DIAG: + return buf[1] + 2; + } + + return 0; +} + +static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs, + unsigned char *pkt, int len) +{ + unsigned char *buffer; + int pkt_len, buf_len, pos; + + /* if the buffer contains data, append */ + if (unlikely(usbtouch->buf_len)) { + int tmp; + + /* if only 1 byte in buffer, add another one to get length */ + if (usbtouch->buf_len == 1) + usbtouch->buffer[1] = pkt[0]; + + pkt_len = egalax_get_pkt_len(usbtouch->buffer); + + /* unknown packet: drop everything */ + if (!pkt_len) + return; + + /* append, process */ + tmp = pkt_len - usbtouch->buf_len; + memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp); + usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len); + + buffer = pkt + tmp; + buf_len = len - tmp; + } else { + buffer = pkt; + buf_len = len; + } + + /* only one byte left in buffer */ + if (unlikely(buf_len == 1)) { + usbtouch->buffer[0] = buffer[0]; + usbtouch->buf_len = 1; + return; + } + + /* loop over the buffer */ + pos = 0; + while (pos < buf_len) { + /* get packet len */ + pkt_len = egalax_get_pkt_len(buffer + pos); + + /* unknown packet: drop everything */ + if (unlikely(!pkt_len)) + return; + + /* full packet: process */ + if (likely(pkt_len <= buf_len)) { + usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len); + } else { + /* incomplete packet: save in buffer */ + memcpy(usbtouch->buffer, buffer + pos, buf_len - pos); + usbtouch->buf_len = buf_len - pos; + } + pos += pkt_len; + } +} +#endif + + +/***************************************************************************** + * PanJit Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT +static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + *y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + *touch = pkt[0] & 0x01; + + return 1; +} +#endif + + +/***************************************************************************** + * 3M/Microtouch Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_3M + +#define MTOUCHUSB_ASYNC_REPORT 1 +#define MTOUCHUSB_RESET 7 +#define MTOUCHUSB_REQ_CTRLLR_ID 10 + +static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = (pkt[8] << 8) | pkt[7]; + *y = (pkt[10] << 8) | pkt[9]; + *touch = (pkt[2] & 0x40) ? 1 : 0; + + return 1; +} + +static int mtouch_init(struct usbtouch_usb *usbtouch) +{ + int ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + MTOUCHUSB_RESET, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", + __FUNCTION__, ret); + if (ret < 0) + return ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + MTOUCHUSB_ASYNC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", + __FUNCTION__, ret); + if (ret < 0) + return ret; + + return 0; +} +#endif + + +/***************************************************************************** + * ITM Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_ITM +static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); + *x = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); + *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); + *touch = ~pkt[7] & 0x20; + + return 1; +} +#endif + + +/***************************************************************************** + * the different device descriptors + */ +static struct usbtouch_device_info usbtouch_dev_info[] = { +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + [DEVTYPE_EGALAX] = { + .min_xc = 0x0, + .max_xc = 0x07ff, + .min_yc = 0x0, + .max_yc = 0x07ff, + .rept_size = 16, + .flags = USBTOUCH_FLG_BUFFER, + .process_pkt = egalax_process, + .read_data = egalax_read_data, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT + [DEVTYPE_PANJIT] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 8, + .read_data = panjit_read_data, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_3M + [DEVTYPE_3M] = { + .min_xc = 0x0, + .max_xc = 0x4000, + .min_yc = 0x0, + .max_yc = 0x4000, + .rept_size = 11, + .read_data = mtouch_read_data, + .init = mtouch_init, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_ITM + [DEVTYPE_ITM] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .max_press = 0xff, + .rept_size = 8, + .read_data = itm_read_data, + }, +#endif +}; + + +/***************************************************************************** + * Generic Part + */ +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + struct pt_regs *regs, unsigned char *pkt, int len) +{ + int x, y, touch, press; + struct usbtouch_device_info *type = usbtouch->type; + + if (!type->read_data(pkt, &x, &y, &touch, &press)) + return; + + input_regs(usbtouch->input, regs); + input_report_key(usbtouch->input, BTN_TOUCH, touch); + + if (swap_xy) { + input_report_abs(usbtouch->input, ABS_X, y); + input_report_abs(usbtouch->input, ABS_Y, x); + } else { + input_report_abs(usbtouch->input, ABS_X, x); + input_report_abs(usbtouch->input, ABS_Y, y); + } + if (type->max_press) + input_report_abs(usbtouch->input, ABS_PRESSURE, press); + input_sync(usbtouch->input); +} + + +static void usbtouch_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usbtouch_usb *usbtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + usbtouch->type->process_pkt(usbtouch, regs, usbtouch->data, urb->actual_length); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int usbtouch_open(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input->private; + + usbtouch->irq->dev = usbtouch->udev; + + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void usbtouch_close(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input->private; + + usb_kill_urb(usbtouch->irq); +} + + +static void usbtouch_free_buffers(struct usb_device *udev, + struct usbtouch_usb *usbtouch) +{ + if (usbtouch->data) + usb_buffer_free(udev, usbtouch->type->rept_size, + usbtouch->data, usbtouch->data_dma); + kfree(usbtouch->buffer); +} + + +static int usbtouch_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usbtouch_usb *usbtouch; + struct input_dev *input_dev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + struct usbtouch_device_info *type; + int err; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!usbtouch || !input_dev) + goto out_free; + + type = &usbtouch_dev_info[id->driver_info]; + usbtouch->type = type; + if (!type->process_pkt) + type->process_pkt = usbtouch_process_pkt; + + usbtouch->data = usb_buffer_alloc(udev, type->rept_size, + SLAB_KERNEL, &usbtouch->data_dma); + if (!usbtouch->data) + goto out_free; + + if (type->flags & USBTOUCH_FLG_BUFFER) { + usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); + if (!usbtouch->buffer) + goto out_free_buffers; + } + + usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!usbtouch->irq) { + dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__); + goto out_free_buffers; + } + + usbtouch->udev = udev; + usbtouch->input = input_dev; + + if (udev->manufacturer) + strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); + strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); + } + + if (!strlen(usbtouch->name)) + snprintf(usbtouch->name, sizeof(usbtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); + strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); + + input_dev->name = usbtouch->name; + input_dev->phys = usbtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = usbtouch; + input_dev->open = usbtouch_open; + input_dev->close = usbtouch_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0); + input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); + if (type->max_press) + input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, + type->max_press, 0, 0); + + usb_fill_int_urb(usbtouch->irq, usbtouch->udev, + usb_rcvintpipe(usbtouch->udev, 0x81), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch, endpoint->bInterval); + + usbtouch->irq->transfer_dma = usbtouch->data_dma; + usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* device specific init */ + if (type->init) { + err = type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", __FUNCTION__, err); + goto out_free_buffers; + } + } + + err = input_register_device(usbtouch->input); + if (err) { + dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err); + goto out_free_buffers; + } + + usb_set_intfdata(intf, usbtouch); + + return 0; + +out_free_buffers: + usbtouch_free_buffers(udev, usbtouch); +out_free: + input_free_device(input_dev); + kfree(usbtouch); + return -ENOMEM; +} + +static void usbtouch_disconnect(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + + if (!usbtouch) + return; + + dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__); + usb_set_intfdata(intf, NULL); + usb_kill_urb(usbtouch->irq); + input_unregister_device(usbtouch->input); + usb_free_urb(usbtouch->irq); + usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); + kfree(usbtouch); +} + +MODULE_DEVICE_TABLE(usb, usbtouch_devices); + +static struct usb_driver usbtouch_driver = { + .name = "usbtouchscreen", + .probe = usbtouch_probe, + .disconnect = usbtouch_disconnect, + .id_table = usbtouch_devices, +}; + +static int __init usbtouch_init(void) +{ + return usb_register(&usbtouch_driver); +} + +static void __exit usbtouch_cleanup(void) +{ + usb_deregister(&usbtouch_driver); +} + +module_init(usbtouch_init); +module_exit(usbtouch_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS("touchkitusb"); +MODULE_ALIAS("itmtouch"); +MODULE_ALIAS("mtouchusb"); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index d3e15df9e81..cf84c6096f2 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -9,7 +9,7 @@ * Copyright (c) 2000 Daniel Egger <egger@suse.de> * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> - * Copyright (c) 2002-2005 Ping Cheng <pingc@wacom.com> + * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com> * * ChangeLog: * v0.1 (vp) - Initial release @@ -56,6 +56,8 @@ * - Merged wacom_intuos3_irq into wacom_intuos_irq * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc. * - Report Device IDs + * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19 + * - Minor data report fix */ /* @@ -78,7 +80,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.44" +#define DRIVER_VERSION "v1.45" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -99,6 +101,8 @@ enum { PL, INTUOS, INTUOS3, + INTUOS312, + INTUOS319, CINTIQ, MAX_TYPE }; @@ -127,7 +131,19 @@ struct wacom { char phys[32]; }; +#define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 + +static int usb_get_report(struct usb_interface *intf, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(interface_to_usbdev(intf), + usb_rcvctrlpipe(interface_to_usbdev(intf), 0), + USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, + buf, size, 100); +} + static int usb_set_report(struct usb_interface *intf, unsigned char type, unsigned char id, void *buf, int size) { @@ -206,7 +222,8 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) wacom->tool[1] = BTN_TOOL_PEN; id = STYLUS_DEVICE_ID; } - input_report_key(dev, wacom->tool[1], id); /* report in proximity for tool */ + input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ + input_report_abs(dev, ABS_MISC, id); /* report tool id */ input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); input_report_abs(dev, ABS_PRESSURE, pressure); @@ -239,7 +256,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) struct wacom *wacom = urb->context; unsigned char *data = wacom->data; struct input_dev *dev = wacom->dev; - int retval; + int retval, id; switch (urb->status) { case 0: @@ -263,12 +280,15 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); if (data[1] & 0x04) { - input_report_key(dev, BTN_TOOL_RUBBER, (data[1] & 0x20) ? ERASER_DEVICE_ID : 0); + input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x08); + id = ERASER_DEVICE_ID; } else { - input_report_key(dev, BTN_TOOL_PEN, (data[1] & 0x20) ? STYLUS_DEVICE_ID : 0); + input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + id = STYLUS_DEVICE_ID; } + input_report_abs(dev, ABS_MISC, id); /* report tool id */ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2])); input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4])); input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); @@ -312,7 +332,8 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) } input_regs(dev, regs); - input_report_key(dev, BTN_TOOL_PEN, STYLUS_DEVICE_ID); + input_report_key(dev, BTN_TOOL_PEN, 1); + input_report_abs(dev, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1])); input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3])); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); @@ -350,6 +371,8 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) goto exit; } + if (data[0] == 99) return; /* for Volito tablets */ + if (data[0] != 2) { dbg("wacom_graphire_irq: received unknown report #%d", data[0]); goto exit; @@ -374,10 +397,10 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) case 2: /* Mouse with wheel */ input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); if (wacom->features->type == WACOM_G4) { - rw = data[7] & 0x04 ? -(data[7] & 0x03) : (data[7] & 0x03); - input_report_rel(dev, REL_WHEEL, rw); + rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03); + input_report_rel(dev, REL_WHEEL, -rw); } else - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + input_report_rel(dev, REL_WHEEL, -(signed char) data[6]); /* fall through */ case 3: /* Mouse without wheel */ @@ -406,39 +429,27 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) } } - input_report_key(dev, wacom->tool[0], (data[1] & 0x10) ? id : 0); + if (data[1] & 0x10) + input_report_abs(dev, ABS_MISC, id); /* report tool id */ + else + input_report_abs(dev, ABS_MISC, 0); /* reset tool id */ + input_report_key(dev, wacom->tool[0], data[1] & 0x10); input_sync(dev); /* send pad data */ if (wacom->features->type == WACOM_G4) { - /* fist time sending pad data */ - if (wacom->tool[1] != BTN_TOOL_FINGER) { - wacom->id[1] = 0; - wacom->serial[1] = (data[7] & 0x38) >> 2; - } - if (data[7] & 0xf8) { + if ((wacom->serial[1] & 0xc0) != (data[7] & 0xf8)) { + wacom->id[1] = 1; + wacom->serial[1] = (data[7] & 0xf8); input_report_key(dev, BTN_0, (data[7] & 0x40)); input_report_key(dev, BTN_4, (data[7] & 0x80)); - if (((data[7] & 0x38) >> 2) == (wacom->serial[1] & 0x0e)) - /* alter REL_WHEEL value so X apps can get it */ - wacom->serial[1] += (wacom->serial[1] & 0x01) ? -1 : 1; - else - wacom->serial[1] = (data[7] & 0x38 ) >> 2; - - /* don't alter the value when there is no wheel event */ - if (wacom->serial[1] == 1) - wacom->serial[1] = 0; - rw = wacom->serial[1]; - rw = (rw & 0x08) ? -(rw & 0x07) : (rw & 0x07); + rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); input_report_rel(dev, REL_WHEEL, rw); - wacom->tool[1] = BTN_TOOL_FINGER; - wacom->id[1] = data[7] & 0xf8; - input_report_key(dev, wacom->tool[1], 0xf0); + input_report_key(dev, BTN_TOOL_FINGER, 0xf0); input_event(dev, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { wacom->id[1] = 0; - wacom->serial[1] = 0; - input_report_key(dev, wacom->tool[1], 0); + input_report_key(dev, BTN_TOOL_FINGER, 0); input_event(dev, EV_MSC, MSC_SERIAL, 0xf0); } input_sync(dev); @@ -516,21 +527,31 @@ static int wacom_intuos_inout(struct urb *urb) default: /* Unknown tool */ wacom->tool[idx] = BTN_TOOL_PEN; } - input_report_key(dev, wacom->tool[idx], wacom->id[idx]); - input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - input_sync(dev); + if(!((wacom->tool[idx] == BTN_TOOL_LENS) && + ((wacom->features->type == INTUOS312) + || (wacom->features->type == INTUOS319)))) { + input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */ + input_report_key(dev, wacom->tool[idx], 1); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + input_sync(dev); + } return 1; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { input_report_key(dev, wacom->tool[idx], 0); + input_report_abs(dev, ABS_MISC, 0); /* reset tool id */ input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); return 1; } - return 0; + if((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS312) + || (wacom->features->type == INTUOS319))) + return 1; + else + return 0; } static void wacom_intuos_general(struct urb *urb) @@ -600,10 +621,9 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* pad packets. Works as a second tool and is always in prox */ if (data[0] == 12) { /* initiate the pad as a device */ - if (wacom->tool[1] != BTN_TOOL_FINGER) { + if (wacom->tool[1] != BTN_TOOL_FINGER) wacom->tool[1] = BTN_TOOL_FINGER; - input_report_key(dev, wacom->tool[1], 1); - } + input_report_key(dev, BTN_0, (data[5] & 0x01)); input_report_key(dev, BTN_1, (data[5] & 0x02)); input_report_key(dev, BTN_2, (data[5] & 0x04)); @@ -614,6 +634,11 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_7, (data[6] & 0x08)); input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); + + if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) + input_report_key(dev, wacom->tool[1], 1); + else + input_report_key(dev, wacom->tool[1], 0); input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff); input_sync(dev); goto exit; @@ -676,8 +701,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1) - - (data[8] & 0x01)); + input_report_rel(dev, REL_WHEEL, (data[8] & 0x01) + - ((data[8] & 0x02) >> 1)); /* I3 2D mouse side buttons */ if (wacom->features->type == INTUOS3) { @@ -695,7 +720,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) } } - input_report_key(dev, wacom->tool[idx], wacom->id[idx]); + input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */ + input_report_key(dev, wacom->tool[idx], 1); input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); @@ -733,7 +759,8 @@ static struct wacom_features wacom_features[] = { { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq }, { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_pl_irq }, { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq }, - { "Wacom PL710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq }, + { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq }, + { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq }, { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_pl_irq }, { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq }, { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, @@ -744,6 +771,8 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq }, + { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS312, wacom_intuos_irq }, + { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS319, wacom_intuos_irq }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, @@ -779,6 +808,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) }, @@ -788,6 +818,8 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, @@ -820,7 +852,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct input_dev *input_dev; - char rep_data[2] = {0x02, 0x02}; + char rep_data[2], limit = 0; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); input_dev = input_allocate_device(); @@ -857,6 +889,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0); + input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC); switch (wacom->features->type) { case WACOM_G4: @@ -875,6 +908,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i break; case INTUOS3: + case INTUOS312: + case INTUOS319: case CINTIQ: input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); @@ -916,10 +951,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i input_register_device(wacom->dev); - /* ask the tablet to report tablet data */ - usb_set_report(intf, 3, 2, rep_data, 2); - /* repeat once (not sure why the first call often fails) */ - usb_set_report(intf, 3, 2, rep_data, 2); + /* Ask the tablet to report tablet data. Repeat until it succeeds */ + do { + rep_data[0] = 2; + rep_data[1] = 2; + usb_set_report(intf, 3, 2, rep_data, 2); + usb_get_report(intf, 3, 2, rep_data, 2); + } while (rep_data[1] != 2 && limit++ < 5); usb_set_intfdata(intf, wacom); return 0; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 9d59b901841..ccc5e8238bd 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -381,6 +381,7 @@ alloc_sglist (int nents, int max, int vary) for (i = 0; i < nents; i++) { char *buf; + unsigned j; buf = kzalloc (size, SLAB_KERNEL); if (!buf) { @@ -391,6 +392,16 @@ alloc_sglist (int nents, int max, int vary) /* kmalloc pages are always physically contiguous! */ sg_init_one(&sg[i], buf, size); + switch (pattern) { + case 0: + /* already zeroed */ + break; + case 1: + for (j = 0; j < size; j++) + *buf++ = (u8) (j % 63); + break; + } + if (vary) { size += vary; size %= max; @@ -425,6 +436,8 @@ static int perform_sglist ( usb_sg_wait (req); retval = req->status; + /* FIXME check resulting data pattern */ + /* FIXME if endpoint halted, clear halt (and log) */ } diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 3094970615c..12b599a0b53 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -37,7 +37,6 @@ #include "usbnet.h" - /* ASIX AX8817X based USB 2.0 Ethernet Devices */ #define AX_CMD_SET_SW_MII 0x06 @@ -109,7 +108,7 @@ #define AX_EEPROM_MAGIC 0xdeadbeef /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct ax8817x_data { +struct asix_data { u8 multi_filter[AX_MCAST_FILTER_SIZE]; }; @@ -121,7 +120,7 @@ struct ax88172_int_data { u16 res3; } __attribute__ ((packed)); -static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { return usb_control_msg( @@ -136,7 +135,7 @@ static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, USB_CTRL_GET_TIMEOUT); } -static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { return usb_control_msg( @@ -151,19 +150,80 @@ static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, USB_CTRL_SET_TIMEOUT); } -static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; if (urb->status < 0) - printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", + printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", urb->status); kfree(req); usb_free_urb(urb); } -static void ax8817x_status(struct usbnet *dev, struct urb *urb) +static inline int asix_set_sw_mii(struct usbnet *dev) +{ + int ret; + ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to enable software MII access"); + return ret; +} + +static inline int asix_set_hw_mii(struct usbnet *dev) +{ + int ret; + ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to enable hardware MII access"); + return ret; +} + +static inline int asix_get_phyid(struct usbnet *dev) +{ + int ret = 0; + void *buf; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + goto out1; + + if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 2) { + devdbg(dev, "Error reading PHYID register: %02x", ret); + goto out2; + } + ret = *((u8 *)buf + 1); +out2: + kfree(buf); +out1: + return ret; +} + +static int asix_sw_reset(struct usbnet *dev, u8 flags) +{ + int ret; + + ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); + if (ret < 0) + devdbg(dev,"Failed to send software reset: %02x", ret); + + return ret; +} + +static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) +{ + int ret; + + ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to write RX_CTL mode: %02x", ret); + + return ret; +} + +static void asix_status(struct usbnet *dev, struct urb *urb) { struct ax88172_int_data *event; int link; @@ -179,12 +239,12 @@ static void ax8817x_status(struct usbnet *dev, struct urb *urb) usbnet_defer_kevent (dev, EVENT_LINK_RESET ); } else netif_carrier_off(dev->net); - devdbg(dev, "ax8817x - Link Status is: %d", link); + devdbg(dev, "Link Status is: %d", link); } } static void -ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, +asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { struct usb_ctrlrequest *req; @@ -211,7 +271,7 @@ ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (void *)req, data, size, - ax8817x_async_cmd_callback, req); + asix_async_cmd_callback, req); if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { deverr(dev, "Error submitting the control message: status=%d", @@ -221,10 +281,10 @@ ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, } } -static void ax8817x_set_multicast(struct net_device *net) +static void asix_set_multicast(struct net_device *net) { struct usbnet *dev = netdev_priv(net); - struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct asix_data *data = (struct asix_data *)&dev->data; u8 rx_ctl = 0x8c; if (net->flags & IFF_PROMISC) { @@ -255,53 +315,51 @@ static void ax8817x_set_multicast(struct net_device *net) mc_list = mc_list->next; } - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, AX_MCAST_FILTER_SIZE, data->multi_filter); rx_ctl |= 0x10; } - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); + asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); } -static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) +static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); u16 res; - u8 buf[1]; - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, + asix_set_sw_mii(dev); + asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + asix_set_hw_mii(dev); return res & 0xffff; } /* same as above, but converts resulting value to cpu byte order */ -static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) +static int asix_mdio_read_le(struct net_device *netdev, int phy_id, int loc) { - return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc)); + return le16_to_cpu(asix_mdio_read(netdev,phy_id, loc)); } static void -ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) { struct usbnet *dev = netdev_priv(netdev); u16 res = val; - u8 buf[1]; - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + asix_set_sw_mii(dev); + asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + asix_set_hw_mii(dev); } /* same as above, but converts new value to le16 byte order before writing */ static void -ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) +asix_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) { - ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); + asix_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); } static int ax88172_link_reset(struct usbnet *dev) @@ -312,23 +370,23 @@ static int ax88172_link_reset(struct usbnet *dev) u8 mode; mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; - lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); - adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); res = mii_nway_result(lpa|adv); if (res & LPA_DUPLEX) mode |= AX_MEDIUM_FULL_DUPLEX; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); return 0; } static void -ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt; - if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { + if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { wolinfo->supported = 0; wolinfo->wolopts = 0; return; @@ -344,7 +402,7 @@ ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) } static int -ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt = 0; @@ -357,19 +415,19 @@ ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) if (opt != 0) opt |= AX_MONITOR_MODE; - if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, + if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, opt, 0, 0, &buf) < 0) return -EINVAL; return 0; } -static int ax8817x_get_eeprom_len(struct net_device *net) +static int asix_get_eeprom_len(struct net_device *net) { return AX_EEPROM_LEN; } -static int ax8817x_get_eeprom(struct net_device *net, +static int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data) { struct usbnet *dev = netdev_priv(net); @@ -386,14 +444,14 @@ static int ax8817x_get_eeprom(struct net_device *net, /* ax8817x returns 2 bytes from eeprom on read */ for (i=0; i < eeprom->len / 2; i++) { - if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, + if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, eeprom->offset + i, 0, 2, &ebuf[i]) < 0) return -EINVAL; } return 0; } -static void ax8817x_get_drvinfo (struct net_device *net, +static void asix_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { /* Inherit standard device info */ @@ -401,14 +459,14 @@ static void ax8817x_get_drvinfo (struct net_device *net, info->eedump_len = 0x3e; } -static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); return mii_ethtool_gset(&dev->mii,cmd); } -static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); @@ -418,27 +476,27 @@ static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ -static struct ethtool_ops ax8817x_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, +static struct ethtool_ops ax88172_ethtool_ops = { + .get_drvinfo = asix_get_drvinfo, .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, + .get_wol = asix_get_wol, + .set_wol = asix_set_wol, + .get_eeprom_len = asix_get_eeprom_len, + .get_eeprom = asix_get_eeprom, + .get_settings = asix_get_settings, + .set_settings = asix_set_settings, }; -static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { struct usbnet *dev = netdev_priv(net); return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) +static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) { int ret = 0; void *buf; @@ -455,55 +513,39 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) /* Toggle the GPIOs in a manufacturer/model specific way */ for (i = 2; i >= 0; i--) { - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, (gpio_bits >> (i * 8)) & 0xff, 0, 0, buf)) < 0) goto out2; msleep(5); } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, - 0x80, 0, 0, buf)) < 0) { - dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); + if ((ret = asix_write_rx_ctl(dev,0x80)) < 0) goto out2; - } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, + if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, - 0, 0, 2, buf)) < 0) { - dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - /* Initialize MII structure */ dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.mdio_read = asix_mdio_read; + dev->mii.mdio_write = asix_mdio_write; dev->mii.phy_id_mask = 0x3f; dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = *((u8 *)buf + 1); - dev->net->do_ioctl = ax8817x_ioctl; + dev->mii.phy_id = asix_get_phyid(dev); + dev->net->do_ioctl = asix_ioctl; - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax8817x_ethtool_ops; + dev->net->set_multicast_list = asix_set_multicast; + dev->net->ethtool_ops = &ax88172_ethtool_ops; - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); @@ -515,16 +557,16 @@ out1: } static struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, + .get_drvinfo = asix_get_drvinfo, .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, + .get_wol = asix_get_wol, + .set_wol = asix_set_wol, + .get_eeprom_len = asix_get_eeprom_len, + .get_eeprom = asix_get_eeprom, + .get_settings = asix_get_settings, + .set_settings = asix_set_settings, }; static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) @@ -541,62 +583,45 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) goto out1; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, buf)) < 0) goto out2; msleep(5); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, - 0, 0, buf)) < 0) { - dbg("Failed to power down internal PHY: %d", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, - 0, 0, buf)) < 0) { - dbg("Failed to perform software reset: %d", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, - AX_SWRESET_IPRL | AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Failed to set Internal/External PHY reset control: %d", - ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, - 0x0000, 0, 0, buf)) < 0) { - dbg("Failed to reset RX_CTL: %d", ret); + if ((ret = asix_write_rx_ctl(dev, 0x00)) < 0) goto out2; - } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, + if ((ret = asix_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { dbg("Failed to read MAC address: %d", ret); goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, - 0, 0, 0, buf)) < 0) { - dbg("Enabling software MII failed: %d", ret); + if ((ret = asix_set_sw_mii(dev)) < 0) goto out2; - } - if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, + if (((ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) || (*((u16 *)buf) != 0x003b)) { dbg("Read PHY register 2 must be 0x3b00: %d", ret); @@ -605,74 +630,49 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) /* Initialize MII structure */ dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.mdio_read = asix_mdio_read; + dev->mii.mdio_write = asix_mdio_write; dev->mii.phy_id_mask = 0xff; dev->mii.reg_num_mask = 0xff; - dev->net->do_ioctl = ax8817x_ioctl; + dev->net->do_ioctl = asix_ioctl; + dev->mii.phy_id = asix_get_phyid(dev); - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, - 0, 0, 2, buf)) < 0) { - dbg("Error reading PHY ID: %02x", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0) goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - dev->mii.phy_id = *((u8 *)buf + 1); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Set external PHY reset pin level: %d", ret); - goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, - AX_SWRESET_IPRL | AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Set Internal/External PHY reset control: %d", ret); + + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) goto out2; - } - msleep(150); + msleep(150); - dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->set_multicast_list = asix_set_multicast; dev->net->ethtool_ops = &ax88772_ethtool_ops; - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(&dev->mii); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { dbg("Write medium mode register: %d", ret); goto out2; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG2_DEFAULT, 0, buf)) < 0) { dbg("Write IPG,IPG1,IPG2 failed: %d", ret); goto out2; } - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to set hardware MII: %02x", ret); + if ((ret = asix_set_hw_mii(dev)) < 0) goto out2; - } /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, - buf)) < 0) { - dbg("Reset RX_CTL failed: %d", ret); + if ((ret = asix_write_rx_ctl(dev, 0x0088)) < 0) goto out2; - } kfree(buf); @@ -794,23 +794,23 @@ static int ax88772_link_reset(struct usbnet *dev) u16 mode; mode = AX88772_MEDIUM_DEFAULT; - lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); - adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); res = mii_nway_result(lpa|adv); if ((res & LPA_DUPLEX) == 0) mode &= ~AX88772_MEDIUM_FULL_DUPLEX; if ((res & LPA_100) == 0) mode &= ~AX88772_MEDIUM_100MB; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); return 0; } static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -819,8 +819,8 @@ static const struct driver_info ax8817x_info = { static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -829,8 +829,8 @@ static const struct driver_info dlink_dub_e100_info = { static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -839,8 +839,8 @@ static const struct driver_info netgear_fa120_info = { static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -850,13 +850,12 @@ static const struct driver_info hawking_uf200_info = { static const struct driver_info ax88772_info = { .description = "ASIX AX88772 USB 2.0 Ethernet", .bind = ax88772_bind, - .status = ax8817x_status, + .status = asix_status, .link_reset = ax88772_link_reset, .reset = ax88772_link_reset, .flags = FLAG_ETHER | FLAG_FRAMING_AX, .rx_fixup = ax88772_rx_fixup, .tx_fixup = ax88772_tx_fixup, - .data = 0x00130103, }; static const struct usb_device_id products [] = { diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 5b667568456..2deb4c01539 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -262,7 +262,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), (char *) &pegasus->dr, - &tmp, 1, ctrl_callback, pegasus); + tmp, 1, ctrl_callback, pegasus); add_wait_queue(&pegasus->ctrl_wait, &wait); set_current_state(TASK_UNINTERRUPTIBLE); diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 49991ac1bf3..94ddfe16fdd 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -39,6 +39,20 @@ * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of * course ACM was intended for modems, not Ethernet links! USB's standard * for Ethernet links is "CDC Ethernet", which is significantly simpler. + * + * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues + * include: + * - Power management in particular relies on information that's scattered + * through other documentation, and which is incomplete or incorrect even + * there. + * - There are various undocumented protocol requirements, such as the + * need to send unused garbage in control-OUT messages. + * - In some cases, MS-Windows will emit undocumented requests; this + * matters more to peripheral implementations than host ones. + * + * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in + * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and + * currently rare) "Ethernet Emulation Model" (EEM). */ /* @@ -72,17 +86,17 @@ struct rndis_msg_hdr { */ #define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */ #define RNDIS_MSG_INIT ccpu2(0x00000002) -#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_HALT ccpu2(0x00000003) #define RNDIS_MSG_QUERY ccpu2(0x00000004) -#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_SET ccpu2(0x00000005) -#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_RESET ccpu2(0x00000006) -#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_INDICATE ccpu2(0x00000007) #define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008) -#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) /* codes for "status" field of completion messages */ #define RNDIS_STATUS_SUCCESS ccpu2(0x00000000) @@ -596,13 +610,13 @@ static struct usb_driver rndis_driver = { static int __init rndis_init(void) { - return usb_register(&rndis_driver); + return usb_register(&rndis_driver); } module_init(rndis_init); static void __exit rndis_exit(void) { - usb_deregister(&rndis_driver); + usb_deregister(&rndis_driver); } module_exit(rndis_exit); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5a8a2c91c2b..f96b73f54bf 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -158,6 +158,15 @@ config USB_SERIAL_FTDI_SIO To compile this driver as a module, choose M here: the module will be called ftdi_sio. +config USB_SERIAL_FUNSOFT + tristate "USB Fundamental Software Dongle Driver" + depends on USB_SERIAL + ---help--- + Say Y here if you want to use the Fundamental Software dongle. + + To compile this driver as a module, choose M here: the + module will be called funsoft. + config USB_SERIAL_VISOR tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index f7fe4172efe..93c21245b1a 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o +obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 167f8ec5613..8023bb7279b 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -54,7 +54,7 @@ static struct console usbcons; * serial.c code, except that the specifier is "ttyUSB" instead * of "ttyS". */ -static int __init usb_console_setup(struct console *co, char *options) +static int usb_console_setup(struct console *co, char *options) { struct usbcons_info *info = &usbcons_info; int baud = 9600; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f3af81b4dd2..f5851db67f5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -489,10 +489,12 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 8da773c2744..2155f0e4a37 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -399,6 +399,21 @@ #define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ #define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ +/* + * Eclo (http://www.eclo.pt/) product IDs. + * PID 0xEA90 submitted by Martin Grill. + */ +#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ + +/* + * Papouch products (http://www.papouch.com/) + * Submitted by Folkert van Heusden + */ + +#define PAPOUCH_VID 0x5050 /* Vendor ID */ +#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ + + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c new file mode 100644 index 00000000000..803721b97e2 --- /dev/null +++ b/drivers/usb/serial/funsoft.c @@ -0,0 +1,65 @@ +/* + * Funsoft Serial USB driver + * + * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include "usb-serial.h" + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1404, 0xcddc) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver funsoft_driver = { + .name = "funsoft", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver funsoft_device = { + .driver = { + .owner = THIS_MODULE, + .name = "funsoft", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, +}; + +static int __init funsoft_init(void) +{ + int retval; + + retval = usb_serial_register(&funsoft_device); + if (retval) + return retval; + retval = usb_register(&funsoft_driver); + if (retval) + usb_serial_deregister(&funsoft_device); + return retval; +} + +static void __exit funsoft_exit(void) +{ + usb_deregister(&funsoft_driver); + usb_serial_deregister(&funsoft_device); +} + +module_init(funsoft_init); +module_exit(funsoft_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index b3014fda645..ccf746b27d4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -78,6 +78,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 77901d14397..09f379b19e9 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -79,3 +79,7 @@ /* USB GSM cable from Speed Dragon Multimedia, Ltd */ #define SPEEDDRAGON_VENDOR_ID 0x0e55 #define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */ +#define OTI_VENDOR_ID 0x0ea0 +#define OTI_PRODUCT_ID 0x6858 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 097f4e8488f..071f86a59c0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -27,10 +27,10 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/list.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> #include <linux/usb.h> #include "usb-serial.h" #include "pl2303.h" @@ -192,7 +192,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) if (!port) return -ENODEV; - if (down_interruptible(&port->sem)) + if (mutex_lock_interruptible(&port->mutex)) return -ERESTARTSYS; ++port->open_count; @@ -219,7 +219,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) goto bailout_module_put; } - up(&port->sem); + mutex_unlock(&port->mutex); return 0; bailout_module_put: @@ -227,7 +227,7 @@ bailout_module_put: bailout_kref_put: kref_put(&serial->kref, destroy_serial); port->open_count = 0; - up(&port->sem); + mutex_unlock(&port->mutex); return retval; } @@ -240,10 +240,10 @@ static void serial_close(struct tty_struct *tty, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); - down(&port->sem); + mutex_lock(&port->mutex); if (port->open_count == 0) { - up(&port->sem); + mutex_unlock(&port->mutex); return; } @@ -262,7 +262,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) module_put(port->serial->type->driver.owner); } - up(&port->sem); + mutex_unlock(&port->mutex); kref_put(&port->serial->kref, destroy_serial); } @@ -783,7 +783,7 @@ int usb_serial_probe(struct usb_interface *interface, port->number = i + serial->minor; port->serial = serial; spin_lock_init(&port->lock); - sema_init(&port->sem, 1); + mutex_init(&port->mutex); INIT_WORK(&port->work, usb_serial_port_softint, port); serial->port[i] = port; } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index d7d27c3385b..dc89d871046 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -16,7 +16,7 @@ #include <linux/config.h> #include <linux/kref.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 255 /* loads of devices :) */ @@ -31,7 +31,7 @@ * @serial: pointer back to the struct usb_serial owner of this port. * @tty: pointer to the corresponding tty for this port. * @lock: spinlock to grab when updating portions of this structure. - * @sem: semaphore used to synchronize serial_open() and serial_close() + * @mutex: mutex used to synchronize serial_open() and serial_close() * access for this port. * @number: the number of the port (the minor number). * @interrupt_in_buffer: pointer to the interrupt in buffer for this port. @@ -63,7 +63,7 @@ struct usb_serial_port { struct usb_serial * serial; struct tty_struct * tty; spinlock_t lock; - struct semaphore sem; + struct mutex mutex; unsigned char number; unsigned char * interrupt_in_buffer; diff --git a/fs/exec.c b/fs/exec.c index 3234a0c32d5..4121bb55973 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -665,9 +665,7 @@ static int de_thread(struct task_struct *tsk) * and to assume its PID: */ if (!thread_group_leader(current)) { - struct task_struct *parent; struct dentry *proc_dentry1, *proc_dentry2; - unsigned long ptrace; /* * Wait for the thread group leader to be a zombie. @@ -704,22 +702,6 @@ static int de_thread(struct task_struct *tsk) * two threads with a switched PID, and release * the former thread group leader: */ - ptrace = leader->ptrace; - parent = leader->parent; - if (unlikely(ptrace) && unlikely(parent == current)) { - /* - * Joker was ptracing his own group leader, - * and now he wants to be his own parent! - * We can't have that. - */ - ptrace = 0; - } - - ptrace_unlink(current); - ptrace_unlink(leader); - remove_parent(current); - remove_parent(leader); - /* Become a process group leader with the old leader's pid. * Note: The old leader also uses thispid until release_task @@ -732,8 +714,6 @@ static int de_thread(struct task_struct *tsk) attach_pid(current, PIDTYPE_SID, current->signal->session); list_add_tail(¤t->tasks, &init_task.tasks); - current->parent = current->real_parent = leader->real_parent; - leader->parent = leader->real_parent = child_reaper; current->group_leader = current; leader->group_leader = current; @@ -742,13 +722,6 @@ static int de_thread(struct task_struct *tsk) detach_pid(leader, PIDTYPE_SID); list_del_init(&leader->tasks); - add_parent(current); - add_parent(leader); - if (ptrace) { - current->ptrace = ptrace; - __ptrace_link(current, parent); - } - current->exit_signal = SIGCHLD; BUG_ON(leader->exit_state != EXIT_ZOMBIE); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6c740f86066..cc750c68fe7 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -92,48 +92,50 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) { struct fuse_req *req; sigset_t oldset; + int intr; int err; + atomic_inc(&fc->num_waiting); block_sigs(&oldset); - err = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); + intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); - if (err) - return ERR_PTR(-EINTR); + err = -EINTR; + if (intr) + goto out; req = fuse_request_alloc(); + err = -ENOMEM; if (!req) - return ERR_PTR(-ENOMEM); + goto out; - atomic_inc(&fc->num_waiting); - fuse_request_init(req); req->in.h.uid = current->fsuid; req->in.h.gid = current->fsgid; req->in.h.pid = current->pid; + req->waiting = 1; return req; + + out: + atomic_dec(&fc->num_waiting); + return ERR_PTR(err); } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { if (atomic_dec_and_test(&req->count)) { - atomic_dec(&fc->num_waiting); + if (req->waiting) + atomic_dec(&fc->num_waiting); fuse_request_free(req); } } -void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) +void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) { - iput(req->inode); - iput(req->inode2); - if (req->file) - fput(req->file); - spin_lock(&fc->lock); - list_del(&req->bg_entry); + list_del_init(&req->bg_entry); if (fc->num_background == FUSE_MAX_BACKGROUND) { fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } fc->num_background--; - spin_unlock(&fc->lock); } /* @@ -163,17 +165,27 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) wake_up(&req->waitq); fuse_put_request(fc, req); } else { + struct inode *inode = req->inode; + struct inode *inode2 = req->inode2; + struct file *file = req->file; void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; + req->inode = NULL; + req->inode2 = NULL; + req->file = NULL; + if (!list_empty(&req->bg_entry)) + fuse_remove_background(fc, req); spin_unlock(&fc->lock); - down_read(&fc->sbput_sem); - if (fc->mounted) - fuse_release_background(fc, req); - up_read(&fc->sbput_sem); + if (end) end(fc, req); else fuse_put_request(fc, req); + + if (file) + fput(file); + iput(inode); + iput(inode2); } } @@ -277,6 +289,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; + if (!req->waiting) { + req->waiting = 1; + atomic_inc(&fc->num_waiting); + } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e4f041a11bb..fc342cf7c2c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1,6 +1,6 @@ /* FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING. @@ -565,8 +565,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, buf += nres; if (nres != nbytes) break; - if (count) - fuse_reset_request(req); + if (count) { + fuse_put_request(fc, req); + req = fuse_get_req(fc); + if (IS_ERR(req)) + break; + } } fuse_put_request(fc, req); if (res > 0) { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 19c7185a754..59661c481d9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -159,6 +159,9 @@ struct fuse_req { /** Data is being copied to/from the request */ unsigned locked:1; + /** Request is counted as "waiting" */ + unsigned waiting:1; + /** State of the request */ enum fuse_req_state state; @@ -255,15 +258,9 @@ struct fuse_conn { /** waitq for blocked connection */ wait_queue_head_t blocked_waitq; - /** RW semaphore for exclusion with fuse_put_super() */ - struct rw_semaphore sbput_sem; - /** The next unique request id */ u64 reqctr; - /** Mount is active */ - unsigned mounted; - /** Connection established, cleared on umount, connection abort and device release */ unsigned connected; @@ -474,11 +471,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); void request_send_background(struct fuse_conn *fc, struct fuse_req *req); /** - * Release inodes and file associated with background request + * Remove request from the the background list */ -void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req); +void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req); -/* Abort all requests */ +/** Abort all requests */ void fuse_abort_conn(struct fuse_conn *fc); /** diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fd34037b058..43a6fc0db8a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -204,17 +204,26 @@ static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); - down_write(&fc->sbput_sem); - while (!list_empty(&fc->background)) - fuse_release_background(fc, - list_entry(fc->background.next, - struct fuse_req, bg_entry)); - spin_lock(&fc->lock); - fc->mounted = 0; fc->connected = 0; + while (!list_empty(&fc->background)) { + struct fuse_req *req = list_entry(fc->background.next, + struct fuse_req, bg_entry); + struct inode *inode = req->inode; + struct inode *inode2 = req->inode2; + + /* File would hold a reference to vfsmount */ + BUG_ON(req->file); + req->inode = NULL; + req->inode2 = NULL; + fuse_remove_background(fc, req); + + spin_unlock(&fc->lock); + iput(inode); + iput(inode2); + spin_lock(&fc->lock); + } spin_unlock(&fc->lock); - up_write(&fc->sbput_sem); /* Flush all readers on this fs */ kill_fasync(&fc->fasync, SIGIO, POLL_IN); wake_up_all(&fc->waitq); @@ -386,7 +395,6 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->io); INIT_LIST_HEAD(&fc->background); - init_rwsem(&fc->sbput_sem); kobj_set_kset_s(fc, connections_subsys); kobject_init(&fc->kobj); atomic_set(&fc->num_waiting, 0); @@ -541,7 +549,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) goto err_free_req; sb->s_root = root_dentry; - fc->mounted = 1; fc->connected = 1; kobject_get(&fc->kobj); file->private_data = fc; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index af0cb4b9e78..f3b6af07172 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -331,7 +331,9 @@ void delete_partition(struct gendisk *disk, int part) devfs_remove("%s/part%d", disk->devfs_name, part); if (p->holder_dir) kobject_unregister(p->holder_dir); - kobject_unregister(&p->kobj); + kobject_uevent(&p->kobj, KOBJ_REMOVE); + kobject_del(&p->kobj); + kobject_put(&p->kobj); } void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) @@ -357,7 +359,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; - kobject_register(&p->kobj); + kobject_init(&p->kobj); + kobject_add(&p->kobj); + if (!disk->part_uevent_suppress) + kobject_uevent(&p->kobj, KOBJ_ADD); partition_sysfs_add_subdir(p); disk->part[part-1] = p; } @@ -395,6 +400,8 @@ void register_disk(struct gendisk *disk) { struct block_device *bdev; char *s; + int i; + struct hd_struct *p; int err; strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); @@ -406,13 +413,12 @@ void register_disk(struct gendisk *disk) return; disk_sysfs_symlinks(disk); disk_sysfs_add_subdirs(disk); - kobject_uevent(&disk->kobj, KOBJ_ADD); /* No minors to use for partitions */ if (disk->minors == 1) { if (disk->devfs_name[0] != '\0') devfs_add_disk(disk); - return; + goto exit; } /* always add handle for the whole disk */ @@ -420,16 +426,32 @@ void register_disk(struct gendisk *disk) /* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) - return; + goto exit; bdev = bdget_disk(disk, 0); if (!bdev) - return; + goto exit; + /* scan partition table, but suppress uevents */ bdev->bd_invalidated = 1; - if (blkdev_get(bdev, FMODE_READ, 0) < 0) - return; + disk->part_uevent_suppress = 1; + err = blkdev_get(bdev, FMODE_READ, 0); + disk->part_uevent_suppress = 0; + if (err < 0) + goto exit; blkdev_put(bdev); + +exit: + /* announce disk after possible partitions are already created */ + kobject_uevent(&disk->kobj, KOBJ_ADD); + + /* announce possible partitions */ + for (i = 1; i < disk->minors; i++) { + p = disk->part[i-1]; + if (!p || !p->nr_sects) + continue; + kobject_uevent(&p->kobj, KOBJ_ADD); + } } int rescan_partitions(struct gendisk *disk, struct block_device *bdev) diff --git a/fs/pipe.c b/fs/pipe.c index e984beb93a0..7fefb10db8d 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -131,12 +131,19 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe, return 0; } +static void anon_pipe_buf_get(struct pipe_inode_info *info, + struct pipe_buffer *buf) +{ + page_cache_get(buf->page); +} + static struct pipe_buf_operations anon_pipe_buf_ops = { .can_merge = 1, .map = anon_pipe_buf_map, .unmap = anon_pipe_buf_unmap, .release = anon_pipe_buf_release, .steal = anon_pipe_buf_steal, + .get = anon_pipe_buf_get, }; static ssize_t diff --git a/fs/splice.c b/fs/splice.c index e50a460239d..8d57e89924a 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -125,12 +125,19 @@ static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, kunmap(buf->page); } +static void page_cache_pipe_buf_get(struct pipe_inode_info *info, + struct pipe_buffer *buf) +{ + page_cache_get(buf->page); +} + static struct pipe_buf_operations page_cache_pipe_buf_ops = { .can_merge = 0, .map = page_cache_pipe_buf_map, .unmap = page_cache_pipe_buf_unmap, .release = page_cache_pipe_buf_release, .steal = page_cache_pipe_buf_steal, + .get = page_cache_pipe_buf_get, }; /* @@ -231,8 +238,9 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, } static int -__generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, - size_t len, unsigned int flags) +__generic_file_splice_read(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) { struct address_space *mapping = in->f_mapping; unsigned int offset, nr_pages; @@ -241,8 +249,8 @@ __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, pgoff_t index; int i, error; - index = in->f_pos >> PAGE_CACHE_SHIFT; - offset = in->f_pos & ~PAGE_CACHE_MASK; + index = *ppos >> PAGE_CACHE_SHIFT; + offset = *ppos & ~PAGE_CACHE_MASK; nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if (nr_pages > PIPE_BUFFERS) @@ -348,8 +356,9 @@ fill_it: * * Will read pages from given file and fill them into a pipe. */ -ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, - size_t len, unsigned int flags) +ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) { ssize_t spliced; int ret; @@ -358,12 +367,12 @@ ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, spliced = 0; while (len) { - ret = __generic_file_splice_read(in, pipe, len, flags); + ret = __generic_file_splice_read(in, ppos, pipe, len, flags); if (ret <= 0) break; - in->f_pos += ret; + *ppos += ret; len -= ret; spliced += ret; @@ -561,7 +570,7 @@ typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. */ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, - size_t len, unsigned int flags, + loff_t *ppos, size_t len, unsigned int flags, splice_actor *actor) { int ret, do_wakeup, err; @@ -573,7 +582,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.total_len = len; sd.flags = flags; sd.file = out; - sd.pos = out->f_pos; + sd.pos = *ppos; if (pipe->inode) mutex_lock(&pipe->inode->i_mutex); @@ -656,9 +665,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); } - out->f_pos = sd.pos; return ret; - } /** @@ -674,12 +681,12 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, */ ssize_t generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, - size_t len, unsigned int flags) + loff_t *ppos, size_t len, unsigned int flags) { struct address_space *mapping = out->f_mapping; ssize_t ret; - ret = move_from_pipe(pipe, out, len, flags, pipe_to_file); + ret = move_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); /* * If file or inode is SYNC and we actually wrote some data, sync it. @@ -715,9 +722,9 @@ EXPORT_SYMBOL(generic_file_splice_write); * */ ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, - size_t len, unsigned int flags) + loff_t *ppos, size_t len, unsigned int flags) { - return move_from_pipe(pipe, out, len, flags, pipe_to_sendpage); + return move_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage); } EXPORT_SYMBOL(generic_splice_sendpage); @@ -726,9 +733,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); * Attempt to initiate a splice from pipe to file. */ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - size_t len, unsigned int flags) + loff_t *ppos, size_t len, unsigned int flags) { - loff_t pos; int ret; if (unlikely(!out->f_op || !out->f_op->splice_write)) @@ -737,22 +743,21 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, if (unlikely(!(out->f_mode & FMODE_WRITE))) return -EBADF; - pos = out->f_pos; - - ret = rw_verify_area(WRITE, out, &pos, len); + ret = rw_verify_area(WRITE, out, ppos, len); if (unlikely(ret < 0)) return ret; - return out->f_op->splice_write(pipe, out, len, flags); + return out->f_op->splice_write(pipe, out, ppos, len, flags); } /* * Attempt to initiate a splice from a file to a pipe. */ -static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, - size_t len, unsigned int flags) +static long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) { - loff_t pos, isize, left; + loff_t isize, left; int ret; if (unlikely(!in->f_op || !in->f_op->splice_read)) @@ -761,28 +766,27 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, if (unlikely(!(in->f_mode & FMODE_READ))) return -EBADF; - pos = in->f_pos; - - ret = rw_verify_area(READ, in, &pos, len); + ret = rw_verify_area(READ, in, ppos, len); if (unlikely(ret < 0)) return ret; isize = i_size_read(in->f_mapping->host); - if (unlikely(in->f_pos >= isize)) + if (unlikely(*ppos >= isize)) return 0; - left = isize - in->f_pos; + left = isize - *ppos; if (unlikely(left < len)) len = left; - return in->f_op->splice_read(in, pipe, len, flags); + return in->f_op->splice_read(in, ppos, pipe, len, flags); } -long do_splice_direct(struct file *in, struct file *out, size_t len, - unsigned int flags) +long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, + size_t len, unsigned int flags) { struct pipe_inode_info *pipe; long ret, bytes; + loff_t out_off; umode_t i_mode; int i; @@ -820,6 +824,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, */ ret = 0; bytes = 0; + out_off = 0; while (len) { size_t read_len, max_read_len; @@ -829,7 +834,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, */ max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); - ret = do_splice_to(in, pipe, max_read_len, flags); + ret = do_splice_to(in, ppos, pipe, max_read_len, flags); if (unlikely(ret < 0)) goto out_release; @@ -840,7 +845,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, * must not do the output in nonblocking mode as then we * could get stuck data in the internal pipe: */ - ret = do_splice_from(pipe, out, read_len, + ret = do_splice_from(pipe, out, &out_off, read_len, flags & ~SPLICE_F_NONBLOCK); if (unlikely(ret < 0)) goto out_release; @@ -898,6 +903,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, size_t len, unsigned int flags) { struct pipe_inode_info *pipe; + loff_t offset, *off; pipe = in->f_dentry->d_inode->i_pipe; if (pipe) { @@ -906,12 +912,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, if (off_out) { if (out->f_op->llseek == no_llseek) return -EINVAL; - if (copy_from_user(&out->f_pos, off_out, - sizeof(loff_t))) + if (copy_from_user(&offset, off_out, sizeof(loff_t))) return -EFAULT; - } + off = &offset; + } else + off = &out->f_pos; - return do_splice_from(pipe, out, len, flags); + return do_splice_from(pipe, out, off, len, flags); } pipe = out->f_dentry->d_inode->i_pipe; @@ -921,11 +928,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, if (off_in) { if (in->f_op->llseek == no_llseek) return -EINVAL; - if (copy_from_user(&in->f_pos, off_in, sizeof(loff_t))) + if (copy_from_user(&offset, off_in, sizeof(loff_t))) return -EFAULT; - } + off = &offset; + } else + off = &in->f_pos; - return do_splice_to(in, pipe, len, flags); + return do_splice_to(in, off, pipe, len, flags); } return -EINVAL; @@ -961,3 +970,182 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, return error; } + +/* + * Link contents of ipipe to opipe. + */ +static int link_pipe(struct pipe_inode_info *ipipe, + struct pipe_inode_info *opipe, + size_t len, unsigned int flags) +{ + struct pipe_buffer *ibuf, *obuf; + int ret = 0, do_wakeup = 0, i; + + /* + * Potential ABBA deadlock, work around it by ordering lock + * grabbing by inode address. Otherwise two different processes + * could deadlock (one doing tee from A -> B, the other from B -> A). + */ + if (ipipe->inode < opipe->inode) { + mutex_lock(&ipipe->inode->i_mutex); + mutex_lock(&opipe->inode->i_mutex); + } else { + mutex_lock(&opipe->inode->i_mutex); + mutex_lock(&ipipe->inode->i_mutex); + } + + for (i = 0;; i++) { + if (!opipe->readers) { + send_sig(SIGPIPE, current, 0); + if (!ret) + ret = -EPIPE; + break; + } + if (ipipe->nrbufs - i) { + ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1)); + + /* + * If we have room, fill this buffer + */ + if (opipe->nrbufs < PIPE_BUFFERS) { + int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1); + + /* + * Get a reference to this pipe buffer, + * so we can copy the contents over. + */ + ibuf->ops->get(ipipe, ibuf); + + obuf = opipe->bufs + nbuf; + *obuf = *ibuf; + + if (obuf->len > len) + obuf->len = len; + + opipe->nrbufs++; + do_wakeup = 1; + ret += obuf->len; + len -= obuf->len; + + if (!len) + break; + if (opipe->nrbufs < PIPE_BUFFERS) + continue; + } + + /* + * We have input available, but no output room. + * If we already copied data, return that. + */ + if (flags & SPLICE_F_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + if (do_wakeup) { + smp_mb(); + if (waitqueue_active(&opipe->wait)) + wake_up_interruptible(&opipe->wait); + kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); + do_wakeup = 0; + } + + opipe->waiting_writers++; + pipe_wait(opipe); + opipe->waiting_writers--; + continue; + } + + /* + * No input buffers, do the usual checks for available + * writers and blocking and wait if necessary + */ + if (!ipipe->writers) + break; + if (!ipipe->waiting_writers) { + if (ret) + break; + } + if (flags & SPLICE_F_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + + if (waitqueue_active(&ipipe->wait)) + wake_up_interruptible_sync(&ipipe->wait); + kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT); + + pipe_wait(ipipe); + } + + mutex_unlock(&ipipe->inode->i_mutex); + mutex_unlock(&opipe->inode->i_mutex); + + if (do_wakeup) { + smp_mb(); + if (waitqueue_active(&opipe->wait)) + wake_up_interruptible(&opipe->wait); + kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); + } + + return ret; +} + +/* + * This is a tee(1) implementation that works on pipes. It doesn't copy + * any data, it simply references the 'in' pages on the 'out' pipe. + * The 'flags' used are the SPLICE_F_* variants, currently the only + * applicable one is SPLICE_F_NONBLOCK. + */ +static long do_tee(struct file *in, struct file *out, size_t len, + unsigned int flags) +{ + struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; + struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; + + /* + * Link ipipe to the two output pipes, consuming as we go along. + */ + if (ipipe && opipe) + return link_pipe(ipipe, opipe, len, flags); + + return -EINVAL; +} + +asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags) +{ + struct file *in; + int error, fput_in; + + if (unlikely(!len)) + return 0; + + error = -EBADF; + in = fget_light(fdin, &fput_in); + if (in) { + if (in->f_mode & FMODE_READ) { + int fput_out; + struct file *out = fget_light(fdout, &fput_out); + + if (out) { + if (out->f_mode & FMODE_WRITE) + error = do_tee(in, out, len, flags); + fput_light(out, fput_out); + } + } + fput_light(in, fput_in); + } + + return error; +} diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 6cfdc9a8777..610b5bdbe75 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, memset(sd, 0, sizeof(*sd)); atomic_set(&sd->s_count, 1); + atomic_set(&sd->s_event, 0); INIT_LIST_HEAD(&sd->s_children); list_add(&sd->s_sibling, &parent_sd->s_children); sd->s_element = element; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index f1cb1ddde51..cf3786625bf 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -6,6 +6,7 @@ #include <linux/fsnotify.h> #include <linux/kobject.h> #include <linux/namei.h> +#include <linux/poll.h> #include <asm/uaccess.h> #include <asm/semaphore.h> @@ -57,6 +58,7 @@ struct sysfs_buffer { struct sysfs_ops * ops; struct semaphore sem; int needs_read_fill; + int event; }; @@ -72,6 +74,7 @@ struct sysfs_buffer { */ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { + struct sysfs_dirent * sd = dentry->d_fsdata; struct attribute * attr = to_attr(dentry); struct kobject * kobj = to_kobj(dentry->d_parent); struct sysfs_ops * ops = buffer->ops; @@ -83,6 +86,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer if (!buffer->page) return -ENOMEM; + buffer->event = atomic_read(&sd->s_event); count = ops->show(kobj,attr,buffer->page); buffer->needs_read_fill = 0; BUG_ON(count > (ssize_t)PAGE_SIZE); @@ -348,12 +352,84 @@ static int sysfs_release(struct inode * inode, struct file * filp) return 0; } +/* Sysfs attribute files are pollable. The idea is that you read + * the content and then you use 'poll' or 'select' to wait for + * the content to change. When the content changes (assuming the + * manager for the kobject supports notification), poll will + * return POLLERR|POLLPRI, and select will return the fd whether + * it is waiting for read, write, or exceptions. + * Once poll/select indicates that the value has changed, you + * need to close and re-open the file, as simply seeking and reading + * again will not get new data, or reset the state of 'poll'. + * Reminder: this only works for attributes which actively support + * it, and it is not possible to test an attribute from userspace + * to see if it supports poll (Nether 'poll' or 'select' return + * an appropriate error code). When in doubt, set a suitable timeout value. + */ +static unsigned int sysfs_poll(struct file *filp, poll_table *wait) +{ + struct sysfs_buffer * buffer = filp->private_data; + struct kobject * kobj = to_kobj(filp->f_dentry->d_parent); + struct sysfs_dirent * sd = filp->f_dentry->d_fsdata; + int res = 0; + + poll_wait(filp, &kobj->poll, wait); + + if (buffer->event != atomic_read(&sd->s_event)) { + res = POLLERR|POLLPRI; + buffer->needs_read_fill = 1; + } + + return res; +} + + +static struct dentry *step_down(struct dentry *dir, const char * name) +{ + struct dentry * de; + + if (dir == NULL || dir->d_inode == NULL) + return NULL; + + mutex_lock(&dir->d_inode->i_mutex); + de = lookup_one_len(name, dir, strlen(name)); + mutex_unlock(&dir->d_inode->i_mutex); + dput(dir); + if (IS_ERR(de)) + return NULL; + if (de->d_inode == NULL) { + dput(de); + return NULL; + } + return de; +} + +void sysfs_notify(struct kobject * k, char *dir, char *attr) +{ + struct dentry *de = k->dentry; + if (de) + dget(de); + if (de && dir) + de = step_down(de, dir); + if (de && attr) + de = step_down(de, attr); + if (de) { + struct sysfs_dirent * sd = de->d_fsdata; + if (sd) + atomic_inc(&sd->s_event); + wake_up_interruptible(&k->poll); + dput(de); + } +} +EXPORT_SYMBOL_GPL(sysfs_notify); + const struct file_operations sysfs_file_operations = { .read = sysfs_read_file, .write = sysfs_write_file, .llseek = generic_file_llseek, .open = sysfs_open_file, .release = sysfs_release, + .poll = sysfs_poll, }; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 32958a7c50e..3651ffb5ec0 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -11,6 +11,7 @@ extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, extern int sysfs_add_file(struct dentry *, const struct attribute *, int); extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); +extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); extern void sysfs_remove_subdir(struct dentry *); diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 269721af02f..c847416f6d1 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -252,6 +252,7 @@ xfs_file_sendfile_invis( STATIC ssize_t xfs_file_splice_read( struct file *infilp, + loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) @@ -259,13 +260,14 @@ xfs_file_splice_read( vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); ssize_t rval; - VOP_SPLICE_READ(vp, infilp, pipe, len, flags, 0, NULL, rval); + VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, 0, NULL, rval); return rval; } STATIC ssize_t xfs_file_splice_read_invis( struct file *infilp, + loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) @@ -273,7 +275,7 @@ xfs_file_splice_read_invis( vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); ssize_t rval; - VOP_SPLICE_READ(vp, infilp, pipe, len, flags, IO_INVIS, NULL, rval); + VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, IO_INVIS, NULL, rval); return rval; } @@ -281,13 +283,14 @@ STATIC ssize_t xfs_file_splice_write( struct pipe_inode_info *pipe, struct file *outfilp, + loff_t *ppos, size_t len, unsigned int flags) { vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); ssize_t rval; - VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, 0, NULL, rval); + VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, 0, NULL, rval); return rval; } @@ -295,13 +298,14 @@ STATIC ssize_t xfs_file_splice_write_invis( struct pipe_inode_info *pipe, struct file *outfilp, + loff_t *ppos, size_t len, unsigned int flags) { vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); ssize_t rval; - VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, IO_INVIS, NULL, rval); + VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, IO_INVIS, NULL, rval); return rval; } diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 74a52937f20..67efe330898 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -338,6 +338,7 @@ ssize_t xfs_splice_read( bhv_desc_t *bdp, struct file *infilp, + loff_t *ppos, struct pipe_inode_info *pipe, size_t count, int flags, @@ -360,7 +361,7 @@ xfs_splice_read( int error; error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), - infilp->f_pos, count, + *ppos, count, FILP_DELAY_FLAG(infilp), &locktype); if (error) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -368,8 +369,8 @@ xfs_splice_read( } } xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, - pipe, count, infilp->f_pos, ioflags); - ret = generic_file_splice_read(infilp, pipe, count, flags); + pipe, count, *ppos, ioflags); + ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); if (ret > 0) XFS_STATS_ADD(xs_read_bytes, ret); @@ -382,6 +383,7 @@ xfs_splice_write( bhv_desc_t *bdp, struct pipe_inode_info *pipe, struct file *outfilp, + loff_t *ppos, size_t count, int flags, int ioflags, @@ -403,7 +405,7 @@ xfs_splice_write( int error; error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), - outfilp->f_pos, count, + *ppos, count, FILP_DELAY_FLAG(outfilp), &locktype); if (error) { xfs_iunlock(ip, XFS_IOLOCK_EXCL); @@ -411,8 +413,8 @@ xfs_splice_write( } } xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, - pipe, count, outfilp->f_pos, ioflags); - ret = generic_file_splice_write(pipe, outfilp, count, flags); + pipe, count, *ppos, ioflags); + ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); if (ret > 0) XFS_STATS_ADD(xs_write_bytes, ret); diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 55c689a86ad..8f453995235 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -93,11 +93,11 @@ extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *, extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, loff_t *, int, size_t, read_actor_t, void *, struct cred *); -extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, +extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, loff_t *, struct pipe_inode_info *, size_t, int, int, struct cred *); extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, - struct file *, size_t, int, int, + struct file *, loff_t *, size_t, int, int, struct cred *); #endif /* __XFS_LRW_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 88b09f18628..2a8e16c2235 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -173,11 +173,11 @@ typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *, typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, loff_t *, int, size_t, read_actor_t, void *, struct cred *); -typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, +typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, loff_t *, struct pipe_inode_info *, size_t, int, int, struct cred *); typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, - struct file *, size_t, int, int, + struct file *, loff_t *, size_t, int, int, struct cred *); typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, int, unsigned int, void __user *); @@ -284,10 +284,10 @@ typedef struct vnodeops { rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) -#define VOP_SPLICE_READ(vp,f,pipe,cnt,fl,iofl,cr,rv) \ - rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) -#define VOP_SPLICE_WRITE(vp,f,pipe,cnt,fl,iofl,cr,rv) \ - rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) +#define VOP_SPLICE_READ(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ + rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) +#define VOP_SPLICE_WRITE(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ + rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) #define VOP_OPEN(vp, cr, rv) \ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 6a8dd83c350..d81d6cfc1bb 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -320,8 +320,9 @@ #define __NR_get_robust_list 312 #define __NR_splice 313 #define __NR_sync_file_range 314 +#define __NR_tee 315 -#define NR_syscalls 315 +#define NR_syscalls 316 /* * user-visible error numbers are in the range -1 - -128: see diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 1c749acca02..a40ebec6aee 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -289,12 +289,13 @@ #define __NR_set_robust_list 1298 #define __NR_get_robust_list 1299 #define __NR_sync_file_range 1300 +#define __NR_tee 1301 #ifdef __KERNEL__ #include <linux/config.h> -#define NR_syscalls 277 /* length of syscall table */ +#define NR_syscalls 278 /* length of syscall table */ #define __ARCH_WANT_SYS_RT_SIGACTION diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index 536ba087305..c612f1a6277 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -302,8 +302,9 @@ #define __NR_ppoll 281 #define __NR_unshare 282 #define __NR_splice 283 +#define __NR_tee 284 -#define __NR_syscalls 284 +#define __NR_syscalls 285 #ifdef __KERNEL__ #define __NR__exit __NR_exit diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index f21ff2c1e96..d86494e23b6 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -611,8 +611,10 @@ __SYSCALL(__NR_set_robust_list, sys_set_robust_list) __SYSCALL(__NR_get_robust_list, sys_get_robust_list) #define __NR_splice 275 __SYSCALL(__NR_splice, sys_splice) +#define __NR_tee 276 +__SYSCALL(__NR_tee, sys_tee) -#define __NR_syscall_max __NR_splice +#define __NR_syscall_max __NR_tee #ifndef __NO_STUBS diff --git a/include/linux/fs.h b/include/linux/fs.h index 162c6e57307..3de2bfb2410 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1039,8 +1039,8 @@ struct file_operations { int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int (*flock) (struct file *, int, struct file_lock *); - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int); - ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); }; struct inode_operations { @@ -1613,13 +1613,13 @@ extern void do_generic_mapping_read(struct address_space *mapping, loff_t *, read_descriptor_t *, read_actor_t); /* fs/splice.c */ -extern ssize_t generic_file_splice_read(struct file *, +extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t generic_file_splice_write(struct pipe_inode_info *, - struct file *, size_t, unsigned int); + struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, - struct file *out, size_t len, unsigned int flags); -extern long do_splice_direct(struct file *in, struct file *out, + struct file *out, loff_t *, size_t len, unsigned int flags); +extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, size_t len, unsigned int flags); extern void diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 10a27f29d69..2ef845b3517 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -105,6 +105,7 @@ struct gendisk { * disks that can't be partitioned. */ char disk_name[32]; /* name of major driver */ struct hd_struct **part; /* [indexed by minor] */ + int part_uevent_suppress; struct block_device_operations *fops; struct request_queue *queue; void *private_data; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 4cb1214ec29..dcd0623be89 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -24,6 +24,7 @@ #include <linux/rwsem.h> #include <linux/kref.h> #include <linux/kernel.h> +#include <linux/wait.h> #include <asm/atomic.h> #define KOBJ_NAME_LEN 20 @@ -56,6 +57,7 @@ struct kobject { struct kset * kset; struct kobj_type * ktype; struct dentry * dentry; + wait_queue_head_t poll; }; extern int kobject_set_name(struct kobject *, const char *, ...) diff --git a/include/linux/pci.h b/include/linux/pci.h index 0aad5a378e9..3a6a4e37a48 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -97,7 +97,13 @@ enum pci_channel_state { typedef unsigned short __bitwise pci_bus_flags_t; enum pci_bus_flags { - PCI_BUS_FLAGS_NO_MSI = (pci_bus_flags_t) 1, + PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, +}; + +struct pci_cap_saved_state { + struct hlist_node next; + char cap_nr; + u32 data[0]; }; /* @@ -159,6 +165,7 @@ struct pci_dev { unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ u32 saved_config_space[16]; /* config space saved at suspend time */ + struct hlist_head saved_cap_space; struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled; /* has display of the rom attribute been enabled? */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ @@ -169,6 +176,30 @@ struct pci_dev { #define to_pci_dev(n) container_of(n, struct pci_dev, dev) #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) +static inline struct pci_cap_saved_state *pci_find_saved_cap( + struct pci_dev *pci_dev,char cap) +{ + struct pci_cap_saved_state *tmp; + struct hlist_node *pos; + + hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) { + if (tmp->cap_nr == cap) + return tmp; + } + return NULL; +} + +static inline void pci_add_saved_cap(struct pci_dev *pci_dev, + struct pci_cap_saved_state *new_cap) +{ + hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space); +} + +static inline void pci_remove_saved_cap(struct pci_cap_saved_state *cap) +{ + hlist_del(&cap->next); +} + /* * For PCI devices, the region numbers are assigned this way: * diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 870fe38378b..8d03e10212f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -497,7 +497,8 @@ #define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b #define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d #define PCI_DEVICE_ID_AMD_8151_0 0x7454 -#define PCI_DEVICE_ID_AMD_8131_APIC 0x7450 +#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 +#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 123a7c24bc7..ef7f33c0be1 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -21,6 +21,7 @@ struct pipe_buf_operations { void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *); void (*release)(struct pipe_inode_info *, struct pipe_buffer *); int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); + void (*get)(struct pipe_inode_info *, struct pipe_buffer *); }; struct pipe_inode_info { diff --git a/include/linux/pm.h b/include/linux/pm.h index 6df2585c016..66be58902b1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -199,6 +199,12 @@ extern int device_suspend(pm_message_t state); extern int dpm_runtime_suspend(struct device *, pm_message_t); extern void dpm_runtime_resume(struct device *); +extern void __suspend_report_result(const char *function, void *fn, int ret); + +#define suspend_report_result(fn, ret) \ + do { \ + __suspend_report_result(__FUNCTION__, fn, ret); \ + } while (0) #else /* !CONFIG_PM */ @@ -219,6 +225,8 @@ static inline void dpm_runtime_resume(struct device * dev) { } +#define suspend_report_result(fn, ret) do { } while (0) + #endif /* changes to device_may_wakeup take effect on the next pm state change. diff --git a/include/linux/pm_legacy.h b/include/linux/pm_legacy.h index 1252b45face..008932d73c3 100644 --- a/include/linux/pm_legacy.h +++ b/include/linux/pm_legacy.h @@ -16,11 +16,6 @@ struct pm_dev __deprecated * pm_register(pm_dev_t type, unsigned long id, pm_callback callback); /* - * Unregister a device with power management - */ -void __deprecated pm_unregister(struct pm_dev *dev); - -/* * Unregister all devices with matching callback */ void __deprecated pm_unregister_all(pm_callback callback); @@ -41,8 +36,6 @@ static inline struct pm_dev *pm_register(pm_dev_t type, return NULL; } -static inline void pm_unregister(struct pm_dev *dev) {} - static inline void pm_unregister_all(pm_callback callback) {} static inline int pm_send_all(pm_request_t rqst, void *data) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index f001bad28d9..d3ebc0e68b2 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -574,6 +574,8 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, unsigned int flags); +asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); + asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 392da5a6dac..1ea5d3cda6a 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -74,6 +74,7 @@ struct sysfs_dirent { umode_t s_mode; struct dentry * s_dentry; struct iattr * s_iattr; + atomic_t s_event; }; #define SYSFS_ROOT 0x0001 @@ -117,6 +118,7 @@ int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); int sysfs_create_group(struct kobject *, const struct attribute_group *); void sysfs_remove_group(struct kobject *, const struct attribute_group *); +void sysfs_notify(struct kobject * k, char *dir, char *attr); #else /* CONFIG_SYSFS */ @@ -185,6 +187,10 @@ static inline void sysfs_remove_group(struct kobject * k, const struct attribute ; } +static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) +{ +} + #endif /* CONFIG_SYSFS */ #endif /* _SYSFS_H_ */ diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h new file mode 100644 index 00000000000..c602f884f18 --- /dev/null +++ b/include/linux/usb/net2280.h @@ -0,0 +1,444 @@ +/* + * NetChip 2280 high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + */ +#ifndef __LINUX_USB_NET2280_H +#define __LINUX_USB_NET2280_H + +/* + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*-------------------------------------------------------------------------*/ + +/* NET2280 MEMORY MAPPED REGISTERS + * + * The register layout came from the chip documentation, and the bit + * number definitions were extracted from chip specification. + * + * Use the shift operator ('<<') to build bit masks, with readl/writel + * to access the registers through PCI. + */ + +/* main registers, BAR0 + 0x0000 */ +struct net2280_regs { + // offset 0x0000 + u32 devinit; +#define LOCAL_CLOCK_FREQUENCY 8 +#define FORCE_PCI_RESET 7 +#define PCI_ID 6 +#define PCI_ENABLE 5 +#define FIFO_SOFT_RESET 4 +#define CFG_SOFT_RESET 3 +#define PCI_SOFT_RESET 2 +#define USB_SOFT_RESET 1 +#define M8051_RESET 0 + u32 eectl; +#define EEPROM_ADDRESS_WIDTH 23 +#define EEPROM_CHIP_SELECT_ACTIVE 22 +#define EEPROM_PRESENT 21 +#define EEPROM_VALID 20 +#define EEPROM_BUSY 19 +#define EEPROM_CHIP_SELECT_ENABLE 18 +#define EEPROM_BYTE_READ_START 17 +#define EEPROM_BYTE_WRITE_START 16 +#define EEPROM_READ_DATA 8 +#define EEPROM_WRITE_DATA 0 + u32 eeclkfreq; + u32 _unused0; + // offset 0x0010 + + u32 pciirqenb0; /* interrupt PCI master ... */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + u32 pciirqenb1; +#define PCI_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + u32 cpu_irqenb0; /* ... or onboard 8051 */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + u32 cpu_irqenb1; +#define CPU_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + + // offset 0x0020 + u32 _unused1; + u32 usbirqenb1; +#define USB_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + u32 irqstat0; +#define INTA_ASSERTED 12 +#define SETUP_PACKET_INTERRUPT 7 +#define ENDPOINT_F_INTERRUPT 6 +#define ENDPOINT_E_INTERRUPT 5 +#define ENDPOINT_D_INTERRUPT 4 +#define ENDPOINT_C_INTERRUPT 3 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_0_INTERRUPT 0 + u32 irqstat1; +#define POWER_STATE_CHANGE_INTERRUPT 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 +#define PCI_PARITY_ERROR_INTERRUPT 25 +#define PCI_INTA_INTERRUPT 24 +#define PCI_PME_INTERRUPT 23 +#define PCI_SERR_INTERRUPT 22 +#define PCI_PERR_INTERRUPT 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 +#define PCI_RETRY_ABORT_INTERRUPT 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 +#define SOF_DOWN_INTERRUPT 14 +#define GPIO_INTERRUPT 13 +#define DMA_D_INTERRUPT 12 +#define DMA_C_INTERRUPT 11 +#define DMA_B_INTERRUPT 10 +#define DMA_A_INTERRUPT 9 +#define EEPROM_DONE_INTERRUPT 8 +#define VBUS_INTERRUPT 7 +#define CONTROL_STATUS_INTERRUPT 6 +#define ROOT_PORT_RESET_INTERRUPT 4 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 +#define RESUME_INTERRUPT 1 +#define SOF_INTERRUPT 0 + // offset 0x0030 + u32 idxaddr; + u32 idxdata; + u32 fifoctl; +#define PCI_BASE2_RANGE 16 +#define IGNORE_FIFO_AVAILABILITY 3 +#define PCI_BASE2_SELECT 2 +#define FIFO_CONFIGURATION_SELECT 0 + u32 _unused2; + // offset 0x0040 + u32 memaddr; +#define START 28 +#define DIRECTION 27 +#define FIFO_DIAGNOSTIC_SELECT 24 +#define MEMORY_ADDRESS 0 + u32 memdata0; + u32 memdata1; + u32 _unused3; + // offset 0x0050 + u32 gpioctl; +#define GPIO3_LED_SELECT 12 +#define GPIO3_INTERRUPT_ENABLE 11 +#define GPIO2_INTERRUPT_ENABLE 10 +#define GPIO1_INTERRUPT_ENABLE 9 +#define GPIO0_INTERRUPT_ENABLE 8 +#define GPIO3_OUTPUT_ENABLE 7 +#define GPIO2_OUTPUT_ENABLE 6 +#define GPIO1_OUTPUT_ENABLE 5 +#define GPIO0_OUTPUT_ENABLE 4 +#define GPIO3_DATA 3 +#define GPIO2_DATA 2 +#define GPIO1_DATA 1 +#define GPIO0_DATA 0 + u32 gpiostat; +#define GPIO3_INTERRUPT 3 +#define GPIO2_INTERRUPT 2 +#define GPIO1_INTERRUPT 1 +#define GPIO0_INTERRUPT 0 +} __attribute__ ((packed)); + +/* usb control, BAR0 + 0x0080 */ +struct net2280_usb_regs { + // offset 0x0080 + u32 stdrsp; +#define STALL_UNSUPPORTED_REQUESTS 31 +#define SET_TEST_MODE 16 +#define GET_OTHER_SPEED_CONFIGURATION 15 +#define GET_DEVICE_QUALIFIER 14 +#define SET_ADDRESS 13 +#define ENDPOINT_SET_CLEAR_HALT 12 +#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 +#define GET_STRING_DESCRIPTOR_2 10 +#define GET_STRING_DESCRIPTOR_1 9 +#define GET_STRING_DESCRIPTOR_0 8 +#define GET_SET_INTERFACE 6 +#define GET_SET_CONFIGURATION 5 +#define GET_CONFIGURATION_DESCRIPTOR 4 +#define GET_DEVICE_DESCRIPTOR 3 +#define GET_ENDPOINT_STATUS 2 +#define GET_INTERFACE_STATUS 1 +#define GET_DEVICE_STATUS 0 + u32 prodvendid; +#define PRODUCT_ID 16 +#define VENDOR_ID 0 + u32 relnum; + u32 usbctl; +#define SERIAL_NUMBER_INDEX 16 +#define PRODUCT_ID_STRING_ENABLE 13 +#define VENDOR_ID_STRING_ENABLE 12 +#define USB_ROOT_PORT_WAKEUP_ENABLE 11 +#define VBUS_PIN 10 +#define TIMED_DISCONNECT 9 +#define SUSPEND_IMMEDIATELY 7 +#define SELF_POWERED_USB_DEVICE 6 +#define REMOTE_WAKEUP_SUPPORT 5 +#define PME_POLARITY 4 +#define USB_DETECT_ENABLE 3 +#define PME_WAKEUP_ENABLE 2 +#define DEVICE_REMOTE_WAKEUP_ENABLE 1 +#define SELF_POWERED_STATUS 0 + // offset 0x0090 + u32 usbstat; +#define HIGH_SPEED 7 +#define FULL_SPEED 6 +#define GENERATE_RESUME 5 +#define GENERATE_DEVICE_REMOTE_WAKEUP 4 + u32 xcvrdiag; +#define FORCE_HIGH_SPEED_MODE 31 +#define FORCE_FULL_SPEED_MODE 30 +#define USB_TEST_MODE 24 +#define LINE_STATE 16 +#define TRANSCEIVER_OPERATION_MODE 2 +#define TRANSCEIVER_SELECT 1 +#define TERMINATION_SELECT 0 + u32 setup0123; + u32 setup4567; + // offset 0x0090 + u32 _unused0; + u32 ouraddr; +#define FORCE_IMMEDIATE 7 +#define OUR_USB_ADDRESS 0 + u32 ourconfig; +} __attribute__ ((packed)); + +/* pci control, BAR0 + 0x0100 */ +struct net2280_pci_regs { + // offset 0x0100 + u32 pcimstctl; +#define PCI_ARBITER_PARK_SELECT 13 +#define PCI_MULTI LEVEL_ARBITER 12 +#define PCI_RETRY_ABORT_ENABLE 11 +#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 +#define DMA_READ_MULTIPLE_ENABLE 9 +#define DMA_READ_LINE_ENABLE 8 +#define PCI_MASTER_COMMAND_SELECT 6 +#define MEM_READ_OR_WRITE 0 +#define IO_READ_OR_WRITE 1 +#define CFG_READ_OR_WRITE 2 +#define PCI_MASTER_START 5 +#define PCI_MASTER_READ_WRITE 4 +#define PCI_MASTER_WRITE 0 +#define PCI_MASTER_READ 1 +#define PCI_MASTER_BYTE_WRITE_ENABLES 0 + u32 pcimstaddr; + u32 pcimstdata; + u32 pcimststat; +#define PCI_ARBITER_CLEAR 2 +#define PCI_EXTERNAL_ARBITER 1 +#define PCI_HOST_MODE 0 +} __attribute__ ((packed)); + +/* dma control, BAR0 + 0x0180 ... array of four structs like this, + * for channels 0..3. see also struct net2280_dma: descriptor + * that can be loaded into some of these registers. + */ +struct net2280_dma_regs { /* [11.7] */ + // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, + u32 dmactl; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 +#define DMA_CLEAR_COUNT_ENABLE 21 +#define DESCRIPTOR_POLLING_RATE 19 +#define POLL_CONTINUOUS 0 +#define POLL_1_USEC 1 +#define POLL_100_USEC 2 +#define POLL_1_MSEC 3 +#define DMA_VALID_BIT_POLLING_ENABLE 18 +#define DMA_VALID_BIT_ENABLE 17 +#define DMA_SCATTER_GATHER_ENABLE 16 +#define DMA_OUT_AUTO_START_ENABLE 4 +#define DMA_PREEMPT_ENABLE 3 +#define DMA_FIFO_VALIDATE 2 +#define DMA_ENABLE 1 +#define DMA_ADDRESS_HOLD 0 + u32 dmastat; +#define DMA_ABORT_DONE_INTERRUPT 27 +#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 +#define DMA_TRANSACTION_DONE_INTERRUPT 24 +#define DMA_ABORT 1 +#define DMA_START 0 + u32 _unused0 [2]; + // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, + u32 dmacount; +#define VALID_BIT 31 +#define DMA_DIRECTION 30 +#define DMA_DONE_INTERRUPT_ENABLE 29 +#define END_OF_CHAIN 28 +#define DMA_BYTE_COUNT_MASK ((1<<24)-1) +#define DMA_BYTE_COUNT 0 + u32 dmaaddr; + u32 dmadesc; + u32 _unused1; +} __attribute__ ((packed)); + +/* dedicated endpoint registers, BAR0 + 0x0200 */ + +struct net2280_dep_regs { /* [11.8] */ + // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 + u32 dep_cfg; + // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 + u32 dep_rsp; + u32 _unused [2]; +} __attribute__ ((packed)); + +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs + * like this, for ep0 then the configurable endpoints A..F + * ep0 reserved for control; E and F have only 64 bytes of fifo + */ +struct net2280_ep_regs { /* [11.9] */ + // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 + u32 ep_cfg; +#define ENDPOINT_BYTE_COUNT 16 +#define ENDPOINT_ENABLE 10 +#define ENDPOINT_TYPE 8 +#define ENDPOINT_DIRECTION 7 +#define ENDPOINT_NUMBER 0 + u32 ep_rsp; +#define SET_NAK_OUT_PACKETS 15 +#define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_EP_FORCE_CRC_ERROR 13 +#define SET_INTERRUPT_MODE 12 +#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 +#define SET_NAK_OUT_PACKETS_MODE 10 +#define SET_ENDPOINT_TOGGLE 9 +#define SET_ENDPOINT_HALT 8 +#define CLEAR_NAK_OUT_PACKETS 7 +#define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_EP_FORCE_CRC_ERROR 5 +#define CLEAR_INTERRUPT_MODE 4 +#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define CLEAR_NAK_OUT_PACKETS_MODE 2 +#define CLEAR_ENDPOINT_TOGGLE 1 +#define CLEAR_ENDPOINT_HALT 0 + u32 ep_irqenb; +#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 + u32 ep_stat; +#define FIFO_VALID_COUNT 24 +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 +#define TIMEOUT 21 +#define USB_STALL_SENT 20 +#define USB_IN_NAK_SENT 19 +#define USB_IN_ACK_RCVD 18 +#define USB_OUT_PING_NAK_SENT 17 +#define USB_OUT_ACK_SENT 16 +#define FIFO_OVERFLOW 13 +#define FIFO_UNDERFLOW 12 +#define FIFO_FULL 11 +#define FIFO_EMPTY 10 +#define FIFO_FLUSH 9 +#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 +#define NAK_OUT_PACKETS 4 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT 1 +#define DATA_IN_TOKEN_INTERRUPT 0 + // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 + u32 ep_avail; + u32 ep_data; + u32 _unused0 [2]; +} __attribute__ ((packed)); + +#endif /* __LINUX_USB_NET2280_H */ diff --git a/kernel/power/pm.c b/kernel/power/pm.c index 0f6908cce1d..84063ac8fcf 100644 --- a/kernel/power/pm.c +++ b/kernel/power/pm.c @@ -75,25 +75,6 @@ struct pm_dev *pm_register(pm_dev_t type, return dev; } -/** - * pm_unregister - unregister a device with power management - * @dev: device to unregister - * - * Remove a device from the power management notification lists. The - * dev passed must be a handle previously returned by pm_register. - */ - -void pm_unregister(struct pm_dev *dev) -{ - if (dev) { - mutex_lock(&pm_devs_lock); - list_del(&dev->entry); - mutex_unlock(&pm_devs_lock); - - kfree(dev); - } -} - static void __pm_unregister(struct pm_dev *dev) { if (dev) { @@ -258,7 +239,6 @@ int pm_send_all(pm_request_t rqst, void *data) } EXPORT_SYMBOL(pm_register); -EXPORT_SYMBOL(pm_unregister); EXPORT_SYMBOL(pm_unregister_all); EXPORT_SYMBOL(pm_send_all); EXPORT_SYMBOL(pm_active); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0eeb7e66722..4e0f0ec003f 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -56,10 +56,6 @@ void ptrace_untrace(task_t *child) signal_wake_up(child, 1); } } - if (child->signal->flags & SIGNAL_GROUP_EXIT) { - sigaddset(&child->pending.signal, SIGKILL); - signal_wake_up(child, 1); - } spin_unlock(&child->sighand->siglock); } @@ -81,7 +77,8 @@ void __ptrace_unlink(task_t *child) add_parent(child); } - ptrace_untrace(child); + if (child->state == TASK_TRACED) + ptrace_untrace(child); } /* diff --git a/kernel/signal.c b/kernel/signal.c index b14f895027c..e5f8aea78ff 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1754,9 +1754,9 @@ relock: /* Let the debugger run. */ ptrace_stop(signr, signr, info); - /* We're back. Did the debugger cancel the sig or group_exit? */ + /* We're back. Did the debugger cancel the sig? */ signr = current->exit_code; - if (signr == 0 || current->signal->flags & SIGNAL_GROUP_EXIT) + if (signr == 0) continue; current->exit_code = 0; diff --git a/lib/kobject.c b/lib/kobject.c index 25204a41a9b..01d95751394 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -128,6 +128,7 @@ void kobject_init(struct kobject * kobj) { kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); + init_waitqueue_head(&kobj->poll); kobj->kset = kset_get(kobj->kset); } diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index db07ae73e05..be0200e9cda 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -196,8 +196,8 @@ int dialog_checklist(const char *title, const char *prompt, int height, print_buttons(dialog, height, width, 0); - wnoutrefresh(list); wnoutrefresh(dialog); + wnoutrefresh(list); doupdate(); while (key != ESC) { @@ -225,12 +225,11 @@ int dialog_checklist(const char *title, const char *prompt, int height, } scroll--; print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE); - wnoutrefresh(list); - print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); - wrefresh(dialog); + wnoutrefresh(dialog); + wrefresh(list); continue; /* wait for another key press */ } else @@ -252,12 +251,12 @@ int dialog_checklist(const char *title, const char *prompt, int height, scroll++; print_item(list, items[(scroll + max_choice - 1) * 3 + 1], status[scroll + max_choice - 1], max_choice - 1, TRUE); - wnoutrefresh(list); print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); - wrefresh(dialog); + wnoutrefresh(dialog); + wrefresh(list); continue; /* wait for another key press */ } else @@ -271,8 +270,8 @@ int dialog_checklist(const char *title, const char *prompt, int height, choice = i; print_item(list, items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE); - wnoutrefresh(list); - wrefresh(dialog); + wnoutrefresh(dialog); + wrefresh(list); } continue; /* wait for another key press */ } @@ -306,8 +305,8 @@ int dialog_checklist(const char *title, const char *prompt, int height, print_item(list, items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice); } - wnoutrefresh(list); - wrefresh(dialog); + wnoutrefresh(dialog); + wrefresh(list); for (i = 0; i < item_no; i++) if (status[i]) |