- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/usb/function/udctest.c

Go to the documentation of this file.

    00001
    00044 #include <byteorder.h>
    00045 #include <debug.h>
    00046 #include <dma.h>
    00047 #include <malloc.h>
    00048 #include <string.h>
    00049 #include <usb/function_core.h>
    00050 #include <usb/request.h>
    00051 #include <usb/udc.h>
    00052 #include <usb/usb_protocol.h>
    00053 #include <usb/udctest.h>
    00054
    00055 #include <app/config_usb.h>
    00056
    00057 #define UDCTEST_NR_BULK_BUFFERS 2
    00058 #define UDCTEST_BUF_SIZE        1024
    00059 #define UDCTEST_FS_BULK_EP_SIZE 64
    00060
    00061 struct udctest_bulk_iface_block {
    00062         struct usb_interface_descriptor iface;
    00063         struct usb_endpoint_descriptor in_ep;
    00064         struct usb_endpoint_descriptor out_ep;
    00065 };
    00066
    00067 struct udctest {
    00068         struct usb_func_iface   iface;
    00069         usb_ep_id_t             bulk_in_ep;
    00070         usb_ep_id_t             bulk_out_ep;
    00071         struct usb_request      bulk_req[UDCTEST_NR_BULK_BUFFERS];
    00072 };
    00073
    00074 static inline struct udctest *udctest_of(struct usb_func_iface *iface)
    00075 {
    00076         return container_of(iface, struct udctest, iface);
    00077 }
    00078
    00079 static const struct udctest_bulk_iface_block udctest_fs_bulk_iface = {
    00080         .iface = {
    00081                 .bLength = sizeof(struct usb_interface_descriptor),
    00082                 .bDescriptorType        = USB_DT_INTERFACE,
    00083                 .bInterfaceNumber       = CONFIG_UDCTEST_INTERFACE_ID,
    00084                 .bAlternateSetting      = 0,
    00085                 .bNumEndpoints          = 2,
    00086                 .bInterfaceClass        = 0xff,
    00087                 .bInterfaceSubClass     = 0x00,
    00088                 .bInterfaceProtocol     = 0xff,
    00089         },
    00090         .in_ep = {
    00091                 .bLength = sizeof(struct usb_endpoint_descriptor),
    00092                 .bDescriptorType        = USB_DT_ENDPOINT,
    00093                 .bEndpointAddress       = USB_DIR_IN
    00094                         | CONFIG_UDCTEST_BULK_IN_EP,
    00095                 .bmAttributes           = USB_EP_XFER_BULK,
    00096                 .wMaxPacketSize         = LE16(UDCTEST_FS_BULK_EP_SIZE),
    00097         },
    00098         .out_ep = {
    00099                 .bLength = sizeof(struct usb_endpoint_descriptor),
    00100                 .bDescriptorType        = USB_DT_ENDPOINT,
    00101                 .bEndpointAddress       = USB_DIR_OUT
    00102                         | CONFIG_UDCTEST_BULK_OUT_EP,
    00103                 .bmAttributes           = USB_EP_XFER_BULK,
    00104                 .wMaxPacketSize         = LE16(UDCTEST_FS_BULK_EP_SIZE),
    00105         },
    00106 };
    00107
    00108 static const struct udctest_bulk_iface_block udctest_hs_bulk_iface = {
    00109         .iface = {
    00110                 .bLength = sizeof(struct usb_interface_descriptor),
    00111                 .bDescriptorType        = USB_DT_INTERFACE,
    00112                 .bInterfaceNumber       = CONFIG_UDCTEST_INTERFACE_ID,
    00113                 .bAlternateSetting      = 0,
    00114                 .bNumEndpoints          = 2,
    00115                 .bInterfaceClass        = 0xff,
    00116                 .bInterfaceSubClass     = 0x00,
    00117                 .bInterfaceProtocol     = 0xff,
    00118         },
    00119         .in_ep = {
    00120                 .bLength = sizeof(struct usb_endpoint_descriptor),
    00121                 .bDescriptorType        = USB_DT_ENDPOINT,
    00122                 .bEndpointAddress       = USB_DIR_IN
    00123                         | CONFIG_UDCTEST_BULK_IN_EP,
    00124                 .bmAttributes           = USB_EP_XFER_BULK,
    00125                 .wMaxPacketSize         = LE16(512),
    00126         },
    00127         .out_ep = {
    00128                 .bLength = sizeof(struct usb_endpoint_descriptor),
    00129                 .bDescriptorType        = USB_DT_ENDPOINT,
    00130                 .bEndpointAddress       = USB_DIR_OUT
    00131                         | CONFIG_UDCTEST_BULK_OUT_EP,
    00132                 .bmAttributes           = USB_EP_XFER_BULK,
    00133                 .wMaxPacketSize         = LE16(512),
    00134         },
    00135 };
    00136
    00137 static struct udctest_descriptor udctest_desc;
    00138 static uint8_t udctest_data1[62];       /* unaligned start, aligned end */
    00139 static uint8_t udctest_data2[1];        /* aligned start, unaligned end */
    00140 static uint8_t udctest_data3[64];       /* unaligned start, unaligned end */
    00141
    00142 static void udctest_in_req_done(struct udc *udc, struct usb_request *req);
    00143
    00144 static void udctest_out_req_done(struct udc *udc, struct usb_request *req)
    00145 {
    00146         struct udctest  *test = req->context;
    00147         struct buffer   *buf;
    00148
    00149         dbg_printf("udctest: OUT req done: %zu bytes status %d\n",
    00150                         req->bytes_xfered, req->status);
    00151
    00152         /* Don't submit any buffers when the endpoint is unavailable */
    00153         if (!test->bulk_in_ep)
    00154                 return;
    00155
    00156         buf = usb_req_get_first_buffer(req);
    00157         buf->len = req->bytes_xfered;
    00158         req->bytes_xfered = 0;
    00159         req->req_done = udctest_in_req_done;
    00160         udc_ep_submit_in_req(udc, test->bulk_in_ep, req);
    00161 }
    00162
    00163 static void udctest_in_req_done(struct udc *udc, struct usb_request *req)
    00164 {
    00165         struct udctest  *test = req->context;
    00166         struct buffer   *buf;
    00167
    00168         dbg_printf("udctest: IN req done: %zu bytes status %d\n",
    00169                         req->bytes_xfered, req->status);
    00170
    00171         /* Don't submit any buffers when the endpoint is unavailable */
    00172         if (!test->bulk_out_ep)
    00173                 return;
    00174
    00175         buf = usb_req_get_first_buffer(req);
    00176         buf->len = UDCTEST_BUF_SIZE;
    00177         req->bytes_xfered = 0;
    00178         req->req_done = udctest_out_req_done;
    00179         udc_ep_submit_out_req(udc, test->bulk_out_ep, req);
    00180 }
    00181
    00182 static void udctest_ctrl_in_done(struct udc *udc, struct usb_request *req)
    00183 {
    00184         dbg_printf("udctest: Control IN request done\n");
    00185
    00186         usb_req_free_all(req);
    00187         udc_ep0_expect_status(udc);
    00188 }
    00189
    00190 static int udctest_iface_enable(struct udc *udc, struct usb_func_iface *iface)
    00191 {
    00192         const struct udctest_bulk_iface_block *desc;
    00193         struct udctest          *test = udctest_of(iface);
    00194         struct usb_request      *req;
    00195         struct buffer           *buf;
    00196         unsigned int            i = 0;
    00197
    00198         switch (udc->speed) {
    00199         case USB_SPEED_FULL:
    00200                 desc = &udctest_fs_bulk_iface;
    00201                 break;
    00202         case USB_SPEED_HIGH:
    00203                 desc = &udctest_hs_bulk_iface;
    00204                 break;
    00205         default:
    00206                 return -1;
    00207         }
    00208
    00209         test->bulk_in_ep = udc_ep_create(udc, &desc->in_ep,
    00210                         CONFIG_UDCTEST_NR_BANKS);
    00211         test->bulk_out_ep = udc_ep_create(udc, &desc->out_ep,
    00212                         CONFIG_UDCTEST_NR_BANKS);
    00213         if (test->bulk_in_ep < 0 || test->bulk_out_ep < 0)
    00214                 goto fail;
    00215
    00216         for (i = 0; i < UDCTEST_NR_BULK_BUFFERS; i++) {
    00217                 void            *data;
    00218
    00219                 data = malloc(UDCTEST_BUF_SIZE);
    00220                 if (!data)
    00221                         goto fail;
    00222
    00223                 req = &test->bulk_req[i];
    00224                 usb_req_init(req);
    00225                 buf = buffer_alloc();
    00226                 if (!buf) {
    00227                         free(data);
    00228                         goto fail;
    00229                 }
    00230                 buffer_init_tx(buf, data, UDCTEST_BUF_SIZE);
    00231                 usb_req_add_buffer(req, buf);
    00232                 req->req_done = udctest_out_req_done;
    00233                 req->context = test;
    00234         }
    00235
    00236         for (i = 0; i < UDCTEST_NR_BULK_BUFFERS; i++)
    00237                 udc_ep_submit_out_req(udc, test->bulk_out_ep,
    00238                                 &test->bulk_req[i]);
    00239
    00240         return 0;
    00241
    00242 fail:
    00243         dbg_printf("udctest: failed to enable interface\n");
    00244
    00245         while (i--) {
    00246                 req = &test->bulk_req[i];
    00247                 buf = usb_req_get_first_buffer(req);
    00248                 free(buf->addr.ptr);
    00249                 buffer_free(buf);
    00250         }
    00251
    00252         if (test->bulk_in_ep > 0) {
    00253                 usb_ep_id_t ep = test->bulk_in_ep;
    00254                 test->bulk_in_ep = 0;
    00255                 udc_ep_destroy(udc, ep);
    00256         }
    00257         if (test->bulk_out_ep > 0) {
    00258                 usb_ep_id_t ep = test->bulk_out_ep;
    00259                 test->bulk_out_ep = 0;
    00260                 udc_ep_destroy(udc, ep);
    00261         }
    00262
    00263         return -1;
    00264 }
    00265
    00266 static void udctest_iface_disable(struct udc *udc, struct usb_func_iface *iface)
    00267 {
    00268         struct udctest          *test = udctest_of(iface);
    00269         struct usb_request      *req;
    00270         struct buffer           *buf;
    00271         usb_ep_id_t             in, out;
    00272         unsigned int            i;
    00273
    00274         in = test->bulk_in_ep;
    00275         test->bulk_in_ep = 0;
    00276         out = test->bulk_out_ep;
    00277         test->bulk_out_ep = 0;
    00278
    00279         if (in > 0)
    00280                 udc_ep_destroy(udc, in);
    00281         if (out > 0)
    00282                 udc_ep_destroy(udc, out);
    00283
    00284         for (i = 0; i < UDCTEST_NR_BULK_BUFFERS; i++) {
    00285                 req = &test->bulk_req[i];
    00286                 buf = usb_req_get_first_buffer(req);
    00287                 free(buf->addr.ptr);
    00288                 buffer_free(buf);
    00289         }
    00290 }
    00291
    00292 static struct usb_request *usbtest_prep_test_desc(struct udctest *test,
    00293                 struct udc *udc, uint16_t value, uint16_t index, uint16_t len)
    00294 {
    00295         static const uint8_t dt_to_len[] = {
    00296                 0, 2, 63, 64, 65, 127, 128, 129,
    00297         };
    00298         struct usb_request      *req;
    00299         struct buffer           *buf;
    00300         unsigned int            desc_len;
    00301         unsigned int            buf_len;
    00302         unsigned int            total_len = 0;
    00303         uint8_t                 dt = value >> 8;
    00304
    00305         req = usb_req_alloc();
    00306         assert(req);
    00307
    00308         dbg_printf("udctest: get test desc %u\n", dt);
    00309
    00310         if (len < sizeof(udctest_desc) || dt == 0
    00311                         || dt >= ARRAY_LEN(dt_to_len))
    00312                 return NULL;
    00313
    00314         desc_len = dt_to_len[dt];
    00315         udctest_desc.bLength = desc_len;
    00316         udctest_desc.bDescriptorType = dt;
    00317
    00318         desc_len = min(len, desc_len);
    00319
    00320         buf = buffer_alloc();
    00321         assert(buf);
    00322         buffer_init_tx(buf, &udctest_desc, sizeof(udctest_desc));
    00323         usb_req_add_buffer(req, buf);
    00324         total_len += sizeof(udctest_desc);
    00325         if (total_len == desc_len)
    00326                 goto done;
    00327
    00328         buf_len = min(desc_len - total_len, sizeof(udctest_data1));
    00329         buf = buffer_alloc();
    00330         assert(buf);
    00331         buffer_init_tx(buf, udctest_data1, buf_len);
    00332         usb_req_add_buffer(req, buf);
    00333         total_len += buf_len;
    00334         if (total_len == desc_len)
    00335                 goto done;
    00336
    00337         buf_len = min(desc_len - total_len, sizeof(udctest_data2));
    00338         buf = buffer_alloc();
    00339         assert(buf);
    00340         buffer_init_tx(buf, udctest_data2, buf_len);
    00341         usb_req_add_buffer(req, buf);
    00342         total_len += buf_len;
    00343         if (total_len == desc_len)
    00344                 goto done;
    00345
    00346         buf_len = min(desc_len - total_len, sizeof(udctest_data3));
    00347         buf = buffer_alloc();
    00348         assert(buf);
    00349         buffer_init_tx(buf, udctest_data3, buf_len);
    00350         usb_req_add_buffer(req, buf);
    00351         total_len += buf_len;
    00352
    00353 done:
    00354         if (total_len < len)
    00355                 set_bit(USB_REQ_SHORT_PKT, &req->flags);
    00356
    00357         req->req_done = udctest_ctrl_in_done;
    00358         req->context = udc;
    00359
    00360         return req;
    00361 }
    00362
    00363 static int udctest_iface_setup(struct udc *udc, struct usb_func_iface *iface,
    00364                 struct usb_setup_req *setup)
    00365 {
    00366         struct udctest          *test = udctest_of(iface);
    00367         struct usb_request      *req;
    00368         uint16_t                value = le16_to_cpu(setup->wValue);
    00369         uint16_t                index = le16_to_cpu(setup->wIndex);
    00370         uint16_t                len = le16_to_cpu(setup->wLength);
    00371
    00372         if (usb_req_type(setup) != USB_REQTYPE_VENDOR)
    00373                 return -1;
    00374
    00375         switch (setup->bRequest) {
    00376         case USBTEST_REQ_INIT_DESC:
    00377                 if (len || usb_req_is_in(setup))
    00378                         return -1;
    00379
    00380                 memset(udctest_data1, value & 0xff, sizeof(udctest_data1));
    00381                 memset(udctest_data2, value & 0xff, sizeof(udctest_data2));
    00382                 memset(udctest_data3, value & 0xff, sizeof(udctest_data3));
    00383
    00384                 dbg_printf("udctest: INIT_DESC done, sending status\n");
    00385
    00386                 udc_ep0_send_status(udc);
    00387                 break;
    00388
    00389         case USBTEST_REQ_GET_DESC:
    00390                 if (usb_req_is_out(setup))
    00391                         return -1;
    00392
    00393                 req = usbtest_prep_test_desc(test, udc, value, index, len);
    00394                 if (!req)
    00395                         return -1;
    00396
    00397                 dbg_printf("udctest: GET_DESC done, sending it\n");
    00398
    00399                 udc_ep0_submit_in_req(udc, req);
    00400                 break;
    00401
    00402         default:
    00403                 return -1;
    00404         }
    00405
    00406         return 0;
    00407 }
    00408
    00409 static const struct usb_func_iface_ops udctest_ops = {
    00410         .enable         = udctest_iface_enable,
    00411         .disable        = udctest_iface_disable,
    00412         .setup          = udctest_iface_setup,
    00413 };
    00414
    00415 static struct udctest   udctest = {
    00416         .iface.nr_settings      = 1,
    00417         .iface.setting[0] = {
    00418                 .ops            = &udctest_ops,
    00419                 .fs_desc        = &udctest_fs_bulk_iface.iface,
    00420                 .hs_desc        = &udctest_hs_bulk_iface.iface,
    00421                 .fs_desc_size   = sizeof(udctest_fs_bulk_iface),
    00422                 .hs_desc_size   = sizeof(udctest_hs_bulk_iface),
    00423         },
    00424 };
    00425
    00426 struct usb_func_iface *udctest_init(void)
    00427 {
    00428         return &udctest.iface;
    00429 }