#include <linux/in.h>
#include <linux/in6.h>
#include <linux/pci.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
#include <linux/interrupt.h>
#include <asm/softirq.h>
#include <asm/fpu.h>
-#include <asm/irq.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/semaphore.h>
#define __KERNEL_SYSCALLS__
#include <asm/unistd.h>
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);
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);
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);
#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
/*
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
source drivers/char/Config.in
-source drivers/usb/Config.in
+# source drivers/usb/Config.in
source fs/Config.in
* 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 */
* 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
#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;
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;
#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);
}
}
/* 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
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;
* 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 */
*/
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;
#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 */
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; i<resultsize; i++){
printk("%2x ", reply_buffer[i]);
}
printk("fd_timer.function=%p\n", fd_timer.function);
if (fd_timeout.prev){
printk("timer_table=%p\n",fd_timeout.function);
- printk("expires=%ld\n",fd_timeout.expires-jiffies);
- printk("now=%ld\n",jiffies);
+ printk("expires=%lu\n",fd_timeout.expires-jiffies);
+ printk("now=%lu\n",jiffies);
}
printk("cont=%p\n", cont);
printk("CURRENT=%p\n", CURRENT);
* Misc Ioctl's and support
* ========================
*/
-static inline int fd_copyout(void *param, const void *address, int size)
+static inline int fd_copyout(void *param, const void *address, unsigned long size)
{
return copy_to_user(param,address, size) ? -EFAULT : 0;
}
-static inline int fd_copyin(void *param, void *address, int size)
+static inline int fd_copyin(void *param, void *address, unsigned long size)
{
return copy_from_user(address, param, size) ? -EFAULT : 0;
}
if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
return 1;
- if (UDP->checkfreq < jiffies - UDRS->last_checked){
+ if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
lock_fdc(drive,0);
poll_drive(0,0);
process_fd_request();
* 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
* 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
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
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
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
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]__ */
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
#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,
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();
}
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);
Johannes Erdfelt <jerdfelt@sventech.com>
ham <ham@unsuave.com>
Bradley M Keryan <keryan@andrew.cmu.edu>
- Paul Mackerras <paulus@cs.anu.edu.au>
Vojtech Pavlik <vojtech@twilight.ucw.cz>
Gregory P. Smith <greg@electricrain.com>
Linus Torvalds <torvalds@transmeta.com>
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
# 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
#
# 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)
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
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
-[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
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
+++ /dev/null
-/*
- * 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 <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/module.h>
-
-#include <asm/spinlock.h>
-
-#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;cfgnum<dev->descriptor.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
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/sched.h>
-#include <linux/module.h>
-
#include "usb.h"
static int usb_audio_probe(struct usb_device *dev);
};
-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;
int i;
int na=0;
- interface = &dev->config[0].altsetting[0].interface[0];
+ interface = &dev->config[0].interface[0];
for(i=0;i<dev->config[0].bNumInterfaces;i++)
{
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);
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)
{
}
-#ifdef MODULE
-int init_module(void)
-{
- return usb_audio_init();
-}
-
-void cleanup_module(void)
-{
- usb_deregister(&usb_audio_driver);
-}
-
-#endif
+++ /dev/null
-/*
- * 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 <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-
-#include <asm/spinlock.h>
-#include <asm/io.h>
-
-#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
-
+++ /dev/null
-#ifndef __LINUX_CPIA_H
-#define __LINUX_CPIA_H
-
-#include <linux/list.h>
-
-#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
-
+++ /dev/null
-/*****************************************************************************/
-
-/*
- * 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 <linux/module.h>
-#include <linux/socket.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-
-#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
-
-/* --------------------------------------------------------------------- */
+++ /dev/null
-/*****************************************************************************/
-
-/*
- * 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 <linux/ioctl.h>
-
-/* --------------------------------------------------------------------- */
-
-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 */
/*
* 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 <linux/kernel.h>
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
-#include <linux/module.h>
#include <asm/spinlock.h>
#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;
* 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;
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
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);
}
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)
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)
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;
}
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);
/* 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);
}
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))) {
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;
}
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);
}
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);
}
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;
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");
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;
}
/*
* 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);
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
/*
* 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
#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
/* 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;
+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);
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/sched.h>
-#include <linux/config.h>
-#include <linux/module.h>
-
#include <linux/kbd_ll.h>
#include "usb.h"
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);
}
}
}
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;
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
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);
kbd);
list_add(&kbd->list, &usb_kbd_list);
-
- return 0;
}
-probe_err:
- if (kbd)
- kfree (kbd);
- return -1;
+ return 0;
}
static void
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
-
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,
# misc fixes
keycode 0 = Pause
keycode 29 = Control
+keycode 99 = Remove
keycode 42 = Shift
keycode 54 = Shift_R
keycode 109 = Application
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
+++ /dev/null
-# 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 'ÿ'
+++ /dev/null
-#!/usr/bin/perl
-
-($ME = $0) =~ s|.*/||;
-
-$file = "maps/mac.map";
-$line = 1;
-open(PC, $file) || die("$!");
-while(<PC>)
-{
- 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(<FIXUP>)
-# {
-# 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(<USB>)
-{
- 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";
* 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
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/module.h>
#include <asm/spinlock.h>
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 */
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 ) +
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;
}
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;
}
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;
}
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)
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;
{
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 = {
{
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
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);
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) {
} /* 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;
printk(KERN_DEBUG " ohci_hcca\n");
for (idx=0; idx<NUM_INTS; idx++) {
- printk(KERN_DEBUG " int_table[%2d] == %x\n", idx,
- le32_to_cpup(hcca->int_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() */
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
*
- * 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 <greg@electricrain.com> ]
#include "usb.h"
#include "ohci-hcd.h"
+#include "inits.h"
+
+
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#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 */
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 */
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;
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;
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);
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
};
}
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);
{
/* int fminterval; */
unsigned int mask;
- int port_nr;
/* fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
reset_hc(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) )); )
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);
}
{
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]) );)
/*
*
* 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]);
* 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 */
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 */
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);
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;
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) {
}
#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) */
{
return 0;
}
+
+
+
/*
* Increment the module usage count, start the control thread and
* return success.
}
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
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
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
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;
* Open Host Controller Interface driver for USB.
*
* (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
- * Significant code from the following individuals has also been used:
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> [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
*
* 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 <linux/config.h>
#include <asm/system.h>
#include "ohci.h"
+#include "inits.h"
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
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);
/*
* 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)
{
/* 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)
{
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);
/* 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
*/
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);
}
/*
*/
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)
{
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 */
/* 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 */
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);
}
}
}
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() */
/*
* 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;
} /* 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 *
**********************************/
*
* 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() */
/*
{
struct usb_device *usb_dev;
struct ohci_device *dev;
- int idx;
/*
* Allocate the generic USB device
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
*/
*/
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
*/
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
};
*/
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;
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
* 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() */
/*
* 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 */
/*
* 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 */
{
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;
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;
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() */
*/
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() */
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;
{
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 */
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;
} /* 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.
{
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 {
}
}
- /* 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 */
* 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 */
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);
}
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;
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 */
* 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);
/* 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;
*/
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 */
/* 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 */
* 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;
}
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) {
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;
}
}
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() */
#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)
{
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
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) {
#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;
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 */
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() */
/* 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;
}
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;
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)
/*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 (;;) {
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
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
*/
*
* (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
*
- * $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 <linux/list.h>
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: */
#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)
/*
__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)
#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
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
* 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
} 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 */
#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
*/
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);
+++ /dev/null
-
-/* Driver for USB Printers
- *
- * (C) Michael Gee (michael@linuxspecific.com) 1999
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/lp.h>
-
-#include <asm/spinlock.h>
-
-#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; i++) {
- if (!minor_data[i])
- break;
- }
- if (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
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/types.h>
-#include <linux/kernel.h>
-/* #include <linux/module.h> */
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/list.h>
-
-#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 <halted> 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 */
+++ /dev/null
-#!/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 = <DEVNUM>) # 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.
#!/bin/sh
-killall khubd
killall ohci-control
-killall uhci-control
sleep 2
-rmmod hub
rmmod usb-ohci
-rmmod usb-uhci
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 " : "",
((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);
}
#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;
}
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;
{
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;
}
}
}
+
*/
/* 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 <linux/config.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <asm/uaccess.h>
#include <asm/spinlock.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include "uhci.h"
+#include "inits.h"
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
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;
}
/*
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;
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);
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);
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
* 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 */
/* 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);
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);
#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);
}
/*
* 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);
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)
while (len > 0) {
/* Build the TD for control status */
int pktsze = len;
+ int maxsze = usb_maxpacket(pipe);
if (pktsze > maxsze)
pktsze = maxsze;
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);
} 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;
}
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);
}
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
};
/*
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);
/*
*
* 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);
* 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);
*/
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 {
{
struct list_head *head = &uhci->interrupt_list;
struct list_head *tmp;
- int status;
spin_lock(&irqlist_lock);
tmp = head->next;
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);
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) {
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);
*/
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);
}
}
-
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);
}
/*
/* 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));
*/
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 */
}
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;
}
}
#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
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");
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");
* Ok, all systems are go..
*/
start_hc(uhci);
- usb_register_bus(uhci->bus);
for(;;) {
siginfo_t info;
int unsigned long signr;
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);
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;
}
#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)
{
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
#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 */
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
*
*/
struct uhci;
-#define UHCI_MAXTD 64
+#define UHCI_MAXTD 64
#define UHCI_MAXQH 16
* 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
* 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
/* 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 */
};
+++ /dev/null
-/*
- * 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 <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-
-#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
-
-
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)
*/
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");
{
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);
{
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);
}
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");
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);
-}
/*
- * drivers/usb/usb.c
+ * driver/usb/usb.c
*
* (C) Copyright Linus Torvalds 1999
*
* 6 wLength 2 Count Bytes for data
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
* 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;i<USB_MAXCHILDREN;i++)
- if (dev->children[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;i<USB_MAXCHILDREN;i++)
- if (dev->children[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.
*
* 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);
}
/*
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;
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;
}
{
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;
}
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)
{
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)
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)
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)
{
}
- 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;
}
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;c<dev->descriptor.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;i<cf->bNumInterfaces;i++)
{
- as = &cf->altsetting[a];
- if (as->interface == NULL)
- break;
- for(i=0;i<cf->bNumInterfaces;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)
*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);
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;
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)
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;
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; i<dev->actconfig->bNumInterfaces; i++) {
- if (as->interface[i].bInterfaceNumber == dev->ifnum) {
- ip = &as->interface[i];
- break;
- }
- }
- ep = ip->endpoint;
- for (i=0; i<ip->bNumEndpoints; 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; i<dev->descriptor.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;
}
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;cfgno<dev->descriptor.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);
}
/*
{
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;
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
#include <linux/list.h>
#include <linux/sched.h>
-#include <linux/version.h>
-#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;
} 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
#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
*/
#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.
*/
#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;
void *audio;
};
-/* hack for alternate settings */
-struct usb_alternate_setting {
- struct usb_interface_descriptor *interface;
-};
-
/* Configuration descriptor information.. */
struct usb_config_descriptor {
__u8 bLength;
__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 */
__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
* 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 *);
};
/*
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 */
};
#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 */
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
* 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)
{
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..
*/
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..
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
+++ /dev/null
-
-/* 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 <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-
-#include <asm/spinlock.h>
-#include <linux/smp_lock.h>
-
-#include <linux/blk.h>
-#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
+++ /dev/null
-/* 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 <linux/config.h>
-
-#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
+++ /dev/null
-
-/* Driver for USB scsi like devices
- *
- * (C) Michael Gee (michael@linuxspecific.com) 1999
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-
-#include <asm/spinlock.h>
-
-#include <linux/blk.h>
-#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");
- }
-}
+++ /dev/null
-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
/* 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;
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;
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;
}
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)
*
* 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;
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;
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;
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;
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;
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;