source: mainline/uspace/drv/bus/usb/usbmid/usbmid.c@ d3a1ad58

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d3a1ad58 was d3a1ad58, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

usbmid: Add endpoint management forwarding.

  • Property mode set to 100644
File size: 6.4 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/**
34 * @file
35 * Helper functions.
36 */
37#include <errno.h>
38#include <str_error.h>
39#include <stdlib.h>
40#include <usb_iface.h>
41#include <usb/dev/pipes.h>
42#include <usb/classes/classes.h>
43#include <usb/dev/recognise.h>
44#include "usbmid.h"
45/** Get host controller handle by calling the parent usb_device_t.
46 *
47 * @param[in] fun Device function the operation is running on.
48 * @param[out] handle Storage for the host controller handle.
49 * @return Error code.
50 */
51static int usb_iface_device_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
52{
53 assert(handle);
54 assert(fun);
55 usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun));
56 assert(usb_dev);
57 *handle = usb_device_hc_handle(usb_dev);
58 return EOK;
59}
60
61/** Get USB device address by calling the parent usb_device_t.
62 *
63 * @param[in] fun Device function the operation is running on.
64 * @param[in] handle Devman handle of USB device we want address of.
65 * @param[out] address Storage for USB address of device with handle @p handle.
66 * @return Error code.
67 */
68static int usb_iface_device_address(ddf_fun_t *fun, usb_address_t *address)
69{
70 assert(address);
71 assert(fun);
72 usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun));
73 assert(usb_dev);
74 *address = usb_device_address(usb_dev);
75 return EOK;
76}
77
78/** Callback for DDF USB interface. */
79static int usb_iface_iface(ddf_fun_t *fun, int *iface_no)
80{
81 usbmid_interface_t *iface = ddf_fun_data_get(fun);
82 assert(iface);
83
84 if (iface_no != NULL) {
85 *iface_no = iface->interface_no;
86 }
87
88 return EOK;
89}
90
91static int usb_iface_register_endpoint(ddf_fun_t *fun, usb_endpoint_t ep,
92 usb_transfer_type_t type, usb_direction_t dir, size_t mps, unsigned inter)
93{
94 usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun));
95 assert(usb_dev);
96 async_exch_t *exch = usb_device_bus_exchange_begin(usb_dev);
97 if (!exch)
98 return ENOMEM;
99 const int ret = usb_register_endpoint(exch, ep, type, dir, mps, inter);
100 usb_device_bus_exchange_end(exch);
101 return ret;
102}
103
104static int usb_iface_unregister_endpoint(ddf_fun_t *fun, usb_endpoint_t ep,
105 usb_direction_t dir)
106{
107 usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun));
108 assert(usb_dev);
109 async_exch_t *exch = usb_device_bus_exchange_begin(usb_dev);
110 if (!exch)
111 return ENOMEM;
112 const int ret = usb_unregister_endpoint(exch, ep, dir);
113 usb_device_bus_exchange_end(exch);
114 return ret;
115}
116
117/** DDF interface of the child - interface function. */
118static usb_iface_t child_usb_iface = {
119 .get_hc_handle = usb_iface_device_hc_handle,
120 .get_my_address = usb_iface_device_address,
121 .get_my_interface = usb_iface_iface,
122 .register_endpoint = usb_iface_register_endpoint,
123 .unregister_endpoint = usb_iface_unregister_endpoint,
124};
125
126/** Operations for children - interface functions. */
127static ddf_dev_ops_t child_device_ops = {
128 .interfaces[USB_DEV_IFACE] = &child_usb_iface
129};
130
131int usbmid_interface_destroy(usbmid_interface_t *mid_iface)
132{
133 assert(mid_iface);
134 assert_link_not_used(&mid_iface->link);
135 const int ret = ddf_fun_unbind(mid_iface->fun);
136 if (ret != EOK) {
137 return ret;
138 }
139 ddf_fun_destroy(mid_iface->fun);
140 return EOK;
141}
142
143/** Spawn new child device from one interface.
144 *
145 * @param parent Parent MID device.
146 * @param iface Interface information.
147 * @param device_descriptor Device descriptor.
148 * @param interface_descriptor Interface descriptor.
149 * @return Error code.
150 */
151int usbmid_spawn_interface_child(usb_device_t *parent,
152 usbmid_interface_t **iface_ret,
153 const usb_standard_device_descriptor_t *device_descriptor,
154 const usb_standard_interface_descriptor_t *interface_descriptor)
155{
156 ddf_fun_t *child = NULL;
157 char *child_name = NULL;
158 int rc;
159
160 /*
161 * Name is class name followed by interface number.
162 * The interface number shall provide uniqueness while the
163 * class name something humanly understandable.
164 */
165 rc = asprintf(&child_name, "%s%hhu",
166 usb_str_class(interface_descriptor->interface_class),
167 interface_descriptor->interface_number);
168 if (rc < 0) {
169 return ENOMEM;
170 }
171
172 /* Create the device. */
173 child = usb_device_ddf_fun_create(parent, fun_inner, child_name);
174 free(child_name);
175 if (child == NULL) {
176 return ENOMEM;
177 }
178
179 match_id_list_t match_ids;
180 init_match_ids(&match_ids);
181
182 rc = usb_device_create_match_ids_from_interface(device_descriptor,
183 interface_descriptor, &match_ids);
184 if (rc != EOK) {
185 ddf_fun_destroy(child);
186 return rc;
187 }
188
189 list_foreach(match_ids.ids, link) {
190 match_id_t *match_id = list_get_instance(link, match_id_t, link);
191 rc = ddf_fun_add_match_id(child, match_id->id, match_id->score);
192 if (rc != EOK) {
193 clean_match_ids(&match_ids);
194 ddf_fun_destroy(child);
195 return rc;
196 }
197 }
198 clean_match_ids(&match_ids);
199 ddf_fun_set_ops(child, &child_device_ops);
200
201 usbmid_interface_t *iface = ddf_fun_data_alloc(child, sizeof(*iface));
202
203 iface->fun = child;
204 iface->interface_no = interface_descriptor->interface_number;
205 link_initialize(&iface->link);
206
207 rc = ddf_fun_bind(child);
208 if (rc != EOK) {
209 /* This takes care of match_id deallocation as well. */
210 ddf_fun_destroy(child);
211 return rc;
212 }
213 *iface_ret = iface;
214
215 return EOK;
216}
217
218/**
219 * @}
220 */
Note: See TracBrowser for help on using the repository browser.