source: mainline/uspace/drv/usbmid/usbmid.c@ c723b772

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

MID driver can tell interface number to child

  • 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(interface_descriptor,
211 &child->match_ids);
212 if (rc != EOK) {
213 goto error_leave;
214 }
215
216 rc = child_device_register(child, parent->dev);
217 if (rc != EOK) {
218 goto error_leave;
219 }
220
221 return EOK;
222
223error_leave:
224 if (child != NULL) {
225 child->name = NULL;
226 /* This takes care of match_id deallocation as well. */
227 delete_device(child);
228 }
229 if (child_name != NULL) {
230 free(child_name);
231 }
232 if (child_as_interface != NULL) {
233 free(child_as_interface);
234 }
235
236 return rc;
237}
238
239/**
240 * @}
241 */
Note: See TracBrowser for help on using the repository browser.