Changes in uspace/drv/bus/usb/usbhid/multimedia/multimedia.c [a0c05e7:1dc4a5e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
ra0c05e7 r1dc4a5e 47 47 #include <errno.h> 48 48 #include <async.h> 49 #include <async_obsolete.h> 49 50 #include <str_error.h> 50 51 … … 52 53 #include <io/console.h> 53 54 54 #define NAME "multimedia-keys" 55 // FIXME: remove this header 56 #include <abi/ipc/methods.h> 57 58 #define NAME "multimedia-keys" 55 59 56 60 /*----------------------------------------------------------------------------*/ … … 64 68 //int32_t *keys; 65 69 /** Count of stored keys (i.e. number of keys in the report). */ 66 //size_t key_count; 67 /** IPC sessionto 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; 69 73 } usb_multimedia_t; 70 74 71 75 72 76 /*----------------------------------------------------------------------------*/ 73 /** 77 /** 74 78 * Default handler for IPC methods not handled by DDF. 75 79 * 76 80 * 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 for81 * assumes the caller is the console and thus it stores IPC phone to it for 78 82 * later use by the driver to notify about key events. 79 83 * … … 86 90 { 87 91 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) { 89 98 async_answer_0(icallid, EINVAL); 90 99 return; 91 100 } 92 101 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) { 104 106 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 109 121 static ddf_dev_ops_t multimedia_ops = { 110 122 .default_handler = default_connection_handler 111 123 }; 124 112 125 /*----------------------------------------------------------------------------*/ 113 126 /** … … 121 134 * sends also these keys to application (otherwise it cannot use those 122 135 * keys at all). 123 * 124 * @param hid_dev 125 * @param multim_dev126 * @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: 127 140 * KEY_PRESS, KEY_RELEASE 128 141 * @param key Key code of the key according to HID Usage Tables. 129 142 */ 130 static void usb_multimedia_push_ev( 143 static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev, 131 144 usb_multimedia_t *multim_dev, int type, unsigned int key) 132 145 { 146 assert(hid_dev != NULL); 133 147 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; 141 155 142 156 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) { 144 158 usb_log_warning( 145 159 "Connection to console not ready, key discarded.\n"); 146 160 return; 147 161 } 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 169 static 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 184 static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev, 185 usb_multimedia_t *multim_dev) 186 { 166 187 /* 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); 169 190 if (fun == NULL) { 170 191 usb_log_error("Could not create DDF function node.\n"); 171 192 return ENOMEM; 172 193 } 173 194 174 195 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 187 198 int rc = ddf_fun_bind(fun); 188 199 if (rc != EOK) { 189 200 usb_log_error("Could not bind DDF function: %s.\n", 190 201 str_error(rc)); 202 // TODO: Can / should I destroy the DDF function? 191 203 ddf_fun_destroy(fun); 192 204 return rc; 193 205 } 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 198 210 rc = ddf_fun_add_to_category(fun, "keyboard"); 199 211 if (rc != EOK) { … … 201 213 "Could not add DDF function to category 'keyboard': %s.\n", 202 214 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); 209 217 return rc; 210 218 } 211 212 /* Save the KBD device structure into the HID device structure. */ 213 *data = fun; 214 219 220 return EOK; 221 } 222 223 /*----------------------------------------------------------------------------*/ 224 225 int 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 215 254 usb_log_debug(NAME " HID/multimedia structure initialized.\n"); 255 216 256 return EOK; 217 257 } 218 /*----------------------------------------------------------------------------*/ 258 259 /*----------------------------------------------------------------------------*/ 260 219 261 void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data) 220 262 { 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 242 275 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data) 243 276 { 244 277 // 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) { 247 279 return false; 248 280 } 249 281 250 usb_multimedia_t *multim_dev = fun->driver_data;251 282 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data; 283 252 284 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); 262 286 263 287 usb_hid_report_path_set_report_id(path, hid_dev->report_id); 264 288 265 289 usb_hid_report_field_t *field = usb_hid_report_get_sibling( 266 &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END267 | 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, 268 292 USB_HID_REPORT_TYPE_INPUT); 269 293 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 */ 272 297 while (field != NULL) { 273 if 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", 275 300 field->value, field->usage); 276 const unsigned key =301 unsigned int key = 277 302 usb_multimedia_map_usage(field->usage); 278 const char *key_str = 303 const char *key_str = 279 304 usbhid_multimedia_usage_to_str(field->usage); 280 305 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); 282 308 } 283 309 284 310 field = usb_hid_report_get_sibling( 285 &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END286 | 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, 287 313 USB_HID_REPORT_TYPE_INPUT); 288 } 314 } 289 315 290 316 usb_hid_report_path_free(path); 291 317 292 318 return true; 293 319 } 320 294 321 /** 295 322 * @}
Note:
See TracChangeset
for help on using the changeset viewer.