Ignore:
File:
1 edited

Legend:

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

    ra0c05e7 r5f6e25e  
    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 int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
     170    usb_multimedia_t *multim_dev)
     171{
    166172        /* Create the exposed function. */
    167         ddf_fun_t *fun = ddf_fun_create(
    168             hid_dev->usb_dev->ddf_dev, fun_exposed, NAME);
     173        ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
     174            NAME);
    169175        if (fun == NULL) {
    170176                usb_log_error("Could not create DDF function node.\n");
    171177                return ENOMEM;
    172178        }
    173 
     179       
    174180        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 
     181        fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
     182       
    187183        int rc = ddf_fun_bind(fun);
    188184        if (rc != EOK) {
    189185                usb_log_error("Could not bind DDF function: %s.\n",
    190186                    str_error(rc));
     187                // TODO: Can / should I destroy the DDF function?
    191188                ddf_fun_destroy(fun);
    192189                return rc;
    193190        }
    194 
    195         usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
    196             fun->handle);
    197 
     191       
     192        usb_log_debug("%s function created (handle: %" PRIun ").\n",
     193            NAME, fun->handle);
     194       
    198195        rc = ddf_fun_add_to_category(fun, "keyboard");
    199196        if (rc != EOK) {
     
    201198                    "Could not add DDF function to category 'keyboard': %s.\n",
    202199                    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                 }
     200                // TODO: Can / should I destroy the DDF function?
     201                ddf_fun_destroy(fun);
    209202                return rc;
    210203        }
    211 
    212         /* Save the KBD device structure into the HID device structure. */
    213         *data = fun;
    214 
     204       
     205        return EOK;
     206}
     207
     208/*----------------------------------------------------------------------------*/
     209
     210int 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       
    215237        usb_log_debug(NAME " HID/multimedia structure initialized.\n");
     238       
    216239        return EOK;
    217240}
    218 /*----------------------------------------------------------------------------*/
     241
     242/*----------------------------------------------------------------------------*/
     243
    219244void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
    220245{
    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 /*----------------------------------------------------------------------------*/
     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
    242259bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
    243260{
    244261        // TODO: checks
    245         ddf_fun_t *fun = data;
    246         if (hid_dev == NULL || fun == NULL || fun->driver_data == NULL) {
     262        if (hid_dev == NULL || data == NULL) {
    247263                return false;
    248264        }
    249265
    250         usb_multimedia_t *multim_dev = fun->driver_data;
    251 
     266        usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
     267       
    252268        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         }
     269        usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
    262270
    263271        usb_hid_report_path_set_report_id(path, hid_dev->report_id);
    264272
    265273        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,
     274            hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
     275            | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
    268276            USB_HID_REPORT_TYPE_INPUT);
    269277
    270         //FIXME Is this iterating OK if done multiple times?
    271         //FIXME The parsing is not OK. (what's wrong?)
     278        /*! @todo Is this iterating OK if done multiple times?
     279         *  @todo The parsing is not OK
     280         */
    272281        while (field != NULL) {
    273                 if (field->value != 0) {
    274                         usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
     282                if(field->value != 0) {
     283                        usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", 
    275284                            field->value, field->usage);
    276                         const unsigned key =
     285                        unsigned int key =
    277286                            usb_multimedia_map_usage(field->usage);
    278                         const char *key_str =
     287                        const char *key_str = 
    279288                            usbhid_multimedia_usage_to_str(field->usage);
    280289                        usb_log_info("Pressed key: %s\n", key_str);
    281                         usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
     290                        usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
     291                                               key);
    282292                }
    283 
     293               
    284294                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,
     295                    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
     296                    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
    287297                    USB_HID_REPORT_TYPE_INPUT);
    288         }
     298        }       
    289299
    290300        usb_hid_report_path_free(path);
    291 
     301       
    292302        return true;
    293303}
     304
    294305/**
    295306 * @}
Note: See TracChangeset for help on using the changeset viewer.