?? dummy_audio.c
字號:
.bNumConfigurations = 2,};struct usb_cs_as_general_descriptor { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bTerminalLink; __u8 bDelay; __u16 wFormatTag;} __attribute__ ((packed));struct usb_cs_as_format_descriptor { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bFormatType; __u8 bNrChannels; __u8 bSubframeSize; __u8 bBitResolution; __u8 bSamfreqType; __u8 tLowerSamFreq[3]; __u8 tUpperSamFreq[3];} __attribute__ ((packed));static const struct usb_interface_descriptorz_audio_control_if_desc = { .bLength = sizeof z_audio_control_if_desc, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 0x1, .bInterfaceProtocol = 0, .iInterface = 0,};static const struct usb_interface_descriptorz_audio_if_desc = { .bLength = sizeof z_audio_if_desc, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 0x2, .bInterfaceProtocol = 0, .iInterface = 0,};static const struct usb_interface_descriptorz_audio_if_desc2 = { .bLength = sizeof z_audio_if_desc, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 0x2, .bInterfaceProtocol = 0, .iInterface = 0,};static const struct usb_cs_as_general_descriptorz_audio_cs_as_if_desc = { .bLength = 7, .bDescriptorType = 0x24, .bDescriptorSubType = 0x01, .bTerminalLink = 0x01, .bDelay = 0x0, .wFormatTag = __constant_cpu_to_le16 (0x0001)};static const struct usb_cs_as_format_descriptor z_audio_cs_as_format_desc = { .bLength = 0xe, .bDescriptorType = 0x24, .bDescriptorSubType = 2, .bFormatType = 1, .bNrChannels = 1, .bSubframeSize = 1, .bBitResolution = 8, .bSamfreqType = 0, .tLowerSamFreq = {0x7e, 0x13, 0x00}, .tUpperSamFreq = {0xe2, 0xd6, 0x00},};static const struct usb_endpoint_descriptor z_iso_ep = { .bLength = 0x09, .bDescriptorType = 0x05, .bEndpointAddress = 0x04, .bmAttributes = 0x09, .wMaxPacketSize = 0x0038, .bInterval = 0x01, .bRefresh = 0x00, .bSynchAddress = 0x00, };static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};// 9 bytesstatic char z_ac_interface_header_desc[] = { 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };// 12 bytesstatic char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00};// 13 bytesstatic char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00};// 9 bytesstatic char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00};static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00};static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00, 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00, 0x00};static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00, 0x00};static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00, 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00, 0x00};static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00, 0x00};static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00, 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00, 0x00};static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00, 0x00};static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00, 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00, 0x00};static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00, 0x00};static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00, 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00, 0x00};static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};static const struct usb_descriptor_header *z_function [] = { (struct usb_descriptor_header *) &z_audio_control_if_desc, (struct usb_descriptor_header *) &z_ac_interface_header_desc, (struct usb_descriptor_header *) &z_0, (struct usb_descriptor_header *) &z_1, (struct usb_descriptor_header *) &z_2, (struct usb_descriptor_header *) &z_audio_if_desc, (struct usb_descriptor_header *) &z_audio_if_desc2, (struct usb_descriptor_header *) &z_audio_cs_as_if_desc, (struct usb_descriptor_header *) &z_audio_cs_as_format_desc, (struct usb_descriptor_header *) &z_iso_ep, (struct usb_descriptor_header *) &z_iso_ep2, (struct usb_descriptor_header *) &za_0, (struct usb_descriptor_header *) &za_1, (struct usb_descriptor_header *) &za_2, (struct usb_descriptor_header *) &za_3, (struct usb_descriptor_header *) &za_4, (struct usb_descriptor_header *) &za_5, (struct usb_descriptor_header *) &za_6, (struct usb_descriptor_header *) &za_7, (struct usb_descriptor_header *) &za_8, (struct usb_descriptor_header *) &za_9, (struct usb_descriptor_header *) &za_10, (struct usb_descriptor_header *) &za_11, (struct usb_descriptor_header *) &za_12, (struct usb_descriptor_header *) &za_13, (struct usb_descriptor_header *) &za_14, (struct usb_descriptor_header *) &za_15, (struct usb_descriptor_header *) &za_16, (struct usb_descriptor_header *) &za_17, (struct usb_descriptor_header *) &za_18, (struct usb_descriptor_header *) &za_19, (struct usb_descriptor_header *) &za_20, (struct usb_descriptor_header *) &za_21, (struct usb_descriptor_header *) &za_22, (struct usb_descriptor_header *) &za_23, (struct usb_descriptor_header *) &za_24, NULL,};/* maxpacket and other transfer characteristics vary by speed. */#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))#else/* if there's no high speed support, maxpacket doesn't change. */#define ep_desc(g,hs,fs) fs#endif /* !CONFIG_USB_GADGET_DUALSPEED */static char manufacturer [40];//static char serial [40];static char serial [] = "Ser 00 em";/* static strings, in UTF-8 */static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, { STRING_LOOPBACK, loopback, }, { STRING_SOURCE_SINK, source_sink, }, { } /* end of list */};static struct usb_gadget_strings stringtab = { .language = 0x0409, /* en-us */ .strings = strings,};/* * config descriptors are also handcrafted. these must agree with code * that sets configurations, and with code managing interfaces and their * altsettings. other complexity may come from: * * - high speed support, including "other speed config" rules * - multiple configurations * - interfaces with alternate settings * - embedded class or vendor-specific descriptors * * this handles high speed, and has a second config that could as easily * have been an alternate interface setting (on most hardware). * * NOTE: to demonstrate (and test) more USB capabilities, this driver * should include an altsetting to test interrupt transfers, including * high bandwidth modes at high speed. (Maybe work like Intel's test * device?) */static intconfig_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index){ int len; const struct usb_descriptor_header **function; function = z_function; len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len;}/*-------------------------------------------------------------------------*/static struct usb_request *alloc_ep_req (struct usb_ep *ep, unsigned length){ struct usb_request *req; req = usb_ep_alloc_request (ep, GFP_ATOMIC); if (req) { req->length = length; req->buf = usb_ep_alloc_buffer (ep, length, &req->dma, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; } } return req;}static void free_ep_req (struct usb_ep *ep, struct usb_request *req){ if (req->buf) usb_ep_free_buffer (ep, req->buf, req->dma, req->length); usb_ep_free_request (ep, req);}/*-------------------------------------------------------------------------*//* optionally require specific source/sink data patterns */static intcheck_read_data ( struct zero_dev *dev, struct usb_ep *ep, struct usb_request *req){ unsigned i; u8 *buf = req->buf; for (i = 0; i < req->actual; i++, buf++) { switch (pattern) { /* all-zeroes has no synchronization issues */ case 0: if (*buf == 0) continue; break; /* mod63 stays in sync with short-terminated transfers, * or otherwise when host and gadget agree on how large * each usb transfer request should be. resync is done * with set_interface or set_config. */ case 1: if (*buf == (u8)(i % 63)) continue; break; } ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf); usb_ep_set_halt (ep); return -EINVAL; } return 0;}/*-------------------------------------------------------------------------*/static void zero_reset_config (struct zero_dev *dev){ if (dev->config == 0) return; DBG (dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); dev->out_ep = NULL; } dev->config = 0; del_timer (&dev->resume);}#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))static void zero_isoc_complete (struct usb_ep *ep, struct usb_request *req){ struct zero_dev *dev = ep->driver_data; int status = req->status; int i, j; switch (status) { case 0: /* normal completion? */ //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual); for (i=0, j=rbuf_start; i<req->actual; i++) { //printk ("%02x ", ((__u8*)req->buf)[i]); rbuf[j] = ((__u8*)req->buf)[i]; j++; if (j >= RBUF_LEN) j=0; } rbuf_start = j; //printk ("\n\n"); if (rbuf_len < RBUF_LEN) { rbuf_len += req->actual; if (rbuf_len > RBUF_LEN) { rbuf_len = RBUF_LEN; } } break; /* this endpoint is normally active while we're configured */ case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) check_read_data (dev, ep, req); free_ep_req (ep, req); return; case -EOVERFLOW: /* buffer overrun on read means that * we didn't provide a big enough * buffer. */ default:#if 1 DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length);#endif case -EREMOTEIO: /* short read */ break; } status = usb_ep_queue (ep, req, GFP_ATOMIC); if (status) { ERROR (dev, "kill %s: resubmit %d bytes --> %d\n", ep->name, req->length, status); usb_ep_set_halt (ep); /* FIXME recover later ... somehow */ }}static struct usb_request *zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags){ struct usb_request *req; int status; req = alloc_ep_req (ep, 512); if (!req) return NULL; req->complete = zero_isoc_complete; status = usb_ep_queue (ep, req, gfp_flags); if (status) { struct zero_dev *dev = ep->driver_data; ERROR (dev, "start %s --> %d\n", ep->name, status); free_ep_req (ep, req); req = NULL; } return req;}/* change our operational config. this code must agree with the code * that returns config descriptors, and altsetting code. * * it's also responsible for power management interactions. some * configurations might not work with our current power sources. * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */static intzero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags){ int result = 0; struct usb_gadget *gadget = dev->gadget; const struct usb_endpoint_descriptor *d; struct usb_ep *ep; if (number == dev->config) return 0; zero_reset_config (dev); gadget_for_each_ep (ep, gadget) { if (strcmp (ep->name, "ep4") == 0) { d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6 result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; dev->in_ep = ep; if (zero_start_isoc_ep (ep, gfp_flags) != 0) { dev->in_ep = ep; continue; } usb_ep_disable (ep); result = -EIO; } } } dev->config = number; return result;}/*-------------------------------------------------------------------------*/static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req){ if (req->status || req->actual != req->length) DBG ((struct zero_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n",
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -