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

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

Debugging support for libusbvirt

Added methods debug and lib_debug to device structure to simplify
debugging. Each method gets as a parameter debug level describing
verbosity of the message and also message tag that allows filtering
based on message type (e.g. messages related to transactions, to
device requests etc.).

  • 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->debug = user_debug;
127 dev->lib_debug = lib_debug;
128
129 dev->state = USBVIRT_STATE_DEFAULT;
130 dev->address = 0;
131 dev->new_address = -1;
132
133 size_t i;
134 for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
135 usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
136 transfer->direction = 0;
137 transfer->request = NULL;
138 transfer->request_size = 0;
139 transfer->data = NULL;
140 transfer->data_size = 0;
141 }
142}
143
144/** Add a virtual device.
145 * The returned device (if not NULL) shall be destroy via destroy_device().
146 */
147static virtual_device_t *add_device(usbvirt_device_t *dev)
148{
149 assert(find_device(dev) == NULL);
150 virtual_device_t *new_device
151 = (virtual_device_t *) malloc(sizeof(virtual_device_t));
152
153 new_device->device = dev;
154 link_initialize(&new_device->link);
155
156 list_append(&new_device->link, &device_list);
157
158 return new_device;
159}
160
161/** Destroy virtual device. */
162static void destroy_device(virtual_device_t *dev)
163{
164 if (dev->vhcd_phone > 0) {
165 ipc_hangup(dev->vhcd_phone);
166 }
167
168 list_remove(&dev->link);
169
170 free(dev);
171}
172
173/** Callback connection handler. */
174static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
175{
176 // FIXME - determine which device just called back
177 virtual_device_t *dev = find_device_by_id(0);
178 if (dev == NULL) {
179 ipc_answer_0(iid, EINVAL);
180 printf("Ooops\n");
181 return;
182 }
183
184 device_callback_connection(dev->device, iid, icall);
185}
186
187/** Create necessary phones for comunication with virtual HCD.
188 * This function wraps following calls:
189 * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
190 * -# access phone of file opened in previous step
191 * -# create callback through just opened phone
192 * -# create handler for calling on data from host to function
193 * -# return the (outgoing) phone
194 *
195 * @warning This function is wrapper for several actions and therefore
196 * it is not possible - in case of error - to determine at which point
197 * error occured.
198 *
199 * @param hcd_path HCD identification under devfs
200 * (without <code>/dev/usb/</code>).
201 * @param dev Device to connect.
202 * @return EOK on success or error code from errno.h.
203 */
204int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
205{
206 virtual_device_t *virtual_device = find_device(dev);
207 if (virtual_device != NULL) {
208 return EEXISTS;
209 }
210
211 char dev_path[DEVMAP_NAME_MAXLEN + 1];
212 snprintf(dev_path, DEVMAP_NAME_MAXLEN,
213 "/dev/%s/%s", NAMESPACE, hcd_path);
214
215 int fd = open(dev_path, O_RDONLY);
216 if (fd < 0) {
217 return fd;
218 }
219
220 int hcd_phone = fd_phone(fd);
221
222 if (hcd_phone < 0) {
223 return hcd_phone;
224 }
225
226 ipcarg_t phonehash;
227 int rc = ipc_connect_to_me(hcd_phone, 1, 0, 0, &phonehash);
228 if (rc != EOK) {
229 return rc;
230 }
231
232 device_init(dev);
233
234 virtual_device = add_device(dev);
235 virtual_device->vhcd_phone = hcd_phone;
236 virtual_device->id = 0;
237
238 async_new_connection(phonehash, 0, NULL, callback_connection);
239
240 return EOK;
241}
242
243/** Prepares device as local.
244 * This is useful if you want to have a virtual device in the same task
245 * as HCD.
246 *
247 * @param dev Device to connect.
248 * @return Error code.
249 * @retval EOK Device connected.
250 * @retval EEXISTS This device is already connected.
251 */
252int usbvirt_connect_local(usbvirt_device_t *dev)
253{
254 virtual_device_t *virtual_device = find_device(dev);
255 if (virtual_device != NULL) {
256 return EEXISTS;
257 }
258
259 device_init(dev);
260
261 virtual_device = add_device(dev);
262 virtual_device->vhcd_phone = -1;
263 virtual_device->id = 0;
264
265 return EOK;
266}
267
268/** Disconnects device from HCD.
269 *
270 * @param dev Device to be disconnected.
271 * @return Error code.
272 * @retval EOK Device connected.
273 * @retval ENOENT This device is not connected.
274 */
275int usbvirt_disconnect(usbvirt_device_t *dev)
276{
277 virtual_device_t *virtual_device = find_device(dev);
278 if (virtual_device == NULL) {
279 return ENOENT;
280 }
281
282 destroy_device(virtual_device);
283
284 return EOK;
285}
286
287
288/**
289 * @}
290 */
Note: See TracBrowser for help on using the repository browser.