- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/usb/function/usb_function_core.c

Go to the documentation of this file.

    00001
    00045 #include <assert.h>
    00046 #include <byteorder.h>
    00047 #include <debug.h>
    00048 #include <dmapool.h>
    00049 #include <malloc.h>
    00050 #include <string.h>
    00051 #include <util.h>
    00052 #include <usb/function.h>
    00053 #include <usb/function_core.h>
    00054 #include <usb/request.h>
    00055 #include <usb/udc.h>
    00056
    00057 #include <app/config_usb.h>
    00058 #include <app/usb_strings.h>
    00059
    00060 static const struct usb_device_descriptor usb_func_device_desc = {
    00061         .bLength                = sizeof(struct usb_device_descriptor),
    00062         .bDescriptorType        = USB_DT_DEVICE,
    00063         .bcdUSB                 = LE16(0x0200),
    00064         .bDeviceClass           = CONFIG_USB_FUNC_DEVICE_CLASS,
    00065         .bDeviceSubClass        = CONFIG_USB_FUNC_DEVICE_SUBCLASS,
    00066         .bDeviceProtocol        = CONFIG_USB_FUNC_DEVICE_PROTOCOL,
    00067         .bMaxPacketSize0        = 64,
    00068         .idVendor               = LE16(CONFIG_USB_FUNC_VENDOR_ID),
    00069         .idProduct              = LE16(CONFIG_USB_FUNC_PRODUCT_ID),
    00070         .bcdDevice              = LE16((CONFIG_USB_FUNC_MAJOR_VERSION << 8)
    00071                                         | CONFIG_USB_FUNC_MINOR_VERSION),
    00072         .iManufacturer          = USB_STRING_DEV_MANUFACTURER,
    00073         .iProduct               = USB_STRING_DEV_PRODUCT,
    00074         .iSerialNumber          = USB_STRING_DEV_SERIAL,
    00075         .bNumConfigurations     = CONFIG_USB_FUNC_NR_CONFIGURATIONS,
    00076 };
    00077
    00078 #ifdef CONFIG_UDC_HIGH_SPEED
    00079 static const struct usb_device_qualifier_descriptor usb_func_device_qual = {
    00080         .bLength        = sizeof(struct usb_device_qualifier_descriptor),
    00081         .bDescriptorType        = USB_DT_DEVICE_QUALIFIER,
    00082         .bcdUSB                 = LE16(0x0200),
    00083         .bDeviceClass           = CONFIG_USB_FUNC_DEVICE_CLASS,
    00084         .bDeviceSubClass        = CONFIG_USB_FUNC_DEVICE_SUBCLASS,
    00085         .bDeviceProtocol        = CONFIG_USB_FUNC_DEVICE_PROTOCOL,
    00086         .bMaxPacketSize0        = 64,
    00087         .bNumConfigurations     = CONFIG_USB_FUNC_NR_CONFIGURATIONS,
    00088 };
    00089 #endif
    00090
    00091 static struct usb_func_config usb_func_config[CONFIG_USB_FUNC_NR_CONFIGURATIONS];
    00092 static struct usb_request usb_func_control_req;
    00093 static struct buffer usb_func_desc_buf;
    00094
    00095 static struct usb_func_config *usb_func_get_config(unsigned int id)
    00096 {
    00097         return &usb_func_config[id - 1];
    00098 }
    00099
    00100 static struct usb_func_config *usb_func_get_current_config(struct udc *udc)
    00101 {
    00102         if (!udc->config)
    00103                 return NULL;
    00104
    00105         return usb_func_get_config(udc->config->bConfigurationValue);
    00106 }
    00107
    00108 static unsigned int usb_func_nr_interfaces(struct usb_func_config *config)
    00109 {
    00110         return config->desc->bNumInterfaces;
    00111 }
    00112
    00137 void usb_func_add_interface(struct usb_func_config *config,
    00138                 struct usb_func_iface *iface)
    00139 {
    00140         struct usb_func_iface_setting *setting;
    00141         unsigned int    id = iface->setting[0].fs_desc->bInterfaceNumber;
    00142         unsigned int    i;
    00143
    00144         assert(iface->nr_settings > 0);
    00145         assert(id < usb_func_nr_interfaces(config));
    00146         assert(!config->interface[id]);
    00147
    00148         config->interface[id] = iface;
    00149
    00150         for (i = 0; i < iface->nr_settings; i++) {
    00151                 setting = &iface->setting[i];
    00152
    00153                 assert(setting->ops);
    00154                 assert(setting->fs_desc->bInterfaceNumber == id);
    00155
    00156                 if (!setting->hs_desc) {
    00157                         setting->hs_desc = setting->fs_desc;
    00158                         setting->hs_desc_size = setting->fs_desc_size;
    00159                 } else {
    00160                         assert(setting->hs_desc->bInterfaceNumber == id);
    00161                 }
    00162         }
    00163
    00164         dbg_printf("func-core: created interface %u with %zu settings\n",
    00165                         id, iface->nr_settings);
    00166 }
    00167
    00185 struct usb_func_config *usb_func_add_config(
    00186                 struct usb_configuration_descriptor *desc)
    00187 {
    00188         struct usb_func_config  *config;
    00189         unsigned int            id = desc->bConfigurationValue;
    00190         unsigned int            nr_interfaces = desc->bNumInterfaces;
    00191
    00192         config = usb_func_get_config(id);
    00193
    00194         assert(id <= CONFIG_USB_FUNC_NR_CONFIGURATIONS);
    00195         assert(!config->desc);
    00196
    00197         config->desc = desc;
    00198         config->interface = malloc(nr_interfaces * sizeof(*config->interface));
    00199         assert(config->interface);
    00200         memset(config->interface, 0,
    00201                         nr_interfaces * sizeof(*config->interface));
    00202
    00203         dbg_printf("func-core: created configuration %u with %u interfaces\n",
    00204                         id, nr_interfaces);
    00205
    00206         return config;
    00207 }
    00208
    00209 static void usb_func_ctrl_in_done(struct udc *udc, struct usb_request *req)
    00210 {
    00211         dbg_printf("func-core: Control IN request done\n");
    00212
    00213         udc_ep0_expect_status(udc);
    00214 }
    00215
    00216 static void usb_func_string_desc_in_done(struct udc *udc,
    00217                 struct usb_request *req)
    00218 {
    00219         struct buffer   *buf;
    00220
    00221         dbg_printf("func-core: String IN descriptor done\n");
    00222
    00223         buf = usb_req_get_first_buffer(req);
    00224         dma_free(buf->addr.ptr, USB_MAX_DESC_SIZE);
    00225
    00226         udc_ep0_expect_status(udc);
    00227 }
    00228
    00229 static int ascii_to_usb_str(const char *src, le16_t *dest, size_t dest_len)
    00230 {
    00231         size_t  len = 0;
    00232         char    c;
    00233
    00234         while (len < (dest_len - 1)) {
    00235                 c = *src++;
    00236                 if (!c)
    00237                         break;
    00238                 *dest++ = cpu_to_le16(c);
    00239                 len += 2;
    00240         }
    00241
    00242         return len;
    00243 }
    00244
    00245 static int usb_func_prep_config_desc(struct udc *udc,
    00246                 struct usb_func_config *config, struct usb_request *req,
    00247                 enum usb_device_speed speed, size_t max_len)
    00248 {
    00249         const struct usb_interface_descriptor *if_desc;
    00250         struct usb_func_iface           *iface;
    00251         struct usb_func_iface_setting   *setting;
    00252         size_t                          buf_len;
    00253         size_t                          total_len;
    00254         size_t                          len;
    00255         unsigned int                    i, j;
    00256
    00257         total_len = sizeof(*config->desc);
    00258         len = min(max_len, total_len);
    00259         buffer_init_tx(&usb_func_desc_buf, config->desc, len);
    00260         usb_req_add_buffer(req, &usb_func_desc_buf);
    00261
    00262         for (i = 0; i < usb_func_nr_interfaces(config); i++) {
    00263                 iface = config->interface[i];
    00264
    00265                 for (j = 0; j < iface->nr_settings; j++) {
    00266                         setting = &iface->setting[j];
    00267
    00268                         switch (speed) {
    00269                         case USB_SPEED_FULL:
    00270                                 if_desc = setting->fs_desc;
    00271                                 buf_len = setting->fs_desc_size;
    00272                                 break;
    00273                         case USB_SPEED_HIGH:
    00274                                 if_desc = setting->hs_desc;
    00275                                 buf_len = setting->hs_desc_size;
    00276                                 break;
    00277                         default:
    00278                                 return -1;
    00279                         }
    00280
    00281                         total_len += buf_len;
    00282                         buf_len = min(buf_len, max_len - len);
    00283                         if (buf_len == 0)
    00284                                 continue;
    00285
    00286                         buffer_init_tx(&setting->desc_buf, if_desc, buf_len);
    00287                         usb_req_add_buffer(req, &setting->desc_buf);
    00288                         len += buf_len;
    00289                 }
    00290         }
    00291
    00292         config->desc->wTotalLength = cpu_to_le16(total_len);
    00293
    00294         return len;
    00295 }
    00296
    00297 static int usb_func_prep_string_desc(struct udc *udc,
    00298                 struct usb_request *req, uint8_t desc_index,
    00299                 uint16_t langid, uint16_t len)
    00300 {
    00301         struct usb_string_descriptor    *desc;
    00302         struct buffer                   *buf;
    00303         const char                      *str;
    00304         phys_addr_t                     desc_phys;
    00305         int                             str_len;
    00306
    00307         if (desc_index >= USB_NR_STRINGS)
    00308                 return -1;
    00309         if (desc_index != USB_STRING_LANGID && langid != USB_DEV_LANGID)
    00310                 return -1;
    00311
    00312         str = usb_dev_string_table[desc_index];
    00313         if (!str)
    00314                 return -1;
    00315
    00316         desc = dma_alloc(&desc_phys, USB_MAX_DESC_SIZE);
    00317         if (!desc)
    00318                 return -1;
    00319
    00320         desc->bDescriptorType = USB_DT_STRING;
    00321         if (desc_index == USB_STRING_LANGID) {
    00322                 desc->bString[0] = LE16(USB_DEV_LANGID);
    00323                 desc->bLength = 4;
    00324         } else {
    00325                 str_len = ascii_to_usb_str(str, desc->bString,
    00326                                 USB_MAX_DESC_SIZE - 2);
    00327                 desc->bLength = str_len + 2;
    00328         }
    00329
    00330         buf = &usb_func_desc_buf;
    00331         buffer_init_tx_mapped(buf, desc, desc_phys, min(desc->bLength, len));
    00332         usb_req_add_buffer(req, buf);
    00333
    00334         req->req_done = usb_func_string_desc_in_done;
    00335
    00336         return buf->len;
    00337 }
    00338
    00339 int usb_func_get_descriptor(struct udc *udc, uint16_t value,
    00340                 uint16_t index, uint16_t len)
    00341 {
    00342         struct usb_func_config  *config;
    00343         struct usb_request      *req = &usb_func_control_req;
    00344         unsigned int            desc_index;
    00345         unsigned int            desc_type;
    00346         int                     buf_len = -1;
    00347
    00348         dbg_printf("func-core: get descriptor v%04x i%04x l%04x\n",
    00349                         value, index, len);
    00350
    00351         usb_req_init(req);
    00352
    00353         req->req_done = usb_func_ctrl_in_done;
    00354
    00355         desc_type = value >> 8;
    00356         desc_index = value & 0xff;
    00357
    00358         switch (desc_type) {
    00359         case USB_DT_DEVICE:
    00360                 buf_len = min(len, sizeof(usb_func_device_desc));
    00361                 buffer_init_tx(&usb_func_desc_buf, &usb_func_device_desc,
    00362                                 buf_len);
    00363                 usb_req_add_buffer(req, &usb_func_desc_buf);
    00364                 break;
    00365
    00366         case USB_DT_CONFIGURATION:
    00367                 if (desc_index >= CONFIG_USB_FUNC_NR_CONFIGURATIONS)
    00368                         return -1;
    00369
    00370                 config = &usb_func_config[desc_index];
    00371                 config->desc->bDescriptorType = desc_type;
    00372
    00373                 buf_len = usb_func_prep_config_desc(udc, config, req,
    00374                                 udc->speed, len);
    00375                 break;
    00376
    00377 #ifdef CONFIG_UDC_HIGH_SPEED
    00378         case USB_DT_DEVICE_QUALIFIER:
    00379                 buf_len = min(len, sizeof(usb_func_device_qual));
    00380                 buffer_init_tx(&usb_func_desc_buf, &usb_func_device_qual,
    00381                                 buf_len);
    00382                 usb_req_add_buffer(req, &usb_func_desc_buf);
    00383                 break;
    00384
    00385         case USB_DT_OTHER_SPEED_CONFIGURATION:
    00386                 if (desc_index >= CONFIG_USB_FUNC_NR_CONFIGURATIONS)
    00387                         return -1;
    00388
    00389                 config = &usb_func_config[desc_index];
    00390                 config->desc->bDescriptorType = desc_type;
    00391
    00392                 if (udc->speed == USB_SPEED_HIGH)
    00393                         buf_len = usb_func_prep_config_desc(udc, config,
    00394                                         req, USB_SPEED_FULL, len);
    00395                 else
    00396                         buf_len = usb_func_prep_config_desc(udc, config,
    00397                                         req, USB_SPEED_HIGH, len);
    00398                 break;
    00399 #endif
    00400
    00401         case USB_DT_STRING:
    00402                 buf_len = usb_func_prep_string_desc(udc, req,
    00403                                 desc_index, index, len);
    00404                 break;
    00405         }
    00406
    00407         if (buf_len < 0)
    00408                 return -1;
    00409
    00410         if (buf_len < len)
    00411                 set_bit(USB_REQ_SHORT_PKT, &req->flags);
    00412
    00413         udc_ep0_submit_in_req(udc, req);
    00414
    00415         return 0;
    00416 }
    00417
    00418 static int usb_config_enable(struct udc *udc, struct usb_func_config *config)
    00419 {
    00420         unsigned int            nr_interfaces;
    00421         unsigned int            i;
    00422
    00423         nr_interfaces = usb_func_nr_interfaces(config);
    00424         for (i = 0; i < nr_interfaces; i++) {
    00425                 struct usb_func_iface   *iface;
    00426
    00427                 iface = config->interface[i];
    00428                 dbg_printf("func-core: enabling interface %u...\n", i);
    00429                 if (iface->cur_setting->ops->enable(udc, iface))
    00430                         goto fail;
    00431         }
    00432
    00433         return 0;
    00434
    00435 fail:
    00436         dbg_printf("func-core: failed to enable config %u\n",
    00437                         config->desc->bConfigurationValue);
    00438         while (i-- > 0) {
    00439                 struct usb_func_iface   *iface;
    00440
    00441                 iface = config->interface[i];
    00442                 iface->cur_setting->ops->disable(udc, iface);
    00443         }
    00444
    00445         return -1;
    00446 }
    00447
    00448 static void usb_config_disable(struct udc *udc, struct usb_func_config *config)
    00449 {
    00450         unsigned int            nr_interfaces;
    00451         unsigned int            i;
    00452
    00453         if (!config)
    00454                 return;
    00455
    00456         dbg_printf("func-core: disabling config %u\n",
    00457                         config->desc->bConfigurationValue);
    00458
    00459         nr_interfaces = usb_func_nr_interfaces(config);
    00460         for (i = 0; i < nr_interfaces; i++) {
    00461                 struct usb_func_iface   *iface;
    00462
    00463                 iface = config->interface[i];
    00464                 iface->cur_setting->ops->disable(udc, iface);
    00465         }
    00466 }
    00467
    00468 static void usb_config_init_iface_settings(struct usb_func_config *config)
    00469 {
    00470         unsigned int            nr_interfaces;
    00471         unsigned int            i;
    00472
    00473         nr_interfaces = usb_func_nr_interfaces(config);
    00474         for (i = 0; i < nr_interfaces; i++) {
    00475                 struct usb_func_iface   *iface;
    00476
    00477                 iface = config->interface[i];
    00478                 iface->cur_setting = &iface->setting[0];
    00479         }
    00480 }
    00481
    00482 int usb_func_set_configuration(struct udc *udc, uint16_t config_id)
    00483 {
    00484         struct usb_func_config  *old;
    00485         struct usb_func_config  *new;
    00486
    00487         dbg_printf("func-core: set configuration %u\n", config_id);
    00488
    00489         if (config_id > CONFIG_USB_FUNC_NR_CONFIGURATIONS)
    00490                 return -1;
    00491
    00492         /* Disable the old configuration, if any */
    00493         old = usb_func_get_current_config(udc);
    00494         udc->config = NULL;
    00495         if (old)
    00496                 usb_config_disable(udc, old);
    00497
    00498         if (config_id == 0)
    00499                 return 0;
    00500
    00501         new = usb_func_get_config(config_id);
    00502         usb_config_init_iface_settings(new);
    00503         udc->config = new->desc;
    00504         if (usb_config_enable(udc, new)) {
    00505                 dbg_printf("Failed to set new configuration\n");
    00506                 if (old) {
    00507                         udc->config = old->desc;
    00508                         if (usb_config_enable(udc, old))
    00509                                 udc->config = NULL;
    00510                 } else {
    00511                         udc->config = NULL;
    00512                 }
    00513                 return -1;
    00514         }
    00515
    00516         return 0;
    00517 }
    00518
    00519 int usb_func_get_interface(struct udc *udc, uint16_t index)
    00520 {
    00521         struct usb_func_config          *config;
    00522         struct usb_func_iface           *iface;
    00523         struct usb_func_iface_setting   *setting;
    00524
    00525         dbg_printf("func-core: get interface %u\n", index);
    00526
    00527         config = usb_func_get_current_config(udc);
    00528         if (!config || index >= usb_func_nr_interfaces(config))
    00529                 return -1;
    00530
    00531         iface = config->interface[index];
    00532         setting = iface->cur_setting;
    00533
    00534         udc_ep0_write_sync(udc, &setting->fs_desc->bAlternateSetting, 1);
    00535         udc_ep0_expect_status(udc);
    00536
    00537         return 0;
    00538 }
    00539
    00540 int usb_func_set_interface(struct udc *udc, uint16_t index, uint16_t altsetting)
    00541 {
    00542         struct usb_func_config          *config;
    00543         struct usb_func_iface           *iface;
    00544         struct usb_func_iface_setting   *old;
    00545         struct usb_func_iface_setting   *new;
    00546
    00547         dbg_printf("func-core: set interface %u altsetting %u\n",
    00548                         index, altsetting);
    00549
    00550         config = usb_func_get_current_config(udc);
    00551         if (!config || index >= usb_func_nr_interfaces(config))
    00552                 return -1;
    00553
    00554         iface = config->interface[index];
    00555         if (altsetting >= iface->nr_settings)
    00556                 return -1;
    00557
    00558         old = iface->cur_setting;
    00559         new = &iface->setting[altsetting];
    00560
    00561         /*
    00562          * Switch interface setting. If this fails, we attempt to
    00563          * switch back to the old setting. If _that_ fails, there's
    00564          * not much we can do, as we're already going to report STALL
    00565          * back to the host.
    00566          */
    00567         old->ops->disable(udc, iface);
    00568         iface->cur_setting = new;
    00569         if (new->ops->enable(udc, iface)) {
    00570                 iface->cur_setting = old;
    00571                 old->ops->enable(udc, iface);
    00572                 return -1;
    00573         }
    00574
    00575         return 0;
    00576 }
    00577
    00578 void usb_func_reset(struct udc *udc)
    00579 {
    00580         dbg_printf("func-core: reset, speed=%u\n", udc->speed);
    00581
    00582         if (udc->config)
    00583                 usb_func_set_configuration(udc, 0);
    00584 }
    00585
    00586 int usb_func_process_setup_request(struct udc *udc, struct usb_setup_req *req)
    00587 {
    00588         struct usb_func_config          *config;
    00589         struct usb_func_iface           *iface;
    00590         struct usb_func_iface_setting   *setting;
    00591         uint16_t                        index = le16_to_cpu(req->wIndex);
    00592
    00593         if (usb_req_recipient(req) != USB_RECIP_INTERFACE) {
    00594                 dbg_printf("func-core: bad request (bmRequestType: %u)\n",
    00595                                 req->bmRequestType);
    00596                 return -1;
    00597         }
    00598
    00599         config = usb_func_get_current_config(udc);
    00600         if (!config || index >= usb_func_nr_interfaces(config))
    00601                 return -1;
    00602
    00603         iface = config->interface[index];
    00604         setting = iface->cur_setting;
    00605
    00606         return setting->ops->setup(udc, iface, req);
    00607 }