source: mainline/uspace/drv/usbkbd/main.c@ 64861b8

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

Disabled last large debug output in usbkbd

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[c7137738]1/*
2 * Copyright (c) 2010 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#include <usb/usbdrv.h>
29#include <driver.h>
[2e15ac40]30#include <ipc/driver.h>
[700af62]31#include <ipc/kbd.h>
32#include <io/keycode.h>
33#include <io/console.h>
[c7137738]34#include <errno.h>
[2e15ac40]35#include <fibril.h>
36#include <usb/classes/hid.h>
[243cb86]37#include <usb/classes/hidparser.h>
38#include <usb/devreq.h>
[dafab9e0]39#include <usb/descriptor.h>
[ca038b4]40#include "descparser.h"
[45019865]41#include "descdump.h"
[c7137738]42
[91db50ac]43#define BUFFER_SIZE 32
[2e15ac40]44#define NAME "usbkbd"
45
[1b29d6fa]46#define GUESSED_POLL_ENDPOINT 1
[2e15ac40]47
[700af62]48static void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
49static device_ops_t keyboard_ops = {
50 .default_handler = default_connection_handler
51};
52
53static int console_callback_phone = -1;
54
55/** Default handler for IPC methods not handled by DDF.
56 *
57 * @param dev Device handling the call.
58 * @param icallid Call id.
59 * @param icall Call data.
60 */
61void default_connection_handler(device_t *dev,
62 ipc_callid_t icallid, ipc_call_t *icall)
63{
64 sysarg_t method = IPC_GET_IMETHOD(*icall);
65
66 if (method == IPC_M_CONNECT_TO_ME) {
67 int callback = IPC_GET_ARG5(*icall);
68
69 if (console_callback_phone != -1) {
70 ipc_answer_0(icallid, ELIMIT);
71 return;
72 }
73
74 console_callback_phone = callback;
75 ipc_answer_0(icallid, EOK);
76 return;
77 }
78
79 ipc_answer_0(icallid, EINVAL);
80}
81
[38c5dfa]82#if 0
[700af62]83static void send_key(int key, int type, wchar_t c) {
84 async_msg_4(console_callback_phone, KBD_EVENT, type, key,
85 KM_NUM_LOCK, c);
86}
[38c5dfa]87#endif
[700af62]88
[243cb86]89/*
90 * Callbacks for parser
91 */
[0a9ea4a]92static void usbkbd_process_keycodes(const uint8_t *key_codes, size_t count,
93 uint8_t modifiers, void *arg)
[91db50ac]94{
[692f13e4]95 printf("Got keys: ");
96 unsigned i;
97 for (i = 0; i < count; ++i) {
98 printf("%d ", key_codes[i]);
99 }
100 printf("\n");
[243cb86]101}
[0e126be7]102
[243cb86]103/*
104 * Kbd functions
105 */
[6986418]106static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev)
107{
108 // iterate over all configurations and interfaces
109 // TODO: more configurations!!
110 unsigned i;
111 for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) {
112 // TODO: endianness
113 uint16_t length =
114 kbd_dev->conf->interfaces[i].hid_desc.report_desc_info.length;
[45019865]115 size_t actual_size = 0;
[6986418]116
117 // allocate space for the report descriptor
118 kbd_dev->conf->interfaces[i].report_desc = (uint8_t *)malloc(length);
119
[45019865]120 // get the descriptor from the device
121 int rc = usb_drv_req_get_descriptor(kbd_dev->device->parent_phone,
122 kbd_dev->address, USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT,
123 0, i, kbd_dev->conf->interfaces[i].report_desc, length,
124 &actual_size);
125
126 if (rc != EOK) {
127 return rc;
128 }
129
130 assert(actual_size == length);
131
[fbddf94]132 //dump_hid_class_descriptor(0, USB_DESCTYPE_HID_REPORT,
133 // kbd_dev->conf->interfaces[i].report_desc, length);
[6986418]134 }
[45019865]135
136 return EOK;
[6986418]137}
138
[ca038b4]139static int usbkbd_process_descriptors(usb_hid_dev_kbd_t *kbd_dev)
[243cb86]140{
[ca038b4]141 // get the first configuration descriptor (TODO: parse also other!)
[dafab9e0]142 usb_standard_configuration_descriptor_t config_desc;
143
144 int rc = usb_drv_req_get_bare_configuration_descriptor(
145 kbd_dev->device->parent_phone, kbd_dev->address, 0, &config_desc);
146
147 if (rc != EOK) {
148 return rc;
149 }
150
151 // prepare space for all underlying descriptors
152 uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length);
153 if (descriptors == NULL) {
154 return ENOMEM;
155 }
156
157 size_t transferred = 0;
158 // get full configuration descriptor
159 rc = usb_drv_req_get_full_configuration_descriptor(
160 kbd_dev->device->parent_phone, kbd_dev->address, 0, descriptors,
161 config_desc.total_length, &transferred);
162
[91db50ac]163 if (rc != EOK) {
[243cb86]164 return rc;
[91db50ac]165 }
[dafab9e0]166 if (transferred != config_desc.total_length) {
167 return ELIMIT;
168 }
169
[ca038b4]170 kbd_dev->conf = (usb_hid_configuration_t *)calloc(1,
171 sizeof(usb_hid_configuration_t));
172 if (kbd_dev->conf == NULL) {
173 free(descriptors);
174 return ENOMEM;
175 }
176
177 rc = usbkbd_parse_descriptors(descriptors, transferred, kbd_dev->conf);
[dafab9e0]178 free(descriptors);
[45019865]179 if (rc != EOK) {
180 printf("Problem with parsing standard descriptors.\n");
181 return rc;
182 }
[6986418]183
184 // get and report descriptors
185 rc = usbkbd_get_report_descriptor(kbd_dev);
[45019865]186 if (rc != EOK) {
187 printf("Problem with parsing HID REPORT descriptor.\n");
188 return rc;
189 }
[243cb86]190
[76cb03c]191 //usbkbd_print_config(kbd_dev->conf);
[0a9ea4a]192
193 /*
194 * TODO:
195 * 1) select one configuration (lets say the first)
196 * 2) how many interfaces?? how to select one??
197 * ("The default setting for an interface is always alternate setting zero.")
198 * 3) find endpoint which is IN and INTERRUPT (parse), save its number
199 * as the endpoint for polling
200 */
[1f383dde]201
[45019865]202 return EOK;
[243cb86]203}
[91db50ac]204
[2e15ac40]205static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
206{
[ca038b4]207 usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)calloc(1,
208 sizeof(usb_hid_dev_kbd_t));
[2e15ac40]209
210 if (kbd_dev == NULL) {
211 fprintf(stderr, NAME ": No memory!\n");
212 return NULL;
213 }
214
215 kbd_dev->device = dev;
216
[101ef25c]217 // get phone to my HC and save it as my parent's phone
218 // TODO: maybe not a good idea if DDF will use parent_phone
[0a9ea4a]219 int rc = kbd_dev->device->parent_phone = usb_drv_hc_connect_auto(dev, 0);
220 if (rc < 0) {
221 printf("Problem setting phone to HC.\n");
222 free(kbd_dev);
223 return NULL;
224 }
[101ef25c]225
[0a9ea4a]226 rc = kbd_dev->address = usb_drv_get_my_address(dev->parent_phone, dev);
227 if (rc < 0) {
228 printf("Problem getting address of the device.\n");
229 free(kbd_dev);
230 return NULL;
231 }
[2e15ac40]232
[101ef25c]233 // doesn't matter now that we have no address
234// if (kbd_dev->address < 0) {
235// fprintf(stderr, NAME ": No device address!\n");
236// free(kbd_dev);
237// return NULL;
238// }
[2e15ac40]239
240 // default endpoint
[1b29d6fa]241 kbd_dev->poll_endpoint = GUESSED_POLL_ENDPOINT;
[dafab9e0]242
243 /*
244 * will need all descriptors:
245 * 1) choose one configuration from configuration descriptors
246 * (set it to the device)
247 * 2) set endpoints from endpoint descriptors
248 */
[2e15ac40]249
[ca038b4]250 // TODO: get descriptors, parse descriptors and save endpoints
251 usbkbd_process_descriptors(kbd_dev);
[2e15ac40]252
253 return kbd_dev;
254}
[91db50ac]255
[101ef25c]256static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
[243cb86]257 uint8_t *buffer, size_t actual_size)
[101ef25c]258{
[243cb86]259 usb_hid_report_in_callbacks_t *callbacks =
260 (usb_hid_report_in_callbacks_t *)malloc(
261 sizeof(usb_hid_report_in_callbacks_t));
262 callbacks->keyboard = usbkbd_process_keycodes;
263
[0a9ea4a]264 //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
265 // NULL);
266 printf("Calling usb_hid_boot_keyboard_input_report()...\n)");
267 usb_hid_boot_keyboard_input_report(buffer, actual_size, callbacks, NULL);
[101ef25c]268}
269
[2e15ac40]270static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev)
[91db50ac]271{
[6986418]272 return;
273
[91db50ac]274 int rc;
275 usb_handle_t handle;
[243cb86]276 uint8_t buffer[BUFFER_SIZE];
[91db50ac]277 size_t actual_size;
[2e15ac40]278 //usb_endpoint_t poll_endpoint = 1;
[91db50ac]279
[2e15ac40]280// usb_address_t my_address = usb_drv_get_my_address(dev->parent_phone,
281// dev);
282// if (my_address < 0) {
283// return;
284// }
[0e126be7]285
286 usb_target_t poll_target = {
[2e15ac40]287 .address = kbd_dev->address,
[1b29d6fa]288 .endpoint = kbd_dev->poll_endpoint
[0e126be7]289 };
290
[101ef25c]291 while (true) {
[f9a0cef]292 async_usleep(1000 * 1000);
[101ef25c]293 rc = usb_drv_async_interrupt_in(kbd_dev->device->parent_phone,
294 poll_target, buffer, BUFFER_SIZE, &actual_size, &handle);
295
296 if (rc != EOK) {
297 continue;
298 }
299
300 rc = usb_drv_async_wait_for(handle);
301 if (rc != EOK) {
302 continue;
303 }
304
305 /*
306 * If the keyboard answered with NAK, it returned no data.
307 * This implies that no change happened since last query.
308 */
309 if (actual_size == 0) {
310 continue;
311 }
312
313 /*
314 * TODO: Process pressed keys.
315 */
316 usbkbd_process_interrupt_in(kbd_dev, buffer, actual_size);
[91db50ac]317 }
318
[101ef25c]319 // not reached
320 assert(0);
[91db50ac]321}
322
[2e15ac40]323static int usbkbd_fibril_device(void *arg)
324{
325 printf("!!! USB device fibril\n");
326
327 if (arg == NULL) {
328 printf("No device!\n");
329 return -1;
330 }
331
332 device_t *dev = (device_t *)arg;
333
334 // initialize device (get and process descriptors, get address, etc.)
335 usb_hid_dev_kbd_t *kbd_dev = usbkbd_init_device(dev);
336
337 usbkbd_poll_keyboard(kbd_dev);
338
339 return EOK;
340}
341
342static int usbkbd_add_device(device_t *dev)
[c7137738]343{
344 /* For now, fail immediately. */
[101ef25c]345 //return ENOTSUP;
[c7137738]346
347 /*
348 * When everything is okay, connect to "our" HC.
[2e15ac40]349 *
350 * Not supported yet, skip..
[c7137738]351 */
[71ed4849]352// int phone = usb_drv_hc_connect_auto(dev, 0);
[2e15ac40]353// if (phone < 0) {
354// /*
355// * Connecting to HC failed, roll-back and announce
356// * failure.
357// */
358// return phone;
359// }
[c7137738]360
[2e15ac40]361// dev->parent_phone = phone;
[91db50ac]362
363 /*
[2e15ac40]364 * Create new fibril for handling this keyboard
[91db50ac]365 */
[2e15ac40]366 fid_t fid = fibril_create(usbkbd_fibril_device, dev);
367 if (fid == 0) {
368 printf("%s: failed to start fibril for HID device\n", NAME);
369 return ENOMEM;
370 }
371 fibril_add_ready(fid);
[91db50ac]372
[700af62]373 dev->ops = &keyboard_ops;
374
375 add_device_to_class(dev, "keyboard");
376
[c7137738]377 /*
378 * Hurrah, device is initialized.
379 */
380 return EOK;
381}
382
383static driver_ops_t kbd_driver_ops = {
[2e15ac40]384 .add_device = usbkbd_add_device,
[c7137738]385};
386
387static driver_t kbd_driver = {
[2e15ac40]388 .name = NAME,
[c7137738]389 .driver_ops = &kbd_driver_ops
390};
391
392int main(int argc, char *argv[])
393{
394 return driver_main(&kbd_driver);
395}
Note: See TracBrowser for help on using the repository browser.