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];
00139 static uint8_t udctest_data2[1];
00140 static uint8_t udctest_data3[64];
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
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
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 }