source: mainline/uspace/drv/usbhid/usbhid.c@ e9f0348

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

Mouse driver integrated into the general HID driver.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/*
2 * Copyright (c) 2011 Lubos Slovak
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 HID driver API.
35 */
36
37#include <usb/debug.h>
38#include <usb/classes/classes.h>
39#include <usb/classes/hid.h>
40#include <usb/classes/hidparser.h>
41#include <usb/classes/hidreport.h>
42#include <usb/classes/hidreq.h>
43#include <errno.h>
44
45#include "usbhid.h"
46
47#include "kbd/kbddev.h"
48#include "generic/hiddev.h"
49#include "mouse/mousedev.h"
50
51/*----------------------------------------------------------------------------*/
52
53/* Array of endpoints expected on the device, NULL terminated. */
54usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
55 &usb_hid_kbd_poll_endpoint_description,
56 &usb_hid_mouse_poll_endpoint_description,
57 &usb_hid_generic_poll_endpoint_description,
58 NULL
59};
60
61/*----------------------------------------------------------------------------*/
62
63usb_hid_dev_t *usb_hid_new(void)
64{
65 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
66 sizeof(usb_hid_dev_t));
67
68 if (hid_dev == NULL) {
69 usb_log_fatal("No memory!\n");
70 return NULL;
71 }
72
73 hid_dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
74 usb_hid_report_parser_t)));
75 if (hid_dev->parser == NULL) {
76 usb_log_fatal("No memory!\n");
77 free(hid_dev);
78 return NULL;
79 }
80
81 return hid_dev;
82}
83
84/*----------------------------------------------------------------------------*/
85
86static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
87{
88 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
89 usb_log_debug("Found keyboard endpoint.\n");
90
91 // save the pipe index and device type
92 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
93 hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;
94
95 // set the polling callback
96 hid_dev->poll_callback = usb_kbd_polling_callback;
97
98 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
99 usb_log_debug("Found mouse endpoint.\n");
100
101 // save the pipe index and device type
102 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
103 hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
104
105 // set the polling callback
106 hid_dev->poll_callback = usb_mouse_polling_callback;
107
108 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
109 usb_log_debug("Found generic HID endpoint.\n");
110
111 // save the pipe index and device type
112 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
113 hid_dev->device_type = USB_HID_PROTOCOL_NONE;
114
115 // set the polling callback
116 hid_dev->poll_callback = usb_hid_polling_callback;
117
118 } else {
119 usb_log_warning("None of supported endpoints found - probably"
120 " not a supported device.\n");
121 return ENOTSUP;
122 }
123
124 return EOK;
125}
126
127/*----------------------------------------------------------------------------*/
128
129static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
130{
131 /* Initialize the report parser. */
132 int rc = usb_hid_parser_init(hid_dev->parser);
133 if (rc != EOK) {
134 usb_log_error("Failed to initialize report parser.\n");
135 return rc;
136 }
137
138 /* Get the report descriptor and parse it. */
139 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
140 hid_dev->parser);
141
142 if (rc != EOK || hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
143 usb_log_warning("Could not process report descriptor.\n");
144
145 if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {
146 usb_log_warning("Falling back to boot protocol.\n");
147 rc = usb_kbd_set_boot_protocol(hid_dev);
148 } else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
149 usb_log_warning("Falling back to boot protocol.\n");
150 rc = usb_mouse_set_boot_protocol(hid_dev);
151 }
152 }
153
154 return rc;
155}
156
157/*----------------------------------------------------------------------------*/
158
159int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
160{
161 int rc;
162
163 usb_log_debug("Initializing HID structure...\n");
164
165 if (hid_dev == NULL) {
166 usb_log_error("Failed to init HID structure: no structure given"
167 ".\n");
168 return EINVAL;
169 }
170
171 if (dev == NULL) {
172 usb_log_error("Failed to init HID structure: no USB device"
173 " given.\n");
174 return EINVAL;
175 }
176
177 /* The USB device should already be initialized, save it in structure */
178 hid_dev->usb_dev = dev;
179
180 rc = usb_hid_check_pipes(hid_dev, dev);
181 if (rc != EOK) {
182 return rc;
183 }
184
185 rc = usb_hid_init_parser(hid_dev);
186 if (rc != EOK) {
187 usb_log_error("Failed to initialize HID parser.\n");
188 return rc;
189 }
190
191 switch (hid_dev->device_type) {
192 case USB_HID_PROTOCOL_KEYBOARD:
193 // initialize the keyboard structure
194 rc = usb_kbd_init(hid_dev);
195 if (rc != EOK) {
196 usb_log_warning("Failed to initialize KBD structure."
197 "\n");
198 }
199 break;
200 case USB_HID_PROTOCOL_MOUSE:
201 rc = usb_mouse_init(hid_dev);
202 if (rc != EOK) {
203 usb_log_warning("Failed to initialize Mouse structure."
204 "\n");
205 }
206 break;
207 default:
208 break;
209 }
210
211 return rc;
212}
213
214/*----------------------------------------------------------------------------*/
215
216void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
217 void *arg)
218{
219 if (dev == NULL || arg == NULL) {
220 return;
221 }
222
223 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
224
225 usb_hid_free(&hid_dev);
226}
227
228/*----------------------------------------------------------------------------*/
229
230const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
231{
232 switch (device_type) {
233 case USB_HID_PROTOCOL_KEYBOARD:
234 return HID_KBD_FUN_NAME;
235 break;
236 case USB_HID_PROTOCOL_MOUSE:
237 return HID_MOUSE_FUN_NAME;
238 break;
239 default:
240 return HID_GENERIC_FUN_NAME;
241 }
242}
243
244/*----------------------------------------------------------------------------*/
245
246const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
247{
248 switch (device_type) {
249 case USB_HID_PROTOCOL_KEYBOARD:
250 return HID_KBD_CLASS_NAME;
251 break;
252 case USB_HID_PROTOCOL_MOUSE:
253 return HID_MOUSE_CLASS_NAME;
254 break;
255 default:
256 return HID_GENERIC_CLASS_NAME;
257 }
258}
259
260/*----------------------------------------------------------------------------*/
261
262void usb_hid_free(usb_hid_dev_t **hid_dev)
263{
264 if (hid_dev == NULL || *hid_dev == NULL) {
265 return;
266 }
267
268 switch ((*hid_dev)->device_type) {
269 case USB_HID_PROTOCOL_KEYBOARD:
270 usb_kbd_deinit(*hid_dev);
271 break;
272 case USB_HID_PROTOCOL_MOUSE:
273 usb_mouse_deinit(*hid_dev);
274 break;
275 default:
276 break;
277 }
278
279 // destroy the parser
280 if ((*hid_dev)->parser != NULL) {
281 usb_hid_free_report_parser((*hid_dev)->parser);
282 }
283
284 if ((*hid_dev)->report_desc != NULL) {
285 free((*hid_dev)->report_desc);
286 }
287
288 free(*hid_dev);
289 *hid_dev = NULL;
290}
291
292/**
293 * @}
294 */
Note: See TracBrowser for help on using the repository browser.