summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/acm.c2
-rw-r--r--drivers/usb/audio.c2
-rw-r--r--drivers/usb/cpia.c2
-rw-r--r--drivers/usb/hub.c2
-rw-r--r--drivers/usb/keyboard.c2
-rw-r--r--drivers/usb/mouse.c2
-rw-r--r--drivers/usb/ohci-hcd.c2
-rw-r--r--drivers/usb/ohci.c211
-rw-r--r--drivers/usb/uhci-debug.c2
-rw-r--r--drivers/usb/uhci.c42
-rw-r--r--drivers/usb/usb-core.c2
-rw-r--r--drivers/usb/usb.h4
-rw-r--r--drivers/usb/usb_scsi.c402
-rw-r--r--drivers/usb/usb_scsi_debug.c2
14 files changed, 517 insertions, 162 deletions
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index d4796e28c..10c837d5a 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -50,7 +50,7 @@ static struct acm_state static_acm_state;
spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
-static int acm_irq(int state, void *__buffer, void *dev_id)
+static int acm_irq(int state, void *__buffer, int len, void *dev_id)
{
// unsigned char *data = __buffer;
struct acm_state *acm = &static_acm_state;
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 45a276772..9743ec89e 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -27,7 +27,7 @@ static struct usb_driver usb_audio_driver =
};
-static int usb_audio_irq(int state, void *buffer, void *dev_id)
+static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_audio *aud = (struct usb_audio*) dev_id;
return 1;
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
index 87e1e4254..2402d3425 100644
--- a/drivers/usb/cpia.c
+++ b/drivers/usb/cpia.c
@@ -451,7 +451,7 @@ printk("copying\n");
}
}
-static int cpia_isoc_irq(int status, void *__buffer, void *dev_id)
+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;
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 1cd7d7ccb..0a1ec1f01 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -33,7 +33,7 @@ static int khubd_pid = 0;
* the low-level driver that it wants to be re-activated,
* or zero to say "I'm done".
*/
-static int hub_irq(int status, void *__buffer, void *dev_id)
+static int hub_irq(int status, void *__buffer, int len, void *dev_id)
{
struct usb_hub *hub = dev_id;
unsigned long flags;
diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c
index 5d93a5a84..e87519d9f 100644
--- a/drivers/usb/keyboard.c
+++ b/drivers/usb/keyboard.c
@@ -92,7 +92,7 @@ usb_kbd_repeat(unsigned long dev_id)
}
static int
-usb_kbd_irq(int state, void *buffer, void *dev_id)
+usb_kbd_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
unsigned long *down = (unsigned long*) buffer;
diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c
index f094c0b0d..a79c10a07 100644
--- a/drivers/usb/mouse.c
+++ b/drivers/usb/mouse.c
@@ -60,7 +60,7 @@ static struct mouse_state static_mouse_state;
spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
-static int mouse_irq(int state, void *__buffer, void *dev_id)
+static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
{
signed char *data = __buffer;
/* finding the mouse is easy when there's only one */
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
index 820efc5dc..8db61e08e 100644
--- a/drivers/usb/ohci-hcd.c
+++ b/drivers/usb/ohci-hcd.c
@@ -102,7 +102,7 @@ static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len,
OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
OHCI_DEBUG( printk(" ret_status: %x\n", status); })
- ret = handler(cc_to_status[status & 0xf], data, dev_id);
+ ret = handler(cc_to_status[status & 0xf], data, data_len, 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 */
diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c
index 4ef570abd..48191e11b 100644
--- a/drivers/usb/ohci.c
+++ b/drivers/usb/ohci.c
@@ -121,7 +121,7 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
u32 new_dummy;
if (ed->tail_td == 0) {
- printk("eek! an ED without a dummy_td\n");
+ printk(KERN_ERR "eek! an ED without a dummy_td\n");
return td;
}
@@ -234,8 +234,8 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
*/
int_ed = &root_hub->ed[ms_to_ed_int(period)];
#ifdef OHCI_DEBUG
- printk("usb-ohci: Using INT ED queue %d for %dms period\n",
- ms_to_ed_int(period), period);
+ 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);
@@ -264,6 +264,21 @@ inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
*/
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, &regs->intrstatus);
+ writel(OHCI_INTR_SF, &regs->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).
*
@@ -296,21 +311,11 @@ void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_ty
* at least the next frame.
*/
if (virt_to_bus(ed) == readl(hw_listcurrent)) {
- DECLARE_WAITQUEUE(wait, current);
-
#ifdef OHCI_DEBUG
- printk("Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed));
+ printk(KERN_INFO "Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed));
#endif
+ ohci_wait_sof(regs);
- add_wait_queue(&start_of_frame_wakeup, &wait);
-
- /* clear the SOF interrupt status and enable it */
- writel(OHCI_INTR_SF, &regs->intrstatus);
- writel(OHCI_INTR_SF, &regs->intrenable);
-
- schedule_timeout(HZ/10);
-
- remove_wait_queue(&start_of_frame_wakeup, &wait);
}
return; /* The ED is now safe */
@@ -334,6 +339,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
if (ed == NULL || !bus_ed)
return;
+ ed->status |= cpu_to_le32(OHCI_ED_SKIP);
switch (ed_type) {
case HCD_ED_CONTROL:
@@ -343,16 +349,10 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
hw_listhead_p = &regs->ed_bulkhead;
break;
default:
- printk("Unknown HCD ED type %d.\n", ed_type);
+ printk(KERN_ERR "Unknown HCD ED type %d.\n", ed_type);
return;
}
- /*
- * Tell the controller to this skip ED and make sure it is not the
- * being accessed by the HC as we speak.
- */
- ohci_wait_for_ed_safe(regs, ed, ed_type);
-
bus_cur = readl(hw_listhead_p);
if (bus_cur == 0)
@@ -364,7 +364,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
/* if its the head ED, move the head */
if (bus_cur == bus_ed) {
- writel(cur->next_ed, hw_listhead_p);
+ writel(le32_to_cpup(&cur->next_ed), hw_listhead_p);
} else if (cur->next_ed != 0) {
struct ohci_ed *prev;
@@ -373,7 +373,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
prev = cur;
cur = bus_to_virt(le32_to_cpup(&cur->next_ed));
- if (virt_to_bus(cur) == bus_ed) {
+ if (cur == ed) {
/* unlink from the list */
prev->next_ed = cur->next_ed;
break;
@@ -381,6 +381,11 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
} 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);
+
/* clear any links from the ED for safety */
ed->next_ed = 0;
@@ -405,6 +410,68 @@ 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 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);
+ *prevp = ed->next_ed;
+ removed = 1;
+ } else {
+ prevp = &ed->next_ed;
+ }
+ }
+ wmb();
+
+ return removed;
+}
+
+/*
+ * 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(&regs->ed_controlhead));
+ if (ohci_remove_device_list(&head, devnum))
+ writel(le32_to_cpup(&head), &regs->ed_controlhead);
+
+ /* Bulk list */
+ head = cpu_to_le32(readl(&regs->ed_bulkhead));
+ if (ohci_remove_device_list(&head, devnum))
+ writel(le32_to_cpup(&head), &regs->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.
@@ -494,7 +561,7 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
}
}
- printk("usb-ohci: unable to allocate a TD\n");
+ printk(KERN_ERR "usb-ohci: unable to allocate a TD\n");
return NULL;
} /* ohci_get_free_td() */
@@ -521,7 +588,7 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
}
}
- printk("usb-ohci: unable to allocate an ED\n");
+ printk(KERN_ERR "usb-ohci: unable to allocate an ED\n");
return NULL;
} /* ohci_get_free_ed() */
@@ -594,12 +661,12 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
struct ohci_td *dummy_td;
if (ed_head_td(ed) != ed_tail_td(ed))
- printk("Reusing a non-empty ED %p!\n", 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("Error allocating dummy TD for ED %p\n", ed);
+ 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 */
@@ -607,7 +674,7 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
} else {
dummy_td = bus_to_virt(ed_tail_td(ed));
if (!td_dummy(*dummy_td))
- printk("ED %p's dummy %p is screwy\n", ed, 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 */
@@ -650,13 +717,13 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
/* Get an ED and TD */
interrupt_ed = ohci_get_free_ed(dev);
if (!interrupt_ed) {
- printk("Out of EDs on device %p in ohci_request_irq\n", dev);
+ printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
return -1;
}
td = ohci_get_free_td(dev);
if (!td) {
- printk("Out of TDs in ohci_request_irq\n");
+ printk(KERN_ERR "Out of TDs in ohci_request_irq\n");
ohci_free_ed(interrupt_ed);
return -1;
}
@@ -710,7 +777,7 @@ static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
*
* This function is called from the interrupt handler.
*/
-static int ohci_control_completed(int stats, void *buffer, void *dev_id)
+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) {
@@ -759,14 +826,14 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
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("usb-ohci: couldn't get ED for dev %p\n", dev);
+ 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("usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev);
ohci_free_ed(control_ed);
return -1;
}
@@ -799,7 +866,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
/* allocate the next TD */
data_td = ohci_get_free_td(dev);
if (!data_td) {
- printk("usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
ohci_free_td(setup_td);
ohci_free_ed(control_ed);
return -1;
@@ -833,7 +900,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
status_td = ohci_get_free_td(dev); /* TODO check for NULL */
if (!status_td) {
- printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
ohci_free_td(setup_td);
ohci_free_td(data_td);
ohci_free_ed(control_ed);
@@ -918,15 +985,17 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
#ifdef OHCI_DEBUG
if (completion_status != 0) {
- printk(KERN_ERR "ohci_control_msg: %s on cmd %x %x %x %x %x\n",
- cc_names[completion_status & 0xf], cmd->requesttype,
- cmd->request, cmd->value, cmd->index, cmd->length);
+ char *what = (completion_status < 0)? "timed out":
+ cc_names[completion_status & 0xf];
+ printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
+ what, pipe, cmd->requesttype, cmd->request,
+ cmd->value, cmd->index, cmd->length);
} else if (!usb_pipeout(pipe)) {
unsigned char *q = data;
int i;
- printk(KERN_DEBUG "ctrl msg %x %x %x %x %x returned:",
+ printk(KERN_DEBUG "ctrl msg %x %x %x %x %x on pipe %x returned:",
cmd->requesttype, cmd->request, cmd->value, cmd->index,
- cmd->length);
+ cmd->length, pipe);
for (i = 0; i < len; ++i) {
if (i % 16 == 0)
printk("\n" KERN_DEBUG);
@@ -1001,8 +1070,12 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
*/
static int ohci_usb_deallocate(struct usb_device *usb_dev)
{
- kfree(usb_to_ohci(usb_dev));
- kfree(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); */
return 0;
}
@@ -1042,13 +1115,13 @@ static int reset_hc(struct ohci *ohci)
while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
if (!--timeout) {
- printk("usb-ohci: USB HC reset timed out!\n");
+ printk(KERN_ERR "usb-ohci: USB HC reset timed out!\n");
return -1;
}
udelay(1);
}
- printk(KERN_INFO "usb-ohci: HC %p reset.\n", ohci);
+ printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
return 0;
} /* reset_hc() */
@@ -1080,7 +1153,8 @@ static int start_hc(struct ohci *ohci)
* XXX Should fminterval also be set here?
* The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
*/
- fminterval |= (0x2edf << 16);
+ /* fminterval |= (0x2edf << 16); */
+ fminterval = (10240 << 16) | 11999;
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
@@ -1122,7 +1196,7 @@ static int start_hc(struct ohci *ohci)
/* Turn on power to the root hub ports (thanks Roman!) */
writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
- printk("usb-ohci: host controller operational\n");
+ printk(KERN_INFO "usb-ohci: host controller operational\n");
return ret;
} /* start_hc() */
@@ -1137,7 +1211,7 @@ static void ohci_reset_port(struct ohci *ohci, unsigned int port)
/* Don't allow overflows. */
if (port >= MAX_ROOT_PORTS) {
- printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
+ printk(KERN_ERR "usb-ohci: bad port #%d in ohci_reset_port\n", port);
port = MAX_ROOT_PORTS-1;
}
@@ -1152,7 +1226,7 @@ static void ohci_reset_port(struct ohci *ohci, unsigned int port)
status = readl(&ohci->regs->roothub.portstatus[port]);
if (status & PORT_PRS) {
/* reset failed, try harder? */
- printk("usb-ohci: port %d reset failed, retrying\n", port);
+ printk(KERN_ERR "usb-ohci: port %d reset failed, retrying\n", port);
writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);
wait_ms(50);
}
@@ -1340,7 +1414,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info));
if (td_dummy(*td))
- printk("yikes! reaping a dummy TD\n");
+ printk(KERN_ERR "yikes! reaping a dummy TD\n");
/* FIXME: munge td->info into a future standard status format */
@@ -1382,7 +1456,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
/* Check if TD should be re-queued */
if ((td->completed != NULL) &&
- (td->completed(cc, td->data, td->dev_id))) {
+ (td->completed(cc, td->data, -1 /* XXX */, td->dev_id))) {
/* Mark the TD as active again:
* Set the not accessed condition code
* Reset the Error count
@@ -1598,14 +1672,14 @@ static struct ohci *alloc_ohci(void* mem_base)
/* Get the number of ports on the root hub */
usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
if (usb->maxchild > MAX_ROOT_PORTS) {
- printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
+ printk(KERN_INFO "usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
usb->maxchild = MAX_ROOT_PORTS;
}
if (usb->maxchild < 1) {
- printk("usb-ohci: Less than one root hub port? Impossible!\n");
+ printk(KERN_ERR "usb-ohci: Less than one root hub port? Impossible!\n");
usb->maxchild = 1;
}
- printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
+ printk(KERN_DEBUG "usb-ohci: %d root hub ports found\n", usb->maxchild);
/*
* Initialize the ED polling "tree" (for simplicity's sake in
@@ -1650,14 +1724,13 @@ static struct ohci *alloc_ohci(void* mem_base)
writel(0, &ohci->regs->ed_bulkhead);
#ifdef OHCI_DEBUG
- printk(KERN_INFO "alloc_ohci(): controller\n");
+ printk(KERN_DEBUG "alloc_ohci(): controller\n");
show_ohci_status(ohci);
#endif
#if 0
printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
#endif
-printk("alloc_ohci done\n");
return ohci;
} /* alloc_ohci() */
@@ -1722,7 +1795,7 @@ static int ohci_control_thread(void * __ohci)
* This thread doesn't need any user-level access,
* so get rid of all of our resources..
*/
- printk(KERN_INFO "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
+ printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
exit_mm(current);
exit_files(current);
exit_fs(current);
@@ -1735,7 +1808,7 @@ static int ohci_control_thread(void * __ohci)
* Damn the torpedoes, full speed ahead
*/
if (start_hc(ohci) < 0) {
- printk("usb-ohci: failed to start the controller\n");
+ printk(KERN_ERR "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);
@@ -1756,7 +1829,7 @@ static int ohci_control_thread(void * __ohci)
writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
#endif
- printk(KERN_INFO "ohci-control thread sleeping\n");
+ printk(KERN_DEBUG "ohci-control thread sleeping\n");
interruptible_sleep_on(&ohci_configure);
#ifdef CONFIG_APM
if (apm_resume) {
@@ -1796,7 +1869,7 @@ static int ohci_control_thread(void * __ohci)
reset_hc(ohci);
release_ohci(ohci);
usb_deregister_bus(ohci->bus);
- printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci);
+ printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci);
return 0;
} /* ohci_control_thread() */
@@ -1891,7 +1964,7 @@ static int found_ohci(int irq, void* mem_base)
ohci->irq = irq;
#ifdef OHCI_DEBUG
- printk(KERN_INFO "usb-ohci: forking ohci-control thread for 0x%p\n", ohci);
+ printk(KERN_DEBUG "usb-ohci: forking ohci-control thread for 0x%p\n", ohci);
#endif
/* fork off the handler */
@@ -1903,7 +1976,7 @@ static int found_ohci(int irq, void* mem_base)
retval = pid;
} else {
- printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
+ printk(KERN_ERR "usb-ohci: Couldn't allocate interrupt %d\n", irq);
}
release_ohci(ohci);
@@ -1931,7 +2004,7 @@ static int init_ohci(struct pci_dev *dev)
/* no interrupt won't work... */
if (dev->irq == 0) {
- printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
+ printk(KERN_ERR "usb-ohci: no irq assigned? check your BIOS settings.\n");
return -ENODEV;
}
@@ -1944,14 +2017,14 @@ static int init_ohci(struct pci_dev *dev)
mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
if (!mem_base) {
- printk("Error mapping OHCI memory\n");
+ printk(KERN_ERR "Error mapping OHCI memory\n");
return -EFAULT;
}
MOD_INC_USE_COUNT;
#ifdef OHCI_DEBUG
- printk("usb-ohci: Warning! Gobs of debugging output has been enabled.\n");
- printk(" Check your kern.debug logs for the bulk of it.\n");
+ 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) {
@@ -1978,11 +2051,11 @@ int ohci_init(void)
/*u8 type;*/
if (sizeof(struct ohci_device) > 4096) {
- printk("usb-ohci: struct ohci_device to large\n");
+ printk(KERN_ERR "usb-ohci: struct ohci_device to large\n");
return -ENODEV;
}
- printk("OHCI USB Driver loading\n");
+ printk(KERN_INFO "OHCI USB Driver loading\n");
retval = -ENODEV;
for (;;) {
@@ -2022,7 +2095,7 @@ void cleanup_module(void){
# ifdef CONFIG_APM
apm_unregister_callback(&handle_apm_event);
# endif
- printk("usb-ohci: module unloaded\n");
+ printk(KERN_ERR "usb-ohci: module unloaded\n");
}
int init_module(void){
diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c
index 7c577a58f..32549763e 100644
--- a/drivers/usb/uhci-debug.c
+++ b/drivers/usb/uhci-debug.c
@@ -131,7 +131,7 @@ void show_queue(struct uhci_qh *qh)
#if 0
printk(" link = %p, element = %p\n", qh->link, qh->element);
#endif
- if(!qh->element) {
+ if(!(qh->element & ~0xF)) {
printk(" td 0 = NULL\n");
return;
}
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 73aab5fa1..c03ce5adf 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -126,7 +126,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
tmp = td->first;
printk("uhci_td_result() failed with status %x\n", status);
- show_status(dev->uhci);
+ //show_status(dev->uhci);
do {
show_td(tmp);
if ((tmp->link & 1) || (tmp->link & 2))
@@ -422,7 +422,7 @@ static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_de
/* notify removal */
- td->completed(USB_ST_REMOVED, NULL, td->dev_id);
+ td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
/* this is DANGEROUS - not sure whether this is right */
@@ -645,7 +645,7 @@ void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
*/
static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
-static int uhci_control_completed(int status, void *buffer, void *dev_id)
+static int uhci_control_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&control_wakeup);
return 0; /* Don't re-instate */
@@ -692,7 +692,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
// show_status(dev->uhci);
// show_queues(dev->uhci);
- schedule_timeout(HZ/10);
+ schedule_timeout(HZ*5);
// control should be empty here...
// show_status(dev->uhci);
@@ -736,8 +736,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
* information, that's just ridiculously high. Most
* control messages have just a few bytes of data.
*/
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
- devrequest *cmd, void *data, int len)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
@@ -805,17 +804,18 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
/*
- * 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->link = 1; /* Terminate */
- td->status = status | (1 << 24); /* IOC */
+ td->backptr = &prevtd->link;
+ td->status = (status /* & ~(3 << 27) */) | (1 << 24); /* no limit on final packet */
td->info = destination | (0x7ff << 21); /* 0 bytes of data */
td->buffer = 0;
td->first = first;
- td->backptr = &prevtd->link;
+ td->link = 1; /* Terminate */
+
/* Start it up.. */
ret = uhci_run_control(dev, first, td);
@@ -841,7 +841,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
if (uhci_debug && ret) {
- __u8 *p = (__u8 *) cmd;
+ __u8 *p = 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]);
@@ -860,7 +860,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
*/
static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
-static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
+static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&bulk_wakeup);
return 0; /* Don't re-instate */
@@ -908,10 +908,11 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
// show_status(dev->uhci);
// show_queues(dev->uhci);
- schedule_timeout(HZ/10);
+ 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.. */
@@ -1243,6 +1244,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
{
struct list_head *head = &uhci->interrupt_list;
struct list_head *tmp;
+ int status;
spin_lock(&irqlist_lock);
tmp = head->next;
@@ -1252,19 +1254,22 @@ static void uhci_interrupt_notify(struct uhci *uhci)
next = tmp->next;
- if (!(td->status & (1 << 23))) { /* No longer active? */
+ 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) */)) {
/* remove from IRQ list */
__list_del(tmp->prev, next);
INIT_LIST_HEAD(tmp);
- if (td->completed(uhci_map_status((td->status & 0xff)>> 16, 0),
- bus_to_virt(td->buffer), td->dev_id)) {
+ 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;
usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
- td->info |= 1 << 19; /* toggle between data0 and data1 */
+ td->info &= ~(1 << 19); /* clear data toggle */
+ td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info)) << 19; /* toggle between data0 and data1 */
td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
/* Remove then readd? Is that necessary */
@@ -1283,7 +1288,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
/* 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);
@@ -1563,6 +1568,7 @@ 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");
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index f9f73a051..082549b6e 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -53,7 +53,7 @@ int usb_init(void)
usb_acm_init();
# endif
# ifdef CONFIG_USB_PRINTER
- usb_print_init();
+ usb_printer_init();
# endif
# ifdef CONFIG_USB_CPIA
usb_cpia_init();
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index 63ebeffb9..a6bf78e4a 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -242,10 +242,12 @@ struct usb_driver {
* until we come up with a common meaning.
* void *buffer - This is a pointer to the data used in this
* USB transfer.
+ * int length - This is the number of bytes transferred in or out
+ * of the buffer by this transfer. (-1 = unknown/unsupported)
* void *dev_id - This is a user defined pointer set when the IRQ
* is requested that is passed back.
*/
-typedef int (*usb_device_irq)(int, void *, void *);
+typedef int (*usb_device_irq)(int, void *, int, void *);
struct usb_operations {
struct usb_device *(*allocate)(struct usb_device *);
diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c
index 655045bea..1a3e16b25 100644
--- a/drivers/usb/usb_scsi.c
+++ b/drivers/usb/usb_scsi.c
@@ -74,7 +74,9 @@ struct us_data {
__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 */
@@ -142,6 +144,9 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
/* 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;
@@ -150,6 +155,11 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
/* 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 );
@@ -216,27 +226,57 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
}
-static int pop_CBI_irq(int state, void *buffer, void *dev_id)
+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 = *(__u16 *)buffer;
- us->ip_wanted = 0;
+ US_DEBUGP("Interrupt Status %x\n", us->ip_data);
}
- wake_up(&us->ip_waitq);
+ if (us->ip_wanted)
+ wake_up(&us->ip_waitq);
+ us->ip_wanted = 0;
/* we dont want another interrupt */
return 0;
}
+
+static int pop_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ devrequest dr;
+ int result;
+
+ 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);
+
+ 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 0;
+}
+
static int pop_CB_command(Scsi_Cmnd *srb)
{
struct us_data *us = (struct us_data *)srb->host_scribble;
devrequest dr;
unsigned char cmd[16];
int result;
- int retry = 1;
+ int retry = 5;
int done_start = 0;
while (retry--) {
@@ -279,7 +319,8 @@ static int pop_CB_command(Scsi_Cmnd *srb)
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
&dr, cmd, us->fixedlength);
- if (!done_start && us->subclass == US_SC_UFI && cmd[0] == TEST_UNIT_READY && result) {
+ if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)
+ && cmd[0] == TEST_UNIT_READY && result) {
/* as per spec try a start command, wait and retry */
done_start++;
@@ -302,35 +343,47 @@ static int pop_CB_command(Scsi_Cmnd *srb)
return result;
}
-/* Protocol command handlers */
+/*
+ * Control/Bulk status handler
+ */
-static int pop_CBI(Scsi_Cmnd *srb)
+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;
- /* run the command */
-
- if ((result = pop_CB_command(srb))) {
- US_DEBUGP("CBI command %x\n", result);
- if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)
- return (DID_OK << 16) | 2;
- return DID_ABORT << 16;
- }
-
- /* transfer the data */
-
- if (us_transfer_length(srb)) {
- result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- if (result && result != USB_ST_DATAUNDERRUN) {
- US_DEBUGP("CBI transfer %x\n", result);
+ 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;
}
- }
-
- /* get status */
+ 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;
- if (us->protocol == US_PR_CBI) {
+ case US_PR_CBI:
/* get from interrupt pipe */
/* add interrupt transfer, marked for removal */
@@ -367,12 +420,48 @@ static int pop_CBI(Scsi_Cmnd *srb)
return DID_ABORT << 16;
}
return (DID_OK << 16) + ((us->ip_data & 0x300) ? 2 : 0);
- } else {
- /* get from where? */
}
return DID_ERROR << 16;
}
+/* Protocol command handlers */
+
+static int pop_CBI(Scsi_Cmnd *srb)
+{
+ struct us_data *us = (struct us_data *)srb->host_scribble;
+ int result;
+
+ /* run the command */
+
+ if ((result = pop_CB_command(srb))) {
+ US_DEBUGP("CBI command %x\n", result);
+ if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) {
+ return (DID_OK << 16) | 2;
+ }
+ return DID_ABORT << 16;
+ }
+
+ /* transfer the data */
+
+ if (us_transfer_length(srb)) {
+ result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ if (result && result != USB_ST_DATAUNDERRUN) {
+ US_DEBUGP("CBI transfer %x\n", result);
+ return DID_ABORT << 16;
+ } else if (result == USB_ST_DATAUNDERRUN) {
+ return DID_OK << 16;
+ }
+ } else {
+ if (!result) {
+ return DID_OK << 16;
+ }
+ }
+
+ /* get status */
+
+ return pop_CB_status(srb);
+}
+
static int pop_Bulk_reset(struct us_data *us)
{
devrequest dr;
@@ -380,21 +469,20 @@ static int pop_Bulk_reset(struct us_data *us)
dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
dr.request = US_BULK_RESET;
- dr.value = US_BULK_RESET_SOFT;
+ dr.value = US_BULK_RESET_HARD;
dr.index = 0;
dr.length = 0;
- US_DEBUGP("Bulk soft reset\n");
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 soft reset failed %d\n", result);
- dr.value = US_BULK_RESET_HARD;
- 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);
- }
+ 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;
}
/*
@@ -453,8 +541,6 @@ static int pop_Bulk(Scsi_Cmnd *srb)
stall = 0;
do {
- //usb_settoggle(us->pusb_dev, us->ep_in, 0); /* AAARgh!! */
- US_DEBUGP("Toggle is %d\n", usb_gettoggle(us->pusb_dev, us->ep_in));
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);
@@ -564,6 +650,9 @@ 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;
@@ -581,9 +670,12 @@ static int us_abort( Scsi_Cmnd *srb )
return 0;
}
-static int us_device_reset( Scsi_Cmnd *srb )
+static int us_bus_reset( Scsi_Cmnd *srb )
{
- return 0;
+ 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 )
@@ -591,10 +683,6 @@ static int us_host_reset( Scsi_Cmnd *srb )
return 0;
}
-static int us_bus_reset( Scsi_Cmnd *srb )
-{
- return 0;
-}
#undef SPRINTF
#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
@@ -623,9 +711,9 @@ int usb_scsi_proc_info (char *buffer, char **start, off_t offset, int length, in
if (inout)
return length;
- if (!(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
+ if (!us->pusb_dev || !(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
vendor = "?";
- if (!(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
+ if (!us->pusb_dev || !(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
product = "?";
switch (us->protocol) {
@@ -677,7 +765,7 @@ static Scsi_Host_Template my_host_template = {
us_queuecommand,
NULL, /* eh_strategy */
us_abort,
- us_device_reset,
+ us_bus_reset,
us_bus_reset,
us_host_reset,
NULL, /* abort */
@@ -695,6 +783,25 @@ static Scsi_Host_Template my_host_template = {
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;
@@ -710,7 +817,7 @@ static int usbscsi_control_thread(void * __us)
exit_files(current);
//exit_fs(current);
- sprintf(current->comm, "usbscsi%d", us->host_no);
+ sprintf(current->comm, "usbscsi%d", us->host_number);
unlock_kernel();
@@ -727,18 +834,160 @@ static int usbscsi_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND :
- if (!us->pusb_dev || us->srb->target || us->srb->lun) {
+ 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
+ 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) {
+ 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 */
+ }
+ }
+ }
}
us->srb->scsi_done(us->srb);
+ us->srb = NULL;
break;
case US_ACT_ABORT :
@@ -820,7 +1069,7 @@ static int scsi_probe(struct usb_device *dev)
if (dev->descriptor.idVendor == 0x04e6 &&
dev->descriptor.idProduct == 0x0001) {
/* shuttle E-USB */
- protocol = US_PR_ZIP;
+ protocol = US_PR_CB;
subclass = US_SC_8070; /* an assumption */
} else if (dev->descriptor.bDeviceClass != 0 ||
dev->config->altsetting->interface->bInterfaceClass != 8 ||
@@ -835,11 +1084,15 @@ static int scsi_probe(struct usb_device *dev)
usb_string(dev, dev->descriptor.iSerialNumber) ) {
make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
usb_string(dev, dev->descriptor.iSerialNumber));
- for (ss = us_list; ss; ss = ss->next) {
- if (GUID_EQUAL(guid, ss->guid)) {
- US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
- break;
- }
+ } 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;
}
}
}
@@ -865,6 +1118,7 @@ static int scsi_probe(struct usb_device *dev)
ss->subclass = interface->bInterfaceSubClass;
ss->protocol = interface->bInterfaceProtocol;
}
+ ss->attention_done = 0;
/* set the protocol op */
@@ -873,16 +1127,19 @@ static int scsi_probe(struct usb_device *dev)
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;
}
@@ -907,6 +1164,7 @@ static int scsi_probe(struct usb_device *dev)
/* 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) {
@@ -933,13 +1191,8 @@ static int scsi_probe(struct usb_device *dev)
/* make unique id if possible */
- if (dev->descriptor.iSerialNumber &&
- usb_string(dev, dev->descriptor.iSerialNumber) ) {
- make_guid(ss->guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
- usb_string(dev, dev->descriptor.iSerialNumber));
- }
-
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+ memcpy(ss->guid, guid, sizeof(guid));
/* set class specific stuff */
@@ -986,9 +1239,30 @@ static int scsi_probe(struct usb_device *dev)
(struct us_data *)htmplt->proc_dir = ss;
- if (ss->protocol == US_PR_CBI)
+
+ 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 */
{
diff --git a/drivers/usb/usb_scsi_debug.c b/drivers/usb/usb_scsi_debug.c
index 2ca847c08..634f4c0f6 100644
--- a/drivers/usb/usb_scsi_debug.c
+++ b/drivers/usb/usb_scsi_debug.c
@@ -95,7 +95,7 @@ void us_show_command(Scsi_Cmnd *srb)
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: what = "??"; 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",