source: mainline/uspace/drv/bus/usb/usbhid/generic/hiddev.c@ 378bf85

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 378bf85 was 378bf85, checked in by Martin Decky <martin@…>, 12 years ago

cstyle
(no change in functionality)

  • Property mode set to 100644
File size: 6.5 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/* XXX Fix this */
38#define _DDF_DATA_IMPLANT
39
40#include <usb/debug.h>
41#include <usb/classes/classes.h>
42#include <errno.h>
43#include <str_error.h>
44#include <stdbool.h>
45
46#include <usbhid_iface.h>
47
48#include "hiddev.h"
49#include "usbhid.h"
50
51const usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
52 .transfer_type = USB_TRANSFER_INTERRUPT,
53 .direction = USB_DIRECTION_IN,
54 .interface_class = USB_CLASS_HID,
55 .interface_subclass = -1,
56 .interface_protocol = -1,
57 .flags = 0
58};
59
60const char *HID_GENERIC_FUN_NAME = "hid";
61const char *HID_GENERIC_CATEGORY = "hid";
62
63
64static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun);
65static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
66 size_t size, size_t *act_size, int *event_nr, unsigned int flags);
67static int usb_generic_hid_client_connected(ddf_fun_t *fun);
68static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun);
69static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
70 size_t size, size_t *actual_size);
71
72static usbhid_iface_t usb_generic_iface = {
73 .get_event = usb_generic_hid_get_event,
74 .get_event_length = usb_generic_hid_get_event_length,
75 .get_report_descriptor_length = usb_generic_get_report_descriptor_length,
76 .get_report_descriptor = usb_generic_get_report_descriptor
77};
78
79static ddf_dev_ops_t usb_generic_hid_ops = {
80 .interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
81 .open = usb_generic_hid_client_connected
82};
83
84/** Return hid_dev_t * for generic HID function node.
85 *
86 * For the generic HID subdriver the 'hid' function has usb_hid_gen_fun_t
87 * as soft state. Through that we can get to the usb_hid_dev_t.
88 */
89static usb_hid_dev_t *fun_hid_dev(ddf_fun_t *fun)
90{
91 return ((usb_hid_gen_fun_t *)ddf_fun_data_get(fun))->hid_dev;
92}
93
94static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun)
95{
96 usb_log_debug2("Generic HID: Get event length (fun: %p, "
97 "fun->driver_data: %p.\n", fun, ddf_fun_data_get(fun));
98
99 const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
100
101 usb_log_debug2("hid_dev: %p, Max input report size (%zu).\n",
102 hid_dev, hid_dev->max_input_report_size);
103
104 return hid_dev->max_input_report_size;
105}
106
107static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
108 size_t size, size_t *act_size, int *event_nr, unsigned int flags)
109{
110 usb_log_debug2("Generic HID: Get event.\n");
111
112 if (buffer == NULL || act_size == NULL || event_nr == NULL) {
113 usb_log_debug("No function");
114 return EINVAL;
115 }
116
117 const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
118
119 if (hid_dev->input_report_size > size) {
120 usb_log_debug("input_report_size > size (%zu, %zu)\n",
121 hid_dev->input_report_size, size);
122 return EINVAL; // TODO: other error code
123 }
124
125 /*! @todo This should probably be somehow atomic. */
126 memcpy(buffer, hid_dev->input_report,
127 hid_dev->input_report_size);
128 *act_size = hid_dev->input_report_size;
129 *event_nr = usb_hid_report_number(hid_dev);
130
131 usb_log_debug2("OK\n");
132
133 return EOK;
134}
135
136static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
137{
138 usb_log_debug("Generic HID: Get report descriptor length.\n");
139
140 const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
141
142 usb_log_debug2("hid_dev->report_desc_size = %zu\n",
143 hid_dev->report_desc_size);
144
145 return hid_dev->report_desc_size;
146}
147
148static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
149 size_t size, size_t *actual_size)
150{
151 usb_log_debug2("Generic HID: Get report descriptor.\n");
152
153 const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
154
155 if (hid_dev->report_desc_size > size) {
156 return EINVAL;
157 }
158
159 memcpy(desc, hid_dev->report_desc, hid_dev->report_desc_size);
160 *actual_size = hid_dev->report_desc_size;
161
162 return EOK;
163}
164
165static int usb_generic_hid_client_connected(ddf_fun_t *fun)
166{
167 usb_log_debug("Generic HID: Client connected.\n");
168 return EOK;
169}
170
171void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
172{
173 ddf_fun_t *fun = data;
174 if (fun == NULL)
175 return;
176
177 if (ddf_fun_unbind(fun) != EOK) {
178 usb_log_error("Failed to unbind generic hid fun.\n");
179 return;
180 }
181 usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun));
182 ddf_fun_destroy(fun);
183}
184
185int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
186{
187 usb_hid_gen_fun_t *hid_fun;
188
189 if (hid_dev == NULL) {
190 return EINVAL;
191 }
192
193 /* Create the exposed function. */
194 usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
195 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
196 HID_GENERIC_FUN_NAME);
197 if (fun == NULL) {
198 usb_log_error("Could not create DDF function node.\n");
199 return ENOMEM;
200 }
201
202 /* Create softstate */
203 hid_fun = ddf_fun_data_alloc(fun, sizeof(usb_hid_gen_fun_t));
204 hid_fun->hid_dev = hid_dev;
205 ddf_fun_set_ops(fun, &usb_generic_hid_ops);
206
207 int rc = ddf_fun_bind(fun);
208 if (rc != EOK) {
209 usb_log_error("Could not bind DDF function: %s.\n",
210 str_error(rc));
211 ddf_fun_destroy(fun);
212 return rc;
213 }
214
215 usb_log_debug("HID function created. Handle: %" PRIun "\n",
216 ddf_fun_get_handle(fun));
217 *data = fun;
218
219 return EOK;
220}
221
222bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data)
223{
224 return true;
225}
226
227/**
228 * @}
229 */
Note: See TracBrowser for help on using the repository browser.