Ignore:
File:
1 edited

Legend:

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

    r1c6c4092 r0f21c0c  
    3636 */
    3737
    38 #include <ddf/driver.h>
     38#include <driver.h>
     39#include <ipc/driver.h>
     40#include <ipc/kbd.h>
     41#include <io/keycode.h>
     42#include <io/console.h>
     43#include <errno.h>
     44#include <str_error.h>
     45#include <fibril.h>
    3946#include <usb/debug.h>
    40 #include <errno.h>
    41 
    42 #include "kbddev.h"
    43 
    44 /*----------------------------------------------------------------------------*/
    45 
     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"
     58
     59#define BUFFER_SIZE 8
    4660#define NAME "usbhid"
    4761
    48 /*----------------------------------------------------------------------------*/
    49 
    50 static int usbhid_add_device(ddf_dev_t *dev)
    51 {
    52         usb_log_debug("usbhid_add_device()\n");
    53        
    54         int rc = usbhid_kbd_try_add_device(dev);
    55        
    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");
     62#define GUESSED_POLL_ENDPOINT 1
     63
     64/** Keyboard polling endpoint description for boot protocol class. */
     65static 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
     74static void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
     75static device_ops_t keyboard_ops = {
     76        .default_handler = default_connection_handler
     77};
     78
     79static 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 */
     87void default_connection_handler(device_t *dev,
     88    ipc_callid_t icallid, ipc_call_t *icall)
     89{
     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
     109static 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
     121static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
     122{
     123        printf("%s\n", msg);
     124       
     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 */
     143static unsigned mods = KM_NUM_LOCK;
     144
     145/** Currently pressed lock keys. We track these to tackle autorepeat. 
     146 *
     147 * TODO: put to device?
     148 */
     149static unsigned lock_keys;
     150
     151#define NUM_LAYOUTS 3
     152
     153static layout_op_t *layout[NUM_LAYOUTS] = {
     154        &us_qwerty_op,
     155        &us_dvorak_op,
     156        &cz_op
     157};
     158
     159static int active_layout = 0;
     160
     161static 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*/
     213       
     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;
     233        }
     234       
     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 */
     259static 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 */
     286static 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}
     319static 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");
    59374                return EREFUSED;
    60375        }
    61        
     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
    62412        return EOK;
    63413}
    64414
    65 /*----------------------------------------------------------------------------*/
     415static usb_hid_dev_kbd_t *usbkbd_init_device(device_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
     468error_leave:
     469        free(kbd_dev);
     470        return NULL;
     471}
     472
     473static 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
     493static 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
     547static 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        device_t *dev = (device_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
     570static int usbkbd_add_device(device_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 new fibril for handling this keyboard
     593         */
     594        fid_t fid = fibril_create(usbkbd_fibril_device, dev);
     595        if (fid == 0) {
     596                printf("%s: failed to start fibril for HID device\n", NAME);
     597                return ENOMEM;
     598        }
     599        fibril_add_ready(fid);
     600
     601        dev->ops = &keyboard_ops;
     602
     603        add_device_to_class(dev, "keyboard");
     604
     605        /*
     606         * Hurrah, device is initialized.
     607         */
     608        return EOK;
     609}
    66610
    67611static driver_ops_t kbd_driver_ops = {
    68         .add_device = usbhid_add_device,
     612        .add_device = usbkbd_add_device,
    69613};
    70 
    71 /*----------------------------------------------------------------------------*/
    72614
    73615static driver_t kbd_driver = {
     
    76618};
    77619
    78 /*----------------------------------------------------------------------------*/
    79 
    80620int main(int argc, char *argv[])
    81621{
    82         usb_log_enable(USB_LOG_LEVEL_INFO, NAME);
    83         return ddf_driver_main(&kbd_driver);
     622        usb_log_enable(USB_LOG_LEVEL_INFO, "usbhid");
     623        return driver_main(&kbd_driver);
    84624}
    85625
Note: See TracChangeset for help on using the changeset viewer.