Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhid/usbhid.c

    r1cbb4b7 rfec47d4  
    4242#include <usb/classes/hidreq.h>
    4343#include <errno.h>
    44 #include <str_error.h>
    4544
    4645#include "usbhid.h"
     
    4847#include "kbd/kbddev.h"
    4948#include "generic/hiddev.h"
    50 #include "mouse/mousedev.h"
    51 #include "subdrivers.h"
    52 
    53 /*----------------------------------------------------------------------------*/
     49
     50/*----------------------------------------------------------------------------*/
     51
     52/** Mouse polling endpoint description for boot protocol class. */
     53static usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
     54        .transfer_type = USB_TRANSFER_INTERRUPT,
     55        .direction = USB_DIRECTION_IN,
     56        .interface_class = USB_CLASS_HID,
     57        .interface_subclass = USB_HID_SUBCLASS_BOOT,
     58        .interface_protocol = USB_HID_PROTOCOL_MOUSE,
     59        .flags = 0
     60};
    5461
    5562/* Array of endpoints expected on the device, NULL terminated. */
     
    6168};
    6269
    63 static const int USB_HID_MAX_SUBDRIVERS = 10;
    64 
    65 /*----------------------------------------------------------------------------*/
    66 
    67 static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
    68 {
    69         assert(hid_dev->subdriver_count == 0);
    70        
    71         hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
    72             sizeof(usb_hid_subdriver_t));
    73         if (hid_dev->subdrivers == NULL) {
    74                 return ENOMEM;
    75         }
    76        
    77         // set the init callback
    78         hid_dev->subdrivers[0].init = usb_kbd_init;
    79        
    80         // set the polling callback
    81         hid_dev->subdrivers[0].poll = usb_kbd_polling_callback;
    82        
    83         // set the polling ended callback
    84         hid_dev->subdrivers[0].poll_end = NULL;
    85        
    86         // set the deinit callback
    87         hid_dev->subdrivers[0].deinit = usb_kbd_deinit;
    88        
    89         // set subdriver count
    90         hid_dev->subdriver_count = 1;
    91        
    92         return EOK;
    93 }
    94 
    95 /*----------------------------------------------------------------------------*/
    96 
    97 static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
    98 {
    99         assert(hid_dev->subdriver_count == 0);
    100        
    101         hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
    102             sizeof(usb_hid_subdriver_t));
    103         if (hid_dev->subdrivers == NULL) {
    104                 return ENOMEM;
    105         }
    106        
    107         // set the init callback
    108         hid_dev->subdrivers[0].init = usb_mouse_init;
    109        
    110         // set the polling callback
    111         hid_dev->subdrivers[0].poll = usb_mouse_polling_callback;
    112        
    113         // set the polling ended callback
    114         hid_dev->subdrivers[0].poll_end = NULL;
    115        
    116         // set the deinit callback
    117         hid_dev->subdrivers[0].deinit = usb_mouse_deinit;
    118        
    119         // set subdriver count
    120         hid_dev->subdriver_count = 1;
    121        
    122         return EOK;
    123 }
    124 
    125 /*----------------------------------------------------------------------------*/
    126 
    127 static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
    128 {
    129         assert(hid_dev->subdriver_count == 0);
    130        
    131         hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
    132             sizeof(usb_hid_subdriver_t));
    133         if (hid_dev->subdrivers == NULL) {
    134                 return ENOMEM;
    135         }
    136        
    137         // set the init callback
    138         hid_dev->subdrivers[0].init = NULL;
    139        
    140         // set the polling callback
    141         hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
    142        
    143         // set the polling ended callback
    144         hid_dev->subdrivers[0].poll_end = NULL;
    145        
    146         // set the deinit callback
    147         hid_dev->subdrivers[0].deinit = NULL;
    148        
    149         // set subdriver count
    150         hid_dev->subdriver_count = 1;
    151        
    152         return EOK;
    153 }
    154 
    155 /*----------------------------------------------------------------------------*/
    156 
    157 static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev,
    158     const usb_hid_subdriver_mapping_t *mapping)
    159 {
    160         return false;
    161 }
    162 
    163 /*----------------------------------------------------------------------------*/
    164 
    165 static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
    166     const usb_hid_subdriver_usage_t *path, int path_size, int compare)
    167 {
    168         assert(hid_dev != NULL);
    169         assert(path != NULL);
    170        
    171         usb_hid_report_path_t *usage_path = usb_hid_report_path();
    172         if (usage_path == NULL) {
    173                 usb_log_debug("Failed to create usage path.\n");
    174                 return false;
    175         }
    176         int i;
    177         for (i = 0; i < path_size; ++i) {
    178                 if (usb_hid_report_path_append_item(usage_path,
    179                     path[i].usage_page, path[i].usage) != EOK) {
    180                         usb_log_debug("Failed to append to usage path.\n");
    181                         usb_hid_report_path_free(usage_path);
    182                         return false;
    183                 }
    184         }
    185        
    186         assert(hid_dev->parser != NULL);
    187        
    188         usb_log_debug("Compare flags: %d\n", compare);
    189         size_t size = usb_hid_report_input_length(hid_dev->parser, usage_path,
    190             compare);
    191         usb_log_debug("Size of the input report: %d\n", size);
    192        
    193         usb_hid_report_path_free(usage_path);
    194        
    195         return (size > 0);
    196 }
    197 
    198 /*----------------------------------------------------------------------------*/
    199 
    200 static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
    201     const usb_hid_subdriver_t **subdrivers, int count)
    202 {
    203         int i;
    204        
    205         if (count <= 0) {
    206                 hid_dev->subdriver_count = 0;
    207                 hid_dev->subdrivers = NULL;
    208                 return EOK;
    209         }
    210        
    211         hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(count *
    212             sizeof(usb_hid_subdriver_t));
    213         if (hid_dev->subdrivers == NULL) {
    214                 return ENOMEM;
    215         }
    216        
    217         for (i = 0; i < count; ++i) {
    218                 hid_dev->subdrivers[i].init = subdrivers[i]->init;
    219                 hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit;
    220                 hid_dev->subdrivers[i].poll = subdrivers[i]->poll;
    221                 hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end;
    222         }
    223        
    224         hid_dev->subdriver_count = count;
    225        
    226         return EOK;
    227 }
    228 
    229 /*----------------------------------------------------------------------------*/
    230 
    231 static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
    232 {
    233         const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
    234        
    235         int i = 0, count = 0;
    236         const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i];
    237        
    238         while (count < USB_HID_MAX_SUBDRIVERS &&
    239             (mapping->usage_path != NULL
    240             || mapping->vendor_id != NULL
    241             || mapping->product_id != NULL)) {
    242                 // check the vendor & product ID
    243                 if (mapping->vendor_id != NULL && mapping->product_id == NULL) {
    244                         usb_log_warning("Missing Product ID for Vendor ID %s\n",
    245                             mapping->vendor_id);
    246                         return EINVAL;
    247                 }
    248                 if (mapping->product_id != NULL && mapping->vendor_id == NULL) {
    249                         usb_log_warning("Missing Vendor ID for Product ID %s\n",
    250                             mapping->product_id);
    251                         return EINVAL;
    252                 }
    253                
    254                 if (mapping->vendor_id != NULL) {
    255                         assert(mapping->product_id != NULL);
    256                         usb_log_debug("Comparing device against vendor ID %s"
    257                             " and product ID %s.\n", mapping->vendor_id,
    258                             mapping->product_id);
    259                         if (usb_hid_ids_match(hid_dev, mapping)) {
    260                                 usb_log_debug("Matched.\n");
    261                                 subdrivers[count++] = &mapping->subdriver;
    262                                 // skip the checking of usage path
    263                                 goto next;
    264                         }
    265                 }
    266                
    267                 if (mapping->usage_path != NULL) {
    268                         usb_log_debug("Comparing device against usage path.\n");
    269                         if (usb_hid_path_matches(hid_dev,
    270                             mapping->usage_path, mapping->path_size,
    271                             mapping->compare)) {
    272                                 subdrivers[count++] = &mapping->subdriver;
    273                         } else {
    274                                 usb_log_debug("Not matched.\n");
    275                         }
    276                 }
    277         next:
    278                 mapping = &usb_hid_subdrivers[++i];
    279         }
    280        
    281         // we have all subdrivers determined, save them into the hid device
    282         return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
    283 }
    284 
    285 /*----------------------------------------------------------------------------*/
    286 
    287 static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
    288 {
    289         int rc = EOK;
    290        
    291         if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
    292                 usb_log_debug("Found keyboard endpoint.\n");
    293                 // save the pipe index
    294                 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
    295         } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
    296                 usb_log_debug("Found mouse endpoint.\n");
    297                 // save the pipe index
    298                 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
    299         } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
    300                 usb_log_debug("Found generic HID endpoint.\n");
    301                 // save the pipe index
    302                 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
    303         } else {
    304                 usb_log_error("None of supported endpoints found - probably"
    305                     " not a supported device.\n");
    306                 rc = ENOTSUP;
    307         }
    308        
    309         return rc;
    310 }
     70static const char *HID_MOUSE_FUN_NAME = "mouse";
     71static const char *HID_MOUSE_CLASS_NAME = "mouse";
    31172
    31273/*----------------------------------------------------------------------------*/
     
    33091        }
    33192       
    332         hid_dev->poll_pipe_index = -1;
    333        
    33493        return hid_dev;
    33594}
     
    33796/*----------------------------------------------------------------------------*/
    33897
     98static bool usb_dummy_polling_callback(usb_device_t *dev, uint8_t *buffer,
     99     size_t buffer_size, void *arg)
     100{
     101        usb_log_debug("Dummy polling callback.\n");
     102        return false;
     103}
     104
     105/*----------------------------------------------------------------------------*/
     106
     107static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
     108{
     109        if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
     110                usb_log_debug("Found keyboard endpoint.\n");
     111               
     112                // save the pipe index and device type
     113                hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
     114                hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;
     115               
     116                // set the polling callback
     117                hid_dev->poll_callback = usb_kbd_polling_callback;
     118
     119        } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
     120                usb_log_debug("Found mouse endpoint.\n");
     121               
     122                // save the pipe index and device type
     123                hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
     124                hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
     125               
     126                // set the polling callback
     127                hid_dev->poll_callback = usb_dummy_polling_callback;
     128               
     129        } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
     130                usb_log_debug("Found generic HID endpoint.\n");
     131               
     132                // save the pipe index and device type
     133                hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
     134                hid_dev->device_type = USB_HID_PROTOCOL_NONE;
     135               
     136                // set the polling callback
     137                hid_dev->poll_callback = usb_hid_polling_callback;
     138               
     139        } else {
     140                usb_log_warning("None of supported endpoints found - probably"
     141                    " not a supported device.\n");
     142                return ENOTSUP;
     143        }
     144       
     145        return EOK;
     146}
     147
     148/*----------------------------------------------------------------------------*/
     149
     150static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
     151{
     152        /* Initialize the report parser. */
     153        int rc = usb_hid_parser_init(hid_dev->parser);
     154        if (rc != EOK) {
     155                usb_log_error("Failed to initialize report parser.\n");
     156                return rc;
     157        }
     158       
     159        /* Get the report descriptor and parse it. */
     160        rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
     161            hid_dev->parser);
     162       
     163        if (rc != EOK) {
     164                usb_log_warning("Could not process report descriptor.\n");
     165               
     166                if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {
     167                        usb_log_warning("Falling back to boot protocol.\n");
     168                       
     169                        rc = usb_kbd_set_boot_protocol(hid_dev);
     170                       
     171                } else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
     172                        usb_log_warning("No boot protocol for mouse yet.\n");
     173                        rc = ENOTSUP;
     174                }
     175        }
     176       
     177        return rc;
     178}
     179
     180/*----------------------------------------------------------------------------*/
     181
    339182int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
    340183{
    341         int rc, i;
     184        int rc;
    342185       
    343186        usb_log_debug("Initializing HID structure...\n");
     
    360203        rc = usb_hid_check_pipes(hid_dev, dev);
    361204        if (rc != EOK) {
    362                 usb_hid_free(&hid_dev);
    363205                return rc;
    364206        }
    365207       
    366         /* Initialize the report parser. */
    367         rc = usb_hid_parser_init(hid_dev->parser);
     208        rc = usb_hid_init_parser(hid_dev);
    368209        if (rc != EOK) {
    369                 usb_log_error("Failed to initialize report parser.\n");
    370                 usb_hid_free(&hid_dev);
     210                usb_log_error("Failed to initialize HID parser.\n");
    371211                return rc;
    372212        }
    373213       
    374         /* Get the report descriptor and parse it. */
    375         rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
    376             hid_dev->parser);
    377        
    378         bool fallback = false;
    379        
    380         if (rc == EOK) {
    381                 // try to find subdrivers that may want to handle this device
    382                 rc = usb_hid_find_subdrivers(hid_dev);
    383                 if (rc != EOK || hid_dev->subdriver_count == 0) {
    384                         // try to fall back to the boot protocol if available
    385                         usb_log_info("No subdrivers found to handle this"
    386                             " device.\n");
    387                         fallback = true;
     214        switch (hid_dev->device_type) {
     215        case USB_HID_PROTOCOL_KEYBOARD:
     216                // initialize the keyboard structure
     217                rc = usb_kbd_init(hid_dev);
     218                if (rc != EOK) {
     219                        usb_log_warning("Failed to initialize KBD structure."
     220                            "\n");
    388221                }
    389         } else {
    390                 usb_log_error("Failed to parse Report descriptor.\n");
    391                 // try to fall back to the boot protocol if available
    392                 fallback = true;
    393         }
    394        
    395         // TODO: remove the mouse hack
    396         if (hid_dev->poll_pipe_index == USB_HID_MOUSE_POLL_EP_NO ||
    397             fallback) {
    398                 // fall back to boot protocol
    399                 switch (hid_dev->poll_pipe_index) {
    400                 case USB_HID_KBD_POLL_EP_NO:
    401                         usb_log_info("Falling back to kbd boot protocol.\n");
    402                         rc = usb_kbd_set_boot_protocol(hid_dev);
    403                         if (rc == EOK) {
    404                                 rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
    405                         }
    406                         break;
    407                 case USB_HID_MOUSE_POLL_EP_NO:
    408                         usb_log_info("Falling back to mouse boot protocol.\n");
    409                         rc = usb_mouse_set_boot_protocol(hid_dev);
    410                         if (rc == EOK) {
    411                                 rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
    412                         }
    413                         break;
    414                 default:
    415                         assert(hid_dev->poll_pipe_index
    416                             == USB_HID_GENERIC_POLL_EP_NO);
    417                        
    418                         /* TODO: this has no meaning if the report descriptor
    419                                  is not parsed */
    420                         usb_log_info("Falling back to generic HID driver.\n");
    421                         rc = usb_hid_set_generic_hid_subdriver(hid_dev);
    422                 }
    423         }
    424        
    425         if (rc != EOK) {
    426                 usb_log_error("No subdriver for handling this device could be"
    427                     " initialized: %s.\n", str_error(rc));
    428                 usb_hid_free(&hid_dev);
    429         } else {
    430                 bool ok = false;
    431                
    432                 usb_log_debug("Subdriver count: %d\n",
    433                     hid_dev->subdriver_count);
    434                
    435                 for (i = 0; i < hid_dev->subdriver_count; ++i) {
    436                         if (hid_dev->subdrivers[i].init != NULL) {
    437                                 usb_log_debug("Initializing subdriver %d.\n",i);
    438                                 rc = hid_dev->subdrivers[i].init(hid_dev);
    439                                 if (rc != EOK) {
    440                                         usb_log_warning("Failed to initialize"
    441                                             " HID subdriver structure.\n");
    442                                 } else {
    443                                         // at least one subdriver initialized
    444                                         ok = true;
    445                                 }
    446                         } else {
    447                                 ok = true;
    448                         }
    449                 }
    450                
    451                 rc = (ok) ? EOK : -1;   // what error to report
     222                break;
     223        case USB_HID_PROTOCOL_MOUSE:
     224                break;
     225        default:
     226//              usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
     227//                  hid_dev->usb_dev->interface_no, 0);
     228                break;
    452229        }
    453230       
    454231        return rc;
    455 }
    456 
    457 /*----------------------------------------------------------------------------*/
    458 
    459 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
    460     size_t buffer_size, void *arg)
    461 {
    462         int i;
    463        
    464         if (dev == NULL || arg == NULL || buffer == NULL) {
    465                 usb_log_error("Missing arguments to polling callback.\n");
    466                 return false;
    467         }
    468        
    469         usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
    470        
    471         bool cont = false;
    472        
    473         // continue if at least one of the subdrivers want to continue
    474         for (i = 0; i < hid_dev->subdriver_count; ++i) {
    475                 if (hid_dev->subdrivers[i].poll != NULL
    476                     && hid_dev->subdrivers[i].poll(hid_dev, buffer,
    477                     buffer_size)) {
    478                         cont = true;
    479                 }
    480         }
    481        
    482         return cont;
    483232}
    484233
     
    488237     void *arg)
    489238{
    490         int i;
    491        
    492239        if (dev == NULL || arg == NULL) {
    493240                return;
     
    496243        usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
    497244       
    498         for (i = 0; i < hid_dev->subdriver_count; ++i) {
    499                 if (hid_dev->subdrivers[i].poll_end != NULL) {
    500                         hid_dev->subdrivers[i].poll_end(hid_dev, reason);
    501                 }
    502         }
    503        
    504245        usb_hid_free(&hid_dev);
    505246}
     
    507248/*----------------------------------------------------------------------------*/
    508249
    509 const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev)
    510 {
    511         switch (hid_dev->poll_pipe_index) {
    512         case USB_HID_KBD_POLL_EP_NO:
     250const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
     251{
     252        switch (device_type) {
     253        case USB_HID_PROTOCOL_KEYBOARD:
    513254                return HID_KBD_FUN_NAME;
    514255                break;
    515         case USB_HID_MOUSE_POLL_EP_NO:
     256        case USB_HID_PROTOCOL_MOUSE:
    516257                return HID_MOUSE_FUN_NAME;
    517258                break;
     
    523264/*----------------------------------------------------------------------------*/
    524265
    525 const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev)
    526 {
    527         // this means that only boot protocol keyboards will be connected
    528         // to the console; there is probably no better way to do this
    529        
    530         switch (hid_dev->poll_pipe_index) {
    531         case USB_HID_KBD_POLL_EP_NO:
     266const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
     267{
     268        switch (device_type) {
     269        case USB_HID_PROTOCOL_KEYBOARD:
    532270                return HID_KBD_CLASS_NAME;
    533271                break;
    534         case USB_HID_MOUSE_POLL_EP_NO:
     272        case USB_HID_PROTOCOL_MOUSE:
    535273                return HID_MOUSE_CLASS_NAME;
    536274                break;
     
    544282void usb_hid_free(usb_hid_dev_t **hid_dev)
    545283{
    546         int i;
    547        
    548284        if (hid_dev == NULL || *hid_dev == NULL) {
    549285                return;
    550286        }
    551287       
    552         assert((*hid_dev)->subdrivers != NULL
    553             || (*hid_dev)->subdriver_count == 0);
    554        
    555         for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
    556                 if ((*hid_dev)->subdrivers[i].deinit != NULL) {
    557                         (*hid_dev)->subdrivers[i].deinit(*hid_dev);
    558                 }
    559         }
    560        
    561         // free the subdrivers info
    562         if ((*hid_dev)->subdrivers != NULL) {
    563                 free((*hid_dev)->subdrivers);
     288        switch ((*hid_dev)->device_type) {
     289        case USB_HID_PROTOCOL_KEYBOARD:
     290                usb_kbd_deinit(*hid_dev);
     291                break;
     292        case USB_HID_PROTOCOL_MOUSE:
     293                break;
     294        default:
     295                break;
    564296        }
    565297
Note: See TracChangeset for help on using the changeset viewer.