From ee579c4627686d02683247749de0da3e59a26ea8 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:19:26 -0500 Subject: [PATCH] Import 2.2.12pre3 --- arch/alpha/kernel/alpha_ksyms.c | 56 +- arch/i386/config.in | 2 +- arch/sparc64/kernel/process.c | 6 +- drivers/block/floppy.c | 47 +- drivers/block/xor.c | 529 +++++++- drivers/char/mem.c | 20 +- drivers/sound/sb_common.c | 2 +- drivers/usb/CREDITS | 7 +- drivers/usb/Config.in | 44 +- drivers/usb/Makefile | 167 +-- drivers/usb/README.ohci | 61 +- drivers/usb/acm.c | 295 ----- drivers/usb/audio.c | 30 +- drivers/usb/cpia.c | 1277 ------------------- drivers/usb/cpia.h | 139 --- drivers/usb/ezusb.c | 472 ------- drivers/usb/ezusb.h | 67 - drivers/usb/hub.c | 156 +-- drivers/usb/hub.h | 9 +- drivers/usb/inits.h | 9 +- drivers/usb/keyboard.c | 40 +- drivers/usb/keymap.c | 4 +- drivers/usb/maps/fixup.map | 3 +- drivers/usb/maps/mac.map | 350 ------ drivers/usb/mkmap.adb | 88 -- drivers/usb/mouse.c | 112 +- drivers/usb/ohci-debug.c | 95 +- drivers/usb/ohci-hcd.c | 205 ++- drivers/usb/ohci-hcd.h | 1 + drivers/usb/ohci.c | 2058 ++++++++----------------------- drivers/usb/ohci.h | 127 +- drivers/usb/printer.c | 420 ------- drivers/usb/proc_usb.c | 487 -------- drivers/usb/procusb | 41 - drivers/usb/stopusb | 4 - drivers/usb/uhci-debug.c | 35 +- drivers/usb/uhci.c | 832 ++----------- drivers/usb/uhci.h | 35 +- drivers/usb/usb-core.c | 103 -- drivers/usb/usb-debug.c | 55 +- drivers/usb/usb.c | 618 +--------- drivers/usb/usb.h | 192 +-- drivers/usb/usb_scsi.c | 1453 ---------------------- drivers/usb/usb_scsi.h | 147 --- drivers/usb/usb_scsi_debug.c | 116 -- drivers/usb/usb_scsi_dt.c | 4 - include/linux/fd.h | 2 +- include/net/tcp.h | 3 +- net/ipv4/tcp_input.c | 6 +- net/ipv4/tcp_ipv4.c | 12 +- net/ipv6/tcp_ipv6.c | 12 +- 51 files changed, 1598 insertions(+), 9457 deletions(-) delete mode 100644 drivers/usb/acm.c delete mode 100644 drivers/usb/cpia.c delete mode 100644 drivers/usb/cpia.h delete mode 100644 drivers/usb/ezusb.c delete mode 100644 drivers/usb/ezusb.h delete mode 100644 drivers/usb/maps/mac.map delete mode 100644 drivers/usb/mkmap.adb delete mode 100644 drivers/usb/printer.c delete mode 100644 drivers/usb/proc_usb.c delete mode 100644 drivers/usb/procusb delete mode 100644 drivers/usb/usb-core.c delete mode 100644 drivers/usb/usb_scsi.c delete mode 100644 drivers/usb/usb_scsi.h delete mode 100644 drivers/usb/usb_scsi_debug.c delete mode 100644 drivers/usb/usb_scsi_dt.c diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index cba493d09b1f..c220ccdc6671 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -25,10 +23,6 @@ #include #include #include -#include -#include -#include -#include #define __KERNEL_SYSCALLS__ #include @@ -47,14 +41,8 @@ extern void __remlu (void); extern void __divqu (void); extern void __remqu (void); -EXPORT_SYMBOL(alpha_mv); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(disable_irq_nosync); -EXPORT_SYMBOL(screen_info); -EXPORT_SYMBOL(perf_irq); /* platform dependent support */ EXPORT_SYMBOL(_inb); @@ -71,7 +59,7 @@ EXPORT_SYMBOL(_writew); EXPORT_SYMBOL(_writel); EXPORT_SYMBOL(_memcpy_fromio); EXPORT_SYMBOL(_memcpy_toio); -EXPORT_SYMBOL(_memset_c_io); +EXPORT_SYMBOL(_memset_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); @@ -88,14 +76,12 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); EXPORT_SYMBOL(dump_thread); @@ -129,9 +115,7 @@ EXPORT_SYMBOL(csum_ipv6_magic); #ifdef CONFIG_MATHEMU_MODULE extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); -extern long (*alpha_fp_emul) (unsigned long pc); EXPORT_SYMBOL(alpha_fp_emul_imprecise); -EXPORT_SYMBOL(alpha_fp_emul); #endif /* @@ -142,44 +126,6 @@ EXPORT_SYMBOL_NOVERS(__do_clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strlen_user); -/* - * The following are specially called from the semaphore assembly stubs. - */ -EXPORT_SYMBOL_NOVERS(__down_failed); -EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); -EXPORT_SYMBOL_NOVERS(__up_wakeup); - -/* - * SMP-specific symbols. - */ - -#ifdef __SMP__ -EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(flush_tlb_all); -EXPORT_SYMBOL(flush_tlb_mm); -EXPORT_SYMBOL(flush_tlb_page); -EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(cpu_number_map); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(synchronize_bh); -EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -#if DEBUG_SPINLOCK -EXPORT_SYMBOL(spin_unlock); -EXPORT_SYMBOL(debug_spin_lock); -EXPORT_SYMBOL(debug_spin_trylock); -#endif -#if DEBUG_RWLOCK -EXPORT_SYMBOL(write_lock); -EXPORT_SYMBOL(read_lock); -#endif -#endif /* __SMP__ */ - /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in diff --git a/arch/i386/config.in b/arch/i386/config.in index e083337bda74..c4e882510e7d 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -172,7 +172,7 @@ endmenu source drivers/char/Config.in -source drivers/usb/Config.in +# source drivers/usb/Config.in source fs/Config.in diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 0d4871132330..4cab7590a26a 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -652,10 +652,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +pid_t kernel_thread(int (*__fn)(void *), void * __arg, unsigned long flags) { + register int (*fn)(void *) asm("g2"); + register void *arg asm("g3"); long retval; + fn = __fn; + arg = __arg; __asm__ __volatile("mov %1, %%g1\n\t" "mov %2, %%o0\n\t" /* Clone flags. */ "mov 0, %%o1\n\t" /* usp arg == 0 */ diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 5cd038abe7c7..a740b65492ea 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -106,6 +106,12 @@ * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives. */ +/* + * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24 + * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were + * being used to store jiffies, which are unsigned longs). + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -604,10 +610,10 @@ static void is_alive(const char *message) #define OLOGSIZE 20 static void (*lasthandler)(void) = NULL; -static int interruptjiffies=0; -static int resultjiffies=0; +static unsigned long interruptjiffies=0; +static unsigned long resultjiffies=0; static int resultsize=0; -static int lastredo=0; +static unsigned long lastredo=0; static struct output_log { unsigned char data; @@ -627,7 +633,7 @@ static void reschedule_timeout(int drive, const char *message, int marg) drive = current_drive; del_timer(&fd_timeout); if (drive < 0 || drive > N_DRIVE) { - fd_timeout.expires = jiffies + 20*HZ; + fd_timeout.expires = jiffies + 20UL*HZ; drive=0; } else fd_timeout.expires = jiffies + UDP->timeout; @@ -710,7 +716,7 @@ static int disk_change(int drive) #ifdef DCL_DEBUG if (UDP->flags & FD_DEBUG){ DPRINT("checking disk change line for drive %d\n",drive); - DPRINT("jiffies=%ld\n", jiffies); + DPRINT("jiffies=%lu\n", jiffies); DPRINT("disk change line=%x\n",fd_inb(FD_DIR)&0x80); DPRINT("flags=%lx\n",UDRS->flags); } @@ -1004,7 +1010,7 @@ static void main_command_interrupt(void) } /* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(int delay, timeout_fn function) +static int wait_for_completion(unsigned long delay, timeout_fn function) { if (FDCS->reset){ reset_fdc(); /* do the reset during sleep to win time @@ -1275,7 +1281,7 @@ static int fdc_configure(void) static void fdc_specify(void) { unsigned char spec1, spec2; - int srt, hlt, hut; + unsigned long srt, hlt, hut; unsigned long dtr = NOMINAL_DTR; unsigned long scale_dtr = NOMINAL_DTR; int hlt_max_code = 0x7f; @@ -1365,7 +1371,7 @@ static int fdc_dtr(void) * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) */ FDCS->dtr = raw_cmd->rate & 3; - return(wait_for_completion(jiffies+2*HZ/100, + return(wait_for_completion(jiffies+2UL*HZ/100, (timeout_fn) floppy_ready)); } /* fdc_dtr */ @@ -1461,7 +1467,8 @@ static int interpret_errors(void) */ static void setup_rw_floppy(void) { - int i,ready_date,r, flags,dflags; + int i,r, flags,dflags; + unsigned long ready_date; timeout_fn function; flags = raw_cmd->flags; @@ -1534,7 +1541,7 @@ static void seek_interrupt(void) #ifdef DCL_DEBUG if (DP->flags & FD_DEBUG){ DPRINT("clearing NEWCHANGE flag because of effective seek\n"); - DPRINT("jiffies=%ld\n", jiffies); + DPRINT("jiffies=%lu\n", jiffies); } #endif CLEARF(FD_DISK_NEWCHANGE); /* effective seek */ @@ -1824,20 +1831,20 @@ static void show_floppy(void) printk("\n"); printk("floppy driver state\n"); printk("-------------------\n"); - printk("now=%ld last interrupt=%d last called handler=%p\n", - jiffies, interruptjiffies, lasthandler); + printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n", + jiffies, interruptjiffies, jiffies-interruptjiffies, lasthandler); #ifdef FLOPPY_SANITY_CHECK printk("timeout_message=%s\n", timeout_message); printk("last output bytes:\n"); for (i=0; i < OLOGSIZE; i++) - printk("%2x %2x %ld\n", + printk("%2x %2x %lu\n", output_log[(i+output_log_pos) % OLOGSIZE].data, output_log[(i+output_log_pos) % OLOGSIZE].status, output_log[(i+output_log_pos) % OLOGSIZE].jiffies); - printk("last result at %d\n", resultjiffies); - printk("last redo_fd_request at %d\n", lastredo); + printk("last result at %lu\n", resultjiffies); + printk("last redo_fd_request at %lu\n", lastredo); for (i=0; icheckfreq < jiffies - UDRS->last_checked){ + if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) { lock_fdc(drive,0); poll_drive(0,0); process_fd_request(); diff --git a/drivers/block/xor.c b/drivers/block/xor.c index d52f79ed5299..062ba73046de 100644 --- a/drivers/block/xor.c +++ b/drivers/block/xor.c @@ -847,7 +847,7 @@ XORBLOCK_TEMPLATE(p5_mmx) * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) * * Requirements: - * !(((long)destp | (long)sourcep) & (64 - 1)) && + * !(((long)dest | (long)sourceN) & (64 - 1)) && * !(len & 127) && len >= 256 * * It is done in pure assembly, as otherwise gcc makes it @@ -855,24 +855,28 @@ XORBLOCK_TEMPLATE(p5_mmx) * Also, we don't measure the speeds as on other architectures, * as the measuring routine does not take into account cold caches * and the fact that xor_block_VIS bypasses the caches. - * xor_block_32regs might be 5% faster if caches are hot and things - * just right, but I think it is better not to pollute the caches. + * xor_block_32regs might be 5% faster for count 2 if caches are hot + * and things just right (for count 3 VIS is about as fast as 32regs for + * hot caches and for count 4 and 5 VIS is faster by good margin always), + * but I think it is better not to pollute the caches. * Actually, if I'd just fight for speed for hot caches, I could * write a hybrid VIS/integer routine, which would do always two * 64B blocks in VIS and two in IEUs, but I really care more about * caches. */ extern void *VISenter(void); -extern void xor_block_VIS SRCDEST; +extern void xor_block_VIS XOR_ARGS; void __xor_block_VIS(void) { __asm__ (" .globl xor_block_VIS xor_block_VIS: - ldx [%%o1 + %0], %%o1 - ldx [%%o0 + %1], %%o2 - ldx [%%o0 + %0], %%o0 + ldx [%%o1 + 0], %%o4 + ldx [%%o1 + 8], %%o3 + ldx [%%o4 + %1], %%g5 + ldx [%%o4 + %0], %%o4 + ldx [%%o3 + %0], %%o3 rd %%fprs, %%o5 andcc %%o5, %2, %%g0 be,pt %%icc, 297f @@ -880,38 +884,170 @@ xor_block_VIS: jmpl %%g1 + %%lo(%5), %%g7 add %%g7, 8, %%g7 297: wr %%g0, %4, %%fprs - wr %%g0, %3, %%asi membar #LoadStore|#StoreLoad|#StoreStore - sub %%o2, 128, %%o2 - ldda [%%o0] %3, %%f0 - ldda [%%o1] %3, %%f16 -1: ldda [%%o0 + 64] %%asi, %%f32 + sub %%g5, 64, %%g5 + ldda [%%o4] %3, %%f0 + ldda [%%o3] %3, %%f16 + cmp %%o0, 4 + bgeu,pt %%xcc, 10f + cmp %%o0, 3 + be,pn %%xcc, 13f + mov -64, %%g1 + sub %%g5, 64, %%g5 + rd %%asi, %%g1 + wr %%g0, %3, %%asi + +2: ldda [%%o4 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o4] %3 + ldda [%%o3 + 64] %%asi, %%f48 + ldda [%%o4 + 128] %%asi, %%f0 + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + add %%o4, 128, %%o4 + fxor %%f36, %%f52, %%f52 + add %%o3, 128, %%o3 + fxor %%f38, %%f54, %%f54 + subcc %%g5, 128, %%g5 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4 - 64] %%asi + bne,pt %%xcc, 2b + ldda [%%o3] %3, %%f16 + + ldda [%%o4 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o4] %3 + ldda [%%o3 + 64] %%asi, %%f48 + membar #Sync + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + fxor %%f36, %%f52, %%f52 + fxor %%f38, %%f54, %%f54 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4 + 64] %%asi + membar #Sync|#StoreStore|#StoreLoad + wr %%g0, 0, %%fprs + retl + wr %%g1, %%g0, %%asi + +13: ldx [%%o1 + 16], %%o2 + ldx [%%o2 + %0], %%o2 + +3: ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + add %%o4, 64, %%o4 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + add %%o3, 64, %%o3 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o4] %3, %%f0 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + add %%o2, 64, %%o2 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + subcc %%g5, 64, %%g5 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 3b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + membar #Sync + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4] %3 + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + +10: cmp %%o0, 5 + be,pt %%xcc, 15f + mov -64, %%g1 + +14: ldx [%%o1 + 16], %%o2 + ldx [%%o1 + 24], %%o0 + ldx [%%o2 + %0], %%o2 + ldx [%%o0 + %0], %%o0 + +4: ldda [%%o2] %3, %%f32 fxor %%f0, %%f16, %%f16 fxor %%f2, %%f18, %%f18 + add %%o4, 64, %%o4 fxor %%f4, %%f20, %%f20 fxor %%f6, %%f22, %%f22 + add %%o3, 64, %%o3 fxor %%f8, %%f24, %%f24 fxor %%f10, %%f26, %%f26 fxor %%f12, %%f28, %%f28 fxor %%f14, %%f30, %%f30 - stda %%f16, [%%o0] %3 - ldda [%%o1 + 64] %%asi, %%f48 - ldda [%%o0 + 128] %%asi, %%f0 + ldda [%%o0] %3, %%f48 + fxor %%f16, %%f32, %%f32 + fxor %%f18, %%f34, %%f34 + fxor %%f20, %%f36, %%f36 + fxor %%f22, %%f38, %%f38 + add %%o2, 64, %%o2 + fxor %%f24, %%f40, %%f40 + fxor %%f26, %%f42, %%f42 + fxor %%f28, %%f44, %%f44 + fxor %%f30, %%f46, %%f46 + ldda [%%o4] %3, %%f0 fxor %%f32, %%f48, %%f48 fxor %%f34, %%f50, %%f50 - add %%o0, 128, %%o0 fxor %%f36, %%f52, %%f52 - add %%o1, 128, %%o1 + add %%o0, 64, %%o0 fxor %%f38, %%f54, %%f54 - subcc %%o2, 128, %%o2 fxor %%f40, %%f56, %%f56 fxor %%f42, %%f58, %%f58 + subcc %%g5, 64, %%g5 fxor %%f44, %%f60, %%f60 fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o0 - 64] %%asi - bne,pt %%xcc, 1b - ldda [%%o1] %3, %%f16 - ldda [%%o0 + 64] %%asi, %%f32 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 4b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 fxor %%f0, %%f16, %%f16 fxor %%f2, %%f18, %%f18 fxor %%f4, %%f20, %%f20 @@ -920,8 +1056,15 @@ xor_block_VIS: fxor %%f10, %%f26, %%f26 fxor %%f12, %%f28, %%f28 fxor %%f14, %%f30, %%f30 - stda %%f16, [%%o0] %3 - ldda [%%o1 + 64] %%asi, %%f48 + ldda [%%o0] %3, %%f48 + fxor %%f16, %%f32, %%f32 + fxor %%f18, %%f34, %%f34 + fxor %%f20, %%f36, %%f36 + fxor %%f22, %%f38, %%f38 + fxor %%f24, %%f40, %%f40 + fxor %%f26, %%f42, %%f42 + fxor %%f28, %%f44, %%f44 + fxor %%f30, %%f46, %%f46 membar #Sync fxor %%f32, %%f48, %%f48 fxor %%f34, %%f50, %%f50 @@ -931,7 +1074,101 @@ xor_block_VIS: fxor %%f42, %%f58, %%f58 fxor %%f44, %%f60, %%f60 fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o0 + 64] %%asi + stda %%f48, [%%o4] %3 + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + +15: ldx [%%o1 + 16], %%o2 + ldx [%%o1 + 24], %%o0 + ldx [%%o1 + 32], %%o1 + ldx [%%o2 + %0], %%o2 + ldx [%%o0 + %0], %%o0 + ldx [%%o1 + %0], %%o1 + +5: ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + add %%o4, 64, %%o4 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + add %%o3, 64, %%o3 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o0] %3, %%f16 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + add %%o2, 64, %%o2 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + ldda [%%o1] %3, %%f32 + fxor %%f48, %%f16, %%f48 + fxor %%f50, %%f18, %%f50 + add %%o0, 64, %%o0 + fxor %%f52, %%f20, %%f52 + fxor %%f54, %%f22, %%f54 + add %%o1, 64, %%o1 + fxor %%f56, %%f24, %%f56 + fxor %%f58, %%f26, %%f58 + fxor %%f60, %%f28, %%f60 + fxor %%f62, %%f30, %%f62 + ldda [%%o4] %3, %%f0 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + subcc %%g5, 64, %%g5 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 5b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o0] %3, %%f16 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + ldda [%%o1] %3, %%f32 + fxor %%f48, %%f16, %%f48 + fxor %%f50, %%f18, %%f50 + fxor %%f52, %%f20, %%f52 + fxor %%f54, %%f22, %%f54 + fxor %%f56, %%f24, %%f56 + fxor %%f58, %%f26, %%f58 + fxor %%f60, %%f28, %%f60 + fxor %%f62, %%f30, %%f62 + membar #Sync + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4] %3 membar #Sync|#StoreStore|#StoreLoad retl wr %%g0, 0, %%fprs @@ -954,38 +1191,216 @@ xor_block_VIS: XORBLOCK_TEMPLATE(SPARC) { - int size = dest->b_size; + int size = bh_ptr[0]->b_size; int lines = size / (sizeof (long)) / 8, i; - long *destp = (long *) dest->b_data; - long *sourcep = (long *) source->b_data; - - for (i = lines; i > 0; i--) { - __asm__ __volatile__(" - ldd [%0 + 0x00], %%g2 - ldd [%0 + 0x08], %%g4 - ldd [%0 + 0x10], %%o0 - ldd [%0 + 0x18], %%o2 - ldd [%1 + 0x00], %%o4 - ldd [%1 + 0x08], %%l0 - ldd [%1 + 0x10], %%l2 - ldd [%1 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - std %%g2, [%0 + 0x00] - std %%g4, [%0 + 0x08] - std %%o0, [%0 + 0x10] - std %%o2, [%0 + 0x18] - " : : "r" (destp), "r" (sourcep) : "g2", "g3", "g4", "g5", "o0", - "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5"); - - destp += 8; - sourcep += 8; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1 = (long *) bh_ptr[1]->b_data; + long *source2, *source3, *source4; + + switch (count) { + case 2: + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1) : "g2", "g3", "g4", "g5", "o0", + "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + } + break; + case 4: + source2 = (long *) bh_ptr[2]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%3 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%3 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%3 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%3 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + source3 += 8; + } + break; + case 5: + source2 = (long *) bh_ptr[2]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source4 = (long *) bh_ptr[4]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%3 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%3 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%3 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%3 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%4 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%4 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%4 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%4 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3), "r" (source4) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + } + break; } } #endif /* __sparc_v[78]__ */ @@ -1429,7 +1844,7 @@ void calibrate_xor_block(void) sti(); /* should be safe */ #if defined(__sparc__) && !defined(__sparc_v9__) - printk(KERN_INFO "raid5: using high-speed SPARC checksum routine\n"); + printk(KERN_INFO "raid5: trying high-speed SPARC checksum routine\n"); xor_speed(&t_xor_block_SPARC,&b1,&b2); #endif diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 4976518a4356..9cee14e44bda 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -52,8 +52,14 @@ extern void mda_console_init(void); #if defined(CONFIG_PPC) || defined(CONFIG_MAC) extern void adbdev_init(void); #endif -#ifdef CONFIG_USB -extern void usb_init(void); +#ifdef CONFIG_USB_UHCI +int uhci_init(void); +#endif +#ifdef CONFIG_USB_OHCI +int ohci_init(void); +#endif +#ifdef CONFIG_USB_OHCI_HCD +int ohci_hcd_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, @@ -612,7 +618,15 @@ __initfunc(int chr_dev_init(void)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); #ifdef CONFIG_USB - usb_init(); +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI + ohci_init(); +#endif +#ifdef CONFIG_USB_OHCI_HCD + ohci_hcd_init(); +#endif #endif #if defined (CONFIG_FB) fbmem_init(); diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index d162e470d5a5..c64c1e71c79d 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -897,7 +897,7 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu) } if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI)) { - if (devc->irq > 0); + if (devc->irq > 0) free_irq(devc->irq, devc); sound_unload_mixerdev(devc->my_mixerdev); diff --git a/drivers/usb/CREDITS b/drivers/usb/CREDITS index 7ad890ee2e48..6cd211b2270c 100644 --- a/drivers/usb/CREDITS +++ b/drivers/usb/CREDITS @@ -8,7 +8,6 @@ difficult to maintain, add yourself with a patch if desired. Johannes Erdfelt ham Bradley M Keryan - Paul Mackerras Vojtech Pavlik Gregory P. Smith Linus Torvalds @@ -29,11 +28,7 @@ of hardware, support, time and development (this is from the original THANKS file in Inaky's driver): The following corporations have helped us in the development - of Linux USB / UUSBD: - - - 3Com GmbH for donating a ISDN Pro TA and supporting me - in technical questions and with test equipment. I'd never - expect such a great help. +of Linux USB / UUSBD: - USAR Systems provided us with one of their excellent USB Evaluation Kits. It allows us to test the Linux-USB driver diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 7eff290a0d7c..632e3d08a5a8 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -5,39 +5,25 @@ # Right now hubs, mice and keyboards work - at least with UHCI. # But that may be more a lucky coincidence than anything else.. # +# This was all developed modularly, but I've been lazy in cleaning +# it up, so right now they are all bools. +# mainmenu_option next_comment comment 'USB drivers - not for the faint of heart' -tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB -if [ ! "$CONFIG_USB" = "n" ]; then - dep_tristate 'UHCI (intel PIIX4 and others) support' CONFIG_USB_UHCI \ - $CONFIG_USB - dep_tristate 'OHCI (mac, compaq and others) support' CONFIG_USB_OHCI \ - $CONFIG_USB +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB + if [ ! "$CONFIG_USB" = "n" ]; then + bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI + bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI + bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD + if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then + bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB + fi - if [ "$CONFIG_USB_OHCI" != "n" ]; then - bool ' Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG - fi - dep_tristate 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \ - CONFIG_USB_OHCI_HCD $CONFIG_USB - if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then -# bool ' OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB - define_bool CONFIG_USB_OHCI_VROOTHUB y - fi - - dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB - dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB - dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB - dep_tristate 'USB Abstract Control Model support' CONFIG_USB_ACM $CONFIG_USB - dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB - dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB - if [ "$CONFIG_USB_SCSI" != "n" ]; then - dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI - fi - dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB - if [ "$CONFIG_PROC_FS" != "n" ]; then - bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC + bool 'USB mouse support' CONFIG_USB_MOUSE + bool 'USB keyboard support' CONFIG_USB_KBD + bool 'USB audio parsing support' CONFIG_USB_AUDIO fi fi diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 10c8bfa1605e..6c6e7b091cc0 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -7,6 +7,8 @@ # # Note 2! The CFLAGS definitions are now inherited from the # parent makes.. +# +# This isn't actually supported yet. Don't try to use it. SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) @@ -15,127 +17,59 @@ ALL_SUB_DIRS := $(SUB_DIRS) L_TARGET := usb.a M_OBJS := L_OBJS := - -ifeq ($(CONFIG_USB),y) - L_OBJS +=usbcore.o -endif -ifeq ($(CONFIG_USB),m) - M_OBJS +=usbcore.o - MIX_OBJS +=usb.o usb-debug.o usb-core.o - ifeq ($(CONFIG_USB_PROC),y) - MIX_OBJS += proc_usb.o - endif -endif - -ifeq ($(CONFIG_USB_UHCI),y) - L_OBJS += uhci.o uhci-debug.o -endif - -ifeq ($(CONFIG_USB_UHCI),m) - M_OBJS += usb-uhci.o - MIX_OBJS += uhci.o uhci-debug.o -endif - -ifeq ($(CONFIG_USB_OHCI),y) - L_OBJS += ohci.o ohci-debug.o -endif -ifeq ($(CONFIG_USB_OHCI),m) - M_OBJS += usb-ohci.o - MIX_OBJS += ohci.o ohci-debug.o -endif - -ifeq ($(CONFIG_USB_OHCI_HCD),y) - L_OBJS += ohci-hcd.o ohci-root-hub.o -endif -ifeq ($(CONFIG_USB_OHCI_HCD),m) - M_OBJS += usb-ohci-hcd.o - MIX_OBJS += ohci-hcd.o ohci-root-hub.o -endif +LX_OBJS := +USBX_OBJS := usb.o hub.o usb-debug.o ifeq ($(CONFIG_USB_MOUSE),y) - L_OBJS += mouse.o -endif -ifeq ($(CONFIG_USB_MOUSE),m) - M_OBJS +=mouse.o - MIX_OBJS +=mouse.o + USBX_OBJS += mouse.o endif -ifeq ($(CONFIG_USB_HUB),y) - L_OBJS += hub.o -endif -ifeq ($(CONFIG_USB_HUB),m) - M_OBJS +=hub.o - MIX_OBJS +=hub.o -endif - -ifeq ($(CONFIG_USB_ACM),y) - L_OBJS += acm.o -endif -ifeq ($(CONFIG_USB_ACM),m) - M_OBJS += acm.o - MIX_OBJS +=acm.o +ifeq ($(CONFIG_USB_KBD),y) + USBX_OBJS += keyboard.o keymap.o endif -ifeq ($(CONFIG_USB_PRINTER),y) - L_OBJS += printer.o +ifeq ($(CONFIG_USB_AUDIO),y) + USBX_OBJS += audio.o endif -ifeq ($(CONFIG_USB_PRINTER),m) - M_OBJS += printer.o - MIX_OBJS += printer.o +ifeq ($(CONFIG_USB), y) + L_OBJS += $(USBX_OBJS) endif -ifeq ($(CONFIG_USB_KBD),y) - ifneq ($(CONFIG_MAC_KEYBOARD),y) - L_OBJS += keyboard.o keymap.o +ifeq ($(CONFIG_USB_UHCI),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += uhci.o uhci-debug.o else - L_OBJS += keyboard.o keymap-mac.o + ifeq ($(CONFIG_USB),m) + M_OBJS += usb-uhci.o + MIX_OBJS += $(USBX_OBJS) + endif endif endif -ifeq ($(CONFIG_USB_KBD),m) - M_OBJS += usb-keyboard.o - ifneq ($(CONFIG_MAC_KEYBOARD),y) - MIX_OBJS += keyboard.o keymap.o +ifeq ($(CONFIG_USB_OHCI),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += ohci.o ohci-debug.o else - MIX_OBJS += keyboard.o keymap-mac.o + ifeq ($(CONFIG_USB),m) + USBO_OBJS += ohci.o ohci-debug.o + M_OBJS += usb-ohci.o + MIX_OBJS += $(USBX_OBJS) + endif endif endif -ifeq ($(CONFIG_USB_AUDIO),y) - L_OBJS += audio.o -endif - -ifeq ($(CONFIG_USB_AUDIO),m) - M_OBJS += audio.o - MIX_OBJS += audio.o -endif - -ifeq ($(CONFIG_USB_CPIA),y) - L_OBJS += cpia.o -endif - -ifeq ($(CONFIG_USB_CPIA),m) - M_OBJS += cpia.o - MIX_OBJS += cpia.o -endif - -ifeq ($(CONFIG_USB_SCSI),y) - L_OBJS += usb_scsi.o - ifeq ($(CONFIG_USB_SCSI_DEBUG),y) - L_OBJS += usb_scsi_debug.o +ifeq ($(CONFIG_USB_OHCI_HCD),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += ohci-hcd.o ohci-root-hub.o + else + ifeq ($(CONFIG_USB),m) + USBO_OBJS += ohci-hcd.o ohci-root-hub.o + M_OBJS += usb-ohci-hcd.o + MIX_OBJS += $(USBX_OBJS) + endif endif endif - -ifeq ($(CONFIG_USB_EZUSB),y) - L_OBJS += ezusb.o -endif - -ifeq ($(CONFIG_USB_EZUSB),m) - M_OBJS += ezusb.o - MIX_OBJS += ezusb.o -endif - include $(TOPDIR)/Rules.make keymap.o: keymap.c @@ -143,31 +77,12 @@ keymap.o: keymap.c keymap.c: maps/serial.map maps/usb.map maps/fixup.map ./mkmap > $@ -keymap-mac.o: keymap-mac.c -keymap-mac.c: maps/mac.map maps/usb.map - ./mkmap.adb > $@ +usb-uhci.o: uhci.o uhci-debug.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ uhci.o uhci-debug.o $(USBX_OBJS) -ifneq ($(CONFIG_MAC_KEYBOARD),y) -usb-keyboard.o: keymap.o keyboard.o - $(LD) $(LD_RFLAG) -r -o $@ keymap.o keyboard.o -else -usb-keyboard.o: keymap-mac.o keyboard.o - $(LD) $(LD_RFLAG) -r -o $@ keymap-mac.o keyboard.o -endif +usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS) -usb-uhci.o: uhci.o uhci-debug.o - $(LD) $(LD_RFLAG) -r -o $@ uhci.o uhci-debug.o - -usb-ohci.o: ohci.o ohci-debug.o - $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o - -usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o - $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o +usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS) -ifeq ($(CONFIG_USB_PROC),y) -usbcore.o: usb.o usb-debug.o usb-core.o proc_usb.o - $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o proc_usb.o -else -usbcore.o: usb.o usb-debug.o usb-core.o - $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o -endif diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci index 921d9a9a36a4..7a544eb3353a 100644 --- a/drivers/usb/README.ohci +++ b/drivers/usb/README.ohci @@ -1,50 +1,4 @@ -[This is the readme for ohci.c, ohci-debug.c and ohci.h] - -June 23, 1999 00:31:20 PST - -I now have bulk support in a reasonably working state. The only -device I have tested it with at the moment is my Epson Stylus 740 -printer. I can print both small and large files. - -I have included code to support transfers of large amounts of data in -either control or bulk transfers. Check out the build_td_chain() and -add_td_chain_to_ed() functions. - -TODO: - -~ Get Michael Gee's mass storage driver working with my donated - YE-Data floppy drive over OHCI. -~ Drool on the Epson printer because its the new toy around the house. - -June 08, 1999 01:23:34 - -Paul Mackerras went through the OHCI (& USB code) to fix most of the -endianness issues so that the code now works on Linux-PPC. He also -simplified add_td_to_ed to be simpler & atomic to the hardware. - -May 16, 1999 16:20:54 - -EDs are now allocated dynamically from their device's pool. Root hub -status changes should stop the infinite "no device connected" messages -that occurred after removing a device. - -TODO: - -~ Add Isochronous transfer support. These have their own special - format TDs to allow for several DMA data pointers. Kinda neat, but - likely harder to use through a generic interface in practice. -~ Support dynamic allocation & growth of the TD/ED pools. Merge them - into global pools rather than a today's static per device allocation. - -KNOWN BUGS: - -~ Unplugging a hub causes khubd to Oops. I don't think this is - directly related to OHCI, but due to the fact that the interrupt TD - for the hub is never stopped. We need a usb_release_irq() that gets - called using the "IRQ handle" that should be returned by - usb_request_irq(). - -May 09, 1999 16:25:58 PST +May 09, 1999 16:25:58 Cool, things are working "well" now. (I'm not getting oops's from the OHCI code anyways.. ;). I can attach a usb hub and mouse in any @@ -55,5 +9,18 @@ acknowledged because /proc/interrupts usb-ohci goes up accordingly with mouse movements/events. That means the TD at least returns some data and requeues itself. +Device attach/detach from the root hub is not working well. Currently +every interrupt checks for root hub status changes and frame number +overflow interrupts are enabled. This means you shouldn't have to +wait more than 32-33 seconds for the change to occur, less if there is +other activity. (due to checking in the WDH caused interrupts) +My OHCI controller [SiS 5598 motherboard] doesn't seem to play well +with the RHSC interrupt so it has been disabled. The ohci_timer +should be polling but it not currently working, I haven't had time to +look into that problem. + +However, when I tried telling X to use /dev/psaux for the mouse my +machine locked up... + - greg@electricrain.com diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c deleted file mode 100644 index 4521bd701ba1..000000000000 --- a/drivers/usb/acm.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * USB Abstract Control Model based on Brad Keryan's USB busmouse driver - * - * Armin Fuerst 5/8/1999 - * - * version 0.2: Improved Bulk transfer. TX led now flashes every time data is - * sent. Send Encapsulated Data is not needed, nor does it do anything. - * Why's that ?!? Thanks to Thomas Sailer for his close look at the bulk code. - * He told me about some importand bugs. (5/21/99) - * - * version 0.1: Bulk transfer for uhci seems to work now, no dangling tds any - * more. TX led of the ISDN TA flashed the first time. Does this mean it works? - * The interrupt of the ctrl endpoint crashes the kernel => no read possible - * (5/19/99) - * - * version 0.0: Driver sets up configuration, sets up data pipes, opens misc - * device. No actual data transfer is done, since we don't have bulk transfer, - * yet. Purely skeleton for now. (5/8/99) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usb.h" - -#define USB_ACM_MINOR 32 - -struct acm_state { - int present; /* this acm is plugged in */ - int active; /* someone is has this acm's device open */ - int serstate; /* Status of the serial port (rate, handshakelines,...) */ - struct usb_device *dev; - unsigned ctrlbuffer; /*buffer for control messages*/ - unsigned int readendp,writeendp,ctrlendp; - unsigned int readpipe,writepipe,ctrlpipe; - char buffer; -}; - -static struct acm_state static_acm_state; - -spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED; - -static int acm_irq(int state, void *__buffer, int len, void *dev_id) -{ -// unsigned char *data = __buffer; - struct acm_state *acm = &static_acm_state; - devrequest *dr; - - dr=__buffer; - printk("ACM_USB_IRQ\n"); - printk("reqtype: %02X\n",dr->requesttype); - printk("request: %02X\n",dr->request); - printk("wValue: %02X\n",dr->value); - printk("wIndex: %02X\n",dr->index); - printk("wLength: %02X\n",dr->length); - - switch(dr->request) { - //Network connection - case 0x00: - printk("Network connection: "); - if (dr->request==0) printk("disconnected\n"); - if (dr->request==1) printk("connected\n"); - break; - - //Response available - case 0x01: - printk("Response available\n"); - acm->buffer=1; - break; - - //Set serial line state - case 0x20: - if ((dr->index==1)&&(dr->length==2)) { - acm->serstate=acm->ctrlbuffer; - printk("Serstate: %02X\n",acm->ctrlbuffer); - } - break; - } -/* - if(!acm->active) - return 1; -*/ - return 1; -} - -static int release_acm(struct inode * inode, struct file * file) -{ - struct acm_state *acm = &static_acm_state; - printk("ACM_FILE_RELEASE\n"); - -// fasync_acm(-1, file, 0); - if (--acm->active) - return 0; - return 0; -} - -static int open_acm(struct inode * inode, struct file * file) -{ - struct acm_state *acm = &static_acm_state; - printk("USB_FILE_OPEN\n"); - - if (!acm->present) - return -EINVAL; - if (acm->active++) - return 0; - return 0; -} - -static ssize_t write_acm(struct file * file, - const char * buffer, size_t count, loff_t *ppos) -{ - devrequest dr; - struct acm_state *acm = &static_acm_state; - unsigned long retval; - - printk("USB_FILE_WRITE\n"); -//Huh, i seem to got that wrong, we don't need this ?!? -/* - dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT; - dr.request = 0; - dr.value = 0; - dr.index = acm->writeendp; - dr.length = count; - acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0); -*/ - - acm->dev->bus->op->bulk_msg(acm->dev,&acm->writepipe,buffer, count, &retval); - return -EINVAL; -} - - -static ssize_t read_acm(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - devrequest dr; - struct acm_state *acm = &static_acm_state; - unsigned long retval; - printk("USB_FILE_READ\n"); -// if (!acm->buffer) return -1; - acm->buffer=0; -//We don't need this -/* - printk("writing control msg\n"); - dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT | 0x80; - dr.request = 1; - dr.value = 0; - dr.index = acm->readendp; - dr.length = 0; - acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0); -*/ - printk("reading:>%s<\n",buffer); - acm->dev->bus->op->bulk_msg(acm->dev,&acm->readpipe,buffer, 1,&retval); - printk("done:>%s<\n",buffer); - return 1; -} - -struct file_operations usb_acm_fops = { - NULL, /* acm_seek */ - read_acm, - write_acm, - NULL, /* acm_readdir */ - NULL, /* acm_poll */ - NULL, /* acm_ioctl */ - NULL, /* acm_mmap */ - open_acm, - NULL, /* flush */ - release_acm, - NULL, - NULL, /*fasync*/ -}; - -static struct miscdevice usb_acm = { - USB_ACM_MINOR, "USB ACM", &usb_acm_fops -}; - -static int acm_probe(struct usb_device *dev) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct acm_state *acm = &static_acm_state; - int cfgnum; - - /* Only use CDC */ - if (dev->descriptor.bDeviceClass != 2 || - dev->descriptor.bDeviceSubClass != 0 || - dev->descriptor.bDeviceProtocol != 0) - return -1; - - /*Now scan all configs for a ACM configuration*/ - for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { - /* The first one should be Communications interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[0]; - if (interface->bInterfaceClass != 2 || - interface->bInterfaceSubClass != 2 || - interface->bInterfaceProtocol != 1 || - interface->bNumEndpoints != 1) - continue; - - /*Which uses an interrupt input */ - endpoint = &interface->endpoint[0]; - if ((endpoint->bEndpointAddress & 0x80) != 0x80 || - (endpoint->bmAttributes & 3) != 3) - continue; - - /* The second one should be a Data interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[1]; - if (interface->bInterfaceClass != 10 || - interface->bInterfaceSubClass != 0 || - interface->bInterfaceProtocol != 0 || - interface->bNumEndpoints != 2) - continue; - - /*With a bulk input */ - endpoint = &interface->endpoint[0]; - if ((endpoint->bEndpointAddress & 0x80) != 0x80 || - (endpoint->bmAttributes & 3) != 2) - continue; - - /*And a bulk output */ - endpoint = &interface->endpoint[1]; - if ((endpoint->bEndpointAddress & 0x80) == 0x80 || - (endpoint->bmAttributes & 3) != 2) - continue; - - printk("USB ACM found\n"); - if (usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: ACM\n"); - continue; - } - acm->dev=dev; - acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress; - acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress; - acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress; - acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp); - acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp); - usb_request_irq(dev,acm->ctrlpipe=usb_rcvctrlpipe(dev,acm->ctrlendp), acm_irq, dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval, &acm->ctrlbuffer); - acm->present = 1; - acm->buffer=0; - return 0; - } - - return -1; -} - -static void acm_disconnect(struct usb_device *dev) -{ - struct acm_state *acm = &static_acm_state; - - /* this might need work */ - acm->present = 0; -} - -static struct usb_driver acm_driver = { - "acm", - acm_probe, - acm_disconnect, - { NULL, NULL } -}; - -int usb_acm_init(void) -{ - struct acm_state *acm = &static_acm_state; - - misc_register(&usb_acm); - - acm->present = acm->active = 0; - - usb_register(&acm_driver); - printk(KERN_INFO "USB ACM registered.\n"); - return 0; -} - -#ifdef MODULE - -int init_module(void) -{ - return usb_acm_init(); -} - -void cleanup_module(void) -{ - /* this, too, probably needs work */ - usb_deregister(&acm_driver); - misc_deregister(&usb_acm); -} - -#endif diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c index fc503f3cb7ec..8b0c9d15c748 100644 --- a/drivers/usb/audio.c +++ b/drivers/usb/audio.c @@ -3,8 +3,6 @@ #include #include #include -#include - #include "usb.h" static int usb_audio_probe(struct usb_device *dev); @@ -26,7 +24,7 @@ static struct usb_driver usb_audio_driver = }; -static int usb_audio_irq(int state, void *buffer, int len, void *dev_id) +static int usb_audio_irq(int state, void *buffer, void *dev_id) { struct usb_audio *aud = (struct usb_audio*) dev_id; return 1; @@ -41,7 +39,7 @@ static int usb_audio_probe(struct usb_device *dev) int i; int na=0; - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0]; for(i=0;iconfig[0].bNumInterfaces;i++) { @@ -81,10 +79,7 @@ static int usb_audio_probe(struct usb_device *dev) endpoint = &interface->endpoint[0]; -// if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { -// printk (KERN_INFO " Failed usb_set_configuration: Audio\n"); -// break; -// } +// usb_set_configuration(dev, dev->config[0].bConfigurationValue); // usb_set_protocol(dev, 0); // usb_set_idle(dev, 0, 0); @@ -95,13 +90,8 @@ static int usb_audio_probe(struct usb_device *dev) aud); list_add(&aud->list, &usb_audio_list); - - return 0; } - - if (aud) - kfree (aud); - return -1; + return 0; } static void usb_audio_disconnect(struct usb_device *dev) @@ -134,15 +124,3 @@ void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) { } -#ifdef MODULE -int init_module(void) -{ - return usb_audio_init(); -} - -void cleanup_module(void) -{ - usb_deregister(&usb_audio_driver); -} - -#endif diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c deleted file mode 100644 index abfd1b11be7a..000000000000 --- a/drivers/usb/cpia.c +++ /dev/null @@ -1,1277 +0,0 @@ -/* - * USB CPiA Video Camera driver - * - * Supports CPiA based Video Camera's. Many manufacturers use this chipset. - * There's a good chance, if you have a USB video camera, it's a CPiA based - * one - * - * (C) Copyright 1999 Johannes Erdfelt - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "usb.h" -#include "cpia.h" - -#define MAX_FRAME_SIZE (384 * 288 * 3) - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -/* convert virtual user memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ - -static inline unsigned long uvirt_to_phys(unsigned long adr) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *ptep, pte; - - pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) - return 0; - pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) - return 0; - ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); - pte = *ptep; - if(pte_present(pte)) - return - virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); - return 0; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); -} - -/* convert virtual kernel memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ - -static inline unsigned long kvirt_to_phys(unsigned long adr) -{ - return uvirt_to_phys(VMALLOC_VMADDR(adr)); -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - return uvirt_to_bus(VMALLOC_VMADDR(adr)); -} - - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr, page; - - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - mem=vmalloc(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_phys(adr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); - adr+=PAGE_SIZE; - if (size > PAGE_SIZE) - size-=PAGE_SIZE; - else - size=0; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr, page; - - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - if (mem) - { - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_phys(adr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); - adr+=PAGE_SIZE; - if (size > PAGE_SIZE) - size-=PAGE_SIZE; - else - size=0; - } - vfree(mem); - } -} - -int usb_cpia_get_version(struct usb_device *dev, void *buf) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; - dr.request = USB_REQ_CPIA_GET_VERSION; - dr.value = 0; - dr.index = 0; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4); -} - -int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; - dr.request = USB_REQ_CPIA_GET_PNP_ID; - dr.value = 0; - dr.index = 0; - dr.length = 6; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6); -} - -int usb_cpia_get_camera_status(struct usb_device *dev, void *buf) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; - dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS; - dr.value = 0; - dr.index = 0; - dr.length = 8; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8); -} - -int usb_cpia_goto_hi_power(struct usb_device *dev) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_GOTO_HI_POWER; - dr.value = 0; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_get_vp_version(struct usb_device *dev, void *buf) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_GET_VP_VERSION; - dr.value = 0; - dr.index = 0; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4); -} - -int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_SET_SENSOR_FPS; - dr.value = (sensorclkdivisor << 8) + sensorbaserate; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_GRAB_FRAME; - dr.value = streamstartline << 8; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_upload_frame(struct usb_device *dev, int forceupload) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_UPLOAD_FRAME; - dr.value = forceupload; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_SET_GRAB_MODE; - dr.value = continuousgrab; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_SET_FORMAT; - dr.value = (subsample << 8) + size; - dr.index = order; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_SET_COMPRESSION; - dr.value = (decimation << 8) + compmode; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_INIT_STREAM_CAP; - dr.value = (streamstartline << 8) + skipframes; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_finistreamcap(struct usb_device *dev) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_FINI_STREAM_CAP; - dr.value = 0; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_startstreamcap(struct usb_device *dev) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_START_STREAM_CAP; - dr.value = 0; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_cpia_endstreamcap(struct usb_device *dev) -{ - devrequest dr; - - dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE); - dr.request = USB_REQ_CPIA_END_STREAM_CAP; - dr.value = 0; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch)) - -static void cpia_parse_data(struct usb_cpia *cpia) -{ - unsigned char *data = cpia->scratch; - int done; - - done = 0; - while (!done && scratch_left(data)) { - switch (cpia->state) { - case STATE_SCANNING: - { - unsigned char *begin = data; - - /* We need atleast 2 bytes for the magic value */ - if (scratch_left(data) < 2) { - done = 1; - break; - } - - printk("header: %X\n", (*data << 8) + *(data + 1)); - if ((*data == 0x19) && (*(data + 1) == 0x68)) { - cpia->state = STATE_HEADER; - printk("moving to header\n"); - break; - } - - if (scratch_left(data) < 4) { - done = 1; - break; - } - - printk("Scanning for end of frame\n"); - while (scratch_left(data) >= 4) { - if ((*data == 0xFF) && - (*(data + 1) == 0xFF) && - (*(data + 2) == 0xFF) && - (*(data + 3) == 0xFF)) { - data += 4; - break; - } - data++; - } -printk("scan: scanned %d bytes\n", data-begin); - break; - } - case STATE_HEADER: - /* We need atleast 64 bytes for the header */ - if (scratch_left(data) < 64) { - done = 1; - break; - } - -printk("header: framerate %d\n", data[41]); - - data += 64; - - cpia->state = STATE_LINES; - - break; - case STATE_LINES: - { - unsigned char *begin = data; - int found = 0; - - while (scratch_left(data)) { - if (*data == 0xFD) { - data++; - found = 1; - break; - } else if ((*data == 0xFF) && - (scratch_left(data) >= 3) && - (*(data + 1) == 0xFF) && - (*(data + 2) == 0xFF) && - (*(data + 3) == 0xFF)) { - data+=4; - cpia->curline = 144; - found = 1; - break; - } - - data++; - } -#if 0 -printk("line %d: scanned %d bytes\n", cpia->curline, data-begin); -#endif -if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) { - int i; - char *f = cpia->frame[cpia->curframe].data, *b = begin; - -#if 0 -printk("copying\n"); -#endif - - b+=2; - f+=(cpia->frame[cpia->curframe].width*3)*cpia->curline; - for (i = 0; i < 176; i++) - f[(i * 3) + 0] = - f[(i * 3) + 1] = - f[(i * 3) + 2] = - b[(i * 2)]; -} - if (found) { - cpia->curline++; - if (cpia->curline >= 144) { - wake_up(&cpia->wq); - cpia->state = STATE_SCANNING; - cpia->curline = 0; - cpia->curframe = -1; - done = 1; - } - } else { - data = begin; - done = 1; - } - - break; - } - } - } - - { - int l; - - l = scratch_left(data); - memmove(cpia->scratch, data, l); - cpia->scratchlen = l; - } -} - -static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) -{ - struct usb_cpia *cpia = dev_id; - struct usb_device *dev = cpia->dev; - struct cpia_sbuf *sbuf; - int i; - char *p; - - if (!cpia->streaming) { - printk("oops, not streaming, but interrupt\n"); - return 0; - } - - if (cpia->curframe < 0) { - if (cpia->frame[0].state == FRAME_READY) { - cpia->curframe = 0; - cpia->frame[0].state = FRAME_GRABBING; -printk("capturing to frame 0\n"); - } else if (cpia->frame[1].state == FRAME_READY) { - cpia->curframe = 1; - cpia->frame[1].state = FRAME_GRABBING; -printk("capturing to frame 1\n"); - } else -printk("no frame available\n"); - } - - sbuf = &cpia->sbuf[cpia->receivesbuf]; - - usb_unschedule_isochronous(dev, sbuf->isodesc); - - /* Do something to it now */ - sbuf->len = usb_compress_isochronous(dev, sbuf->isodesc); - - if (sbuf->len) - printk("%d bytes received\n", sbuf->len); - - if (sbuf->len && cpia->curframe >= 0) { - if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) { - printk("overflow!\n"); - return 0; - } - memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len); - cpia->scratchlen += sbuf->len; - - cpia_parse_data(cpia); - } - - /* Reschedule this block of Isochronous desc */ - usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc); - - /* Move to the next one */ - cpia->receivesbuf = (cpia->receivesbuf + 1) % 3; - - return 1; -} - -int cpia_init_isoc(struct usb_cpia *cpia) -{ - struct usb_device *dev = cpia->dev; - - cpia->receivesbuf = 0; - -#if 0 - cpia->parsesbuf = 0; - cpia->parsepos = 0; -#endif - cpia->scratchlen = 0; - cpia->curline = 0; - cpia->state = STATE_SCANNING; - - /* Allocate all of the memory necessary */ - cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); - cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); - cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); - - printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc); - printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc); - printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc); - - /* Schedule the queues */ - usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL); - usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); - usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc); - - if (usb_set_interface(cpia->dev, 1, 3)) { - printk("cpia_set_interface error\n"); - return -EINVAL; - } - - usb_cpia_startstreamcap(cpia->dev); - - cpia->streaming = 1; - - return 0; -} - -void cpia_stop_isoc(struct usb_cpia *cpia) -{ - struct usb_device *dev = cpia->dev; - - if (!cpia->streaming) - return; - - cpia->streaming = 0; - - /* Stop the streaming */ - usb_cpia_endstreamcap(cpia->dev); - - /* Set packet size to 0 */ - if (usb_set_interface(cpia->dev, 1, 0)) { - printk("cpia_set_interface error\n"); - return /* -EINVAL */; - } - - /* Unschedule all of the iso td's */ - usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc); - usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc); - usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc); - - /* Delete them all */ - usb_delete_isochronous(dev, cpia->sbuf[2].isodesc); - usb_delete_isochronous(dev, cpia->sbuf[1].isodesc); - usb_delete_isochronous(dev, cpia->sbuf[0].isodesc); -} - -/* Video 4 Linux API */ -static int cpia_open(struct video_device *dev, int flags) -{ - struct usb_cpia *cpia = (struct usb_cpia *)dev; - -printk("cpia_open\n"); - - cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); - if (!cpia->fbuf) - goto open_err_ret; - - cpia->frame[0].state = FRAME_DONE; - cpia->frame[1].state = FRAME_DONE; - - cpia->frame[0].data = cpia->fbuf; - cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE; - printk("frame [0] @ %p\n", cpia->frame[0].data); - printk("frame [1] @ %p\n", cpia->frame[1].data); - - cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); - if (!cpia->sbuf[0].data) - goto open_err_on0; - - cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); - if (!cpia->sbuf[1].data) - goto open_err_on1; - - cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); - if (!cpia->sbuf[2].data) - goto open_err_on2; - - printk("sbuf[0] @ %p\n", cpia->sbuf[0].data); - printk("sbuf[1] @ %p\n", cpia->sbuf[1].data); - printk("sbuf[2] @ %p\n", cpia->sbuf[2].data); - - cpia->curframe = -1; - cpia->receivesbuf = 0; - - usb_cpia_initstreamcap(cpia->dev, 0, 60); - - cpia_init_isoc(cpia); - - return 0; - -open_err_on2: - kfree (cpia->sbuf[1].data); -open_err_on1: - kfree (cpia->sbuf[0].data); -open_err_on0: - rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); -open_err_ret: - return -ENOMEM; -} - -static void cpia_close(struct video_device *dev) -{ - struct usb_cpia *cpia = (struct usb_cpia *)dev; - -printk("cpia_close\n"); - - cpia_stop_isoc(cpia); - - usb_cpia_finistreamcap(cpia->dev); - - rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); - - kfree(cpia->sbuf[2].data); - kfree(cpia->sbuf[1].data); - kfree(cpia->sbuf[0].data); -} - -static int cpia_init_done(struct video_device *dev) -{ - return 0; -} - -static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) -{ - return -EINVAL; -} - -#if 0 - if (usb_set_interface(dev, 1, 3)) { - printk("cpia_set_interface error\n"); - return -EINVAL; - } - - if (usb_cpia_grab_frame(dev, 0)) { - printk("cpia_grab_frame error\n"); - return -EINVAL; - } - - if (usb_cpia_upload_frame(dev, 0)) { - printk("cpia_upload_frame error\n"); - return -EINVAL; - } - - buf = cpia->ibuf; - uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 176*144*4); - - { - printk("header magic: %X\n", (buf[0] << 8) + buf[1]); - - while ((buf[0] != 0x19) || (buf[1] != 0x68)) { - int i; - - printk("resync'ing\n"); - for (i=0;i<(176*144*4)-4;i++, buf++) - if ( - (buf[0] == 0xFF) && - (buf[1] == 0xFF) && - (buf[2] == 0xFF) && - (buf[3] == 0xFF)) { - buf+=4; - i+=4; - break; - } - - memmove(cpia->ibuf, buf, (176*144*4) - i); - uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->ibuf + (176*144*4) - i, i); - buf = cpia->ibuf; - -#if 0 - printk("header magic: %X\n", (buf[0] << 8) + buf[1]); -#endif - } - - printk("size: %d, sample: %d, order: %d\n", buf[16], buf[17], buf[18]); - printk("comp: %d, decimation: %d\n", buf[28], buf[29]); - printk("roi: top left: %d, %d bottom right: %d, %d\n", - buf[26] * 4, buf[24] * 8, - buf[27] * 4, buf[25] * 8); - - printk("vm->frame: %d\n", vm->frame); - - { - int i, i1; - char *b = buf + 64, *fbuf = &cpia->fbuffer[MAX_FRAME_SIZE * (vm->frame & 1)]; - for (i=0;i<144;i++) { -#if 0 - printk("line len: %d\n", (b[1] << 8) + b[0]); -#endif - b += 2; - for (i1=0;i1<176;i1++) { - fbuf[(i * vm->width * 3) + (i1 * 3)] = - fbuf[(i * vm->width * 3) + (i1 * 3) + 1] = - fbuf[(i * vm->width * 3) + (i1 * 3) + 2] = - b[i1 * 2]; -#if 0 - *((short *)&fbuf[(i * vm->width * 2) + (i1 * 2)]) = - ((b[i1 * 2] >> 3) << 11) + ((b[i1 * 2] >> 2) << 6) + (b[i1 * 2] >> 3); -#endif - } - b += (176 * 2) + 1; - } - } - - } - - if (usb_set_interface(dev, 1, 0)) { - printk("cpia_set_interface error\n"); - return -EINVAL; - } -#endif - -static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct usb_cpia *cpia = (struct usb_cpia *)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - - strcpy(b.name, "CPiA USB Camera"); - b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */; - b.channels = 1; - b.audios = 0; - b.maxwidth = 176 /* 352 */; - b.maxheight = 144 /* 240 */; - b.minwidth = 176 /* (Something small?) */; - b.minheight = 144 /* " " */; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.channel != 0) - return -EINVAL; - - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - strcpy(v.name, "Camera"); - - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSCHAN: - { - int v; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v != 0) - return -EINVAL; - - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v.tuner) - return -EINVAL; - - strcpy(v.name, "Format"); - - v.rangelow = 0; - v.rangehigh = 0; - v.flags = 0; - v.mode = VIDEO_MODE_AUTO; - - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v.tuner) - return -EINVAL; - - if (v.mode != VIDEO_MODE_AUTO) - return -EINVAL; - - return 0; - } - case VIDIOCGPICT: - { - struct video_picture p; - - p.colour = 0x8000; /* Damn British people :) */ - p.hue = 0x8000; - p.brightness = 180 << 8; /* XXX */ - p.contrast = 192 << 8; /* XXX */ - p.whiteness = 105 << 8; /* XXX */ -#if 0 - p.depth = 24; -#endif - p.depth = 16; - p.palette = VIDEO_PALETTE_YUYV; - - if (copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - - return 0; - } - case VIDIOCSPICT: - { - struct video_picture p; - - if (copy_from_user(&p, arg, sizeof(p))) - return -EFAULT; - -printk("Attempting to set palette %d, depth %d\n", p.palette, p.depth); - -#if 0 - if (p.palette != VIDEO_PALETTE_YUYV) - return -EINVAL; - if (p.depth != 16) - return -EINVAL; -#endif - - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - -printk("VIDIOCSWIN\n"); - if (copy_from_user(&vw, arg, sizeof(vw))) - return -EFAULT; - if (vw.flags) - return -EINVAL; - if (vw.clipcount) - return -EINVAL; - if (vw.height != 176) - return -EINVAL; - if (vw.width != 144) - return -EINVAL; - - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - -printk("VIDIOCGWIN\n"); - vw.x = 0; - vw.y = 0; - vw.width = 176; - vw.height = 144; - vw.chromakey = 0; - vw.flags = 0; - - if (copy_to_user(arg, &vw, sizeof(vw))) - return -EFAULT; - - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf vm; - - memset(&vm, 0, sizeof(vm)); - vm.size = MAX_FRAME_SIZE * 2; - vm.frames = 2; - vm.offsets[0] = 0; - vm.offsets[1] = MAX_FRAME_SIZE; - - if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) - return -EFAULT; - -printk("MCAPTURE\n"); -printk("frame: %d, size: %dx%d, format: %d\n", vm.frame, vm.width, vm.height, vm.format); - - if (vm.format != VIDEO_PALETTE_RGB24) - return -EINVAL; - - if ((vm.frame != 0) && (vm.frame != 1)) - return -EINVAL; - - cpia->frame[vm.frame].width = vm.width; - cpia->frame[vm.frame].height = vm.height; - - /* Mark it as free */ - cpia->frame[vm.frame].state = FRAME_READY; - - return 0; - } - case VIDIOCSYNC: - { - int frame; - - if (copy_from_user((void *)&frame, arg, sizeof(int))) - return -EFAULT; - - printk("syncing to frame %d\n", frame); - switch (cpia->frame[frame].state) { - case FRAME_UNUSED: - return -EINVAL; - case FRAME_READY: - case FRAME_GRABBING: - interruptible_sleep_on(&cpia->wq); - case FRAME_DONE: - cpia->frame[frame].state = FRAME_UNUSED; - break; - } - printk("synced to frame %d\n", frame); - return 0; - } - case VIDIOCCAPTURE: - return -EINVAL; - case VIDIOCGFBUF: - return -EINVAL; - case VIDIOCSFBUF: - return -EINVAL; - case VIDIOCKEY: - return 0; - case VIDIOCGFREQ: - return -EINVAL; - case VIDIOCSFREQ: - return -EINVAL; - case VIDIOCGAUDIO: - return -EINVAL; - case VIDIOCSAUDIO: - return -EINVAL; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock) -{ - struct usb_cpia *cpia = (struct usb_cpia *)dev; - int len; - - printk("cpia_read: %ld bytes\n", count); -#if 0 - len = cpia_capture(cpia, buf, count); - - return len; -#endif - return 0; -} - -static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct usb_cpia *cpia = (struct usb_cpia *)dev; - unsigned long start = (unsigned long)adr; - unsigned long page, pos; - - printk("mmap: %ld (%lX) bytes\n", size, size); - if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) - return -EINVAL; - -#if 0 - if (!cpia->fbuffer) { - if ((cpia->fbuffer = rvmalloc(2 * MAX_FRAME_SIZE)) == NULL) - return -EINVAL; - } -#endif - - pos = (unsigned long)cpia->fbuf; - while (size > 0) - { - page = kvirt_to_phys(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - if (size > PAGE_SIZE) - size-=PAGE_SIZE; - else - size=0; - } - - return 0; -} - -static struct video_device cpia_template = { - "CPiA USB Camera", - VID_TYPE_CAPTURE, - VID_HARDWARE_CPIA, - cpia_open, - cpia_close, - cpia_read, - cpia_write, - NULL, - cpia_ioctl, - cpia_mmap, - cpia_init_done, - NULL, - 0, - 0 -}; - -static void usb_cpia_configure(struct usb_cpia *cpia) -{ - struct usb_device *dev = cpia->dev; - unsigned char version[4]; - unsigned char pnpid[6]; - unsigned char camerastat[8]; - unsigned char *buf; - - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: CPIA\n"); - return; - } - - if (usb_cpia_get_version(dev, version)) { - printk("cpia_get_version error\n"); - return; - } - - printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n", - version[0], version[1], version[2], version[3]); - - if (usb_cpia_get_pnp_id(dev, pnpid)) { - printk("cpia_get_pnp_id error\n"); - return; - } - - printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n", - (pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2], - (pnpid[5] << 8) + pnpid[4]); - - memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template)); - - init_waitqueue_head(&cpia->wq); - - if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) { - printk("video_register_device failed\n"); - return; - } - - if (usb_cpia_goto_hi_power(dev)) { - printk("cpia_goto_hi_power error\n"); - return; - } - - if (usb_cpia_get_vp_version(dev, version)) { - printk("cpia_get_vp_version error\n"); - return; - } - - printk("cpia: VP v%d rev %d\n", version[0], version[1]); - printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]); - - /* Turn off continuous grab */ - if (usb_cpia_set_grab_mode(dev, 1)) { - printk("cpia_set_grab_mode error\n"); - return; - } - - /* Set up the sensor to be 30fps */ - if (usb_cpia_set_sensor_fps(dev, 1, 0)) { - printk("cpia_set_sensor_fps error\n"); - return; - } - - /* Set video into QCIF mode, and order into YUYV mode */ - if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) { - printk("cpia_set_format error\n"); - return; - } - - /* Turn off compression */ - if (usb_cpia_set_compression(dev, 0, 0)) { - printk("cpia_set_compression error\n"); - return; - } - -#if 0 - if (usb_cpia_grab_frame(dev, 0)) { - printk("cpia_grab_frame error\n"); - return; - } - - if (usb_cpia_upload_frame(dev, 1)) { - printk("cpia_upload_frame error\n"); - return; - } - - buf = (void *)__get_free_page(GFP_KERNEL); - - { - int i; - for (i=0;i<448;i++) - buf[i]=0; - } - uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 448); - - { - int i; - for (i=0;i<448;i++) { - printk("%02X ", buf[i]); - if ((i % 16) == 15) - printk("\n"); - } - printk("\n"); - } - - free_page((unsigned long)buf); -#endif -} - -static int cpia_probe(struct usb_device *dev) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_cpia *cpia; - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -1; - -#if 0 - /* We don't handle multi-interface hubs */ - if (dev->config[0].bNumInterfaces != 1) - return -1; -#endif - - interface = &dev->config[0].altsetting[0].interface[0]; - - /* Is it a CPiA? */ -/* -Apr 24 17:49:04 bjorn kernel: Vendor: 0545 -Apr 24 17:49:04 bjorn kernel: Product: 8080 -*/ -/* - if (dev->descriptor.idVendor != 0x0545) - return -1; - if (dev->descriptor.idProduct != 0x8080) - return -1; - if (interface->bInterfaceClass != 0xFF) - return -1; - if (interface->bInterfaceSubClass != 0xFF) - return -1; -*/ - if (dev->descriptor.idVendor != 0x0553) - return -1; - if (dev->descriptor.idProduct != 0x0002) - return -1; - if (interface->bInterfaceClass != 0xFF) - return -1; - if (interface->bInterfaceSubClass != 0x00) - return -1; - -#if 0 - /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (interface->bNumEndpoints != 1) - return -1; - - endpoint = &interface->endpoint[0]; - - /* Output endpoint? Curiousier and curiousier.. */ - if (!(endpoint->bEndpointAddress & 0x80)) - return -1; - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & 3) != 3) - return -1; -#endif - - /* We found a CPiA */ - printk("USB CPiA camera found\n"); - - if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) { - printk("couldn't kmalloc cpia struct\n"); - return -1; - } - - memset(cpia, 0, sizeof(*cpia)); - - dev->private = cpia; - cpia->dev = dev; - - usb_cpia_configure(cpia); - -#if 0 - usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), pport_irq, endpoint->bInterval, pport); -#endif - - return 0; -} - -static void cpia_disconnect(struct usb_device *dev) -{ - struct usb_cpia *cpia = dev->private; - - video_unregister_device(&cpia->vdev); - - /* Free the memory */ - kfree(cpia); -} - -static struct usb_driver cpia_driver = { - "cpia", - cpia_probe, - cpia_disconnect, - { NULL, NULL } -}; - -/* - * This should be a separate module. - */ -int usb_cpia_init(void) -{ - usb_register(&cpia_driver); - - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - return usb_cpia_init(); -} -void cleanup_module(void) -{ -} -#endif - diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h deleted file mode 100644 index 51ff43e79404..000000000000 --- a/drivers/usb/cpia.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef __LINUX_CPIA_H -#define __LINUX_CPIA_H - -#include - -#define USB_REQ_CPIA_GET_VERSION 0x01 -#define USB_REQ_CPIA_GET_PNP_ID 0x02 -#define USB_REQ_CPIA_GET_CAMERA_STATUS 0x03 -#define USB_REQ_CPIA_GOTO_HI_POWER 0x04 -#define USB_REQ_CPIA_GOTO_LO_POWER 0x05 -/* No 0x06 */ -#define USB_REQ_CPIA_GOTO_SUSPEND 0x07 -#define USB_REQ_CPIA_GOTO_PASS_THROUGH 0x08 -/* No 0x09 */ -#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS 0x0A - -#define USB_REQ_CPIA_READ_VC_REGS 0x21 -#define USB_REQ_CPIA_WRITE_BC_REG 0x22 -#define USB_REQ_CPIA_READ_MC_PORTS 0x23 -#define USB_REQ_CPIA_WRITE_MC_PORT 0x24 -#define USB_REQ_CPIA_SET_BAUD_RATE 0x25 -#define USB_REQ_CPIA_SET_ECP_TIMING 0x26 -#define USB_REQ_CPIA_READ_IDATA 0x27 -#define USB_REQ_CPIA_WRITE_IDATA 0x28 -#define USB_REQ_CPIA_GENERIC_CALL 0x29 -#define USB_REQ_CPIA_I2CSTART 0x2A -#define USB_REQ_CPIA_I2CSTOP 0x2B -#define USB_REQ_CPIA_I2CWRITE 0x2C -#define USB_REQ_CPIA_I2CREAD 0x2D - -#define USB_REQ_CPIA_GET_VP_VERSION 0xA1 -#define USB_REQ_CPIA_SET_COLOUR_PARAMS 0xA3 -#define USB_REQ_CPIA_SET_EXPOSURE 0xA4 -/* No 0xA5 */ -#define USB_REQ_CPIA_SET_COLOUR_BALANCE 0xA6 -#define USB_REQ_CPIA_SET_SENSOR_FPS 0xA7 -#define USB_REQ_CPIA_SET_VP_DEFAULTS 0xA8 -#define USB_REQ_CPIA_SET_APCOR 0xA9 -#define USB_REQ_CPIA_SET_FLICKER_CTRL 0xAA -#define USB_REQ_CPIA_SET_VL_OFFSET 0xAB - -#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS 0xB0 -#define USB_REQ_CPIA_GET_COLOUR_BALANCE 0xB1 -#define USB_REQ_CPIA_GET_EXPOSURE 0xB2 -#define USB_REQ_CPIA_SET_SENSOR_MATRIX 0xB3 - -#define USB_REQ_CPIA_COLOUR_BARS 0xBD -#define USB_REQ_CPIA_READ_VP_REGS 0xBE -#define USB_REQ_CPIA_WRITE_VP_REGS 0xBF - -#define USB_REQ_CPIA_GRAB_FRAME 0xC1 -#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2 -#define USB_REQ_CPIA_SET_GRAB_MODE 0xC3 -#define USB_REQ_CPIA_INIT_STREAM_CAP 0xC4 -#define USB_REQ_CPIA_FINI_STREAM_CAP 0xC5 -#define USB_REQ_CPIA_START_STREAM_CAP 0xC6 -#define USB_REQ_CPIA_END_STREAM_CAP 0xC7 -#define USB_REQ_CPIA_SET_FORMAT 0xC8 -#define USB_REQ_CPIA_SET_ROI 0xC9 -#define USB_REQ_CPIA_SET_COMPRESSION 0xCA -#define USB_REQ_CPIA_SET_COMPRESSION_TARGET 0xCB -#define USB_REQ_CPIA_SET_YUV_THRESH 0xCC -#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS 0xCD -#define USB_REQ_CPIA_DISCARD_FRAME 0xCE - -#define USB_REQ_CPIA_OUTPUT_RS232 0xE1 -#define USB_REQ_CPIA_ABORT_PROCESS 0xE4 -#define USB_REQ_CPIA_SET_DRAM_PAGE 0xE5 -#define USB_REQ_CPIA_START_DRAM_UPLOAD 0xE6 -#define USB_REQ_CPIA_START_DUMMY_STREAM 0xE8 -#define USB_REQ_CPIA_ABORT_STREAM 0xE9 -#define USB_REQ_CPIA_DOWNLOAD_DRAM 0xEA -/* #define USB_REQ_CPIA_NULL_CMD 0x?? */ - -#define CPIA_QCIF 0 -#define CPIA_CIF 1 - -#define CPIA_YUYV 0 -#define CPIA_UYVY 1 - -#define STREAM_BUF_SIZE (PAGE_SIZE * 4) - -#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) - -enum { - STATE_SCANNING, /* Scanning for start */ - STATE_HEADER, /* Parsing header */ - STATE_LINES, /* Parsing lines */ -}; - -struct usb_device; - -struct cpia_sbuf { - char *data; - int len; - void *isodesc; -}; - -enum { - FRAME_READY, /* Ready to grab into */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_UNUSED, /* Unused (no MCAPTURE) */ -}; - -struct cpia_frame { - char *data; - int width; - int height; - int state; -}; - -struct usb_cpia { - struct video_device vdev; - - /* Device structure */ - struct usb_device *dev; - - int streaming; - - char *fbuf; /* Videodev buffer area */ - - int curframe; - struct cpia_frame frame[2]; /* Double buffering */ - - int receivesbuf; /* Current receiving sbuf */ - struct cpia_sbuf sbuf[3]; /* Triple buffering */ - - int state; /* Current scanning state */ - int curline; - - char scratch[SCRATCH_BUF_SIZE]; - int scratchlen; - - wait_queue_head_t wq; -}; - -#endif - diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c deleted file mode 100644 index 90e45b54e5b2..000000000000 --- a/drivers/usb/ezusb.c +++ /dev/null @@ -1,472 +0,0 @@ -/*****************************************************************************/ - -/* - * ezusb.c -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers. - * - * Copyright (C) 1999 - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * 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. - * - * History: - * 0.1 26.05.99 Created - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include - -#include "usb.h" -#include "ezusb.h" - -/* --------------------------------------------------------------------- */ - -#define NREZUSB 1 - -static struct ezusb { - struct semaphore mutex; - struct usb_device *usbdev; - unsigned int irqep; - unsigned int intlen; - unsigned char intdata[64]; -} ezusb[NREZUSB]; - -/* --------------------------------------------------------------------- */ - -static int ezusb_irq(int state, void *__buffer, int len, void *dev_id) -{ - struct ezusb *ez = (struct ezusb *)dev_id; - - if (len > sizeof(ez->intdata)) - len = sizeof(ez->intdata); - ez->intlen = len; - memcpy(ez->intdata, __buffer, len); - return 1; -} - -/* --------------------------------------------------------------------- */ - -static loff_t ezusb_llseek(struct file *file, loff_t offset, int origin) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - - switch(origin) { - case 1: - offset += file->f_pos; - break; - case 2: - offset += 0x10000; - break; - } - if (offset < 0 || offset >= 0x10000) - return -EINVAL; - return (file->f_pos = offset); -} - -static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - unsigned pos = *ppos; - unsigned ret = 0; - unsigned len; - unsigned char b[64]; - devrequest dr; - int i; - - if (*ppos < 0 || *ppos >= 0x10000) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - while (sz > 0 && pos < 0x10000) { - len = sz; - if (len > sizeof(b)) - len = sizeof(b); - if (pos + len > 0x10000) - len = 0x10000 - pos; - dr.requesttype = 0xc0; - dr.request = 0xa0; - dr.value = pos; - dr.index = 0; - dr.length = len; - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), &dr, b, len); - if (i) { - up(&ez->mutex); - printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", dr.value, dr.length, i); - *ppos = pos; - if (ret) - return ret; - return -ENXIO; - } - if (copy_to_user(buf, b, len)) { - up(&ez->mutex); - *ppos = pos; - if (ret) - return ret; - return -EFAULT; - } - pos += len; - buf += len; - sz -= len; - ret += len; - } - up(&ez->mutex); - *ppos = pos; - return ret; -} - -static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t *ppos) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - unsigned pos = *ppos; - unsigned ret = 0; - unsigned len; - unsigned char b[64]; - devrequest dr; - int i; - - if (*ppos < 0 || *ppos >= 0x10000) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - while (sz > 0 && pos < 0x10000) { - len = sz; - if (len > sizeof(b)) - len = sizeof(b); - if (pos + len > 0x10000) - len = 0x10000 - pos; - if (copy_from_user(b, buf, len)) { - up(&ez->mutex); - *ppos = pos; - if (ret) - return ret; - return -EFAULT; - } - dr.requesttype = 0x40; - dr.request = 0xa0; - dr.value = pos; - dr.index = 0; - dr.length = len; - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), &dr, b, len); - if (i) { - up(&ez->mutex); - printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", dr.value, dr.length, i); - *ppos = pos; - if (ret) - return ret; - return -ENXIO; - } - pos += len; - buf += len; - sz -= len; - ret += len; - } - up(&ez->mutex); - *ppos = pos; - return ret; -} - -static int ezusb_open(struct inode *inode, struct file *file) -{ - struct ezusb *ez = &ezusb[0]; - - down(&ez->mutex); - while (!ez->usbdev) { - up(&ez->mutex); - if (!(file->f_flags & O_NONBLOCK)) { - return -EIO; - } - schedule_timeout(HZ/2); - if (signal_pending(current)) - return -EAGAIN; - down(&ez->mutex); - } - up(&ez->mutex); - file->f_pos = 0; - file->private_data = ez; - return 0; -} - -static int ezusb_release(struct inode *inode, struct file *file) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - return 0; -} - -static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - struct ezusb_ctrltransfer ctrl; - struct ezusb_bulktransfer bulk; - unsigned int len1, ep; - unsigned long len2; - unsigned int irqep; - unsigned char tbuf[1024]; - int i; - - switch (cmd) { - case EZUSB_CONTROL: - copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); - if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024) - return -EINVAL; - if (ctrl.requesttype & 0x80) { - if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), - (devrequest *)&ctrl, tbuf, ctrl.dlen); - up(&ez->mutex); - if (!i && ctrl.dlen) { - copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT); - } - } else { - if (ctrl.dlen) { - copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT); - } - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), - (devrequest *)&ctrl, tbuf, ctrl.dlen); - up(&ez->mutex); - } - if (i) { - printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", - ctrl.requesttype, ctrl.request, ctrl.length, i); - return -ENXIO; - } - return 0; - - case EZUSB_INTERRUPT: - get_user_ret(irqep, (unsigned int *)arg, -EFAULT); - if (irqep != ez->irqep) { - if (ez->irqep) - return -EIO; - ez->irqep = irqep; - usb_request_irq(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, ez->irqep), - ezusb_irq, 2 /* interval */, ez); - ez->intlen = 0; - return -EAGAIN; - } - copy_to_user_ret((&((struct ezusb_interrupttransfer *)0)->data) + arg, - ez->intdata, 64, -EFAULT); - return ez->intlen; - - case EZUSB_BULK: - copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); - len1 = bulk.len; - if (len1 > sizeof(tbuf)) - len1 = sizeof(tbuf); - if (bulk.ep & 0x80) { - if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f), - tbuf, len1, &len2); - up(&ez->mutex); - if (!i && len2) { - copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); - } - } else { - if (len1) { - copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); - } - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f), - tbuf, len1, &len2); - up(&ez->mutex); - } - if (i) { - printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", - bulk.ep, bulk.len, i); - return -ENXIO; - } - return len2; - - case EZUSB_RESETEP: - get_user_ret(ep, (unsigned int *)arg, -EFAULT); - if ((ep & ~0x80) >= 16) - return -EINVAL; - usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0); - return 0; - } - return -ENOIOCTLCMD; -} - -static struct file_operations ezusb_fops = { - ezusb_llseek, - ezusb_read, - ezusb_write, - NULL, /* readdir */ - NULL, /* poll */ - ezusb_ioctl, - NULL, /* mmap */ - ezusb_open, - NULL, /* flush */ - ezusb_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ - NULL /* lock */ -}; - -static struct miscdevice ezusb_misc = { - 192, "ezusb", &ezusb_fops -}; - -/* --------------------------------------------------------------------- */ - -static int ezusb_probe(struct usb_device *usbdev) -{ - struct ezusb *ez = &ezusb[0]; - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - -#undef KERN_DEBUG -#define KERN_DEBUG "" - printk(KERN_DEBUG "ezusb: probe: vendor id 0x%x, device id 0x%x\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); - - /* the 1234:5678 is just a self assigned test ID */ - if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) && - (usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678)) - return -1; - - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return -1; - - /* We don't handle multiple interfaces */ - if (usbdev->config[0].bNumInterfaces != 1) - return -1; - - down(&ez->mutex); - if (ez->usbdev) { - up(&ez->mutex); - printk(KERN_INFO "ezusb: device already used\n"); - return -1; - } - ez->usbdev = usbdev; - usbdev->private = ez; - if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue)) { - printk(KERN_ERR "ezusb: set_configuration failed\n"); - goto err; - } - interface = &usbdev->config[0].altsetting[1].interface[0]; - if (usb_set_interface(usbdev, 0, 1)) { - printk(KERN_ERR "ezusb: set_interface failed\n"); - goto err; - } - up(&ez->mutex); - MOD_INC_USE_COUNT; - return 0; - - err: - up(&ez->mutex); - ez->usbdev = NULL; - usbdev->private = NULL; - return -1; -} - -static void ezusb_disconnect(struct usb_device *usbdev) -{ - struct ezusb *ez = (struct ezusb *)usbdev->private; - - down(&ez->mutex); - ez->usbdev = NULL; - up(&ez->mutex); - usbdev->private = NULL; - MOD_DEC_USE_COUNT; -} - -static struct usb_driver ezusb_driver = { - "ezusb", - ezusb_probe, - ezusb_disconnect, - { NULL, NULL } -}; - -/* --------------------------------------------------------------------- */ - -int ezusb_init(void) -{ - unsigned u; - - /* initialize struct */ - for (u = 0; u < NREZUSB; u++) { - ezusb[u].mutex = MUTEX; - ezusb[u].usbdev = NULL; - ezusb[u].irqep = 0; - } - /* register misc device */ - if (misc_register(&ezusb_misc)) { - printk(KERN_WARNING "ezusb: cannot register minor %d\n", ezusb_misc.minor); - return -1; - } - usb_register(&ezusb_driver); - printk(KERN_INFO "ezusb: Anchorchip firmware download driver registered\n"); - return 0; -} - -void ezusb_cleanup(void) -{ - usb_deregister(&ezusb_driver); - misc_deregister(&ezusb_misc); -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -int minor = 192; - -int init_module(void) -{ - ezusb_misc.minor = minor; - return ezusb_init(); -} - -void cleanup_module(void) -{ - ezusb_cleanup(); -} - -#endif - -/* --------------------------------------------------------------------- */ diff --git a/drivers/usb/ezusb.h b/drivers/usb/ezusb.h deleted file mode 100644 index 8ddaad1272b0..000000000000 --- a/drivers/usb/ezusb.h +++ /dev/null @@ -1,67 +0,0 @@ -/*****************************************************************************/ - -/* - * ezusb.h -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers. - * - * Copyright (C) 1999 - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * 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. - * - */ - -/*****************************************************************************/ - -#ifndef _LINUX_EZUSB_H -#define _LINUX_EZUSB_H - -#include - -/* --------------------------------------------------------------------- */ - -struct ezusb_ctrltransfer { - /* keep in sync with usb.h:devrequest */ - unsigned char requesttype; - unsigned char request; - unsigned short value; - unsigned short index; - unsigned short length; - /* pointer to data */ - unsigned dlen; - void *data; -}; - -#define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer) - -struct ezusb_interrupttransfer { - unsigned int ep; - unsigned char data[64]; -}; - -#define EZUSB_INTERRUPT _IOWR('E', 1, struct ezusb_interrupttransfer) - -struct ezusb_bulktransfer { - unsigned int ep; - unsigned int len; - void *data; -}; - -#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer) - -#define EZUSB_RESETEP _IOR('E', 3, unsigned int) - - -/* --------------------------------------------------------------------- */ -#endif /* _LINUX_EZUSB_H */ diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index a0874889fad3..16789b9445c0 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -1,9 +1,12 @@ /* * USB hub driver. * + * This is horrible, it knows about the UHCI driver + * internals, but it's just meant as a rough example, + * let's do the virtualization later when this works. + * * (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Gregory P. Smith */ #include @@ -11,24 +14,22 @@ #include #include #include -#include #include #include "usb.h" +#include "uhci.h" #include "hub.h" +extern struct usb_operations uhci_device_operations; + /* Wakes up khubd */ -static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait); +static struct wait_queue *usb_hub_wait = NULL; static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED; /* List of hubs needing servicing */ static struct list_head hub_event_list; -/* List containing all of the hubs (for cleanup) */ -static struct list_head all_hubs_list; - /* PID of khubd */ static int khubd_pid = 0; @@ -37,7 +38,7 @@ static int khubd_pid = 0; * the low-level driver that it wants to be re-activated, * or zero to say "I'm done". */ -static int hub_irq(int status, void *__buffer, int len, void *dev_id) +static int hub_irq(int status, void *__buffer, void *dev_id) { struct usb_hub *hub = dev_id; unsigned long flags; @@ -68,59 +69,59 @@ static void usb_hub_configure(struct usb_hub *hub) return; hub->nports = dev->maxchild = hubdescriptor[2]; - printk(KERN_DEBUG "hub: %d-port%s detected\n", hub->nports, + printk("hub: %d-port%s detected\n", hub->nports, (hub->nports == 1) ? "" : "s"); charac = (hubdescriptor[4] << 8) + hubdescriptor[3]; switch (charac & HUB_CHAR_LPSM) { case 0x00: - printk(KERN_DEBUG "hub: ganged power switching\n"); + printk("hub: ganged power switching\n"); break; case 0x01: - printk(KERN_DEBUG "hub: individual port power switching\n"); + printk("hub: individual port power switching\n"); break; case 0x02: case 0x03: - printk(KERN_DEBUG "hub: unknown reserved power switching mode\n"); + printk("hub: unknown reserved power switching mode\n"); break; } if (charac & HUB_CHAR_COMPOUND) - printk(KERN_DEBUG "hub: part of a compound device\n"); + printk("hub: part of a compound device\n"); else - printk(KERN_DEBUG "hub: standalone hub\n"); + printk("hub: standalone hub\n"); switch (charac & HUB_CHAR_OCPM) { case 0x00: - printk(KERN_DEBUG "hub: global over current protection\n"); + printk("hub: global over current protection\n"); break; case 0x08: - printk(KERN_DEBUG "hub: individual port over current protection\n"); + printk("hub: individual port over current protection\n"); break; case 0x10: case 0x18: - printk(KERN_DEBUG "hub: no over current protection\n"); + printk("hub: no over current protection\n"); break; } - printk(KERN_DEBUG "hub: power on to power good time: %dms\n", + printk("hub: power on to power good time: %dms\n", hubdescriptor[5] * 2); - printk(KERN_DEBUG "hub: hub controller current requirement: %dmA\n", + printk("hub: hub controller current requirement: %dmA\n", hubdescriptor[6]); for (i = 0; i < dev->maxchild; i++) - printk(KERN_DEBUG "hub: port %d is%s removable\n", i + 1, + printk("hub: port %d is%s removable\n", i + 1, hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) ? " not" : ""); if (usb_get_hub_status(dev, buf)) return; - printk(KERN_DEBUG "hub: local power source is %s\n", + printk("hub: local power source is %s\n", (buf[0] & 1) ? "lost (inactive)" : "good"); - printk(KERN_DEBUG "hub: %sover current condition exists\n", + printk("hub: %sover current condition exists\n", (buf[0] & 2) ? "" : "no "); #if 0 @@ -133,19 +134,18 @@ static void usb_hub_configure(struct usb_hub *hub) portstat = (portstatus[1] << 8) + portstatus[0]; portchange = (portstatus[3] << 8) + portstatus[2]; - printk(KERN_DEBUG "hub: port %d status\n", i + 1); - printk(KERN_DEBUG "hub: %sdevice present\n", (portstat & 1) ? "" : "no "); - printk(KERN_DEBUG "hub: %s\n", (portstat & 2) ? "enabled" : "disabled"); - printk(KERN_DEBUG "hub: %ssuspended\n", (portstat & 4) ? "" : "not "); - printk(KERN_DEBUG "hub: %sover current\n", (portstat & 8) ? "" : "not "); - printk(KERN_DEBUG "hub: has %spower\n", (portstat & 0x100) ? "" : "no "); - printk(KERN_DEBUG "hub: %s speed\n", (portstat & 0x200) ? "low" : "full"); + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstat & 1) ? "" : "no "); + printk("hub: %s\n", (portstat & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstat & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstat & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstat & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstat & 0x200) ? "low" : "full"); } #endif /* Enable power to the ports */ - printk(KERN_INFO "USB hub %d: enabling power on all ports\n", - dev->devnum); + printk("enabling power on all ports\n"); for (i = 0; i < hub->nports; i++) usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); } @@ -155,7 +155,6 @@ static int hub_probe(struct usb_device *dev) struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_hub *hub; - unsigned long flags; /* We don't handle multi-config hubs */ if (dev->descriptor.bNumConfigurations != 1) @@ -165,7 +164,7 @@ static int hub_probe(struct usb_device *dev) if (dev->config[0].bNumInterfaces != 1) return -1; - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0]; /* Is it a hub? */ if (interface->bInterfaceClass != 9) @@ -189,10 +188,10 @@ static int hub_probe(struct usb_device *dev) return -1; /* We found a hub */ - printk(KERN_INFO "USB hub found\n"); + printk("USB hub found\n"); if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "couldn't kmalloc hub struct\n"); + printk("couldn't kmalloc hub struct\n"); return -1; } @@ -203,15 +202,9 @@ static int hub_probe(struct usb_device *dev) INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; - /* Record the new hub's existence */ - spin_lock_irqsave(&hub_list_lock, flags); - INIT_LIST_HEAD(&hub->hub_list); - list_add(&hub->hub_list, &all_hubs_list); - spin_unlock_irqrestore(&hub_list_lock, flags); - usb_hub_configure(hub); - hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); /* Wake up khubd */ wake_up(&usb_hub_wait); @@ -229,14 +222,9 @@ static void hub_disconnect(struct usb_device *dev) /* Delete it and then reset it */ list_del(&hub->event_list); INIT_LIST_HEAD(&hub->event_list); - list_del(&hub->hub_list); - INIT_LIST_HEAD(&hub->hub_list); spin_unlock_irqrestore(&hub_event_lock, flags); - usb_release_irq(hub->dev, hub->irq_handle); - hub->irq_handle = NULL; - /* Free the memory */ kfree(hub); } @@ -254,12 +242,12 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port) wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */ if (usb_get_port_status(hub, port + 1, buf)) { - printk(KERN_ERR "get_port_status failed\n"); + printk("get_port_status failed\n"); return; } - portstatus = le16_to_cpup((unsigned short *)buf + 0); - portchange = le16_to_cpup((unsigned short *)buf + 1); + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); if ((!(portstatus & USB_PORT_STAT_CONNECTION)) && (!(portstatus & USB_PORT_STAT_ENABLE))) { @@ -270,7 +258,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port) usb = hub->bus->op->allocate(hub); if (!usb) { - printk(KERN_ERR "couldn't allocate usb_device\n"); + printk("couldn't allocate usb_device\n"); return; } @@ -307,15 +295,15 @@ static void usb_hub_events(void) for (i = 0; i < hub->nports; i++) { if (usb_get_port_status(dev, i + 1, buf)) { - printk(KERN_ERR "get_port_status failed\n"); + printk("get_port_status failed\n"); continue; } - portstatus = le16_to_cpup((unsigned short *)buf + 0); - portchange = le16_to_cpup((unsigned short *)buf + 1); + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); if (portchange & USB_PORT_STAT_C_CONNECTION) { - printk(KERN_DEBUG "hub: port %d connection change\n", i + 1); + printk("hub: port %d connection change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_CONNECTION); @@ -324,19 +312,19 @@ static void usb_hub_events(void) } if (portchange & USB_PORT_STAT_C_ENABLE) { - printk(KERN_DEBUG "hub: port %d enable change\n", i + 1); + printk("hub: port %d enable change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); } if (portchange & USB_PORT_STAT_C_SUSPEND) - printk(KERN_DEBUG "hub: port %d suspend change\n", i + 1); + printk("hub: port %d suspend change\n", i + 1); if (portchange & USB_PORT_STAT_C_OVERCURRENT) - printk(KERN_DEBUG "hub: port %d over-current change\n", i + 1); + printk("hub: port %d over-current change\n", i + 1); if (portchange & USB_PORT_STAT_C_RESET) { - printk(KERN_DEBUG "hub: port %d reset change\n", i + 1); + printk("hub: port %d reset change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } @@ -351,13 +339,13 @@ static void usb_hub_events(void) portstatus = (buf[1] << 8) + buf[0]; portchange = (buf[3] << 8) + buf[2]; - printk(KERN_DEBUG "hub: port %d status\n", i + 1); - printk(KERN_DEBUG "hub: %sdevice present\n", (portstatus & 1) ? "" : "no "); - printk(KERN_DEBUG "hub: %s\n", (portstatus & 2) ? "enabled" : "disabled"); - printk(KERN_DEBUG "hub: %ssuspended\n", (portstatus & 4) ? "" : "not "); - printk(KERN_DEBUG "hub: %sover current\n", (portstatus & 8) ? "" : "not "); - printk(KERN_DEBUG "hub: has %spower\n", (portstatus & 0x100) ? "" : "no "); - printk(KERN_DEBUG "hub: %s speed\n", (portstatus & 0x200) ? "low" : "full"); + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstatus & 1) ? "" : "no "); + printk("hub: %s\n", (portstatus & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstatus & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstatus & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstatus & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstatus & 0x200) ? "low" : "full"); #endif } tmp = next; @@ -371,19 +359,16 @@ static void usb_hub_events(void) static int usb_hub_thread(void *__hub) { - MOD_INC_USE_COUNT; - - printk(KERN_INFO "USB hub driver registered\n"); - lock_kernel(); /* * This thread doesn't need any user-level access, * so get rid of all our resources */ + printk("usb_hub_thread at %p\n", &usb_hub_thread); exit_mm(current); exit_files(current); - /* exit_fs(current); */ + exit_fs(current); /* Setup a nice name */ strcpy(current->comm, "khubd"); @@ -394,9 +379,7 @@ static int usb_hub_thread(void *__hub) usb_hub_events(); } while (!signal_pending(current)); - MOD_DEC_USE_COUNT; - - printk(KERN_DEBUG "usb_hub_thread exiting\n"); + printk("usb_hub_thread exiting\n"); return 0; } @@ -411,12 +394,11 @@ static struct usb_driver hub_driver = { /* * This should be a separate module. */ -int usb_hub_init(void) +int hub_init(void) { int pid; INIT_LIST_HEAD(&hub_event_list); - INIT_LIST_HEAD(&all_hubs_list); usb_register(&hub_driver); pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -431,24 +413,10 @@ int usb_hub_init(void) return 0; } -void usb_hub_cleanup(void) +void hub_cleanup(void) { - /* - * Hub resources are freed for us by usb_deregister. It - * usb_driver_purge on every device which in turn calls that - * devices disconnect function if it is using this driver. - * The hub_disconnect function takes care of releasing the - * individual hub resources. -greg - */ - usb_deregister(&hub_driver); -} /* usb_hub_cleanup() */ + if (khubd_pid >= 0) + kill_proc(khubd_pid, SIGINT, 1); -#ifdef MODULE -int init_module(void){ - return usb_hub_init(); -} - -void cleanup_module(void){ - usb_hub_cleanup(); + usb_deregister(&hub_driver); } -#endif diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h index 62f4c0ef93d2..d015c5a33063 100644 --- a/drivers/usb/hub.h +++ b/drivers/usb/hub.h @@ -12,7 +12,6 @@ /* * Port feature numbers */ -#define USB_PORT_FEAT_CONNECTION 0 #define USB_PORT_FEAT_ENABLE 1 #define USB_PORT_FEAT_SUSPEND 2 #define USB_PORT_FEAT_OVER_CURRENT 3 @@ -41,7 +40,7 @@ #define USB_PORT_STAT_C_OVERCURRENT 0x0008 #define USB_PORT_STAT_C_RESET 0x0010 -/* wHubCharacteristics (masks) */ +/* Characteristics */ #define HUB_CHAR_LPSM 0x0003 #define HUB_CHAR_COMPOUND 0x0004 #define HUB_CHAR_OCPM 0x0018 @@ -68,12 +67,6 @@ struct usb_hub { /* Device structure */ struct usb_device *dev; - /* Reference to the hub's polling IRQ */ - void* irq_handle; - - /* List of hubs */ - struct list_head hub_list; - /* Temporary event list */ struct list_head event_list; diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h index 28636769904a..81979ce399fa 100644 --- a/drivers/usb/inits.h +++ b/drivers/usb/inits.h @@ -1,9 +1,6 @@ +int bp_mouse_init(void); int usb_kbd_init(void); int usb_audio_init(void); -int usb_hub_init(void); -int usb_acm_init(void); -int usb_printer_init(void); -void usb_hub_cleanup(void); +int hub_init(void); +void hub_cleanup(void); void usb_mouse_cleanup(void); -int proc_usb_init (void); -void proc_usb_cleanup (void); diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c index 47c0780e51b6..c60c812a587e 100644 --- a/drivers/usb/keyboard.c +++ b/drivers/usb/keyboard.c @@ -3,9 +3,6 @@ #include #include #include -#include -#include - #include #include "usb.h" @@ -56,12 +53,10 @@ usb_kbd_handle_key(unsigned char key, int down) int scancode = (int) usb_kbd_map[key]; if(scancode) { -#ifndef CONFIG_MAC_KEYBOARD if(scancode & PCKBD_NEEDS_E0) { handle_scancode(0xe0, 1); } -#endif /* CONFIG_MAC_KEYBOARD */ handle_scancode((scancode & ~PCKBD_NEEDS_E0), down); } } @@ -92,7 +87,7 @@ usb_kbd_repeat(unsigned long dev_id) } static int -usb_kbd_irq(int state, void *buffer, int len, void *dev_id) +usb_kbd_irq(int state, void *buffer, void *dev_id) { struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; unsigned long *down = (unsigned long*) buffer; @@ -173,10 +168,7 @@ usb_kbd_probe(struct usb_device *dev) struct usb_endpoint_descriptor *endpoint; struct usb_keyboard *kbd; - if (dev->descriptor.bNumConfigurations < 1) - return -1; - - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0]; endpoint = &interface->endpoint[0]; if(interface->bInterfaceClass != 3 @@ -195,10 +187,7 @@ usb_kbd_probe(struct usb_device *dev) kbd->dev = dev; dev->private = kbd; - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: kbd\n"); - goto probe_err; - } + usb_set_configuration(dev, dev->config[0].bConfigurationValue); usb_set_protocol(dev, 0); usb_set_idle(dev, 0, 0); @@ -209,14 +198,9 @@ usb_kbd_probe(struct usb_device *dev) kbd); list_add(&kbd->list, &usb_kbd_list); - - return 0; } -probe_err: - if (kbd) - kfree (kbd); - return -1; + return 0; } static void @@ -234,21 +218,9 @@ usb_kbd_disconnect(struct usb_device *dev) printk(KERN_INFO "USB HID boot protocol keyboard removed.\n"); } -int usb_kbd_init(void) +int +usb_kbd_init(void) { usb_register(&usb_kbd_driver); return 0; } - -#ifdef MODULE -int init_module(void) -{ - return usb_kbd_init(); -} - -void cleanup_module(void) -{ - usb_deregister(&usb_kbd_driver); -} -#endif - diff --git a/drivers/usb/keymap.c b/drivers/usb/keymap.c index 478de504b085..16c7b28f3b5e 100644 --- a/drivers/usb/keymap.c +++ b/drivers/usb/keymap.c @@ -7,13 +7,13 @@ unsigned char usb_kbd_map[256] = 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, + 0x1c, 0x01, 0xd3, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, 0x1b, 0x2b, 0x00, 0x27, 0x28, 0x29, 0x33, 0x34, 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, - 0x00, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, + 0x00, 0xd2, 0xc7, 0xc9, 0x63, 0xcf, 0xd1, 0xcd, 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, diff --git a/drivers/usb/maps/fixup.map b/drivers/usb/maps/fixup.map index 6fbec256240d..fc5d1ed7f227 100644 --- a/drivers/usb/maps/fixup.map +++ b/drivers/usb/maps/fixup.map @@ -1,6 +1,7 @@ # misc fixes keycode 0 = Pause keycode 29 = Control +keycode 99 = Remove keycode 42 = Shift keycode 54 = Shift_R keycode 109 = Application @@ -24,7 +25,7 @@ keycode 207 = End keycode 208 = Down keycode 209 = Next keycode 210 = Insert -keycode 211 = Remove +keycode 211 = Delete keycode 219 = Window keycode 220 = Window_R keycode 221 = Menu diff --git a/drivers/usb/maps/mac.map b/drivers/usb/maps/mac.map deleted file mode 100644 index dd601f76d225..000000000000 --- a/drivers/usb/maps/mac.map +++ /dev/null @@ -1,350 +0,0 @@ -# Kernel keymap for Macintoshes. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# -# Fixups: -keycode 0x69 = Print_Screen -keycode 0x6b = F14 -keycode 0x37 = Window_R -# -#keycode 0x00 = a -# hack! -keycode 0x80 = a - altgr keycode 0x00 = Hex_A -keycode 0x01 = s -keycode 0x02 = d - altgr keycode 0x02 = Hex_D -keycode 0x03 = f - altgr keycode 0x03 = Hex_F -keycode 0x04 = h -keycode 0x05 = g -keycode 0x06 = z -keycode 0x07 = x -keycode 0x08 = c - altgr keycode 0x08 = Hex_C -keycode 0x09 = v -keycode 0x0a = -keycode 0x0b = b - altgr keycode 0x0b = Hex_B -keycode 0x0c = q -keycode 0x0d = w -keycode 0x0e = e - altgr keycode 0x0e = Hex_E -keycode 0x0f = r -keycode 0x10 = y -keycode 0x11 = t -keycode 0x12 = one exclam - alt keycode 0x12 = Meta_one -keycode 0x13 = two at at - control keycode 0x13 = nul - shift control keycode 0x13 = nul - alt keycode 0x13 = Meta_two -keycode 0x14 = three numbersign - control keycode 0x14 = Escape - alt keycode 0x14 = Meta_three -keycode 0x15 = four dollar dollar - control keycode 0x15 = Control_backslash - alt keycode 0x15 = Meta_four -keycode 0x16 = six asciicircum - control keycode 0x16 = Control_asciicircum - alt keycode 0x16 = Meta_six -keycode 0x17 = five percent - control keycode 0x17 = Control_bracketright - alt keycode 0x17 = Meta_five -keycode 0x18 = equal plus - alt keycode 0x18 = Meta_equal -keycode 0x19 = nine parenleft bracketright - alt keycode 0x19 = Meta_nine -keycode 0x1a = seven ampersand braceleft - control keycode 0x1a = Control_underscore - alt keycode 0x1a = Meta_seven -keycode 0x1b = minus underscore backslash - control keycode 0x1b = Control_underscore - shift control keycode 0x1b = Control_underscore - alt keycode 0x1b = Meta_minus -keycode 0x1c = eight asterisk bracketleft - control keycode 0x1c = Delete - alt keycode 0x1c = Meta_eight -keycode 0x1d = zero parenright braceright - alt keycode 0x1d = Meta_zero -keycode 0x1e = bracketright braceright asciitilde - control keycode 0x1e = Control_bracketright - alt keycode 0x1e = Meta_bracketright -keycode 0x1f = o -keycode 0x20 = u -keycode 0x21 = bracketleft braceleft - control keycode 0x21 = Escape - alt keycode 0x21 = Meta_bracketleft -keycode 0x22 = i -keycode 0x23 = p -keycode 0x24 = Return - alt keycode 0x24 = Meta_Control_m -keycode 0x25 = l -keycode 0x26 = j -keycode 0x27 = apostrophe quotedbl - control keycode 0x27 = Control_g - alt keycode 0x27 = Meta_apostrophe -keycode 0x28 = k -keycode 0x29 = semicolon colon - alt keycode 0x29 = Meta_semicolon -keycode 0x2a = backslash bar - control keycode 0x2a = Control_backslash - alt keycode 0x2a = Meta_backslash -keycode 0x2b = comma less - alt keycode 0x2b = Meta_comma -keycode 0x2c = slash question - control keycode 0x2c = Delete - alt keycode 0x2c = Meta_slash -keycode 0x2d = n -keycode 0x2e = m -keycode 0x2f = period greater - control keycode 0x2f = Compose - alt keycode 0x2f = Meta_period -keycode 0x30 = Tab Tab - alt keycode 0x30 = Meta_Tab -keycode 0x31 = space space - control keycode 0x31 = nul - alt keycode 0x31 = Meta_space -keycode 0x32 = grave asciitilde - control keycode 0x32 = nul - alt keycode 0x32 = Meta_grave -keycode 0x33 = Delete Delete - control keycode 0x33 = BackSpace - alt keycode 0x33 = Meta_Delete -keycode 0x34 = -keycode 0x35 = Escape Escape - alt keycode 0x35 = Meta_Escape -keycode 0x36 = Control -keycode 0x37 = Window -keycode 0x38 = Shift -keycode 0x39 = Caps_Lock -keycode 0x3a = Alt -keycode 0x3b = Left - alt keycode 0x3b = Decr_Console -keycode 0x3c = Right - alt keycode 0x3c = Incr_Console -keycode 0x3d = Down -keycode 0x3e = Up -keycode 0x3f = -keycode 0x40 = -keycode 0x41 = KP_Period -keycode 0x42 = -keycode 0x43 = KP_Multiply -keycode 0x44 = -keycode 0x45 = KP_Add -keycode 0x46 = -keycode 0x47 = Num_Lock -# shift keycode 0x47 = Bare_Num_Lock -keycode 0x48 = -keycode 0x49 = -keycode 0x4a = -keycode 0x4b = KP_Divide -keycode 0x4c = KP_Enter -keycode 0x4d = -keycode 0x4e = KP_Subtract -keycode 0x4f = -keycode 0x50 = -keycode 0x51 = -#keycode 0x51 = KP_Equals -keycode 0x52 = KP_0 - alt keycode 0x52 = Ascii_0 - altgr keycode 0x52 = Hex_0 -keycode 0x53 = KP_1 - alt keycode 0x53 = Ascii_1 - altgr keycode 0x53 = Hex_1 -keycode 0x54 = KP_2 - alt keycode 0x54 = Ascii_2 - altgr keycode 0x54 = Hex_2 -keycode 0x55 = KP_3 - alt keycode 0x55 = Ascii_3 - altgr keycode 0x55 = Hex_3 -keycode 0x56 = KP_4 - alt keycode 0x56 = Ascii_4 - altgr keycode 0x56 = Hex_4 -keycode 0x57 = KP_5 - alt keycode 0x57 = Ascii_5 - altgr keycode 0x57 = Hex_5 -keycode 0x58 = KP_6 - alt keycode 0x58 = Ascii_6 - altgr keycode 0x58 = Hex_6 -keycode 0x59 = KP_7 - alt keycode 0x59 = Ascii_7 - altgr keycode 0x59 = Hex_7 -keycode 0x5b = KP_8 - alt keycode 0x5b = Ascii_8 - altgr keycode 0x5b = Hex_8 -keycode 0x5c = KP_9 - alt keycode 0x5c = Ascii_9 - altgr keycode 0x5c = Hex_9 -keycode 0x5d = -keycode 0x5e = -keycode 0x5f = -keycode 0x60 = F5 F15 Console_17 - control keycode 0x60 = F5 - alt keycode 0x60 = Console_5 - control alt keycode 0x60 = Console_5 -keycode 0x61 = F6 F16 Console_18 - control keycode 0x61 = F6 - alt keycode 0x61 = Console_6 - control alt keycode 0x61 = Console_6 -keycode 0x62 = F7 F17 Console_19 - control keycode 0x62 = F7 - alt keycode 0x62 = Console_7 - control alt keycode 0x62 = Console_7 -keycode 0x63 = F3 F13 Console_15 - control keycode 0x63 = F3 - alt keycode 0x63 = Console_3 - control alt keycode 0x63 = Console_3 -keycode 0x64 = F8 F18 Console_20 - control keycode 0x64 = F8 - alt keycode 0x64 = Console_8 - control alt keycode 0x64 = Console_8 -keycode 0x65 = F9 F19 Console_21 - control keycode 0x65 = F9 - alt keycode 0x65 = Console_9 - control alt keycode 0x65 = Console_9 -keycode 0x66 = -keycode 0x67 = F11 F11 Console_23 - control keycode 0x67 = F11 - alt keycode 0x67 = Console_11 - control alt keycode 0x67 = Console_11 -keycode 0x68 = -keycode 0x69 = F13 -keycode 0x6a = -keycode 0x6b = Scroll_Lock Show_Memory Show_Registers - control keycode 0x6b = Show_State - alt keycode 0x6b = Scroll_Lock -keycode 0x6c = -keycode 0x6d = F10 F20 Console_22 - control keycode 0x6d = F10 - alt keycode 0x6d = Console_10 - control alt keycode 0x6d = Console_10 -keycode 0x6e = -keycode 0x6f = F12 F12 Console_24 - control keycode 0x6f = F12 - alt keycode 0x6f = Console_12 - control alt keycode 0x6f = Console_12 -keycode 0x70 = -keycode 0x71 = Pause -keycode 0x72 = Insert -keycode 0x73 = Home -keycode 0x74 = Prior - shift keycode 0x74 = Scroll_Backward -keycode 0x75 = Remove -keycode 0x76 = F4 F14 Console_16 - control keycode 0x76 = F4 - alt keycode 0x76 = Console_4 - control alt keycode 0x76 = Console_4 -keycode 0x77 = End -keycode 0x78 = F2 F12 Console_14 - control keycode 0x78 = F2 - alt keycode 0x78 = Console_2 - control alt keycode 0x78 = Console_2 -keycode 0x79 = Next - shift keycode 0x79 = Scroll_Forward -keycode 0x7a = F1 F11 Console_13 - control keycode 0x7a = F1 - alt keycode 0x7a = Console_1 - control alt keycode 0x7a = Console_1 -keycode 0x7b = Shift_R -keycode 0x7c = Alt_R -keycode 0x7d = Control_R -keycode 0x7e = -keycode 0x7f = -#keycode 0x7f = Power - control shift keycode 0x7f = Boot -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff --git a/drivers/usb/mkmap.adb b/drivers/usb/mkmap.adb deleted file mode 100644 index 45020d5ccdfc..000000000000 --- a/drivers/usb/mkmap.adb +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/perl - -($ME = $0) =~ s|.*/||; - -$file = "maps/mac.map"; -$line = 1; -open(PC, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+|0x[0-9a-fA-F]+)\s*=\s*(\S+)/) - { - my($idx) = $1; - my($sym) = $2; - if ($idx =~ "0x.*") { - $idx = hex($idx); - } else { - $idx = int($idx); - } - if(defined($map{uc($sym)})) - { - # print STDERR "$file:$line: warning: `$sym' redefined\n"; - } - $map{uc($sym)} = $idx; - } - $line++; -} -close(PC); - -# $file = "maps/fixup.map"; -# $line = 1; -# open(FIXUP, $file) || die("$!"); -# while() -# { -# if(/^\s*keycode\s+(\d+)\s*=\s*/) -# { -# my($idx) = int($1); -# for $sym (split(/\s+/, $')) -# { -# $map{uc($sym)} = $idx; -# } -# } -# $line++; -# } -# close(FIXUP); - -$file = "maps/usb.map"; -$line = 1; -open(USB, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - my($val) = $map{uc($sym)}; - $map[$idx] = $val; - if(!defined($val)) - { - print STDERR "$file:$line: warning: `$sym' undefined\n"; - } - else - { - last; - } - } - } - $line++; -} -close(USB); - -print "unsigned char usb_kbd_map[256] = \n{\n"; -for($x = 0; $x < 32; $x++) -{ - if($x && !($x % 2)) - { - print "\n"; - } - print " "; - for($y = 0; $y < 8; $y++) - { - my($idx) = $x * 8 + $y; - print sprintf(" 0x%02x,", - int(defined($map[$idx]) ? $map[$idx]:0)); - } - print "\n"; -} -print "};\n"; diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 906e455c12c1..4d346c41ac98 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -2,8 +2,6 @@ * USB HID boot protocol mouse support based on MS BusMouse driver, psaux * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus. * - * N.B. this driver can't cope if more than one mouse is connected! - paulus - * * Brad Keryan 4/3/1999 * * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it @@ -35,7 +33,6 @@ #include #include #include -#include #include @@ -51,23 +48,17 @@ struct mouse_state { int present; /* this mouse is plugged in */ int active; /* someone is has this mouse's device open */ int ready; /* the mouse has changed state since the last read */ - wait_queue_head_t wait; /* for polling */ + struct wait_queue *wait; /* for polling */ struct fasync_struct *fasync; /* later, add a list here to support multiple mice */ /* but we will also need a list of file pointers to identify it */ - - /* FIXME: move these to a per-mouse structure */ - struct usb_device *dev; /* host controller this mouse is on */ - void* irq_handle; /* host controller's IRQ transfer handle */ - __u8 bEndpointAddress; /* these are from the endpoint descriptor */ - __u8 bInterval; /* ... used when calling usb_request_irq */ }; static struct mouse_state static_mouse_state; spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; -static int mouse_irq(int state, void *__buffer, int len, void *dev_id) +static int mouse_irq(int state, void *__buffer, void *dev_id) { signed char *data = __buffer; /* finding the mouse is easy when there's only one */ @@ -82,7 +73,7 @@ static int mouse_irq(int state, void *__buffer, int len, void *dev_id) mouse->buttons = data[0] & 0x07; mouse->dx += data[1]; /* data[] is signed, so this works */ mouse->dy -= data[2]; /* y-axis is reversed */ - mouse->dz -= data[3]; + mouse->dz += data[3]; mouse->ready = 1; add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + @@ -111,16 +102,8 @@ static int release_mouse(struct inode * inode, struct file * file) struct mouse_state *mouse = &static_mouse_state; fasync_mouse(-1, file, 0); - - MOD_DEC_USE_COUNT; - - if (--mouse->active == 0) { - /* stop polling the mouse while its not in use */ - usb_release_irq(mouse->dev, mouse->irq_handle); - /* never keep a reference to a released IRQ! */ - mouse->irq_handle = NULL; - } - + if (--mouse->active) + return 0; return 0; } @@ -134,13 +117,6 @@ static int open_mouse(struct inode * inode, struct file * file) return 0; /* flush state */ mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; - - /* prevent the driver from being unloaded while its in use */ - MOD_INC_USE_COUNT; - - /* start the usb controller's polling of the mouse */ - mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL); - return 0; } @@ -196,30 +172,6 @@ static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_ buffer++; retval++; state = 0; - if (!--count) - break; - } - - /* - * SUBTLE: - * - * The only way to get here is to do a read() of - * more than 3 bytes: if you read a byte at a time - * you will just ever see states 0-2, for backwards - * compatibility. - * - * So you can think of this as a packet interface, - * where you have arbitrary-sized packets, and you - * only ever see the first three bytes when you read - * them in small chunks. - */ - { /* fallthrough - dz */ - int dz = mouse->dz; - mouse->dz = 0; - put_user(dz, buffer); - buffer++; - retval++; - state = 0; } break; } @@ -271,7 +223,7 @@ static int mouse_probe(struct usb_device *dev) return -1; /* Is it a mouse interface? */ - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0]; if (interface->bInterfaceClass != 3) return -1; if (interface->bInterfaceSubClass != 1) @@ -293,17 +245,11 @@ static int mouse_probe(struct usb_device *dev) if ((endpoint->bmAttributes & 3) != 3) return -1; - printk(KERN_INFO "USB mouse found\n"); + printk("USB mouse found\n"); - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: mouse\n"); - return -1; - } + usb_set_configuration(dev, dev->config[0].bConfigurationValue); - /* these are used to request the irq when the mouse is opened */ - mouse->dev = dev; - mouse->bEndpointAddress = endpoint->bEndpointAddress; - mouse->bInterval = endpoint->bInterval; + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL); mouse->present = 1; return 0; @@ -313,18 +259,8 @@ static void mouse_disconnect(struct usb_device *dev) { struct mouse_state *mouse = &static_mouse_state; - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_release_irq(mouse->dev, mouse->irq_handle); - /* never keep a reference to a released IRQ! */ - mouse->irq_handle = NULL; - } - - mouse->irq_handle = NULL; - /* this might need work */ mouse->present = 0; - printk(KERN_INFO "Mouse disconnected\n"); } static struct usb_driver mouse_driver = { @@ -338,42 +274,20 @@ int usb_mouse_init(void) { struct mouse_state *mouse = &static_mouse_state; + misc_register(&usb_mouse); + mouse->present = mouse->active = 0; - mouse->irq_handle = NULL; - init_waitqueue_head(&mouse->wait); + mouse->wait = NULL; mouse->fasync = NULL; - misc_register(&usb_mouse); - usb_register(&mouse_driver); - printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n"); + printk(KERN_INFO "USB HID boot protocol mouse registered.\n"); return 0; } void usb_mouse_cleanup(void) { - struct mouse_state *mouse = &static_mouse_state; - - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_release_irq(mouse->dev, mouse->irq_handle); - /* never keep a reference to a released IRQ! */ - mouse->irq_handle = NULL; - } - /* this, too, probably needs work */ usb_deregister(&mouse_driver); misc_deregister(&usb_mouse); } - -#ifdef MODULE -int init_module(void) -{ - return usb_mouse_init(); -} - -void cleanup_module(void) -{ - usb_mouse_cleanup(); -} -#endif diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c index 339652d210e5..1510bb9da441 100644 --- a/drivers/usb/ohci-debug.c +++ b/drivers/usb/ohci-debug.c @@ -67,7 +67,7 @@ void show_ohci_status(struct ohci *ohci) void show_ohci_ed(struct ohci_ed *ed) { - int stat = le32_to_cpup(&ed->status); + int stat = ed->status; int skip = (stat & OHCI_ED_SKIP); int mps = (stat & OHCI_ED_MPS) >> 16; int isoc = (stat & OHCI_ED_F_ISOC); @@ -75,74 +75,58 @@ void show_ohci_ed(struct ohci_ed *ed) int dir = (stat & OHCI_ED_D); int endnum = (stat & OHCI_ED_EN) >> 7; int funcaddr = (stat & OHCI_ED_FA); - int halted = (le32_to_cpup(&ed->_head_td) & 1); - int toggle = (le32_to_cpup(&ed->_head_td) & 2) >> 1; + int halted = (ed->_head_td & 1); + int toggle = (ed->_head_td & 2) >> 1; printk(KERN_DEBUG " ohci ED:\n"); printk(KERN_DEBUG " status = 0x%x\n", stat); - printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n", + printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d\n", skip ? "Skip " : "", mps, - isoc ? " Isoc." : "", + isoc ? "Isoc. " : "", low_speed ? " LowSpd" : "", (dir == OHCI_ED_D_IN) ? " Input" : (dir == OHCI_ED_D_OUT) ? " Output" : "", halted ? " Halted" : "", toggle, endnum, - funcaddr, - (stat & ED_ALLOCATED) ? " Allocated" : ""); - printk(KERN_DEBUG " tail_td = 0x%x\n", ed_tail_td(ed)); + funcaddr); + printk(KERN_DEBUG " tail_td = 0x%x\n", ed->tail_td); printk(KERN_DEBUG " head_td = 0x%x\n", ed_head_td(ed)); - printk(KERN_DEBUG " next_ed = 0x%x\n", le32_to_cpup(&ed->next_ed)); + printk(KERN_DEBUG " next_ed = 0x%x\n", ed->next_ed); } /* show_ohci_ed() */ void show_ohci_td(struct ohci_td *td) { - int info = le32_to_cpup(&td->info); - int td_round = info & OHCI_TD_ROUND; - int td_dir = info & OHCI_TD_D; - int td_int_delay = (info & OHCI_TD_IOC_DELAY) >> 21; - int td_toggle = (info & OHCI_TD_DT) >> 24; + int td_round = td->info & OHCI_TD_ROUND; + int td_dir = td->info & OHCI_TD_D; + int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21; + int td_toggle = (td->info & OHCI_TD_DT) >> 24; int td_errcnt = td_errorcount(*td); - int td_cc = OHCI_TD_CC_GET(info); + int td_cc = OHCI_TD_CC_GET(td->info); printk(KERN_DEBUG " ohci TD hardware fields:\n"); - printk(KERN_DEBUG " info = 0x%x\n", info); - printk(KERN_DEBUG " %s%s%s%d %s %s%d\n", + printk(KERN_DEBUG " info = 0x%x\n", td->info); + printk(KERN_DEBUG " %s%s%s%d %s\n", td_round ? "Rounding " : "", (td_dir == OHCI_TD_D_IN) ? "Input " : (td_dir == OHCI_TD_D_OUT) ? "Output " : (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "", "IntDelay ", td_int_delay, (td_toggle < 2) ? " " : - (td_toggle & 1) ? "Data1" : "Data0", - "ErrorCnt ", td_errcnt); - printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed\n", - td_cc, - td_cc_accessed(*td) ? "" : "Not "); - - printk(KERN_DEBUG " %s%s\n", - td_allocated(*td) ? "Allocated" : "Free", - td_dummy(*td) ? " DUMMY" : ""); - - printk(KERN_DEBUG " cur_buf = 0x%x\n", le32_to_cpup(&td->cur_buf)); - printk(KERN_DEBUG " next_td = 0x%x\n", le32_to_cpup(&td->next_td)); - printk(KERN_DEBUG " buf_end = 0x%x\n", le32_to_cpup(&td->buf_end)); + (td_toggle & 1) ? "Data1 " : "Data0 "); + printk(KERN_DEBUG " %s%d %s0x%x, %sAccessed, %sActive\n", + "ErrorCnt ", td_errcnt, + "ComplCode ", td_cc, + td_cc_accessed(*td) ? "" : "Not ", + td_active(*td) ? "" : "Not "); + + printk(KERN_DEBUG " cur_buf = 0x%x\n", td->cur_buf); + printk(KERN_DEBUG " next_td = 0x%x\n", td->next_td); + printk(KERN_DEBUG " buf_end = 0x%x\n", td->buf_end); printk(KERN_DEBUG " ohci TD driver fields:\n"); - printk(KERN_DEBUG " flags = %x {", td->hcd_flags); - if (td_allocated(*td)) - printk(" alloc"); - if (td_dummy(*td)) - printk(" dummy"); - if (td_endofchain(*td)) - printk(" endofchain"); - if (!can_auto_free(*td)) - printk(" noautofree"); - printk("}\n"); printk(KERN_DEBUG " data = %p\n", td->data); - printk(KERN_DEBUG " cmpltd = %p\n", td->completed); printk(KERN_DEBUG " dev_id = %p\n", td->dev_id); printk(KERN_DEBUG " ed = %p\n", td->ed); if (td->data != NULL) { @@ -153,26 +137,6 @@ void show_ohci_td(struct ohci_td *td) } /* show_ohci_td() */ -void show_ohci_td_chain(struct ohci_td *td) -{ - struct ohci_td *cur_td; - if (td == NULL) return; - - printk(KERN_DEBUG "+++ OHCI TD Chain %lx: +++\n", virt_to_bus(td)); - - cur_td = td; - for (;;) { - show_ohci_td(cur_td); - if (!cur_td->next_td) break; - cur_td = bus_to_virt(le32_to_cpup(&cur_td->next_td)); - /* we can't trust -anything- we find inside of a dummy TD */ - if (td_dummy(*cur_td)) break; - } - - printk(KERN_DEBUG "--- End TD Chain %lx. ---\n", virt_to_bus(td)); -} /* show_ohci_td_chain () */ - - void show_ohci_device(struct ohci_device *dev) { int idx; @@ -202,14 +166,11 @@ void show_ohci_hcca(struct ohci_hcca *hcca) printk(KERN_DEBUG " ohci_hcca\n"); for (idx=0; idxint_table + idx)); + printk(KERN_DEBUG " int_table[%2d] == %p\n", idx, hcca->int_table +idx); } - printk(KERN_DEBUG " frame_no == %d\n", - le16_to_cpup(&hcca->frame_no)); - printk(KERN_DEBUG " donehead == 0x%08x\n", - le32_to_cpup(&hcca->donehead)); + printk(KERN_DEBUG " frame_no == %d\n", hcca->frame_no); + printk(KERN_DEBUG " donehead == 0x%08x\n", hcca->donehead); } /* show_ohci_hcca() */ diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c index b839ba884138..da3ef6657dc0 100644 --- a/drivers/usb/ohci-hcd.c +++ b/drivers/usb/ohci-hcd.c @@ -3,14 +3,12 @@ * * (C) Copyright 1999 Roman Weissgaerber * - * The OHCI HCD layer is a simple but nearly complete implementation of what - * the USB people would call a HCD for the OHCI. + * The OHCI HCD layer is a simple but nearly complete implementation of what the + * USB people would call a HCD for the OHCI. * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled) - * The layer on top of it, is for interfacing to the alternate-usb - * device-drivers. + * The layer on top of it, is for interfacing to the alternate-usb device-drivers. * - * [ This is based on Linus' UHCI code and gregs OHCI fragments - * (0.03c source tree). ] + * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ] * [ Open Host Controller Interface driver for USB. ] * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ] * [ (C) Copyright 1999 Gregory P. Smith ] @@ -53,6 +51,9 @@ #include "usb.h" #include "ohci-hcd.h" +#include "inits.h" + + #ifdef CONFIG_APM #include @@ -61,9 +62,9 @@ static int apm_resume = 0; #endif -static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); -static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); -static DECLARE_WAIT_QUEUE_HEAD(root_hub); + +static struct wait_queue *control_wakeup; +static struct wait_queue *root_hub = NULL; static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */ /* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */ @@ -102,7 +103,7 @@ static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) OHCI_DEBUG( printk(" ret_status: %x\n", status); }) - ret = handler(cc_to_status[status & 0xf], data, data_len, dev_id); + ret = handler(cc_to_status[status & 0xf], data, dev_id); if(ret == 0) return 0; /* 0 .. do not requeue */ if(status > 0) return -1; /* error occured do not requeue ? */ ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */ @@ -121,19 +122,7 @@ static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len OHCI_DEBUG( printk(" ret_status: %x\n", status); }) return 0; } - -static int sohci_bulk_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw) -{ - *(int * )lw0 = status; - wake_up(&bulk_wakeup); - - OHCI_DEBUG( { int i; printk("USB HC BULK<<<: %x:", ep_addr, ctrl_len);) - OHCI_DEBUG( printk(" data(%d):", data_len);) - OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) - OHCI_DEBUG( printk(" ret_status: %x\n", status); }) - return 0; -} - + static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { struct ohci * ohci = usb_dev->bus->hcpriv; @@ -156,7 +145,7 @@ static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) { - DECLARE_WAITQUEUE(wait, current); + struct wait_queue wait = { current, NULL }; struct ohci * ohci = usb_dev->bus->hcpriv; int status; union ep_addr_ ep_addr; @@ -190,40 +179,6 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void return cc_to_status[status & 0x0f]; } -static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len) -{ - DECLARE_WAITQUEUE(wait, current); - struct ohci * ohci = usb_dev->bus->hcpriv; - int status; - union ep_addr_ ep_addr; - - ep_addr.iep = 0; - ep_addr.bep.ep = ((pipe >> 15) & 0x0f) /* endpoint address */ - | (pipe & 0x80) /* direction */ - | (11 << 5); /* type = bulk*/ - ep_addr.bep.fa = ((pipe >> 8) & 0x7f); /* device address */ - - status = 0xf; /* CC not Accessed */ - OHCI_DEBUG( { int i; printk("USB HC BULK>>>: %x:", ep_addr.iep);) - OHCI_DEBUG( printk(" data(%d):", len);) - OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) - OHCI_DEBUG( printk("\n"); }) - - usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_bulk_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01); - - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&bulk_wakeup, &wait); - - ohci_trans_req(ohci, ep_addr.iep, 0, NULL, data, len, (__OHCI_BAG) &status, 0); - - schedule_timeout(HZ/10); - - remove_wait_queue(&bulk_wakeup, &wait); - - OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);) - - return cc_to_status[status & 0x0f]; -} static int sohci_usb_deallocate(struct usb_device *usb_dev) { struct ohci_device *dev = usb_to_ohci(usb_dev); @@ -279,45 +234,11 @@ static struct usb_device *sohci_usb_allocate(struct usb_device *parent) { return usb_dev; } - -static void *sohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - return NULL; -} - -static void sohci_delete_isochronous (struct usb_device *dev, void *_isodesc) -{ - return; -} - -static int sohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - return USB_ST_NOTSUPPORTED; -} - -static int sohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; -} - -static int sohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; -} - - struct usb_operations sohci_device_operations = { sohci_usb_allocate, sohci_usb_deallocate, sohci_control_msg, - sohci_bulk_msg, sohci_request_irq, - NULL, /* FIXME: should be release_irq/remove_irq */ - sohci_alloc_isochronous, - sohci_delete_isochronous, - sohci_sched_isochronous, - sohci_unsched_isochronous, - sohci_compress_isochronous }; @@ -642,7 +563,7 @@ static int ohci_rm_eds(struct ohci * ohci) { } writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */ writel(0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */ - writel_set((0x03<<4), &ohci->regs->control); /* start CTRL u. (BULK list) */ + writel_set((0x01<<4), &ohci->regs->control); /* start CTRL u. (BULK list) */ spin_unlock_irqrestore(&usb_ed_lock, flags); @@ -990,7 +911,6 @@ void start_hc(struct ohci *ohci) { /* int fminterval; */ unsigned int mask; - int port_nr; /* fminterval = readl(&ohci->regs->fminterval) & 0x3fff; reset_hc(ohci); */ @@ -1002,19 +922,16 @@ void start_hc(struct ohci *ohci) /* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF| OHCI_INTR_FNO */ - if(readl(&ohci->regs->roothub.a) & 0x100) /* global power on */ - writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */ - else { /* port power on */ - for(port_nr=0; port_nr < (ohci->regs->roothub.a & 0xff); port_nr++) - writel(0x100, &ohci->regs->roothub.portstatus[port_nr]); - } - wait_ms(50); + writel((0x00), &ohci->regs->control); /* USB Reset BUS */ wait_ms(10); - writel((0xB7), &ohci->regs->control); /* USB Operational */ - + writel((0x97), &ohci->regs->control); /* USB Operational */ + + writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */ + wait_ms(50); + OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); ) OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); ) OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); ) @@ -1031,15 +948,15 @@ void start_hc(struct ohci *ohci) struct usb_device * usb_dev; struct ohci_device *dev; - struct ohci_device *tmp_root_hub= usb_to_ohci(ohci->bus->root_hub); - usb_dev = sohci_usb_allocate(tmp_root_hub->usb); + + usb_dev = sohci_usb_allocate(ohci->root_hub->usb); dev = usb_dev->hcpriv; dev->ohci = ohci; usb_connect(usb_dev); - tmp_root_hub->usb->children[0] = usb_dev; + ohci->root_hub->usb->children[0] = usb_dev; usb_new_device(usb_dev); } @@ -1116,7 +1033,6 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr) { struct usb_device *usb_dev; struct ohci_device *dev; - struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub); OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );) /* @@ -1126,7 +1042,7 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr) * * So start off by getting rid of any old devices.. */ - usb_disconnect(&tmp_root_hub->usb->children[port_nr]); + usb_disconnect(&ohci->root_hub->usb->children[port_nr]); if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) { writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]); @@ -1136,11 +1052,11 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr) * Ok, we got a new connection. Allocate a device to it, * and find out what it wants to do.. */ - usb_dev = sohci_usb_allocate(tmp_root_hub->usb); + usb_dev = sohci_usb_allocate(ohci->root_hub->usb); dev = usb_dev->hcpriv; dev->ohci = ohci; usb_connect(dev->usb); - tmp_root_hub->usb->children[port_nr] = usb_dev; + ohci->root_hub->usb->children[port_nr] = usb_dev; wait_ms(200); /* wait for powerup */ /* reset port/device */ writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */ @@ -1285,9 +1201,10 @@ static struct ohci *alloc_ohci(void* mem_base) if (!usb) return NULL; - dev = usb_to_ohci(usb); + dev = ohci->root_hub = usb_to_ohci(usb); + usb->bus = bus; - bus->root_hub = usb; + /* bus->root_hub = ohci_to_usb(ohci->root_hub); */ dev->ohci = ohci; /* Initialize the root hub */ @@ -1306,11 +1223,10 @@ static struct ohci *alloc_ohci(void* mem_base) static void release_ohci(struct ohci *ohci) { int i; - struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub); union ep_addr_ ep_addr; ep_addr.iep = 0; - OHCI_DEBUG(printk("USB HC release ohci \n");); + OHCI_DEBUG(printk("USB HC release ohci \n");) if (ohci->irq >= 0) { free_irq(ohci->irq, ohci); @@ -1328,22 +1244,25 @@ static void release_ohci(struct ohci *ohci) ohci_rm_eds(ohci); /* remove eds */ /* disconnect all devices */ - if(ohci->bus->root_hub) - for(i = 0; i < tmp_root_hub->usb->maxchild; i++) - usb_disconnect(tmp_root_hub->usb->children + i); + if(ohci->root_hub) + for(i = 0; i < ohci->root_hub->usb->maxchild; i++) + usb_disconnect(ohci->root_hub->usb->children + i); - usb_deregister_bus(ohci->bus); - USB_FREE(tmp_root_hub->usb); - USB_FREE(tmp_root_hub); + USB_FREE(ohci->root_hub->usb); + USB_FREE(ohci->root_hub); USB_FREE(ohci->bus); /* unmap the IO address space */ iounmap(ohci->regs); + free_pages((unsigned int) ohci->hc_area, 1); } + +void cleanup_drivers(void); + static int ohci_roothub_thread(void * __ohci) { struct ohci *ohci = (struct ohci *)__ohci; @@ -1365,7 +1284,6 @@ static int ohci_roothub_thread(void * __ohci) start_hc(ohci); writel( 0x10000, &ohci->regs->roothub.status); wait_ms(50); /* root hub power on */ - usb_register_bus(ohci->bus); do { #ifdef CONFIG_APM if (apm_resume) { @@ -1375,7 +1293,7 @@ static int ohci_roothub_thread(void * __ohci) } #endif - OHCI_DEBUG(printk("USB RH tasks: int: %x\n",ohci->intrstatus);); + OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); ) #ifndef VROOTHUB /* if (ohci->intrstatus & OHCI_INTR_RHSC) */ { @@ -1410,6 +1328,9 @@ static int ohci_roothub_thread(void * __ohci) return 0; } + + + /* * Increment the module usage count, start the control thread and * return success. @@ -1505,6 +1426,21 @@ static int handle_apm_event(apm_event_t event) } return 0; } +#endif + + + int usb_mouse_init(void); +#ifdef MODULE + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define ohci_hcd_init init_module + #endif #define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310 @@ -1524,6 +1460,16 @@ int ohci_hcd_init(void) if (retval < 0) break; +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif @@ -1533,16 +1479,11 @@ int ohci_hcd_init(void) return retval; } -#ifdef MODULE -int init_module(void){ - return ohci_hcd_init(); -} - -void cleanup_module(void) +void cleanup_drivers(void) { -# ifdef CONFIG_APM - apm_unregister_callback(&handle_apm_event); -# endif + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif } -#endif //MODULE diff --git a/drivers/usb/ohci-hcd.h b/drivers/usb/ohci-hcd.h index 27d07c93291c..aa782bb1df7f 100644 --- a/drivers/usb/ohci-hcd.h +++ b/drivers/usb/ohci-hcd.h @@ -307,6 +307,7 @@ struct ohci { struct usb_ohci_ed * ed_bulktail; /* last endpoint of bulk list */ struct usb_ohci_ed * ed_controltail; /* last endpoint of control list */ struct usb_ohci_ed * ed_isotail; /* last endpoint of iso list */ + struct ohci_device * root_hub; struct usb_ohci_ed ed_rh_ep0; struct usb_ohci_ed ed_rh_epi; struct ohci_rep_td *td_rh_epi; diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c index 6cb8f518d15a..b12d0114c690 100644 --- a/drivers/usb/ohci.c +++ b/drivers/usb/ohci.c @@ -2,14 +2,19 @@ * Open Host Controller Interface driver for USB. * * (C) Copyright 1999 Gregory P. Smith - * Significant code from the following individuals has also been used: - * (C) Copyright 1999 Roman Weissgaerber [ohci-hcd.c] - * (C) Copyright 1999 Linus Torvalds [uhci.c] * * This is the "other" host controller interface for USB. You will * find this on many non-Intel based motherboards, and of course the - * Mac. As Linus hacked his UHCI driver together first, I originally - * modeled this after his.. (it should be obvious) + * Mac. As Linus hacked his UHCI driver together first, I modeled + * this after his.. (it should be obvious) + * + * From the programming standpoint the OHCI interface seems a little + * prettier and potentially less CPU intensive. This remains to be + * proven. In reality, I don't believe it'll make one darn bit of + * difference. USB v1.1 is a slow bus by today's standards. + * + * OHCI hardware takes care of most of the scheduling of different + * transfer types with the correct prioritization for us. * * To get started in USB, I used the "Universal Serial Bus System * Architecture" book by Mindshare, Inc. It was a reasonable introduction @@ -24,7 +29,7 @@ * * No filesystems were harmed in the development of this code. * - * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $ + * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $ */ #include @@ -44,6 +49,7 @@ #include #include "ohci.h" +#include "inits.h" #ifdef CONFIG_APM #include @@ -51,128 +57,94 @@ static int handle_apm_event(apm_event_t event); static int apm_resume = 0; #endif -static DECLARE_WAIT_QUEUE_HEAD(ohci_configure); +static struct wait_queue *ohci_configure = NULL; -#ifdef CONFIG_USB_OHCI_DEBUG -#define OHCI_DEBUG /* to make typing it easier.. */ +#ifdef OHCI_TIMER +static struct timer_list ohci_timer; /* timer for root hub polling */ #endif -int MegaDebug = 0; /* SIGUSR2 to the control thread toggles this */ +static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td) +{ + unsigned int status; -#ifdef OHCI_TIMER -static struct timer_list ohci_timer; /* timer for root hub polling */ -#endif + status = td->info & OHCI_TD_CC; -static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; + /* TODO Debugging code for TD failures goes here */ + + return status; +} /* ohci_td_result() */ -#define FIELDS_OF_ED(e) le32_to_cpup(&e->status), le32_to_cpup(&e->tail_td), \ - le32_to_cpup(&e->_head_td), le32_to_cpup(&e->next_ed) -#define FIELDS_OF_TD(t) le32_to_cpup(&t->info), le32_to_cpup(&t->cur_buf), \ - le32_to_cpup(&t->next_td), le32_to_cpup(&t->buf_end) - -#ifdef OHCI_DEBUG -static const char *cc_names[16] = { - "no error", - "CRC error", - "bit stuff error", - "data toggle mismatch", - "stall", - "device not responding", - "PID check failed", - "unexpected PID", - "data overrun", - "data underrun", - "reserved (10)", - "reserved (11)", - "buffer overrun", - "buffer underrun", - "not accessed (14)", - "not accessed" -}; -#endif + +static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; /* - * Add a chain of TDs to the end of the TD list on a given ED. - * - * This function uses the first TD of the chain as the new dummy TD - * for the ED, and uses the old dummy TD instead of the first TD - * of the chain. The reason for this is that this makes it possible - * to update the TD chain without needing any locking between the - * CPU and the OHCI controller. - * - * The return value is the pointer to the new first TD (the old - * dummy TD). + * Add a TD to the end of the TD list on a given ED. If td->next_td + * points to any more TDs, they will be added as well (naturally). + * Otherwise td->next_td must be 0. + * + * The SKIP flag will be cleared after this function. * - * Important! This function is not re-entrant w.r.t. each ED. - * Locking ohci_edtd_lock while using the function is a must - * if there is any possibility of another CPU or an interrupt routine - * calling this function with the same ED. + * Important! This function needs locking and atomicity as it works + * in parallel with the HC's DMA. Locking ohci_edtd_lock while using + * the function is a must. * * This function can be called by the interrupt handler. */ -static struct ohci_td *ohci_add_tds_to_ed(struct ohci_td *td, - struct ohci_ed *ed) +static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed) { - struct ohci_td *t, *dummy_td; - u32 new_dummy; + /* don't let the HC pull anything from underneath us */ + ed->status |= OHCI_ED_SKIP; - if (ed->tail_td == 0) { - printk(KERN_ERR "eek! an ED without a dummy_td\n"); - return td; + if (ed_head_td(ed) == 0) { /* empty list, put it on the head */ + set_ed_head_td(ed, virt_to_bus(td)); + ed->tail_td = 0; + } else { + struct ohci_td *tail, *head; + head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed)); + tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td); + if (!tail) { /* no tail, single element list */ + td->next_td = head->next_td; + head->next_td = virt_to_bus(td); + ed->tail_td = virt_to_bus(td); + } else { /* append to the list */ + td->next_td = tail->next_td; + tail->next_td = virt_to_bus(td); + ed->tail_td = virt_to_bus(td); + } } - /* Get a pointer to the current dummy TD. */ - dummy_td = bus_to_virt(ed_tail_td(ed)); - - for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) { - t->ed = ed; - if (t->next_td == 0) - break; + /* save the ED link in each of the TDs added */ + td->ed = ed; + while (td->next_td != 0) { + td = bus_to_virt(td->next_td); + td->ed = ed; } - /* Make the last TD point back to the first, since it - * will become the new dummy TD. */ - new_dummy = cpu_to_le32(virt_to_bus(td)); - t->next_td = new_dummy; - - /* Copy the contents of the first TD into the dummy */ - *dummy_td = *td; - - /* Turn the first TD into a dummy */ - make_dumb_td(td); - - /* Set the HC's tail pointer to the new dummy */ - ed->tail_td = new_dummy; - - return dummy_td; /* replacement head of chain */ -} /* ohci_add_tds_to_ed() */ - + /* turn off the SKIP flag */ + ed->status &= ~OHCI_ED_SKIP; +} /* ohci_add_td_to_ed() */ -/* .......... */ - -void ohci_start_control(struct ohci *ohci) +inline void ohci_start_control(struct ohci *ohci) { /* tell the HC to start processing the control list */ - writel_set(OHCI_USB_CLE, &ohci->regs->control); - writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); + writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); } -void ohci_start_bulk(struct ohci *ohci) +inline void ohci_start_bulk(struct ohci *ohci) { /* tell the HC to start processing the bulk list */ - writel_set(OHCI_USB_BLE, &ohci->regs->control); - writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); + writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); } -void ohci_start_periodic(struct ohci *ohci) +inline void ohci_start_periodic(struct ohci *ohci) { - /* enable processing periodic (intr) transfers starting next frame */ + /* enable processing periodc transfers starting next frame */ writel_set(OHCI_USB_PLE, &ohci->regs->control); } -void ohci_start_isoc(struct ohci *ohci) +inline void ohci_start_isoc(struct ohci *ohci) { /* enable processing isoc. transfers starting next frame */ writel_set(OHCI_USB_IE, &ohci->regs->control); @@ -180,7 +152,6 @@ void ohci_start_isoc(struct ohci *ohci) /* * Add an ED to the hardware register ED list pointed to by hw_listhead_p - * This function only makes sense for Control and Bulk EDs. */ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) { @@ -193,17 +164,19 @@ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) /* if the list is not empty, insert this ED at the front */ /* XXX should they go on the end? */ - ed->next_ed = cpu_to_le32(listhead); + if (listhead) { + ed->next_ed = listhead; + } /* update the hardware listhead pointer */ writel(virt_to_bus(ed), hw_listhead_p); spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_add_ed_to_hw() */ +} /* ohci_add_ed() */ /* - * Put a control ED on the controller's list + * Put another control ED on the controller's list */ void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) { @@ -211,187 +184,37 @@ void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) ohci_start_control(ohci); } /* ohci_add_control_ed() */ -/* - * Put a bulk ED on the controller's list - */ -void ohci_add_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) -{ - ohci_add_ed_to_hw(ed, &ohci->regs->ed_bulkhead); - ohci_start_bulk(ohci); -} /* ohci_add_bulk_ed() */ +#if 0 /* - * Put a periodic ED on the appropriate list given the period. + * Put another control ED on the controller's list */ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) { - struct ohci_ed *int_ed; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - unsigned long flags; - - /* - * Pick a good frequency endpoint based on the requested period - */ - int_ed = &root_hub->ed[ms_to_ed_int(period)]; -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n", - ms_to_ed_int(period), period); -#endif - - spin_lock_irqsave(&ohci_edtd_lock, flags); - /* - * Insert this ED at the front of the list. - */ - ed->next_ed = int_ed->next_ed; - int_ed->next_ed = cpu_to_le32(virt_to_bus(ed)); - - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - + ohci_add_ed_to_hw(ed, /* XXX */); ohci_start_periodic(ohci); -} /* ohci_add_periodic_ed() */ - -/* - * Locate the periodic ED for a given interrupt endpoint. - */ -struct ohci_ed *ohci_get_periodic_ed(struct ohci_device *dev, int period, - unsigned int pipe, int isoc) -{ - struct ohci_device *root_hub = usb_to_ohci(dev->ohci->bus->root_hub); - unsigned long flags; - struct ohci_ed *int_ed; - unsigned int status, req_status; - - /* get the dummy ED before the EDs for this period */ - int_ed = &root_hub->ed[ms_to_ed_int(period)]; - - /* decide on what the status field should look like */ - req_status = ed_set_maxpacket(usb_maxpacket(ohci_to_usb(dev), pipe)) - | ed_set_speed(usb_pipeslow(pipe)) - | (usb_pipe_endpdev(pipe) & 0x7ff) - | ed_set_type_isoc(isoc); - - spin_lock_irqsave(&ohci_edtd_lock, flags); - for (;;) { - int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed)); - /* stop if we get to the end or to another dummy ED. */ - if (int_ed == 0) - break; - status = le32_to_cpup(&int_ed->status); - if ((status & OHCI_ED_FA) == 0) { - int_ed = 0; - break; - } - /* check whether all the appropriate fields match */ - if ((status & 0x7ffa7ff) == req_status) - break; - } - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - return int_ed; -} - -/* - * Put an isochronous ED on the controller's list - */ -inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed) -{ - ohci_add_periodic_ed(ohci, ed, 1); -} - - -/* - * This will be used for the interrupt to wake us up on the next SOF - */ -DECLARE_WAIT_QUEUE_HEAD(start_of_frame_wakeup); - -static void ohci_wait_sof(struct ohci_regs *regs) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&start_of_frame_wakeup, &wait); - - /* clear the SOF interrupt status and enable it */ - writel(OHCI_INTR_SF, ®s->intrstatus); - writel(OHCI_INTR_SF, ®s->intrenable); - - schedule_timeout(HZ/10); - - remove_wait_queue(&start_of_frame_wakeup, &wait); -} - -/* - * Guarantee that an ED is safe to be modified by the HCD (us). - * - * This function can NOT be called from an interrupt. - */ -void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type) -{ - __u32 *hw_listcurrent; - - /* tell the controller to skip this ED */ - ed->status |= cpu_to_le32(OHCI_ED_SKIP); - - switch (ed_type) { - case HCD_ED_CONTROL: - hw_listcurrent = ®s->ed_controlcurrent; - break; - case HCD_ED_BULK: - hw_listcurrent = ®s->ed_bulkcurrent; - break; - case HCD_ED_ISOC: - case HCD_ED_INT: - hw_listcurrent = ®s->ed_periodcurrent; - break; - default: - return; - } - - /* - * If the HC is processing this ED we need to wait until the - * at least the next frame. - */ - if (virt_to_bus(ed) == readl(hw_listcurrent)) { -#ifdef OHCI_DEBUG - printk(KERN_INFO "Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed)); +} /* ohci_add_control_ed() */ #endif - ohci_wait_sof(regs); - - } - - return; /* The ED is now safe */ -} /* ohci_wait_for_ed_safe() */ /* - * Remove an ED from the HC's list. - * This function can ONLY be used for Control or Bulk EDs. + * Remove an ED from the HC list whos bus headpointer is pointed to + * by hw_listhead_p * * Note that the SKIP bit is left on in the removed ED. */ -void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type) +void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) { unsigned long flags; - struct ohci_regs *regs = ohci->regs; struct ohci_ed *cur; __u32 bus_ed = virt_to_bus(ed); __u32 bus_cur; - __u32 *hw_listhead_p; if (ed == NULL || !bus_ed) return; - ed->status |= cpu_to_le32(OHCI_ED_SKIP); - switch (ed_type) { - case HCD_ED_CONTROL: - hw_listhead_p = ®s->ed_controlhead; - break; - case HCD_ED_BULK: - hw_listhead_p = ®s->ed_bulkhead; - break; - default: - printk(KERN_ERR "Unknown HCD ED type %d.\n", ed_type); - return; - } + /* tell the controller this skip ED */ + ed->status |= OHCI_ED_SKIP; bus_cur = readl(hw_listhead_p); @@ -404,33 +227,31 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t /* if its the head ED, move the head */ if (bus_cur == bus_ed) { - writel(le32_to_cpup(&cur->next_ed), hw_listhead_p); + writel(cur->next_ed, hw_listhead_p); } else if (cur->next_ed != 0) { struct ohci_ed *prev; /* walk the list and unlink the ED if found */ - do { + for (;;) { prev = cur; - cur = bus_to_virt(le32_to_cpup(&cur->next_ed)); + cur = bus_to_virt(cur->next_ed); - if (cur == ed) { + if (virt_to_bus(cur) == bus_ed) { /* unlink from the list */ prev->next_ed = cur->next_ed; break; } - } while (cur->next_ed != 0); - } - /* - * Make sure this ED is not being accessed by the HC as we speak. - */ - ohci_wait_for_ed_safe(regs, ed, ed_type); + if (cur->next_ed == 0) + break; + } + } /* clear any links from the ED for safety */ ed->next_ed = 0; spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_remove_norm_ed_from_hw() */ +} /* ohci_remove_ed_from_hw() */ /* * Remove an ED from the controller's control list. Note that the SKIP bit @@ -438,7 +259,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t */ inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL); + ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead); } /* @@ -447,128 +268,12 @@ inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) */ inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK); -} - - -/* - * Remove a periodic ED from the host controller - */ -void ohci_remove_periodic_ed(struct ohci *ohci, struct ohci_ed *ed) -{ - struct ohci_device *root_hub = usb_to_ohci(ohci->bus->root_hub); - struct ohci_ed *cur_ed = NULL, *prev_ed; - unsigned long flags; - - /* FIXME: this will need to up fixed when add_periodic_ed() - * is updated to spread similar polling rate EDs out over - * multiple periodic queues. Currently this assumes that the - * 32ms (slowest) polling queue links to all others... */ - - /* search the periodic EDs, skipping the first one which is - * only a placeholder. */ - prev_ed = &root_hub->ed[ED_INT_32]; - if (prev_ed->next_ed) - cur_ed = bus_to_virt(le32_to_cpup(&prev_ed->next_ed)); - - while (cur_ed) { - if (ed == cur_ed) { /* remove the ED */ - /* set its SKIP bit and be sure its not in use */ - ohci_wait_for_ed_safe(ohci->regs, ed, HCD_ED_INT); - - /* unlink it */ - spin_lock_irqsave(&ohci_edtd_lock, flags); - prev_ed->next_ed = ed->next_ed; - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - ed->next_ed = 0; - - break; - } - - spin_lock_irqsave(&ohci_edtd_lock, flags); - if (cur_ed->next_ed) { - prev_ed = cur_ed; - cur_ed = bus_to_virt(le32_to_cpup(&cur_ed->next_ed)); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - } else { - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - - /* if multiple polling queues need to be checked, - * here is where you'd advance to the next one */ - - printk(KERN_ERR "usb-ohci: ed %p not found on periodic queue\n", ed); - break; - } - } -} /* ohci_remove_periodic_ed() */ - - -/* - * Remove all the EDs which have a given device address from a list. - * Used when the device is unplugged. - * Returns 1 if anything was changed. - */ -static int ohci_remove_device_list(__u32 *headp, int devnum) -{ - struct ohci_ed *ed; - __u32 *prevp = headp; - int removed = 0; - - while (*prevp != 0) { - ed = bus_to_virt(le32_to_cpup(prevp)); - if ((le32_to_cpup(&ed->status) & OHCI_ED_FA) == devnum) { - /* set the controller to skip this one - and remove it from the list */ - ed->status |= cpu_to_le32(OHCI_ED_SKIP); - /* XXX should call td->completed for each td */ - *prevp = ed->next_ed; - removed = 1; - } else { - prevp = &ed->next_ed; - } - } - wmb(); - - return removed; + ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead); } -/* - * Remove all the EDs for a given device from all lists. - */ -void ohci_remove_device(struct ohci *ohci, int devnum) -{ - unsigned long flags; - __u32 head; - struct ohci_regs *regs = ohci->regs; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - - spin_lock_irqsave(&ohci_edtd_lock, flags); - - /* Control list */ - head = cpu_to_le32(readl(®s->ed_controlhead)); - if (ohci_remove_device_list(&head, devnum)) - writel(le32_to_cpup(&head), ®s->ed_controlhead); - - /* Bulk list */ - head = cpu_to_le32(readl(®s->ed_bulkhead)); - if (ohci_remove_device_list(&head, devnum)) - writel(le32_to_cpup(&head), ®s->ed_bulkhead); - - /* Interrupt/iso list */ - head = cpu_to_le32(virt_to_bus(&root_hub->ed[ED_INT_32])); - ohci_remove_device_list(&head, devnum); - - /* - * Wait until the start of the next frame to ensure - * that the HC has seen any changes. - */ - ohci_wait_sof(ohci->regs); - - spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* - * Remove a TD from the given EDs TD list. The TD is freed as well. + * Remove a TD from the given EDs TD list. */ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) { @@ -578,13 +283,13 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) if ((td == NULL) || (ed == NULL)) return; + spin_lock_irqsave(&ohci_edtd_lock, flags); + if (ed_head_td(ed) == 0) return; - spin_lock_irqsave(&ohci_edtd_lock, flags); - /* set the "skip me bit" in this ED */ - ed->status |= cpu_to_le32(OHCI_ED_SKIP); + ed->status |= OHCI_ED_SKIP; /* XXX Assuming this list will never be circular */ @@ -598,7 +303,7 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) /* FIXME: collapse this into a nice simple loop :) */ if (head_td->next_td != 0) { prev_td = head_td; - cur_td = bus_to_virt(le32_to_cpup(&head_td->next_td)); + cur_td = bus_to_virt(head_td->next_td); for (;;) { if (td == cur_td) { /* remove it */ @@ -608,7 +313,7 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) if (cur_td->next_td == 0) break; prev_td = cur_td; - cur_td = bus_to_virt(le32_to_cpup(&cur_td->next_td)); + cur_td = bus_to_virt(cur_td->next_td); } } } @@ -616,11 +321,10 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) td->next_td = 0; /* remove the TDs links */ td->ed = NULL; - /* return this TD to the pool of free TDs */ - ohci_free_td(td); + /* TODO return this TD to the pool of free TDs */ /* unset the "skip me bit" in this ED */ - ed->status &= cpu_to_le32(~OHCI_ED_SKIP); + ed->status &= ~OHCI_ED_SKIP; spin_unlock_irqrestore(&ohci_edtd_lock, flags); } /* ohci_remove_td_from_ed() */ @@ -628,109 +332,47 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) /* * Get a pointer (virtual) to an available TD from the given device's - * pool. Return NULL if none are left. + * pool. + * + * Return NULL if none are left. */ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) { int idx; - /* FIXME: this is horribly inefficient */ for (idx=0; idx < NUM_TDS; idx++) { if (!td_allocated(dev->td[idx])) { struct ohci_td *new_td = &dev->td[idx]; /* zero out the TD */ memset(new_td, 0, sizeof(*new_td)); /* mark the new TDs as unaccessed */ - new_td->info = cpu_to_le32(OHCI_TD_CC_NEW); + new_td->info = OHCI_TD_CC_NEW; /* mark it as allocated */ allocate_td(new_td); - /* record the device that its on */ - new_td->usb_dev = ohci_to_usb(dev); return new_td; } } - printk(KERN_ERR "usb-ohci: unable to allocate a TD\n"); + printk("usb-ohci error: unable to allocate a TD\n"); return NULL; } /* ohci_get_free_td() */ -/* - * Get a pointer (virtual) to an available TD from the given device's - * pool. Return NULL if none are left. - * - * NOTE: This function does not allocate and attach the dummy_td. - * That is done in ohci_fill_ed(). FIXME: it should probably be moved - * into here. - */ -static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev) -{ - int idx; - - /* FIXME: this is horribly inefficient */ - for (idx=0; idx < NUM_EDS; idx++) { - if (!ed_allocated(dev->ed[idx])) { - struct ohci_ed *new_ed = &dev->ed[idx]; - /* zero out the ED */ - memset(new_ed, 0, sizeof(*new_ed)); - /* all new EDs start with the SKIP bit set */ - new_ed->status |= cpu_to_le32(OHCI_ED_SKIP); - /* mark it as allocated */ - allocate_ed(new_ed); - new_ed->ohci_dev = dev; - return new_ed; - } - } - - printk(KERN_ERR "usb-ohci: unable to allocate an ED\n"); - return NULL; -} /* ohci_get_free_ed() */ - - -/* - * Free an OHCI ED and all of the TDs on its list. It is assumed that - * this ED is not active. You should call ohci_wait_for_ed_safe() - * beforehand if you can't guarantee that. - */ -void ohci_free_ed(struct ohci_ed *ed) -{ - if (!ed) - return; - - if (ed_head_td(ed) != 0) { - struct ohci_td *td, *tail_td, *next_td; - - td = bus_to_virt(ed_head_td(ed)); - tail_td = bus_to_virt(ed_tail_td(ed)); - for (;;) { - next_td = bus_to_virt(le32_to_cpup(&td->next_td)); - ohci_free_td(td); - if (td == tail_td) - break; - td = next_td; - } - } - - ed->status &= cpu_to_le32(~(__u32)ED_ALLOCATED); -} /* ohci_free_ed() */ - - /* * Initialize a TD * * dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP * toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1 */ -struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed) +inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed) { /* hardware fields */ - td->info = cpu_to_le32(OHCI_TD_CC_NEW | - (dir & OHCI_TD_D) | - (toggle & OHCI_TD_DT) | - flags); - td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data)); - td->buf_end = (len == 0) ? 0 : - cpu_to_le32(virt_to_bus((char *)data + len - 1)); + td->info = OHCI_TD_CC_NEW | + (dir & OHCI_TD_D) | + (toggle & OHCI_TD_DT) | + flags; + td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data); + td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1; /* driver fields */ td->data = data; @@ -741,177 +383,6 @@ struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 } /* ohci_fill_new_td() */ -/* - * Initialize a new ED on device dev, including allocating and putting the - * dummy tail_td on its queue if it doesn't already have one. Any - * TDs on this ED other than the dummy will be lost (so there better - * not be any!). This assumes that the ED is Allocated and will - * force the Allocated bit on. - */ -struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, - int maxpacketsize, int lowspeed, int endp_id, - int isoc_tds) -{ - struct ohci_td *dummy_td; - - if (ed_head_td(ed) != ed_tail_td(ed)) - printk(KERN_ERR "Reusing a non-empty ED %p!\n", ed); - - if (!ed->tail_td) { - dummy_td = ohci_get_free_td(dev); - if (dummy_td == NULL) { - printk(KERN_ERR "Error allocating dummy TD for ED %p\n", ed); - return NULL; /* no dummy available! */ - } - make_dumb_td(dummy_td); /* flag it as a dummy */ - ed->tail_td = cpu_to_le32(virt_to_bus(dummy_td)); - } else { - dummy_td = bus_to_virt(ed_tail_td(ed)); - if (!td_dummy(*dummy_td)) - printk(KERN_ERR "ED %p's dummy %p is screwy\n", ed, dummy_td); - } - - /* set the head TD to the dummy and clear the Carry & Halted bits */ - ed->_head_td = ed->tail_td; - - ed->status = cpu_to_le32( - ed_set_maxpacket(maxpacketsize) | - ed_set_speed(lowspeed) | - (endp_id & 0x7ff) | - ((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC)); - allocate_ed(ed); - ed->next_ed = 0; - - return ed; -} /* ohci_fill_ed() */ - - -/* - * Create a chain of Normal TDs to be used for a large data transfer - * (bulk or control). - * - * Returns the head TD in the chain. - */ -struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, - void *data, unsigned int len, int dir, __u32 toggle, - int round, int auto_free, void* dev_id, - usb_device_irq handler, __u32 next_td) -{ - struct ohci_td *head, *cur_td; - unsigned max_len; - - if (!data || (len == 0)) - return NULL; - - /* Get the first TD */ - head = ohci_get_free_td(dev); - if (head == NULL) { - printk(KERN_ERR "usb-ohci: out of TDs\n"); - return NULL; - } - - cur_td = head; - - /* AFICT, that the OHCI controller takes care of the innards of - * bulk & control data transfers by sending zero length - * packets as necessary if the transfer falls on an even packet - * size boundary, we don't need a special TD for that. */ - - /* check the 4096 byte alignment of the start of the data */ - max_len = 0x2000 - ((unsigned long)data & 0xfff); - - /* check if the remaining data occupies more than two pages */ - while (len > max_len) { - struct ohci_td *new_td; - - /* TODO lookup effect of rounding bit on - * individual TDs vs. whole TD chain transfers; - * disable cur_td's rounding bit here if needed. */ - - ohci_fill_new_td(cur_td, - td_set_dir_out(dir), - toggle & OHCI_TD_DT, - (round ? OHCI_TD_ROUND : 0), - data, max_len - 1, - dev_id, handler); - if (!auto_free) - noauto_free_td(head); - - /* adjust the data pointer & remaining length */ - data += max_len; - len -= max_len; - - /* allocate another td */ - new_td = ohci_get_free_td(dev); - if (new_td == NULL) { - printk(KERN_ERR "usb-ohci: out of TDs\n"); - /* FIXME: free any allocated TDs */ - return NULL; - } - - /* Link the new TD to the chain & advance */ - cur_td->next_td = cpu_to_le32(virt_to_bus(new_td)); - cur_td = new_td; - - /* address is page-aligned now */ - max_len = 0x2000; - toggle = TOGGLE_AUTO; /* toggle Data0/1 via the ED */ - } - - ohci_fill_new_td(cur_td, - td_set_dir_out(dir), - toggle & OHCI_TD_DT, - (round ? OHCI_TD_ROUND : 0), - data, len, - dev_id, handler); - if (!auto_free) - noauto_free_td(head); - - /* link the given next_td to the end of this chain */ - cur_td->next_td = cpu_to_le32(next_td); - if (next_td == 0) - set_td_endofchain(cur_td); - - return head; -} /* ohci_build_td_chain() */ - - -/* - * Compute the number of bytes that have been transferred on a given - * TD. Do not call this on TDs that are active on the host - * controller. - */ -static __u16 ohci_td_bytes_done(struct ohci_td *td) -{ - __u16 result; - __u32 bus_data_start, bus_data_end; - - bus_data_start = virt_to_bus(td->data); - if (!td->data || !bus_data_start) - return 0; - - /* if cur_buf is 0, all data has been transferred */ - if (!td->cur_buf) { - /* XXX this could be wrong for transfers > 1 page */ - return le32_to_cpup(&td->buf_end) - bus_data_start + 1; - } - - bus_data_end = le32_to_cpup(&td->cur_buf); - - /* is it on the same page? */ - if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) { - result = bus_data_end - bus_data_start; - } else { - /* compute the amount transferred on the first page */ - result = 0x1000 - (bus_data_start & 0xfff); - /* add the amount done in the second page */ - result += (bus_data_end & 0xfff); - } - - return result; -} /* ohci_td_bytes_done() */ - - /********************************** * OHCI interrupt list operations * **********************************/ @@ -925,631 +396,276 @@ static __u16 ohci_td_bytes_done(struct ohci_td *td) * * Period is desired polling interval in ms. The closest, shorter * match will be used. Powers of two from 1-32 are supported by OHCI. - * - * Returns: a "handle pointer" that release_irq can use to stop this - * interrupt. (It's really a pointer to the TD). NULL = error. */ -static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe, +static int ohci_request_irq(struct usb_device *usb, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { struct ohci_device *dev = usb_to_ohci(usb); struct ohci_td *td; struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ - int maxps = usb_maxpacket(usb, pipe); - unsigned long flags; - - /* Get an ED and TD */ - interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0); - if (interrupt_ed == 0) { - interrupt_ed = ohci_get_free_ed(dev); - if (!interrupt_ed) { - printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev); - return NULL; - } - - /* - * Set the max packet size, device speed, endpoint number, usb - * device number (function address), and type of TD. - */ - ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe), - usb_pipe_endpdev(pipe), 0 /* normal TDs */); - interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - - /* Assimilate the new ED into the collective */ - ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); - } -#ifdef OHCI_DEBUG - if (MegaDebug) { - printk(KERN_DEBUG "ohci_request irq: using ED %p [%x %x %x %x]\n", - interrupt_ed, FIELDS_OF_ED(interrupt_ed)); - printk(KERN_DEBUG " for dev %d pipe %x period %d\n", usb->devnum, - pipe, period); - } -#endif - - td = ohci_get_free_td(dev); - if (!td) { - printk(KERN_ERR "Out of TDs in ohci_request_irq\n"); - ohci_free_ed(interrupt_ed); - return NULL; - } - - /* Fill in the TD */ - if (maxps > sizeof(dev->data)) - maxps = sizeof(dev->data); - ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), - TOGGLE_AUTO, - OHCI_TD_ROUND, - dev->data, maxps, - dev_id, handler); - set_td_endofchain(td); /* - * Put the TD onto our ED and make sure its ready to run + * Pick a good frequency endpoint based on the requested period */ - td->next_td = 0; - spin_lock_irqsave(&ohci_edtd_lock, flags); - td = ohci_add_tds_to_ed(td, interrupt_ed); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - - return (void*)td; -} /* ohci_request_irq() */ - -/* - * Release an interrupt handler previously allocated using - * ohci_request_irq. This function does no validity checking, so make - * sure you're not releasing an already released handle as it may be - * in use by something else.. - * - * This function can NOT be called from an interrupt. - */ -int ohci_release_irq(void* handle) -{ - struct ohci_device *dev; - struct ohci_td *int_td; - struct ohci_ed *int_ed; - -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "usb-ohci: Releasing irq handle %p\n", handle); -#endif - - int_td = (struct ohci_td*)handle; - if (int_td == NULL) - return USB_ST_INTERNALERROR; - - dev = usb_to_ohci(int_td->usb_dev); - int_ed = int_td->ed; - - ohci_remove_periodic_ed(dev->ohci, int_ed); - - /* Tell the driver that the IRQ has been killed. */ - /* Passing NULL in the "buffer" void* along with the - * USB_ST_REMOVED status is the signal. */ - if (int_td->completed != NULL) - int_td->completed(USB_ST_REMOVED, NULL, 0, int_td->dev_id); - - /* Free the ED (& TD) */ - ohci_free_ed(int_ed); - - return USB_ST_NOERROR; -} /* ohci_release_irq() */ - - -/************************************ - * OHCI control transfer operations * - ************************************/ - -static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); - -/* - * This is the handler that gets called when a control transaction - * completes. - * - * This function is called from the interrupt handler. - */ -static int ohci_control_completed(int stats, void *buffer, int len, void *dev_id) -{ - /* pass the TDs completion status back to control_msg */ - if (dev_id) { - int *completion_status = (int *)dev_id; - *completion_status = stats; - } - - wake_up(&control_wakeup); - return 0; -} /* ohci_control_completed() */ - - -/* - * Send or receive a control message on a "pipe" - * - * The cmd parameter is a pointer to the 8 byte setup command to be - * sent. - * - * A control message contains: - * - The command itself - * - An optional data phase (if len > 0) - * - Status complete phase - * - * This function can NOT be called from an interrupt. - */ -static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, - devrequest *cmd, void *data, int len) -{ - struct ohci_device *dev = usb_to_ohci(usb); - struct ohci_ed *control_ed = ohci_get_free_ed(dev); - struct ohci_td *setup_td, *data_td, *status_td; - DECLARE_WAITQUEUE(wait, current); - int completion_status = -1; - devrequest our_cmd; - - /* byte-swap fields of cmd if necessary */ - our_cmd = *cmd; - cpu_to_le16s(&our_cmd.value); - cpu_to_le16s(&our_cmd.index); - cpu_to_le16s(&our_cmd.length); - -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); -#endif - if (!control_ed) { - printk(KERN_ERR "usb-ohci: couldn't get ED for dev %p\n", dev); - return -1; - } - - /* get a TD to send this control message with */ - setup_td = ohci_get_free_td(dev); - if (!setup_td) { - printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev); - ohci_free_ed(control_ed); - return -1; - } + interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)]; /* * Set the max packet size, device speed, endpoint number, usb * device number (function address), and type of TD. * + * FIXME: Isochronous transfers need a pool of special 32 byte + * TDs (32 byte aligned) in order to be supported. */ - ohci_fill_ed(dev, control_ed, usb_maxpacket(usb,pipe), usb_pipeslow(pipe), - usb_pipe_endpdev(pipe), 0 /* normal TDs */); + interrupt_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; - /* - * Build the control TD - */ + td = ohci_get_free_td(dev); + /* FIXME: check for NULL */ + /* Fill in the TD */ + ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), + TOGGLE_AUTO, + OHCI_TD_ROUND, + dev->data, DATA_BUF_LEN, + dev_id, handler); /* - * Set the not accessed condition code, allow odd sized data, - * and set the data transfer type to SETUP. Setup DATA always - * uses a DATA0 packet. + * TODO: be aware that OHCI won't advance out of the 4kb + * page cur_buf started in. It'll wrap around to the start + * of the page... annoying or useful? you decide. * - * The setup packet contains a devrequest (usb.h) which - * will always be 8 bytes long. + * We should make sure dev->data doesn't cross a page... */ - ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0, - OHCI_TD_IOC_OFF, - &our_cmd, 8, /* cmd is always 8 bytes long */ - &completion_status, NULL); - - /* Allocate a TD for the control xfer status */ - status_td = ohci_get_free_td(dev); - if (!status_td) { - printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev); - ohci_free_td(setup_td); - ohci_free_ed(control_ed); - return -1; - } - /* The control status packet always uses a DATA1 - * Give "dev_id" the address of completion_status so that the - * TDs status can be passed back to us from the IRQ. */ - ohci_fill_new_td(status_td, - td_set_dir_in(usb_pipeout(pipe) | (len == 0)), - TOGGLE_DATA1, - 0 /* flags */, - NULL /* data */, 0 /* data len */, - &completion_status, ohci_control_completed); - set_td_endofchain(status_td); - status_td->next_td = 0; /* end of TDs */ - - /* If there is data to transfer, create the chain of data TDs - * followed by the status TD. */ - if (len > 0) { - data_td = ohci_build_td_chain( dev, data, len, - usb_pipeout(pipe), TOGGLE_DATA1, - 1 /* round */, 1 /* autofree */, - &completion_status, NULL /* no handler here */, - virt_to_bus(status_td) ); - if (!data_td) { - printk(KERN_ERR "usb-ohci: couldn't allocate control data TDs for dev %p\n", dev); - ohci_free_td(setup_td); - ohci_free_td(status_td); - ohci_free_ed(control_ed); - return -1; - } + /* FIXME: this just guarantees that its the end of the list */ + td->next_td = 0; - /* link the to the data & status TDs */ - setup_td->next_td = cpu_to_le32(virt_to_bus(data_td)); - } else { - /* no data TDs, link to the status TD */ - setup_td->next_td = cpu_to_le32(virt_to_bus(status_td)); - } + /* Linus did this. see asm/system.h; scary concept... I don't + * know if its needed here or not but it won't hurt. */ + wmb(); /* - * Add the control TDs to the control ED (setup_td is the first) + * Put the TD onto our ED */ - setup_td = ohci_add_tds_to_ed(setup_td, control_ed); - control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - /* ohci_unhalt_ed(control_ed); */ - -#ifdef OHCI_DEBUG - if (MegaDebug > 1) { - /* complete transaction debugging output (before) */ - printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); - show_ohci_ed(control_ed); - printk(KERN_DEBUG " Control TD chain:\n"); - show_ohci_td_chain(setup_td); - printk(KERN_DEBUG " OHCI Controller Status:\n"); - show_ohci_status(dev->ohci); + { + unsigned long flags; + spin_lock_irqsave(&ohci_edtd_lock, flags); + ohci_add_td_to_ed(td, interrupt_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); } -#endif +#if 0 + /* Assimilate the new ED into the collective */ /* - * Start the control transaction.. + * When dynamic ED allocation is done, this call will be + * useful. For now, the correct ED already on the + * controller's proper periodic ED lists was chosen above. */ - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&control_wakeup, &wait); - - /* Give the ED to the HC */ - ohci_add_control_ed(dev->ohci, control_ed); - - schedule_timeout(HZ); - - remove_wait_queue(&control_wakeup, &wait); - -#ifdef OHCI_DEBUG - if (completion_status != 0) { - const char *what = (completion_status < 0)? "timed out": - cc_names[completion_status & 0xf]; - printk(KERN_DEBUG "ohci_control_msg: %s on pipe %x\n", - what, pipe); - } - if (MegaDebug) { - printk(KERN_DEBUG "ctrl msg %x %x %x %x %x on pipe %x", - cmd->requesttype, cmd->request, cmd->value, cmd->index, - cmd->length, pipe); - if (usb_pipeout(pipe)) - printk(" data (%d)", len); - else - printk(" returned (%d)", len); - if (len > 0) { - int i; - unsigned char *q = data; - for (i = 0; i < len; ++i) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG); - printk(" %x", q[i]); - } - } - printk("\n"); - } - if (MegaDebug && completion_status < 0) { - printk(KERN_DEBUG "control_ed at %p:\n", control_ed); - show_ohci_ed(control_ed); - if (ed_head_td(control_ed) != ed_tail_td(control_ed)) - show_ohci_td_chain(bus_to_virt(ed_head_td(control_ed))); - printk(KERN_DEBUG "setup TD at %p:\n", setup_td); - show_ohci_td(setup_td); - } - - if (MegaDebug > 1) { - /* complete transaction debugging output (after) */ - printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); - show_ohci_ed(control_ed); - printk(KERN_DEBUG " *after* Control TD chain:\n"); - show_ohci_td_chain(setup_td); - printk(KERN_DEBUG " *after* OHCI Controller Status:\n"); - show_ohci_status(dev->ohci); - } + ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); +#else + /* enable periodic (interrupt) transfers on the HC */ + ohci_start_periodic(dev->ohci); #endif - /* no TD cleanup, the TDs were auto-freed as they finished */ - - /* remove the control ED from the HC */ - ohci_remove_control_ed(dev->ohci, control_ed); - ohci_free_ed(control_ed); /* return it to the pool */ - - if (completion_status < 0) - completion_status = USB_ST_TIMEOUT; - return completion_status; -} /* ohci_control_msg() */ - - -/********************************************************************** - * Bulk transfer processing - **********************************************************************/ - -/* - * Internal state for an ohci_bulk_request - */ -struct ohci_bulk_request_state { - struct usb_device *usb_dev; - unsigned int pipe; /* usb "pipe" */ - void *data; /* ptr to data */ - int length; /* length to transfer */ - int _bytes_done; /* bytes transferred so far */ - unsigned long *bytes_transferred_p; /* where to increment */ - void *dev_id; /* pass to the completion handler */ - usb_device_irq completion; /* completion handler */ -}; - -/* - * this handles the individual TDs of a (possibly) larger bulk - * request. It keeps track of the total bytes transferred, calls the - * final completion handler, etc. - */ -static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id) -{ - struct ohci_bulk_request_state *req; - - req = (struct ohci_bulk_request_state *) dev_id; - -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req); -#endif - - /* only count TDs that were completed successfully */ - if (stats == USB_ST_NOERROR) - req->_bytes_done += len; - -#ifdef OHCI_DEBUG - if (MegaDebug && req->_bytes_done) { - int i; - printk(KERN_DEBUG " %d bytes, bulk data:", req->_bytes_done); - for (i = 0; i < 16 && i < req->_bytes_done; ++i) - printk(" %.2x", ((unsigned char *)buffer)[i]); - if (i < req->_bytes_done) - printk(" ..."); - printk("\n"); - } -#endif - - /* call the real completion handler when done or on an error */ - if ((stats != USB_ST_NOERROR) || - (req->_bytes_done >= req->length && req->completion != NULL)) { - *req->bytes_transferred_p += req->_bytes_done; -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req); -#endif - req->completion(stats, buffer, req->_bytes_done, req->dev_id); - } + return 0; +} /* ohci_request_irq() */ - return 0; /* do not re-queue the TD */ -} /* ohci_bulk_td_handler() */ +/* + * Control thread operations: + */ +static struct wait_queue *control_wakeup; /* - * Request to send or receive bulk data. The completion() function - * will be called when the transfer has completed or been aborted due - * to an error. + * This is the handler that gets called when a control transaction + * completes. * - * bytes_transferred_p is a pointer to an integer that will be - * set to the number of bytes that have been successfully - * transferred. The interrupt handler will update it after each - * internal TD completes successfully. + * This function is called from the interrupt handler. + */ +static int ohci_control_completed(int stats, void *buffer, void *dev_id) +{ + wake_up(&control_wakeup); + return 0; +} /* ohci_control_completed() */ + + +/* + * Send or receive a control message on a "pipe" * - * This function can NOT be called from an interrupt (?) - * (TODO: verify & fix this if needed). + * The cmd parameter is a pointer to the 8 byte setup command to be + * sent. FIXME: This is a devrequest in usb.h. The function + * should be updated to accept a devrequest* instead of void*.. * - * Returns: a pointer to the ED being used for this request. At the - * moment, removing & freeing it is the responsibilty of the caller. + * A control message contains: + * - The command itself + * - An optional data phase (if len > 0) + * - Status complete phase */ -static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_request) +static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len) { - /* local names for the readonly fields */ - struct usb_device *usb_dev = bulk_request->usb_dev; - unsigned int pipe = bulk_request->pipe; - void *data = bulk_request->data; - int len = bulk_request->length; - - struct ohci_device *dev = usb_to_ohci(usb_dev); - struct ohci_ed *bulk_ed; - struct ohci_td *head_td; - unsigned long flags; + struct ohci_device *dev = usb_to_ohci(usb); + /* + * ideally dev->ed should be linked into the root hub's + * control_ed list and used instead of just using it directly. + * This could present a problem as is with more than one + * device. (but who wants to use a keyboard AND a mouse + * anyways? ;) + */ + struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + struct ohci_td *setup_td, *data_td, *status_td; + struct wait_queue wait = { current, NULL }; -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len); +#if 0 + printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); #endif - bulk_ed = ohci_get_free_ed(dev); - if (!bulk_ed) { - printk(KERN_ERR "usb-ohci: couldn't get ED for dev %p\n", dev); - return NULL; - } - - /* allocate & fill in the TDs for this request */ - head_td = ohci_build_td_chain(dev, data, len, usb_pipeout(pipe), - TOGGLE_AUTO, - 0 /* round not required */, 1 /* autofree */, - bulk_request, /* dev_id: the bulk_request */ - ohci_bulk_td_handler, - 0 /* no additional TDs */); - if (!head_td) { - printk(KERN_ERR "usb-ohci: couldn't get TDs for dev %p\n", dev); - ohci_free_ed(bulk_ed); - return NULL; - } - - /* Set the max packet size, device speed, endpoint number, usb - * device number (function address), and type of TD. */ - ohci_fill_ed(dev, bulk_ed, - usb_maxpacket(usb_dev, pipe), - usb_pipeslow(pipe), - usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */); + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + * + */ + control_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; - /* initialize the toggle carry */ - if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) - ohci_ed_set_carry(bulk_ed); + /* + * Build the control TD + */ - /* initialize the internal counter */ - bulk_request->_bytes_done = 0; + /* get a TD to send this control message with */ + setup_td = ohci_get_free_td(dev); + /* TODO check for NULL */ /* - * Add the TDs to the ED + * Set the not accessed condition code, allow odd sized data, + * and set the data transfer type to SETUP. Setup DATA always + * uses a DATA0 packet. + * + * The setup packet contains a devrequest (usb.h) which + * will always be 8 bytes long. FIXME: the cmd parameter + * should be a pointer to one of these instead of a void* !!! */ - spin_lock_irqsave(&ohci_edtd_lock, flags); - head_td = ohci_add_tds_to_ed(head_td, bulk_ed); - bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - /* ohci_unhalt_ed(bulk_ed); */ - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - -#ifdef OHCI_DEBUG - if (MegaDebug > 1) { - /* complete request debugging output (before) */ - printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed)); - show_ohci_ed(bulk_ed); - printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td)); - show_ohci_td_chain(head_td); - } -#endif + ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0, + OHCI_TD_IOC_OFF, + cmd, 8, /* cmd is always 8 bytes long */ + NULL, NULL); - /* Give the ED to the HC */ - ohci_add_bulk_ed(dev->ohci, bulk_ed); + /* allocate the next TD */ + data_td = ohci_get_free_td(dev); /* TODO check for NULL */ - return bulk_ed; -} /* ohci_request_bulk() */ + /* link to the next TD */ + setup_td->next_td = virt_to_bus(data_td); + if (len > 0) { -static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); + /* build the Control DATA TD, it starts with a DATA1. */ + ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)), + TOGGLE_DATA1, + OHCI_TD_ROUND | OHCI_TD_IOC_OFF, + data, len, + NULL, NULL); + /* + * XXX we should check that the data buffer doesn't + * cross a 4096 byte boundary. If so, it needs to be + * copied into a single 4096 byte aligned area for the + * OHCI's TD logic to see it all, or multiple TDs need + * to be made for each page. + * + * It's not likely a control transfer will run into + * this problem.. (famous last words) + */ -static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id) -{ -#ifdef OHCI_DEBUG - if (MegaDebug) - printk("ohci_bulk_msg_completed %x, %p, %d, %p\n", stats, buffer, len, dev_id); -#endif - if (dev_id != NULL) { - int *completion_status = (int *)dev_id; - *completion_status = stats; + status_td = ohci_get_free_td(dev); /* TODO check for NULL */ + data_td->next_td = virt_to_bus(status_td); + } else { + status_td = data_td; /* no data_td, use it for status */ } - wake_up(&bulk_wakeup); - return 0; /* don't requeue the TD */ -} /* ohci_bulk_msg_completed() */ - - -static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, unsigned long *bytes_transferred_p) -{ - DECLARE_WAITQUEUE(wait, current); - int completion_status = USB_ST_INTERNALERROR; - struct ohci_bulk_request_state req; - struct ohci_ed *req_ed; - -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", - usb_dev, pipe, data, len, bytes_transferred_p); -#endif - - /* initialize bytes transferred to nothing */ - *bytes_transferred_p = 0; - - /* Hopefully this is similar to the "URP" (USB Request Packet) code - * that michael gee is working on... */ - req.usb_dev = usb_dev; - req.pipe = pipe; - req.data = data; - req.length = len; - req.bytes_transferred_p = bytes_transferred_p; - req.dev_id = &completion_status; - req.completion = ohci_bulk_msg_completed; - if (bytes_transferred_p) - *bytes_transferred_p = 0; - - if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe)) - && usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80))) - return USB_ST_STALL; + /* The control status packet always uses a DATA1 */ + ohci_fill_new_td(status_td, + td_set_dir_in(usb_pipeout(pipe) | (len == 0)), + TOGGLE_DATA1, + 0, + NULL, 0, + NULL, ohci_control_completed); + status_td->next_td = 0; /* end of TDs */ /* - * Start the transaction.. + * Start the control transaction.. */ current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&bulk_wakeup, &wait); - - req_ed = ohci_request_bulk(&req); - - /* FIXME this should to wait for a caller specified time... */ - schedule_timeout(HZ*5); - - /* completion_status will only stay in this state of the - * request never finished */ - if (completion_status == USB_ST_INTERNALERROR) { - struct ohci_device *dev = usb_to_ohci(usb_dev); - struct ohci_regs *regs = dev->ohci->regs; - -#ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci_bulk_msg timing out\n"); -#endif - /* XXX This code should go into a function used to stop - * a previously requested bulk transfer. -greg */ - - /* stop the transfer & collect the number of bytes */ - ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK); - - /* Get the number of bytes transferred out of the head TD - * on the ED if it didn't finish while we were waiting. */ - if ( ed_head_td(req_ed) && - (ed_head_td(req_ed) != ed_tail_td(req_ed)) ) { - struct ohci_td *partial_td; - partial_td = bus_to_virt(ed_head_td(req_ed)); - -#ifdef OHCI_DEBUG - if (MegaDebug) { - show_ohci_td(partial_td); - } -#endif - /* Record the bytes as transferred */ - *bytes_transferred_p += ohci_td_bytes_done(partial_td); - - /* If there was an unreported error, return it. - * Otherwise return a timeout */ - completion_status = OHCI_TD_CC_GET(partial_td->info); - if (completion_status == USB_ST_NOERROR) { - completion_status = USB_ST_TIMEOUT; - } - } + add_wait_queue(&control_wakeup, &wait); + /* + * Add the chain of 2-3 control TDs to the control ED's TD list + */ + { + unsigned long flags; + spin_lock_irqsave(&ohci_edtd_lock, flags); + ohci_add_td_to_ed(setup_td, control_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); } - remove_wait_queue(&bulk_wakeup, &wait); +#if 0 + /* complete transaction debugging output (before) */ + printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td)); + show_ohci_td(setup_td); + if (data_td != status_td) { + printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td)); + show_ohci_td(data_td); + } + printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td)); + show_ohci_td(status_td); +#endif - /* remove the ED from the HC */ - ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed); + /* Give the ED to the HC */ + ohci_add_control_ed(dev->ohci, control_ed); - /* save the toggle value back into the usb_dev */ - usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), - ohci_ed_carry(req_ed)); + /* FIXME: + * this should really check to see that the transaction completed. + */ + schedule_timeout(HZ/10); - ohci_free_ed(req_ed); /* return it to the pool */ + remove_wait_queue(&control_wakeup, &wait); -#ifdef OHCI_DEBUG - if (completion_status != 0 || MegaDebug) - printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", - completion_status, *bytes_transferred_p); +#if 0 + /* complete transaction debugging output (after) */ + printk(KERN_DEBUG " (after) Control ED:\n"); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " (after) Setup TD:\n"); + show_ohci_td(setup_td); + if (data_td != status_td) { + printk(KERN_DEBUG " (after) Data TD:\n"); + show_ohci_td(data_td); + } + printk(KERN_DEBUG " (after) Status TD:\n"); + show_ohci_td(status_td); #endif - return completion_status; -} /* ohci_bulk_msg() */ + /* clean up incase it failed */ + /* XXX only do this if their ed pointer still points to control_ed + * incase they've been reclaimed and used by something else + * already. -greg */ + ohci_remove_td_from_ed(setup_td, control_ed); + ohci_remove_td_from_ed(data_td, control_ed); + ohci_remove_td_from_ed(status_td, control_ed); + /* remove the control ED */ + ohci_remove_control_ed(dev->ohci, control_ed); -/* .......... */ +#if 0 + printk(KERN_DEBUG "leaving ohci_control_msg\n"); +#endif + return ohci_td_result(dev, status_td); +} /* ohci_control_msg() */ /* @@ -1559,7 +675,6 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent) { struct usb_device *usb_dev; struct ohci_device *dev; - int idx; /* * Allocate the generic USB device @@ -1581,12 +696,6 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent) memset(dev, 0, sizeof(*dev)); - /* Initialize all EDs in a new device with the skip flag so that - * they are ignored by the controller until set otherwise. */ - for (idx = 0; idx < NUM_EDS; ++idx) { - dev->ed[idx].status = cpu_to_le32(OHCI_ED_SKIP); - } - /* * Link them together */ @@ -1614,42 +723,12 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent) */ static int ohci_usb_deallocate(struct usb_device *usb_dev) { - struct ohci_device *dev = usb_to_ohci(usb_dev); - - ohci_remove_device(dev->ohci, usb_dev->devnum); - - /* kfree(usb_to_ohci(usb_dev)); */ - /* kfree(usb_dev); */ + kfree(usb_to_ohci(usb_dev)); + kfree(usb_dev); return 0; } -static void *ohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - return NULL; -} - -static void ohci_delete_isochronous (struct usb_device *dev, void *_isodesc) -{ - return; -} - -static int ohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - return USB_ST_NOTSUPPORTED; -} - -static int ohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; -} - -static int ohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; -} - - /* * functions for the generic USB driver */ @@ -1657,14 +736,7 @@ struct usb_operations ohci_device_operations = { ohci_usb_allocate, ohci_usb_deallocate, ohci_control_msg, - ohci_bulk_msg, ohci_request_irq, - ohci_release_irq, - ohci_alloc_isochronous, - ohci_delete_isochronous, - ohci_sched_isochronous, - ohci_unsched_isochronous, - ohci_compress_isochronous }; @@ -1677,25 +749,24 @@ struct usb_operations ohci_device_operations = { */ static int reset_hc(struct ohci *ohci) { - int timeout = 10000; /* prevent an infinite loop */ + int timeout = 1000; /* prevent an infinite loop */ + +#if 0 + printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci); +#endif writel(~0x0, &ohci->regs->intrdisable); /* Disable HC interrupts */ - /* this seems to be needed for the lucent controller on powerbooks... */ - writel(0, &ohci->regs->control); /* Move to reset state */ writel(1, &ohci->regs->cmdstatus); /* HC Reset */ - udelay(100); + writel_mask(0x3f, &ohci->regs->control); /* move to UsbReset state */ while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) { if (!--timeout) { - printk(KERN_ERR "usb-ohci: USB HC reset timed out!\n"); + printk("usb-ohci: USB HC reset timed out!\n"); return -1; } udelay(1); } - writel_mask(0x3f, &ohci->regs->control); /* move to UsbReset state */ - wait_ms(10); /* give the bus time to be reset */ - printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci); return 0; @@ -1708,34 +779,29 @@ static int reset_hc(struct ohci *ohci) static int start_hc(struct ohci *ohci) { int ret = 0; - int fminterval, pot; - __u32 what_to_enable; + int fminterval; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); + fminterval = readl(&ohci->regs->fminterval) & 0x3fff; +#if 0 + printk(KERN_DEBUG "entering start_hc %p\n", ohci); +#endif if (reset_hc(ohci) < 0) return -1; /* restore registers cleared by the reset */ - writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca); + writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca); /* - * fminterval has to be 11999 (it can be adjusted +/- 1 - * to sync with other things if necessary). + * XXX Should fminterval also be set here? + * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant) */ - fminterval = 11999; - + fminterval |= (0x2edf << 16); + writel(fminterval, &ohci->regs->fminterval); /* Start periodic transfers at 90% of fminterval (fmremaining * counts down; this will put them in the first 10% of the * frame). */ - writel((fminterval * 9) / 10, &ohci->regs->periodicstart); - - /* Set largest data packet counter and frame interval. */ - fminterval |= ((fminterval - 210) * 6 / 7) << 16; - writel(fminterval, &ohci->regs->fminterval); - - /* Set low-speed threshold (value from MacOS) */ - writel(1576, &ohci->regs->lsthresh); + writel((0x2edf*9)/10, &ohci->regs->periodicstart); /* * FNO (frame number overflow) could be enabled... they @@ -1743,40 +809,20 @@ static int start_hc(struct ohci *ohci) * useful for debugging and as a bus heartbeat. -greg */ /* Choose the interrupts we care about */ - what_to_enable = OHCI_INTR_MIE | -#ifdef OHCI_RHSC_INT - OHCI_INTR_RHSC | -#endif - /* | OHCI_INTR_FNO */ - OHCI_INTR_WDH; - writel( what_to_enable, &ohci->regs->intrenable); + writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */ + OHCI_INTR_WDH | OHCI_INTR_FNO, + &ohci->regs->intrenable); /* Enter the USB Operational state & start the frames a flowing.. */ - writel(OHCI_USB_OPER, &ohci->regs->control); + writel_set(OHCI_USB_OPER, &ohci->regs->control); /* Enable control lists */ writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control); - /* Force global power enable -gal@cs.uni-magdeburg.de */ - /* - * This turns on global power switching for all the ports - * and tells the HC that all of the ports should be powered on - * all of the time. - * - * TODO: This could be battery draining for laptops.. We - * should implement power switching. - */ - writel_set( OHCI_ROOT_A_NPS, &ohci->regs->roothub.a ); - writel_mask( ~(OHCI_ROOT_A_PSM), &ohci->regs->roothub.a ); - /* Turn on power to the root hub ports (thanks Roman!) */ writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status ); - /* wait for power-on to power-good time */ - pot = readl(&ohci->regs->roothub.a) >> 24; /* power-on time (* 2ms) */ - wait_ms(pot * 2); - - printk(KERN_INFO "usb-ohci: host controller operational\n"); + printk("usb-ohci: host controller operational\n"); return ret; } /* start_hc() */ @@ -1785,14 +831,14 @@ static int start_hc(struct ohci *ohci) /* * Reset a root hub port */ -static int ohci_reset_port(struct ohci *ohci, unsigned int port) +static void ohci_reset_port(struct ohci *ohci, unsigned int port) { int status; /* Don't allow overflows. */ if (port >= MAX_ROOT_PORTS) { - printk(KERN_ERR "usb-ohci: bad port #%d in ohci_reset_port\n", port); - return -1; + printk("usb-ohci: bad port #%d in ohci_reset_port\n", port); + port = MAX_ROOT_PORTS-1; } writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); /* Reset */ @@ -1800,21 +846,20 @@ static int ohci_reset_port(struct ohci *ohci, unsigned int port) /* * Wait for the reset to complete. */ - wait_ms(20); + wait_ms(10); /* check port status to see that the reset completed */ status = readl(&ohci->regs->roothub.portstatus[port]); if (status & PORT_PRS) { /* reset failed, try harder? */ - printk(KERN_ERR "usb-ohci: port %d reset failed\n", port); - show_ohci_status(ohci); - return -1; + printk("usb-ohci: port %d reset failed, retrying\n", port); + writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); + wait_ms(50); } /* TODO we might need to re-enable the port here or is that * done elsewhere? */ - return 0; } /* ohci_reset_port */ @@ -1825,47 +870,31 @@ static void ohci_connect_change(struct ohci * ohci, int port) { struct usb_device *usb_dev; struct ohci_device *dev; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); /* memory I/O address of the port status register */ - __u32 *portaddr = &ohci->regs->roothub.portstatus[port]; + void *portaddr = &ohci->regs->roothub.portstatus[port]; int portstatus; + printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port); + /* * Because of the status change we have to forget * everything we think we know about the device * on this root hub port. It may have changed. */ - usb_disconnect(root_hub->usb->children + port); + usb_disconnect(ohci->root_hub->usb->children + port); portstatus = readl(portaddr); -#ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci_connect_change on port %d, status=%x\n", - port, portstatus); -#endif - /* disable the port if nothing is connected */ if (!(portstatus & PORT_CCS)) { writel(PORT_CCS, portaddr); - /* We need to reset the CSC bit -after- disabling the - * port because it causes the CSC bit to come on - * again... */ - wait_ms(20); - writel(PORT_CSC, portaddr); -#ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci port %d disabled, nothing connected.\n", port); -#endif return; } - if (ohci_reset_port(ohci, port) < 0) - return; - wait_ms(10); /* give the device a while to get reset */ - /* * Allocate a device for the new thingy that's been attached */ - usb_dev = ohci_usb_allocate(root_hub->usb); + usb_dev = ohci_usb_allocate(ohci->root_hub->usb); dev = usb_dev->hcpriv; dev->ohci = ohci; @@ -1873,7 +902,10 @@ static void ohci_connect_change(struct ohci * ohci, int port) usb_connect(dev->usb); /* link it into the bus's device tree */ - root_hub->usb->children[port] = usb_dev; + ohci->root_hub->usb->children[port] = usb_dev; + + wait_ms(200); /* wait for powerup; XXX is this needed? */ + ohci_reset_port(ohci, port); /* Get information on speed by using LSD */ usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0; @@ -1896,24 +928,23 @@ static void ohci_check_configuration(struct ohci *ohci) struct ohci_regs *regs = ohci->regs; int num = 0; int maxport = readl(&ohci->regs->roothub) & 0xff; - __u32 rh_change_flags = PORT_CSC | PORT_PESC; /* root hub status changes */ -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci); +#if 1 + printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci); #endif do { - __u32 *portstatus_p = ®s->roothub.portstatus[num]; - if (readl(portstatus_p) & rh_change_flags) { - /* acknowledge the root hub status changes */ - writel_set(rh_change_flags, portstatus_p); - /* disable the port if nothing is on it */ + if (readl(®s->roothub.portstatus[num]) & PORT_CSC) { + /* reset the connect status change bit */ + writel(PORT_CSC, ®s->roothub.portstatus[num]); /* check the port for a nifty device */ ohci_connect_change(ohci, num); } } while (++num < maxport); +#if 0 + printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci); +#endif } /* ohci_check_configuration() */ @@ -1926,21 +957,19 @@ static void ohci_check_configuration(struct ohci *ohci) */ static void ohci_root_hub_events(struct ohci *ohci) { - int num = 0; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - int maxport = root_hub->usb->maxchild; + if (waitqueue_active(&ohci_configure)) { + int num = 0; + int maxport = ohci->root_hub->usb->maxchild; - if (!waitqueue_active(&ohci_configure)) - return; - do { - __u32 *portstatus_p = &ohci->regs->roothub.portstatus[num]; - if (readl(portstatus_p) & PORT_CSC) { - if (waitqueue_active(&ohci_configure)) - wake_up(&ohci_configure); - return; - } - } while (++num < maxport); - + do { + if (readl(&ohci->regs->roothub.portstatus[num]) & + PORT_CSC) { + if (waitqueue_active(&ohci_configure)) + wake_up(&ohci_configure); + return; + } + } while (++num < maxport); + } } /* ohci_root_hub_events() */ @@ -1956,19 +985,19 @@ static void ohci_root_hub_events(struct ohci *ohci) static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci) { __u32 td_list_hc; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - struct ohci_hcca *hcca = root_hub->hcca; + struct ohci_hcca *hcca = ohci->root_hub->hcca; struct ohci_td *td_list = NULL; struct ohci_td *td_rev = NULL; - - td_list_hc = le32_to_cpup(&hcca->donehead) & 0xfffffff0; + + td_list_hc = hcca->donehead & 0xfffffff0; hcca->donehead = 0; while(td_list_hc) { td_list = (struct ohci_td *) bus_to_virt(td_list_hc); td_list->next_dl_td = td_rev; + td_rev = td_list; - td_list_hc = le32_to_cpup(&td_list->next_td) & 0xfffffff0; + td_list_hc = td_list->next_td & 0xfffffff0; } return td_list; @@ -1985,8 +1014,6 @@ static void ohci_reap_donelist(struct ohci *ohci) { struct ohci_td *td; /* used for walking the list */ - /* um... isn't this dangerous to do in an interrupt handler? -greg */ - /* nope. -paulus */ spin_lock(&ohci_edtd_lock); /* create the FIFO ordered donelist */ @@ -1994,85 +1021,27 @@ static void ohci_reap_donelist(struct ohci *ohci) while (td != NULL) { struct ohci_td *next_td = td->next_dl_td; - int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info)); - struct ohci_ed *ed = td->ed; - - if (td_dummy(*td)) - printk(KERN_ERR "yikes! reaping a dummy TD\n"); - -#ifdef OHCI_DEBUG - if (cc != 0 && MegaDebug) { - printk(KERN_DEBUG "cc=%s on td %p (ed %p)\n", cc_names[cc], td, ed); - show_ohci_td(td); - show_ohci_ed(ed); - if (ed_head_td(ed) != ed_tail_td(ed)) - show_ohci_td_chain(bus_to_virt(ed_head_td(ed))); - } -#endif - - if (cc == USB_ST_STALL) { - /* mark endpoint as halted */ - usb_endpoint_halt(ed->ohci_dev->usb, ed_get_en(ed)); - } - - if (cc != 0 && ohci_ed_halted(ed) && !td_endofchain(*td)) { - /* - * There was an error on this TD and the ED - * is halted, and this was not the last TD - * of the transaction, so there will be TDs - * to clean off the ED. - */ - struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed)); - struct ohci_td *ntd; - - ohci_free_td(td); - td = ntd = bus_to_virt(ed_head_td(ed)); - while (td != tail_td) { - ntd = bus_to_virt(le32_to_cpup(&td->next_td)); - if (td_endofchain(*td)) - break; - - if (MegaDebug) - printk(KERN_DEBUG "skipping TD %p\n", td); - ohci_free_td(td); - - td = ntd; - } - /* Set the ED head past the ones we cleaned - off, and clear the halted flag */ - if (MegaDebug) - printk(KERN_DEBUG "restarting ED %p at TD %p\n", ed, ntd); - set_ed_head_td(ed, virt_to_bus(ntd)); - ohci_unhalt_ed(ed); - /* If we didn't find an endofchain TD, give up */ - if (td == tail_td) { - td = next_td; - continue; - } - } + /* FIXME: munge td->info into a future standard status format */ /* Check if TD should be re-queued */ if ((td->completed != NULL) && - (td->completed(cc, td->data, ohci_td_bytes_done(td), td->dev_id))) { + (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id))) + { /* Mark the TD as active again: * Set the not accessed condition code - * Reset the Error count + * FIXME: should this reset OHCI_TD_ERRCNT? */ - td->info |= cpu_to_le32(OHCI_TD_CC_NEW); - clear_td_errorcount(td); - /* reset the toggle field to TOGGLE_AUTO (0) */ - td->info &= cpu_to_le32(~OHCI_TD_DT); + td->info |= OHCI_TD_CC_NEW; /* point it back to the start of the data buffer */ - td->cur_buf = cpu_to_le32(virt_to_bus(td->data)); + td->cur_buf = virt_to_bus(td->data); + /* XXX disabled for debugging reasons right now.. */ /* insert it back on its ED */ - td->next_td = 0; - ohci_add_tds_to_ed(td, ed); + ohci_add_td_to_ed(td, td->ed); } else { /* return it to the pool of free TDs */ - if (can_auto_free(*td)) - ohci_free_td(td); + ohci_free_td(td); } td = next_td; @@ -2082,6 +1051,9 @@ static void ohci_reap_donelist(struct ohci *ohci) } /* ohci_reap_donelist() */ +#if 0 +static int in_int = 0; +#endif /* * Get annoyed at the controller for bothering us. * This pretty much follows the OHCI v1.0a spec, section 5.3. @@ -2090,18 +1062,26 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) { struct ohci *ohci = __ohci; struct ohci_regs *regs = ohci->regs; - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); - struct ohci_hcca *hcca = root_hub->hcca; + struct ohci_hcca *hcca = ohci->root_hub->hcca; __u32 status, context; +#if 0 + /* for debugging to keep IRQs from running away. */ + if (in_int >= 2) + return; + ++in_int; + return; +#endif + /* Save the status of the interrupts that are enabled */ status = readl(®s->intrstatus); status &= readl(®s->intrenable); + /* make context = the interrupt status bits that we care about */ if (hcca->donehead != 0) { context = OHCI_INTR_WDH; /* hcca donehead needs processing */ - if (hcca->donehead & cpu_to_le32(1)) { + if (hcca->donehead & 1) { context |= status; /* other status change to check */ } } else { @@ -2112,32 +1092,21 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) } } - /* Disable HC interrupts */ /* why? - paulus */ + /* Disable HC interrupts */ writel(OHCI_INTR_MIE, ®s->intrdisable); -#if 0 - /* Only do this for SERIOUS debugging, be sure kern.debug logs - * are not going to the console as this can cause your - * machine to lock up if so... -greg */ - show_ohci_status(ohci); -#endif - /* Process the done list */ if (context & OHCI_INTR_WDH) { /* See which TD's completed.. */ ohci_reap_donelist(ohci); /* reset the done queue and tell the controller */ - hcca->donehead = 0; /* XXX already done in ohci_reverse_donelist */ + hcca->donehead = 0; writel(OHCI_INTR_WDH, ®s->intrstatus); context &= ~OHCI_INTR_WDH; /* mark this as checked */ } -#ifdef OHCI_RHSC_INT - /* NOTE: this is very funky on some USB controllers (ie: it - * doesn't work right). Using the ohci_timer instead to poll - * the root hub is a much better choice. */ /* Process any root hub status changes */ if (context & OHCI_INTR_RHSC) { /* Wake the thread to process root hub events */ @@ -2150,17 +1119,10 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) * The control thread will re-enable it after it has * checked the root hub status. */ - } -#endif - - /* Start of Frame interrupts, used during safe ED removal */ - if (context & (OHCI_INTR_SF)) { - writel(OHCI_INTR_SF, ®s->intrstatus); - if (waitqueue_active(&start_of_frame_wakeup)) - wake_up(&start_of_frame_wakeup); - /* Do NOT mark the frame start interrupt as checked - * as we don't want to receive any more of them until - * asked. */ + } else { + /* check the root hub status anyways. Some controllers + * might not generate the interrupt properly. (?) */ + ohci_root_hub_events(ohci); } /* Check those "other" pesky bits */ @@ -2189,8 +1151,8 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) context &= ~OHCI_INTR_OC; /* mark this as checked */ } - /* Mask out any remaining unprocessed or unmasked interrupts - * so that we don't get any more of them. */ + /* Mask out any remaining unprocessed interrupts so we don't + * get any more of them. */ if (context & ~OHCI_INTR_MIE) { writel(context, ®s->intrdisable); } @@ -2217,6 +1179,10 @@ static struct ohci *alloc_ohci(void* mem_base) struct ohci_device *dev; struct usb_device *usb; +#if 0 + printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base); +#endif + ohci = kmalloc(sizeof(*ohci), GFP_KERNEL); if (!ohci) return NULL; @@ -2249,8 +1215,8 @@ static struct ohci *alloc_ohci(void* mem_base) if (!usb) return NULL; - dev = usb_to_ohci(usb); - ohci->bus->root_hub= ohci_to_usb(dev); + dev = ohci->root_hub = usb_to_ohci(usb); + usb->bus = bus; /* Initialize the root hub */ @@ -2262,8 +1228,7 @@ static struct ohci *alloc_ohci(void* mem_base) * page as that's guaranteed to have a nice boundary. */ dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL); - memset(dev->hcca, 0, sizeof(struct ohci_hcca)); - + /* Tell the controller where the HCCA is */ writel(virt_to_bus(dev->hcca), &ohci->regs->hcca); @@ -2274,62 +1239,66 @@ static struct ohci *alloc_ohci(void* mem_base) /* Get the number of ports on the root hub */ usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff; if (usb->maxchild > MAX_ROOT_PORTS) { - printk(KERN_INFO "usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS); + printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS); usb->maxchild = MAX_ROOT_PORTS; } if (usb->maxchild < 1) { - printk(KERN_ERR "usb-ohci: Less than one root hub port? Impossible!\n"); + printk("usb-ohci: Less than one root hub port? Impossible!\n"); usb->maxchild = 1; } - printk(KERN_DEBUG "usb-ohci: %d root hub ports found\n", usb->maxchild); + printk("usb-ohci: %d root hub ports found\n", usb->maxchild); /* * Initialize the ED polling "tree" (for simplicity's sake in * this driver many nodes in the tree will be identical) */ - dev->ed[ED_INT_32].next_ed = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_16])); - dev->ed[ED_INT_16].next_ed = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_8])); - dev->ed[ED_INT_8].next_ed = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_4])); - dev->ed[ED_INT_4].next_ed = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_2])); - dev->ed[ED_INT_2].next_ed = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_1])); + dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]); + dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]); + dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]); + dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]); + dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]); /* * Initialize the polling table to call interrupts at the - * intended intervals. Note that these EDs are just - * placeholders. They have their SKIP bit set and are used as - * list heads to insert real EDs onto. + * intended intervals. */ - dev->hcca->int_table[0] = cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_1])); + dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]); for (i = 1; i < NUM_INTS; i++) { - if (i & 16) + if (i & 1) dev->hcca->int_table[i] = - cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_32])); - if (i & 8) + virt_to_bus(&dev->ed[ED_INT_16]); + else if (i & 2) dev->hcca->int_table[i] = - cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_16])); - if (i & 4) + virt_to_bus(&dev->ed[ED_INT_8]); + else if (i & 4) dev->hcca->int_table[i] = - cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_8])); - if (i & 2) + virt_to_bus(&dev->ed[ED_INT_4]); + else if (i & 8) dev->hcca->int_table[i] = - cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_4])); - if (i & 1) + virt_to_bus(&dev->ed[ED_INT_2]); + else if (i & 16) dev->hcca->int_table[i] = - cpu_to_le32(virt_to_bus(&dev->ed[ED_INT_2])); + virt_to_bus(&dev->ed[ED_INT_1]); } /* - * Tell the controller where the control and bulk lists are. + * Tell the controller where the control and bulk lists are * The lists start out empty. */ writel(0, &ohci->regs->ed_controlhead); writel(0, &ohci->regs->ed_bulkhead); + /* + writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead); + writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead); + */ -#ifdef OHCI_DEBUG - if (MegaDebug) { - printk(KERN_DEBUG "alloc_ohci(): controller\n"); - show_ohci_status(ohci); - } +#if 0 + printk(KERN_DEBUG "alloc_ohci(): controller\n"); + show_ohci_status(ohci); +#endif + +#if 0 + printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci); #endif return ohci; @@ -2341,7 +1310,7 @@ static struct ohci *alloc_ohci(void* mem_base) */ static void release_ohci(struct ohci *ohci) { - printk(KERN_DEBUG "Releasing OHCI controller 0x%p\n", ohci); + printk(KERN_DEBUG "entering release_ohci %p\n", ohci); #ifdef OHCI_TIMER /* stop our timer */ @@ -2355,14 +1324,13 @@ static void release_ohci(struct ohci *ohci) /* stop all OHCI interrupts */ writel(~0x0, &ohci->regs->intrdisable); - if (ohci->bus->root_hub) { - struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); + if (ohci->root_hub) { /* ensure that HC is stopped before releasing the HCCA */ writel(OHCI_USB_SUSPEND, &ohci->regs->control); - free_page((unsigned long) root_hub->hcca); - kfree(ohci->bus->root_hub); - root_hub->hcca = NULL; - ohci->bus->root_hub = NULL; + free_page((unsigned long) ohci->root_hub->hcca); + kfree(ohci->root_hub); + ohci->root_hub->hcca = NULL; + ohci->root_hub = NULL; } /* unmap the IO address space */ @@ -2395,23 +1363,20 @@ static int ohci_control_thread(void * __ohci) * This thread doesn't need any user-level access, * so get rid of all of our resources.. */ - printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread); + printk("ohci_control_thread code at %p\n", &ohci_control_thread); exit_mm(current); exit_files(current); - /*exit_fs(current);*/ /* can't do kernel_thread if we do this */ + exit_fs(current); strcpy(current->comm, "ohci-control"); - usb_register_bus(ohci->bus); - /* * Damn the torpedoes, full speed ahead */ if (start_hc(ohci) < 0) { - printk(KERN_ERR "usb-ohci: failed to start the controller\n"); + printk("usb-ohci: failed to start the controller\n"); release_ohci(ohci); - usb_deregister_bus(ohci->bus); - printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci); + printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); return 0; } @@ -2425,12 +1390,11 @@ static int ohci_control_thread(void * __ohci) ohci_check_configuration(ohci); /* re-enable root hub status change interrupts. */ -#ifdef OHCI_RHSC_INT +#if 0 writel(OHCI_INTR_RHSC, &ohci->regs->intrenable); #endif - if (MegaDebug) - printk(KERN_DEBUG "ohci-control thread sleeping\n"); + printk(KERN_DEBUG "ohci-control thread sleeping\n"); interruptible_sleep_on(&ohci_configure); #ifdef CONFIG_APM if (apm_resume) { @@ -2452,19 +1416,11 @@ static int ohci_control_thread(void * __ohci) spin_unlock_irq(¤t->sigmask_lock); if(signr == SIGUSR1) { - /* TODO: have it do a full ed/td queue dump? */ + /* FIXME: have it do a full ed/td queue dump */ printk(KERN_DEBUG "OHCI status dump:\n"); show_ohci_status(ohci); - } else if (signr == SIGUSR2) { - /* toggle mega TD/ED debugging output */ -#ifdef OHCI_DEBUG - MegaDebug = (MegaDebug + 1) & 3; - printk(KERN_DEBUG "usb-ohci: Mega debugging level %d.\n", - MegaDebug); -#endif } else { /* unknown signal, exit the thread */ - printk(KERN_DEBUG "usb-ohci: control thread for %p exiting on signal %ld\n", __ohci, signr); break; } } @@ -2472,7 +1428,8 @@ static int ohci_control_thread(void * __ohci) reset_hc(ohci); release_ohci(ohci); - usb_deregister_bus(ohci->bus); + + printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); return 0; } /* ohci_control_thread() */ @@ -2513,12 +1470,9 @@ static int handle_apm_event(apm_event_t event) #ifdef OHCI_TIMER /* * Inspired by Iñaky's driver. This function is a timer routine that - * is called every OHCI_TIMER_FREQ ms. It polls the root hub for - * status changes as on my system the RHSC interrupt just doesn't - * play well with others.. (so RHSC is turned off by default in this - * driver) - * [my controller is a "SiS 7001 USB (rev 16)"] - * -greg + * is called OHCI_TIMER_FREQ times per second. It polls the root hub + * for status changes as on my system things are acting a bit odd at + * the moment.. */ static void ohci_timer_func (unsigned long ohci_ptr) { @@ -2526,9 +1480,8 @@ static void ohci_timer_func (unsigned long ohci_ptr) ohci_root_hub_events(ohci); - /* set the next timer */ - mod_timer(&ohci_timer, jiffies + ((OHCI_TIMER_FREQ*HZ)/1000)); - + /* press the snooze button... */ + mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ)); } /* ohci_timer_func() */ #endif @@ -2542,6 +1495,10 @@ static int found_ohci(int irq, void* mem_base) int retval; struct ohci *ohci; +#if 0 + printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base); +#endif + /* Allocate the running OHCI structures */ ohci = alloc_ohci(mem_base); if (!ohci) { @@ -2550,10 +1507,9 @@ static int found_ohci(int irq, void* mem_base) #ifdef OHCI_TIMER init_timer(&ohci_timer); - ohci_timer.expires = jiffies + ((OHCI_TIMER_FREQ*HZ)/1000); + ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ); ohci_timer.data = (unsigned long)ohci; ohci_timer.function = ohci_timer_func; - add_timer(&ohci_timer); #endif retval = -EBUSY; @@ -2562,8 +1518,8 @@ static int found_ohci(int irq, void* mem_base) ohci->irq = irq; -#ifdef OHCI_DEBUG - printk(KERN_DEBUG "usb-ohci: forking ohci-control thread for 0x%p\n", ohci); +#if 0 + printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n"); #endif /* fork off the handler */ @@ -2575,10 +1531,14 @@ static int found_ohci(int irq, void* mem_base) retval = pid; } else { - printk(KERN_ERR "usb-ohci: Couldn't allocate interrupt %d\n", irq); + printk("usb-ohci: Couldn't allocate interrupt %d\n", irq); } release_ohci(ohci); +#if 0 + printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base); +#endif + return retval; } /* found_ohci() */ @@ -2599,7 +1559,7 @@ static int init_ohci(struct pci_dev *dev) /* no interrupt won't work... */ if (dev->irq == 0) { - printk(KERN_ERR "usb-ohci: no irq assigned? check your BIOS settings.\n"); + printk("usb-ohci: no irq assigned? check your BIOS settings.\n"); return -ENODEV; } @@ -2612,16 +1572,11 @@ static int init_ohci(struct pci_dev *dev) mem_base = (unsigned long) ioremap_nocache(mem_base, 4096); if (!mem_base) { - printk(KERN_ERR "Error mapping OHCI memory\n"); + printk("Error mapping OHCI memory\n"); return -EFAULT; } MOD_INC_USE_COUNT; -#ifdef OHCI_DEBUG - printk(KERN_INFO "usb-ohci: Warning! Gobs of debugging output has been enabled.\n"); - printk(KERN_INFO " Check your kern.debug logs for the bulk of it.\n"); -#endif - if (found_ohci(dev->irq, (void *) mem_base) < 0) { MOD_DEC_USE_COUNT; return -1; @@ -2630,6 +1585,26 @@ static int init_ohci(struct pci_dev *dev) return 0; } /* init_ohci() */ +#ifdef MODULE +/* + * Clean up when unloading the module + */ +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif + printk("usb-ohci: module unloaded\n"); +} + +#define ohci_init init_module + +#endif + + /* TODO this should be named following Linux convention and go in pci.h */ #define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010) @@ -2646,11 +1621,11 @@ int ohci_init(void) /*u8 type;*/ if (sizeof(struct ohci_device) > 4096) { - printk(KERN_ERR "usb-ohci: struct ohci_device to large\n"); + printk("usb-ohci: struct ohci_device to large\n"); return -ENODEV; } - printk(KERN_INFO "OHCI USB Driver loading\n"); + printk("OHCI USB Driver loading\n"); retval = -ENODEV; for (;;) { @@ -2669,6 +1644,18 @@ int ohci_init(void) if (retval < 0) continue; + /* TODO check module params here to determine what to load */ + +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif @@ -2678,22 +1665,5 @@ int ohci_init(void) return retval; } /* ohci_init */ - -#ifdef MODULE -/* - * Clean up when unloading the module - */ -void cleanup_module(void){ -# ifdef CONFIG_APM - apm_unregister_callback(&handle_apm_event); -# endif - printk(KERN_ERR "usb-ohci: module unloaded\n"); -} - -int init_module(void){ - return ohci_init(); -} -#endif //MODULE - /* vim:sw=8 */ diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h index 4bb71c55ce2e..8714cd2e833b 100644 --- a/drivers/usb/ohci.h +++ b/drivers/usb/ohci.h @@ -6,7 +6,7 @@ * * (C) Copyright 1999 Gregory P. Smith * - * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $ + * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $ */ #include @@ -37,16 +37,11 @@ struct ohci_td { struct ohci_td *next_dl_td; /* used during donelist processing */ void *data; /* virt. address of the the buffer */ usb_device_irq completed; /* Completion handler routine */ - int hcd_flags; /* Flags for the HCD: */ - /* bit0: Is this TD allocated? */ - /* bit1: Is this a dummy (end of list) TD? */ - /* bit2: do NOT automatically free this TD on completion */ - /* bit3: this is the last TD in a contiguious TD chain */ - - struct usb_device *usb_dev; /* the owning device */ + int allocated; /* boolean: is this TD allocated? */ + /* User or Device class driver specific fields */ void *dev_id; /* user defined pointer passed to irq handler */ -} __attribute((aligned(32))); +} __attribute((aligned(16))); #define OHCI_TD_ROUND (1 << 18) /* buffer rounding bit */ #define OHCI_TD_D (3 << 19) /* direction of xfer: */ @@ -57,46 +52,25 @@ struct ohci_td { #define td_set_dir_out(d) ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN ) #define OHCI_TD_IOC_DELAY (7 << 21) /* frame delay allowed before int. */ #define OHCI_TD_IOC_OFF (OHCI_TD_IOC_DELAY) /* no interrupt on complete */ -#define td_set_ioc_delay(frames) (((frames) & 7) << 21) #define OHCI_TD_DT (3 << 24) /* data toggle bits */ #define TOGGLE_AUTO (0 << 24) /* automatic (from the ED) */ #define TOGGLE_DATA0 (2 << 24) /* force Data0 */ #define TOGGLE_DATA1 (3 << 24) /* force Data1 */ #define td_force_toggle(b) (((b) | 2) << 24) #define OHCI_TD_ERRCNT (3 << 26) /* error count */ -#define td_errorcount(td) ((le32_to_cpup(&(td).info) >> 26) & 3) -#define clear_td_errorcount(td) ((td)->info &= cpu_to_le32(~(__u32)OHCI_TD_ERRCNT)) +#define td_errorcount(td) (((td).info >> 26) & 3) #define OHCI_TD_CC (0xf << 28) /* condition code */ #define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf) #define OHCI_TD_CC_NEW (OHCI_TD_CC) /* set this on all unaccessed TDs! */ -#define td_cc_notaccessed(td) ((le32_to_cpup(&(td).info) >> 29) == 7) -#define td_cc_accessed(td) ((le32_to_cpup(&(td).info) >> 29) != 7) -#define td_cc_noerror(td) (((le32_to_cpup(&(td).info)) & OHCI_TD_CC) == 0) +#define td_cc_notaccessed(td) (((td).info >> 29) == 7) +#define td_cc_accessed(td) (((td).info >> 29) != 7) +#define td_cc_noerror(td) ((((td).info) & OHCI_TD_CC) == 0) +#define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) #define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) -/* - * Macros to use the td->hcd_flags field. - */ -#define td_allocated(td) ((td).hcd_flags & 1) -#define allocate_td(td) ((td)->hcd_flags |= 1) -#define ohci_free_td(td) ((td)->hcd_flags &= ~(__u32)1) - -#define td_dummy(td) ((td).hcd_flags & 2) -#define make_dumb_td(td) ((td)->hcd_flags |= 2) -#define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2) - -#define td_endofchain(td) ((td).hcd_flags & (1 << 3)) -#define clear_td_endofchain(td) ((td)->hcd_flags &= ~(1 << 3)) -#define set_td_endofchain(td) ((td)->hcd_flags |= (1 << 3)) - -/* - * These control if the IRQ will call ohci_free_td after taking the TDs - * off of the donelist (assuming the completion function does not ask - * for the TD to be requeued). - */ -#define can_auto_free(td) (!((td).hcd_flags & 4)) -#define noauto_free_td(td) ((td)->hcd_flags |= 4) -#define auto_free_td(td) ((td)->hcd_flags &= ~(__u32)4) +#define td_allocated(td) ((td).allocated) +#define allocate_td(td) ((td)->allocated = 1) +#define ohci_free_td(td) ((td)->allocated = 0) /* @@ -108,27 +82,13 @@ struct ohci_ed { __u32 tail_td; /* TD Queue tail pointer */ __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */ __u32 next_ed; /* Next ED */ - - /* driver fields */ - struct ohci_device *ohci_dev; - struct ohci_ed *ed_chain; } __attribute((aligned(16))); /* get the head_td */ -#define ed_head_td(ed) (le32_to_cpup(&(ed)->_head_td) & 0xfffffff0) -#define ed_tail_td(ed) (le32_to_cpup(&(ed)->tail_td)) +#define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0) -/* save the carry & halted flag while setting the head_td */ -#define set_ed_head_td(ed, td) ((ed)->_head_td = cpu_to_le32((td)) \ - | ((ed)->_head_td & cpu_to_le32(3))) - -/* Control the ED's halted and carry flags */ -#define ohci_halt_ed(ed) ((ed)->_head_td |= cpu_to_le32(1)) -#define ohci_unhalt_ed(ed) ((ed)->_head_td &= cpu_to_le32(~(__u32)1)) -#define ohci_ed_halted(ed) ((ed)->_head_td & cpu_to_le32(1)) -#define ohci_ed_set_carry(ed) ((ed)->_head_td |= cpu_to_le32(2)) -#define ohci_ed_clr_carry(ed) ((ed)->_head_td &= ~cpu_to_le32(2)) -#define ohci_ed_carry(ed) ((le32_to_cpup(&(ed)->_head_td) >> 1) & 1) +/* save the carry flag while setting the head_td */ +#define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3)) #define OHCI_ED_SKIP (1 << 14) #define OHCI_ED_MPS (0x7ff << 16) @@ -148,17 +108,15 @@ struct ohci_ed { #define OHCI_ED_EN (0xf << 7) #define OHCI_ED_FA (0x7f) -#define ed_get_en(ed) ((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7) -#define ed_get_fa(ed) (le32_to_cpup(&(ed)->status) & OHCI_ED_FA) -/* NOTE: bits 27-31 of the status dword are reserved for the HCD */ +/* NOTE: bits 27-31 of the status dword are reserved for the driver */ /* * We'll use this status flag for to mark if an ED is in use by the - * driver or not. If the bit is set, it is being used. + * driver or not. If the bit is set, it is used. + * + * FIXME: implement this! */ -#define ED_ALLOCATED (1 << 31) -#define ed_allocated(ed) (le32_to_cpup(&(ed).status) & ED_ALLOCATED) -#define allocate_ed(ed) ((ed)->status |= cpu_to_le32(ED_ALLOCATED)) +#define ED_USED (1 << 31) /* * The HCCA (Host Controller Communications Area) is a 256 byte @@ -220,21 +178,20 @@ struct ohci_device { struct ohci_td td[NUM_TDS]; /* Transfer Descriptors */ unsigned long data[DATA_BUF_LEN]; -} __attribute((aligned(32))); +}; /* .... */ -/* - * These are the index of the placeholder EDs for the root hub to - * build the interrupt transfer ED tree out of. - */ #define ED_INT_1 0 #define ED_INT_2 1 #define ED_INT_4 2 #define ED_INT_8 3 #define ED_INT_16 4 #define ED_INT_32 5 +#define ED_CONTROL 6 +#define ED_BULK 7 #define ED_ISO ED_INT_1 /* same as 1ms interrupt queue */ +#define ED_FIRST_AVAIL 8 /* first non-reserved ED */ /* * Given a period p in ms, convert it to the closest endpoint @@ -253,9 +210,7 @@ struct ohci_device { * This is the maximum number of root hub ports. I don't think we'll * ever see more than two as that's the space available on an ATX * motherboard's case, but it could happen. The OHCI spec allows for - * up to 15... (which is insane given that they each need to supply up - * to 500ma; that would be 7.5 amps!). I have seen a PCI card with 4 - * downstream ports on it. + * up to 15... (which is insane!) * * Although I suppose several "ports" could be connected directly to * internal laptop devices such as a keyboard, mouse, camera and @@ -299,24 +254,15 @@ struct ohci_regs { } roothub; } __attribute((aligned(32))); -/* - * These are used by internal ED managing functions as a - * parameter to state the type of ED to deal with (when it matters). - */ -#define HCD_ED_ISOC (0) -#define HCD_ED_INT (1) -#define HCD_ED_CONTROL (2) -#define HCD_ED_BULK (3) - /* * Read a MMIO register and re-write it after ANDing with (m) */ -#define writel_mask(m, a) writel( (readl((unsigned long)(a))) & (__u32)(m), (unsigned long)(a) ) +#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) /* * Read a MMIO register and re-write it after ORing with (b) */ -#define writel_set(b, a) writel( (readl((unsigned long)(a))) | (__u32)(b), (unsigned long)(a) ) +#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) #define PORT_CCS (1) /* port current connect status */ @@ -342,16 +288,6 @@ struct ohci_regs { #define OHCI_ROOT_OCIC (1 << 17) /* Overcurrent indicator change */ #define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */ -/* - * Root hub A register masks - */ -#define OHCI_ROOT_A_NPS (1 << 9) -#define OHCI_ROOT_A_PSM (1 << 8) - -/* - * Root hub B register masks - */ - /* * Interrupt register masks */ @@ -398,15 +334,12 @@ struct ohci { struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */ }; -#define OHCI_TIMER /* enable the OHCI timer */ -#define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */ - -#undef OHCI_RHSC_INT /* Don't use root hub status interrupts! */ +#define OHCI_TIMER +#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */ -/* Debugging code [ohci-debug.c] */ +/* Debugging code */ void show_ohci_ed(struct ohci_ed *ed); void show_ohci_td(struct ohci_td *td); -void show_ohci_td_chain(struct ohci_td *td); void show_ohci_status(struct ohci *ohci); void show_ohci_device(struct ohci_device *dev); void show_ohci_hcca(struct ohci_hcca *hcca); diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c deleted file mode 100644 index 84083ce4654b..000000000000 --- a/drivers/usb/printer.c +++ /dev/null @@ -1,420 +0,0 @@ - -/* Driver for USB Printers - * - * (C) Michael Gee (michael@linuxspecific.com) 1999 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usb.h" - -#define NAK_TIMEOUT (HZ) /* stall wait for printer */ -#define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT) /* should not take 1 minute a page! */ - -#ifndef USB_PRINTER_MAJOR -#define USB_PRINTER_MAJOR 63 -#endif - -static int mymajor = USB_PRINTER_MAJOR; - -#define MAX_PRINTERS 8 - -struct pp_usb_data { - struct usb_device *pusb_dev; - __u8 isopen; /* nz if open */ - __u8 noinput; /* nz if no input stream */ - __u8 minor; /* minor number of device */ - __u8 status; /* last status from device */ - int maxin, maxout; /* max transfer size in and out */ - char *obuf; /* transfer buffer (out only) */ - wait_queue_head_t wait_q; /* for timeouts */ - unsigned int last_error; /* save for checking */ -}; - -static struct pp_usb_data *minor_data[MAX_PRINTERS]; - -#define PPDATA(x) ((struct pp_usb_data *)(x)) - -unsigned char printer_read_status(struct pp_usb_data *p) -{ - __u8 status; - devrequest dr; - struct usb_device *dev = p->pusb_dev; - - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80; - dr.request = 1; - dr.value = 0; - dr.index = 0; - dr.length = 1; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1)) { - return 0; - } - return status; -} - -static int printer_check_status(struct pp_usb_data *p) -{ - unsigned int last = p->last_error; - unsigned char status = printer_read_status(p); - - if (status & LP_PERRORP) - /* No error. */ - last = 0; - else if ((status & LP_POUTPA)) { - if (last != LP_POUTPA) { - last = LP_POUTPA; - printk(KERN_INFO "usblp%d out of paper\n", p->minor); - } - } else if (!(status & LP_PSELECD)) { - if (last != LP_PSELECD) { - last = LP_PSELECD; - printk(KERN_INFO "usblp%d off-line\n", p->minor); - } - } else { - if (last != LP_PERRORP) { - last = LP_PERRORP; - printk(KERN_INFO "usblp%d on fire\n", p->minor); - } - } - - p->last_error = last; - - return status; -} - -void printer_reset(struct pp_usb_data *p) -{ - devrequest dr; - struct usb_device *dev = p->pusb_dev; - - dr.requesttype = USB_TYPE_CLASS | USB_RECIP_OTHER; - dr.request = 2; - dr.value = 0; - dr.index = 0; - dr.length = 0; - dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -static int open_printer(struct inode * inode, struct file * file) -{ - struct pp_usb_data *p; - - if(MINOR(inode->i_rdev) >= MAX_PRINTERS || - !minor_data[MINOR(inode->i_rdev)]) { - return -ENODEV; - } - - p = minor_data[MINOR(inode->i_rdev)]; - p->minor = MINOR(inode->i_rdev); - - if (p->isopen++) { - return -EBUSY; - } - if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) { - p->isopen = 0; - return -ENOMEM; - } - - printer_check_status(p); - - - file->private_data = p; -// printer_reset(p); - init_waitqueue_head(&p->wait_q); - return 0; -} - -static int close_printer(struct inode * inode, struct file * file) -{ - struct pp_usb_data *p = file->private_data; - - free_page((unsigned long)p->obuf); - p->isopen = 0; - file->private_data = NULL; - if(!p->pusb_dev) { - minor_data[p->minor] = NULL; - kfree(p); - - MOD_DEC_USE_COUNT; - - } - return 0; -} - -static ssize_t write_printer(struct file * file, - const char * buffer, size_t count, loff_t *ppos) -{ - struct pp_usb_data *p = file->private_data; - unsigned long copy_size; - unsigned long bytes_written = 0; - unsigned long partial; - int result; - int maxretry; - - do { - char *obuf = p->obuf; - unsigned long thistime; - - thistime = copy_size = (count > p->maxout) ? p->maxout : count; - if (copy_from_user(p->obuf, buffer, copy_size)) - return -EFAULT; - maxretry = MAX_RETRY_COUNT; - while (thistime) { - if (!p->pusb_dev) - return -ENODEV; - if (signal_pending(current)) { - return bytes_written ? bytes_written : -EINTR; - } - result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_sndbulkpipe(p->pusb_dev, 1), obuf, thistime, &partial); - if (partial) { - obuf += partial; - thistime -= partial; - maxretry = MAX_RETRY_COUNT; - } - if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */ - if(!maxretry--) - return -ETIME; - interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT); - continue; - } else if (!result && !partial) { - break; - } - }; - if (result) { - /* whoops - let's reset and fail the request */ -// printk("Whoops - %x\n", result); - printer_reset(p); - interruptible_sleep_on_timeout(&p->wait_q, 5*HZ); /* let reset do its stuff */ - return -EIO; - } - bytes_written += copy_size; - count -= copy_size; - buffer += copy_size; - } while ( count > 0 ); - - return bytes_written ? bytes_written : -EIO; -} - -static ssize_t read_printer(struct file * file, - char * buffer, size_t count, loff_t *ppos) -{ - struct pp_usb_data *p = file->private_data; - int read_count; - int this_read; - char buf[64]; - unsigned long partial; - int result; - - if (p->noinput) - return -EINVAL; - - read_count = 0; - while (count) { - if (signal_pending(current)) { - return read_count ? read_count : -EINTR; - } - if (!p->pusb_dev) - return -ENODEV; - this_read = (count > sizeof(buf)) ? sizeof(buf) : count; - - result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_rcvbulkpipe(p->pusb_dev, 2), buf, this_read, &partial); - - /* unlike writes, we don't retry a NAK, just stop now */ - if (!result & partial) - count = this_read = partial; - else if (result) - return -EIO; - - if (this_read) { - if (copy_to_user(buffer, p->obuf, this_read)) - return -EFAULT; - count -= this_read; - read_count += this_read; - buffer += this_read; - } - } - return read_count; -} - -static int printer_probe(struct usb_device *dev) -{ - struct usb_interface_descriptor *interface; - int i; - - /* - * FIXME - this will not cope with combined printer/scanners - */ - if ((dev->descriptor.bDeviceClass != 7 && - dev->descriptor.bDeviceClass != 0) || - dev->descriptor.bNumConfigurations != 1 || - dev->config[0].bNumInterfaces != 1) { - return -1; - } - - interface = dev->config->altsetting->interface; - - /* Lets be paranoid (for the moment)*/ - if (interface->bInterfaceClass != 7 || - interface->bInterfaceSubClass != 1 || - (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1)|| - interface->bNumEndpoints > 2) { - return -1; - } - - if (interface->endpoint[0].bEndpointAddress != 0x01 || - interface->endpoint[0].bmAttributes != 0x02 || - (interface->bNumEndpoints > 1 && ( - interface->endpoint[1].bEndpointAddress != 0x82 || - interface->endpoint[1].bmAttributes != 0x02))) { - return -1; - } - - for (i=0; i= MAX_PRINTERS) { - return -1; - } - - printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum); - - if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) { - printk( KERN_DEBUG "usb_printer: no memory!\n"); - return -1; - } - - memset(dev->private, 0, sizeof(struct pp_usb_data)); - minor_data[i] = PPDATA(dev->private); - minor_data[i]->minor = i; - minor_data[i]->pusb_dev = dev; - /* The max packet size can't be more than 64 (& will be 64 for - * any decent bulk device); this calculation was silly. -greg - * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16; - */ - minor_data[i]->maxout = 8192; - if (minor_data[i]->maxout > PAGE_SIZE) { - minor_data[i]->maxout = PAGE_SIZE; - } - if (interface->bInterfaceProtocol != 2) - minor_data[i]->noinput = 1; - else { - minor_data[i]->maxin = interface->endpoint[1].wMaxPacketSize; - } - - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk(KERN_INFO " Failed usb_set_configuration: printer\n"); - return -1; - } -#if 0 - { - __u8 status; - __u8 ieee_id[64]; - devrequest dr; - - /* Lets get the device id if possible */ - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80; - dr.request = 0; - dr.value = 0; - dr.index = 0; - dr.length = sizeof(ieee_id) - 1; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1) == 0) { - if (ieee_id[1] < sizeof(ieee_id) - 1) - ieee_id[ieee_id[1]+2] = '\0'; - else - ieee_id[sizeof(ieee_id)-1] = '\0'; - printk(KERN_INFO " Printer ID is %s\n", &ieee_id[2]); - } - status = printer_read_status(PPDATA(dev->private)); - printk(KERN_INFO " Status is %s,%s,%s\n", - (status & 0x10) ? "Selected" : "Not Selected", - (status & 0x20) ? "No Paper" : "Paper", - (status & 0x08) ? "No Error" : "Error"); - } -#endif - return 0; -} - -static void printer_disconnect(struct usb_device *dev) -{ - struct pp_usb_data *pp = dev->private; - - if (pp->isopen) { - /* better let it finish - the release will do whats needed */ - pp->pusb_dev = NULL; - return; - } - minor_data[pp->minor] = NULL; - kfree(pp); - dev->private = NULL; /* just in case */ - MOD_DEC_USE_COUNT; -} - -static struct usb_driver printer_driver = { - "printer", - printer_probe, - printer_disconnect, - { NULL, NULL } -}; - -static struct file_operations usb_printer_fops = { - NULL, /* seek */ - read_printer, - write_printer, - NULL, /* readdir */ - NULL, /* poll - out for the moment */ - NULL, /* ioctl */ - NULL, /* mmap */ - open_printer, - NULL, /* flush ? */ - close_printer, - NULL, - NULL -}; - -int usb_printer_init(void) -{ - int result; - - MOD_INC_USE_COUNT; - - if ((result = register_chrdev(USB_PRINTER_MAJOR, "usblp", &usb_printer_fops)) < 0) { - printk(KERN_WARNING "usbprinter: Cannot register device\n"); - return result; - } - if (mymajor == 0) { - mymajor = result; - } - usb_register(&printer_driver); - printk(KERN_INFO "USB Printer support registered.\n"); - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - - return usb_printer_init(); -} - -void cleanup_module(void) -{ - usb_deregister(&printer_driver); - unregister_chrdev(mymajor, "usblp"); -} -#endif diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c deleted file mode 100644 index 20cb728ba8a6..000000000000 --- a/drivers/usb/proc_usb.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * drivers/usb/proc_usb.c - * (C) Copyright 1999 Randy Dunlap. - * - * 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 - * - ************************************************************* - * - * This is a /proc/bus/usb filesystem output module for USB. - * It creates /proc/bus/usb/drivers and /proc/bus/usb/devices. - * - * /proc/bus/usb/devices contains USB topology, device, config, class, - * interface, & endpoint data. - * - * I considered using /proc/bus/usb/devices/device# for each device - * as it is attached or detached, but I didn't like this for some - * reason -- maybe it's just too deep of a directory structure. - * I also don't like looking in multiple places to gather and view - * the data. Having only one file for ./devices also prevents race - * conditions that could arise if a program was reading device info - * for devices that are being removed (unplugged). (That is, the - * program may find a directory for devnum_12 then try to open it, - * but it was just unplugged, so the directory is now deleted. - * But programs would just have to be prepared for situations like - * this in any plug-and-play environment.) - */ - -#define __KERNEL__ 1 - -#include -#include -#include -/* #include */ -#include -#include -#include -#include -#include - -#include "usb.h" - -#define DUMP_LIMIT (PAGE_SIZE - 100) - /* limit to only one memory page of output */ - -#define MAX_TOPO_LEVEL 6 - - -static char *format_topo = -/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */ - "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n"; - -static char *format_device1 = -/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */ - "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n"; - -static char *format_device2 = -/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */ - "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n"; - -static char *format_config = -/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */ - "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n"; - -static char *format_iface = -/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */ - "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; - -static char *format_endpt = -/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */ - "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n"; - - -/* - * Need access to the driver and USB bus lists. - * extern struct list_head usb_driver_list; - * extern struct list_head usb_bus_list; - * However, these will come from functions that return ptrs to each of them. - */ - -extern struct list_head *usb_driver_get_list (void); -extern struct list_head *usb_bus_get_list (void); - -extern struct proc_dir_entry *proc_bus; - -static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL; -static struct proc_dir_entry *devicesdir = NULL; - -struct class_info { - int class; - char *class_name; -}; - -struct class_info clas_info [] = -{ /* max. 5 chars. per name string */ - {USB_CLASS_PER_INTERFACE, ">ifc"}, - {USB_CLASS_AUDIO, "audio"}, - {USB_CLASS_COMM, "comm."}, - {USB_CLASS_HID, "HID"}, - {USB_CLASS_HUB, "hub"}, - {USB_CLASS_PRINTER, "print"}, - {USB_CLASS_MASS_STORAGE, "stor."}, - {USB_CLASS_VENDOR_SPEC, "vend."}, - {-1, "unk."} /* leave as last */ -}; - -/*****************************************************************/ - -static char *class_decode (const int class) -{ - int ix; - - for (ix = 0; clas_info [ix].class != -1; ix++) - if (clas_info [ix].class == class) - break; - - return (clas_info [ix].class_name); -} -static int usb_dump_endpoint_descriptor (const struct usb_endpoint_descriptor *desc, - char *buf, int *len) -{ - char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."}; - - *len += sprintf (buf + *len, format_endpt, - desc->bEndpointAddress, - (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O', - desc->bmAttributes, - EndpointType[desc->bmAttributes & 3], - desc->wMaxPacketSize, - desc->bInterval - ); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint, - char *buf, int *len) -{ - if (usb_dump_endpoint_descriptor (endpoint, buf, len) < 0) - return -1; - - return 0; -} - -static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc, - char *buf, int *len) -{ - *len += sprintf (buf + *len, format_iface, - desc->bInterfaceNumber, - desc->bAlternateSetting, - desc->bNumEndpoints, - desc->bInterfaceClass, - class_decode (desc->bInterfaceClass), - desc->bInterfaceSubClass, - desc->bInterfaceProtocol - ); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -static int usb_dump_interface (const struct usb_interface_descriptor *interface, - char *buf, int *len) -{ - int i; - - if (usb_dump_interface_descriptor (interface, buf, len) < 0) - return -1; - - for (i = 0; i < interface->bNumEndpoints; i++) { - if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0) - return -1; - } - - return 0; -} - -/* TBD: - * 0. TBDs - * 1. marking active config and ifaces (code lists all, but should mark - * which ones are active, if any) - * 2. Add proc_usb_init() call from usb-core.c. - * 3. proc_usb as a MODULE ? - * 4. use __initfunc() ? - * 5. add status to each endpoint line - */ - -static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc, - const int active, char *buf, int *len) -{ - *len += sprintf (buf + *len, format_config, - active ? '*' : ' ', /* mark active/actual/current cfg. */ - desc->bNumInterfaces, - desc->bConfigurationValue, - desc->bmAttributes, - desc->MaxPower * 2 - ); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -static int usb_dump_config (const struct usb_config_descriptor *config, - const int active, char *buf, int *len) -{ - int i, j; - struct usb_alternate_setting *as; - - if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */ - *len += sprintf (buf + *len, "(null Cfg. desc.)\n"); - return 0; - } - - if (usb_dump_config_descriptor (config, active, buf, len) < 0) - return -1; - - for (i = 0; i < config->num_altsetting; i++) { - as = config->altsetting + i; - if ((as) == NULL) - break; - - for (j = 0; j < config->bNumInterfaces; j++) - if (usb_dump_interface (as->interface + j, buf, len) < 0) - return -1; - } - - return 0; -} - -/* - * Dump the different USB descriptors. - */ -static int usb_dump_device_descriptor (const struct usb_device_descriptor *desc, - char *buf, int *len) -{ - *len += sprintf (buf + *len, format_device1, - desc->bcdUSB >> 8, desc->bcdUSB & 0xff, - desc->bDeviceClass, - class_decode (desc->bDeviceClass), - desc->bDeviceSubClass, - desc->bDeviceProtocol, - desc->bMaxPacketSize0, - desc->bNumConfigurations - ); - if (*len >= DUMP_LIMIT) return -1; - - *len += sprintf (buf + *len, format_device2, - desc->idVendor, desc->idProduct, - desc->bcdDevice >> 8, desc->bcdDevice & 0xff - ); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len) -{ - int i; - - if (usb_dump_device_descriptor (&dev->descriptor, buf, len) < 0) - return -1; - - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - if (usb_dump_config (dev->config + i, - (dev->config + i) == dev->actconfig, /* active ? */ - buf, len) < 0) - return -1; - } - - return 0; -} - -#ifdef PROC_EXTRA /* TBD: may want to add this code later */ - -static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc, - char *buf, int *len) -{ - int leng = USB_DT_HUB_NONVAR_SIZE; - unsigned char *ptr = (unsigned char *) desc; - - *len += sprintf (buf + *len, "Interface:"); - - while (leng) { - *len += sprintf (buf + *len, " %02x", *ptr); - ptr++; leng--; - } - *len += sprintf (buf + *len, "\n"); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -static int usb_dump_string (const struct usb_device *dev, char *id, int index, - char *buf, int *len) -{ - if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index]) - *len += sprintf (buf + *len, "%s: %s ", id, dev->stringindex[index]); - - return (*len >= DUMP_LIMIT) ? -1 : 0; -} - -#endif /* PROC_EXTRA */ - -/*****************************************************************/ - -static int usb_device_dump (char *buf, int *len, - const struct usb_device *usbdev, - int level, int index, int count) -{ - int chix; - int cnt = 0; - int parent_devnum; - - if (level > MAX_TOPO_LEVEL) return -1; - - parent_devnum = usbdev->parent ? (usbdev->parent->devnum == -1) ? 0 - : usbdev->parent->devnum : 0; - /* - * So the root hub's parent is 0 and any device that is - * plugged into the root hub has a parent of 0. - */ - *len += sprintf (buf + *len, format_topo, - level, parent_devnum, index, count, - usbdev->devnum, - usbdev->slow ? "1.5" : "12 ", - usbdev->ifnum, usbdev->maxchild, - usbdev->driver ? usbdev->driver->name : - (level == 0) ? "(root hub)" : "(none)" - ); - /* - * level = topology-tier level; - * parent_devnum = parent device number; - * index = parent's connector number; - * count = device count at this level - */ - - if (*len >= DUMP_LIMIT) - return -1; - - if (usbdev->devnum > 0) { /* for any except root hub */ - if (usb_dump_desc (usbdev, buf, len) < 0) - return -1; - } - - /* Now look at all of this device's children. */ - for (chix = 0; chix < usbdev->maxchild; chix++) { - if (usbdev->children [chix]) { - if (usb_device_dump (buf, len, - usbdev->children [chix], - level + 1, chix, ++cnt) < 0) - return -1; - } - } - - return 0; -} - -static int usb_bus_list_dump (char *buf, int len) -{ - struct list_head *usb_bus_list = usb_bus_get_list (); - struct list_head *list = usb_bus_list->next; - - len = 0; - - /* - * Go thru each usb_bus. Within each usb_bus: each usb_device. - * Within each usb_device: all of its device & config. descriptors, - * marking the currently active ones. - */ - - - while (list != usb_bus_list) { - struct usb_bus *bus = list_entry (list, struct usb_bus, bus_list); - - if (usb_device_dump (buf, &len, bus->root_hub, 0, 0, 0) - < 0) - break; - - list = list->next; - - if (len >= DUMP_LIMIT) { - len += sprintf (buf + len, "(truncated)\n"); - break; - } - } - - return (len); -} - -static int usb_bus_list_dump_devices (char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - return usb_bus_list_dump (buf, len); -} - -/* - * Dump usb_driver_list. - * - * We now walk the list of registered USB drivers. - */ -static int usb_driver_list_dump (char *buf, char **start, off_t offset, - int len, int *eof, void *data) -{ - struct list_head *usb_driver_list = usb_driver_get_list (); - struct list_head *tmp = usb_driver_list->next; - int cnt = 0; - - len = 0; - - while (tmp != usb_driver_list) { - struct usb_driver *driver = list_entry (tmp, struct usb_driver, - driver_list); - len += sprintf (buf + len, "%s\n", driver->name); - cnt++; - tmp = tmp->next; - - if (len >= DUMP_LIMIT) - { - len += sprintf (buf + len, "(truncated)\n"); - return (len); - } - } - - if (!cnt) - len += sprintf (buf + len, "(none)\n"); - return (len); -} - -void proc_usb_cleanup (void) -{ - if (driversdir) - remove_proc_entry ("drivers", usbdir); - if (devicesdir) - remove_proc_entry ("devices", usbdir); - if (usbdir) - remove_proc_entry ("usb", proc_bus); -} - -int proc_usb_init (void) -{ - usbdir = create_proc_entry ("usb", S_IFDIR, proc_bus); - if (!usbdir) { - printk ("proc_usb: cannot create /proc/bus/usb entry\n"); - return -1; - } - - driversdir = create_proc_entry ("drivers", 0, usbdir); - if (!driversdir) { - printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n"); - proc_usb_cleanup (); - return -1; - } - driversdir->read_proc = usb_driver_list_dump; - - devicesdir = create_proc_entry ("devices", 0, usbdir); - if (!devicesdir) { - printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n"); - proc_usb_cleanup (); - return -1; - } - devicesdir->read_proc = usb_bus_list_dump_devices; - - return 0; -} - -#ifdef PROCFS_MODULE /* TBD: support proc_fs MODULE ??? */ - -int init_module (void) -{ - return proc_usb_init (); -} - -void cleanup_module (void) -{ - proc_usb_cleanup (); -} - -#endif /* PROCFS_MODULE */ - -/* end proc_usb.c */ diff --git a/drivers/usb/procusb b/drivers/usb/procusb deleted file mode 100644 index 6c956f7f8509..000000000000 --- a/drivers/usb/procusb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/perl - -# Reads /proc/bus/usb/devices and selectively lists and/or -# interprets it. - -$DEVFILENAME = "/proc/bus/usb/devices"; -$PROGNAME = $0; - -$TAGS = $ARGV[0]; # save user TAGS -if (length ($TAGS) == 0) -{ - print "usage: $PROGNAME tags\n"; - print " where 'tags' can be any number of 'TDPCIE' or 'A(LL)'\n"; - exit 1; -} - -$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i); - -# TBD: Check that $TAGS is valid. -if (! $ALL) -{ -} - -if (! open (DEVNUM, "<$DEVFILENAME")) -{ - print "$PROGNAME: cannot open '$DEVFILENAME'\n"; - exit 1; -} - -while ($line = ) # read a text line from DEVNUM -{ - if (($ALL) || ($line =~ /^[$TAGS]:/i)) # any of TAGS at beg. of line? - { - print "$line"; # still has newline char on it - # TBD: add more/paging functionality. - } -} # end while DEVNUM - -close (DEVNUM); - -# END. diff --git a/drivers/usb/stopusb b/drivers/usb/stopusb index 7226738d4dde..1dc46980b537 100644 --- a/drivers/usb/stopusb +++ b/drivers/usb/stopusb @@ -1,11 +1,7 @@ #!/bin/sh -killall khubd killall ohci-control -killall uhci-control sleep 2 -rmmod hub rmmod usb-ohci -rmmod usb-uhci diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c index 8a1d3032c533..fd2aba6da44a 100644 --- a/drivers/usb/uhci-debug.c +++ b/drivers/usb/uhci-debug.c @@ -12,8 +12,6 @@ void show_td(struct uhci_td * td) { - char *spid; - printk("%08x ", td->link); printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ", ((td->status >> 29) & 1) ? "SPD " : "", @@ -29,27 +27,12 @@ void show_td(struct uhci_td * td) ((td->status >> 18) & 1) ? "CRC/Timeo " : "", ((td->status >> 17) & 1) ? "BitStuff " : "", td->status & 0x7ff); - switch (td->info & 0xff) { - case 0x2d: - spid = "SETUP"; - break; - case 0xe1: - spid = "OUT"; - break; - case 0x69: - spid = "IN"; - break; - default: - spid = "?"; - break; - } - printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", + printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ", td->info >> 21, - ((td->info >> 19) & 1), + ((td->info >> 19) & 1) ? "DT " : "", (td->info >> 15) & 15, (td->info >> 8) & 127, - (td->info & 0xff), - spid); + td->info & 0xff); printk("(buf=%08x)\n", td->buffer); } @@ -131,7 +114,7 @@ void show_queue(struct uhci_qh *qh) #if 0 printk(" link = %p, element = %p\n", qh->link, qh->element); #endif - if(!(qh->element & ~0xF)) { + if(!qh->element) { printk(" td 0 = NULL\n"); return; } @@ -147,9 +130,9 @@ void show_queue(struct uhci_qh *qh) int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) { int j; - struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub); + for (j = 0; j < UHCI_MAXQH; j++) - if (qh == root_hub->qh + j) + if (qh == uhci->root_hub->qh + j) return 1; return 0; @@ -165,16 +148,15 @@ void show_queues(struct uhci *uhci) { int i; struct uhci_qh *qh; - struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub); for (i = 0; i < UHCI_MAXQH; ++i) { printk(" %s:\n", qh_names[i]); #if 0 - printk(" qh #%d, %p\n", i, virt_to_bus(root_hub->qh + i)); + printk(" qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i)); show_queue(uhci->root_hub->qh + i); #endif - qh = uhci_link_to_qh(root_hub->qh[i].link); + qh = uhci_link_to_qh(uhci->root_hub->qh[i].link); for (; qh; qh = uhci_link_to_qh(qh->link)) { if (is_skeleton_qh(uhci, qh)) break; @@ -183,3 +165,4 @@ void show_queues(struct uhci *uhci) } } } + diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index b57b93eb5e8c..3d8ccdb7d9d9 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -19,8 +19,6 @@ */ /* 4/4/1999 added data toggle for interrupt pipes -keryan */ -/* 5/16/1999 added global toggles for bulk and control */ -/* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */ #include #include @@ -32,15 +30,14 @@ #include #include #include -#include -#include #include #include #include #include #include "uhci.h" +#include "inits.h" #ifdef CONFIG_APM #include @@ -48,105 +45,33 @@ static int handle_apm_event(apm_event_t event); static int apm_resume = 0; #endif -static int uhci_debug = 1; - #define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0) -static DECLARE_WAIT_QUEUE_HEAD(uhci_configure); +static struct wait_queue *uhci_configure = NULL; -/* - * Map status to standard result codes - */ -static int uhci_map_status(int status, int dir_out) -{ - if (!status) - return USB_ST_NOERROR; - if (status & 0x02) /* Bitstuff error*/ - return USB_ST_BITSTUFF; - if (status & 0x04) { /* CRC/Timeout */ - if (dir_out) - return USB_ST_NORESPONSE; - else - return USB_ST_CRC; - } - if (status & 0x08) /* NAK */ - return USB_ST_TIMEOUT; - if (status & 0x10) /* Babble */ - return USB_ST_STALL; - if (status & 0x20) /* Buffer error */ - return USB_ST_BUFFERUNDERRUN; - if (status & 0x40) /* Stalled */ - return USB_ST_STALL; - if (status & 0x80) /* Active */ - return USB_ST_NOERROR; - return USB_ST_INTERNALERROR; -} /* * Return the result of a TD.. */ -static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval) +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td) { unsigned int status; - struct uhci_td *tmp = td->first; - - if(rval) - *rval = 0; - - /* locate the first failing td, if any */ - - do { - status = (tmp->status >> 16) & 0xff; - if (status) { - /* must reset the toggle on first error */ - if (uhci_debug) { - printk("Set toggle from %x rval %ld\n", (unsigned int)tmp, rval ? *rval : 0); - } - usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1); - break; - } else { - if(rval) - *rval += (tmp->status & 0x3ff) + 1; - } - if ((tmp->link & 1) || (tmp->link & 2)) - break; - tmp = bus_to_virt(tmp->link & ~0xF); - } while (1); - - if (!status) - return USB_ST_NOERROR; + status = (td->status >> 16) & 0xff; /* Some debugging code */ - if (uhci_debug /* && (!usb_pipeendpoint(tmp->info) || !(status & 0x08))*/ ) { + if (status) { int i = 10; - - tmp = td->first; - printk("uhci_td_result() failed with status %x\n", status); - //show_status(dev->uhci); + struct uhci_td *tmp = dev->control_td; + printk("uhci_td_result() failed with status %d\n", status); + show_status(dev->uhci); do { show_td(tmp); - if ((tmp->link & 1) || (tmp->link & 2)) - break; - tmp = bus_to_virt(tmp->link & ~0xF); + tmp++; if (!--i) break; - } while (1); - } - - if (status & 0x40) { - /* endpoint has stalled - mark it halted */ - - usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info)); - return USB_ST_STALL; - + } while (tmp <= td); } - - if (status == 0x80) { - /* still active */ - if (!rval) - return USB_ST_DATAUNDERRUN; - } - return uhci_map_status(status, usb_pipeout(tmp->info)); + return status; } /* @@ -280,8 +205,8 @@ static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev) static void uhci_qh_deallocate(struct uhci_qh *qh) { -// if (qh->element != 1) -// printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element); + if (qh->element != 1) + printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element); qh->element = 1; qh->link = 1; @@ -298,10 +223,8 @@ static struct uhci_td *uhci_td_allocate(struct uhci_device *dev) for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++) ; - if (!inuse) { - td->inuse = 1; + if (!inuse) return(td); - } printk("ran out of td's for dev %p\n", dev); return(NULL); @@ -344,24 +267,19 @@ static void uhci_remove_irq_list(struct uhci_td *td) spin_unlock_irqrestore(&irqlist_lock, flags); } - /* * Request a interrupt handler.. - * - * Returns: a "handle pointer" that release_irq can use to stop this - * interrupt. (It's really a pointer to the TD). */ -static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub); struct uhci_td *td = uhci_td_allocate(dev); struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev); unsigned int destination, status; /* Destination: pipe destination with INPUT */ - destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe); + destination = (pipe & 0x0007ff00) | 0x69; /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */ status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27); @@ -371,315 +289,21 @@ static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb interrupt_qh->element); td->link = 1; - td->status = status; - td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) | - (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); + td->status = status; /* In */ + td->info = destination | (7 << 21); /* 8 bytes of data */ td->buffer = virt_to_bus(dev->data); - td->first = td; td->qh = interrupt_qh; - td->dev = usb_dev; - - /* if period 0, insert into fast q */ - - if (period == 0) { - td->inuse |= 2; - interrupt_qh->skel = &root_hub->skel_int2_qh; - } else - interrupt_qh->skel = &root_hub->skel_int8_qh; + interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh; uhci_add_irq_list(dev->uhci, td, handler, dev_id); uhci_insert_td_in_qh(interrupt_qh, td); /* Add it into the skeleton */ - uhci_insert_qh(interrupt_qh->skel, interrupt_qh); - - return (void*)td; -} - -/* - * Remove running irq td from queues - * - * This function is not used anymore. - */ -#if 0 -static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub); - struct uhci_td *td; - struct uhci_qh *interrupt_qh; - unsigned long flags; - struct list_head *head = &dev->uhci->interrupt_list; - struct list_head *tmp; - - spin_lock_irqsave(&irqlist_lock, flags); - - /* find the TD in the interrupt list */ - - tmp = head->next; - while (tmp != head) { - td = list_entry(tmp, struct uhci_td, irq_list); - if (td->dev_id == dev_id && td->completed == handler) { - - /* found the right one - let's remove it */ - - /* notify removal */ - - td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id); - - /* this is DANGEROUS - not sure whether this is right */ - - list_del(&td->irq_list); - uhci_remove_td(td); - interrupt_qh = td->qh; - uhci_remove_qh(interrupt_qh->skel, interrupt_qh); - uhci_td_deallocate(td); - uhci_qh_deallocate(interrupt_qh); - spin_unlock_irqrestore(&irqlist_lock, flags); - return USB_ST_NOERROR; - } - } - spin_unlock_irqrestore(&irqlist_lock, flags); - return USB_ST_INTERNALERROR; -} -#endif - -/* - * Release an interrupt handler previously allocated using - * uhci_request_irq. This function does no validity checking, so make - * sure you're not releasing an already released handle as it may be - * in use by something else.. - * - * This function can NOT be called from an interrupt. - */ -int uhci_release_irq(void* handle) -{ - struct uhci_td *td; - struct uhci_qh *interrupt_qh; - unsigned long flags; - -#ifdef UHCI_DEBUG - printk("usb-uhci: Releasing irq handle %p\n", handle); -#endif - - td = (struct uhci_td*)handle; - if (td == NULL) - return USB_ST_INTERNALERROR; - - /* Remove it from the internal irq_list */ - spin_lock_irqsave(&irqlist_lock, flags); - list_del(&td->irq_list); - spin_unlock_irqrestore(&irqlist_lock, flags); - - /* Remove the interrupt TD and QH */ - uhci_remove_td(td); - interrupt_qh = td->qh; - uhci_remove_qh(interrupt_qh->skel, interrupt_qh); - - if (td->completed != NULL) - td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id); - - /* Free the TD and QH */ - uhci_td_deallocate(td); - uhci_qh_deallocate(interrupt_qh); - - return USB_ST_NOERROR; -} /* uhci_release_irq() */ - - -/* - * Isochronous thread operations - */ - -static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc) -{ - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - char *data = isodesc->data; - int i, totlen = 0; - - for (i = 0; i < isodesc->num; i++) { - char *cdata = bus_to_virt(isodesc->td[i].buffer & ~0xF); - int n = (isodesc->td[i].status + 1) & 0x7FF; - - if ((cdata != data) && (n)) - memmove(data, cdata, n); - -#if 0 -if (n && n != 960) - printk("underrun: %d %d\n", i, n); -#endif -if ((isodesc->td[i].status >> 16) & 0xFF) - printk("error: %d %X\n", i, (isodesc->td[i].status >> 16)); - - data += n; - totlen += n; - } - - return totlen; -} - -static int uhci_unschedule_isochronous(struct usb_device *usb_dev, void *_isodesc) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - int i; - - if ((isodesc->frame < 0) || (isodesc->frame > 1023)) - return 1; - - /* Remove from previous frames */ - for (i = 0; i < isodesc->num; i++) { - /* Turn off Active and IOC bits */ - isodesc->td[i].status &= ~(3 << 23); - uhci->fl->frame[(isodesc->frame + i) % 1024] = isodesc->td[i].link; - } - - isodesc->frame = -1; - - return 0; -} - -/* td points to the one td we allocated for isochronous transfers */ -static int uhci_schedule_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc; - int frame, i; - - if (isodesc->frame != -1) { - printk("isoc queue not removed\n"); - uhci_unschedule_isochronous(usb_dev, isodesc); - } - - /* Insert TD into list */ - if (!pisodesc) { - frame = inw(uhci->io_addr + USBFRNUM) % 1024; - /* HACK: Start 2 frames from now */ - frame = (frame + 2) % 1024; - } else - frame = (pisodesc->endframe + 1) % 1024; - -#if 0 -printk("scheduling first at frame %d\n", frame); -#endif - - for (i = 0; i < isodesc->num; i++) { - /* Active */ - isodesc->td[i].status |= (1 << 23); - isodesc->td[i].backptr = &uhci->fl->frame[(frame + i) % 1024]; - isodesc->td[i].link = uhci->fl->frame[(frame + i) % 1024]; - uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(&isodesc->td[i]); - } - -#if 0 -printk("last at frame %d\n", (frame + i - 1) % 1024); -#endif - - /* Interrupt */ - isodesc->td[i - 1].status |= (1 << 24); - - isodesc->frame = frame; - isodesc->endframe = (frame + isodesc->num - 1) % 1024; - -#if 0 - return uhci_td_result(dev, td[num - 1]); -#endif + uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh); return 0; } -/* - * Initialize isochronous queue - */ -static void *uhci_allocate_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - unsigned long destination, status; - struct uhci_td *td; - struct uhci_iso_td *isodesc; - int i; - - isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL); - if (!isodesc) { - printk("Couldn't allocate isodesc!\n"); - return NULL; - } - memset(isodesc, 0, sizeof(*isodesc)); - - /* Carefully work around the non contiguous pages */ - isodesc->num = (len / PAGE_SIZE) * (PAGE_SIZE / maxsze); - isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL); - isodesc->frame = isodesc->endframe = -1; - isodesc->data = data; - isodesc->maxsze = maxsze; - - if (!isodesc->td) { - printk("Couldn't allocate td's\n"); - kfree(isodesc); - return NULL; - } - - isodesc->frame = isodesc->endframe = -1; - - /* - * Build the DATA TD's - */ - i = 0; - do { - /* Build the TD for control status */ - td = &isodesc->td[i]; - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (pipe & PIPE_DEVEP_MASK) - | usb_packetid (pipe); /* add IN or OUT */ - - /* Status: slow/fast, Active, Isochronous */ - status = (pipe & (1 << 26)) | (1 << 23) | (1 << 25); - - /* - * Build the TD for the control request - */ - td->status = status; - td->info = destination | ((maxsze - 1) << 21); - td->buffer = virt_to_bus(data); - td->first = td; - td->backptr = NULL; - - i++; - - data += maxsze; - - if (((int)data % PAGE_SIZE) + maxsze >= PAGE_SIZE) - data = (char *)(((int)data + maxsze) & ~(PAGE_SIZE - 1)); - - len -= maxsze; - } while (i < isodesc->num); - - /* IOC on the last TD */ - td->status |= (1 << 24); - uhci_add_irq_list(dev->uhci, td, completed, dev_id); - - return isodesc; -} - -static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc) -{ - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - - /* If it's still scheduled, unschedule them */ - if (isodesc->frame) - uhci_unschedule_isochronous(usb_dev, isodesc); - - /* Remove it from the IRQ list */ - uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]); - - kfree(isodesc->td); - kfree(isodesc); -} - /* * Control thread operations: we just mark the last TD * in a control thread as an interrupt TD, and wake up @@ -688,9 +312,9 @@ static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc) * We need to remove the TD from the lists (both interrupt * list and TD lists) by hand if something bad happens! */ -static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); +static struct wait_queue *control_wakeup; -static int uhci_control_completed(int status, void *buffer, int len, void *dev_id) +static int uhci_control_completed(int status, void *buffer, void *dev_id) { wake_up(&control_wakeup); return 0; /* Don't re-instate */ @@ -699,10 +323,10 @@ static int uhci_control_completed(int status, void *buffer, int len, void *dev_i /* td points to the last td in the list, which interrupts on completion */ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) { - DECLARE_WAITQUEUE(wait, current); + struct wait_queue wait = { current, NULL }; struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev); struct uhci_td *curtd; - struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub); + current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(&control_wakeup, &wait); @@ -730,18 +354,9 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru uhci_insert_tds_in_qh(ctrl_qh, first, last); /* Add it into the skeleton */ - uhci_insert_qh(&root_hub->skel_control_qh, ctrl_qh); - -// control should be full here... -// printk("control\n"); -// show_status(dev->uhci); -// show_queues(dev->uhci); + uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); - schedule_timeout(HZ*5); - -// control should be empty here... -// show_status(dev->uhci); -// show_queues(dev->uhci); + schedule_timeout(HZ/10); remove_wait_queue(&control_wakeup, &wait); @@ -753,11 +368,11 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru #endif /* Remove it from the skeleton */ - uhci_remove_qh(&root_hub->skel_control_qh, ctrl_qh); + uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); uhci_qh_deallocate(ctrl_qh); - return uhci_td_result(dev, last, NULL); + return uhci_td_result(dev, last); } /* @@ -781,21 +396,20 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru * information, that's just ridiculously high. Most * control messages have just a few bytes of data. */ -static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len) +static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) { struct uhci_device *dev = usb_to_uhci(usb_dev); struct uhci_td *first, *td, *prevtd; unsigned long destination, status; int ret; - int maxsze = usb_maxpacket(usb_dev, pipe); - if (len > maxsze * 29) + if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29) printk("Warning, too much data for a control packet, crashing\n"); first = td = uhci_td_allocate(dev); /* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */ - destination = (pipe & PIPE_DEVEP_MASK) | 0x2D; + destination = (pipe & 0x0007ff00) | 0x2D; /* Status: slow/fast, Active, Short Packet Detect Three Errors */ status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); @@ -806,7 +420,6 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre td->status = status; /* Try forever */ td->info = destination | (7 << 21); /* 8 bytes of data */ td->buffer = virt_to_bus(cmd); - td->first = td; /* * If direction is "send", change the frame from SETUP (0x2D) @@ -826,6 +439,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre while (len > 0) { /* Build the TD for control status */ int pktsze = len; + int maxsze = usb_maxpacket(pipe); if (pktsze > maxsze) pktsze = maxsze; @@ -836,31 +450,27 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre td->status = status; /* Status */ td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ td->buffer = virt_to_bus(data); - td->first = first; td->backptr = &prevtd->link; - data += pktsze; - len -= pktsze; - prevtd = td; td = uhci_td_allocate(dev); prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ + data += maxsze; + len -= maxsze; } /* - * Build the final TD for control status + * Build the final TD for control status */ destination ^= (0xE1 ^ 0x69); /* OUT -> IN */ destination |= 1 << 19; /* End in Data1 */ - td->backptr = &prevtd->link; - td->status = (status /* & ~(3 << 27) */) | (1 << 24); /* no limit on final packet */ - td->info = destination | (UHCI_NULL_DATA_SIZE << 21); /* 0 bytes of data */ - td->buffer = 0; - td->first = first; td->link = 1; /* Terminate */ - + td->status = status | (1 << 24); /* IOC */ + td->info = destination | (0x7ff << 21); /* 0 bytes of data */ + td->buffer = 0; + td->backptr = &prevtd->link; /* Start it up.. */ ret = uhci_run_control(dev, first, td); @@ -885,192 +495,6 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre } while (1); } - if (uhci_debug && ret) { - __u8 *p = (__u8 *)cmd; - - printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - } - return ret; -} - - -/* - * Bulk thread operations: we just mark the last TD - * in a bulk thread as an interrupt TD, and wake up - * the front-end on completion. - * - * We need to remove the TD from the lists (both interrupt - * list and TD lists) by hand if something bad happens! - */ -static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); - -static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id) -{ - wake_up(&bulk_wakeup); - return 0; /* Don't re-instate */ -} - -/* td points to the last td in the list, which interrupts on completion */ -static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval) -{ - DECLARE_WAITQUEUE(wait, current); - struct uhci_qh *bulk_qh = uhci_qh_allocate(dev); - struct uhci_td *curtd; - struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub); - - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&bulk_wakeup, &wait); - - uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL); - - /* FIXME: This is kinda kludged */ - /* Walk the TD list and update the QH pointer */ - { - int maxcount = 100; - - curtd = first; - do { - curtd->qh = bulk_qh; - if (curtd->link & 1) - break; - - curtd = bus_to_virt(curtd->link & ~0xF); - if (!--maxcount) { - printk("runaway tds!\n"); - break; - } - } while (1); - } - - uhci_insert_tds_in_qh(bulk_qh, first, last); - - /* Add it into the skeleton */ - uhci_insert_qh(&root_hub->skel_bulk0_qh, bulk_qh); - -// now we're in the queue... but don't ask WHAT is in there ;-( -// printk("bulk\n"); -// show_status(dev->uhci); -// show_queues(dev->uhci); - - schedule_timeout(HZ*5); -// show_status(dev->uhci); -// show_queues(dev->uhci); - - //show_queue(first->qh); - remove_wait_queue(&bulk_wakeup, &wait); - - /* Clean up in case it failed.. */ - uhci_remove_irq_list(last); - -#if 0 - printk("Looking for tds [%p, %p]\n", dev->control_td, td); -#endif - - /* Remove it from the skeleton */ - uhci_remove_qh(&root_hub->skel_bulk0_qh, bulk_qh); - - uhci_qh_deallocate(bulk_qh); - - return uhci_td_result(dev, last, rval); -} - -/* - * Send or receive a bulk message on a pipe. - * - * Note that the "pipe" structure is set up to map - * easily to the uhci destination fields. - * - * A bulk message is only built up from - * the data phase - * - * The data phase can be an arbitrary number of TD's - * although we currently had better not have more than - * 31 TD's here. - * - * 31 TD's is a minimum of 248 bytes worth of bulk - * information. - */ -static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci_td *first, *td, *prevtd; - unsigned long destination, status; - int ret; - int maxsze = usb_maxpacket(usb_dev, pipe); - - if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe)) && - usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80))) - return USB_ST_STALL; - - if (len > maxsze * 31) - printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze); - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe); - - /* Status: slow/fast, Active, Short Packet Detect Three Errors */ - status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); - - /* - * Build the TDs for the bulk request - */ - first = td = uhci_td_allocate(dev); - prevtd = first; //This is fake, but at least it's not NULL - while (len > 0) { - /* Build the TD for control status */ - int pktsze = len; - - if (pktsze > maxsze) - pktsze = maxsze; - - td->status = status; /* Status */ - td->info = destination | ((pktsze-1) << 21) | - (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */ - td->buffer = virt_to_bus(data); - td->backptr = &prevtd->link; - td->first = first; - - data += maxsze; - len -= maxsze; - - if (len > 0) { - prevtd = td; - td = uhci_td_allocate(dev); - prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ - } - - /* Alternate Data0/1 (start with Data0) */ - usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - } - td->link = 1; /* Terminate */ - td->status |= (1 << 24); /* IOC */ - - /* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */ - - /* Start it up.. */ - ret = uhci_run_bulk(dev, first, td, rval); - - { - int maxcount = 100; - struct uhci_td *curtd = first; - unsigned int nextlink; - - do { - nextlink = curtd->link; - uhci_remove_td(curtd); - uhci_td_deallocate(curtd); - if (nextlink & 1) /* Tail? */ - break; - - curtd = bus_to_virt(nextlink & ~0xF); - if (!--maxcount) { - printk("runaway td's!?\n"); - break; - } - } while (1); - } - return ret; } @@ -1130,23 +554,19 @@ static int uhci_usb_deallocate(struct usb_device *usb_dev) for (i = 0; i < UHCI_MAXTD; ++i) { struct uhci_td *td = dev->td + i; - if (td->inuse & 1) { - uhci_remove_td(td); + /* And remove it from the irq list, if it's active */ + if (td->status & (1 << 23)) + uhci_remove_irq_list(td); - /* And remove it from the irq list, if it's active */ - if (td->status & (1 << 23)) - td->status &= ~(1 << 23); -#if 0 - uhci_remove_irq_list(td); -#endif - } + if (td->inuse) + uhci_remove_td(td); } /* Remove the td from any queues */ for (i = 0; i < UHCI_MAXQH; ++i) { struct uhci_qh *qh = dev->qh + i; - if (qh->inuse & 1) + if (qh->inuse) uhci_remove_qh(qh->skel, qh); } @@ -1161,14 +581,7 @@ struct usb_operations uhci_device_operations = { uhci_usb_allocate, uhci_usb_deallocate, uhci_control_msg, - uhci_bulk_msg, uhci_request_irq, - uhci_release_irq, - uhci_allocate_isochronous, - uhci_delete_isochronous, - uhci_schedule_isochronous, - uhci_unschedule_isochronous, - uhci_compress_isochronous }; /* @@ -1210,7 +623,7 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i struct usb_device *usb_dev; struct uhci_device *dev; unsigned short status; - struct uhci_device *root_hub=usb_to_uhci(uhci->bus->root_hub); + printk("uhci_connect_change: called for %d\n", nr); /* @@ -1220,7 +633,7 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i * * So start off by getting rid of any old devices.. */ - usb_disconnect(&root_hub->usb->children[nr]); + usb_disconnect(&uhci->root_hub->usb->children[nr]); status = inw(port); @@ -1235,17 +648,14 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i * Ok, we got a new connection. Allocate a device to it, * and find out what it wants to do.. */ - usb_dev = uhci_usb_allocate(root_hub->usb); - if (!usb_dev) - return; - + usb_dev = uhci_usb_allocate(uhci->root_hub->usb); dev = usb_dev->hcpriv; dev->uhci = uhci; usb_connect(usb_dev); - root_hub->usb->children[nr] = usb_dev; + uhci->root_hub->usb->children[nr] = usb_dev; wait_ms(200); /* wait for powerup */ uhci_reset_port(port); @@ -1268,9 +678,8 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i */ static void uhci_check_configuration(struct uhci *uhci) { - struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub); unsigned int io_addr = uhci->io_addr + USBPORTSC1; - int maxchild = root_hub->usb->maxchild; + int maxchild = uhci->root_hub->usb->maxchild; int nr = 0; do { @@ -1287,7 +696,6 @@ static void uhci_interrupt_notify(struct uhci *uhci) { struct list_head *head = &uhci->interrupt_list; struct list_head *tmp; - int status; spin_lock(&irqlist_lock); tmp = head->next; @@ -1297,41 +705,25 @@ static void uhci_interrupt_notify(struct uhci *uhci) next = tmp->next; - if (!((status = td->status) & (1 << 23)) || /* No longer active? */ - ((td->qh->element & ~15) && - !((status = uhci_link_to_td(td->qh->element)->status) & (1 <<23)) && - (status & 0x760000) /* is in error state (Stall, db, babble, timeout, bitstuff) */)) { + if (!(td->status & (1 << 23))) { /* No longer active? */ /* remove from IRQ list */ __list_del(tmp->prev, next); INIT_LIST_HEAD(tmp); - if (td->completed(uhci_map_status(status, 0), bus_to_virt(td->buffer), -1, td->dev_id)) { - list_add(&td->irq_list, &uhci->interrupt_list); - - if (!(td->status & (1 << 25))) { - struct uhci_qh *interrupt_qh = td->qh; + if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) { + struct uhci_qh *interrupt_qh = td->qh; - usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)); - td->info &= ~(1 << 19); /* clear data toggle */ - td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */ - td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ + list_add(&td->irq_list, &uhci->interrupt_list); + td->info ^= 1 << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ - /* Remove then readd? Is that necessary */ - uhci_remove_td(td); - uhci_insert_td_in_qh(interrupt_qh, td); - } - } else if (td->inuse & 2) { - struct uhci_qh *interrupt_qh = td->qh; - /* marked for removal */ - td->inuse &= ~2; - usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)); - uhci_remove_qh(interrupt_qh->skel, interrupt_qh); - uhci_qh_deallocate(interrupt_qh); - uhci_td_deallocate(td); + /* Remove then readd? Is that necessary */ + uhci_remove_td(td); + uhci_insert_td_in_qh(interrupt_qh, td); } /* If completed wants to not reactivate, then it's */ /* responsible for free'ing the TD's and QH's */ /* or another function (such as run_control) */ - } + } tmp = next; } spin_unlock(&irqlist_lock); @@ -1348,8 +740,7 @@ static void uhci_interrupt_notify(struct uhci *uhci) static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr) { if (waitqueue_active(&uhci_configure)) { - struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub); - int ports = root_hub->usb->maxchild; + int ports = uhci->root_hub->usb->maxchild; io_addr += USBPORTSC1; do { if (inw(io_addr) & USBPORTSC_CSC) { @@ -1373,9 +764,6 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) status = inw(io_addr + USBSTS); outw(status, io_addr + USBSTS); -// if ((status & ~0x21) != 0) -// printk("interrupt: %X\n", status); - /* Walk the list of pending TD's to see which ones completed.. */ uhci_interrupt_notify(uhci); @@ -1392,14 +780,13 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) */ static void uhci_init_ticktd(struct uhci *uhci) { - struct uhci_device *dev = usb_to_uhci(uhci->bus->root_hub); + struct uhci_device *dev = uhci->root_hub; struct uhci_td *td = uhci_td_allocate(dev); td->link = 1; td->status = (1 << 24); /* interrupt on completion */ td->info = (15 << 21) | 0x7f69; /* (ignored) input packet, 16 bytes, device 127 */ td->buffer = 0; - td->first = td; td->qh = NULL; uhci->fl->frame[0] = virt_to_bus(td); @@ -1437,13 +824,12 @@ static void start_hc(struct uhci *uhci) } } - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR); outw(0, io_addr + USBFRNUM); outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD); /* Run and mark it configured with a 64-byte max packet */ - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); + outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD); } /* @@ -1484,12 +870,10 @@ static struct uhci *alloc_uhci(unsigned int io_addr) /* We need exactly one page (per UHCI specs), how convenient */ uhci->fl = (void *)__get_free_page(GFP_KERNEL); - if (!uhci->fl) - goto au_free_uhci; bus = kmalloc(sizeof(*bus), GFP_KERNEL); if (!bus) - goto au_free_fl; + return NULL; memset(bus, 0, sizeof(*bus)); @@ -1509,11 +893,12 @@ static struct uhci *alloc_uhci(unsigned int io_addr) */ usb = uhci_usb_allocate(NULL); if (!usb) - goto au_free_bus; + return NULL; + + dev = uhci->root_hub = usb_to_uhci(usb); usb->bus = bus; - dev = usb_to_uhci(usb); - uhci->bus->root_hub=uhci_to_usb(dev); + /* Initialize the root hub */ /* UHCI specs says devices must have 2 ports, but goes on to say */ /* they may have more but give no way to determine how many they */ @@ -1580,18 +965,6 @@ static struct uhci *alloc_uhci(unsigned int io_addr) } return uhci; - -/* - * error exits: - */ - -au_free_bus: - kfree (bus); -au_free_fl: - free_page ((unsigned long)uhci->fl); -au_free_uhci: - kfree (uhci); - return NULL; } @@ -1606,9 +979,9 @@ static void release_uhci(struct uhci *uhci) } #if 0 - if (uhci->bus->root_hub) { - uhci_usb_deallocate(uhci_to_usb(uhci->bus->root_hub)); - uhci->bus->root_hub = NULL; + if (uhci->root_hub) { + uhci_usb_deallocate(uhci_to_usb(uhci->root_hub)); + uhci->root_hub = NULL; } #endif @@ -1621,10 +994,11 @@ static void release_uhci(struct uhci *uhci) kfree(uhci); } +void cleanup_drivers(void); + static int uhci_control_thread(void * __uhci) { struct uhci *uhci = (struct uhci *)__uhci; - struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub); lock_kernel(); request_region(uhci->io_addr, 32, "usb-uhci"); @@ -1636,7 +1010,7 @@ static int uhci_control_thread(void * __uhci) printk("uhci_control_thread at %p\n", &uhci_control_thread); exit_mm(current); exit_files(current); - //exit_fs(current); + exit_fs(current); strcpy(current->comm, "uhci-control"); @@ -1644,7 +1018,6 @@ static int uhci_control_thread(void * __uhci) * Ok, all systems are go.. */ start_hc(uhci); - usb_register_bus(uhci->bus); for(;;) { siginfo_t info; int unsigned long signr; @@ -1668,23 +1041,19 @@ static int uhci_control_thread(void * __uhci) if(signr == SIGUSR1) { printk("UHCI queue dump:\n"); show_queues(uhci); - } else if (signr == SIGUSR2) { - uhci_debug = !uhci_debug; - printk("UHCI debug toggle = %x\n", uhci_debug); } else { break; } } } - { - int i; - if(root_hub) - for(i = 0; i < root_hub->usb->maxchild; i++) - usb_disconnect(root_hub->usb->children + i); - } +#if 0 + if(uhci->root_hub) + for(i = 0; i < uhci->root_hub->usb->maxchild; i++) + usb_disconnect(uhci->root_hub->usb->children + i); +#endif - usb_deregister_bus(uhci->bus); + cleanup_drivers(); reset_hc(uhci); release_region(uhci->io_addr, 32); @@ -1715,10 +1084,10 @@ static int found_uhci(int irq, unsigned int io_addr) retval = -EBUSY; if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) { int pid; + MOD_INC_USE_COUNT; uhci->irq = irq; - pid = kernel_thread(uhci_control_thread, uhci, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); if (pid >= 0) return 0; @@ -1783,6 +1152,18 @@ static int handle_apm_event(apm_event_t event) } #endif +#ifdef MODULE + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define uhci_init init_module + +#endif int uhci_init(void) { @@ -1804,24 +1185,29 @@ int uhci_init(void) if (retval < 0) continue; +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif + return 0; } return retval; } -#ifdef MODULE -int init_module(void) -{ - return uhci_init(); -} - -void cleanup_module(void) +void cleanup_drivers(void) { -#ifdef CONFIG_APM - apm_unregister_callback(&handle_apm_event); + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); #endif } -#endif //MODULE diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h index ea76df0cc1fa..f063356acc58 100644 --- a/drivers/usb/uhci.h +++ b/drivers/usb/uhci.h @@ -53,8 +53,6 @@ #define USBPORTSC_PR 0x0200 /* Port Reset */ #define USBPORTSC_SUSP 0x1000 /* Suspend */ -#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */ - struct uhci_qh { unsigned int link; /* Next queue */ unsigned int element; /* Queue element pointer */ @@ -91,23 +89,10 @@ struct uhci_td { usb_device_irq completed; /* Completion handler routine */ unsigned int *backptr; /* Where to remove this from.. */ void *dev_id; - int inuse; /* Inuse? (b0) Remove (b1)*/ + int inuse; /* Inuse? */ struct uhci_qh *qh; - struct uhci_td *first; - struct usb_device *dev; /* the owning device */ } __attribute__((aligned(32))); -struct uhci_iso_td { - int num; - char *data; - int maxsze; - - struct uhci_td *td; - - int frame; - int endframe; -}; - /* * Note the alignment requirements of the entries * @@ -117,7 +102,7 @@ struct uhci_iso_td { */ struct uhci; -#define UHCI_MAXTD 64 +#define UHCI_MAXTD 64 #define UHCI_MAXQH 16 @@ -139,11 +124,9 @@ struct uhci_device { * The root hub pre-allocated QH's and TD's have * some special global uses.. */ -#if 0 #define control_td td /* Td's 0-30 */ /* This is only for the root hub's TD list */ #define tick_td td[31] -#endif /* * There are various standard queues. We set up several different @@ -169,12 +152,12 @@ struct uhci_device { * Linus: * * generic-iso-QH -> dev1-iso-QH -> generic-irq-QH -> dev1-irq-QH -> ... - * | | | | - * End dev1-iso-TD1 End dev1-irq-TD1 - * | - * dev1-iso-TD2 - * | - * .... + * | | | | + * End dev1-iso-TD1 End dev1-irq-TD1 + * | + * dev1-iso-TD2 + * | + * .... * * This may vary a bit (the UHCI docs don't explicitly say you can put iso * transfers in QH's and all of their pictures don't have that either) but @@ -228,6 +211,8 @@ struct uhci { /* These are "standard" QH's for the entire bus */ struct uhci_qh qh[UHCI_MAXQH]; #endif + struct uhci_device *root_hub; /* Root hub device descriptor.. */ + struct uhci_framelist *fl; /* Frame list */ struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ }; diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c deleted file mode 100644 index 2103789a8868..000000000000 --- a/drivers/usb/usb-core.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * driver/usb/usb-core.c - * - * (C) Copyright David Waite 1999 - * based on code from usb.c, by Linus Torvolds - * - * The purpose of this file is to pull any and all generic modular code from - * usb.c and put it in a separate file. This way usb.c is kept as a generic - * library, while this file handles starting drivers, etc. - * - */ -#include -#include -#include - -#include "inits.h" -#include "usb.h" - -#ifndef CONFIG_USB_MODULE -# ifdef CONFIG_USB_UHCI - int uhci_init(void); -# endif -# ifdef CONFIG_USB_OHCI - int ohci_init(void); -# endif -# ifdef CONFIG_USB_OHCI_HCD - int ohci_hcd_init(void); -# endif -#endif - - -int usb_init(void) -{ -#ifndef CONFIG_USB_MODULE -# ifdef CONFIG_USB_UHCI - uhci_init(); -# endif -# ifdef CONFIG_USB_OHCI - ohci_init(); -# endif -# ifdef CONFIG_USB_OHCI_HCD - ohci_hcd_init(); -# endif -# ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -# endif -# ifdef CONFIG_USB_KBD - usb_kbd_init(); -# endif -# ifdef CONFIG_USB_AUDIO - usb_audio_init(); -# endif -# ifdef CONFIG_USB_ACM - usb_acm_init(); -# endif -# ifdef CONFIG_USB_PRINTER - usb_printer_init(); -# endif -# ifdef CONFIG_USB_CPIA - usb_cpia_init(); -# endif -# ifdef CONFIG_USB_HUB - usb_hub_init(); -# endif -# ifdef CONFIG_USB_SCSI - usb_scsi_init(); -# endif -#endif -#ifdef CONFIG_USB_PROC - proc_usb_init (); -#endif - return 0; -} -/* - * Clean up when unloading the module - */ -void cleanup_drivers(void) -{ -#ifdef CONFIG_USB_PROC - proc_usb_cleanup (); -#endif -#ifndef MODULE -# ifdef CONFIG_USB_HUB - usb_hub_cleanup(); -# endif -# ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -# endif -#endif -} - -#ifdef MODULE -int init_module(void) -{ - return usb_init(); -} -void cleanup_module(void) -{ - cleanup_drivers(); -} -#endif - - diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c index e656cc6c4c8e..86d08cd787f1 100644 --- a/drivers/usb/usb-debug.c +++ b/drivers/usb/usb-debug.c @@ -24,18 +24,11 @@ static void usb_show_interface(struct usb_interface_descriptor *interface) static void usb_show_config(struct usb_config_descriptor *config) { - int i, j; - struct usb_alternate_setting *as; - - usb_show_config_descriptor(config); - for (i = 0; i < config->num_altsetting; i++) { - as = config->altsetting + i; - if ((as) == NULL) - break; - printk("\n Alternate Setting: %d\n", i); - for (j = 0 ; j < config->bNumInterfaces; j++) - usb_show_interface(as->interface + j); - } + int i; + + usb_show_config_descriptor(config); + for (i = 0 ; i < config->bNumInterfaces; i++) + usb_show_interface(config->interface + i); } void usb_show_device(struct usb_device *dev) @@ -53,21 +46,12 @@ void usb_show_device(struct usb_device *dev) */ void usb_show_device_descriptor(struct usb_device_descriptor *desc) { - printk(" Length = %2d%s\n", desc->bLength, - desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)"); - printk(" DescriptorType = %02x\n", desc->bDescriptorType); - - printk(" USB version = %x.%02x\n", - desc->bcdUSB >> 8, desc->bcdUSB & 0xff); - printk(" Vendor:Product = %04x:%04x\n", - desc->idVendor, desc->idProduct); - printk(" MaxPacketSize0 = %d\n", desc->bMaxPacketSize0); - printk(" NumConfigurations = %d\n", desc->bNumConfigurations); - printk(" Device version = %x.%02x\n", - desc->bcdDevice >> 8, desc->bcdDevice & 0xff); - - printk(" Device Class:SubClass:Protocol = %02x:%02x:%02x\n", - desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol); + printk(" USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff); + printk(" Vendor: %04x\n", desc->idVendor); + printk(" Product: %04x\n", desc->idProduct); + printk(" Configurations: %d\n", desc->bNumConfigurations); + + printk(" Device Class: %d\n", desc->bDeviceClass); switch (desc->bDeviceClass) { case 0: printk(" Per-interface classes\n"); @@ -87,7 +71,7 @@ void usb_show_config_descriptor(struct usb_config_descriptor * desc) { printk("Configuration:\n"); printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)"); + desc->bLength == 9 ? "" : " (!!!)"); printk(" bDescriptorType = %02x\n", desc->bDescriptorType); printk(" wTotalLength = %04x\n", desc->wTotalLength); printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces); @@ -101,13 +85,14 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) { printk(" Interface:\n"); printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)"); + desc->bLength == 9 ? "" : " (!!!)"); printk(" bDescriptorType = %02x\n", desc->bDescriptorType); printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber); printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting); printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints); - printk(" bInterface Class:SubClass:Protocol = %02x:%02x:%02x\n", - desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol); + printk(" bInterfaceClass = %02x\n", desc->bInterfaceClass); + printk(" bInterfaceSubClass = %02x\n", desc->bInterfaceSubClass); + printk(" bInterfaceProtocol = %02x\n", desc->bInterfaceProtocol); printk(" iInterface = %02x\n", desc->iInterface); } @@ -116,7 +101,7 @@ void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; printk(" Endpoint:\n"); printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : " (!!!)"); + desc->bLength == 7 ? "" : " (!!!)"); printk(" bDescriptorType = %02x\n", desc->bDescriptorType); printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, (desc->bEndpointAddress & 0x80) ? "in" : "out"); @@ -139,10 +124,4 @@ void usb_show_hub_descriptor(struct usb_hub_descriptor * desc) printk("\n"); } -void usb_show_string(struct usb_device* dev, char *id, int index) -{ - char *p = usb_string(dev, index); - if (p != 0) - printk(KERN_INFO "%s: %s\n", id, p); -} diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index fdfe24f33f56..f5e89ea8986c 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -1,5 +1,5 @@ /* - * drivers/usb/usb.c + * driver/usb/usb.c * * (C) Copyright Linus Torvalds 1999 * @@ -36,7 +36,6 @@ * 6 wLength 2 Count Bytes for data */ -#include #include #include #include @@ -47,113 +46,25 @@ * We have a per-interface "registered driver" list. */ static LIST_HEAD(usb_driver_list); -static LIST_HEAD(usb_bus_list); int usb_register(struct usb_driver *new_driver) { - struct list_head *tmp = usb_bus_list.next; /* Add it to the list of known drivers */ list_add(&new_driver->driver_list, &usb_driver_list); /* - * We go through all existing devices, and see if any of them would - * be acceptable to the new driver.. This is done using a depth-first - * search for devices without a registered driver already, then - * running 'probe' with each of the drivers registered on every one - * of these. + * We should go through all existing devices, and see if any of + * them would be acceptable to the new driver.. Let's do that + * in version 2.0. */ - while (tmp!= &usb_bus_list) { - struct usb_bus * bus = list_entry(tmp,struct - usb_bus,bus_list); - tmp=tmp->next; - usb_check_support(bus->root_hub); - } return 0; } void usb_deregister(struct usb_driver *driver) { - struct list_head *tmp = usb_bus_list.next; - /*first we remove the driver, to be sure it doesn't get used by - *another thread while we are stepping through removing entries - */ list_del(&driver->driver_list); - printk(KERN_INFO "usbcore: deregistering driver\n"); - while (tmp!= &usb_bus_list) { - struct usb_bus * bus = list_entry(tmp,struct - usb_bus,bus_list); - tmp=tmp->next; - usb_driver_purge(driver,bus->root_hub); - } -} - -/* This function is part of a depth-first search down the device tree, - * removing any instances of a device driver. - */ -void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) -{ - int i; - if (dev==NULL){ - printk(KERN_ERR "null device being passed in!!!\n"); - return; - } - for (i=0;ichildren[i]!=NULL) - usb_driver_purge(driver,dev->children[i]); - /*now we check this device*/ - if(dev->driver==driver) { - /* - * Note: this is not the correct way to do this, this - * uninitializes and reinitializes EVERY driver - */ - printk(KERN_ERR "disconnecting driverless device\n"); - dev->driver->disconnect(dev); - dev->driver=NULL; - /* This will go back through the list looking for a driver - * that can handle the device - */ - usb_device_descriptor(dev); - } -} - -/* - * New functions for (de)registering a controller - */ -void usb_register_bus(struct usb_bus *new_bus) -{ - /* Add it to the list of buses */ - list_add(&new_bus->bus_list, &usb_bus_list); - printk(KERN_DEBUG "New bus registered\n"); -} - -void usb_deregister_bus(struct usb_bus *bus) -{ - /* NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning - * itself up - */ - list_del(&bus->bus_list); } -/* - * This function is for doing a depth-first search for devices which - * have support, for dynamic loading of driver modules. - */ -void usb_check_support(struct usb_device *dev) -{ - int i; - if (dev==NULL) - { - printk(KERN_ERR "null device being passed in!!!\n"); - return; - } - for (i=0;ichildren[i]!=NULL) - usb_check_support(dev->children[i]); - /*now we check this device*/ - if (dev->driver==NULL) - usb_device_descriptor(dev); -} /* * This entrypoint gets called for each new device. * @@ -161,24 +72,25 @@ void usb_check_support(struct usb_device *dev) * looking for one that will accept this device as * his.. */ -int usb_device_descriptor(struct usb_device *dev) +void usb_device_descriptor(struct usb_device *dev) { struct list_head *tmp = usb_driver_list.next; while (tmp != &usb_driver_list) { - struct usb_driver *driver = list_entry(tmp, struct usb_driver, - driver_list); + struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list); tmp = tmp->next; if (driver->probe(dev)) continue; dev->driver = driver; - return 1; + return; } + /* * Ok, no driver accepted the device, so show the info * for debugging.. */ - return 0; + printk("Unknown new USB device:\n"); + usb_show_device(dev); } /* @@ -197,8 +109,8 @@ static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desc if (len < descindex) return -1; - n_desc = le16_to_cpup((unsigned short *)ptr); - n_len = ptr[0]; + n_desc = *(unsigned short *)ptr; + n_len = n_desc & 0xff; if (n_desc == ((desctype << 8) + descindex)) break; @@ -206,30 +118,28 @@ static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desc if (((n_desc >> 8)&0xFF) == desctype && n_len > descindex) { - printk(KERN_DEBUG "bug: oversized descriptor.\n"); + printk("bug: oversized descriptor.\n"); break; } if (n_len < 2 || n_len > len) { - printk(KERN_DEBUG "Short descriptor\n"); + printk("Short descriptor.\n"); return -1; } - printk(KERN_DEBUG - "Expected descriptor %02X/%02X, got %02X/%02X - skipping", - desctype, descindex, ptr[1], ptr[0]); - for (i = 0; i < n_len; i++) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG); - printk(" %02x", ptr[i]); - } - printk("\n"); + printk( + "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", + desctype, descindex, + (n_desc >> 8) & 0xFF, n_desc & 0xFF); + for (i = 0 ; i < n_len; i++) + printk(" %d %02x\n", i, ptr[i]); len -= n_len; ptr += n_len; parsed += n_len; } - printk(KERN_DEBUG "Found %02X:%02X\n", desctype, descindex); + printk("Found %02X:%02X\n", + desctype, descindex); return parsed; } @@ -242,15 +152,9 @@ static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desct { int n_len = ptr[0]; - if (len <= 0) - return -1; - if (n_len < 2 || n_len > len) { - int i; - printk(KERN_DEBUG "Short descriptor. (%d, %d):\n", len, n_len); - for (i = 0; i < len; ++i) - printk(KERN_DEBUG " %d: %x\n", i, ptr[i]); + printk("Short descriptor.\n"); return -1; } @@ -263,16 +167,15 @@ static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desct static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) { - int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE); + int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7); int i; if (parsed < 0) return parsed; memcpy(endpoint, ptr + parsed, ptr[parsed]); - le16_to_cpus(&endpoint->wMaxPacketSize); parsed += ptr[parsed]; - len -= parsed; + len -= ptr[parsed]; while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0) { @@ -287,7 +190,7 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descri static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len) { int i; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE); + int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9); int retval; if (parsed < 0) @@ -334,9 +237,7 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface_desc static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len) { - int i, j; - int retval; - struct usb_alternate_setting *as; + int i; int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); if (parsed < 0) @@ -345,12 +246,6 @@ static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor memcpy(config, ptr + parsed, *ptr); len -= *ptr; parsed += *ptr; - le16_to_cpus(&config->wTotalLength); - - if (config->MaxPower == 200) { - printk(KERN_ERR "bNumInterfaces kludge\n"); - config->bNumInterfaces += 3; - } if (config->bNumInterfaces > USB_MAXINTERFACES) { @@ -359,59 +254,23 @@ static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor } - config->altsetting = (struct usb_alternate_setting *) - kmalloc(USB_MAXALTSETTING * sizeof(struct usb_alternate_setting), GFP_KERNEL); - if (config->altsetting == NULL) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - config->act_altsetting = 0; - config->num_altsetting = 1; - - config->altsetting->interface = (struct usb_interface_descriptor *) + config->interface = (struct usb_interface_descriptor *) kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if(config->altsetting->interface==NULL) + if(config->interface==NULL) { printk(KERN_WARNING "usb: out of memory.\n"); return -1; } - memset(config->altsetting->interface, - 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + memset(config->interface, 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); for (i = 0; i < config->bNumInterfaces; i++) { - retval = usb_parse_interface(dev, config->altsetting->interface + i, ptr + parsed, len); + int retval = usb_parse_interface(dev, config->interface + i, ptr + parsed, len); if (retval < 0) return parsed; // HACK // return retval; parsed += retval; len -= retval; } - - printk(KERN_DEBUG "parsed = %d len = %d\n", parsed, len); - - // now parse for additional alternate settings - for (j = 1; j < USB_MAXALTSETTING; j++) { - retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9); - if (retval) - break; - config->num_altsetting++; - as = config->altsetting + j; - as->interface = (struct usb_interface_descriptor *) - kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if (as->interface == NULL) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor)); - for (i = 0; i < config->bNumInterfaces; i++) { - retval = usb_parse_interface(dev, as->interface + i, - ptr + parsed, len); - if (retval < 0) - return parsed; - parsed += retval; - len -= retval; - } - } return parsed; } @@ -439,58 +298,34 @@ int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) if (retval < 0) return retval; ptr += retval; - bytes -= retval; + bytes += retval; } - if (bytes) - printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes); return 0; } void usb_destroy_configuration(struct usb_device *dev) { - int c, a, i; + int c, i; struct usb_config_descriptor *cf; - struct usb_alternate_setting *as; struct usb_interface_descriptor *ifp; if(dev->config==NULL) return; - - for(c = 0; c < dev->descriptor.bNumConfigurations; c++) + for(c=0;cdescriptor.bNumConfigurations;c++) { - cf = &dev->config[c]; - if (cf->altsetting == NULL) - break; - for (a = 0; a < cf->num_altsetting; a++) + cf=&dev->config[c]; + if(cf->interface==NULL) + break; + for(i=0;ibNumInterfaces;i++) { - as = &cf->altsetting[a]; - if (as->interface == NULL) - break; - for(i=0;ibNumInterfaces;i++) - { - ifp = &as->interface[i]; - if(ifp->endpoint==NULL) - break; - kfree(ifp->endpoint); - } - kfree(as->interface); + ifp=&cf->interface[i]; + if(ifp->endpoint==NULL) + break; + kfree(ifp->endpoint); } - kfree(cf->altsetting); + kfree(cf->interface); } kfree(dev->config); - - for (i = 1; i < USB_MAXSTRINGS; ++i) { - if (dev->stringindex[i]) { - kfree(dev->stringindex[i]); - dev->stringindex[i] = 0; - } - } -#if 0 - if (dev->stringindex) - kfree(dev->stringindex); - if (dev->stringtable) - kfree(dev->stringtable); -#endif } void usb_init_root_hub(struct usb_device *dev) @@ -511,7 +346,7 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; - printk(KERN_INFO "USB disconnect on device %d\n", dev->devnum); + printk("USB disconnect on device %d\n", dev->devnum); if(dev->driver) dev->driver->disconnect(dev); @@ -568,8 +403,6 @@ int usb_set_address(struct usb_device *dev) int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { devrequest dr; - int i = 5; - int result; dr.requesttype = 0x80; dr.request = USB_REQ_GET_DESCRIPTOR; @@ -577,38 +410,12 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char dr.index = 0; dr.length = size; - while (i--) { - if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)) - || result == USB_ST_STALL) - break; - } - return result; -} - -int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) -{ - devrequest dr; - - dr.requesttype = 0x80; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (USB_DT_STRING << 8) + index; - dr.index = langid; - dr.length = size; - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size); } int usb_get_device_descriptor(struct usb_device *dev) { - int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, - sizeof(dev->descriptor)); - if (ret == 0) { - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); - } - return ret; + return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); } int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) @@ -650,19 +457,6 @@ int usb_set_port_feature(struct usb_device *dev, int port, int feature) return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); } -int usb_get_status (struct usb_device *dev, int type, int target, void *data) -{ - devrequest dr; - - dr.requesttype = USB_DIR_IN | type; /* USB_RECIP_DEVICE, _INTERFACE, or _ENDPOINT */ - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = target; - dr.length = 2; - - return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2); -} - int usb_get_hub_status(struct usb_device *dev, void *data) { devrequest dr; @@ -740,120 +534,19 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id) return 0; } -static void usb_set_maxpacket(struct usb_device *dev) -{ - int i; - struct usb_endpoint_descriptor *ep; - int act_as = dev->actconfig->act_altsetting; - struct usb_alternate_setting *as = dev->actconfig->altsetting + act_as; - struct usb_interface_descriptor *ip = as->interface; - - for (i=0; iactconfig->bNumInterfaces; i++) { - if (as->interface[i].bInterfaceNumber == dev->ifnum) { - ip = &as->interface[i]; - break; - } - } - ep = ip->endpoint; - for (i=0; ibNumEndpoints; i++) { - dev->epmaxpacket[ep[i].bEndpointAddress & 0x0f] = ep[i].wMaxPacketSize; - } -} - -int usb_clear_halt(struct usb_device *dev, int endp) -{ - devrequest dr; - int result; - __u16 status; - - //if (!usb_endpoint_halted(dev, endp)) - // return 0; - - dr.requesttype = USB_RT_ENDPOINT; - dr.request = USB_REQ_CLEAR_FEATURE; - dr.value = 0; - dr.index = endp; - dr.length = 0; - - result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); - - /* dont clear if failed */ - if (result) { - return result; - } - -#if 1 /* lets be really tough */ - dr.requesttype = 0x80 | USB_RT_ENDPOINT; - dr.request = USB_REQ_GET_STATUS; - dr.length = 2; - status = 0xffff; - - result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2); - - if (result) { - return result; - } - if (status & 1) { - return 1; /* still halted */ - } -#endif - usb_endpoint_running(dev, endp & 0x0f); - - /* toggle is reset on clear */ - - usb_settoggle(dev, endp & 0x0f, ((endp >> 7) & 1) ^ 1, 0); - - return 0; -} - -int usb_set_interface(struct usb_device *dev, int interface, int alternate) -{ - devrequest dr; - - dr.requesttype = 1; - dr.request = USB_REQ_SET_INTERFACE; - dr.value = alternate; - dr.index = interface; - dr.length = 0; - - if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) - return -1; - - dev->ifnum = interface; - dev->actconfig->act_altsetting = alternate; - usb_set_maxpacket(dev); - return 0; -} - int usb_set_configuration(struct usb_device *dev, int configuration) { devrequest dr; - int i; - struct usb_config_descriptor *cp = NULL; - + dr.requesttype = 0; dr.request = USB_REQ_SET_CONFIGURATION; dr.value = configuration; dr.index = 0; dr.length = 0; - for (i=0; idescriptor.bNumConfigurations; i++) { - if (dev->config[i].bConfigurationValue == configuration) { - cp = &dev->config[i]; - break; - } - } - if (!cp) { - printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration); - return -1; - } if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) return -1; - dev->actconfig = cp; - dev->toggle[0] = 0; - dev->toggle[1] = 0; - usb_set_maxpacket(dev); return 0; } @@ -876,139 +569,30 @@ int usb_get_report(struct usb_device *dev) int usb_get_configuration(struct usb_device *dev) { - unsigned int cfgno; + unsigned int cfgno,size; + unsigned char buffer[400]; unsigned char * bufptr; - unsigned char * buffer; - int parse; - - buffer = (unsigned char *) __get_free_page (GFP_KERNEL); - if (!buffer) - return -1; - - bufptr = buffer; - for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { - unsigned int size; + + bufptr=buffer; + for (cfgno=0;cfgnodescriptor.bNumConfigurations;cfgno++) { /* Get the first 8 bytes - guaranteed */ - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) { - __free_page ((struct page *) buffer); + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) return -1; - } /* Get the full buffer */ - size = le16_to_cpup((unsigned short *)(bufptr+2)); - if (bufptr+size > buffer+PAGE_SIZE) { + size = *(unsigned short *)(bufptr+2); + if (bufptr+size > buffer+sizeof(buffer)) + { printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); - size = buffer+PAGE_SIZE-bufptr; + size = buffer+sizeof(buffer)-bufptr; } - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) { - __free_page ((struct page *) buffer); + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) return -1; - } /* Prepare for next configuration */ - bufptr += size; + bufptr+=size; } - parse = usb_parse_configuration(dev, buffer, bufptr - buffer); - __free_page ((struct page *) buffer); - return parse; -} - -#if 0 -int usb_get_stringtable(struct usb_device *dev) -{ - int i; - int maxindex; - int langid; - unsigned char buffer[256]; - int totalchars; - struct usb_string_descriptor *sd = (struct usb_string_descriptor *)buffer; - char *string; - __u8 bLengths[USB_MAXSTRINGS+1]; - int j; - - dev->maxstring = 0; - if(usb_get_string(dev, 0, 0, buffer, 2) || - usb_get_string(dev, 0, 0, buffer, sd->bLength)) - return -1; - /* we are going to assume that the first ID is good */ - langid = le16_to_cpup(&sd->wData[0]); - - /* whip through and find total length and max index */ - for (maxindex = 1, totalchars = 0; maxindex<=USB_MAXSTRINGS; maxindex++) { - if(usb_get_string(dev, langid, maxindex, buffer, 2)) - break; - totalchars += (sd->bLength - 2)/2 + 1; - bLengths[maxindex] = sd->bLength; - } - if (--maxindex <= 0) - return -1; - - /* get space for strings and index */ - dev->stringindex = kmalloc(sizeof(char *) * (maxindex+1), GFP_KERNEL); - if (!dev->stringindex) - return -1; - dev->stringtable = kmalloc(totalchars, GFP_KERNEL); - if (!dev->stringtable) { - kfree(dev->stringindex); - dev->stringindex = NULL; - return -1; - } - - /* fill them in */ - memset(dev->stringindex, 0, sizeof(char *) * (maxindex+1)); - for (i=1, string = dev->stringtable; i <= maxindex; i++) { - if (usb_get_string(dev, langid, i, buffer, bLengths[i])) - continue; - dev->stringindex[i] = string; - for (j=0; j < (bLengths[i] - 2)/2; j++) { - *string++ = le16_to_cpup(&sd->wData[j]); - } - *string++ = '\0'; - } - dev->maxstring = maxindex; - return 0; -} -#endif - -char *usb_string(struct usb_device *dev, int index) -{ - int len, i; - char *ptr; - union { - unsigned char buffer[256]; - struct usb_string_descriptor desc; - } u; - - if (index <= 0 || index >= USB_MAXSTRINGS) - return 0; - if (dev->stringindex[index] != 0) - return dev->stringindex[index]; - - if (dev->string_langid == 0) { - /* read string descriptor 0 */ - if (usb_get_string(dev, 0, 0, u.buffer, 2) == 0 - && u.desc.bLength >= 4 - && usb_get_string(dev, 0, 0, u.buffer, 4) == 0) - dev->string_langid = le16_to_cpup(&u.desc.wData[0]); - dev->string_langid |= 0x10000; /* so it's non-zero */ - } - - if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) - || usb_get_string(dev, dev->string_langid, index, u.buffer, - u.desc.bLength)) - return 0; - - len = u.desc.bLength / 2; /* includes terminating null */ - ptr = kmalloc(len, GFP_KERNEL); - if (ptr == 0) - return 0; - - for (i = 0; i < len - 1; ++i) - ptr[i] = le16_to_cpup(&u.desc.wData[i]); - ptr[i] = 0; - - dev->stringindex[index] = ptr; - return ptr; + return usb_parse_configuration(dev, buffer, size); } /* @@ -1020,34 +604,30 @@ void usb_new_device(struct usb_device *dev) { int addr, i; - printk(KERN_INFO "USB new device connect, assigned device number %d\n", + printk("USB new device connect, assigned device number %d\n", dev->devnum); dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ - dev->epmaxpacket[0] = 8; addr = dev->devnum; dev->devnum = 0; -#if 1 /* Slow devices */ for (i = 0; i < 5; i++) { if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) break; - printk(KERN_ERR "get_descriptor failed, waiting\n"); + printk("get_descriptor failed, waiting\n"); wait_ms(200); } if (i == 5) { - printk(KERN_ERR "giving up\n"); + printk("giving up\n"); return; } -#endif #if 0 printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0); #endif - dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { case 8: dev->maxpacketsize = 0; break; case 16: dev->maxpacketsize = 1; break; @@ -1060,98 +640,34 @@ void usb_new_device(struct usb_device *dev) dev->devnum = addr; -#if 1 if (usb_set_address(dev)) { - printk(KERN_ERR "Unable to set address\n"); + printk("Unable to set address\n"); /* FIXME: We should disable the port */ return; } -#else - usb_set_address(dev); -#endif wait_ms(10); /* Let the SET_ADDRESS settle */ if (usb_get_device_descriptor(dev)) { - printk(KERN_ERR "Unable to get device descriptor\n"); + printk("Unable to get device descriptor\n"); return; } if (usb_get_configuration(dev)) { - printk(KERN_ERR "Unable to get configuration\n"); + printk("Unable to get configuration\n"); return; } - /* usb_get_stringtable(dev); */ - - dev->actconfig = dev->config; - dev->ifnum = 0; - usb_set_maxpacket(dev); - - usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer); - usb_show_string(dev, "Product", dev->descriptor.iProduct); - usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); - #if 0 printk("Vendor: %X\n", dev->descriptor.idVendor); printk("Product: %X\n", dev->descriptor.idProduct); #endif - if (usb_device_descriptor(dev)==0) - { - /* - * Ok, no driver accepted the device, so show the info for - * debugging - */ - printk (KERN_WARNING "Unknown new USB device:\n"); - usb_show_device(dev); - } + usb_device_descriptor(dev); } -void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); } - -void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id); -} - -void usb_delete_isochronous (struct usb_device *dev, void *_isodesc) -{ - return dev->bus->op->delete_isoc (dev, _isodesc); -} - -int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - return usb_dev->bus->op->sched_isoc (usb_dev, _isodesc, _pisodesc); -} - -int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return usb_dev->bus->op->unsched_isoc (usb_dev, _isodesc); -} - -int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return usb_dev->bus->op->compress_isoc (usb_dev, _isodesc); -} - -int usb_release_irq(struct usb_device *dev, void* handle) -{ - return dev->bus->op->release_irq(handle); -} - -#ifdef CONFIG_PROC_FS -struct list_head * usb_driver_get_list (void) -{ - return &usb_driver_list; -} - -struct list_head * usb_bus_get_list (void) -{ - return &usb_bus_list; -} -#endif diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index 7414f6a51189..10379ef88da4 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -6,24 +6,6 @@ #include #include -#include -#if LINUX_VERSION_CODE < 0x020300 -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define wait_queue_head_t struct wait_queue * -#define init_waitqueue_head(w) *(w) = 0 -#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED -#endif - -extern int usb_hub_init(void); -extern int usb_kbd_init(void); -extern int usb_cpia_init(void); -extern int usb_mouse_init(void); -extern int usb_printer_init(void); - -extern void hub_cleanup(void); -extern void usb_mouse_cleanup(void); - static __inline__ void wait_ms(unsigned int ms) { current->state = TASK_UNINTERRUPTIBLE; @@ -40,16 +22,9 @@ typedef struct { } devrequest; /* - * Device and/or Interface Class codes + * Class codes */ -#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ -#define USB_CLASS_AUDIO 1 -#define USB_CLASS_COMM 2 -#define USB_CLASS_HID 3 -#define USB_CLASS_PRINTER 7 -#define USB_CLASS_MASS_STORAGE 8 #define USB_CLASS_HUB 9 -#define USB_CLASS_VENDOR_SPEC 0xff /* * Descriptor types @@ -63,28 +38,6 @@ typedef struct { #define USB_DT_HUB 0x29 #define USB_DT_HID 0x21 -/* - * Descriptor sizes per descriptor type - */ -#define USB_DT_DEVICE_SIZE 18 -#define USB_DT_CONFIG_SIZE 9 -#define USB_DT_INTERFACE_SIZE 9 -#define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_HUB_NONVAR_SIZE 7 - -/* - * USB Request Type and Endpoint Directions - */ -#define USB_DIR_OUT 0 -#define USB_DIR_IN 0x80 - -/* - * USB Packet IDs (PIDs) - */ -#define USB_PID_OUT 0xe1 -#define USB_PID_IN 0x69 -#define USB_PID_SETUP 0x2d - /* * Standard requests */ @@ -134,32 +87,6 @@ typedef struct { #define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) -/* - * Status codes (these follow an OHCI controllers condition codes) - */ -#define USB_ST_NOERROR 0x0 -#define USB_ST_CRC 0x1 -#define USB_ST_BITSTUFF 0x2 -#define USB_ST_DTMISMATCH 0x3 /* data toggle mismatch */ -#define USB_ST_STALL 0x4 -#define USB_ST_NORESPONSE 0x5 /* device not responding/handshaking */ -#define USB_ST_PIDCHECK 0x6 /* Check bits on PID failed */ -#define USB_ST_PIDUNDEF 0x7 /* PID unexpected/undefined */ -#define USB_ST_DATAOVERRUN 0x8 -#define USB_ST_DATAUNDERRUN 0x9 -#define USB_ST_RESERVED1 0xA -#define USB_ST_RESERVED2 0xB -#define USB_ST_BUFFEROVERRUN 0xC -#define USB_ST_BUFFERUNDERRUN 0xD -#define USB_ST_RESERVED3 0xE -#define USB_ST_RESERVED4 0xF - -/* internal errors */ -#define USB_ST_REMOVED 0x100 -#define USB_ST_TIMEOUT 0x110 -#define USB_ST_INTERNALERROR -1 -#define USB_ST_NOTSUPPORTED -2 - /* * USB device number allocation bitmap. There's one bitmap * per USB tree. @@ -176,10 +103,8 @@ struct usb_devmap { */ #define USB_MAXCONFIG 8 -#define USB_MAXALTSETTING 5 #define USB_MAXINTERFACES 32 #define USB_MAXENDPOINTS 32 -#define USB_MAXSTRINGS 32 struct usb_device_descriptor { __u8 bLength; @@ -225,11 +150,6 @@ struct usb_interface_descriptor { void *audio; }; -/* hack for alternate settings */ -struct usb_alternate_setting { - struct usb_interface_descriptor *interface; -}; - /* Configuration descriptor information.. */ struct usb_config_descriptor { __u8 bLength; @@ -240,16 +160,14 @@ struct usb_config_descriptor { __u8 iConfiguration; __u8 bmAttributes; __u8 MaxPower; - int act_altsetting; /* active alternate setting */ - int num_altsetting; /* number of alternate settings */ - struct usb_alternate_setting *altsetting; + + struct usb_interface_descriptor *interface; }; /* String descriptor */ struct usb_string_descriptor { __u8 bLength; __u8 bDescriptorType; - __u16 wData[1]; }; /* Hub descriptor */ @@ -257,7 +175,7 @@ struct usb_hub_descriptor { __u8 bLength; __u8 bDescriptorType; __u8 bNbrPorts; - __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */ + __u16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; /* DeviceRemovable and PortPwrCtrlMask want to be variable-length @@ -282,28 +200,16 @@ struct usb_driver { * until we come up with a common meaning. * void *buffer - This is a pointer to the data used in this * USB transfer. - * int length - This is the number of bytes transferred in or out - * of the buffer by this transfer. (-1 = unknown/unsupported) * void *dev_id - This is a user defined pointer set when the IRQ * is requested that is passed back. - * - * Special Cases: - * if (status == USB_ST_REMOVED), don't trust buffer or len. */ -typedef int (*usb_device_irq)(int, void *, int, void *); +typedef int (*usb_device_irq)(int, void *, void *); struct usb_operations { struct usb_device *(*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); - int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int); - int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *); - void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); - int (*release_irq)(void* handle); - void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id); - void (*delete_isoc)(struct usb_device *dev, void *_isodesc); - int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); - int (*unsched_isoc)(struct usb_device *usb_dev, void *_isodesc); - int (*compress_isoc)(struct usb_device *usb_dev, void *_isodesc); + int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int); + int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); }; /* @@ -313,7 +219,6 @@ struct usb_bus { struct usb_devmap devmap; /* Device map */ struct usb_operations *op; /* Operations (specific to the HC) */ struct usb_device *root_hub; /* Root hub */ - struct list_head bus_list; void *hcpriv; /* Host Controller private data */ }; @@ -321,28 +226,22 @@ struct usb_bus { #define USB_MAXCHILDREN (8) struct usb_device { - int devnum; /* Device number on USB bus */ - int slow; /* Slow device? */ - int maxpacketsize; /* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */ - unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ - unsigned int halted; /* endpoint halts */ - struct usb_config_descriptor *actconfig;/* the active configuration */ - int epmaxpacket[16]; /* endpoint specific maximums */ - int ifnum; /* active interface number */ - struct usb_bus *bus; /* Bus we're apart of */ - struct usb_driver *driver; /* Driver */ - struct usb_device_descriptor descriptor;/* Descriptor */ - struct usb_config_descriptor *config; /* All of the configs */ + int devnum; /* Device number on USB bus */ + int slow; /* Slow device? */ + int maxpacketsize; /* Maximum packet size */ + + struct usb_bus *bus; /* Bus we're apart of */ + struct usb_driver *driver; /* Driver */ + struct usb_device_descriptor descriptor; /* Descriptor */ + struct usb_config_descriptor *config; /* All of the configs */ struct usb_device *parent; - char *stringindex[USB_MAXSTRINGS]; /* pointers to strings */ - int string_langid; /* language ID for strings */ /* * Child devices - these can be either new devices * (if this is a hub device), or different instances * of this same device. * - * Each instance needs its own set of data structures. + * Each instance needs its own set of data structuctures. */ int maxchild; /* Number of ports if hub */ @@ -355,28 +254,14 @@ struct usb_device { extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); -extern void usb_register_bus(struct usb_bus *); -extern void usb_deregister_bus(struct usb_bus *); - -extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); -extern int usb_release_irq(struct usb_device *dev, void *handle); +extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); extern void usb_init_root_hub(struct usb_device *dev); extern void usb_connect(struct usb_device *dev); extern void usb_disconnect(struct usb_device **); +extern void usb_device_descriptor(struct usb_device *dev); -extern int usb_device_descriptor(struct usb_device *dev); -void usb_check_support(struct usb_device *); -void usb_driver_purge(struct usb_driver *,struct usb_device *); extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); -extern void usb_destroy_configuration(struct usb_device *dev); - -extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, - int maxsze, usb_device_irq completed, void *dev_id); -extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc); -extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); -extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc); -extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc); /* * Calling this entity a "pipe" is glorifying it. A USB pipe @@ -397,47 +282,36 @@ extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) * Let's not fall in that trap. We'll just encode it as a simple * unsigned int. The encoding is: * - * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) - * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) * - device: bits 8-14 * - endpoint: bits 15-18 * - Data0/1: bit 19 - * - speed: bit 26 (0 = Full, 1 = Low Speed) + * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) + * - speed: bit 26 (0 = High, 1 = Low Speed) + * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) * * Why? Because it's arbitrary, and whatever encoding we select is really - * up to us. This one happens to share a lot of bit positions with the UHCI + * up to us. This one happens to share a lot of bit positions with the UCHI * specification, so that much of the uhci driver can just mask the bits * appropriately. */ -#define usb_maxpacket(dev,pipe) ((dev)->epmaxpacket[usb_pipeendpoint(pipe)]) +#define usb_maxpacket(pipe) (8 << ((pipe) & 3)) #define usb_packetid(pipe) (((pipe) & 0x80) ? 0x69 : 0xE1) -#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1) -#define usb_pipein(pipe) (((pipe) >> 7) & 1) #define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) -#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) #define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) #define usb_pipedata(pipe) (((pipe) >> 19) & 1) +#define usb_pipeout(pipe) (((pipe) & 0x80) == 0) #define usb_pipeslow(pipe) (((pipe) >> 26) & 1) + #define usb_pipetype(pipe) (((pipe) >> 30) & 3) #define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == 0) #define usb_pipeint(pipe) (usb_pipetype((pipe)) == 1) #define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == 2) #define usb_pipebulk(pipe) (usb_pipetype((pipe)) == 3) -#define PIPE_DEVEP_MASK 0x0007ff00 - -/* The D0/D1 toggle bits */ -#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1) -#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep)) -#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep)) - -/* Endpoint halt */ -#define usb_endpoint_halt(dev, ep) ((dev)->halted |= (1 << (ep))) -#define usb_endpoint_running(dev, ep) ((dev)->halted &= ~(1 << (ep))) -#define usb_endpoint_halted(dev, ep) ((dev)->halted & (1 << (ep))) +#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) { @@ -449,16 +323,14 @@ static inline unsigned int __default_pipe(struct usb_device *dev) return (dev->slow << 26); } -/* Create various pipes... */ +/* Create control pipes.. */ #define usb_sndctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint)) #define usb_rcvctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint) | 0x80) -#define usb_sndisocpipe(dev,endpoint) ((0 << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvisocpipe(dev,endpoint) ((0 << 30) | __create_pipe(dev,endpoint) | 0x80) -#define usb_sndbulkpipe(dev,endpoint) ((3 << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvbulkpipe(dev,endpoint) ((3 << 30) | __create_pipe(dev,endpoint) | 0x80) #define usb_snddefctrl(dev) ((2 << 30) | __default_pipe(dev)) #define usb_rcvdefctrl(dev) ((2 << 30) | __default_pipe(dev) | 0x80) +/* Create .. */ + /* * Send and receive control messages.. */ @@ -470,18 +342,13 @@ int usb_get_device_descriptor(struct usb_device *dev); int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size); int usb_clear_port_feature(struct usb_device *dev, int port, int feature); int usb_set_port_feature(struct usb_device *dev, int port, int feature); -int usb_get_status (struct usb_device *dev, int type, int target, void *data); int usb_get_hub_status(struct usb_device *dev, void *data); int usb_get_port_status(struct usb_device *dev, int port, void *data); int usb_get_protocol(struct usb_device *dev); int usb_set_protocol(struct usb_device *dev, int protocol); -int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_idle(struct usb_device *dev, int duration, int report_id); -int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_configuration(struct usb_device *dev, int configuration); int usb_get_report(struct usb_device *dev); -char *usb_string(struct usb_device *dev, int index); -int usb_clear_halt(struct usb_device *dev, int endp); /* * Debugging helpers.. @@ -492,7 +359,6 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor *); void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); void usb_show_hub_descriptor(struct usb_hub_descriptor *); void usb_show_device(struct usb_device *); -void usb_show_string(struct usb_device* dev, char *id, int index); /* * Audio parsing helpers diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c deleted file mode 100644 index e2e2d5bc593c..000000000000 --- a/drivers/usb/usb_scsi.c +++ /dev/null @@ -1,1453 +0,0 @@ - -/* Driver for USB scsi like devices - * - * (C) Michael Gee (michael@linuxspecific.com) 1999 - * - * This driver is scitzoid - it makes a USB device appear as both a SCSI device - * and a character device. The latter is only available if the device has an - * interrupt endpoint, and is used specifically to receive interrupt events. - * - * In order to support various 'strange' devices, this module supports plug in - * device specific filter modules, which can do their own thing when required. - * - * Further reference. - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the transformation of SCSI command blocks to the - * equivalent USB control and data transfer required. - * It is important to note that in a number of cases this class exhibits - * class-specific exemptions from the USB specification. Notably the - * usage of NAK, STALL and ACK differs from the norm, in that they are - * used to communicate wait, failed and OK on SCSI commands. - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Basically, this stuff is WIERD!! - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" - -#include "usb.h" -#include "usb_scsi.h" - -/* direction table (what a pain) */ - -unsigned char us_direction[256/8] = { - -#include "usb_scsi_dt.c" - -}; - -/* - * Per device data - */ - -static int my_host_number; - -int usbscsi_debug = 1; - -struct us_data { - struct us_data *next; /* next device */ - struct usb_device *pusb_dev; - struct usb_scsi_filter *filter; /* filter driver */ - void *fdata; /* filter data */ - unsigned int flags; /* from filter initially*/ - __u8 ep_in; /* in endpoint */ - __u8 ep_out; /* out ....... */ - __u8 ep_int; /* interrupt . */ - __u8 subclass; /* as in overview */ - __u8 protocol; /* .............. */ - __u8 attention_done; /* force attention on first command */ - int (*pop)(Scsi_Cmnd *); /* protocol specific do cmd */ - int (*pop_reset)(struct us_data *); /* ................. device reset */ - GUID(guid); /* unique dev id */ - struct Scsi_Host *host; /* our dummy host data */ - Scsi_Host_Template *htmplt; /* own host template */ - int host_number; /* to find us */ - int host_no; /* allocated by scsi */ - int fixedlength; /* expand commands */ - Scsi_Cmnd *srb; /* current srb */ - int action; /* what to do */ - wait_queue_head_t waitq; /* thread waits */ - wait_queue_head_t ip_waitq; /* for CBI interrupts */ - __u16 ip_data; /* interrupt data */ - int ip_wanted; /* needed */ - int pid; /* control thread */ - struct semaphore *notify; /* wait for thread to begin */ -}; - -/* - * kernel thread actions - */ - -#define US_ACT_COMMAND 1 -#define US_ACT_ABORT 2 -#define US_ACT_DEVICE_RESET 3 -#define US_ACT_BUS_RESET 4 -#define US_ACT_HOST_RESET 5 - -static struct proc_dir_entry proc_usb_scsi = -{ - PROC_SCSI_USB_SCSI, - 0, - NULL, - S_IFDIR | S_IRUGO | S_IXUGO, - 2 -}; - -static struct us_data *us_list; - -static struct usb_scsi_filter *filters; - -static int scsi_probe(struct usb_device *dev); -static void scsi_disconnect(struct usb_device *dev); -static struct usb_driver scsi_driver = { - "usb_scsi", - scsi_probe, - scsi_disconnect, - { NULL, NULL } -}; - -/* Data handling, using SG if required */ - -static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) -{ - int max_size = usb_maxpacket(us->pusb_dev, pipe) * 16; - int this_xfer; - int result; - unsigned long partial; - int maxtry = 100; - while (length) { - this_xfer = length > max_size ? max_size : length; - length -= this_xfer; - do { - /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/ - result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, - this_xfer, &partial); - - if (result != 0 || partial != this_xfer) - US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n", - result, partial, this_xfer); - - if (result == USB_ST_STALL) { - US_DEBUGP("clearing endpoing halt for pipe %x\n", pipe); - usb_clear_halt(us->pusb_dev, - usb_pipeendpoint(pipe) | (pipe & 0x80)); - } - - /* we want to retry if the device reported NAK */ - if (result == USB_ST_TIMEOUT) { - if (partial != this_xfer) { - return 0; /* I do not like this */ - } - if (!maxtry--) - break; - this_xfer -= partial; - buf += partial; - } else if (!result && partial != this_xfer) { - /* short data - assume end */ - result = USB_ST_DATAUNDERRUN; - break; - } else if (result == USB_ST_STALL && us->protocol == US_PR_CB) { - if (!maxtry--) - break; - this_xfer -= partial; - buf += partial; - } else - break; - } while ( this_xfer ); - if (result) - return result; - buf += this_xfer; - } - return 0; - -} - -static int us_transfer(Scsi_Cmnd *srb, int dir_in) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - int i; - int result = -1; - unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : - usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - if (srb->use_sg) { - struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; - - for (i = 0; i < srb->use_sg; i++) { - result = us_one_transfer(us, pipe, sg[i].address, sg[i].length); - if (result) - break; - } - } - else - result = us_one_transfer(us, pipe, - srb->request_buffer, srb->request_bufflen); - - if (result) - US_DEBUGP("us_transfer returning error %d\n", result); - return result; -} - -static unsigned int us_transfer_length(Scsi_Cmnd *srb) -{ - int i; - unsigned int total = 0; - - /* always zero for some commands */ - switch (srb->cmnd[0]) { - case SEEK_6: - case SEEK_10: - case REZERO_UNIT: - case ALLOW_MEDIUM_REMOVAL: - case START_STOP: - case TEST_UNIT_READY: - return 0; - - default: - break; - } - - if (srb->use_sg) { - struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; - - for (i = 0; i < srb->use_sg; i++) { - total += sg[i].length; - } - return total; - } - else - return srb->request_bufflen; - -} - -static int pop_CBI_irq(int state, void *buffer, int len, void *dev_id) -{ - struct us_data *us = (struct us_data *)dev_id; - - if (state != USB_ST_REMOVED) { - us->ip_data = le16_to_cpup((__u16 *)buffer); - if (us->ip_data != 0) - US_DEBUGP("Interrupt Status %x\n", us->ip_data); - } - if (us->ip_wanted) { - us->ip_wanted = 0; - wake_up(&us->ip_waitq); - } - - /* we dont want another interrupt */ - - return 0; -} - -static int pop_CB_reset(struct us_data *us) -{ - unsigned char cmd[12]; - devrequest dr; - - US_DEBUGP("pop_CB_reset\n"); - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE; - dr.request = US_CBI_ADSC; - dr.value = 0; - dr.index = us->pusb_dev->ifnum; - dr.length = 12; - memset(cmd, -1, sizeof(cmd)); - cmd[0] = SEND_DIAGNOSTIC; - cmd[1] = 4; - us->pusb_dev->bus->op->control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev,0), - &dr, cmd, 12); - - /* long wait for reset */ - - schedule_timeout(HZ*5); - - US_DEBUGP("pop_CB_reset: clearing endpoint halt\n"); - usb_clear_halt(us->pusb_dev, us->ep_in | 0x80); - usb_clear_halt(us->pusb_dev, us->ep_out); - - US_DEBUGP("pop_CB_reset done\n"); - return 0; -} - -static int pop_CB_command(Scsi_Cmnd *srb, unsigned char *cmnd, int cmd_len) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - devrequest dr; - int result; - int retry = 5; - int done_start = 0; - - while (retry--) { - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE; - dr.request = US_CBI_ADSC; - dr.value = 0; - dr.index = us->pusb_dev->ifnum; - dr.length = cmd_len; - - result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev,0), - &dr, cmnd, cmd_len); - - if (result && !done_start && (us->flags & US_FL_FIXED_COMMAND) - && cmnd[0] == TEST_UNIT_READY - && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)) { - /* as per spec try a start command, wait and retry */ - - done_start++; - cmnd[0] = START_STOP; - cmnd[4] = 1; /* start */ - result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev,0), - &dr, cmnd, cmd_len); - wait_ms(100); - retry++; - cmnd[0] = TEST_UNIT_READY; - cmnd[4] = 0; - continue; - } - if (result != USB_ST_TIMEOUT) - break; - } - return result; -} - -/* - * Control/Bulk status handler - */ - -static int pop_CB_status(Scsi_Cmnd *srb) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - int result; - __u8 status[2]; - devrequest dr; - int retry = 5; - void *irq_handle; - - switch (us->protocol) { - case US_PR_CB: - /* get from control */ - - while (retry--) { - dr.requesttype = 0x80 | USB_TYPE_STANDARD | USB_RT_DEVICE; - dr.request = USB_REQ_GET_STATUS; - dr.index = 0; - dr.value = 0; - dr.length = 2; - result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev,0), - &dr, status, sizeof(status)); - if (result != USB_ST_TIMEOUT) - break; - } - if (result) { - US_DEBUGP("Bad AP status request %d\n", result); - return DID_ABORT << 16; - } - US_DEBUGP("Got AP status %x %x\n", status[0], status[1]); - if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY && - ( (status[0] & ~3) || status[1])) - return (DID_OK << 16) | 2; - else - return DID_OK << 16; - break; - - case US_PR_CBI: - /* get from interrupt pipe */ - - /* add interrupt transfer, marked for removal */ - us->ip_wanted = 1; - irq_handle = us->pusb_dev->bus->op->request_irq - (us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev, us->ep_int), - pop_CBI_irq, 0, (void *)us); - if (irq_handle == 0) { - US_DEBUGP("No interrupt for CBI %x\n", result); - return DID_ABORT << 16; - } - sleep_on(&us->ip_waitq); - if (us->ip_wanted) { - US_DEBUGP("Did not get interrupt on CBI\n"); - us->ip_wanted = 0; - return DID_ABORT << 16; - } - - if (us->ip_data != 0) - US_DEBUGP("Got interrupt data %x\n", us->ip_data); - - /* sort out what it means */ - - if (us->subclass == US_SC_UFI) { - /* gives us asc and ascq, as per request sense */ - - if (srb->cmnd[0] == REQUEST_SENSE || - srb->cmnd[0] == INQUIRY) - return DID_OK << 16; - else - return (DID_OK << 16) + ((us->ip_data & 0xff) ? 2 : 0); - } - if (us->ip_data & 0xff) { - US_DEBUGP("Bad CBI interrupt data %x\n", us->ip_data); - return DID_ABORT << 16; - } - return (DID_OK << 16) + ((us->ip_data & 0x300) ? 2 : 0); - } - return DID_ERROR << 16; -} - -/* Protocol command handlers */ - -static int pop_CBI(Scsi_Cmnd *srb) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - unsigned char cmd[16]; - unsigned char *cmdp; - int cmd_len, len; - int result; - unsigned char modebuf[260]; - unsigned char *savebuf = srb->request_buffer; - int savelen = srb->request_bufflen; - - /* first fix some commands */ - cmdp = srb->cmnd; - cmd_len = srb->cmd_len; - - if (us->flags & US_FL_FIXED_COMMAND) { - cmdp = cmd; - cmd_len = us->fixedlength; - memset(cmd, 0, cmd_len); - - switch (srb->cmnd[0]) { - case WRITE_6: - case READ_6: - cmd[0] = srb->cmnd[0] | 0x20; - cmd[1] = srb->cmnd[1] & 0xE0; - cmd[2] = 0; - cmd[3] = srb->cmnd[1] & 0x1F; - cmd[4] = srb->cmnd[2]; - cmd[5] = srb->cmnd[3]; - cmd[8] = srb->cmnd[4]; - break; - - case MODE_SENSE: - if (srb->use_sg > 0) - US_DEBUGP("MODE SENSE with use_sg=%d!!!\n", srb->use_sg); - len = srb->cmnd[4] + 4; - cmd[0] = srb->cmnd[0] | 0x40; /* op code */ - cmd[1] = srb->cmnd[1]; /* LUN, various bits */ - cmd[2] = srb->cmnd[2]; /* page code */ - cmd[8] = len; /* allocation length */ - cmd[7] = len >> 8; - srb->request_buffer = modebuf; - srb->request_bufflen = len; - break; - - case MODE_SELECT: - if (srb->use_sg > 0) - US_DEBUGP("MODE SELECT with use_sg=%d!!!\n", srb->use_sg); - len = srb->cmnd[4] + 4; - memset(modebuf, 0, 8); - modebuf[1] = savebuf[0]; - modebuf[2] = savebuf[1]; - modebuf[3] = savebuf[2]; - modebuf[7] = savebuf[3]; - if (len > 8) - memcpy(modebuf+8, savebuf+4, len-8); - srb->request_buffer = modebuf; - srb->request_bufflen = len; - cmd[0] = srb->cmnd[0] | 0x40; - cmd[1] = srb->cmnd[1]; - cmd[2] = srb->cmnd[2]; - cmd[8] = len; - cmd[7] = len >> 8; - break; - - default: - memcpy(cmd, srb->cmnd, srb->cmd_len); - break; - } - } - - /* run the command */ - if ((result = pop_CB_command(srb, cmdp, cmd_len))) { - US_DEBUGP("CBI command %x\n", result); - if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) { - return (DID_OK << 16) | 2; - } - return DID_ERROR << 16; - } - - /* transfer the data */ - - if (us_transfer_length(srb)) { - result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); - if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) { - US_DEBUGP("CBI transfer %x\n", result); - return DID_ERROR << 16; - } -#if 0 - else if (result == USB_ST_DATAUNDERRUN) { - return DID_OK << 16; - } - } else { - if (!result) { - return DID_OK << 16; - } -#endif - } - - if (us->flags & US_FL_FIXED_COMMAND) { - switch (srb->cmnd[0]) { - case MODE_SENSE: - len = srb->cmnd[4]; - savebuf[0] = modebuf[1]; - savebuf[1] = modebuf[2]; - savebuf[2] = modebuf[3]; - savebuf[3] = modebuf[7]; - if (len > 4) - memcpy(savebuf+4, modebuf+8, len-4); - /* fall through */ - case MODE_SELECT: - srb->request_buffer = savebuf; - srb->request_bufflen = savelen; - break; - } - } - - /* get status */ - - return pop_CB_status(srb); -} - -static int pop_Bulk_reset(struct us_data *us) -{ - devrequest dr; - int result; - - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE; - dr.request = US_BULK_RESET; - dr.value = US_BULK_RESET_HARD; - dr.index = 0; - dr.length = 0; - - result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0); - if (result) - US_DEBUGP("Bulk hard reset failed %d\n", result); - usb_clear_halt(us->pusb_dev, us->ep_in | 0x80); - usb_clear_halt(us->pusb_dev, us->ep_out); - - /* long wait for reset */ - - schedule_timeout(HZ*5); - - return result; -} -/* - * The bulk only protocol handler. - * Uses the in and out endpoints to transfer commands and data (nasty) - */ -static int pop_Bulk(Scsi_Cmnd *srb) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - struct bulk_cb_wrap bcb; - struct bulk_cs_wrap bcs; - int result; - unsigned long partial; - int stall; - - /* set up the command wrapper */ - - bcb.Signature = US_BULK_CB_SIGN; - bcb.DataTransferLength = us_transfer_length(srb);; - bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; - bcb.Tag = srb->serial_number; - bcb.Lun = 0; - memset(bcb.CDB, 0, sizeof(bcb.CDB)); - memcpy(bcb.CDB, srb->cmnd, srb->cmd_len); - if (us->flags & US_FL_FIXED_COMMAND) { - bcb.Length = us->fixedlength; - } else { - bcb.Length = srb->cmd_len; - } - - /* send it to out endpoint */ - - US_DEBUGP("Bulk command S %x T %x L %d F %d CL %d\n", bcb.Signature, - bcb.Tag, bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out), &bcb, - US_BULK_CB_WRAP_LEN, &partial); - if (result) { - US_DEBUGP("Bulk command result %x\n", result); - return DID_ABORT << 16; - } - - //return DID_BAD_TARGET << 16; - /* send/receive data */ - - if (bcb.DataTransferLength) { - result = us_transfer(srb, bcb.Flags); - if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) { - US_DEBUGP("Bulk transfer result %x\n", result); - return DID_ABORT << 16; - } - } - - /* get status */ - - - stall = 0; - do { - result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in), &bcs, - US_BULK_CS_WRAP_LEN, &partial); - if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) - stall++; - else - break; - } while ( stall < 3); - if (result && result != USB_ST_DATAUNDERRUN) { - US_DEBUGP("Bulk status result = %x\n", result); - return DID_ABORT << 16; - } - - /* check bulk status */ - - US_DEBUGP("Bulk status S %x T %x R %d V %x\n", bcs.Signature, bcs.Tag, - bcs.Residue, bcs.Status); - if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE) { - US_DEBUGP("Bulk logical error\n"); - return DID_ABORT << 16; - } - switch (bcs.Status) { - case US_BULK_STAT_OK: - return DID_OK << 16; - - case US_BULK_STAT_FAIL: - /* check for underrun - dont report */ - if (bcs.Residue) - return DID_OK << 16; - //pop_Bulk_reset(us); - break; - - case US_BULK_STAT_PHASE: - return DID_ERROR << 16; - } - return (DID_OK << 16) | 2; /* check sense required */ - -} - -/* Host functions */ - -/* detect adapter (always true ) */ -static int us_detect(struct SHT *sht) -{ - /* FIXME - not nice at all, but how else ? */ - struct us_data *us = (struct us_data *)sht->proc_dir; - char name[32]; - - sprintf(name, "usbscsi%d", us->host_number); - proc_usb_scsi.namelen = strlen(name); - proc_usb_scsi.name = kmalloc(proc_usb_scsi.namelen+1, GFP_KERNEL); - if (!proc_usb_scsi.name) - return 0; - strcpy((char *)proc_usb_scsi.name, name); - sht->proc_dir = kmalloc(sizeof(*sht->proc_dir), GFP_KERNEL); - if (!sht->proc_dir) { - kfree(proc_usb_scsi.name); - return 0; - } - *sht->proc_dir = proc_usb_scsi; - sht->name = proc_usb_scsi.name; - us->host = scsi_register(sht, sizeof(us)); - if (us->host) { - us->host->hostdata[0] = (unsigned long)us; - us->host_no = us->host->host_no; - return 1; - } - kfree(proc_usb_scsi.name); - kfree(sht->proc_dir); - return 0; -} - -/* release - must be here to stop scsi - * from trying to release IRQ etc. - * Kill off our data - */ -static int us_release(struct Scsi_Host *psh) -{ - struct us_data *us = (struct us_data *)psh->hostdata[0]; - struct us_data *prev = (struct us_data *)&us_list; - - if (us->filter) - us->filter->release(us->fdata); - if (us->pusb_dev) - usb_deregister(&scsi_driver); - - /* FIXME - leaves hanging host template copy */ - /* (bacause scsi layer uses it after removal !!!) */ - while(prev->next != us) - prev = prev->next; - prev->next = us->next; - return 0; -} - -/* run command */ -static int us_command( Scsi_Cmnd *srb ) -{ - US_DEBUGP("Bad use of us_command\n"); - - return DID_BAD_TARGET << 16; -} - -/* run command */ -static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - /* US_DEBUGP("Command wakeup\n"); */ - if (us->srb) { - /* busy */ - } - srb->host_scribble = (unsigned char *)us; - us->srb = srb; - srb->scsi_done = done; - us->action = US_ACT_COMMAND; - - /* wake up the process task */ - - wake_up_interruptible(&us->waitq); - - return 0; -} - -static int us_abort( Scsi_Cmnd *srb ) -{ - return 0; -} - -static int us_bus_reset( Scsi_Cmnd *srb ) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - us->pop_reset(us); - return SUCCESS; -} - -static int us_host_reset( Scsi_Cmnd *srb ) -{ - return 0; -} - - -#undef SPRINTF -#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } - -int usb_scsi_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) -{ - struct us_data *us = us_list; - char *pos = buffer; - char *vendor; - char *product; - char *style = ""; - - /* find our data from hostno */ - - while (us) { - if (us->host_no == hostno) - break; - us = us->next; - } - - if (!us) - return -ESRCH; - - /* null on outward */ - - if (inout) - return length; - - if (!us->pusb_dev || !(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer))) - vendor = "?"; - if (!us->pusb_dev || !(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct))) - product = "?"; - - switch (us->protocol) { - case US_PR_CB: - style = "Control/Bulk"; - break; - - case US_PR_CBI: - style = "Control/Bulk/Interrupt"; - break; - - case US_PR_ZIP: - style = "Bulk only"; - break; - - } - SPRINTF ("Host scsi%d: usb-scsi\n", hostno); - SPRINTF ("Device: %s %s - GUID " GUID_FORMAT "\n", vendor, product, GUID_ARGS(us->guid) ); - SPRINTF ("Style: %s\n", style); - - /* - * Calculate start of next buffer, and return value. - */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - -/* - * this defines our 'host' - */ - -static Scsi_Host_Template my_host_template = { - NULL, /* next */ - NULL, /* module */ - NULL, /* proc_dir */ - usb_scsi_proc_info, - NULL, /* name - points to unique */ - us_detect, - us_release, - NULL, /* info */ - NULL, /* ioctl */ - us_command, - us_queuecommand, - NULL, /* eh_strategy */ - us_abort, - us_bus_reset, - us_bus_reset, - us_host_reset, - NULL, /* abort */ - NULL, /* reset */ - NULL, /* slave_attach */ - NULL, /* bios_param */ - 1, /* can_queue */ - -1, /* this_id */ - SG_ALL, /* sg_tablesize */ - 1, /* cmd_per_lun */ - 0, /* present */ - FALSE, /* unchecked_isa_dma */ - FALSE, /* use_clustering */ - TRUE, /* use_new_eh_code */ - TRUE /* emulated */ -}; - -static unsigned char sense_notready[] = { - 0x70, /* current error */ - 0x00, - 0x02, /* not ready */ - 0x00, - 0x00, - 10, /* additional length */ - 0x00, - 0x00, - 0x00, - 0x00, - 0x04, /* not ready */ - 0x03, /* manual intervention */ - 0x00, - 0x00, - 0x00, - 0x00 -}; - -static int usbscsi_control_thread(void * __us) -{ - struct us_data *us = (struct us_data *)__us; - int action; - - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources.. - */ - exit_mm(current); - exit_files(current); - //exit_fs(current); - - sprintf(current->comm, "usbscsi%d", us->host_number); - - unlock_kernel(); - - up(us->notify); - - for(;;) { - siginfo_t info; - int unsigned long signr; - - interruptible_sleep_on(&us->waitq); - - action = us->action; - us->action = 0; - - switch (action) { - case US_ACT_COMMAND : - if (us->srb->target || us->srb->lun) { - /* bad device */ - US_DEBUGP( "Bad device number (%d/%d) or dev %x\n", us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev); - us->srb->result = DID_BAD_TARGET << 16; - } else if (!us->pusb_dev) { - - /* our device has gone - pretend not ready */ - - if (us->srb->cmnd[0] == REQUEST_SENSE) { - memcpy(us->srb->request_buffer, sense_notready, sizeof(sense_notready)); - us->srb->result = DID_OK << 16; - } else { - us->srb->result = (DID_OK << 16) | 2; - } - } else { - /* US_DEBUG(us_show_command(us->srb)); */ - - /* check for variable length - do properly if so */ - - if (us->filter && us->filter->command) - us->srb->result = us->filter->command(us->fdata, us->srb); - else if (us->srb->cmnd[0] == START_STOP && - us->pusb_dev->descriptor.idProduct == 0x0001 && - us->pusb_dev->descriptor.idVendor == 0x04e6) - us->srb->result = DID_OK << 16; - else { - unsigned int savelen = us->srb->request_bufflen; - unsigned int saveallocation; - - switch (us->srb->cmnd[0]) { - case REQUEST_SENSE: - if (us->srb->request_bufflen > 18) - us->srb->request_bufflen = 18; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 18; - break; - - case INQUIRY: - if (us->srb->request_bufflen > 36) - us->srb->request_bufflen = 36; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 36; - break; - - case MODE_SENSE: - if (us->srb->request_bufflen > 4) - us->srb->request_bufflen = 4; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 4; - break; - - case LOG_SENSE: - case MODE_SENSE_10: - if (us->srb->request_bufflen > 8) - us->srb->request_bufflen = 8; - else - break; - saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8]; - us->srb->cmnd[7] = 0; - us->srb->cmnd[8] = 8; - break; - - default: - break; - } - us->srb->result = us->pop(us->srb); - - if (savelen != us->srb->request_bufflen && - us->srb->result == (DID_OK << 16)) { - unsigned char *p = (unsigned char *)us->srb->request_buffer; - unsigned int length; - - /* set correct length and retry */ - switch (us->srb->cmnd[0]) { - case REQUEST_SENSE: - /* simply return 18 bytes */ - p[7] = 10; - length = us->srb->request_bufflen;; - break; - - case INQUIRY: - length = p[4] + 5 > savelen ? savelen : p[4] + 5; - us->srb->cmnd[4] = length; - break; - - case MODE_SENSE: - length = p[0] + 4 > savelen ? savelen : p[0] + 4; - us->srb->cmnd[4] = 4; - break; - - case LOG_SENSE: - length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4; - us->srb->cmnd[7] = length >> 8; - us->srb->cmnd[8] = length; - break; - - case MODE_SENSE_10: - length = ((p[0] << 8) + p[1]) + 8 > savelen ? savelen : ((p[0] << 8) + p[1]) + 8; - us->srb->cmnd[7] = length >> 8; - us->srb->cmnd[8] = length; - break; - } - - US_DEBUGP("Old/New length = %d/%d\n", savelen, length); - - if (us->srb->request_bufflen != length) { - us->srb->request_bufflen = length; - us->srb->result = us->pop(us->srb); - } - /* reset back to original values */ - - us->srb->request_bufflen = savelen; - switch (us->srb->cmnd[0]) { - case REQUEST_SENSE: - case INQUIRY: - case MODE_SENSE: - us->srb->cmnd[4] = saveallocation; - break; - - case LOG_SENSE: - case MODE_SENSE_10: - us->srb->cmnd[7] = saveallocation >> 8; - us->srb->cmnd[8] = saveallocation; - break; - } - } - /* force attention on first command */ - if (!us->attention_done) { - US_DEBUGP("forcing unit attention\n"); - if (us->srb->cmnd[0] == REQUEST_SENSE) { - if (us->srb->result == (DID_OK << 16)) { - unsigned char *p = (unsigned char *)us->srb->request_buffer; - - us->attention_done = 1; - if ((p[2] & 0x0f) != UNIT_ATTENTION) { - p[2] = UNIT_ATTENTION; - p[12] = 0x29; /* power on, reset or bus-reset */ - p[13] = 0; - } - } - } else if (us->srb->cmnd[0] != INQUIRY && - us->srb->result == (DID_OK << 16)) { - us->srb->result |= 2; /* force check condition */ - } - } - } - } - if (us->srb->result) { - US_DEBUG(us_show_command(us->srb)); - US_DEBUGP("scsi cmd done, result=%x\n", us->srb->result); - } - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - - case US_ACT_ABORT : - break; - - case US_ACT_DEVICE_RESET : - break; - - case US_ACT_BUS_RESET : - break; - - case US_ACT_HOST_RESET : - break; - - } - - if(signal_pending(current)) { - /* sending SIGUSR1 makes us print out some info */ - spin_lock_irq(¤t->sigmask_lock); - signr = dequeue_signal(¤t->blocked, &info); - spin_unlock_irq(¤t->sigmask_lock); - - if (signr == SIGUSR2) { - printk("USBSCSI debug toggle\n"); - usbscsi_debug = !usbscsi_debug; - } else { - break; - } - } - } - - MOD_DEC_USE_COUNT; - - printk("usbscsi_control_thread exiting\n"); - - return 0; -} - -static int scsi_probe(struct usb_device *dev) -{ - struct usb_interface_descriptor *interface; - int i; - char *mf; /* manufacturer */ - char *prod; /* product */ - char *serial; /* serial number */ - struct us_data *ss = NULL; - struct usb_scsi_filter *filter = filters; - void *fdata = NULL; - unsigned int flags = 0; - GUID(guid); - struct us_data *prev; - Scsi_Host_Template *htmplt; - int protocol = 0; - int subclass = 0; - - GUID_CLEAR(guid); - mf = usb_string(dev, dev->descriptor.iManufacturer); - prod = usb_string(dev, dev->descriptor.iProduct); - serial = usb_string(dev, dev->descriptor.iSerialNumber); - - /* probe with filters first */ - - if (mf && prod) { - while (filter) { - if ((fdata = filter->probe(dev, mf, prod, serial)) != NULL) { - flags = filter->flags; - printk(KERN_INFO "USB Scsi filter %s\n", filter->name); - break; - } - filter = filter->next; - } - } - - /* generic devices next */ - - if (fdata == NULL) { - - /* some exceptions */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - /* shuttle E-USB */ - protocol = US_PR_CB; - subclass = US_SC_8070; /* an assumption */ - } else if (dev->descriptor.bDeviceClass != 0 || - dev->config->altsetting->interface->bInterfaceClass != 8 || - dev->config->altsetting->interface->bInterfaceSubClass < US_SC_MIN || - dev->config->altsetting->interface->bInterfaceSubClass > US_SC_MAX) { - return -1; - } - - /* now check if we have seen it before */ - - if (dev->descriptor.iSerialNumber && - usb_string(dev, dev->descriptor.iSerialNumber) ) { - make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, - usb_string(dev, dev->descriptor.iSerialNumber)); - } else { - make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, - "0"); - } - for (ss = us_list; ss; ss = ss->next) { - if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) { - US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); - flags = ss->flags; - break; - } - } - } - - if (!ss) { - if ((ss = (struct us_data *)kmalloc(sizeof(*ss), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING USB_SCSI "Out of memory\n"); - if (filter) - filter->release(fdata); - return -1; - } - memset(ss, 0, sizeof(struct us_data)); - } - - interface = dev->config->altsetting->interface; - ss->filter = filter; - ss->fdata = fdata; - ss->flags = flags; - if (subclass) { - ss->subclass = subclass; - ss->protocol = protocol; - } else { - ss->subclass = interface->bInterfaceSubClass; - ss->protocol = interface->bInterfaceProtocol; - } - ss->attention_done = 0; - - /* set the protocol op */ - - US_DEBUGP("Protocol "); - switch (ss->protocol) { - case US_PR_CB: - US_DEBUGPX("Control/Bulk\n"); - ss->pop = pop_CBI; - ss->pop_reset = pop_CB_reset; - break; - - case US_PR_CBI: - US_DEBUGPX("Control/Bulk/Interrupt\n"); - ss->pop = pop_CBI; - ss->pop_reset = pop_CB_reset; - break; - - default: - US_DEBUGPX("Bulk\n"); - ss->pop = pop_Bulk; - ss->pop_reset = pop_Bulk_reset; - break; - } - - /* - * we are expecting a minimum of 2 endpoints - in and out (bulk) - * an optional interrupt is OK (necessary for CBI protocol) - * we will ignore any others - */ - - for (i = 0; i < interface->bNumEndpoints; i++) { - if (interface->endpoint[i].bmAttributes == 0x02) { - if (interface->endpoint[i].bEndpointAddress & 0x80) - ss->ep_in = interface->endpoint[i].bEndpointAddress & 0x0f; - else - ss->ep_out = interface->endpoint[i].bEndpointAddress & 0x0f; - } else if (interface->endpoint[i].bmAttributes == 0x03) { - ss->ep_int = interface->endpoint[i].bEndpointAddress & 0x0f; - } - } - US_DEBUGP("Endpoints In %d Out %d Int %d\n", ss->ep_in, ss->ep_out, ss->ep_int); - - /* exit if strange looking */ - - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) || - usb_set_interface(dev, interface->bInterfaceNumber, 0) || - !ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { - US_DEBUGP("Problems with device\n"); - if (ss->host) { - scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt); - kfree(ss->htmplt->name); - kfree(ss->htmplt); - } - if (filter) - filter->release(fdata); - kfree(ss); - return -1; /* no endpoints */ - } - - if (dev->config[0].iConfiguration && usb_string(dev, dev->config[0].iConfiguration)) - US_DEBUGP("Configuration %s\n", usb_string(dev, dev->config[0].iConfiguration)); - if (interface->iInterface && usb_string(dev, interface->iInterface)) - US_DEBUGP("Interface %s\n", usb_string(dev, interface->iInterface)); - - ss->pusb_dev = dev; - - /* Now generate a scsi host definition, and register with scsi above us */ - - if (!ss->host) { - - /* make unique id if possible */ - - US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); - memcpy(ss->guid, guid, sizeof(guid)); - - /* set class specific stuff */ - - US_DEBUGP("SubClass "); - switch (ss->subclass) { - case US_SC_RBC: - US_DEBUGPX("Reduced Block Commands\n"); - break; - case US_SC_8020: - US_DEBUGPX("8020\n"); - break; - case US_SC_QIC: - US_DEBUGPX("QIC157\n"); - break; - case US_SC_8070: - US_DEBUGPX("8070\n"); - ss->flags |= US_FL_FIXED_COMMAND; - ss->fixedlength = 12; - break; - case US_SC_SCSI: - US_DEBUGPX("Transparent SCSI\n"); - break; - case US_SC_UFI: - US_DEBUGPX(" UFF\n"); - ss->flags |= US_FL_FIXED_COMMAND; - ss->fixedlength = 12; - break; - - default: - break; - } - - /* create unique host template */ - - if ((htmplt = (Scsi_Host_Template *)kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) { - printk(KERN_WARNING USB_SCSI "Out of memory\n"); - if (filter) - filter->release(fdata); - kfree(ss); - return -1; - } - memcpy(htmplt, &my_host_template, sizeof(my_host_template)); - ss->host_number = my_host_number++; - - - (struct us_data *)htmplt->proc_dir = ss; - - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - devrequest dr; - __u8 qstat[2]; - - /* shuttle E-USB */ - dr.requesttype = 0xC0; - dr.request = 1; - dr.index = 0; - dr.value = 0; - dr.length = 0; - ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2); - US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]); - init_waitqueue_head(&ss->ip_waitq); - ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, - usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int), - pop_CBI_irq, 0, (void *)ss); - interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5); - - } else if (ss->protocol == US_PR_CBI) - init_waitqueue_head(&ss->ip_waitq); - - - /* start up our thread */ - - { - DECLARE_MUTEX_LOCKED(sem); - - init_waitqueue_head(&ss->waitq); - - ss->notify = &sem; - ss->pid = kernel_thread(usbscsi_control_thread, ss, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - if (ss->pid < 0) { - printk(KERN_WARNING USB_SCSI "Unable to start control thread\n"); - kfree(htmplt); - if (filter) - filter->release(fdata); - kfree(ss); - return -1; - } - - /* wait for it to start */ - - down(&sem); - } - - /* now register - our detect function will be called */ - - scsi_register_module(MODULE_SCSI_HA, htmplt); - - /* put us in the list */ - - prev = (struct us_data *)&us_list; - while (prev->next) - prev = prev->next; - prev->next = ss; - - } - - - printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum); - - dev->private = ss; - return 0; -} - -static void scsi_disconnect(struct usb_device *dev) -{ - struct us_data *ss = dev->private; - - if (!ss) - return; - if (ss->filter) - ss->filter->release(ss->fdata); - ss->pusb_dev = NULL; - dev->private = NULL; /* just in case */ - MOD_DEC_USE_COUNT; -} - -int usb_scsi_init(void) -{ - - MOD_INC_USE_COUNT; -#ifdef CONFIG_USB_HP4100 - hp4100_init(); -#endif -#ifdef CONFIG_USB_ZIP - usb_zip_init(); -#endif - usb_register(&scsi_driver); - printk(KERN_INFO "USB SCSI support registered.\n"); - return 0; -} - - -int usb_scsi_register(struct usb_scsi_filter *filter) -{ - struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters; - - while (prev->next) - prev = prev->next; - prev->next = filter; - return 0; -} - -void usb_scsi_deregister(struct usb_scsi_filter *filter) -{ - struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters; - - while (prev->next && prev->next != filter) - prev = prev->next; - if (prev->next) - prev->next = filter->next; -} - -#ifdef MODULE -int init_module(void) -{ - - return usb_scsi_init(); -} - -void cleanup_module(void) -{ - unsigned int offset; - - usb_deregister(&scsi_driver); -} -#endif diff --git a/drivers/usb/usb_scsi.h b/drivers/usb/usb_scsi.h deleted file mode 100644 index 3e6386f4f1e3..000000000000 --- a/drivers/usb/usb_scsi.h +++ /dev/null @@ -1,147 +0,0 @@ -/* Driver for USB scsi - include file - * - * (C) Michael Gee (michael@linuxspecific.com) 1999 - * - * This driver is scitzoid - it make a USB scanner appear as both a SCSI device - * and a character device. The latter is only available if the device has an - * interrupt endpoint, and is used specifically to receive interrupt events. - * - * In order to support various 'strange' scanners, this module supports plug in - * device specific filter modules, which can do their own thing when required. - * - */ - -#include - -#define USB_SCSI "usbscsi: " - -extern int usbscsi_debug; - -#ifdef CONFIG_USB_SCSI_DEBUG -void us_show_command(Scsi_Cmnd *srb); -#define US_DEBUGP(x...) { if(usbscsi_debug) printk( KERN_DEBUG USB_SCSI ## x ); } -#define US_DEBUGPX(x...) { if(usbscsi_debug) printk( ## x ); } -#define US_DEBUG(x) { if(usbscsi_debug) x; } -#else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) -#define US_DEBUG(x) -#endif - -/* bit set if input */ -extern unsigned char us_direction[256/8]; -#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) - -/* Sub Classes */ - -#define US_SC_RBC 1 /* Typically, flash devices */ -#define US_SC_8020 2 /* CD-ROM */ -#define US_SC_QIC 3 /* QIC-157 Tapes */ -#define US_SC_UFI 4 /* Floppy */ -#define US_SC_8070 5 /* Removable media */ -#define US_SC_SCSI 6 /* Transparent */ -#define US_SC_MIN US_SC_RBC -#define US_SC_MAX US_SC_SCSI - -/* Protocols */ - -#define US_PR_CB 1 /* Control/Bulk w/o interrupt */ -#define US_PR_CBI 0 /* Control/Bulk/Interrupt */ -#define US_PR_ZIP 0x50 /* bulk only */ -/* #define US_PR_BULK ?? */ - -/* - * Bulk only data structures (Zip 100, for example) - */ - -struct bulk_cb_wrap { - __u32 Signature; /* contains 'USBC' */ - __u32 Tag; /* unique per command id */ - __u32 DataTransferLength; /* size of data */ - __u8 Flags; /* direction in bit 0 */ - __u8 Lun; /* LUN normally 0 */ - __u8 Length; /* of of the CDB */ - __u8 CDB[16]; /* max command */ -}; - -#define US_BULK_CB_WRAP_LEN 31 -#define US_BULK_CB_SIGN 0x43425355 -#define US_BULK_FLAG_IN 1 -#define US_BULK_FLAG_OUT 0 - -struct bulk_cs_wrap { - __u32 Signature; /* should = 'USBS' */ - __u32 Tag; /* same as original command */ - __u32 Residue; /* amount not transferred */ - __u8 Status; /* see below */ - __u8 Filler[18]; -}; - -#define US_BULK_CS_WRAP_LEN 31 -#define US_BULK_CS_SIGN 0x53425355 -#define US_BULK_STAT_OK 0 -#define US_BULK_STAT_FAIL 1 -#define US_BULK_STAT_PHASE 2 - -#define US_BULK_RESET 0xff -#define US_BULK_RESET_SOFT 1 -#define US_BULK_RESET_HARD 0 - -/* - * CBI style - */ - -#define US_CBI_ADSC 0 - -/* - * Filter device definitions - */ -struct usb_scsi_filter { - - struct usb_scsi_filter * next; /* usb_scsi driver only */ - char *name; /* not really required */ - - unsigned int flags; /* Filter flags */ - void * (* probe) (struct usb_device *, char *, char *, char *); /* probe device */ - void (* release)(void *); /* device gone */ - int (* command)(void *, Scsi_Cmnd *); /* all commands */ -}; - -#define GUID(x) __u32 x[3] -#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) -#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0; -#define GUID_NONE(x) (!x[0] && !x[1] && !x[2]) -#define GUID_FORMAT "%08x%08x%08x" -#define GUID_ARGS(x) x[0], x[1], x[2] - -static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial) -{ - pg[0] = (vendor << 16) | product; - pg[1] = pg[2] = 0; - while (*serial) { - pg[1] <<= 4; - pg[1] |= pg[2] >> 28; - pg[2] <<= 4; - if (*serial >= 'a') - *serial -= 'a' - 'A'; - pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0' - : *serial - 'A' + 10; - serial++; - } -} - -/* Flag definitions */ -#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */ -#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */ - -/* - * Called by filters to register/unregister the mini driver - * - * WARNING - the supplied probe function may be called before exiting this fn - */ -int usb_scsi_register(struct usb_scsi_filter *); -void usb_scsi_deregister(struct usb_scsi_filter *); - -#ifdef CONFIG_USB_HP4100 -int hp4100_init(void); -#endif diff --git a/drivers/usb/usb_scsi_debug.c b/drivers/usb/usb_scsi_debug.c deleted file mode 100644 index 1a4273f94eb2..000000000000 --- a/drivers/usb/usb_scsi_debug.c +++ /dev/null @@ -1,116 +0,0 @@ - -/* Driver for USB scsi like devices - * - * (C) Michael Gee (michael@linuxspecific.com) 1999 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" - -#include "usb.h" -#include "usb_scsi.h" - -void us_show_command(Scsi_Cmnd *srb) -{ - char *what; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; - case REZERO_UNIT: what = "REZERO_UNIT"; break; - case REQUEST_SENSE: what = "REQUEST_SENSE"; break; - case FORMAT_UNIT: what = "FORMAT_UNIT"; break; - case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; - case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; - case READ_6: what = "READ_6"; break; - case WRITE_6: what = "WRITE_6"; break; - case SEEK_6: what = "SEEK_6"; break; - case READ_REVERSE: what = "READ_REVERSE"; break; - case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; - case SPACE: what = "SPACE"; break; - case INQUIRY: what = "INQUIRY"; break; - case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; - case MODE_SELECT: what = "MODE_SELECT"; break; - case RESERVE: what = "RESERVE"; break; - case RELEASE: what = "RELEASE"; break; - case COPY: what = "COPY"; break; - case ERASE: what = "ERASE"; break; - case MODE_SENSE: what = "MODE_SENSE"; break; - case START_STOP: what = "START_STOP"; break; - case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; - case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; - case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; - case SET_WINDOW: what = "SET_WINDOW"; break; - case READ_CAPACITY: what = "READ_CAPACITY"; break; - case READ_10: what = "READ_10"; break; - case WRITE_10: what = "WRITE_10"; break; - case SEEK_10: what = "SEEK_10"; break; - case WRITE_VERIFY: what = "WRITE_VERIFY"; break; - case VERIFY: what = "VERIFY"; break; - case SEARCH_HIGH: what = "SEARCH_HIGH"; break; - case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; - case SEARCH_LOW: what = "SEARCH_LOW"; break; - case SET_LIMITS: what = "SET_LIMITS"; break; - case READ_POSITION: what = "READ_POSITION"; break; - case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; - case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; - case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; - case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; - case COMPARE: what = "COMPARE"; break; - case COPY_VERIFY: what = "COPY_VERIFY"; break; - case WRITE_BUFFER: what = "WRITE_BUFFER"; break; - case READ_BUFFER: what = "READ_BUFFER"; break; - case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; - case READ_LONG: what = "READ_LONG"; break; - case WRITE_LONG: what = "WRITE_LONG"; break; - case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; - case WRITE_SAME: what = "WRITE_SAME"; break; - case READ_TOC: what = "READ_TOC"; break; - case LOG_SELECT: what = "LOG_SELECT"; break; - case LOG_SENSE: what = "LOG_SENSE"; break; - case MODE_SELECT_10: what = "MODE_SELECT_10"; break; - case MODE_SENSE_10: what = "MODE_SENSE_10"; break; - case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; - case READ_12: what = "READ_12"; break; - case WRITE_12: what = "WRITE_12"; break; - case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; - case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; - case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; - case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; - case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; - case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; - case WRITE_LONG_2: what = "WRITE_LONG_2"; break; - default: break; - } - printk(KERN_DEBUG USB_SCSI "Command %s (%d bytes)\n", what, srb->cmd_len); - printk(KERN_DEBUG USB_SCSI " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], - srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); - printk(KERN_DEBUG USB_SCSI " use_sg=%d buff=%p len=%d\n", - srb->use_sg, srb->request_buffer, srb->request_bufflen); - if (srb->use_sg) { - struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; - int i; - printk(KERN_DEBUG USB_SCSI " "); - for (i = 0; i < srb->use_sg && i < 5; ++i) - printk(" [%p %d]", sg[i].address, sg[i].length); - if (i < srb->use_sg) - printk(" ..."); - printk("\n"); - } -} diff --git a/drivers/usb/usb_scsi_dt.c b/drivers/usb/usb_scsi_dt.c deleted file mode 100644 index 5d615bdff923..000000000000 --- a/drivers/usb/usb_scsi_dt.c +++ /dev/null @@ -1,4 +0,0 @@ -0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, -0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 diff --git a/include/linux/fd.h b/include/linux/fd.h index dc8439540e40..c0ed2792ba8b 100644 --- a/include/linux/fd.h +++ b/include/linux/fd.h @@ -216,7 +216,7 @@ struct floppy_drive_struct { /* Prevent "aliased" accesses. */ int fd_ref; int fd_device; - int last_checked; /* when was the drive last checked for a disk + unsigned long last_checked; /* when was the drive last checked for a disk * change? */ char *dmabuf; diff --git a/include/net/tcp.h b/include/net/tcp.h index 38ea51d50133..8b050c63a8a3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -142,7 +142,8 @@ struct tcp_tw_bucket { nonagle; /* And these are ours. */ - __u32 rcv_nxt,snd_nxt; + __u32 rcv_nxt, snd_nxt; + __u16 window; struct tcp_func *af_specific; struct tcp_bind_bucket *tb; struct tcp_tw_bucket *next_death; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4c0fc202f6da..314ec5ea9227 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1006,7 +1006,8 @@ tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, tcp_tw_reschedule(tw); } /* Ack old packets if necessary */ - if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt)) + if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) && + (th->doff * 4) > len) return TCP_TW_ACK; return 0; } @@ -1067,7 +1068,8 @@ void tcp_time_wait(struct sock *sk) tw->family = sk->family; tw->reuse = sk->reuse; tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt; - tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt; + tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt; + tw->window = tcp_select_window(sk); tw->af_specific = sk->tp_pinfo.af_tcp.af_specific; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 935fcb08dd6d..1decfc5857f9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1026,7 +1026,7 @@ static void tcp_v4_send_reset(struct sk_buff *skb) * * Assumes that the caller did basic address and flag checks. */ -static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack) +static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window) { struct tcphdr *th = skb->h.th; struct tcphdr rth; @@ -1042,6 +1042,8 @@ static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack) rth.ack_seq = ack; rth.ack = 1; + rth.window = htons(window); + memset(&arg, 0, sizeof arg); arg.iov[0].iov_base = (unsigned char *)&rth; arg.iov[0].iov_len = sizeof rth; @@ -1774,10 +1776,12 @@ discard_it: do_time_wait: /* Sorry for the ugly switch. 2.3 will have a better solution. */ switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk, - skb, th, skb->len)) { + skb, th, skb->len)) { case TCP_TW_ACK: - tcp_v4_send_ack(skb, ((struct tcp_tw_bucket *)sk)->snd_nxt, - ((struct tcp_tw_bucket *)sk)->rcv_nxt); + tcp_v4_send_ack(skb, + ((struct tcp_tw_bucket *)sk)->snd_nxt, + ((struct tcp_tw_bucket *)sk)->rcv_nxt, + ((struct tcp_tw_bucket *)sk)->window); goto discard_it; case TCP_TW_RST: goto no_tcp_socket; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fc3f239d730d..fe86124688b7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1121,7 +1121,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) kfree_skb(buff); } -static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack) +static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window) { struct tcphdr *th = skb->h.th, *t1; struct sk_buff *buff; @@ -1144,6 +1144,8 @@ static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack) t1->seq = seq; t1->ack_seq = ack; + t1->window = htons(window); + buff->csum = csum_partial((char *)t1, sizeof(*t1), 0); fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr; @@ -1461,10 +1463,12 @@ discard_it: do_time_wait: switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk, - skb, th, skb->len)) { + skb, th, skb->len)) { case TCP_TW_ACK: - tcp_v6_send_ack(skb, ((struct tcp_tw_bucket *)sk)->snd_nxt, - ((struct tcp_tw_bucket *)sk)->rcv_nxt); + tcp_v6_send_ack(skb, + ((struct tcp_tw_bucket *)sk)->snd_nxt, + ((struct tcp_tw_bucket *)sk)->rcv_nxt, + ((struct tcp_tw_bucket *)sk)->window); goto discard_it; case TCP_TW_RST: goto no_tcp_socket; -- 2.39.5