source: mainline/uspace/lib/usbvirt/main.c@ 954ea70

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

usbvirt: standard requests handled better

Also, SET_ADDRESS works according to specification.

  • Property mode set to 100644
File size: 5.5 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 Main handler for virtual USB device.
34 */
35#include <devmap.h>
36#include <fcntl.h>
37#include <vfs/vfs.h>
38#include <errno.h>
39#include <stdlib.h>
40
41#include "hub.h"
42#include "device.h"
43#include "private.h"
44
45#define NAMESPACE "usb"
46
47usbvirt_device_t *device = NULL;
48
49
50static void handle_data_to_device(ipc_callid_t iid, ipc_call_t icall)
51{
52 usb_address_t address = IPC_GET_ARG1(icall);
53 usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
54 size_t expected_len = IPC_GET_ARG5(icall);
55
56 if (address != device->address) {
57 ipc_answer_0(iid, EADDRNOTAVAIL);
58 return;
59 }
60
61 size_t len = 0;
62 void * buffer = NULL;
63 if (expected_len > 0) {
64 int rc = async_data_write_accept(&buffer, false,
65 1, USB_MAX_PAYLOAD_SIZE,
66 0, &len);
67
68 if (rc != EOK) {
69 ipc_answer_0(iid, rc);
70 return;
71 }
72 }
73
74 device->receive_data(device, endpoint, buffer, len);
75
76 if (buffer != NULL) {
77 free(buffer);
78 }
79
80 ipc_answer_0(iid, EOK);
81}
82
83static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
84{
85 ipc_answer_0(iid, EOK);
86
87 while (true) {
88 ipc_callid_t callid;
89 ipc_call_t call;
90
91 callid = async_get_call(&call);
92 switch (IPC_GET_METHOD(call)) {
93 case IPC_M_PHONE_HUNGUP:
94 ipc_answer_0(callid, EOK);
95 return;
96
97 case IPC_M_USBVIRT_DATA_TO_DEVICE:
98 handle_data_to_device(callid, call);
99 break;
100
101 default:
102 ipc_answer_0(callid, EINVAL);
103 break;
104 }
105 }
106}
107
108static void device_init(usbvirt_device_t *dev)
109{
110 dev->send_data = usbvirt_data_to_host;
111 dev->receive_data = handle_incoming_data;
112 dev->state = USBVIRT_STATE_DEFAULT;
113 dev->address = 0;
114}
115
116int usbvirt_data_to_host(struct usbvirt_device *dev,
117 usb_endpoint_t endpoint, void *buffer, size_t size)
118{
119 int phone = dev->vhcd_phone_;
120
121 if (phone < 0) {
122 return EINVAL;
123 }
124 if ((buffer == NULL) && (size != 0)) {
125 return EINVAL;
126 }
127
128 ipc_call_t answer_data;
129 ipcarg_t answer_rc;
130 aid_t req;
131 int rc;
132
133 req = async_send_3(phone,
134 IPC_M_USBVIRT_DATA_FROM_DEVICE,
135 dev->address,
136 endpoint,
137 size,
138 &answer_data);
139
140 if (size > 0) {
141 rc = async_data_write_start(phone, buffer, size);
142 if (rc != EOK) {
143 async_wait_for(req, NULL);
144 return rc;
145 }
146 }
147
148 async_wait_for(req, &answer_rc);
149 rc = (int)answer_rc;
150 if (rc != EOK) {
151 return rc;
152 }
153
154 return EOK;
155}
156
157/** Create necessary phones for comunication with virtual HCD.
158 * This function wraps following calls:
159 * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
160 * -# access phone of file opened in previous step
161 * -# create callback through just opened phone
162 * -# create handler for calling on data from host to function
163 * -# return the (outgoing) phone
164 *
165 * @warning This function is wrapper for several actions and therefore
166 * it is not possible - in case of error - to determine at which point
167 * error occured.
168 *
169 * @param hcd_path HCD identification under devfs
170 * (without <code>/dev/usb/</code>).
171 * @param dev Device to connect.
172 * @return EOK on success or error code from errno.h.
173 */
174int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
175{
176 char dev_path[DEVMAP_NAME_MAXLEN + 1];
177 snprintf(dev_path, DEVMAP_NAME_MAXLEN,
178 "/dev/%s/%s", NAMESPACE, hcd_path);
179
180 int fd = open(dev_path, O_RDONLY);
181 if (fd < 0) {
182 return fd;
183 }
184
185 int hcd_phone = fd_phone(fd);
186
187 if (hcd_phone < 0) {
188 return hcd_phone;
189 }
190
191 ipcarg_t phonehash;
192 int rc = ipc_connect_to_me(hcd_phone, 1, dev->device_id_, 0, &phonehash);
193 if (rc != EOK) {
194 return rc;
195 }
196
197 dev->vhcd_phone_ = hcd_phone;
198 device_init(dev);
199
200 device = dev;
201
202 async_new_connection(phonehash, 0, NULL, callback_connection);
203
204 return EOK;
205}
206
207/** Prepares device as local.
208 * This is useful if you want to have a virtual device in the same task
209 * as HCD.
210 *
211 * @param dev Device to connect.
212 * @return Always EOK.
213 */
214int usbvirt_connect_local(usbvirt_device_t *dev)
215{
216 dev->vhcd_phone_ = -1;
217 device_init(dev);
218
219 device = dev;
220
221 return EOK;
222}
223
224/** Disconnects device from HCD.
225 *
226 * @return Always EOK.
227 */
228int usbvirt_disconnect(void)
229{
230 ipc_hangup(device->vhcd_phone_);
231
232 device = NULL;
233
234 return EOK;
235}
236
237
238/**
239 * @}
240 */
Note: See TracBrowser for help on using the repository browser.