00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include "multimedia.h"
00039 #include "../usbhid.h"
00040 #include "keymap.h"
00041
00042 #include <usb/hid/hidparser.h>
00043 #include <usb/debug.h>
00044 #include <usb/hid/usages/core.h>
00045 #include <usb/hid/usages/consumer.h>
00046
00047 #include <errno.h>
00048 #include <str_error.h>
00049
00050 #include <ipc/kbd.h>
00051 #include <io/console.h>
00052
00053 #define NAME "multimedia-keys"
00054
00055
00059 typedef struct usb_multimedia_t {
00061
00063
00065
00067 int console_phone;
00068 } usb_multimedia_t;
00069
00070
00071
00083 static void default_connection_handler(ddf_fun_t *fun,
00084 ipc_callid_t icallid, ipc_call_t *icall)
00085 {
00086 usb_log_debug(NAME " default_connection_handler()\n");
00087
00088 sysarg_t method = IPC_GET_IMETHOD(*icall);
00089
00090 usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
00091
00092
00093 if (multim_dev == NULL) {
00094 async_answer_0(icallid, EINVAL);
00095 return;
00096 }
00097
00098 if (method == IPC_M_CONNECT_TO_ME) {
00099 int callback = IPC_GET_ARG5(*icall);
00100
00101 if (multim_dev->console_phone != -1) {
00102 async_answer_0(icallid, ELIMIT);
00103 return;
00104 }
00105
00106 multim_dev->console_phone = callback;
00107 usb_log_debug(NAME " Saved phone to console: %d\n", callback);
00108 async_answer_0(icallid, EOK);
00109 return;
00110 }
00111
00112 async_answer_0(icallid, EINVAL);
00113 }
00114
00115
00116
00117 static ddf_dev_ops_t multimedia_ops = {
00118 .default_handler = default_connection_handler
00119 };
00120
00121
00139 static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev,
00140 usb_multimedia_t *multim_dev, int type, unsigned int key)
00141 {
00142 assert(hid_dev != NULL);
00143 assert(multim_dev != NULL);
00144
00145 console_event_t ev;
00146
00147 ev.type = type;
00148 ev.key = key;
00149 ev.mods = 0;
00150 ev.c = 0;
00151
00152 usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
00153 if (multim_dev->console_phone < 0) {
00154 usb_log_warning(
00155 "Connection to console not ready, key discarded.\n");
00156 return;
00157 }
00158
00159 async_msg_4(multim_dev->console_phone, KBD_EVENT, ev.type, ev.key,
00160 ev.mods, ev.c);
00161 }
00162
00163
00164
00165 static void usb_multimedia_free(usb_multimedia_t **multim_dev)
00166 {
00167 if (multim_dev == NULL || *multim_dev == NULL) {
00168 return;
00169 }
00170
00171
00172 async_hangup((*multim_dev)->console_phone);
00173
00174 free(*multim_dev);
00175 *multim_dev = NULL;
00176 }
00177
00178
00179
00180 static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
00181 usb_multimedia_t *multim_dev)
00182 {
00183
00184 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
00185 NAME);
00186 if (fun == NULL) {
00187 usb_log_error("Could not create DDF function node.\n");
00188 return ENOMEM;
00189 }
00190
00191 fun->ops = &multimedia_ops;
00192 fun->driver_data = multim_dev;
00193
00194 int rc = ddf_fun_bind(fun);
00195 if (rc != EOK) {
00196 usb_log_error("Could not bind DDF function: %s.\n",
00197 str_error(rc));
00198
00199 ddf_fun_destroy(fun);
00200 return rc;
00201 }
00202
00203 usb_log_debug("%s function created (jandle: %" PRIun ").\n",
00204 NAME, fun->handle);
00205
00206 rc = ddf_fun_add_to_class(fun, "keyboard");
00207 if (rc != EOK) {
00208 usb_log_error(
00209 "Could not add DDF function to class 'keyboard': %s.\n",
00210 str_error(rc));
00211
00212 ddf_fun_destroy(fun);
00213 return rc;
00214 }
00215
00216 return EOK;
00217 }
00218
00219
00220
00221 int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
00222 {
00223 if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
00224 return EINVAL;
00225 }
00226
00227 usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
00228
00229 usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
00230 sizeof(usb_multimedia_t));
00231 if (multim_dev == NULL) {
00232 return ENOMEM;
00233 }
00234
00235 multim_dev->console_phone = -1;
00236
00239
00240 *data = multim_dev;
00241
00242 usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
00243
00244 int rc = usb_multimedia_create_function(hid_dev, multim_dev);
00245 if (rc != EOK) {
00246 usb_multimedia_free(&multim_dev);
00247 return rc;
00248 }
00249
00250 usb_log_debug(NAME " HID/multimedia structure initialized.\n");
00251
00252 return EOK;
00253 }
00254
00255
00256
00257 void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
00258 {
00259 if (hid_dev == NULL) {
00260 return;
00261 }
00262
00263 if (data != NULL) {
00264 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
00265 usb_multimedia_free(&multim_dev);
00266 }
00267 }
00268
00269
00270
00271 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data
00272 )
00273 {
00274
00275 if (hid_dev == NULL || data == NULL) {
00276 return false;
00277 }
00278
00279
00280
00281
00282 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
00283
00284
00285
00286
00287 usb_hid_report_path_t *path = usb_hid_report_path();
00288 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
00302
00303 usb_hid_report_field_t *field = usb_hid_report_get_sibling(
00304 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
00305 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00306 USB_HID_REPORT_TYPE_INPUT);
00307
00311 while (field != NULL) {
00312 if(field->value != 0) {
00313 usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
00314 field->value, field->usage);
00315 unsigned int key =
00316 usb_multimedia_map_usage(field->usage);
00317 const char *key_str =
00318 usbhid_multimedia_usage_to_str(field->usage);
00319 usb_log_info("Pressed key: %s\n", key_str);
00320 usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
00321 key);
00322 }
00323
00324 field = usb_hid_report_get_sibling(
00325 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
00326 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00327 USB_HID_REPORT_TYPE_INPUT);
00328 }
00329
00330 usb_hid_report_path_free(path);
00331
00332 return true;
00333 }
00334