📄 auerswald.c
字号:
urb->status = 0; /* needed! */ result = usb_submit_urb(urb, GFP_ATOMIC); /* check for submit errors */ if (result) { urb->status = result; dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result); /* and do error handling via completion function */ auerchain_complete( urb, NULL); } } return 0;}/* submit function for chained urbs this function may be called from completion context or from user space!*/static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb){ return auerchain_submit_urb_list (acp, urb, 0);}/* cancel an urb which is submitted to the chain the result is 0 if the urb is cancelled, or -EINPROGRESS if the function is successfully started.*/static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb){ unsigned long flags; struct urb * urbp; pauerchainelement_t acep; struct list_head *tmp; dbg ("auerchain_unlink_urb called"); /* search the chain of waiting elements */ spin_lock_irqsave (&acp->lock, flags); list_for_each (tmp, &acp->waiting_list) { acep = list_entry (tmp, auerchainelement_t, list); if (acep->urbp == urb) { list_del (tmp); urb->context = acep->context; urb->complete = acep->complete; list_add_tail (&acep->list, &acp->free_list); spin_unlock_irqrestore (&acp->lock, flags); dbg ("unlink waiting urb"); urb->status = -ENOENT; urb->complete (urb, NULL); return 0; } } /* not found. */ spin_unlock_irqrestore (&acp->lock, flags); /* get the active urb */ acep = acp->active; if (acep) { urbp = acep->urbp; /* check if we have to cancel the active urb */ if (urbp == urb) { /* note that there is a race condition between the check above and the unlink() call because of no lock. This race is harmless, because the usb module will detect the unlink() after completion. We can't use the acp->lock here because the completion function wants to grab it. */ dbg ("unlink active urb"); return usb_unlink_urb (urbp); } } /* not found anyway ... is some kind of success */ dbg ("urb to unlink not found in chain"); return 0;}/* cancel all urbs which are in the chain. this function must not be called from interrupt or completion handler.*/static void auerchain_unlink_all (pauerchain_t acp){ unsigned long flags; struct urb * urbp; pauerchainelement_t acep; dbg ("auerchain_unlink_all called"); /* clear the chain of waiting elements */ spin_lock_irqsave (&acp->lock, flags); while (!list_empty (&acp->waiting_list)) { /* get the next entry */ struct list_head *tmp = acp->waiting_list.next; list_del (tmp); acep = list_entry (tmp, auerchainelement_t, list); urbp = acep->urbp; urbp->context = acep->context; urbp->complete = acep->complete; list_add_tail (&acep->list, &acp->free_list); spin_unlock_irqrestore (&acp->lock, flags); dbg ("unlink waiting urb"); urbp->status = -ENOENT; urbp->complete (urbp, NULL); spin_lock_irqsave (&acp->lock, flags); } spin_unlock_irqrestore (&acp->lock, flags); /* clear the active urb */ acep = acp->active; if (acep) { urbp = acep->urbp; dbg ("unlink active urb"); usb_kill_urb (urbp); }}/* free the chain. this function must not be called from interrupt or completion handler.*/static void auerchain_free (pauerchain_t acp){ unsigned long flags; pauerchainelement_t acep; dbg ("auerchain_free called"); /* first, cancel all pending urbs */ auerchain_unlink_all (acp); /* free the elements */ spin_lock_irqsave (&acp->lock, flags); while (!list_empty (&acp->free_list)) { /* get the next entry */ struct list_head *tmp = acp->free_list.next; list_del (tmp); spin_unlock_irqrestore (&acp->lock, flags); acep = list_entry (tmp, auerchainelement_t, list); kfree (acep); spin_lock_irqsave (&acp->lock, flags); } spin_unlock_irqrestore (&acp->lock, flags);}/* Init the chain control structure */static void auerchain_init (pauerchain_t acp){ /* init the chain data structure */ acp->active = NULL; spin_lock_init (&acp->lock); INIT_LIST_HEAD (&acp->waiting_list); INIT_LIST_HEAD (&acp->free_list);}/* setup a chain. It is assumed that there is no concurrency while setting up the chain requirement: auerchain_init()*/static int auerchain_setup (pauerchain_t acp, unsigned int numElements){ pauerchainelement_t acep; dbg ("auerchain_setup called with %d elements", numElements); /* fill the list of free elements */ for (;numElements; numElements--) { acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL); if (!acep) goto ac_fail; memset (acep, 0, sizeof (auerchainelement_t)); INIT_LIST_HEAD (&acep->list); list_add_tail (&acep->list, &acp->free_list); } return 0;ac_fail:/* free the elements */ while (!list_empty (&acp->free_list)) { /* get the next entry */ struct list_head *tmp = acp->free_list.next; list_del (tmp); acep = list_entry (tmp, auerchainelement_t, list); kfree (acep); } return -ENOMEM;}/* completion handler for synchronous chained URBs */static void auerchain_blocking_completion (struct urb *urb, struct pt_regs *regs){ pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context; pchs->done = 1; wmb(); wake_up (&pchs->wqh);}/* Starts chained urb and waits for completion or timeout */static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length){ auerchain_chs_t chs; int status; dbg ("auerchain_start_wait_urb called"); init_waitqueue_head (&chs.wqh); chs.done = 0; urb->context = &chs; status = auerchain_submit_urb (acp, urb); if (status) /* something went wrong */ return status; timeout = wait_event_timeout(chs.wqh, chs.done, timeout); if (!timeout && !chs.done) { if (urb->status != -EINPROGRESS) { /* No callback?!! */ dbg ("auerchain_start_wait_urb: raced timeout"); status = urb->status; } else { dbg ("auerchain_start_wait_urb: timeout"); auerchain_unlink_urb (acp, urb); /* remove urb safely */ status = -ETIMEDOUT; } } else status = urb->status; if (actual_length) *actual_length = urb->actual_length; return status;}/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion acp: pointer to the auerchain dev: pointer to the usb device to send the message to pipe: endpoint "pipe" to send the message to request: USB message request value requesttype: USB message request type value value: USB message value index: USB message index value data: pointer to the data to send size: length in bytes of the data to send timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) This function sends a simple control message to a specified endpoint and waits for the message to complete, or timeout. If successful, it returns the transferred length, otherwise a negative error number. Don't use this function from within an interrupt context, like a bottom half handler. If you need an asynchronous message, or need to send a message from within interrupt context, use auerchain_submit_urb()*/static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout){ int ret; struct usb_ctrlrequest *dr; struct urb *urb; int length; dbg ("auerchain_control_msg"); dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL); if (!dr) return -ENOMEM; urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) { kfree (dr); return -ENOMEM; } dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16 (value); dr->wIndex = cpu_to_le16 (index); dr->wLength = cpu_to_le16 (size); usb_fill_control_urb (urb, dev, pipe, (unsigned char*)dr, data, size, /* build urb */ auerchain_blocking_completion, NULL); ret = auerchain_start_wait_urb (acp, urb, timeout, &length); usb_free_urb (urb); kfree (dr); if (ret < 0) return ret; else return length;}/*-------------------------------------------------------------------*//* Buffer List helper functions *//* free a single auerbuf */static void auerbuf_free (pauerbuf_t bp){ kfree(bp->bufp); kfree(bp->dr); if (bp->urbp) { usb_free_urb(bp->urbp); } kfree(bp);}/* free the buffers from an auerbuf list */static void auerbuf_free_list (struct list_head *q){ struct list_head *tmp; struct list_head *p; pauerbuf_t bp; dbg ("auerbuf_free_list"); for (p = q->next; p != q;) { bp = list_entry (p, auerbuf_t, buff_list); tmp = p->next; list_del (p); p = tmp; auerbuf_free (bp); }}/* init the members of a list control block */static void auerbuf_init (pauerbufctl_t bcp){ dbg ("auerbuf_init"); spin_lock_init (&bcp->lock); INIT_LIST_HEAD (&bcp->free_buff_list); INIT_LIST_HEAD (&bcp->rec_buff_list);}/* free all buffers from an auerbuf chain */static void auerbuf_free_buffers (pauerbufctl_t bcp){ unsigned long flags; dbg ("auerbuf_free_buffers"); spin_lock_irqsave (&bcp->lock, flags); auerbuf_free_list (&bcp->free_buff_list); auerbuf_free_list (&bcp->rec_buff_list); spin_unlock_irqrestore (&bcp->lock, flags);}/* setup a list of buffers *//* requirement: auerbuf_init() */static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned int bufsize){ pauerbuf_t bep = NULL; dbg ("auerbuf_setup called with %d elements of %d bytes", numElements, bufsize); /* fill the list of free elements */ for (;numElements; numElements--) { bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL); if (!bep) goto bl_fail; memset (bep, 0, sizeof (auerbuf_t)); bep->list = bcp; INIT_LIST_HEAD (&bep->buff_list); bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL); if (!bep->bufp) goto bl_fail; bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL); if (!bep->dr) goto bl_fail; bep->urbp = usb_alloc_urb (0, GFP_KERNEL); if (!bep->urbp) goto bl_fail; list_add_tail (&bep->buff_list, &bcp->free_buff_list); } return 0;bl_fail:/* not enough memory. Free allocated elements */ dbg ("auerbuf_setup: no more memory"); kfree(bep); auerbuf_free_buffers (bcp); return -ENOMEM;}/* insert a used buffer into the free list */static void auerbuf_releasebuf( pauerbuf_t bp){ unsigned long flags; pauerbufctl_t bcp = bp->list; bp->retries = 0; dbg ("auerbuf_releasebuf called"); spin_lock_irqsave (&bcp->lock, flags); list_add_tail (&bp->buff_list, &bcp->free_buff_list); spin_unlock_irqrestore (&bcp->lock, flags);}/*-------------------------------------------------------------------*//* Completion handlers */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -