patch-2.3.11 linux/drivers/usb/ohci.c
Next file: linux/drivers/usb/ohci.h
Previous file: linux/drivers/usb/ohci-hcd.c
Back to the patch index
Back to the overall index
- Lines: 235
- Date:
Mon Jul 19 11:18:10 1999
- Orig file:
v2.3.10/linux/drivers/usb/ohci.c
- Orig date:
Thu Jul 8 15:42:21 1999
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
@@ -437,6 +437,59 @@
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("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.
@@ -584,6 +637,8 @@
new_td->info = cpu_to_le32(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;
}
}
@@ -879,8 +934,11 @@
*
* 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 int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
+static void* 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);
@@ -892,14 +950,14 @@
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 -1;
+ return NULL;
}
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 -1;
+ return NULL;
}
/*
@@ -917,10 +975,6 @@
OHCI_TD_ROUND,
dev->data, maxps,
dev_id, handler);
- /*
- * TODO: be aware of how the OHCI controller deals with DMA
- * spanning more than one page.
- */
/*
* Put the TD onto our ED and make sure its ready to run
@@ -936,17 +990,54 @@
/* Assimilate the new ED into the collective */
ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
- /* FIXME: return a request handle that can be used by the
- * caller to cancel this request. Be sure its guaranteed not
- * to be re-used until the caller is guaranteed to know that
- * the transfer has ended or been cancelled */
- return 0;
+ return (void*)td;
} /* ohci_request_irq() */
-
/*
- * Control thread operations:
+ * 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 (handle)
+ printk("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);
/*
@@ -1134,7 +1225,7 @@
#ifdef OHCI_DEBUG
if (completion_status != 0) {
- char *what = (completion_status < 0)? "timed out":
+ const 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,
@@ -1407,6 +1498,7 @@
/* .......... */
+
/*
* Allocate a new USB device to be attached to an OHCI controller
*/
@@ -1479,6 +1571,32 @@
}
+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
*/
@@ -1488,6 +1606,12 @@
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
};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)