00001
00042 #include <assert.h>
00043 #include <byteorder.h>
00044 #include <debug.h>
00045 #include <dmapool.h>
00046 #include <interrupt.h>
00047 #include <malloc.h>
00048 #include <status_codes.h>
00049 #include <string.h>
00050 #include <util.h>
00051 #include <usb/dev.h>
00052 #include <usb/dev_mux.h>
00053 #include <usb/request.h>
00054 #include <usb/udc.h>
00055
00056 #include <app/usb.h>
00057
00165
00166
00167
00190 #ifndef USB_STRING_DEV_MANUFACTURER
00191 # define USB_STRING_DEV_MANUFACTURER 0
00192 #endif
00193 #ifndef USB_STRING_DEV_PRODUCT
00194 # define USB_STRING_DEV_PRODUCT 0
00195 #endif
00196 #ifndef USB_STRING_DEV_SERIAL
00197 # define USB_STRING_DEV_SERIAL 0
00198 #endif
00199
00201
00202 static const struct usb_device_descriptor udm_device_desc = {
00203 .bLength = sizeof(struct usb_device_descriptor),
00204 .bDescriptorType = USB_DT_DEVICE,
00205 .bcdUSB = LE16(0x0200),
00206 .bDeviceClass = APP_USB_DEVICE_CLASS,
00207 .bDeviceSubClass = APP_USB_DEVICE_SUBCLASS,
00208 .bDeviceProtocol = APP_USB_DEVICE_PROTOCOL,
00209 .bMaxPacketSize0 = APP_UDC_MAXPACKETSIZE0,
00210 .idVendor = LE16(APP_USB_DEVICE_VENDOR_ID),
00211 .idProduct = LE16(APP_USB_DEVICE_PRODUCT_ID),
00212 .bcdDevice = LE16((APP_USB_DEVICE_MAJOR_VERSION << 8)
00213 | APP_USB_DEVICE_MINOR_VERSION),
00214 .iManufacturer = USB_STRING_DEV_MANUFACTURER,
00215 .iProduct = USB_STRING_DEV_PRODUCT,
00216 .iSerialNumber = USB_STRING_DEV_SERIAL,
00217 .bNumConfigurations = APP_USB_DEVICE_NR_CONFIGS,
00218 };
00219
00220 #ifdef CONFIG_UDC_HIGH_SPEED
00221 static const struct usb_device_qualifier_descriptor udm_device_qual = {
00222 .bLength = sizeof(struct usb_device_qualifier_descriptor),
00223 .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
00224 .bcdUSB = LE16(0x0200),
00225 .bDeviceClass = APP_USB_DEVICE_CLASS,
00226 .bDeviceSubClass = APP_USB_DEVICE_SUBCLASS,
00227 .bDeviceProtocol = APP_USB_DEVICE_PROTOCOL,
00228 .bMaxPacketSize0 = APP_UDC_MAXPACKETSIZE0,
00229 .bNumConfigurations = APP_USB_DEVICE_NR_CONFIGS,
00230 };
00231 #endif
00232
00233 static const struct usb_configuration_descriptor udm_config_desc_template = {
00234 .bLength = sizeof(struct usb_configuration_descriptor),
00235 .bDescriptorType = USB_DT_CONFIGURATION,
00236 .bmAttributes = USB_CONFIG_ATTR_MUST_SET
00237 | USB_CONFIG_ATTR_SELF_POWERED,
00238 .bMaxPower = USB_CONFIG_MAX_POWER(4),
00239 };
00240
00241 static struct udm_config *udm_config[APP_USB_DEVICE_NR_CONFIGS];
00242 static struct usb_request udm_control_req;
00243 static struct buffer udm_desc_buf;
00244
00245 static struct udm_config *udm_get_config(unsigned int id)
00246 {
00247 return udm_config[id - 1];
00248 }
00249
00250 static struct udm_config *udm_get_current_config(struct udc *udc)
00251 {
00252 if (!udc->config)
00253 return NULL;
00254
00255 return udm_get_config(udc->config);
00256 }
00257
00258 static unsigned int udm_nr_interfaces(struct udm_config *config)
00259 {
00260 return config->desc.bNumInterfaces;
00261 }
00262
00282
00307 void udm_config_add_interface(struct udm_config *config,
00308 struct udm_interface *iface)
00309 {
00310 unsigned int id = iface->iface_number;
00311
00312 assert(id < udm_nr_interfaces(config));
00313 assert(!config->interface[id]);
00314
00315 config->interface[id] = iface;
00316
00317 dbg_info("udm: config %u: new interface %u\n",
00318 config->desc.bConfigurationValue, id);
00319 }
00320
00341 struct udm_config *udm_create_config(uint8_t value,
00342 uint8_t nr_interfaces)
00343 {
00344 struct udm_config *config;
00345
00346 assert(value > 0 && value <= APP_USB_DEVICE_NR_CONFIGS);
00347 assert(!udm_get_config(value));
00348
00349 config = zalloc(sizeof(struct udm_config)
00350 + nr_interfaces * sizeof(config->interface[0]));
00351 if (unlikely(!config))
00352 return NULL;
00353
00354 memcpy(&config->desc, &udm_config_desc_template, sizeof(config->desc));
00355 config->desc.bConfigurationValue = value;
00356 config->desc.bNumInterfaces = nr_interfaces;
00357
00358 udm_config[value - 1] = config;
00359
00360 return config;
00361 }
00362
00369 void udm_config_set_max_power(struct udm_config *config,
00370 unsigned int milliamps)
00371 {
00372 assert(USB_CONFIG_MAX_POWER(milliamps) < 256);
00373 config->desc.bMaxPower = USB_CONFIG_MAX_POWER(milliamps);
00374 }
00375
00381 void udm_config_set_self_powered(struct udm_config *config)
00382 {
00383 irqflags_t iflags;
00384
00385
00386 iflags = cpu_irq_save();
00387 config->desc.bmAttributes |= USB_CONFIG_ATTR_SELF_POWERED;
00388 cpu_irq_restore(iflags);
00389 }
00390
00396 void udm_config_set_bus_powered(struct udm_config *config)
00397 {
00398 irqflags_t iflags;
00399
00400
00401 iflags = cpu_irq_save();
00402 config->desc.bmAttributes &= ~USB_CONFIG_ATTR_SELF_POWERED;
00403 cpu_irq_restore(iflags);
00404 }
00405
00407
00408 static void udm_ctrl_in_done(struct udc *udc, struct usb_request *req)
00409 {
00410 dbg_verbose("udm: Control IN request done\n");
00411
00412 udc_ep0_expect_status(udc);
00413 }
00414
00415 static void udm_config_desc_sent(struct udc *udc, struct usb_request *req)
00416 {
00417 struct udm_config *config = req->context;
00418 unsigned int i;
00419
00420
00421 slist_pop_head_node(&req->buf_list);
00422
00423
00424 for (i = 0; i < udm_nr_interfaces(config); i++) {
00425 struct udm_interface *iface;
00426
00427 if (slist_is_empty(&req->buf_list))
00428 break;
00429
00430 iface = config->interface[i];
00431 iface->free_descriptor(iface, req);
00432 }
00433
00434 udm_ctrl_in_done(udc, req);
00435 }
00436
00437 static void udm_string_desc_in_done(struct udc *udc,
00438 struct usb_request *req)
00439 {
00440 struct buffer *buf;
00441
00442 buf = slist_pop_head(&req->buf_list, struct buffer, node);
00443 buffer_dma_free(buf, USB_MAX_DESC_LEN);
00444
00445 udm_ctrl_in_done(udc, req);
00446 }
00447
00462
00475 int udm_submit_utf16le_string_desc(struct udc *udc, struct usb_request *req,
00476 const le16_t *str, uint16_t max_len)
00477 {
00478 struct usb_string_descriptor *desc;
00479 struct buffer *buf;
00480 const le16_t *src;
00481 le16_t *dst;
00482 uint16_t len;
00483
00484 if (max_len < offsetof(struct usb_string_descriptor, bString))
00485 return ERR_INVALID_ARG;
00486
00487 buf = buffer_dma_alloc(USB_MAX_DESC_LEN);
00488 if (!buf)
00489 return ERR_NO_MEMORY;
00490
00491 desc = buf->addr.ptr;
00492 desc->bDescriptorType = USB_DT_STRING;
00493
00494 src = str;
00495 dst = desc->bString;
00496 for (len = offsetof(struct usb_string_descriptor, bString);
00497 len < max_len; len += 2) {
00498 le16_t c = *src++;
00499
00500 if (c == LE16(0))
00501 break;
00502 *dst++ = c;
00503 }
00504
00505 desc->bLength = len;
00506 buffer_resize(buf, len);
00507 usb_req_add_buffer(req, buf);
00508 req->req_done = udm_string_desc_in_done;
00509
00510 return len;
00511 }
00512
00525 int udm_submit_ascii_string_desc(struct udc *udc, struct usb_request *req,
00526 const char *str, uint16_t max_len)
00527 {
00528 struct usb_string_descriptor *desc;
00529 struct buffer *buf;
00530 const char *src;
00531 le16_t *dst;
00532 uint16_t len;
00533
00534 if (max_len < offsetof(struct usb_string_descriptor, bString))
00535 return ERR_INVALID_ARG;
00536
00537 buf = buffer_dma_alloc(USB_MAX_DESC_LEN);
00538 if (!buf)
00539 return ERR_NO_MEMORY;
00540
00541 desc = buf->addr.ptr;
00542 desc->bDescriptorType = USB_DT_STRING;
00543
00544 src = str;
00545 dst = desc->bString;
00546 for (len = offsetof(struct usb_string_descriptor, bString);
00547 len < max_len; len += 2) {
00548 char c = *src++;
00549
00550 if (c == '\0')
00551 break;
00552 *dst++ = cpu_to_le16(c);
00553 }
00554
00555 desc->bLength = len;
00556 buffer_resize(buf, len);
00557 usb_req_add_buffer(req, buf);
00558 req->req_done = udm_string_desc_in_done;
00559
00560 return len;
00561 }
00562
00586 #ifndef HAVE_APP_USB_GET_STRING_DESCRIPTOR
00587 static int app_usb_get_string_descriptor(struct udc *udc,
00588 struct usb_request *req, uint8_t index,
00589 uint16_t langid, uint16_t len)
00590 {
00591
00592 return -1;
00593 }
00594 #endif
00595
00597
00598 static int udm_prep_config_desc(struct udm_config *config,
00599 struct usb_request *req,
00600 enum usb_device_speed speed, size_t max_len)
00601 {
00602 struct udm_interface *iface;
00603 struct buffer *buffer;
00604 size_t buf_len;
00605 size_t total_len;
00606 size_t len;
00607 unsigned int i;
00608
00609 total_len = sizeof(config->desc);
00610 len = min_u(max_len, total_len);
00611
00612 buffer = &udm_desc_buf;
00613 buffer_init_tx(buffer, &config->desc, len);
00614
00615 req->req_done = udm_config_desc_sent;
00616 req->context = config;
00617 usb_req_add_buffer(req, buffer);
00618
00619 for (i = 0; i < udm_nr_interfaces(config); i++) {
00620 size_t remaining_len;
00621
00622 remaining_len = max_len - len;
00623 iface = config->interface[i];
00624 buf_len = iface->get_iface_descriptor(iface, req, speed,
00625 remaining_len);
00626 total_len += buf_len;
00627 len += min_u(buf_len, remaining_len);
00628 }
00629
00630 config->desc.wTotalLength = cpu_to_le16(total_len);
00631
00632 return len;
00633 }
00634
00635 static int udm_enable_config(struct udc *udc, struct udm_config *config)
00636 {
00637 unsigned int nr_interfaces;
00638 unsigned int i;
00639
00640 dbg_verbose("udm: enabling configuration %u...\n",
00641 config->desc.bConfigurationValue);
00642
00643 nr_interfaces = udm_nr_interfaces(config);
00644 for (i = 0; i < nr_interfaces; i++) {
00645 struct udm_interface *iface;
00646
00647 iface = config->interface[i];
00648 dbg_verbose(" - enabling interface %u...\n", i);
00649 if (iface->enable(udc, iface, 0))
00650 goto fail;
00651 }
00652
00653 return 0;
00654
00655 fail:
00656 dbg_error("udm: failed to enable configuration %u, interface %u\n",
00657 config->desc.bConfigurationValue, i);
00658 while (i-- > 0) {
00659 struct udm_interface *iface;
00660
00661 iface = config->interface[i];
00662 iface->disable(udc, iface);
00663 }
00664
00665 return -1;
00666 }
00667
00668 static void udm_disable_config(struct udc *udc, struct udm_config *config)
00669 {
00670 unsigned int nr_interfaces;
00671 unsigned int i;
00672
00673 if (!config)
00674 return;
00675
00676 dbg_verbose("udm: disabling configuration %u\n",
00677 config->desc.bConfigurationValue);
00678
00679 nr_interfaces = udm_nr_interfaces(config);
00680 for (i = 0; i < nr_interfaces; i++) {
00681 struct udm_interface *iface;
00682
00683 iface = config->interface[i];
00684 dbg_verbose(" - disabling interface %u...\n", i);
00685 iface->disable(udc, iface);
00686 }
00687 }
00688
00689 #if 0
00690 static int udm_prep_string_desc(struct udc *udc,
00691 struct usb_request *req, uint8_t desc_index,
00692 uint16_t langid, uint16_t len)
00693 {
00694 struct usb_string_descriptor *desc;
00695 struct buffer *buf;
00696 const char *str;
00697 phys_addr_t desc_phys;
00698 int str_len;
00699
00700 if (desc_index >= USB_NR_STRINGS)
00701 return -1;
00702 if (desc_index != USB_STRING_LANGID && langid != USB_DEV_LANGID)
00703 return -1;
00704
00705 str = usb_dev_string_table[desc_index];
00706 if (!str)
00707 return -1;
00708
00709 desc = dma_alloc(&desc_phys, USB_MAX_DESC_SIZE);
00710 if (!desc)
00711 return -1;
00712
00713 desc->bDescriptorType = USB_DT_STRING;
00714 if (desc_index == USB_STRING_LANGID) {
00715 desc->bString[0] = LE16(USB_DEV_LANGID);
00716 desc->bLength = 4;
00717 } else {
00718 str_len = ascii_to_usb_str(str, desc->bString,
00719 USB_MAX_DESC_SIZE - 2);
00720 desc->bLength = str_len + 2;
00721 }
00722
00723 buf = &udm_desc_buf;
00724 buffer_init_tx_mapped(buf, desc, desc_phys, min_u(desc->bLength, len));
00725 usb_req_add_buffer(req, buf);
00726
00727 req->req_done = udm_string_desc_in_done;
00728
00729 return buf->len;
00730 }
00731 #endif
00732
00734
00740 status_t usb_dev_get_descriptor(struct udc *udc, uint16_t value,
00741 uint16_t index, uint16_t len)
00742 {
00743 struct udm_config *config;
00744 struct usb_request *req;
00745 unsigned int desc_index;
00746 unsigned int desc_type;
00747 int buf_len = -1;
00748
00749 dbg_verbose("udm: get descriptor v%04x i%04x l%04x\n",
00750 value, index, len);
00751
00752 req = &udm_control_req;
00753 usb_req_init(req);
00754 req->req_done = udm_ctrl_in_done;
00755
00756 desc_type = value >> 8;
00757 desc_index = value & 0xff;
00758
00759 switch (desc_type) {
00760 case USB_DT_DEVICE:
00761 buf_len = min_u(len, sizeof(udm_device_desc));
00762 buffer_init_tx(&udm_desc_buf, &udm_device_desc,
00763 buf_len);
00764 usb_req_add_buffer(req, &udm_desc_buf);
00765 break;
00766
00767 case USB_DT_CONFIGURATION:
00768 if (desc_index >= APP_USB_DEVICE_NR_CONFIGS)
00769 return -1;
00770
00771 config = udm_config[desc_index];
00772 config->desc.bDescriptorType = desc_type;
00773 buf_len = udm_prep_config_desc(config, req,
00774 udc->speed, len);
00775 break;
00776
00777 #ifdef CONFIG_UDC_HIGH_SPEED
00778 case USB_DT_DEVICE_QUALIFIER:
00779 buf_len = min_u(len, sizeof(udm_device_qual));
00780 buffer_init_tx(&udm_desc_buf, &udm_device_qual,
00781 buf_len);
00782 usb_req_add_buffer(req, &udm_desc_buf);
00783 break;
00784
00785 case USB_DT_OTHER_SPEED_CONFIGURATION:
00786 if (desc_index >= APP_USB_DEVICE_NR_CONFIGS)
00787 return -1;
00788
00789 config = udm_config[desc_index];
00790 config->desc.bDescriptorType = desc_type;
00791
00792 if (udc->speed == USB_SPEED_HIGH)
00793 buf_len = udm_prep_config_desc(config, req,
00794 USB_SPEED_FULL, len);
00795 else
00796 buf_len = udm_prep_config_desc(config, req,
00797 USB_SPEED_HIGH, len);
00798 break;
00799 #endif
00800
00801 case USB_DT_STRING:
00802 buf_len = app_usb_get_string_descriptor(udc, req,
00803 desc_index, index, len);
00804 break;
00805 }
00806
00807 if (buf_len < 0)
00808 return buf_len;
00809
00810 if (buf_len < len)
00811 set_bit(USB_REQ_SHORT_PKT, &req->flags);
00812
00813 udc_ep0_submit_in_req(udc, req);
00814
00815 return STATUS_OK;
00816 }
00817
00818 status_t usb_dev_set_configuration(struct udc *udc, uint16_t config_id)
00819 {
00820 struct udm_config *old;
00821 struct udm_config *new;
00822
00823 dbg_verbose("udm: set configuration %u\n", config_id);
00824
00825 if (config_id > APP_USB_DEVICE_NR_CONFIGS)
00826 return -1;
00827
00828
00829 old = udm_get_current_config(udc);
00830 udc->config = 0;
00831 if (old)
00832 udm_disable_config(udc, old);
00833
00834 if (config_id == 0)
00835 return STATUS_OK;
00836
00837 new = udm_get_config(config_id);
00838 udc->config = config_id;
00839 if (udm_enable_config(udc, new)) {
00840 udc->config = 0;
00841 return -1;
00842 }
00843
00844 return STATUS_OK;
00845 }
00846
00847 status_t usb_dev_get_interface(struct udc *udc, uint16_t index)
00848 {
00849 struct udm_config *config;
00850 struct udm_interface *iface;
00851
00852 dbg_verbose("udm: get interface %u\n", index);
00853
00854 config = udm_get_current_config(udc);
00855 if (!config || index >= udm_nr_interfaces(config))
00856 return -1;
00857
00858 iface = config->interface[index];
00859 build_assert(sizeof(iface->cur_setting) == 1);
00860
00861 udc_ep0_write_sync(udc, &iface->cur_setting, 1);
00862 udc_ep0_expect_status(udc);
00863
00864 return 0;
00865 }
00866
00867 status_t usb_dev_set_interface(struct udc *udc, uint16_t index,
00868 uint16_t altsetting)
00869 {
00870 struct udm_config *config;
00871 struct udm_interface *iface;
00872 int ret;
00873
00874 dbg_verbose("udm: set interface %u altsetting %u\n",
00875 index, altsetting);
00876
00877 config = udm_get_current_config(udc);
00878 if (!config || index >= udm_nr_interfaces(config))
00879 return -1;
00880
00881 iface = config->interface[index];
00882 ret = iface->enable(udc, iface, altsetting);
00883 if (likely(!ret))
00884 iface->cur_setting = altsetting;
00885
00886 return ret;
00887 }
00888
00889 void usb_dev_reset(struct udc *udc)
00890 {
00891 dbg_verbose("udm: reset, speed=%u\n", udc->speed);
00892
00893 if (udc->config)
00894 usb_dev_set_configuration(udc, 0);
00895 }
00896
00897 status_t usb_dev_process_setup_request(struct udc *udc,
00898 struct usb_setup_req *req)
00899 {
00900 struct udm_config *config;
00901 struct udm_interface *iface;
00902 uint16_t index = le16_to_cpu(req->wIndex);
00903
00904 if (usb_setup_recipient(req) != USB_RECIP_INTERFACE) {
00905 dbg_warning("udm: bad request (bmRequestType: %u)\n",
00906 req->bmRequestType);
00907 return -1;
00908 }
00909
00910 config = udm_get_current_config(udc);
00911 if (!config || index >= udm_nr_interfaces(config)) {
00912 dbg_warning("udm: bad interface %u\n", index);
00913 return -1;
00914 }
00915
00916 iface = config->interface[index];
00917 if (!iface->setup)
00918 return -1;
00919
00920 return iface->setup(udc, iface, req);
00921 }
00922