source: mainline/uspace/drv/usbhid/mouse/mousedev.c@ a49e171

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

Fix in mouse polling callback

  • Property mode set to 100644
File size: 9.5 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 (%d).\n", callback);
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 usb_log_debug("Console phone: %d\n", mouse_dev->console_phone);
202 if ((shift_x != 0) || (shift_y != 0)) {
203 /* FIXME: guessed for QEMU */
204 async_req_2_0(mouse_dev->console_phone,
205 MEVENT_MOVE,
206 - shift_x / 10, - shift_y / 10);
207 } else {
208 usb_log_error("No move reported\n");
209 }
210 if (butt) {
211 /* FIXME: proper button clicking. */
212 async_req_2_0(mouse_dev->console_phone,
213 MEVENT_BUTTON, 1, 1);
214 async_req_2_0(mouse_dev->console_phone,
215 MEVENT_BUTTON, 1, 0);
216 }
217 } else {
218 usb_log_error("No console phone in mouse!!\n");
219 }
220
221 usb_log_debug("buttons=%s dX=%+3d dY=%+3d wheel=%+3d\n",
222 str_buttons, shift_x, shift_y, wheel);
223
224 /* Guess. */
225 //async_usleep(1000);
226 // no sleep right now
227
228 return true;
229}
230
231/*----------------------------------------------------------------------------*/
232
233int usb_mouse_init(struct usb_hid_dev_t *hid_dev)
234{
235 usb_log_debug("Initializing HID/Mouse structure...\n");
236
237 if (hid_dev == NULL) {
238 usb_log_error("Failed to init keyboard structure: no structure"
239 " given.\n");
240 return EINVAL;
241 }
242
243 usb_mouse_t *mouse_dev = usb_mouse_new();
244 if (mouse_dev == NULL) {
245 usb_log_error("Error while creating USB/HID Mouse device "
246 "structure.\n");
247 return ENOMEM;
248 }
249
250 // save the Mouse device structure into the HID device structure
251 hid_dev->data = mouse_dev;
252
253 // set handler for incoming calls
254 // TODO: now does this behave when we have more such handlers in
255 // one actual driver??
256 hid_dev->ops.default_handler = default_connection_handler;
257
258 // TODO: how to know if the device supports the request???
259// usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
260// hid_dev->usb_dev->interface_no, IDLE_RATE);
261
262 return EOK;
263}
264
265/*----------------------------------------------------------------------------*/
266
267bool usb_mouse_polling_callback(usb_device_t *dev, uint8_t *buffer,
268 size_t buffer_size, void *arg)
269{
270 usb_log_debug("usb_mouse_polling_callback()\n");
271 usb_debug_str_buffer(buffer, buffer_size, 0);
272
273 if (arg == NULL) {
274 usb_log_error("Missing argument to the mouse polling callback."
275 "\n");
276 return false;
277 }
278
279 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
280 if (hid_dev->data == NULL) {
281 usb_log_error("Wrong argument to the mouse polling callback."
282 "\n");
283 return false;
284 }
285 usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
286
287 return usb_mouse_process_boot_report(mouse_dev, buffer, buffer_size);
288}
289
290/*----------------------------------------------------------------------------*/
291
292void usb_mouse_deinit(struct usb_hid_dev_t *hid_dev)
293{
294 usb_mouse_free((usb_mouse_t **)&hid_dev->data);
295}
296
297/*----------------------------------------------------------------------------*/
298
299int usb_mouse_set_boot_protocol(struct usb_hid_dev_t *hid_dev)
300{
301 int rc = usb_hid_parse_report_descriptor(hid_dev->parser,
302 USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
303 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
304
305 if (rc != EOK) {
306 usb_log_error("Failed to parse boot report descriptor: %s\n",
307 str_error(rc));
308 return rc;
309 }
310
311 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
312 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
313
314 if (rc != EOK) {
315 usb_log_warning("Failed to set boot protocol to the device: "
316 "%s\n", str_error(rc));
317 return rc;
318 }
319
320 return EOK;
321}
322
323/**
324 * @}
325 */
Note: See TracBrowser for help on using the repository browser.