📄 auerswald.c
字号:
/* Values of urb->status or results of usb_submit_urb():0 Initial, OK-EINPROGRESS during submission until end-ENOENT if urb is unlinked-ETIMEDOUT Transfer timed out, NAK-ENOMEM Memory Overflow-ENODEV Specified USB-device or bus doesn't exist-ENXIO URB already queued-EINVAL a) Invalid transfer type specified (or not supported) b) Invalid interrupt interval (0n256)-EAGAIN a) Specified ISO start frame too early b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again.-EFBIG Too much ISO frames requested (currently uhci900)-EPIPE Specified pipe-handle/Endpoint is already stalled-EMSGSIZE Endpoint message size is zero, do interface/alternate setting-EPROTO a) Bitstuff error b) Unknown USB error-EILSEQ CRC mismatch-ENOSR Buffer error-EREMOTEIO Short packet detected-EXDEV ISO transfer only partially completed look at individual frame status for details-EINVAL ISO madness, if this happens: Log off and go home-EOVERFLOW babble*//* check if a status code allows a retry */static int auerswald_status_retry (int status){ switch (status) { case 0: case -ETIMEDOUT: case -EOVERFLOW: case -EAGAIN: case -EPIPE: case -EPROTO: case -EILSEQ: case -ENOSR: case -EREMOTEIO: return 1; /* do a retry */ } return 0; /* no retry possible */}/* Completion of asynchronous write block */static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs){ pauerbuf_t bp = (pauerbuf_t) urb->context; pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); dbg ("auerchar_ctrlwrite_complete called"); /* reuse the buffer */ auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait);}/* Completion handler for dummy retry packet */static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *regs){ pauerbuf_t bp = (pauerbuf_t) urb->context; pauerswald_t cp; int ret; dbg ("auerswald_ctrlread_wretcomplete called"); dbg ("complete with status: %d", urb->status); cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); /* check if it is possible to advance */ if (!auerswald_status_retry (urb->status) || !cp->usbdev) { /* reuse the buffer */ err ("control dummy: transmission error %d, can not retry", urb->status); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); return; } /* fill the control message */ bp->dr->bRequestType = AUT_RREQ; bp->dr->bRequest = AUV_RBLOCK; bp->dr->wLength = bp->dr->wValue; /* temporary stored */ bp->dr->wValue = cpu_to_le16 (1); /* Retry Flag */ /* bp->dr->index = channel id; remains */ usb_fill_control_urb (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->wLength), auerswald_ctrlread_complete,bp); /* submit the control msg as next paket */ ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); if (ret) { dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; auerswald_ctrlread_complete (bp->urbp, NULL); }}/* completion handler for receiving of control messages */static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs){ unsigned int serviceid; pauerswald_t cp; pauerscon_t scp; pauerbuf_t bp = (pauerbuf_t) urb->context; int ret; dbg ("auerswald_ctrlread_complete called"); cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); /* check if there is valid data in this urb */ if (urb->status) { dbg ("complete with non-zero status: %d", urb->status); /* should we do a retry? */ if (!auerswald_status_retry (urb->status) || !cp->usbdev || (cp->version < AUV_RETRY) || (bp->retries >= AU_RETRIES)) { /* reuse the buffer */ err ("control read: transmission error %d, can not retry", urb->status); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); return; } bp->retries++; dbg ("Retry count = %d", bp->retries); /* send a long dummy control-write-message to allow device firmware to react */ bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_DUMMY; bp->dr->wValue = bp->dr->wLength; /* temporary storage */ // bp->dr->wIndex channel ID remains bp->dr->wLength = cpu_to_le16 (32); /* >= 8 bytes */ usb_fill_control_urb (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), (unsigned char*)bp->dr, bp->bufp, 32, auerswald_ctrlread_wretcomplete,bp); /* submit the control msg as next paket */ ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); if (ret) { dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; auerswald_ctrlread_wretcomplete (bp->urbp, regs); } return; } /* get the actual bytecount (incl. headerbyte) */ bp->len = urb->actual_length; serviceid = bp->bufp[0] & AUH_TYPEMASK; dbg ("Paket with serviceid %d and %d bytes received", serviceid, bp->len); /* dispatch the paket */ scp = cp->services[serviceid]; if (scp) { /* look, Ma, a listener! */ scp->dispatch (scp, bp); } /* release the paket */ auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait);}/*-------------------------------------------------------------------*//* Handling of Interrupt Endpoint *//* This interrupt Endpoint is used to inform the host about waiting messages from the USB device.*//* int completion handler. */static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs){ unsigned long flags; unsigned int channelid; unsigned int bytecount; int ret; pauerbuf_t bp = NULL; pauerswald_t cp = (pauerswald_t) urb->context; dbg ("%s called", __FUNCTION__); switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); goto exit; } /* check if all needed data was received */ if (urb->actual_length < AU_IRQMINSIZE) { dbg ("invalid data length received: %d bytes", urb->actual_length); goto exit; } /* check the command code */ if (cp->intbufp[0] != AU_IRQCMDID) { dbg ("invalid command received: %d", cp->intbufp[0]); goto exit; } /* check the command type */ if (cp->intbufp[1] != AU_BLOCKRDY) { dbg ("invalid command type received: %d", cp->intbufp[1]); goto exit; } /* now extract the information */ channelid = cp->intbufp[2]; bytecount = (unsigned char)cp->intbufp[3]; bytecount |= (unsigned char)cp->intbufp[4] << 8; /* check the channel id */ if (channelid >= AUH_TYPESIZE) { dbg ("invalid channel id received: %d", channelid); goto exit; } /* check the byte count */ if (bytecount > (cp->maxControlLength+AUH_SIZE)) { dbg ("invalid byte count received: %d", bytecount); goto exit; } dbg ("Service Channel = %d", channelid); dbg ("Byte Count = %d", bytecount); /* get a buffer for the next data paket */ spin_lock_irqsave (&cp->bufctl.lock, flags); if (!list_empty (&cp->bufctl.free_buff_list)) { /* yes: get the entry */ struct list_head *tmp = cp->bufctl.free_buff_list.next; list_del (tmp); bp = list_entry (tmp, auerbuf_t, buff_list); } spin_unlock_irqrestore (&cp->bufctl.lock, flags); /* if no buffer available: skip it */ if (!bp) { dbg ("auerswald_int_complete: no data buffer available"); /* can we do something more? This is a big problem: if this int packet is ignored, the device will wait forever and not signal any more data. The only real solution is: having enough buffers! Or perhaps temporary disabling the int endpoint? */ goto exit; } /* fill the control message */ bp->dr->bRequestType = AUT_RREQ; bp->dr->bRequest = AUV_RBLOCK; bp->dr->wValue = cpu_to_le16 (0); bp->dr->wIndex = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT); bp->dr->wLength = cpu_to_le16 (bytecount); usb_fill_control_urb (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), (unsigned char*)bp->dr, bp->bufp, bytecount, auerswald_ctrlread_complete,bp); /* submit the control msg */ ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); if (ret) { dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret); bp->urbp->status = ret; auerswald_ctrlread_complete( bp->urbp, NULL); /* here applies the same problem as above: device locking! */ }exit: ret = usb_submit_urb (urb, GFP_ATOMIC); if (ret) err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, ret);}/* int memory deallocation NOTE: no mutex please!*/static void auerswald_int_free (pauerswald_t cp){ if (cp->inturbp) { usb_free_urb(cp->inturbp); cp->inturbp = NULL; } kfree(cp->intbufp); cp->intbufp = NULL;}/* This function is called to activate the interrupt endpoint. This function returns 0 if successful or an error code. NOTE: no mutex please!*/static int auerswald_int_open (pauerswald_t cp){ int ret; struct usb_host_endpoint *ep; int irqsize; dbg ("auerswald_int_open"); ep = cp->usbdev->ep_in[AU_IRQENDP]; if (!ep) { ret = -EFAULT; goto intoend; } irqsize = le16_to_cpu(ep->desc.wMaxPacketSize); cp->irqsize = irqsize; /* allocate the urb and data buffer */ if (!cp->inturbp) { cp->inturbp = usb_alloc_urb (0, GFP_KERNEL); if (!cp->inturbp) { ret = -ENOMEM; goto intoend; } } if (!cp->intbufp) { cp->intbufp = (char *) kmalloc (irqsize, GFP_KERNEL); if (!cp->intbufp) { ret = -ENOMEM; goto intoend; } } /* setup urb */ usb_fill_int_urb (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->desc.bInterval); /* start the urb */ cp->inturbp->status = 0; /* needed! */ ret = usb_submit_urb (cp->inturbp, GFP_KERNEL);intoend: if (ret < 0) { /* activation of interrupt endpoint has failed. Now clean up. */ dbg ("auerswald_int_open: activation of int endpoint failed"); /* deallocate memory */ auerswald_int_free (cp); } return ret;}/* This function is called to deactivate the interrupt endpoint. This function returns 0 if successful or an error code. NOTE: no mutex please!*/static void auerswald_int_release (pauerswald_t cp){ dbg ("auerswald_int_release"); /* stop the int endpoint */ if (cp->inturbp) usb_kill_urb (cp->inturbp); /* deallocate memory */ auerswald_int_free (cp);}/* --------------------------------------------------------------------- *//* Helper functions *//* wake up waiting readers */static void auerchar_disconnect (pauerscon_t scp){ pauerchar_t ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); dbg ("auerchar_disconnect called"); ccp->removed = 1; wake_up (&ccp->readwait);}/* dispatch a read paket to a waiting character device */static void auerchar_ctrlread_dispatch (pauerscon_t scp, pauerbuf_t bp){ unsigned long flags; pauerchar_t ccp; pauerbuf_t newbp = NULL; char * charp; dbg ("auerchar_ctrlread_dispatch called"); ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); /* get a read buffer from character device context */ spin_lock_irqsave (&ccp->bufctl.lock, flags); if (!list_empty (&ccp->bufctl.free_buff_list)) { /* yes: get the entry */ struct list_head *tmp = ccp->bufctl.free_buff_list.next; list_del (tmp); newbp = list_entry (tmp, auerbuf_t, buff_list); } spin_unlock_irqrestore (&ccp->bufctl.lock, flags); if (!newbp) { dbg ("No read buffer available, discard paket!"); return; /* no buffer, no dispatch */ } /* copy information to new buffer element (all buffers have the same length) */ charp = newbp->bufp; newbp->bufp = bp->bufp; bp->bufp = charp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -