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

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

Changed checks in usb_mouse_free()

  • Property mode set to 100644
File size: 9.3 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 assert(mouse_dev != NULL && *mouse_dev != NULL);
160
161 // hangup phone to the console
162 if ((*mouse_dev)->console_phone >= 0) {
163 async_hangup((*mouse_dev)->console_phone);
164 }
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(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 hid_dev->ops.default_handler = default_connection_handler;
255
256 // TODO: how to know if the device supports the request???
257 usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
258 hid_dev->usb_dev->interface_no, IDLE_RATE);
259
260 return EOK;
261}
262
263/*----------------------------------------------------------------------------*/
264
265bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, uint8_t *buffer,
266 size_t buffer_size)
267{
268 usb_log_debug("usb_mouse_polling_callback()\n");
269 usb_debug_str_buffer(buffer, buffer_size, 0);
270
271 if (hid_dev == NULL) {
272 usb_log_error("Missing argument to the mouse polling callback."
273 "\n");
274 return false;
275 }
276
277 if (hid_dev->data == NULL) {
278 usb_log_error("Wrong argument to the mouse polling callback."
279 "\n");
280 return false;
281 }
282 usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
283
284 return usb_mouse_process_boot_report(mouse_dev, buffer, buffer_size);
285}
286
287/*----------------------------------------------------------------------------*/
288
289void usb_mouse_deinit(usb_hid_dev_t *hid_dev)
290{
291 usb_mouse_free((usb_mouse_t **)&hid_dev->data);
292}
293
294/*----------------------------------------------------------------------------*/
295
296int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
297{
298 int rc = usb_hid_parse_report_descriptor(hid_dev->parser,
299 USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
300 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
301
302 if (rc != EOK) {
303 usb_log_error("Failed to parse boot report descriptor: %s\n",
304 str_error(rc));
305 return rc;
306 }
307
308 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
309 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
310
311 if (rc != EOK) {
312 usb_log_warning("Failed to set boot protocol to the device: "
313 "%s\n", str_error(rc));
314 return rc;
315 }
316
317 return EOK;
318}
319
320/**
321 * @}
322 */
Note: See TracBrowser for help on using the repository browser.