Changeset ca07cd3 in mainline for uspace/lib/usbvirt/main.c
- Timestamp:
- 2010-10-25T13:23:33Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 23cb44b
- Parents:
- 355f7c2
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbvirt/main.c
r355f7c2 rca07cd3 31 31 */ 32 32 /** @file 33 * @brief Main handler for virtual USB device.33 * @brief Device registration with virtual USB framework. 34 34 */ 35 35 #include <devmap.h> … … 39 39 #include <stdlib.h> 40 40 #include <mem.h> 41 #include <assert.h> 41 42 42 43 #include "hub.h" … … 46 47 #define NAMESPACE "usb" 47 48 48 usbvirt_device_t *device = NULL; 49 50 static void handle_setup_transaction(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_ARG3(icall); 55 56 if (address != device->address) { 57 ipc_answer_0(iid, EADDRNOTAVAIL); 58 return; 59 } 60 61 if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) { 62 ipc_answer_0(iid, EINVAL); 63 return; 64 } 65 66 if (expected_len == 0) { 67 ipc_answer_0(iid, EINVAL); 68 return; 69 } 70 71 size_t len = 0; 72 void * buffer = NULL; 73 int rc = async_data_write_accept(&buffer, false, 74 1, USB_MAX_PAYLOAD_SIZE, 0, &len); 75 76 if (rc != EOK) { 77 ipc_answer_0(iid, rc); 78 return; 79 } 80 81 rc = device->transaction_setup(device, endpoint, buffer, len); 82 83 ipc_answer_0(iid, rc); 84 } 85 86 87 static void handle_out_transaction(ipc_callid_t iid, ipc_call_t icall) 88 { 89 usb_address_t address = IPC_GET_ARG1(icall); 90 usb_endpoint_t endpoint = IPC_GET_ARG2(icall); 91 size_t expected_len = IPC_GET_ARG3(icall); 92 93 if (address != device->address) { 94 ipc_answer_0(iid, EADDRNOTAVAIL); 95 return; 96 } 97 98 if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) { 99 ipc_answer_0(iid, EINVAL); 100 return; 101 } 102 103 int rc = EOK; 104 105 size_t len = 0; 106 void *buffer = NULL; 107 108 if (expected_len > 0) { 109 rc = async_data_write_accept(&buffer, false, 110 1, USB_MAX_PAYLOAD_SIZE, 0, &len); 111 112 if (rc != EOK) { 113 ipc_answer_0(iid, rc); 114 return; 49 /** Virtual device wrapper. */ 50 typedef 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. */ 62 static LIST_INITIALIZE(device_list); 63 64 /** Find virtual device wrapper based on the contents. */ 65 static 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; 115 77 } 116 78 } 117 79 118 rc = device->transaction_out(device, endpoint, buffer, len); 119 120 if (buffer != NULL) { 121 free(buffer); 122 } 123 124 ipc_answer_0(iid, rc); 125 } 126 127 128 129 static void handle_in_transaction(ipc_callid_t iid, ipc_call_t icall) 130 { 131 usb_address_t address = IPC_GET_ARG1(icall); 132 usb_endpoint_t endpoint = IPC_GET_ARG2(icall); 133 size_t expected_len = IPC_GET_ARG3(icall); 134 135 if (address != device->address) { 136 ipc_answer_0(iid, EADDRNOTAVAIL); 137 return; 138 } 139 140 if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) { 141 ipc_answer_0(iid, EINVAL); 142 return; 143 } 144 145 int rc = EOK; 146 147 void *buffer = expected_len > 0 ? malloc(expected_len) : NULL; 148 size_t len; 149 150 rc = device->transaction_in(device, endpoint, buffer, expected_len, &len); 151 /* 152 * If the request was processed, we will send data back. 153 */ 154 if (rc == EOK) { 155 size_t receive_len; 156 if (!async_data_read_receive(&iid, &receive_len)) { 157 ipc_answer_0(iid, EINVAL); 158 return; 80 return NULL; 81 } 82 83 /** Find virtual device wrapper by its id. */ 84 static 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; 159 96 } 160 async_data_read_finalize(iid, buffer, receive_len); 161 } 162 163 ipc_answer_0(iid, rc); 164 } 165 166 167 168 static void callback_connection(ipc_callid_t iid, ipc_call_t *icall) 169 { 170 ipc_answer_0(iid, EOK); 171 172 while (true) { 173 ipc_callid_t callid; 174 ipc_call_t call; 175 176 callid = async_get_call(&call); 177 switch (IPC_GET_METHOD(call)) { 178 case IPC_M_PHONE_HUNGUP: 179 ipc_answer_0(callid, EOK); 180 return; 181 182 case IPC_M_USBVIRT_TRANSACTION_SETUP: 183 handle_setup_transaction(callid, call); 184 break; 185 186 case IPC_M_USBVIRT_TRANSACTION_OUT: 187 handle_out_transaction(callid, call); 188 break; 189 190 case IPC_M_USBVIRT_TRANSACTION_IN: 191 handle_in_transaction(callid, call); 192 break; 193 194 default: 195 ipc_answer_0(callid, EINVAL); 196 break; 197 } 198 } 199 } 200 201 static int control_transfer_reply(struct usbvirt_device *device, 97 } 98 99 return NULL; 100 } 101 102 /** Reply to a control transfer. */ 103 static int control_transfer_reply(usbvirt_device_t *device, 202 104 usb_endpoint_t endpoint, void *buffer, size_t size) 203 105 { … … 213 115 } 214 116 117 /** Initialize virtual device. */ 215 118 static void device_init(usbvirt_device_t *dev) 216 119 { … … 223 126 dev->state = USBVIRT_STATE_DEFAULT; 224 127 dev->address = 0; 128 dev->new_address = -1; 225 129 226 130 size_t i; … … 235 139 } 236 140 141 /** Add a virtual device. 142 * The returned device (if not NULL) shall be destroy via destroy_device(). 143 */ 144 static 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. */ 159 static 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. */ 171 static 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 237 184 /** Create necessary phones for comunication with virtual HCD. 238 185 * This function wraps following calls: … … 254 201 int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path) 255 202 { 203 virtual_device_t *virtual_device = find_device(dev); 204 if (virtual_device != NULL) { 205 return EEXISTS; 206 } 207 256 208 char dev_path[DEVMAP_NAME_MAXLEN + 1]; 257 209 snprintf(dev_path, DEVMAP_NAME_MAXLEN, … … 270 222 271 223 ipcarg_t phonehash; 272 int rc = ipc_connect_to_me(hcd_phone, 1, dev->device_id_, 0, &phonehash);224 int rc = ipc_connect_to_me(hcd_phone, 1, 0, 0, &phonehash); 273 225 if (rc != EOK) { 274 226 return rc; 275 227 } 276 228 277 dev->vhcd_phone_ = hcd_phone;278 229 device_init(dev); 279 230 280 device = dev; 231 virtual_device = add_device(dev); 232 virtual_device->vhcd_phone = hcd_phone; 233 virtual_device->id = 0; 281 234 282 235 async_new_connection(phonehash, 0, NULL, callback_connection); … … 290 243 * 291 244 * @param dev Device to connect. 292 * @return Always EOK. 245 * @return Error code. 246 * @retval EOK Device connected. 247 * @retval EEXISTS This device is already connected. 293 248 */ 294 249 int usbvirt_connect_local(usbvirt_device_t *dev) 295 250 { 296 dev->vhcd_phone_ = -1; 251 virtual_device_t *virtual_device = find_device(dev); 252 if (virtual_device != NULL) { 253 return EEXISTS; 254 } 255 297 256 device_init(dev); 298 257 299 device = dev; 258 virtual_device = add_device(dev); 259 virtual_device->vhcd_phone = -1; 260 virtual_device->id = 0; 300 261 301 262 return EOK; … … 304 265 /** Disconnects device from HCD. 305 266 * 306 * @return Always EOK. 307 */ 308 int usbvirt_disconnect(void) 309 { 310 ipc_hangup(device->vhcd_phone_); 311 312 device = NULL; 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 */ 272 int 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); 313 280 314 281 return EOK;
Note:
See TracChangeset
for help on using the changeset viewer.