source: mainline/uspace/lib/usbvirt/main.c@ ca07cd3

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

Code cleanup, various bugfixes

The internal functions of virtual device framework always get
device structure as parameter, thus possible enabling more devices
within single task (that is not possible because currently there
is no way to pass extra argument into callback_connection()).

Also, added some missing comments and completely removed the device
id nonsense (devices can send their descriptors and the hub is able
to enable/disable its ports).

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 * Copyright (c) 2010 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 libusbvirt usb
30 * @{
31 */
32/** @file
33 * @brief Device registration with virtual USB framework.
34 */
35#include <devmap.h>
36#include <fcntl.h>
37#include <vfs/vfs.h>
38#include <errno.h>
39#include <stdlib.h>
40#include <mem.h>
41#include <assert.h>
42
43#include "hub.h"
44#include "device.h"
45#include "private.h"
46
47#define NAMESPACE "usb"
48
49/** Virtual device wrapper. */
50typedef struct {
51 /** Actual device. */
52 usbvirt_device_t *device;
53 /** Phone to host controller. */
54 int vhcd_phone;
55 /** Device id. */
56 ipcarg_t id;
57 /** Linked-list member. */
58 link_t link;
59} virtual_device_t;
60
61/*** List of known device. */
62static LIST_INITIALIZE(device_list);
63
64/** Find virtual device wrapper based on the contents. */
65static virtual_device_t *find_device(usbvirt_device_t *device)
66{
67 if (list_empty(&device_list)) {
68 return NULL;
69 }
70
71 link_t *pos;
72 for (pos = device_list.next; pos != &device_list; pos = pos->next) {
73 virtual_device_t *dev
74 = list_get_instance(pos, virtual_device_t, link);
75 if (dev->device == device) {
76 return dev;
77 }
78 }
79
80 return NULL;
81}
82
83/** Find virtual device wrapper by its id. */
84static virtual_device_t *find_device_by_id(ipcarg_t id)
85{
86 if (list_empty(&device_list)) {
87 return NULL;
88 }
89
90 link_t *pos;
91 for (pos = device_list.next; pos != &device_list; pos = pos->next) {
92 virtual_device_t *dev
93 = list_get_instance(pos, virtual_device_t, link);
94 if (dev->id == id) {
95 return dev;
96 }
97 }
98
99 return NULL;
100}
101
102/** Reply to a control transfer. */
103static int control_transfer_reply(usbvirt_device_t *device,
104 usb_endpoint_t endpoint, void *buffer, size_t size)
105{
106 usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
107 if (transfer->data != NULL) {
108 free(transfer->data);
109 }
110 transfer->data = malloc(size);
111 memcpy(transfer->data, buffer, size);
112 transfer->data_size = size;
113
114 return EOK;
115}
116
117/** Initialize virtual device. */
118static void device_init(usbvirt_device_t *dev)
119{
120 dev->transaction_out = transaction_out;
121 dev->transaction_setup = transaction_setup;
122 dev->transaction_in = transaction_in;
123
124 dev->control_transfer_reply = control_transfer_reply;
125
126 dev->state = USBVIRT_STATE_DEFAULT;
127 dev->address = 0;
128 dev->new_address = -1;
129
130 size_t i;
131 for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
132 usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
133 transfer->direction = 0;
134 transfer->request = NULL;
135 transfer->request_size = 0;
136 transfer->data = NULL;
137 transfer->data_size = 0;
138 }
139}
140
141/** Add a virtual device.
142 * The returned device (if not NULL) shall be destroy via destroy_device().
143 */
144static virtual_device_t *add_device(usbvirt_device_t *dev)
145{
146 assert(find_device(dev) == NULL);
147 virtual_device_t *new_device
148 = (virtual_device_t *) malloc(sizeof(virtual_device_t));
149
150 new_device->device = dev;
151 link_initialize(&new_device->link);
152
153 list_append(&new_device->link, &device_list);
154
155 return new_device;
156}
157
158/** Destroy virtual device. */
159static void destroy_device(virtual_device_t *dev)
160{
161 if (dev->vhcd_phone > 0) {
162 ipc_hangup(dev->vhcd_phone);
163 }
164
165 list_remove(&dev->link);
166
167 free(dev);
168}
169
170/** Callback connection handler. */
171static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
172{
173 // FIXME - determine which device just called back
174 virtual_device_t *dev = find_device_by_id(0);
175 if (dev == NULL) {
176 ipc_answer_0(iid, EINVAL);
177 printf("Ooops\n");
178 return;
179 }
180
181 device_callback_connection(dev->device, iid, icall);
182}
183
184/** Create necessary phones for comunication with virtual HCD.
185 * This function wraps following calls:
186 * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
187 * -# access phone of file opened in previous step
188 * -# create callback through just opened phone
189 * -# create handler for calling on data from host to function
190 * -# return the (outgoing) phone
191 *
192 * @warning This function is wrapper for several actions and therefore
193 * it is not possible - in case of error - to determine at which point
194 * error occured.
195 *
196 * @param hcd_path HCD identification under devfs
197 * (without <code>/dev/usb/</code>).
198 * @param dev Device to connect.
199 * @return EOK on success or error code from errno.h.
200 */
201int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
202{
203 virtual_device_t *virtual_device = find_device(dev);
204 if (virtual_device != NULL) {
205 return EEXISTS;
206 }
207
208 char dev_path[DEVMAP_NAME_MAXLEN + 1];
209 snprintf(dev_path, DEVMAP_NAME_MAXLEN,
210 "/dev/%s/%s", NAMESPACE, hcd_path);
211
212 int fd = open(dev_path, O_RDONLY);
213 if (fd < 0) {
214 return fd;
215 }
216
217 int hcd_phone = fd_phone(fd);
218
219 if (hcd_phone < 0) {
220 return hcd_phone;
221 }
222
223 ipcarg_t phonehash;
224 int rc = ipc_connect_to_me(hcd_phone, 1, 0, 0, &phonehash);
225 if (rc != EOK) {
226 return rc;
227 }
228
229 device_init(dev);
230
231 virtual_device = add_device(dev);
232 virtual_device->vhcd_phone = hcd_phone;
233 virtual_device->id = 0;
234
235 async_new_connection(phonehash, 0, NULL, callback_connection);
236
237 return EOK;
238}
239
240/** Prepares device as local.
241 * This is useful if you want to have a virtual device in the same task
242 * as HCD.
243 *
244 * @param dev Device to connect.
245 * @return Error code.
246 * @retval EOK Device connected.
247 * @retval EEXISTS This device is already connected.
248 */
249int usbvirt_connect_local(usbvirt_device_t *dev)
250{
251 virtual_device_t *virtual_device = find_device(dev);
252 if (virtual_device != NULL) {
253 return EEXISTS;
254 }
255
256 device_init(dev);
257
258 virtual_device = add_device(dev);
259 virtual_device->vhcd_phone = -1;
260 virtual_device->id = 0;
261
262 return EOK;
263}
264
265/** Disconnects device from HCD.
266 *
267 * @param dev Device to be disconnected.
268 * @return Error code.
269 * @retval EOK Device connected.
270 * @retval ENOENT This device is not connected.
271 */
272int usbvirt_disconnect(usbvirt_device_t *dev)
273{
274 virtual_device_t *virtual_device = find_device(dev);
275 if (virtual_device == NULL) {
276 return ENOENT;
277 }
278
279 destroy_device(virtual_device);
280
281 return EOK;
282}
283
284
285/**
286 * @}
287 */
Note: See TracBrowser for help on using the repository browser.