source: mainline/uspace/drv/usbmid/usbmid.c@ 51f0e410

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 51f0e410 was 51f0e410, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Interface-based matches use also device descriptor

This way it is possible to distinguish generic class drivers and
class drivers for specific device (it allows to mix these drivers
when MID is in use).

  • Property mode set to 100644
File size: 6.2 KB
Line 
1/*
2 * Copyright (c) 2011 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 drvusbmid
30 * @{
31 */
32/**
33 * @file
34 * Helper functions.
35 */
36#include <errno.h>
37#include <str_error.h>
38#include <stdlib.h>
39#include <usb_iface.h>
40#include <usb/ddfiface.h>
41#include <usb/pipes.h>
42#include <usb/classes/classes.h>
43#include <usb/recognise.h>
44#include "usbmid.h"
45
46/** Callback for DDF USB interface. */
47static int usb_iface_get_address_impl(device_t *device, devman_handle_t handle,
48 usb_address_t *address)
49{
50 assert(device);
51 device_t *parent = device->parent;
52
53 /* Default error, device does not support this operation. */
54 int rc = ENOTSUP;
55
56 if (parent && parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
57 usb_iface_t *usb_iface
58 = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
59 assert(usb_iface != NULL);
60
61 if (usb_iface->get_address) {
62 rc = usb_iface->get_address(parent, parent->handle,
63 address);
64 }
65 }
66
67 return rc;
68}
69
70/** Callback for DDF USB interface. */
71static int usb_iface_get_interface_impl(device_t *device, devman_handle_t handle,
72 int *iface_no)
73{
74 assert(device);
75
76 usbmid_interface_t *iface = device->driver_data;
77 assert(iface);
78
79 if (iface_no != NULL) {
80 *iface_no = iface->interface_no;
81 }
82
83 return EOK;
84}
85
86static usb_iface_t child_usb_iface = {
87 .get_hc_handle = usb_iface_get_hc_handle_hub_child_impl,
88 .get_address = usb_iface_get_address_impl,
89 .get_interface = usb_iface_get_interface_impl
90};
91
92
93static device_ops_t child_device_ops = {
94 .interfaces[USB_DEV_IFACE] = &child_usb_iface
95};
96
97static device_ops_t mid_device_ops = {
98 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
99};
100
101/** Create new USB multi interface device.
102 *
103 * @param dev Backing generic DDF device.
104 * @return New USB MID device.
105 * @retval NULL Error occured.
106 */
107usbmid_device_t *usbmid_device_create(device_t *dev)
108{
109 usbmid_device_t *mid = malloc(sizeof(usbmid_device_t));
110 if (mid == NULL) {
111 usb_log_error("Out of memory (wanted %zu bytes).\n",
112 sizeof(usbmid_device_t));
113 return NULL;
114 }
115
116 int rc;
117 rc = usb_device_connection_initialize_from_device(&mid->wire, dev);
118 if (rc != EOK) {
119 usb_log_error("Failed to initialize `USB wire': %s.\n",
120 str_error(rc));
121 free(mid);
122 return NULL;
123 }
124
125 rc = usb_endpoint_pipe_initialize_default_control(&mid->ctrl_pipe,
126 &mid->wire);
127 if (rc != EOK) {
128 usb_log_error("Failed to initialize control pipe: %s.\n",
129 str_error(rc));
130 free(mid);
131 return NULL;
132 }
133
134 mid->dev = dev;
135 dev->ops = &mid_device_ops;
136
137 return mid;
138}
139
140/** Create new interface for USB MID device.
141 *
142 * @param dev Backing generic DDF child device (representing interface).
143 * @param iface_no Interface number.
144 * @return New interface.
145 * @retval NULL Error occured.
146 */
147usbmid_interface_t *usbmid_interface_create(device_t *dev, int iface_no)
148{
149 usbmid_interface_t *iface = malloc(sizeof(usbmid_interface_t));
150 if (iface == NULL) {
151 usb_log_error("Out of memory (wanted %zuB).\n",
152 sizeof(usbmid_interface_t));
153 return NULL;
154 }
155
156 iface->dev = dev;
157 iface->interface_no = iface_no;
158
159 return iface;
160}
161
162
163/** Spawn new child device from one interface.
164 *
165 * @param parent Parent MID device.
166 * @param device_descriptor Device descriptor.
167 * @param interface_descriptor Interface descriptor.
168 * @return Error code.
169 */
170int usbmid_spawn_interface_child(usbmid_device_t *parent,
171 const usb_standard_device_descriptor_t *device_descriptor,
172 const usb_standard_interface_descriptor_t *interface_descriptor)
173{
174 device_t *child = NULL;
175 char *child_name = NULL;
176 usbmid_interface_t *child_as_interface = NULL;
177 int rc;
178
179 /* Create the device. */
180 child = create_device();
181 if (child == NULL) {
182 rc = ENOMEM;
183 goto error_leave;
184 }
185
186 /*
187 * Name is class name followed by interface number.
188 * The interface number shall provide uniqueness while the
189 * class name something humanly understandable.
190 */
191 rc = asprintf(&child_name, "%s%d",
192 usb_str_class(interface_descriptor->interface_class),
193 (int) interface_descriptor->interface_number);
194 if (rc < 0) {
195 goto error_leave;
196 }
197
198 child_as_interface = usbmid_interface_create(child,
199 (int) interface_descriptor->interface_number);
200 if (child_as_interface == NULL) {
201 rc = ENOMEM;
202 goto error_leave;
203 }
204
205 child->driver_data = child_as_interface;
206 child->parent = parent->dev;
207 child->name = child_name;
208 child->ops = &child_device_ops;
209
210 rc = usb_device_create_match_ids_from_interface(device_descriptor,
211 interface_descriptor,
212 &child->match_ids);
213 if (rc != EOK) {
214 goto error_leave;
215 }
216
217 rc = child_device_register(child, parent->dev);
218 if (rc != EOK) {
219 goto error_leave;
220 }
221
222 return EOK;
223
224error_leave:
225 if (child != NULL) {
226 child->name = NULL;
227 /* This takes care of match_id deallocation as well. */
228 delete_device(child);
229 }
230 if (child_name != NULL) {
231 free(child_name);
232 }
233 if (child_as_interface != NULL) {
234 free(child_as_interface);
235 }
236
237 return rc;
238}
239
240/**
241 * @}
242 */
Note: See TracBrowser for help on using the repository browser.