Changeset 26d46d2 in mainline for uspace/drv/usbhid/usbhid.c


Ignore:
Timestamp:
2011-04-10T22:33:27Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1a46610, fd153d3
Parents:
c6fe469 (diff), c7bdfa7 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Development branch changes

File:
1 edited

Legend:

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

    rc6fe469 r26d46d2  
    4242#include <usb/classes/hidreq.h>
    4343#include <errno.h>
     44#include <str_error.h>
    4445
    4546#include "usbhid.h"
     
    4748#include "kbd/kbddev.h"
    4849#include "generic/hiddev.h"
    49 
    50 /*----------------------------------------------------------------------------*/
    51 
    52 /** Mouse polling endpoint description for boot protocol class. */
    53 static 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 };
     50#include "mouse/mousedev.h"
     51#include "subdrivers.h"
     52
     53/*----------------------------------------------------------------------------*/
    6154
    6255/* Array of endpoints expected on the device, NULL terminated. */
     
    6861};
    6962
    70 static const char *HID_MOUSE_FUN_NAME = "mouse";
    71 static const char *HID_MOUSE_CLASS_NAME = "mouse";
     63static const int USB_HID_MAX_SUBDRIVERS = 10;
     64
     65/*----------------------------------------------------------------------------*/
     66
     67static 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
     97static 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
     127static 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
     157static 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
     165static 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
     200static 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
     231static 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
     287static 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}
    72311
    73312/*----------------------------------------------------------------------------*/
     
    91330        }
    92331       
     332        hid_dev->poll_pipe_index = -1;
     333       
    93334        return hid_dev;
    94335}
     
    96337/*----------------------------------------------------------------------------*/
    97338
    98 static 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 
    107 static 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 
    150 static 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 
    182339int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
    183340{
    184         int rc;
     341        int rc, i;
    185342       
    186343        usb_log_debug("Initializing HID structure...\n");
     
    203360        rc = usb_hid_check_pipes(hid_dev, dev);
    204361        if (rc != EOK) {
     362                usb_hid_free(&hid_dev);
    205363                return rc;
    206364        }
    207365       
    208         rc = usb_hid_init_parser(hid_dev);
     366        /* Initialize the report parser. */
     367        rc = usb_hid_parser_init(hid_dev->parser);
    209368        if (rc != EOK) {
    210                 usb_log_error("Failed to initialize HID parser.\n");
     369                usb_log_error("Failed to initialize report parser.\n");
     370                usb_hid_free(&hid_dev);
    211371                return rc;
    212372        }
    213373       
    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");
    221                 }
    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;
     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;
     388                }
     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
    229452        }
    230453       
    231454        return rc;
     455}
     456
     457/*----------------------------------------------------------------------------*/
     458
     459bool 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;
    232483}
    233484
     
    237488     void *arg)
    238489{
     490        int i;
     491       
    239492        if (dev == NULL || arg == NULL) {
    240493                return;
     
    243496        usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
    244497       
     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       
    245504        usb_hid_free(&hid_dev);
    246505}
     
    248507/*----------------------------------------------------------------------------*/
    249508
    250 const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
    251 {
    252         switch (device_type) {
    253         case USB_HID_PROTOCOL_KEYBOARD:
     509const 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:
    254513                return HID_KBD_FUN_NAME;
    255514                break;
    256         case USB_HID_PROTOCOL_MOUSE:
     515        case USB_HID_MOUSE_POLL_EP_NO:
    257516                return HID_MOUSE_FUN_NAME;
    258517                break;
     
    264523/*----------------------------------------------------------------------------*/
    265524
    266 const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
    267 {
    268         switch (device_type) {
    269         case USB_HID_PROTOCOL_KEYBOARD:
     525const 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:
    270532                return HID_KBD_CLASS_NAME;
    271533                break;
    272         case USB_HID_PROTOCOL_MOUSE:
     534        case USB_HID_MOUSE_POLL_EP_NO:
    273535                return HID_MOUSE_CLASS_NAME;
    274536                break;
     
    282544void usb_hid_free(usb_hid_dev_t **hid_dev)
    283545{
     546        int i;
     547       
    284548        if (hid_dev == NULL || *hid_dev == NULL) {
    285549                return;
    286550        }
    287551       
    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;
     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);
    296564        }
    297565
Note: See TracChangeset for help on using the changeset viewer.