Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhid/multimedia/multimedia.c

    r5f6e25e ra0c05e7  
    4747#include <errno.h>
    4848#include <async.h>
    49 #include <async_obsolete.h>
    5049#include <str_error.h>
    5150
     
    5352#include <io/console.h>
    5453
    55 // FIXME: remove this header
    56 #include <abi/ipc/methods.h>
    57 
    58 #define NAME "multimedia-keys"
     54#define NAME  "multimedia-keys"
    5955
    6056/*----------------------------------------------------------------------------*/
     
    6864        //int32_t *keys;
    6965        /** Count of stored keys (i.e. number of keys in the report). */
    70         //size_t key_count;     
    71         /** IPC phone to the console device (for sending key events). */
    72         int console_phone;
     66        //size_t key_count;
     67        /** IPC session to the console device (for sending key events). */
     68        async_sess_t *console_sess;
    7369} usb_multimedia_t;
    7470
    7571
    7672/*----------------------------------------------------------------------------*/
    77 /** 
     73/**
    7874 * Default handler for IPC methods not handled by DDF.
    7975 *
    8076 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
    81  * assumes the caller is the console and thus it stores IPC phone to it for
     77 * assumes the caller is the console and thus it stores IPC session to it for
    8278 * later use by the driver to notify about key events.
    8379 *
     
    9086{
    9187        usb_log_debug(NAME " default_connection_handler()\n");
    92        
    93         sysarg_t method = IPC_GET_IMETHOD(*icall);
    94        
    95         usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
    96        
    97         if (multim_dev == NULL) {
     88        if (fun == NULL || fun->driver_data == NULL) {
    9889                async_answer_0(icallid, EINVAL);
    9990                return;
    10091        }
    10192
    102         if (method == IPC_M_CONNECT_TO_ME) {
    103                 int callback = IPC_GET_ARG5(*icall);
    104 
    105                 if (multim_dev->console_phone != -1) {
     93        usb_multimedia_t *multim_dev = fun->driver_data;
     94
     95        async_sess_t *sess =
     96            async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
     97        if (sess != NULL) {
     98                if (multim_dev->console_sess == NULL) {
     99                        multim_dev->console_sess = sess;
     100                        usb_log_debug(NAME " Saved session to console: %p\n",
     101                            sess);
     102                        async_answer_0(icallid, EOK);
     103                } else
    106104                        async_answer_0(icallid, ELIMIT);
    107                         return;
    108                 }
    109 
    110                 multim_dev->console_phone = callback;
    111                 usb_log_debug(NAME " Saved phone to console: %d\n", callback);
    112                 async_answer_0(icallid, EOK);
    113                 return;
    114         }
    115        
    116         async_answer_0(icallid, EINVAL);
    117 }
    118 
    119 /*----------------------------------------------------------------------------*/
    120 
     105        } else
     106                async_answer_0(icallid, EINVAL);
     107}
     108/*----------------------------------------------------------------------------*/
    121109static ddf_dev_ops_t multimedia_ops = {
    122110        .default_handler = default_connection_handler
    123111};
    124 
    125112/*----------------------------------------------------------------------------*/
    126113/**
     
    134121 *       sends also these keys to application (otherwise it cannot use those
    135122 *       keys at all).
    136  * 
    137  * @param hid_dev 
    138  * @param lgtch_dev
    139  * @param type Type of the event (press / release). Recognized values: 
     123 *
     124 * @param hid_dev
     125 * @param multim_dev
     126 * @param type Type of the event (press / release). Recognized values:
    140127 *             KEY_PRESS, KEY_RELEASE
    141128 * @param key Key code of the key according to HID Usage Tables.
    142129 */
    143 static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev,
     130static void usb_multimedia_push_ev(
    144131    usb_multimedia_t *multim_dev, int type, unsigned int key)
    145132{
    146         assert(hid_dev != NULL);
    147133        assert(multim_dev != NULL);
    148        
    149         kbd_event_t ev;
    150        
    151         ev.type = type;
    152         ev.key = key;
    153         ev.mods = 0;
    154         ev.c = 0;
     134
     135        const kbd_event_t ev = {
     136                .type = type,
     137                .key = key,
     138                .mods = 0,
     139                .c = 0,
     140        };
    155141
    156142        usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
    157         if (multim_dev->console_phone < 0) {
     143        if (multim_dev->console_sess == NULL) {
    158144                usb_log_warning(
    159145                    "Connection to console not ready, key discarded.\n");
    160146                return;
    161147        }
    162        
    163         async_obsolete_msg_4(multim_dev->console_phone, KBDEV_EVENT, ev.type, ev.key,
    164             ev.mods, ev.c);
    165 }
    166 
    167 /*----------------------------------------------------------------------------*/
    168 
    169 static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
    170     usb_multimedia_t *multim_dev)
    171 {
     148
     149        async_exch_t *exch = async_exchange_begin(multim_dev->console_sess);
     150        if (exch != NULL) {
     151                async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
     152                async_exchange_end(exch);
     153        } else {
     154                usb_log_warning("Failed to send multimedia key.\n");
     155        }
     156}
     157/*----------------------------------------------------------------------------*/
     158int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
     159{
     160        if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
     161                return EINVAL;
     162        }
     163
     164        usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
     165
    172166        /* Create the exposed function. */
    173         ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
    174             NAME);
     167        ddf_fun_t *fun = ddf_fun_create(
     168            hid_dev->usb_dev->ddf_dev, fun_exposed, NAME);
    175169        if (fun == NULL) {
    176170                usb_log_error("Could not create DDF function node.\n");
    177171                return ENOMEM;
    178172        }
    179        
     173
    180174        fun->ops = &multimedia_ops;
    181         fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
    182        
     175
     176        usb_multimedia_t *multim_dev =
     177            ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t));
     178        if (multim_dev == NULL) {
     179                ddf_fun_destroy(fun);
     180                return ENOMEM;
     181        }
     182
     183        multim_dev->console_sess = NULL;
     184
     185        //todo Autorepeat?
     186
    183187        int rc = ddf_fun_bind(fun);
    184188        if (rc != EOK) {
    185189                usb_log_error("Could not bind DDF function: %s.\n",
    186190                    str_error(rc));
    187                 // TODO: Can / should I destroy the DDF function?
    188191                ddf_fun_destroy(fun);
    189192                return rc;
    190193        }
    191        
    192         usb_log_debug("%s function created (handle: %" PRIun ").\n",
    193             NAME, fun->handle);
    194        
     194
     195        usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
     196            fun->handle);
     197
    195198        rc = ddf_fun_add_to_category(fun, "keyboard");
    196199        if (rc != EOK) {
     
    198201                    "Could not add DDF function to category 'keyboard': %s.\n",
    199202                    str_error(rc));
    200                 // TODO: Can / should I destroy the DDF function?
    201                 ddf_fun_destroy(fun);
     203                if (ddf_fun_unbind(fun) != EOK) {
     204                        usb_log_error("Failed to unbind %s, won't destroy.\n",
     205                            fun->name);
     206                } else {
     207                        ddf_fun_destroy(fun);
     208                }
    202209                return rc;
    203210        }
    204        
     211
     212        /* Save the KBD device structure into the HID device structure. */
     213        *data = fun;
     214
     215        usb_log_debug(NAME " HID/multimedia structure initialized.\n");
    205216        return EOK;
    206217}
    207 
    208 /*----------------------------------------------------------------------------*/
    209 
    210 int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
    211 {
    212         if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
    213                 return EINVAL; /*! @todo Other return code? */
    214         }
    215        
    216         usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
    217        
    218         usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
    219             sizeof(usb_multimedia_t));
    220         if (multim_dev == NULL) {
    221                 return ENOMEM;
    222         }
    223        
    224         multim_dev->console_phone = -1;
    225        
    226         /*! @todo Autorepeat */
    227        
    228         // save the KBD device structure into the HID device structure
    229         *data = multim_dev;
    230        
    231         usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
    232        
    233         int rc = usb_multimedia_create_function(hid_dev, multim_dev);
    234         if (rc != EOK)
    235                 return rc;
    236        
    237         usb_log_debug(NAME " HID/multimedia structure initialized.\n");
    238        
    239         return EOK;
    240 }
    241 
    242 /*----------------------------------------------------------------------------*/
    243 
     218/*----------------------------------------------------------------------------*/
    244219void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
    245220{
    246         if (hid_dev == NULL) {
    247                 return;
    248         }
    249        
    250         if (data != NULL) {
    251                 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
    252                 // hangup phone to the console
    253                 async_obsolete_hangup(multim_dev->console_phone);
    254         }
    255 }
    256 
    257 /*----------------------------------------------------------------------------*/
    258 
     221        ddf_fun_t *fun = data;
     222        if (fun != NULL && fun->driver_data != NULL) {
     223                usb_multimedia_t *multim_dev = fun->driver_data;
     224                /* Hangup session to the console */
     225                if (multim_dev->console_sess)
     226                        async_hangup(multim_dev->console_sess);
     227                if (ddf_fun_unbind(fun) != EOK) {
     228                        usb_log_error("Failed to unbind %s, won't destroy.\n",
     229                            fun->name);
     230                } else {
     231                        usb_log_debug2("%s unbound.\n", fun->name);
     232                        /* This frees multim_dev too as it was stored in
     233                         * fun->data */
     234                        ddf_fun_destroy(fun);
     235                }
     236        } else {
     237                usb_log_error(
     238                    "Failed to deinit multimedia subdriver, data missing.\n");
     239        }
     240}
     241/*----------------------------------------------------------------------------*/
    259242bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
    260243{
    261244        // TODO: checks
    262         if (hid_dev == NULL || data == NULL) {
     245        ddf_fun_t *fun = data;
     246        if (hid_dev == NULL || fun == NULL || fun->driver_data == NULL) {
    263247                return false;
    264248        }
    265249
    266         usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
    267        
     250        usb_multimedia_t *multim_dev = fun->driver_data;
     251
    268252        usb_hid_report_path_t *path = usb_hid_report_path();
    269         usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
     253        if (path == NULL)
     254                return true; /* This might be a temporary failure. */
     255
     256        int ret =
     257            usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
     258        if (ret != EOK) {
     259                usb_hid_report_path_free(path);
     260                return true; /* This might be a temporary failure. */
     261        }
    270262
    271263        usb_hid_report_path_set_report_id(path, hid_dev->report_id);
    272264
    273265        usb_hid_report_field_t *field = usb_hid_report_get_sibling(
    274             hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
    275             | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
     266            &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
     267            | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
    276268            USB_HID_REPORT_TYPE_INPUT);
    277269
    278         /*! @todo Is this iterating OK if done multiple times?
    279          *  @todo The parsing is not OK
    280          */
     270        //FIXME Is this iterating OK if done multiple times?
     271        //FIXME The parsing is not OK. (what's wrong?)
    281272        while (field != NULL) {
    282                 if(field->value != 0) {
    283                         usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", 
     273                if (field->value != 0) {
     274                        usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
    284275                            field->value, field->usage);
    285                         unsigned int key =
     276                        const unsigned key =
    286277                            usb_multimedia_map_usage(field->usage);
    287                         const char *key_str = 
     278                        const char *key_str =
    288279                            usbhid_multimedia_usage_to_str(field->usage);
    289280                        usb_log_info("Pressed key: %s\n", key_str);
    290                         usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
    291                                                key);
     281                        usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
    292282                }
    293                
     283
    294284                field = usb_hid_report_get_sibling(
    295                     hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
    296                     | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
     285                    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
     286                    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
    297287                    USB_HID_REPORT_TYPE_INPUT);
    298         }       
     288        }
    299289
    300290        usb_hid_report_path_free(path);
    301        
     291
    302292        return true;
    303293}
    304 
    305294/**
    306295 * @}
Note: See TracChangeset for help on using the changeset viewer.