source: mainline/uspace/drv/usbhid/multimedia/multimedia.c@ 3e95cd7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3e95cd7 was 3e95cd7, checked in by Lubos Slovak <lubos.slovak@…>, 15 years ago

Removed unused things from multimedia driver.

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Copyright (c) 2011 Lubos Slovak, Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbhid
30 * @{
31 */
32/**
33 * @file
34 * USB Keyboard multimedia keys subdriver.
35 */
36
37
38#include "multimedia.h"
39#include "../usbhid.h"
40#include "keymap.h"
41
42#include <usb/hid/hidparser.h>
43#include <usb/debug.h>
44#include <usb/hid/usages/core.h>
45#include <usb/hid/usages/consumer.h>
46
47#include <errno.h>
48#include <str_error.h>
49
50#include <ipc/kbd.h>
51#include <io/console.h>
52
53#define NAME "multimedia-keys"
54
55/*----------------------------------------------------------------------------*/
56/**
57 * Logitech UltraX device type.
58 */
59typedef struct usb_multimedia_t {
60 /** Previously pressed keys (not translated to key codes). */
61 //int32_t *keys_old;
62 /** Currently pressed keys (not translated to key codes). */
63 //int32_t *keys;
64 /** Count of stored keys (i.e. number of keys in the report). */
65 //size_t key_count;
66 /** IPC phone to the console device (for sending key events). */
67 int console_phone;
68} usb_multimedia_t;
69
70
71/*----------------------------------------------------------------------------*/
72/**
73 * Default handler for IPC methods not handled by DDF.
74 *
75 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
76 * assumes the caller is the console and thus it stores IPC phone to it for
77 * later use by the driver to notify about key events.
78 *
79 * @param fun Device function handling the call.
80 * @param icallid Call id.
81 * @param icall Call data.
82 */
83static void default_connection_handler(ddf_fun_t *fun,
84 ipc_callid_t icallid, ipc_call_t *icall)
85{
86 usb_log_debug(NAME " default_connection_handler()\n");
87
88 sysarg_t method = IPC_GET_IMETHOD(*icall);
89
90 usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
91 //usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
92
93 if (multim_dev == NULL) {
94 async_answer_0(icallid, EINVAL);
95 return;
96 }
97
98 if (method == IPC_M_CONNECT_TO_ME) {
99 int callback = IPC_GET_ARG5(*icall);
100
101 if (multim_dev->console_phone != -1) {
102 async_answer_0(icallid, ELIMIT);
103 return;
104 }
105
106 multim_dev->console_phone = callback;
107 usb_log_debug(NAME " Saved phone to console: %d\n", callback);
108 async_answer_0(icallid, EOK);
109 return;
110 }
111
112 async_answer_0(icallid, EINVAL);
113}
114
115/*----------------------------------------------------------------------------*/
116
117static ddf_dev_ops_t multimedia_ops = {
118 .default_handler = default_connection_handler
119};
120
121/*----------------------------------------------------------------------------*/
122/**
123 * Processes key events.
124 *
125 * @note This function was copied from AT keyboard driver and modified to suit
126 * USB keyboard.
127 *
128 * @note Lock keys are not sent to the console, as they are completely handled
129 * in the driver. It may, however, be required later that the driver
130 * sends also these keys to application (otherwise it cannot use those
131 * keys at all).
132 *
133 * @param hid_dev
134 * @param lgtch_dev
135 * @param type Type of the event (press / release). Recognized values:
136 * KEY_PRESS, KEY_RELEASE
137 * @param key Key code of the key according to HID Usage Tables.
138 */
139static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev,
140 usb_multimedia_t *multim_dev, int type, unsigned int key)
141{
142 assert(hid_dev != NULL);
143 assert(multim_dev != NULL);
144
145// usb_multimedia_t *multim_dev = (usb_multimedia_t *)hid_dev->data;
146
147 console_event_t ev;
148
149 ev.type = type;
150 ev.key = key;
151 ev.mods = 0;
152 ev.c = 0;
153
154 usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
155 if (multim_dev->console_phone < 0) {
156 usb_log_warning(
157 "Connection to console not ready, key discarded.\n");
158 return;
159 }
160
161 async_msg_4(multim_dev->console_phone, KBD_EVENT, ev.type, ev.key,
162 ev.mods, ev.c);
163}
164
165/*----------------------------------------------------------------------------*/
166
167static void usb_multimedia_free(usb_multimedia_t **multim_dev)
168{
169 if (multim_dev == NULL || *multim_dev == NULL) {
170 return;
171 }
172
173 // hangup phone to the console
174 async_hangup((*multim_dev)->console_phone);
175
176 // free all buffers
177// if ((*multim_dev)->keys != NULL) {
178// free((*multim_dev)->keys);
179// }
180// if ((*multim_dev)->keys_old != NULL) {
181// free((*multim_dev)->keys_old);
182// }
183
184 free(*multim_dev);
185 *multim_dev = NULL;
186}
187
188/*----------------------------------------------------------------------------*/
189
190static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
191 usb_multimedia_t *multim_dev)
192{
193 /* Create the function exposed under /dev/devices. */
194 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
195 NAME);
196 if (fun == NULL) {
197 usb_log_error("Could not create DDF function node.\n");
198 return ENOMEM;
199 }
200
201 fun->ops = &multimedia_ops;
202 fun->driver_data = multim_dev; // TODO: maybe change to hid_dev->data
203
204 int rc = ddf_fun_bind(fun);
205 if (rc != EOK) {
206 usb_log_error("Could not bind DDF function: %s.\n",
207 str_error(rc));
208 // TODO: Can / should I destroy the DDF function?
209 ddf_fun_destroy(fun);
210 return rc;
211 }
212
213 usb_log_debug("%s function created. Handle: %d\n", NAME, fun->handle);
214
215 rc = ddf_fun_add_to_class(fun, "keyboard");
216 if (rc != EOK) {
217 usb_log_error(
218 "Could not add DDF function to class 'keyboard': %s.\n",
219 str_error(rc));
220 // TODO: Can / should I destroy the DDF function?
221 ddf_fun_destroy(fun);
222 return rc;
223 }
224
225 return EOK;
226}
227
228/*----------------------------------------------------------------------------*/
229
230int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
231{
232 if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
233 return EINVAL; /*! @todo Other return code? */
234 }
235
236 usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
237
238 usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
239 sizeof(usb_multimedia_t));
240 if (multim_dev == NULL) {
241 return ENOMEM;
242 }
243
244 multim_dev->console_phone = -1;
245
246// usb_hid_report_path_t *path = usb_hid_report_path();
247// usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
248
249// usb_hid_report_path_set_report_id(path, 1);
250
251// multim_dev->key_count = usb_hid_report_size(
252// hid_dev->report, 1, USB_HID_REPORT_TYPE_INPUT);
253
254// usb_hid_report_path_free(path);
255
256// usb_log_debug(NAME " Size of the input report: %zu\n",
257// multim_dev->key_count);
258
259// multim_dev->keys = (int32_t *)calloc(multim_dev->key_count,
260// sizeof(int32_t));
261
262// if (multim_dev->keys == NULL) {
263// usb_log_fatal("No memory!\n");
264// free(multim_dev);
265// return ENOMEM;
266// }
267
268// multim_dev->keys_old =
269// (int32_t *)calloc(multim_dev->key_count, sizeof(int32_t));
270
271// if (multim_dev->keys_old == NULL) {
272// usb_log_fatal("No memory!\n");
273// free(multim_dev->keys);
274// free(multim_dev);
275// return ENOMEM;
276// }
277
278 /*! @todo Autorepeat */
279
280 // save the KBD device structure into the HID device structure
281 *data = multim_dev;
282
283 usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
284
285 int rc = usb_multimedia_create_function(hid_dev, multim_dev);
286 if (rc != EOK) {
287 usb_multimedia_free(&multim_dev);
288 return rc;
289 }
290
291 usb_log_debug(NAME " HID/multimedia structure initialized.\n");
292
293 return EOK;
294}
295
296/*----------------------------------------------------------------------------*/
297
298void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
299{
300 if (hid_dev == NULL) {
301 return;
302 }
303
304 if (data != NULL) {
305 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
306 usb_multimedia_free(&multim_dev);
307 }
308}
309
310/*----------------------------------------------------------------------------*/
311
312bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data,
313 uint8_t *buffer, size_t buffer_size)
314{
315 // TODO: checks
316
317 usb_log_debug(NAME " usb_lgtch_polling_callback(%p, %p, %zu)\n",
318 hid_dev, buffer, buffer_size);
319
320 if (data == NULL) {
321 return EINVAL; // TODO: other error code?
322 }
323
324 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
325
326 usb_log_debug(NAME " Calling usb_hid_parse_report() with "
327 "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));
328
329 usb_hid_report_path_t *path = usb_hid_report_path();
330 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
331
332 uint8_t report_id;
333
334 int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size,
335 &report_id);
336
337 if (rc != EOK) {
338 usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n",
339 str_error(rc));
340 return true;
341 }
342
343 usb_hid_report_path_set_report_id(path, report_id);
344
345 usb_hid_report_field_t *field = usb_hid_report_get_sibling(
346 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
347 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
348 USB_HID_REPORT_TYPE_INPUT);
349
350// unsigned int key;
351
352 /*! @todo Is this iterating OK if done multiple times?
353 * @todo The parsing is not OK
354 */
355 while (field != NULL) {
356 if(field->value != 0) {
357 usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
358 field->value, field->usage);
359 unsigned int key =
360 usb_multimedia_map_usage(field->usage);
361 const char *key_str =
362 usbhid_multimedia_usage_to_str(field->usage);
363 usb_log_info("Pressed key: %s\n", key_str);
364 usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
365 key);
366 }
367
368 field = usb_hid_report_get_sibling(
369 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
370 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
371 USB_HID_REPORT_TYPE_INPUT);
372 }
373
374 usb_hid_report_path_free(path);
375
376 return true;
377}
378
379/**
380 * @}
381 */
Note: See TracBrowser for help on using the repository browser.