Changeset 61257f4 in mainline


Ignore:
Timestamp:
2011-04-07T20:19:24Z (13 years ago)
Author:
Lubos Slovak <lubos.slovak@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f8e8738
Parents:
fd9ba204
Message:

Initial implementation of general HID driver.

  • Should handle:
    • keyboard (most of functions from usbkbd driver), more-or-less works
    • mouse (not implemented yet)
    • generic HID device (just dummy polling callback now)
Location:
uspace/drv/usbhid
Files:
12 added
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhid/Makefile

    rfd9ba204 r61257f4  
    3232BINARY = usbhid
    3333
     34STOLEN_LAYOUT_SOURCES = \
     35        kbd/layout/us_qwerty.c \
     36        kbd/layout/us_dvorak.c \
     37        kbd/layout/cz.c
     38
    3439SOURCES = \
    3540        main.c \
    36         usbhid.c
     41        usbhid.c \
     42        kbd/conv.c \
     43        kbd/kbddev.c \
     44        kbd/kbdrepeat.c \
     45        generic/hidd.c \
     46        $(STOLEN_LAYOUT_SOURCES)
     47
     48EXTRA_CLEAN = $(STOLEN_LAYOUT_SOURCES)
     49
     50SRV_KBD = $(USPACE_PREFIX)/srv/hid/kbd
    3751
    3852include $(USPACE_PREFIX)/Makefile.common
    3953
     54kbd/layout/%.c: $(SRV_KBD)/layout/%.c
     55        ln -sfn ../../$< $@
  • uspace/drv/usbhid/main.c

    rfd9ba204 r61257f4  
    7171 * @return Other error code inherited from one of functions usb_kbd_init(),
    7272 *         ddf_fun_bind() and ddf_fun_add_to_class().
    73  *
    74  * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
    7573 */
    7674static int usb_hid_try_add_device(usb_device_t *dev)
    7775{
     76        /*
     77         * Initialize device (get and process descriptors, get address, etc.)
     78         */
     79        usb_log_debug("Initializing USB/HID device...\n");
     80       
     81        usb_hid_dev_t *hid_dev = usb_hid_new();
     82        if (hid_dev == NULL) {
     83                usb_log_error("Error while creating USB/HID device "
     84                    "structure.\n");
     85                return ENOMEM;
     86        }
     87       
     88        int rc = usb_hid_init(hid_dev, dev);
     89       
     90        if (rc != EOK) {
     91                usb_log_error("Failed to initialize USB/HID device.\n");
     92                usb_hid_free(&hid_dev);
     93                return rc;
     94        }       
     95       
     96        usb_log_debug("USB/HID device structure initialized.\n");
     97       
    7898        /* Create the function exposed under /dev/devices. */
    7999        ddf_fun_t *hid_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
    80             "hid");
     100            usb_hid_get_function_name(hid_dev->device_type));
    81101        if (hid_fun == NULL) {
    82102                usb_log_error("Could not create DDF function node.\n");
     103                usb_hid_free(&hid_dev);
    83104                return ENOMEM;
    84105        }
    85106       
    86         /*
    87          * Initialize device (get and process descriptors, get address, etc.)
    88          */
    89         usb_log_debug("Initializing USB/HID device...\n");
    90        
    91 //      usb_kbd_t *kbd_dev = usb_kbd_new();
    92 //      if (kbd_dev == NULL) {
    93 //              usb_log_error("Error while creating USB/HID KBD device "
    94 //                  "structure.\n");
    95 //              ddf_fun_destroy(hid_fun);
    96 //              return ENOMEM;  // TODO: some other code??
    97 //      }
    98        
    99 //      int rc = usb_kbd_init(kbd_dev, dev);
    100        
    101 //      if (rc != EOK) {
    102 //              usb_log_error("Failed to initialize USB/HID KBD device.\n");
    103 //              ddf_fun_destroy(hid_fun);
    104 //              usb_kbd_free(&kbd_dev);
    105 //              return rc;
    106 //      }       
    107        
    108 //      usb_log_debug("USB/HID KBD device structure initialized.\n");
    109        
    110107        /*
    111          * Store the initialized keyboard device and keyboard ops
     108         * Store the initialized HID device and HID ops
    112109         * to the DDF function.
    113110         */
    114         //kbd_fun->driver_data = kbd_dev;
    115         hid_fun->ops = &hid_ops;
    116 
    117         int rc = ddf_fun_bind(hid_fun);
     111        hid_fun->ops = &hid_dev->ops;
     112        hid_fun->driver_data = hid_dev;   // TODO: maybe change to hid_dev->data
     113
     114        rc = ddf_fun_bind(hid_fun);
    118115        if (rc != EOK) {
    119116                usb_log_error("Could not bind DDF function: %s.\n",
     
    121118                // TODO: Can / should I destroy the DDF function?
    122119                ddf_fun_destroy(hid_fun);
    123                 return rc;
    124         }
    125        
    126         rc = ddf_fun_add_to_class(hid_fun, "hid");
     120                usb_hid_free(&hid_dev);
     121                return rc;
     122        }
     123       
     124        rc = ddf_fun_add_to_class(hid_fun,
     125            usb_hid_get_class_name(hid_dev->device_type));
    127126        if (rc != EOK) {
    128127                usb_log_error(
     
    131130                // TODO: Can / should I destroy the DDF function?
    132131                ddf_fun_destroy(hid_fun);
    133                 return rc;
    134         }
    135        
    136 
     132                usb_hid_free(&hid_dev);
     133                return rc;
     134        }
     135       
    137136        /* Start automated polling function.
    138137         * This will create a separate fibril that will query the device
     
    141140       rc = usb_device_auto_poll(dev,
    142141           /* Index of the polling pipe. */
    143            USB_HID_POLL_EP_NO,
     142           hid_dev->poll_pipe_index,
    144143           /* Callback when data arrives. */
    145            usb_hid_polling_callback,
     144           hid_dev->poll_callback,
    146145           /* How much data to request. */
    147            dev->pipes[USB_HID_POLL_EP_NO].pipe->max_packet_size,
     146           dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size,
    148147           /* Callback when the polling ends. */
    149148           usb_hid_polling_ended_callback,
    150149           /* Custom argument. */
    151            NULL);
     150           hid_dev);
    152151       
    153152       
     
    157156                return rc;
    158157        }
    159 
    160         (void)hid_ops;
    161158
    162159        /*
     
    183180        if (dev->interface_no < 0) {
    184181                usb_log_warning("Device is not a supported HID device.\n");
    185                 usb_log_error("Failed to add HID device: endpoint not found."
     182                usb_log_error("Failed to add HID device: endpoints not found."
    186183                    "\n");
    187184                return ENOTSUP;
  • uspace/drv/usbhid/usbhid.c

    rfd9ba204 r61257f4  
    3737#include <usb/debug.h>
    3838#include <usb/classes/classes.h>
     39#include <usb/classes/hid.h>
     40#include <usb/classes/hidparser.h>
     41#include <usb/classes/hidreport.h>
     42#include <errno.h>
    3943
    4044#include "usbhid.h"
    4145
    42 /*----------------------------------------------------------------------------*/
    43 
    44 /** HID device polling endpoint description. */
    45 static usb_endpoint_description_t poll_endpoint_description = {
     46#include "kbd/kbddev.h"
     47#include "generic/hidd.h"
     48
     49/*----------------------------------------------------------------------------*/
     50
     51/** Generic HID device polling endpoint description. */
     52//static usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
     53//      .transfer_type = USB_TRANSFER_INTERRUPT,
     54//      .direction = USB_DIRECTION_IN,
     55//      .interface_class = USB_CLASS_HID,
     56//      .flags = 0
     57//};
     58
     59///** Keyboard polling endpoint description for boot protocol class. */
     60//static usb_endpoint_description_t ush_hid_kbd_poll_endpoint_description = {
     61//      .transfer_type = USB_TRANSFER_INTERRUPT,
     62//      .direction = USB_DIRECTION_IN,
     63//      .interface_class = USB_CLASS_HID,
     64//      .interface_subclass = USB_HID_SUBCLASS_BOOT,
     65//      .interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
     66//      .flags = 0
     67//};
     68
     69/** Mouse polling endpoint description for boot protocol class. */
     70static usb_endpoint_description_t ush_hid_mouse_poll_endpoint_description = {
    4671        .transfer_type = USB_TRANSFER_INTERRUPT,
    4772        .direction = USB_DIRECTION_IN,
    4873        .interface_class = USB_CLASS_HID,
     74        .interface_subclass = USB_HID_SUBCLASS_BOOT,
     75        .interface_protocol = USB_HID_PROTOCOL_MOUSE,
    4976        .flags = 0
    5077};
     
    5380usb_endpoint_description_t
    5481    *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
    55         &poll_endpoint_description,
     82        &ush_hid_kbd_poll_endpoint_description,
     83        &ush_hid_mouse_poll_endpoint_description,
     84        &usb_hid_generic_poll_endpoint_description,
    5685        NULL
    5786};
    5887
    59 /*----------------------------------------------------------------------------*/
    60 
    61 ddf_dev_ops_t hid_ops = {
    62         .default_handler = NULL
    63 };
    64 
    65 /*----------------------------------------------------------------------------*/
    66 
    67 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
     88static const char *HID_MOUSE_FUN_NAME = "mouse";
     89static const char *HID_MOUSE_CLASS_NAME = "mouse";
     90
     91/*----------------------------------------------------------------------------*/
     92
     93usb_hid_dev_t *usb_hid_new(void)
     94{
     95        usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
     96            sizeof(usb_hid_dev_t));
     97       
     98        if (hid_dev == NULL) {
     99                usb_log_fatal("No memory!\n");
     100                return NULL;
     101        }
     102       
     103        hid_dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
     104            usb_hid_report_parser_t)));
     105        if (hid_dev->parser == NULL) {
     106                usb_log_fatal("No memory!\n");
     107                free(hid_dev);
     108                return NULL;
     109        }
     110       
     111        return hid_dev;
     112}
     113
     114/*----------------------------------------------------------------------------*/
     115
     116static bool usb_dummy_polling_callback(usb_device_t *dev, uint8_t *buffer,
    68117     size_t buffer_size, void *arg)
    69118{
    70         usb_debug_str_buffer(buffer, buffer_size, 0);
    71         return true;
    72 }
    73 
    74 /*----------------------------------------------------------------------------*/
    75 
    76 void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
    77      void *arg)
    78 {
    79        
     119        return false;
     120}
     121
     122/*----------------------------------------------------------------------------*/
     123
     124static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
     125{
     126        if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
     127                usb_log_debug("Found keyboard endpoint.\n");
     128               
     129                // save the pipe index and device type
     130                hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
     131                hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;
     132               
     133                // set the polling callback
     134                hid_dev->poll_callback = usb_kbd_polling_callback;
     135
     136        } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
     137                usb_log_debug("Found mouse endpoint.\n");
     138               
     139                // save the pipe index and device type
     140                hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
     141                hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
     142               
     143                // set the polling callback
     144                hid_dev->poll_callback = usb_dummy_polling_callback;
     145               
     146        } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
     147                usb_log_debug("Found generic HID endpoint.\n");
     148               
     149                // save the pipe index and device type
     150                hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
     151                hid_dev->device_type = USB_HID_PROTOCOL_NONE;
     152               
     153                // set the polling callback
     154                hid_dev->poll_callback = usb_hid_polling_callback;
     155               
     156        } else {
     157                usb_log_warning("None of supported endpoints found - probably"
     158                    " not a supported device.\n");
     159                return ENOTSUP;
     160        }
     161       
     162        return EOK;
     163}
     164
     165/*----------------------------------------------------------------------------*/
     166
     167static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
     168{
     169        /* Initialize the report parser. */
     170        int rc = usb_hid_parser_init(hid_dev->parser);
     171        if (rc != EOK) {
     172                usb_log_error("Failed to initialize report parser.\n");
     173                return rc;
     174        }
     175       
     176        /* Get the report descriptor and parse it. */
     177        rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
     178            hid_dev->parser);
     179        if (rc != EOK) {
     180                usb_log_warning("Could not process report descriptor.\n");
     181               
     182                if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {
     183                        usb_log_warning("Falling back to boot protocol.\n");
     184                       
     185                        rc = usb_kbd_set_boot_protocol(hid_dev);
     186                       
     187                } else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
     188                        usb_log_warning("No boot protocol for mouse yet.\n");
     189                        rc = ENOTSUP;
     190                }
     191        }
     192       
     193        return rc;
     194}
     195
     196/*----------------------------------------------------------------------------*/
     197
     198int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
     199{
     200        int rc;
     201       
     202        usb_log_debug("Initializing HID structure...\n");
     203       
     204        if (hid_dev == NULL) {
     205                usb_log_error("Failed to init HID structure: no structure given"
     206                    ".\n");
     207                return EINVAL;
     208        }
     209       
     210        if (dev == NULL) {
     211                usb_log_error("Failed to init HID structure: no USB device"
     212                    " given.\n");
     213                return EINVAL;
     214        }
     215       
     216        /* The USB device should already be initialized, save it in structure */
     217        hid_dev->usb_dev = dev;
     218       
     219        rc = usb_hid_check_pipes(hid_dev, dev);
     220        if (rc != EOK) {
     221                return rc;
     222        }
     223       
     224        rc = usb_hid_init_parser(hid_dev);
     225        if (rc != EOK) {
     226                usb_log_error("Failed to initialize HID parser.\n");
     227                return rc;
     228        }
     229       
     230        switch (hid_dev->device_type) {
     231        case USB_HID_PROTOCOL_KEYBOARD:
     232                // initialize the keyboard structure
     233                rc = usb_kbd_init(hid_dev);
     234                if (rc != EOK) {
     235                        usb_log_warning("Failed to initialize KBD structure."
     236                            "\n");
     237                }
     238                break;
     239        case USB_HID_PROTOCOL_MOUSE:
     240                break;
     241        default:
     242                break;
     243        }
     244       
     245        return rc;
     246}
     247
     248/*----------------------------------------------------------------------------*/
     249
     250void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
     251     void *arg)
     252{
     253        if (dev == NULL || arg == NULL) {
     254                return;
     255        }
     256       
     257        usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
     258       
     259        usb_hid_free(&hid_dev);
     260}
     261
     262/*----------------------------------------------------------------------------*/
     263
     264const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
     265{
     266        switch (device_type) {
     267        case USB_HID_PROTOCOL_KEYBOARD:
     268                return HID_KBD_FUN_NAME;
     269                break;
     270        case USB_HID_PROTOCOL_MOUSE:
     271                return HID_MOUSE_FUN_NAME;
     272                break;
     273        default:
     274                return HID_GENERIC_FUN_NAME;
     275        }
     276}
     277
     278/*----------------------------------------------------------------------------*/
     279
     280const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
     281{
     282        switch (device_type) {
     283        case USB_HID_PROTOCOL_KEYBOARD:
     284                return HID_KBD_CLASS_NAME;
     285                break;
     286        case USB_HID_PROTOCOL_MOUSE:
     287                return HID_MOUSE_CLASS_NAME;
     288                break;
     289        default:
     290                return HID_GENERIC_CLASS_NAME;
     291        }
     292}
     293
     294/*----------------------------------------------------------------------------*/
     295
     296void usb_hid_free(usb_hid_dev_t **hid_dev)
     297{
     298        if (hid_dev == NULL || *hid_dev == NULL) {
     299                return;
     300        }
     301       
     302        switch ((*hid_dev)->device_type) {
     303        case USB_HID_PROTOCOL_KEYBOARD:
     304                usb_kbd_deinit(*hid_dev);
     305                break;
     306        case USB_HID_PROTOCOL_MOUSE:
     307                break;
     308        default:
     309                break;
     310        }
     311
     312        // destroy the parser
     313        if ((*hid_dev)->parser != NULL) {
     314                usb_hid_free_report_parser((*hid_dev)->parser);
     315        }
     316
     317        if ((*hid_dev)->report_desc != NULL) {
     318                free((*hid_dev)->report_desc);
     319        }
     320
     321        free(*hid_dev);
     322        *hid_dev = NULL;
    80323}
    81324
  • uspace/drv/usbhid/usbhid.h

    rfd9ba204 r61257f4  
    4242
    4343//#include <usb/classes/hid.h>
    44 //#include <usb/classes/hidparser.h>
     44#include <usb/classes/hidparser.h>
    4545#include <ddf/driver.h>
    4646#include <usb/pipes.h>
    4747#include <usb/devdrv.h>
     48#include <usb/classes/hid.h>
    4849
    4950/*----------------------------------------------------------------------------*/
    50 ///**
    51 // * USB/HID keyboard device type.
    52 // *
    53 // * Holds a reference to generic USB/HID device structure and keyboard-specific
    54 // * data, such as currently pressed keys, modifiers and lock keys.
    55 // *
    56 // * Also holds a IPC phone to the console (since there is now no other way to
    57 // * communicate with it).
    58 // *
    59 // * @note Storing active lock keys in this structure results in their setting
    60 // *       being device-specific.
    61 // */
    62 //typedef struct usb_kbd_t {
    63 //      /** Structure holding generic USB device information. */
    64 //      //usbhid_dev_t *hid_dev;
    65 //      usb_device_t *usb_dev;
     51/**
     52 * Structure for holding general HID device data.
     53 */
     54typedef struct usb_hid_dev_t {
     55        /** Structure holding generic USB device information. */
     56        usb_device_t *usb_dev;
    6657       
    67 //      /** Currently pressed keys (not translated to key codes). */
    68 //      uint8_t *keys;
    69 //      /** Count of stored keys (i.e. number of keys in the report). */
    70 //      size_t key_count;
    71 //      /** Currently pressed modifiers (bitmap). */
    72 //      uint8_t modifiers;
     58        /** @todo What is this actually? */
     59        ddf_dev_ops_t ops;
    7360       
    74 //      /** Currently active modifiers including locks. Sent to the console. */
    75 //      unsigned mods;
     61        /** Index of the polling pipe in usb_hid_endpoints array. */
     62        int poll_pipe_index;
    7663       
    77 //      /** Currently active lock keys. */
    78 //      unsigned lock_keys;
     64        /** Function to be called when data arrives from the device. */
     65        usb_polling_callback_t poll_callback;
    7966       
    80 //      /** IPC phone to the console device (for sending key events). */
    81 //      int console_phone;
     67        /** Report descriptor. */
     68        uint8_t *report_desc;
     69
     70        /** Report descriptor size. */
     71        size_t report_desc_size;
    8272       
    83 //      /** Information for auto-repeat of keys. */
    84 //      usb_kbd_repeat_t repeat;
     73        /** HID Report parser. */
     74        usb_hid_report_parser_t *parser;
    8575       
    86 //      /** Mutex for accessing the information about auto-repeat. */
    87 //      fibril_mutex_t *repeat_mtx;
     76        /** Arbitrary data (e.g. a special structure for handling keyboard). */
     77        void *data;
    8878       
    89 //      /** Report descriptor. */
    90 //      uint8_t *report_desc;
    91 
    92 //      /** Report descriptor size. */
    93 //      size_t report_desc_size;
    94        
    95 //      uint8_t *output_buffer;
    96        
    97 //      size_t output_size;
    98        
    99 //      size_t led_output_size;
    100        
    101 //      usb_hid_report_path_t *led_path;
    102        
    103 //      int32_t *led_data;
    104 
    105 //      /** HID Report parser. */
    106 //      usb_hid_report_parser_t *parser;
    107        
    108 //      /** State of the structure (for checking before use).
    109 //       *
    110 //       * 0 - not initialized
    111 //       * 1 - initialized
    112 //       * -1 - ready for destroying
    113 //       */
    114 //      int initialized;
    115 //} usb_kbd_t;
     79        /** Type of the device (keyboard, mouse, generic HID device). */
     80        usb_hid_iface_protocol_t device_type;
     81} usb_hid_dev_t;
    11682
    11783/*----------------------------------------------------------------------------*/
    11884
    11985enum {
    120         USB_HID_POLL_EP_NO = 0,
    121         USB_HID_POLL_EP_COUNT = 1
     86        USB_HID_KBD_POLL_EP_NO = 0,
     87        USB_HID_MOUSE_POLL_EP_NO = 1,
     88        USB_HID_GENERIC_POLL_EP_NO = 2,
     89        USB_HID_POLL_EP_COUNT = 3
    12290};
    12391
    12492usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1];
    12593
    126 ddf_dev_ops_t hid_ops;
    127 
    12894/*----------------------------------------------------------------------------*/
    12995
    130 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
    131      size_t buffer_size, void *arg);
     96usb_hid_dev_t *usb_hid_new(void);
    13297
    133 void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
     98int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
     99
     100void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
    134101     void *arg);
    135102
    136 #endif /* USB_KBDDEV_H_ */
     103const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type);
     104
     105const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type);
     106
     107/** @todo Maybe not needed in the API. */
     108void usb_hid_free(usb_hid_dev_t **hid_dev);
     109
     110#endif /* USB_USBHID_H_ */
    137111
    138112/**
  • uspace/drv/usbhid/usbhid.ma

    rfd9ba204 r61257f4  
    1 100 usb&interface&class=HID
     11000 usb&interface&class=HID&subclass=0x01&protocol=0x02
     21000 usb&interface&class=HID
Note: See TracChangeset for help on using the changeset viewer.