Ignore:
File:
1 edited

Legend:

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

    ra0c05e7 r1dc4a5e  
    4747#include <errno.h>
    4848#include <async.h>
     49#include <async_obsolete.h>
    4950#include <str_error.h>
    5051
     
    5253#include <io/console.h>
    5354
    54 #define NAME  "multimedia-keys"
     55// FIXME: remove this header
     56#include <abi/ipc/methods.h>
     57
     58#define NAME "multimedia-keys"
    5559
    5660/*----------------------------------------------------------------------------*/
     
    6468        //int32_t *keys;
    6569        /** Count of stored keys (i.e. number of keys in the report). */
    66         //size_t key_count;
    67         /** IPC session to the console device (for sending key events). */
    68         async_sess_t *console_sess;
     70        //size_t key_count;     
     71        /** IPC phone to the console device (for sending key events). */
     72        int console_phone;
    6973} usb_multimedia_t;
    7074
    7175
    7276/*----------------------------------------------------------------------------*/
    73 /**
     77/** 
    7478 * Default handler for IPC methods not handled by DDF.
    7579 *
    7680 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
    77  * assumes the caller is the console and thus it stores IPC session to it for
     81 * assumes the caller is the console and thus it stores IPC phone to it for
    7882 * later use by the driver to notify about key events.
    7983 *
     
    8690{
    8791        usb_log_debug(NAME " default_connection_handler()\n");
    88         if (fun == NULL || fun->driver_data == NULL) {
     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) {
    8998                async_answer_0(icallid, EINVAL);
    9099                return;
    91100        }
    92101
    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
     102        if (method == IPC_M_CONNECT_TO_ME) {
     103                int callback = IPC_GET_ARG5(*icall);
     104
     105                if (multim_dev->console_phone != -1) {
    104106                        async_answer_0(icallid, ELIMIT);
    105         } else
    106                 async_answer_0(icallid, EINVAL);
    107 }
    108 /*----------------------------------------------------------------------------*/
     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
    109121static ddf_dev_ops_t multimedia_ops = {
    110122        .default_handler = default_connection_handler
    111123};
     124
    112125/*----------------------------------------------------------------------------*/
    113126/**
     
    121134 *       sends also these keys to application (otherwise it cannot use those
    122135 *       keys at all).
    123  *
    124  * @param hid_dev
    125  * @param multim_dev
    126  * @param type Type of the event (press / release). Recognized values:
     136 * 
     137 * @param hid_dev 
     138 * @param lgtch_dev
     139 * @param type Type of the event (press / release). Recognized values: 
    127140 *             KEY_PRESS, KEY_RELEASE
    128141 * @param key Key code of the key according to HID Usage Tables.
    129142 */
    130 static void usb_multimedia_push_ev(
     143static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev,
    131144    usb_multimedia_t *multim_dev, int type, unsigned int key)
    132145{
     146        assert(hid_dev != NULL);
    133147        assert(multim_dev != NULL);
    134 
    135         const kbd_event_t ev = {
    136                 .type = type,
    137                 .key = key,
    138                 .mods = 0,
    139                 .c = 0,
    140         };
     148       
     149        kbd_event_t ev;
     150       
     151        ev.type = type;
     152        ev.key = key;
     153        ev.mods = 0;
     154        ev.c = 0;
    141155
    142156        usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
    143         if (multim_dev->console_sess == NULL) {
     157        if (multim_dev->console_phone < 0) {
    144158                usb_log_warning(
    145159                    "Connection to console not ready, key discarded.\n");
    146160                return;
    147161        }
    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 /*----------------------------------------------------------------------------*/
    158 int 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 
     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
     169static void usb_multimedia_free(usb_multimedia_t **multim_dev)
     170{
     171        if (multim_dev == NULL || *multim_dev == NULL) {
     172                return;
     173        }
     174       
     175        // hangup phone to the console
     176        async_obsolete_hangup((*multim_dev)->console_phone);
     177
     178        free(*multim_dev);
     179        *multim_dev = NULL;
     180}
     181
     182/*----------------------------------------------------------------------------*/
     183
     184static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
     185    usb_multimedia_t *multim_dev)
     186{
    166187        /* Create the exposed function. */
    167         ddf_fun_t *fun = ddf_fun_create(
    168             hid_dev->usb_dev->ddf_dev, fun_exposed, NAME);
     188        ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
     189            NAME);
    169190        if (fun == NULL) {
    170191                usb_log_error("Could not create DDF function node.\n");
    171192                return ENOMEM;
    172193        }
    173 
     194       
    174195        fun->ops = &multimedia_ops;
    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 
     196        fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
     197       
    187198        int rc = ddf_fun_bind(fun);
    188199        if (rc != EOK) {
    189200                usb_log_error("Could not bind DDF function: %s.\n",
    190201                    str_error(rc));
     202                // TODO: Can / should I destroy the DDF function?
    191203                ddf_fun_destroy(fun);
    192204                return rc;
    193205        }
    194 
    195         usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
    196             fun->handle);
    197 
     206       
     207        usb_log_debug("%s function created (handle: %" PRIun ").\n",
     208            NAME, fun->handle);
     209       
    198210        rc = ddf_fun_add_to_category(fun, "keyboard");
    199211        if (rc != EOK) {
     
    201213                    "Could not add DDF function to category 'keyboard': %s.\n",
    202214                    str_error(rc));
    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                 }
     215                // TODO: Can / should I destroy the DDF function?
     216                ddf_fun_destroy(fun);
    209217                return rc;
    210218        }
    211 
    212         /* Save the KBD device structure into the HID device structure. */
    213         *data = fun;
    214 
     219       
     220        return EOK;
     221}
     222
     223/*----------------------------------------------------------------------------*/
     224
     225int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
     226{
     227        if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
     228                return EINVAL; /*! @todo Other return code? */
     229        }
     230       
     231        usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
     232       
     233        usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
     234            sizeof(usb_multimedia_t));
     235        if (multim_dev == NULL) {
     236                return ENOMEM;
     237        }
     238       
     239        multim_dev->console_phone = -1;
     240       
     241        /*! @todo Autorepeat */
     242       
     243        // save the KBD device structure into the HID device structure
     244        *data = multim_dev;
     245       
     246        usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
     247       
     248        int rc = usb_multimedia_create_function(hid_dev, multim_dev);
     249        if (rc != EOK) {
     250                usb_multimedia_free(&multim_dev);
     251                return rc;
     252        }
     253       
    215254        usb_log_debug(NAME " HID/multimedia structure initialized.\n");
     255       
    216256        return EOK;
    217257}
    218 /*----------------------------------------------------------------------------*/
     258
     259/*----------------------------------------------------------------------------*/
     260
    219261void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
    220262{
    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 /*----------------------------------------------------------------------------*/
     263        if (hid_dev == NULL) {
     264                return;
     265        }
     266       
     267        if (data != NULL) {
     268                usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
     269                usb_multimedia_free(&multim_dev);
     270        }
     271}
     272
     273/*----------------------------------------------------------------------------*/
     274
    242275bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
    243276{
    244277        // TODO: checks
    245         ddf_fun_t *fun = data;
    246         if (hid_dev == NULL || fun == NULL || fun->driver_data == NULL) {
     278        if (hid_dev == NULL || data == NULL) {
    247279                return false;
    248280        }
    249281
    250         usb_multimedia_t *multim_dev = fun->driver_data;
    251 
     282        usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
     283       
    252284        usb_hid_report_path_t *path = usb_hid_report_path();
    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         }
     285        usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
    262286
    263287        usb_hid_report_path_set_report_id(path, hid_dev->report_id);
    264288
    265289        usb_hid_report_field_t *field = usb_hid_report_get_sibling(
    266             &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
    267             | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
     290            hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
     291            | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
    268292            USB_HID_REPORT_TYPE_INPUT);
    269293
    270         //FIXME Is this iterating OK if done multiple times?
    271         //FIXME The parsing is not OK. (what's wrong?)
     294        /*! @todo Is this iterating OK if done multiple times?
     295         *  @todo The parsing is not OK
     296         */
    272297        while (field != NULL) {
    273                 if (field->value != 0) {
    274                         usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
     298                if(field->value != 0) {
     299                        usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", 
    275300                            field->value, field->usage);
    276                         const unsigned key =
     301                        unsigned int key =
    277302                            usb_multimedia_map_usage(field->usage);
    278                         const char *key_str =
     303                        const char *key_str = 
    279304                            usbhid_multimedia_usage_to_str(field->usage);
    280305                        usb_log_info("Pressed key: %s\n", key_str);
    281                         usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
     306                        usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
     307                                               key);
    282308                }
    283 
     309               
    284310                field = usb_hid_report_get_sibling(
    285                     &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
    286                     | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
     311                    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
     312                    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
    287313                    USB_HID_REPORT_TYPE_INPUT);
    288         }
     314        }       
    289315
    290316        usb_hid_report_path_free(path);
    291 
     317       
    292318        return true;
    293319}
     320
    294321/**
    295322 * @}
Note: See TracChangeset for help on using the changeset viewer.