source: mainline/uspace/drv/usbkbd/main.c@ 82122f3

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

Merged development into lelian/hidd

  • Property mode set to 100644
File size: 7.0 KB
Line 
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>
30#include <ipc/driver.h>
31#include <errno.h>
32#include <fibril.h>
33#include <usb/classes/hid.h>
34#include <usb/classes/hidparser.h>
35#include <usb/devreq.h>
36#include <usb/descriptor.h>
37#include "descparser.h"
38
39#define BUFFER_SIZE 32
40#define NAME "usbkbd"
41
42#define GUESSED_POLL_ENDPOINT 1
43
44/*
45 * Callbacks for parser
46 */
47static void usbkbd_process_keycodes(const uint16_t *key_codes, size_t count,
48 void *arg)
49{
50 printf("Got keys: ");
51 unsigned i;
52 for (i = 0; i < count; ++i) {
53 printf("%d ", key_codes[i]);
54 }
55 printf("\n");
56}
57
58/*
59 * Kbd functions
60 */
61static int usbkbd_process_descriptors(usb_hid_dev_kbd_t *kbd_dev)
62{
63 // get the first configuration descriptor (TODO: parse also other!)
64 usb_standard_configuration_descriptor_t config_desc;
65
66 int rc = usb_drv_req_get_bare_configuration_descriptor(
67 kbd_dev->device->parent_phone, kbd_dev->address, 0, &config_desc);
68
69 if (rc != EOK) {
70 return rc;
71 }
72
73 // prepare space for all underlying descriptors
74 uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length);
75 if (descriptors == NULL) {
76 return ENOMEM;
77 }
78
79 size_t transferred = 0;
80 // get full configuration descriptor
81 rc = usb_drv_req_get_full_configuration_descriptor(
82 kbd_dev->device->parent_phone, kbd_dev->address, 0, descriptors,
83 config_desc.total_length, &transferred);
84
85 if (rc != EOK) {
86 return rc;
87 }
88 if (transferred != config_desc.total_length) {
89 return ELIMIT;
90 }
91
92 kbd_dev->conf = (usb_hid_configuration_t *)calloc(1,
93 sizeof(usb_hid_configuration_t));
94 if (kbd_dev->conf == NULL) {
95 free(descriptors);
96 return ENOMEM;
97 }
98
99 rc = usbkbd_parse_descriptors(descriptors, transferred, kbd_dev->conf);
100 free(descriptors);
101
102 return rc;
103}
104
105static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
106{
107 usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)calloc(1,
108 sizeof(usb_hid_dev_kbd_t));
109
110 if (kbd_dev == NULL) {
111 fprintf(stderr, NAME ": No memory!\n");
112 return NULL;
113 }
114
115 kbd_dev->device = dev;
116
117 // get phone to my HC and save it as my parent's phone
118 // TODO: maybe not a good idea if DDF will use parent_phone
119 kbd_dev->device->parent_phone = usb_drv_hc_connect(dev, 0);
120
121 kbd_dev->address = usb_drv_get_my_address(dev->parent_phone,
122 dev);
123
124 // doesn't matter now that we have no address
125// if (kbd_dev->address < 0) {
126// fprintf(stderr, NAME ": No device address!\n");
127// free(kbd_dev);
128// return NULL;
129// }
130
131 // default endpoint
132 kbd_dev->poll_endpoint = GUESSED_POLL_ENDPOINT;
133
134 /*
135 * will need all descriptors:
136 * 1) choose one configuration from configuration descriptors
137 * (set it to the device)
138 * 2) set endpoints from endpoint descriptors
139 */
140
141 // TODO: get descriptors, parse descriptors and save endpoints
142 usbkbd_process_descriptors(kbd_dev);
143
144 return kbd_dev;
145}
146
147static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
148 uint8_t *buffer, size_t actual_size)
149{
150 /*
151 * here, the parser will be called, probably with some callbacks
152 * now only take last 6 bytes and process, i.e. send to kbd
153 */
154
155 usb_hid_report_in_callbacks_t *callbacks =
156 (usb_hid_report_in_callbacks_t *)malloc(
157 sizeof(usb_hid_report_in_callbacks_t));
158 callbacks->keyboard = usbkbd_process_keycodes;
159
160 usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
161 NULL);
162}
163
164static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev)
165{
166 int rc;
167 usb_handle_t handle;
168 uint8_t buffer[BUFFER_SIZE];
169 size_t actual_size;
170 //usb_endpoint_t poll_endpoint = 1;
171
172// usb_address_t my_address = usb_drv_get_my_address(dev->parent_phone,
173// dev);
174// if (my_address < 0) {
175// return;
176// }
177
178 usb_target_t poll_target = {
179 .address = kbd_dev->address,
180 .endpoint = kbd_dev->poll_endpoint
181 };
182
183 while (true) {
184 async_usleep(1000 * 1000);
185 rc = usb_drv_async_interrupt_in(kbd_dev->device->parent_phone,
186 poll_target, buffer, BUFFER_SIZE, &actual_size, &handle);
187
188 if (rc != EOK) {
189 continue;
190 }
191
192 rc = usb_drv_async_wait_for(handle);
193 if (rc != EOK) {
194 continue;
195 }
196
197 /*
198 * If the keyboard answered with NAK, it returned no data.
199 * This implies that no change happened since last query.
200 */
201 if (actual_size == 0) {
202 continue;
203 }
204
205 /*
206 * TODO: Process pressed keys.
207 */
208 usbkbd_process_interrupt_in(kbd_dev, buffer, actual_size);
209 }
210
211 // not reached
212 assert(0);
213}
214
215static int usbkbd_fibril_device(void *arg)
216{
217 printf("!!! USB device fibril\n");
218
219 if (arg == NULL) {
220 printf("No device!\n");
221 return -1;
222 }
223
224 device_t *dev = (device_t *)arg;
225
226 // initialize device (get and process descriptors, get address, etc.)
227 usb_hid_dev_kbd_t *kbd_dev = usbkbd_init_device(dev);
228
229 usbkbd_poll_keyboard(kbd_dev);
230
231 return EOK;
232}
233
234static int usbkbd_add_device(device_t *dev)
235{
236 /* For now, fail immediately. */
237 //return ENOTSUP;
238
239 /*
240 * When everything is okay, connect to "our" HC.
241 *
242 * Not supported yet, skip..
243 */
244// int phone = usb_drv_hc_connect(dev, 0);
245// if (phone < 0) {
246// /*
247// * Connecting to HC failed, roll-back and announce
248// * failure.
249// */
250// return phone;
251// }
252
253// dev->parent_phone = phone;
254
255 /*
256 * Create new fibril for handling this keyboard
257 */
258 fid_t fid = fibril_create(usbkbd_fibril_device, dev);
259 if (fid == 0) {
260 printf("%s: failed to start fibril for HID device\n", NAME);
261 return ENOMEM;
262 }
263 fibril_add_ready(fid);
264
265 /*
266 * Hurrah, device is initialized.
267 */
268 return EOK;
269}
270
271static driver_ops_t kbd_driver_ops = {
272 .add_device = usbkbd_add_device,
273};
274
275static driver_t kbd_driver = {
276 .name = NAME,
277 .driver_ops = &kbd_driver_ops
278};
279
280int main(int argc, char *argv[])
281{
282 return driver_main(&kbd_driver);
283}
Note: See TracBrowser for help on using the repository browser.