source: mainline/uspace/drv/usbhid/mouse/mousedev.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@…>, 15 years ago

Mouse driver integrated into the general HID driver.

  • Property mode set to 100644
File size: 9.2 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 Mouse 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/hidreq.h>
41#include <errno.h>
42#include <str_error.h>
43#include <ipc/mouse.h>
44
45#include "mousedev.h"
46#include "../usbhid.h"
47
48/*----------------------------------------------------------------------------*/
49
50usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
51 .transfer_type = USB_TRANSFER_INTERRUPT,
52 .direction = USB_DIRECTION_IN,
53 .interface_class = USB_CLASS_HID,
54 .interface_subclass = USB_HID_SUBCLASS_BOOT,
55 .interface_protocol = USB_HID_PROTOCOL_MOUSE,
56 .flags = 0
57};
58
59const char *HID_MOUSE_FUN_NAME = "mouse";
60const char *HID_MOUSE_CLASS_NAME = "mouse";
61
62/** Default idle rate for mouses. */
63static const uint8_t IDLE_RATE = 0;
64
65/*----------------------------------------------------------------------------*/
66
67enum {
68 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
69};
70
71static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
72 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
73 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
74 0x09, 0x02, // USAGE (Mouse)
75 0xa1, 0x01, // COLLECTION (Application)
76 0x09, 0x01, // USAGE (Pointer)
77 0xa1, 0x00, // COLLECTION (Physical)
78 0x95, 0x03, // REPORT_COUNT (3)
79 0x75, 0x01, // REPORT_SIZE (1)
80 0x05, 0x09, // USAGE_PAGE (Button)
81 0x19, 0x01, // USAGE_MINIMUM (Button 1)
82 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
83 0x15, 0x00, // LOGICAL_MINIMUM (0)
84 0x25, 0x01, // LOGICAL_MAXIMUM (1)
85 0x81, 0x02, // INPUT (Data,Var,Abs)
86 0x95, 0x01, // REPORT_COUNT (1)
87 0x75, 0x05, // REPORT_SIZE (5)
88 0x81, 0x01, // INPUT (Cnst)
89 0x75, 0x08, // REPORT_SIZE (8)
90 0x95, 0x02, // REPORT_COUNT (2)
91 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
92 0x09, 0x30, // USAGE (X)
93 0x09, 0x31, // USAGE (Y)
94 0x15, 0x81, // LOGICAL_MINIMUM (-127)
95 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
96 0x81, 0x06, // INPUT (Data,Var,Rel)
97 0xc0, // END_COLLECTION
98 0xc0 // END_COLLECTION
99};
100
101/*----------------------------------------------------------------------------*/
102
103/** Default handler for IPC methods not handled by DDF.
104 *
105 * @param fun Device function handling the call.
106 * @param icallid Call id.
107 * @param icall Call data.
108 */
109static void default_connection_handler(ddf_fun_t *fun,
110 ipc_callid_t icallid, ipc_call_t *icall)
111{
112 sysarg_t method = IPC_GET_IMETHOD(*icall);
113
114 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
115
116 if (hid_dev == NULL || hid_dev->data == NULL) {
117 async_answer_0(icallid, EINVAL);
118 return;
119 }
120
121 assert(hid_dev != NULL);
122 assert(hid_dev->data != NULL);
123 usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
124
125 if (method == IPC_M_CONNECT_TO_ME) {
126 int callback = IPC_GET_ARG5(*icall);
127
128 if (mouse_dev->console_phone != -1) {
129 async_answer_0(icallid, ELIMIT);
130 return;
131 }
132
133 mouse_dev->console_phone = callback;
134 usb_log_debug("Console phone to mouse set ok.\n");
135 async_answer_0(icallid, EOK);
136 return;
137 }
138
139 async_answer_0(icallid, EINVAL);
140}
141
142/*----------------------------------------------------------------------------*/
143
144static usb_mouse_t *usb_mouse_new(void)
145{
146 usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
147 if (mouse == NULL) {
148 return NULL;
149 }
150 mouse->console_phone = -1;
151
152 return mouse;
153}
154
155/*----------------------------------------------------------------------------*/
156
157static void usb_mouse_free(usb_mouse_t **mouse_dev)
158{
159 if (mouse_dev == NULL || *mouse_dev == NULL) {
160 return;
161 }
162
163 // hangup phone to the console
164 async_hangup((*mouse_dev)->console_phone);
165
166 free(*mouse_dev);
167 *mouse_dev = NULL;
168}
169
170/*----------------------------------------------------------------------------*/
171
172static bool usb_mouse_process_boot_report(usb_mouse_t *mouse_dev,
173 uint8_t *buffer, size_t buffer_size)
174{
175 usb_log_debug2("got buffer: %s.\n",
176 usb_debug_str_buffer(buffer, buffer_size, 0));
177
178 uint8_t butt = buffer[0];
179 char str_buttons[4] = {
180 butt & 1 ? '#' : '.',
181 butt & 2 ? '#' : '.',
182 butt & 4 ? '#' : '.',
183 0
184 };
185
186 int shift_x = ((int) buffer[1]) - 127;
187 int shift_y = ((int) buffer[2]) - 127;
188 int wheel = ((int) buffer[3]) - 127;
189
190 if (buffer[1] == 0) {
191 shift_x = 0;
192 }
193 if (buffer[2] == 0) {
194 shift_y = 0;
195 }
196 if (buffer[3] == 0) {
197 wheel = 0;
198 }
199
200 if (mouse_dev->console_phone >= 0) {
201 if ((shift_x != 0) || (shift_y != 0)) {
202 /* FIXME: guessed for QEMU */
203 async_req_2_0(mouse_dev->console_phone,
204 MEVENT_MOVE,
205 - shift_x / 10, - shift_y / 10);
206 } else {
207 usb_log_error("No move reported\n");
208 }
209 if (butt) {
210 /* FIXME: proper button clicking. */
211 async_req_2_0(mouse_dev->console_phone,
212 MEVENT_BUTTON, 1, 1);
213 async_req_2_0(mouse_dev->console_phone,
214 MEVENT_BUTTON, 1, 0);
215 }
216 } else {
217 usb_log_error("No console phone in mouse!!\n");
218 }
219
220 usb_log_debug("buttons=%s dX=%+3d dY=%+3d wheel=%+3d\n",
221 str_buttons, shift_x, shift_y, wheel);
222
223 /* Guess. */
224 //async_usleep(1000);
225 // no sleep right now
226
227 return true;
228}
229
230/*----------------------------------------------------------------------------*/
231
232int usb_mouse_init(struct usb_hid_dev_t *hid_dev)
233{
234 usb_log_debug("Initializing HID/Mouse structure...\n");
235
236 if (hid_dev == NULL) {
237 usb_log_error("Failed to init keyboard structure: no structure"
238 " given.\n");
239 return EINVAL;
240 }
241
242 usb_mouse_t *mouse_dev = usb_mouse_new();
243 if (mouse_dev == NULL) {
244 usb_log_error("Error while creating USB/HID Mouse device "
245 "structure.\n");
246 return ENOMEM;
247 }
248
249 // save the Mouse device structure into the HID device structure
250 hid_dev->data = mouse_dev;
251
252 // set handler for incoming calls
253 // TODO: now does this behave when we have more such handlers in
254 // one actual driver??
255 hid_dev->ops.default_handler = default_connection_handler;
256
257 // TODO: how to know if the device supports the request???
258// usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
259// hid_dev->usb_dev->interface_no, IDLE_RATE);
260
261 return EOK;
262}
263
264/*----------------------------------------------------------------------------*/
265
266bool usb_mouse_polling_callback(usb_device_t *dev, uint8_t *buffer,
267 size_t buffer_size, void *arg)
268{
269 usb_log_debug("usb_mouse_polling_callback()\n");
270 usb_debug_str_buffer(buffer, buffer_size, 0);
271
272 if (arg == NULL) {
273 usb_log_error("Missing argument to the mouse polling callback."
274 "\n");
275 return false;
276 }
277
278 usb_mouse_t *mouse_dev = (usb_mouse_t *)arg;
279
280 return usb_mouse_process_boot_report(mouse_dev, buffer, buffer_size);
281}
282
283/*----------------------------------------------------------------------------*/
284
285void usb_mouse_deinit(struct usb_hid_dev_t *hid_dev)
286{
287 usb_mouse_free((usb_mouse_t **)&hid_dev->data);
288}
289
290/*----------------------------------------------------------------------------*/
291
292int usb_mouse_set_boot_protocol(struct usb_hid_dev_t *hid_dev)
293{
294 int rc = usb_hid_parse_report_descriptor(hid_dev->parser,
295 USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
296 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
297
298 if (rc != EOK) {
299 usb_log_error("Failed to parse boot report descriptor: %s\n",
300 str_error(rc));
301 return rc;
302 }
303
304 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
305 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
306
307 if (rc != EOK) {
308 usb_log_warning("Failed to set boot protocol to the device: "
309 "%s\n", str_error(rc));
310 return rc;
311 }
312
313 return EOK;
314}
315
316/**
317 * @}
318 */
Note: See TracBrowser for help on using the repository browser.