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
RevLine 
[bc9a629]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
[b8100da]29/** @addtogroup libusbvirt usb
[bc9a629]30 * @{
31 */
32/** @file
[b8100da]33 * @brief Main handler for virtual USB device.
[bc9a629]34 */
35#include <devmap.h>
36#include <fcntl.h>
37#include <vfs/vfs.h>
38#include <errno.h>
39#include <stdlib.h>
40
[b8100da]41#include "hub.h"
42#include "device.h"
43#include "private.h"
44
[bc9a629]45#define NAMESPACE "usb"
46
[b8100da]47usbvirt_device_t *device = NULL;
48
[bc9a629]49
50static void handle_data_to_device(ipc_callid_t iid, ipc_call_t icall)
51{
[47e3a8e]52 usb_address_t address = IPC_GET_ARG1(icall);
53 usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
[b791e3e]54 size_t expected_len = IPC_GET_ARG5(icall);
[47e3a8e]55
56 if (address != device->address) {
57 ipc_answer_0(iid, EADDRNOTAVAIL);
58 return;
59 }
[bc9a629]60
[b791e3e]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 }
[bc9a629]72 }
73
[186d630]74 device->receive_data(device, endpoint, buffer, len);
[bc9a629]75
[b791e3e]76 if (buffer != NULL) {
77 free(buffer);
78 }
[bc9a629]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
[b8100da]97 case IPC_M_USBVIRT_DATA_TO_DEVICE:
[bc9a629]98 handle_data_to_device(callid, call);
99 break;
100
101 default:
102 ipc_answer_0(callid, EINVAL);
103 break;
104 }
105 }
106}
107
[47e3a8e]108static void device_init(usbvirt_device_t *dev)
109{
110 dev->send_data = usbvirt_data_to_host;
[186d630]111 dev->receive_data = handle_incoming_data;
[47e3a8e]112 dev->state = USBVIRT_STATE_DEFAULT;
113 dev->address = 0;
114}
115
[b8100da]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 }
[954ea70]124 if ((buffer == NULL) && (size != 0)) {
[b8100da]125 return EINVAL;
126 }
127
128 ipc_call_t answer_data;
129 ipcarg_t answer_rc;
130 aid_t req;
131 int rc;
132
[954ea70]133 req = async_send_3(phone,
[b8100da]134 IPC_M_USBVIRT_DATA_FROM_DEVICE,
[47e3a8e]135 dev->address,
[b8100da]136 endpoint,
[954ea70]137 size,
[b8100da]138 &answer_data);
139
[954ea70]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 }
[b8100da]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
[bc9a629]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>).
[186d630]171 * @param dev Device to connect.
[b8100da]172 * @return EOK on success or error code from errno.h.
[bc9a629]173 */
[b8100da]174int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
[bc9a629]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;
[b8100da]192 int rc = ipc_connect_to_me(hcd_phone, 1, dev->device_id_, 0, &phonehash);
[bc9a629]193 if (rc != EOK) {
194 return rc;
195 }
[b8100da]196
197 dev->vhcd_phone_ = hcd_phone;
[47e3a8e]198 device_init(dev);
[b8100da]199
200 device = dev;
201
[bc9a629]202 async_new_connection(phonehash, 0, NULL, callback_connection);
203
[b8100da]204 return EOK;
[bc9a629]205}
206
[186d630]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
[b791e3e]219 device = dev;
220
[186d630]221 return EOK;
222}
[bc9a629]223
[186d630]224/** Disconnects device from HCD.
225 *
226 * @return Always EOK.
227 */
[b8100da]228int usbvirt_disconnect(void)
229{
230 ipc_hangup(device->vhcd_phone_);
[bc9a629]231
[b8100da]232 device = NULL;
[bc9a629]233
234 return EOK;
235}
236
[b8100da]237
[bc9a629]238/**
239 * @}
240 */
Note: See TracBrowser for help on using the repository browser.