source: mainline/uspace/drv/bus/usb/usbhid/multimedia/multimedia.c@ 940f576

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 940f576 was 5da7199, checked in by Martin Decky <martin@…>, 14 years ago

remove the obsolete async API

  • Property mode set to 100644
File size: 8.7 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 <async.h>
49#include <str_error.h>
50
51#include <ipc/kbdev.h>
52#include <io/console.h>
53
54#define NAME "multimedia-keys"
55
56/*----------------------------------------------------------------------------*/
57/**
58 * Logitech UltraX device type.
59 */
60typedef struct usb_multimedia_t {
61 /** Previously pressed keys (not translated to key codes). */
62 //int32_t *keys_old;
63 /** Currently pressed keys (not translated to key codes). */
64 //int32_t *keys;
65 /** 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;
69} usb_multimedia_t;
70
71
72/*----------------------------------------------------------------------------*/
73/**
74 * Default handler for IPC methods not handled by DDF.
75 *
76 * 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
78 * later use by the driver to notify about key events.
79 *
80 * @param fun Device function handling the call.
81 * @param icallid Call id.
82 * @param icall Call data.
83 */
84static void default_connection_handler(ddf_fun_t *fun,
85 ipc_callid_t icallid, ipc_call_t *icall)
86{
87 usb_log_debug(NAME " default_connection_handler()\n");
88
89 usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
90
91 if (multim_dev == NULL) {
92 async_answer_0(icallid, EINVAL);
93 return;
94 }
95
96 async_sess_t *sess =
97 async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
98 if (sess != NULL) {
99 if (multim_dev->console_sess == NULL) {
100 multim_dev->console_sess = sess;
101 usb_log_debug(NAME " Saved session to console: %p\n",
102 sess);
103 async_answer_0(icallid, EOK);
104 } else
105 async_answer_0(icallid, ELIMIT);
106 } else
107 async_answer_0(icallid, EINVAL);
108}
109
110/*----------------------------------------------------------------------------*/
111
112static ddf_dev_ops_t multimedia_ops = {
113 .default_handler = default_connection_handler
114};
115
116/*----------------------------------------------------------------------------*/
117/**
118 * Processes key events.
119 *
120 * @note This function was copied from AT keyboard driver and modified to suit
121 * USB keyboard.
122 *
123 * @note Lock keys are not sent to the console, as they are completely handled
124 * in the driver. It may, however, be required later that the driver
125 * sends also these keys to application (otherwise it cannot use those
126 * keys at all).
127 *
128 * @param hid_dev
129 * @param lgtch_dev
130 * @param type Type of the event (press / release). Recognized values:
131 * KEY_PRESS, KEY_RELEASE
132 * @param key Key code of the key according to HID Usage Tables.
133 */
134static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev,
135 usb_multimedia_t *multim_dev, int type, unsigned int key)
136{
137 assert(hid_dev != NULL);
138 assert(multim_dev != NULL);
139
140 kbd_event_t ev;
141
142 ev.type = type;
143 ev.key = key;
144 ev.mods = 0;
145 ev.c = 0;
146
147 usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
148 if (multim_dev->console_sess == NULL) {
149 usb_log_warning(
150 "Connection to console not ready, key discarded.\n");
151 return;
152 }
153
154 async_exch_t *exch = async_exchange_begin(multim_dev->console_sess);
155 async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
156 async_exchange_end(exch);
157}
158
159/*----------------------------------------------------------------------------*/
160
161static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
162 usb_multimedia_t *multim_dev)
163{
164 /* Create the exposed function. */
165 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
166 NAME);
167 if (fun == NULL) {
168 usb_log_error("Could not create DDF function node.\n");
169 return ENOMEM;
170 }
171
172 fun->ops = &multimedia_ops;
173 fun->driver_data = multim_dev; // TODO: maybe change to hid_dev->data
174
175 int rc = ddf_fun_bind(fun);
176 if (rc != EOK) {
177 usb_log_error("Could not bind DDF function: %s.\n",
178 str_error(rc));
179 // TODO: Can / should I destroy the DDF function?
180 ddf_fun_destroy(fun);
181 return rc;
182 }
183
184 usb_log_debug("%s function created (handle: %" PRIun ").\n",
185 NAME, fun->handle);
186
187 rc = ddf_fun_add_to_category(fun, "keyboard");
188 if (rc != EOK) {
189 usb_log_error(
190 "Could not add DDF function to category 'keyboard': %s.\n",
191 str_error(rc));
192 // TODO: Can / should I destroy the DDF function?
193 ddf_fun_destroy(fun);
194 return rc;
195 }
196
197 return EOK;
198}
199
200/*----------------------------------------------------------------------------*/
201
202int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
203{
204 if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
205 return EINVAL; /*! @todo Other return code? */
206 }
207
208 usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
209
210 usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
211 sizeof(usb_multimedia_t));
212 if (multim_dev == NULL) {
213 return ENOMEM;
214 }
215
216 multim_dev->console_sess = NULL;
217
218 /*! @todo Autorepeat */
219
220 // save the KBD device structure into the HID device structure
221 *data = multim_dev;
222
223 usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
224
225 int rc = usb_multimedia_create_function(hid_dev, multim_dev);
226 if (rc != EOK)
227 return rc;
228
229 usb_log_debug(NAME " HID/multimedia structure initialized.\n");
230
231 return EOK;
232}
233
234/*----------------------------------------------------------------------------*/
235
236void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
237{
238 if (hid_dev == NULL) {
239 return;
240 }
241
242 if (data != NULL) {
243 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
244 // hangup session to the console
245 async_hangup(multim_dev->console_sess);
246 }
247}
248
249/*----------------------------------------------------------------------------*/
250
251bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
252{
253 // TODO: checks
254 if (hid_dev == NULL || data == NULL) {
255 return false;
256 }
257
258 usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
259
260 usb_hid_report_path_t *path = usb_hid_report_path();
261 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
262
263 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
264
265 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,
268 USB_HID_REPORT_TYPE_INPUT);
269
270 /*! @todo Is this iterating OK if done multiple times?
271 * @todo The parsing is not OK
272 */
273 while (field != NULL) {
274 if(field->value != 0) {
275 usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
276 field->value, field->usage);
277 unsigned int key =
278 usb_multimedia_map_usage(field->usage);
279 const char *key_str =
280 usbhid_multimedia_usage_to_str(field->usage);
281 usb_log_info("Pressed key: %s\n", key_str);
282 usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS,
283 key);
284 }
285
286 field = usb_hid_report_get_sibling(
287 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
288 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
289 USB_HID_REPORT_TYPE_INPUT);
290 }
291
292 usb_hid_report_path_free(path);
293
294 return true;
295}
296
297/**
298 * @}
299 */
Note: See TracBrowser for help on using the repository browser.