Changeset 8c877b2 in mainline for uspace/drv/usbhid/main.c


Ignore:
Timestamp:
2011-03-04T13:05:35Z (13 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d49728c
Parents:
dff940f8 (diff), 9a422574 (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:

merge with \usb\development

File:
1 edited

Legend:

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

    rdff940f8 r8c877b2  
    3737
    3838#include <ddf/driver.h>
    39 #include <ipc/driver.h>
    40 #include <ipc/kbd.h>
    41 #include <io/keycode.h>
    42 #include <io/console.h>
     39#include <usb/debug.h>
    4340#include <errno.h>
    44 #include <str_error.h>
    45 #include <fibril.h>
    46 #include <usb/debug.h>
    47 #include <usb/classes/classes.h>
    48 #include <usb/classes/hid.h>
    49 #include <usb/classes/hidparser.h>
    50 #include <usb/request.h>
    51 #include <usb/descriptor.h>
    52 #include <io/console.h>
    53 #include "hid.h"
    54 #include "descparser.h"
    55 #include "descdump.h"
    56 #include "conv.h"
    57 #include "layout.h"
    5841
    59 #define BUFFER_SIZE 8
     42#include "kbddev.h"
     43
     44/*----------------------------------------------------------------------------*/
     45
    6046#define NAME "usbhid"
    6147
    62 #define GUESSED_POLL_ENDPOINT 1
     48/*----------------------------------------------------------------------------*/
    6349
    64 /** Keyboard polling endpoint description for boot protocol class. */
    65 static usb_endpoint_description_t poll_endpoint_description = {
    66         .transfer_type = USB_TRANSFER_INTERRUPT,
    67         .direction = USB_DIRECTION_IN,
    68         .interface_class = USB_CLASS_HID,
    69         .interface_subclass = USB_HID_SUBCLASS_BOOT,
    70         .interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
    71         .flags = 0
    72 };
    73 
    74 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    75 static ddf_dev_ops_t keyboard_ops = {
    76         .default_handler = default_connection_handler
    77 };
    78 
    79 static int console_callback_phone = -1;
    80 
    81 /** Default handler for IPC methods not handled by DDF.
    82  *
    83  * @param dev Device handling the call.
    84  * @param icallid Call id.
    85  * @param icall Call data.
    86  */
    87 void default_connection_handler(ddf_fun_t *fun,
    88     ipc_callid_t icallid, ipc_call_t *icall)
     50static int usbhid_add_device(ddf_dev_t *dev)
    8951{
    90         sysarg_t method = IPC_GET_IMETHOD(*icall);
    91 
    92         if (method == IPC_M_CONNECT_TO_ME) {
    93                 int callback = IPC_GET_ARG5(*icall);
    94 
    95                 if (console_callback_phone != -1) {
    96                         async_answer_0(icallid, ELIMIT);
    97                         return;
    98                 }
    99 
    100                 console_callback_phone = callback;
    101                 async_answer_0(icallid, EOK);
    102                 return;
    103         }
    104 
    105         async_answer_0(icallid, EINVAL);
    106 }
    107 
    108 #if 0
    109 static void send_key(int key, int type, wchar_t c) {
    110         async_msg_4(console_callback_phone, KBD_EVENT, type, key,
    111             KM_NUM_LOCK, c);
    112 }
    113 #endif
    114 
    115 /*
    116  * TODO: Move somewhere else
    117  */
    118 /*
    119 #define BYTES_PER_LINE 12
    120 
    121 static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
    122 {
    123         printf("%s\n", msg);
     52        usb_log_debug("usbhid_add_device()\n");
    12453       
    125         size_t i;
    126         for (i = 0; i < length; i++) {
    127                 printf("  0x%02X", buffer[i]);
    128                 if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0))
    129                     || (i + 1 == length)) {
    130                         printf("\n");
    131                 }
    132         }
    133 }
    134 */
    135 /*
    136  * Copy-paste from srv/hid/kbd/generic/kbd.c
    137  */
    138 
    139 /** Currently active modifiers.
    140  *
    141  * TODO: put to device?
    142  */
    143 static unsigned mods = KM_NUM_LOCK;
    144 
    145 /** Currently pressed lock keys. We track these to tackle autorepeat. 
    146  *
    147  * TODO: put to device?
    148  */
    149 static unsigned lock_keys;
    150 
    151 #define NUM_LAYOUTS 3
    152 
    153 static layout_op_t *layout[NUM_LAYOUTS] = {
    154         &us_qwerty_op,
    155         &us_dvorak_op,
    156         &cz_op
    157 };
    158 
    159 static int active_layout = 0;
    160 
    161 static void kbd_push_ev(int type, unsigned int key)
    162 {
    163         console_event_t ev;
    164         unsigned mod_mask;
    165 
    166         // TODO: replace by our own parsing?? or are the key codes identical??
    167         switch (key) {
    168         case KC_LCTRL: mod_mask = KM_LCTRL; break;
    169         case KC_RCTRL: mod_mask = KM_RCTRL; break;
    170         case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
    171         case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
    172         case KC_LALT: mod_mask = KM_LALT; break;
    173         case KC_RALT: mod_mask = KM_RALT; break;
    174         default: mod_mask = 0; break;
    175         }
    176 
    177         if (mod_mask != 0) {
    178                 if (type == KEY_PRESS)
    179                         mods = mods | mod_mask;
    180                 else
    181                         mods = mods & ~mod_mask;
    182         }
    183 
    184         switch (key) {
    185         case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
    186         case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
    187         case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
    188         default: mod_mask = 0; break;
    189         }
    190 
    191         if (mod_mask != 0) {
    192                 if (type == KEY_PRESS) {
    193                         /*
    194                          * Only change lock state on transition from released
    195                          * to pressed. This prevents autorepeat from messing
    196                          * up the lock state.
    197                          */
    198                         mods = mods ^ (mod_mask & ~lock_keys);
    199                         lock_keys = lock_keys | mod_mask;
    200 
    201                         /* Update keyboard lock indicator lights. */
    202                         // TODO
    203                         //kbd_ctl_set_ind(mods);
    204                 } else {
    205                         lock_keys = lock_keys & ~mod_mask;
    206                 }
    207         }
    208 /*
    209         printf("type: %d\n", type);
    210         printf("mods: 0x%x\n", mods);
    211         printf("keycode: %u\n", key);
    212 */
     54        int rc = usbhid_kbd_try_add_device(dev);
    21355       
    214         if (type == KEY_PRESS && (mods & KM_LCTRL) &&
    215                 key == KC_F1) {
    216                 active_layout = 0;
    217                 layout[active_layout]->reset();
    218                 return;
    219         }
    220 
    221         if (type == KEY_PRESS && (mods & KM_LCTRL) &&
    222                 key == KC_F2) {
    223                 active_layout = 1;
    224                 layout[active_layout]->reset();
    225                 return;
    226         }
    227 
    228         if (type == KEY_PRESS && (mods & KM_LCTRL) &&
    229                 key == KC_F3) {
    230                 active_layout = 2;
    231                 layout[active_layout]->reset();
    232                 return;
     56        if (rc != EOK) {
     57                usb_log_info("Device is not a supported keyboard.\n");
     58                usb_log_error("Failed to add HID device.\n");
     59                return EREFUSED;
    23360        }
    23461       
    235         ev.type = type;
    236         ev.key = key;
    237         ev.mods = mods;
    238 
    239         ev.c = layout[active_layout]->parse_ev(&ev);
    240 
    241         printf("Sending key %d to the console\n", ev.key);
    242         assert(console_callback_phone != -1);
    243         async_msg_4(console_callback_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
    244 }
    245 /*
    246  * End of copy-paste
    247  */
    248 
    249         /*
    250          * TODO:
    251          * 1) key press / key release - how does the keyboard notify about release?
    252          * 2) layouts (use the already defined), not important now
    253          * 3)
    254          */
    255 
    256 /*
    257  * Callbacks for parser
    258  */
    259 static void usbkbd_process_keycodes(const uint8_t *key_codes, size_t count,
    260     uint8_t modifiers, void *arg)
    261 {
    262         printf("Got keys: ");
    263         unsigned i;
    264         for (i = 0; i < count; ++i) {
    265                 printf("%d ", key_codes[i]);
    266         }
    267         printf("\n");
    268 
    269         for (i = 0; i < count; ++i) {
    270                 // TODO: Key press / release
    271 
    272                 // TODO: NOT WORKING
    273                 unsigned int key = usbkbd_parse_scancode(key_codes[i]);
    274 
    275                 if (key == 0) {
    276                         continue;
    277                 }
    278                 kbd_push_ev(KEY_PRESS, key);
    279         }
    280         printf("\n");
    281 }
    282 
    283 /*
    284  * Kbd functions
    285  */
    286 static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev)
    287 {
    288         // iterate over all configurations and interfaces
    289         // TODO: more configurations!!
    290         unsigned i;
    291         for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) {
    292                 // TODO: endianness
    293                 uint16_t length =
    294                     kbd_dev->conf->interfaces[i].hid_desc.report_desc_info.length;
    295                 size_t actual_size = 0;
    296 
    297                 // allocate space for the report descriptor
    298                 kbd_dev->conf->interfaces[i].report_desc = (uint8_t *)malloc(length);
    299                
    300                 // get the descriptor from the device
    301                 int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe,
    302                     USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT,
    303                     i, 0,
    304                     kbd_dev->conf->interfaces[i].report_desc, length,
    305                     &actual_size);
    306 
    307                 if (rc != EOK) {
    308                         return rc;
    309                 }
    310 
    311                 assert(actual_size == length);
    312 
    313                 //dump_hid_class_descriptor(0, USB_DESCTYPE_HID_REPORT,
    314                 //    kbd_dev->conf->interfaces[i].report_desc, length);
    315         }
    316 
    317         return EOK;
    318 }
    319 static int usbkbd_process_descriptors(usb_hid_dev_kbd_t *kbd_dev)
    320 {
    321         // get the first configuration descriptor (TODO: parse also other!)
    322         usb_standard_configuration_descriptor_t config_desc;
    323        
    324         int rc;
    325         rc = usb_request_get_bare_configuration_descriptor(&kbd_dev->ctrl_pipe,
    326             0, &config_desc);
    327        
    328         if (rc != EOK) {
    329                 return rc;
    330         }
    331        
    332         // prepare space for all underlying descriptors
    333         uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length);
    334         if (descriptors == NULL) {
    335                 return ENOMEM;
    336         }
    337        
    338         size_t transferred = 0;
    339         // get full configuration descriptor
    340         rc = usb_request_get_full_configuration_descriptor(&kbd_dev->ctrl_pipe,
    341             0, descriptors,
    342             config_desc.total_length, &transferred);
    343        
    344         if (rc != EOK) {
    345                 return rc;
    346         }
    347         if (transferred != config_desc.total_length) {
    348                 return ELIMIT;
    349         }
    350        
    351         /*
    352          * Initialize the interrupt in endpoint.
    353          */
    354         usb_endpoint_mapping_t endpoint_mapping[1] = {
    355                 {
    356                         .pipe = &kbd_dev->poll_pipe,
    357                         .description = &poll_endpoint_description,
    358                         .interface_no =
    359                             usb_device_get_assigned_interface(kbd_dev->device)
    360                 }
    361         };
    362         rc = usb_endpoint_pipe_initialize_from_configuration(
    363             endpoint_mapping, 1,
    364             descriptors, config_desc.total_length,
    365             &kbd_dev->wire);
    366         if (rc != EOK) {
    367                 usb_log_error("Failed to initialize poll pipe: %s.\n",
    368                     str_error(rc));
    369                 return rc;
    370         }
    371         if (!endpoint_mapping[0].present) {
    372                 usb_log_warning("Not accepting device, " \
    373                     "not boot-protocol keyboard.\n");
    374                 return EREFUSED;
    375         }
    376 
    377 
    378 
    379 
    380         kbd_dev->conf = (usb_hid_configuration_t *)calloc(1,
    381             sizeof(usb_hid_configuration_t));
    382         if (kbd_dev->conf == NULL) {
    383                 free(descriptors);
    384                 return ENOMEM;
    385         }
    386        
    387         /*rc = usbkbd_parse_descriptors(descriptors, transferred, kbd_dev->conf);
    388         free(descriptors);
    389         if (rc != EOK) {
    390                 printf("Problem with parsing standard descriptors.\n");
    391                 return rc;
    392         }
    393 
    394         // get and report descriptors*/
    395         rc = usbkbd_get_report_descriptor(kbd_dev);
    396         if (rc != EOK) {
    397                 printf("Problem with parsing HID REPORT descriptor.\n");
    398                 return rc;
    399         }
    400        
    401         //usbkbd_print_config(kbd_dev->conf);
    402 
    403         /*
    404          * TODO:
    405          * 1) select one configuration (lets say the first)
    406          * 2) how many interfaces?? how to select one??
    407      *    ("The default setting for an interface is always alternate setting zero.")
    408          * 3) find endpoint which is IN and INTERRUPT (parse), save its number
    409      *    as the endpoint for polling
    410          */
    411 
    41262        return EOK;
    41363}
    41464
    415 static usb_hid_dev_kbd_t *usbkbd_init_device(ddf_dev_t *dev)
    416 {
    417         int rc;
    418 
    419         usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)calloc(1,
    420             sizeof(usb_hid_dev_kbd_t));
    421 
    422         if (kbd_dev == NULL) {
    423                 fprintf(stderr, NAME ": No memory!\n");
    424                 return NULL;
    425         }
    426 
    427         kbd_dev->device = dev;
    428 
    429         /*
    430          * Initialize the backing connection to the host controller.
    431          */
    432         rc = usb_device_connection_initialize_from_device(&kbd_dev->wire, dev);
    433         if (rc != EOK) {
    434                 printf("Problem initializing connection to device: %s.\n",
    435                     str_error(rc));
    436                 goto error_leave;
    437         }
    438 
    439         /*
    440          * Initialize device pipes.
    441          */
    442         rc = usb_endpoint_pipe_initialize_default_control(&kbd_dev->ctrl_pipe,
    443             &kbd_dev->wire);
    444         if (rc != EOK) {
    445                 printf("Failed to initialize default control pipe: %s.\n",
    446                     str_error(rc));
    447                 goto error_leave;
    448         }
    449 
    450         /*
    451          * will need all descriptors:
    452          * 1) choose one configuration from configuration descriptors
    453          *    (set it to the device)
    454          * 2) set endpoints from endpoint descriptors
    455          */
    456 
    457         // TODO: get descriptors, parse descriptors and save endpoints
    458         usb_endpoint_pipe_start_session(&kbd_dev->ctrl_pipe);
    459         //usb_request_set_configuration(&kbd_dev->ctrl_pipe, 1);
    460         rc = usbkbd_process_descriptors(kbd_dev);
    461         usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe);
    462         if (rc != EOK) {
    463                 goto error_leave;
    464         }
    465 
    466         return kbd_dev;
    467 
    468 error_leave:
    469         free(kbd_dev);
    470         return NULL;
    471 }
    472 
    473 static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
    474                                         uint8_t *buffer, size_t actual_size)
    475 {
    476         usb_hid_report_in_callbacks_t *callbacks =
    477             (usb_hid_report_in_callbacks_t *)malloc(
    478                 sizeof(usb_hid_report_in_callbacks_t));
    479         callbacks->keyboard = usbkbd_process_keycodes;
    480 
    481         //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
    482         //    NULL);
    483         printf("Calling usb_hid_boot_keyboard_input_report() with size %zu\n",
    484             actual_size);
    485         //dump_buffer("bufffer: ", buffer, actual_size);
    486         int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size, callbacks,
    487             NULL);
    488         if (rc != EOK) {
    489                 printf("Error in usb_hid_boot_keyboard_input_report(): %d\n", rc);
    490         }
    491 }
    492 
    493 static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev)
    494 {
    495         int rc, sess_rc;
    496         uint8_t buffer[BUFFER_SIZE];
    497         size_t actual_size;
    498 
    499         printf("Polling keyboard...\n");
    500 
    501         while (true) {
    502                 async_usleep(1000 * 10);
    503 
    504                 sess_rc = usb_endpoint_pipe_start_session(&kbd_dev->poll_pipe);
    505                 if (sess_rc != EOK) {
    506                         printf("Failed to start a session: %s.\n",
    507                             str_error(sess_rc));
    508                         continue;
    509                 }
    510 
    511                 rc = usb_endpoint_pipe_read(&kbd_dev->poll_pipe, buffer,
    512                     BUFFER_SIZE, &actual_size);
    513                 sess_rc = usb_endpoint_pipe_end_session(&kbd_dev->poll_pipe);
    514 
    515                 if (rc != EOK) {
    516                         printf("Error polling the keyboard: %s.\n",
    517                             str_error(rc));
    518                         continue;
    519                 }
    520 
    521                 if (sess_rc != EOK) {
    522                         printf("Error closing session: %s.\n",
    523                             str_error(sess_rc));
    524                         continue;
    525                 }
    526 
    527                 /*
    528                  * If the keyboard answered with NAK, it returned no data.
    529                  * This implies that no change happened since last query.
    530                  */
    531                 if (actual_size == 0) {
    532                         printf("Keyboard returned NAK\n");
    533                         continue;
    534                 }
    535 
    536                 /*
    537                  * TODO: Process pressed keys.
    538                  */
    539                 printf("Calling usbkbd_process_interrupt_in()\n");
    540                 usbkbd_process_interrupt_in(kbd_dev, buffer, actual_size);
    541         }
    542 
    543         // not reached
    544         assert(0);
    545 }
    546 
    547 static int usbkbd_fibril_device(void *arg)
    548 {
    549         printf("!!! USB device fibril\n");
    550 
    551         if (arg == NULL) {
    552                 printf("No device!\n");
    553                 return -1;
    554         }
    555 
    556         ddf_dev_t *dev = (ddf_dev_t *)arg;
    557 
    558         // initialize device (get and process descriptors, get address, etc.)
    559         usb_hid_dev_kbd_t *kbd_dev = usbkbd_init_device(dev);
    560         if (kbd_dev == NULL) {
    561                 printf("Error while initializing device.\n");
    562                 return -1;
    563         }
    564 
    565         usbkbd_poll_keyboard(kbd_dev);
    566 
    567         return EOK;
    568 }
    569 
    570 static int usbkbd_add_device(ddf_dev_t *dev)
    571 {
    572         /* For now, fail immediately. */
    573         //return ENOTSUP;
    574 
    575         /*
    576          * When everything is okay, connect to "our" HC.
    577          *
    578          * Not supported yet, skip..
    579          */
    580 //      int phone = usb_drv_hc_connect_auto(dev, 0);
    581 //      if (phone < 0) {
    582 //              /*
    583 //               * Connecting to HC failed, roll-back and announce
    584 //               * failure.
    585 //               */
    586 //              return phone;
    587 //      }
    588 
    589 //      dev->parent_phone = phone;
    590 
    591         /*
    592          * Create default function.
    593          */
    594         // FIXME - check for errors
    595         ddf_fun_t *kbd_fun = ddf_fun_create(dev, fun_exposed, "keyboard");
    596         assert(kbd_fun != NULL);
    597         kbd_fun->ops = &keyboard_ops;
    598 
    599         int rc = ddf_fun_bind(kbd_fun);
    600         assert(rc == EOK);
    601         rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
    602         assert(rc == EOK);
    603 
    604         /*
    605          * Create new fibril for handling this keyboard
    606          */
    607         fid_t fid = fibril_create(usbkbd_fibril_device, dev);
    608         if (fid == 0) {
    609                 printf("%s: failed to start fibril for HID device\n", NAME);
    610                 return ENOMEM;
    611         }
    612         fibril_add_ready(fid);
    613 
    614         //dev->ops = &keyboard_ops;
    615         (void)keyboard_ops;
    616 
    617         //add_device_to_class(dev, "keyboard");
    618 
    619         /*
    620          * Hurrah, device is initialized.
    621          */
    622         return EOK;
    623 }
     65/*----------------------------------------------------------------------------*/
    62466
    62567static driver_ops_t kbd_driver_ops = {
    626         .add_device = usbkbd_add_device,
     68        .add_device = usbhid_add_device,
    62769};
     70
     71/*----------------------------------------------------------------------------*/
    62872
    62973static driver_t kbd_driver = {
     
    63276};
    63377
     78/*----------------------------------------------------------------------------*/
     79
    63480int main(int argc, char *argv[])
    63581{
    636         usb_log_enable(USB_LOG_LEVEL_INFO, "usbhid");
     82        usb_log_enable(USB_LOG_LEVEL_INFO, NAME);
    63783        return ddf_driver_main(&kbd_driver);
    63884}
Note: See TracChangeset for help on using the changeset viewer.