source: mainline/uspace/drv/usbkbd/main.c@ 339aeac

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

Getting of full configuration descriptor.

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