📄 usbd-inline.h
字号:
/* * linux/drivers/usbd/usb-inline.h - additional USB Device Core support * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * By: * Stuart Lynne <sl@lineo.com>, * Tom Rushworth <tbr@lineo.com>, * Bruce Balden <balden@lineo.com> * * 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. * *//* * Initialize an urb_link to be a single element list. * If the urb_link is being used as a distinguished list head * the list is empty when the head is the only link in the list. */static __inline__ void urb_link_init (urb_link * ul){ if (ul) { ul->prev = ul->next = ul; }}/* * Detach an urb_link from a list, and set it * up as a single element list, so no dangling * pointers can be followed, and so it can be * joined to another list if so desired. * * Called from interrupt. */static __inline__ void urb_detach_irq (struct urb *urb){ if (urb) { urb_link *ul = &urb->link; ul->next->prev = ul->prev; ul->prev->next = ul->next; urb_link_init (ul); }}/* * Return the first urb_link in a list with a distinguished * head "hd", or NULL if the list is empty. This will also * work as a predicate, returning NULL if empty, and non-NULL * otherwise. * * Called from interrupt. */static __inline__ urb_link *first_urb_link_irq (urb_link * hd){ urb_link *nx; if (NULL != hd && NULL != (nx = hd->next) && nx != hd) { // There is at least one element in the list // (besides the distinguished head). return (nx); } // The list is empty return (NULL);}/* * Return the first urb in a list with a distinguished * head "hd", or NULL if the list is empty. * * Called from interrupt. */static __inline__ struct urb *first_urb_irq (urb_link * hd){ urb_link *nx; if (NULL == (nx = first_urb_link_irq (hd))) { // The list is empty return (NULL); } return (p2surround (struct urb, link, nx));}/* * Detach and return the first urb in a list with a distinguished * head "hd", or NULL if the list is empty. */static __inline__ struct urb *first_urb_detached_irq (urb_link * hd){ struct urb *urb; if ((urb = first_urb_irq (hd))) { urb_detach_irq (urb); } return urb;}/* * Detach and return the first urb in a list with a distinguished * head "hd", or NULL if the list is empty. * * Can be called from non-interrupt context. * */static __inline__ struct urb *first_urb_detached (urb_link * hd){ struct urb *urb; unsigned long flags; local_irq_save (flags); urb = first_urb_detached_irq (hd); local_irq_restore (flags); return urb;}/* * Append an urb_link (or a whole list of * urb_links) to the tail of another list * of urb_links. */static __inline__ void urb_append_irq (urb_link * hd, struct urb *urb){ // XXX XXX _urb_detach(urb); if (hd && urb) { urb_link *new = &urb->link;#ifdef C2L_SINGLETON_ONLY // This _assumes_ the new urb is a singleton, // but allows it to have an uninitialized link. //printk(KERN_DEBUG"urb_append: hd: %p n:%p p:%p new: %p n:%p p:%p\n", hd, hd->next, hd->prev, new, new->next, new->prev); new->prev = hd->prev; new->next = hd; hd->prev->next = new; hd->prev = new;#else // This allows the new urb to be a list of urbs, // with new pointing at the first, but the link // must be initialized. // Order is important here... urb_link *pul = hd->prev; new->prev->next = hd; hd->prev = new->prev; new->prev = pul; pul->next = new;#endif }}#if 0/** * usbd_dealloc_urb - deallocate an URB and associated buffer * @urb: pointer to an urb structure * * Deallocate an urb structure and associated data. */static __inline__ void usbd_dealloc_urb (struct urb *urb){ if (urb) { if (urb->buffer) { if (urb->function_instance && urb->function_instance->function_driver->ops->dealloc_urb_data) { urb->function_instance->function_driver->ops->dealloc_urb_data (urb); } else { kfree (urb->buffer); } } kfree (urb); }}#elsevoid usbd_dealloc_urb (struct urb *urb);#endif/** * usbd_schedule_device_bh - schedule bottom half * * Schedule the device bottom half. This runs from timer tick so is equivalent * to interrupt but at lower priority. * */static __inline__ void usbd_schedule_device_bh (struct usb_device_instance *device){ if (device && (device->status != USBD_CLOSING) && !device->device_bh.sync) {#ifdef CONFIG_ARCH_PXA usbd_device_bh (device);#else queue_task (&device->device_bh, &tq_immediate); mark_bh (IMMEDIATE_BH);#endif }}/** * usbd_schedule_function_bh - schedule bottom half * * Schedule the function bottom half. This runs as a process. * */static __inline__ void usbd_schedule_function_bh (struct usb_device_instance *device){ if (device && (device->status != USBD_CLOSING) && !device->function_bh.sync) { schedule_task (&device->function_bh); }}#if 0/** * usbd_recv_urb_irq - process a received urb * @urb: pointer to an urb structure * * Used by a USB Bus interface driver to pass received data in a URB to the * appropriate USB Function driver via the endpoints receive queue. * * Called from interrupt. * */static __inline__ void usbd_recv_urb_irq (struct urb *urb){ if (urb) { urb->status = RECV_OK; urb->jiffies = jiffies; /* XXX XXX { unsigned long flags; local_irq_save(flags); */ urb_append_irq (&(urb->endpoint->rcv), urb); /* local_irq_restore(flags); } */ usbd_schedule_device_bh (urb->device); }}#endif/** * usbd_recycle_urb - recycle a received urb * @urb: pointer to an urb structure * * Used by a USB Function interface driver to recycle an urb. * */static __inline__ void usbd_recycle_urb (struct urb *urb){ if (urb) { urb->actual_length = 0; urb->status = RECV_READY; urb->jiffies = jiffies; { unsigned long flags; local_irq_save (flags); urb_append_irq (&(urb->endpoint->rdy), urb); local_irq_restore (flags); } }}/** * usbd_send_urb - submit a urb to send * @urb: pointer to an urb structure * * Used by a USB Function driver to submit data to be sent in an urb to the * appropriate USB Bus driver via the endpoints transmit queue. * * This is NOT called from interrupts. * */static __inline__ int usbd_send_urb (struct urb *urb){ if (urb && urb->endpoint && (urb->device->status == USBD_OK)) { //urb->device->urbs_queued++; urb->status = SEND_IN_PROGRESS; urb->jiffies = jiffies; { unsigned long flags; local_irq_save (flags); urb_append_irq (&(urb->endpoint->tx), urb); local_irq_restore (flags); } return urb->device->bus->driver->ops->send_urb (urb); } printk (KERN_ERR "usbd_send_urb: !USBD_OK\n"); return -EINVAL;}/* * * usbd_urb_sent_irq - tell function that an urb has been transmitted. * @urb: pointer to an urb structure * * Must be called from an interrupt or with interrupts disabled. * * Used by a USB Bus driver to pass a sent urb back to the function * driver via the endpoints done queue. * * Called from interrupt. */static __inline__ void usbd_urb_sent_irq (struct urb *urb, int rc){ if (urb) { urb->status = rc; urb->jiffies = jiffies; /* XXX XXX { unsigned long flags; local_irq_save(flags); */ urb_append_irq (&(urb->endpoint->done), urb); /* local_irq_restore(flags); } */ usbd_schedule_device_bh (urb->device); }}/** * usbd_recv_setup - process a received urb * @urb: pointer to an urb structure * * Used by a USB Bus interface driver to pass received data in a URB to the * appropriate USB Function driver. */static __inline__ int usbd_recv_setup (struct urb *urb){ struct usb_function_instance *function_instance;#ifdef CONFIG_USBD_EP0_SUPPORT int i;#else int port = 0; // XXX compound devices#endif#ifdef CONFIG_USBD_EP0_SUPPORT if (urb && !(urb->device->status == USBD_CLOSING)) { switch ( urb->device_request.bmRequestType & USB_REQ_TYPE_MASK ) { case USB_REQ_TYPE_STANDARD: function_instance = urb->device->ep0; if ( function_instance!=NULL && function_instance->function_driver->ops->recv_setup!=NULL ) return function_instance->function_driver->ops->recv_setup( urb ); return 1; case USB_REQ_TYPE_VENDOR: case USB_REQ_TYPE_CLASS: for ( i=0; i<urb->device->functions; i++ ) { function_instance = urb->device->function_instance_array + i; if ( function_instance!=NULL && function_instance->function_driver->ops->recv_setup!=NULL ) return function_instance->function_driver->ops->recv_setup( urb ); } return 1; default: break; } }#else if (urb && !(urb->device->status == USBD_CLOSING)) { //printk(KERN_DEBUG"usbd_recv_setup: %p request: %x vendor: %d\n", // urb, urb->device_request.bmRequestType, (urb->device_request.bmRequestType&USB_REQ_TYPE_MASK)!=0); function_instance = ((urb->device_request.bmRequestType & USB_REQ_TYPE_MASK) == 0) ? urb->device->ep0 : urb->device->function_instance_array + port; if (function_instance == NULL) { printk (KERN_ERR "usbd_recv_setup: endpoint: %d function_instance NULL\n", urb->endpoint->endpoint_address); return 1; } if (function_instance->function_driver->ops->recv_setup == NULL) { printk (KERN_ERR "usbd_recv_setup: recv_setup NULL\n"); return 1; } return function_instance->function_driver->ops->recv_setup (urb); }#endif printk (KERN_ERR "usbd_recv_setup: !USBD_OK\n"); return -EINVAL;}/** * usbd_rcv_complete_irq - complete a receive * @endpoint: * @len: * @urb_bad: * * Called from rcv interrupt to complete. */static __inline__ void usbd_rcv_complete_irq (struct usb_endpoint_instance *endpoint, int len, int urb_bad){ // XXX XXX //return; if (endpoint) { struct urb *rcv_urb; //printk(KERN_ERR"usbd_rcv_complete: len: %d urb: %p\n", len, endpoint->rcv_urb); // if we had an urb then update actual_length, dispatch if neccessary if ((rcv_urb = endpoint->rcv_urb)) { //printk(KERN_ERR"usbd_rcv_complete: actual: %d buffer: %d\n", //rcv_urb->actual_length, rcv_urb->buffer_length); // check the urb is ok, are we adding data less than the packetsize if (!urb_bad && (rcv_urb->device->status == USBD_OK) && (len <= endpoint->rcv_packetSize)) { // increment the received data size rcv_urb->actual_length += len; // if the current received data is short (less than full packetsize) which // indicates the end of the bulk transfer, we have received the maximum // transfersize, or if we do not have enough room to receive another packet // then pass this data up to the function driver if (((len < endpoint->rcv_packetSize) || (rcv_urb->actual_length >= endpoint->rcv_transferSize) || (rcv_urb->actual_length >= (rcv_urb->buffer_length - endpoint->rcv_packetSize)))) { //printk(KERN_ERR"usbd_rcv_complete: finishing %p\n", rcv_urb); endpoint->rcv_urb = NULL; rcv_urb->status = RECV_OK; rcv_urb->jiffies = jiffies; urb_append_irq (&(rcv_urb->endpoint->rcv), rcv_urb); usbd_schedule_device_bh (rcv_urb->device); //printk(KERN_INFO"cmplt: %p\n", rcv_urb); rcv_urb = NULL; } } else { printk (KERN_ERR "usbd_rcv_complete: RECV_ERROR actual: %d buffer: %d urb_bad: %d\n", rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad); // XXX TEST rcv_urb->actual_length = 0; // XXX TEST printk(KERN_ERR"too large %d %d\n", len, endpoint->rcv_packetSize); rcv_urb->actual_length = 0; rcv_urb->status = RECV_ERROR; rcv_urb->jiffies = jiffies; urb_append_irq (&(rcv_urb->endpoint->rcv), rcv_urb); usbd_schedule_device_bh (rcv_urb->device); rcv_urb = NULL; } } else { printk (KERN_ERR "usbd_rcv_complete: no rcv_urb!\n"); } // if we don't have an urb see if we can get one if (!rcv_urb) { endpoint->rcv_urb = first_urb_detached_irq (&endpoint->rdy); } } else { printk (KERN_ERR "usbd_rcv_complete: no endpoint!\n"); }}/** * usbd_tx_complete_irq - complete a transmit * @endpoint: * @resetart: * * Called from tx interrupt to complete. */static __inline__ void usbd_tx_complete_irq (struct usb_endpoint_instance *endpoint, int restart){ if (endpoint) { struct urb *tx_urb; // if we have a tx_urb advance or reset, finish if complete if ((tx_urb = endpoint->tx_urb)) { if (!restart) { //int sent = MIN(endpoint->last,endpoint->tx_packetSize); int sent = endpoint->last; //endpoint->sent += endpoint->last; endpoint->sent += sent; endpoint->last -= sent; } else { endpoint->last = 0; } //printk(KERN_INFO"cmplt: act: %d last: %d sent: %d\n", // endpoint->tx_urb->actual_length, // endpoint->last, endpoint->sent); if ((tx_urb->device->status == USBD_OK) && (endpoint->tx_urb->actual_length - endpoint->sent) <= 0) { if (endpoint->endpoint_address) { usbd_urb_sent_irq (endpoint->tx_urb, SEND_FINISHED_OK); } endpoint->tx_urb = NULL; endpoint->last = endpoint->sent = 0; //printk(KERN_INFO"cmplt: finished\n"); } } // if we do not have a tx_urb see if we can get one if (endpoint->endpoint_address && !endpoint->tx_urb && (endpoint->tx_urb = first_urb_detached_irq (&endpoint->tx))) { endpoint->last = endpoint->sent = 0; } } else { printk (KERN_ERR "usbd_tx_complete_irq: no endpoint!\n"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -