Changes in uspace/lib/usbdev/src/pipes.c [b7fd2a0:e773f58] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/pipes.c
rb7fd2a0 re773f58 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch 4 5 * All rights reserved. 5 6 * … … 36 37 #include <usb/dev/request.h> 37 38 #include <usb/usb.h> 38 #include <usb _iface.h>39 #include <usb/dma_buffer.h> 39 40 40 41 #include <assert.h> 42 #include <bitops.h> 41 43 #include <async.h> 44 #include <as.h> 42 45 #include <errno.h> 43 46 #include <mem.h> … … 51 54 assert(pipe != NULL); 52 55 53 if (!pipe->auto_reset_halt || (pipe-> endpoint_no != 0)) {56 if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) { 54 57 return; 55 58 } … … 57 60 /* Prevent infinite recursion. */ 58 61 pipe->auto_reset_halt = false; 59 usb_ request_clear_endpoint_halt(pipe, 0);62 usb_pipe_clear_halt(pipe, pipe); 60 63 pipe->auto_reset_halt = true; 64 } 65 66 /* Helper structure to avoid passing loads of arguments through */ 67 typedef struct { 68 usb_pipe_t *pipe; 69 usb_direction_t dir; 70 bool is_control; // Only for checking purposes 71 72 usbhc_iface_transfer_request_t req; 73 74 size_t transferred_size; 75 } transfer_t; 76 77 /** 78 * Issue a transfer in a separate exchange. 79 */ 80 static errno_t transfer_common(transfer_t *t) 81 { 82 if (!t->pipe) 83 return EBADMEM; 84 85 /* Only control writes make sense without buffer */ 86 if ((t->dir != USB_DIRECTION_OUT || !t->is_control) && t->req.size == 0) 87 return EINVAL; 88 89 /* Nonzero size requires buffer */ 90 if (!dma_buffer_is_set(&t->req.buffer) && t->req.size != 0) 91 return EINVAL; 92 93 /* Check expected direction */ 94 if (t->pipe->desc.direction != USB_DIRECTION_BOTH && 95 t->pipe->desc.direction != t->dir) 96 return EBADF; 97 98 /* Check expected transfer type */ 99 if ((t->pipe->desc.transfer_type == USB_TRANSFER_CONTROL) != t->is_control) 100 return EBADF; 101 102 async_exch_t *exch = async_exchange_begin(t->pipe->bus_session); 103 if (!exch) 104 return ENOMEM; 105 106 t->req.dir = t->dir; 107 t->req.endpoint = t->pipe->desc.endpoint_no; 108 109 const errno_t rc = usbhc_transfer(exch, &t->req, &t->transferred_size); 110 111 async_exchange_end(exch); 112 113 if (rc == ESTALL) 114 clear_self_endpoint_halt(t->pipe); 115 116 return rc; 117 } 118 119 /** 120 * Setup the transfer request inside transfer according to dma buffer provided. 121 * 122 * TODO: The buffer could have been allocated as a more strict one. Currently, 123 * we assume that the policy is just the requested one. 124 */ 125 static void setup_dma_buffer(transfer_t *t, void *base, void *ptr, size_t size) 126 { 127 t->req.buffer.virt = base; 128 t->req.buffer.policy = t->pipe->desc.transfer_buffer_policy; 129 t->req.offset = ptr - base; 130 t->req.size = size; 131 } 132 133 /** 134 * Compatibility wrapper for reads/writes without preallocated buffer. 135 */ 136 static errno_t transfer_wrap_dma(transfer_t *t, void *buf, size_t size) 137 { 138 if (size == 0) { 139 setup_dma_buffer(t, NULL, NULL, 0); 140 return transfer_common(t); 141 } 142 143 void *dma_buf = usb_pipe_alloc_buffer(t->pipe, size); 144 setup_dma_buffer(t, dma_buf, dma_buf, size); 145 146 if (t->dir == USB_DIRECTION_OUT) 147 memcpy(dma_buf, buf, size); 148 149 const errno_t err = transfer_common(t); 150 151 if (!err && t->dir == USB_DIRECTION_IN) 152 memcpy(buf, dma_buf, t->transferred_size); 153 154 usb_pipe_free_buffer(t->pipe, dma_buf); 155 return err; 156 } 157 158 static errno_t prepare_control(transfer_t *t, const void *setup, size_t setup_size) 159 { 160 if ((setup == NULL) || (setup_size != 8)) 161 return EINVAL; 162 163 memcpy(&t->req.setup, setup, 8); 164 return EOK; 61 165 } 62 166 … … 70 174 * @param[out] data_buffer Buffer for incoming data. 71 175 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes). 72 * @param[out] data_transfer ed_size Number of bytes that were actually73 * transfer ed during the DATA stage.176 * @param[out] data_transferred_size Number of bytes that were actually 177 * transferred during the DATA stage. 74 178 * @return Error code. 75 179 */ 76 180 errno_t usb_pipe_control_read(usb_pipe_t *pipe, 77 181 const void *setup_buffer, size_t setup_buffer_size, 78 void *buffer, size_t buffer_size, size_t *transfered_size) 79 { 80 assert(pipe); 81 82 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 83 return EINVAL; 84 } 85 86 if ((buffer == NULL) || (buffer_size == 0)) { 87 return EINVAL; 88 } 89 90 if ((pipe->direction != USB_DIRECTION_BOTH) 91 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 92 return EBADF; 93 } 94 95 uint64_t setup_packet; 96 memcpy(&setup_packet, setup_buffer, 8); 97 98 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 99 size_t act_size = 0; 100 const errno_t rc = usb_read(exch, pipe->endpoint_no, setup_packet, buffer, 101 buffer_size, &act_size); 102 async_exchange_end(exch); 103 104 if (rc == ESTALL) { 105 clear_self_endpoint_halt(pipe); 106 } 107 108 if (rc == EOK && transfered_size != NULL) { 109 *transfered_size = act_size; 110 } 111 112 return rc; 182 void *buffer, size_t buffer_size, size_t *transferred_size) 183 { 184 errno_t err; 185 transfer_t transfer = { 186 .pipe = pipe, 187 .dir = USB_DIRECTION_IN, 188 .is_control = true, 189 }; 190 191 if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size))) 192 return err; 193 194 if ((err = transfer_wrap_dma(&transfer, buffer, buffer_size))) 195 return err; 196 197 if (transferred_size) 198 *transferred_size = transfer.transferred_size; 199 200 return EOK; 113 201 } 114 202 … … 129 217 { 130 218 assert(pipe); 131 132 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 133 return EINVAL; 134 } 135 136 if ((buffer == NULL) && (buffer_size > 0)) { 137 return EINVAL; 138 } 139 140 if ((buffer != NULL) && (buffer_size == 0)) { 141 return EINVAL; 142 } 143 144 if ((pipe->direction != USB_DIRECTION_BOTH) 145 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 146 return EBADF; 147 } 148 149 uint64_t setup_packet; 150 memcpy(&setup_packet, setup_buffer, 8); 151 152 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 153 const errno_t rc = usb_write(exch, 154 pipe->endpoint_no, setup_packet, buffer, buffer_size); 155 async_exchange_end(exch); 156 157 if (rc == ESTALL) { 158 clear_self_endpoint_halt(pipe); 159 } 160 161 return rc; 219 errno_t err; 220 transfer_t transfer = { 221 .pipe = pipe, 222 .dir = USB_DIRECTION_OUT, 223 .is_control = true, 224 }; 225 226 if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size))) 227 return err; 228 229 return transfer_wrap_dma(&transfer, (void *) buffer, buffer_size); 230 } 231 232 /** 233 * Allocate a buffer for data transmission, that satisfies the constraints 234 * imposed by the host controller. 235 * 236 * @param[in] pipe Pipe for which the buffer is allocated 237 * @param[in] size Size of the required buffer 238 */ 239 void *usb_pipe_alloc_buffer(usb_pipe_t *pipe, size_t size) 240 { 241 dma_buffer_t buf; 242 if (dma_buffer_alloc_policy(&buf, size, pipe->desc.transfer_buffer_policy)) 243 return NULL; 244 245 return buf.virt; 246 } 247 248 void usb_pipe_free_buffer(usb_pipe_t *pipe, void *buffer) 249 { 250 dma_buffer_t buf; 251 buf.virt = buffer; 252 dma_buffer_free(&buf); 162 253 } 163 254 … … 167 258 * @param[out] buffer Buffer where to store the data. 168 259 * @param[in] size Size of the buffer (in bytes). 169 * @param[out] size_transfer ed Number of bytes that were actually transfered.260 * @param[out] size_transferred Number of bytes that were actually transferred. 170 261 * @return Error code. 171 262 */ 172 263 errno_t usb_pipe_read(usb_pipe_t *pipe, 173 void *buffer, size_t size, size_t *size_transfered) 174 { 175 assert(pipe); 176 177 if (buffer == NULL) { 178 return EINVAL; 179 } 180 181 if (size == 0) { 182 return EINVAL; 183 } 184 185 if (pipe->direction != USB_DIRECTION_IN) { 186 return EBADF; 187 } 188 189 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 190 return EBADF; 191 } 192 193 /* Isochronous transfer are not supported (yet) */ 194 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 195 pipe->transfer_type != USB_TRANSFER_BULK) 196 return ENOTSUP; 197 198 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 199 size_t act_size = 0; 200 const errno_t rc = 201 usb_read(exch, pipe->endpoint_no, 0, buffer, size, &act_size); 202 async_exchange_end(exch); 203 204 if (rc == EOK && size_transfered != NULL) { 205 *size_transfered = act_size; 206 } 207 208 return rc; 264 void *buffer, size_t size, size_t *size_transferred) 265 { 266 assert(pipe); 267 errno_t err; 268 transfer_t transfer = { 269 .pipe = pipe, 270 .dir = USB_DIRECTION_IN, 271 }; 272 273 if ((err = transfer_wrap_dma(&transfer, buffer, size))) 274 return err; 275 276 if (size_transferred) 277 *size_transferred = transfer.transferred_size; 278 279 return EOK; 209 280 } 210 281 … … 219 290 { 220 291 assert(pipe); 221 222 if (buffer == NULL || size == 0) { 223 return EINVAL; 224 } 225 226 if (pipe->direction != USB_DIRECTION_OUT) { 227 return EBADF; 228 } 229 230 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 231 return EBADF; 232 } 233 234 /* Isochronous transfer are not supported (yet) */ 235 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 236 pipe->transfer_type != USB_TRANSFER_BULK) 237 return ENOTSUP; 238 239 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 240 const errno_t rc = usb_write(exch, pipe->endpoint_no, 0, buffer, size); 241 async_exchange_end(exch); 242 return rc; 292 transfer_t transfer = { 293 .pipe = pipe, 294 .dir = USB_DIRECTION_OUT, 295 }; 296 297 return transfer_wrap_dma(&transfer, (void *) buffer, size); 298 } 299 300 /** 301 * Request a read (in) transfer on an endpoint pipe, declaring that buffer 302 * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer. 303 * 304 * @param[in] pipe Pipe used for the transfer. 305 * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer. 306 * @param[in] size Size of the buffer (in bytes). 307 * @param[out] size_transferred Number of bytes that were actually transferred. 308 * @return Error code. 309 */ 310 errno_t usb_pipe_read_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size, 311 size_t *size_transferred) 312 { 313 assert(pipe); 314 errno_t err; 315 transfer_t transfer = { 316 .pipe = pipe, 317 .dir = USB_DIRECTION_IN, 318 }; 319 320 setup_dma_buffer(&transfer, base, ptr, size); 321 322 if ((err = transfer_common(&transfer))) 323 return err; 324 325 if (size_transferred) 326 *size_transferred = transfer.transferred_size; 327 328 return EOK; 329 } 330 331 /** 332 * Request a write (out) transfer on an endpoint pipe, declaring that buffer 333 * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer. 334 * 335 * @param[in] pipe Pipe used for the transfer. 336 * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer. 337 * @param[in] size Size of the buffer (in bytes). 338 * @return Error code. 339 */ 340 errno_t usb_pipe_write_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size) 341 { 342 assert(pipe); 343 transfer_t transfer = { 344 .pipe = pipe, 345 .dir = USB_DIRECTION_OUT, 346 }; 347 348 setup_dma_buffer(&transfer, base, ptr, size); 349 350 return transfer_common(&transfer); 243 351 } 244 352 … … 246 354 * 247 355 * @param pipe Endpoint pipe to be initialized. 248 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15). 249 * @param transfer_type Transfer type (e.g. interrupt or bulk). 250 * @param max_packet_size Maximum packet size in bytes. 251 * @param direction Endpoint direction (in/out). 252 * @return Error code. 253 */ 254 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_endpoint_t endpoint_no, 255 usb_transfer_type_t transfer_type, size_t max_packet_size, 256 usb_direction_t direction, unsigned packets, usb_dev_session_t *bus_session) 257 { 258 assert(pipe); 259 260 pipe->endpoint_no = endpoint_no; 261 pipe->transfer_type = transfer_type; 262 pipe->packets = packets; 263 pipe->max_packet_size = max_packet_size; 264 pipe->direction = direction; 356 * @param bus_session Endpoint pipe to be initialized. 357 * @return Error code. 358 */ 359 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_dev_session_t *bus_session) 360 { 361 assert(pipe); 362 265 363 pipe->auto_reset_halt = false; 266 364 pipe->bus_session = bus_session; … … 269 367 } 270 368 271 /** Initialize USB endpoint pipe as the default zero control pipe. 369 static const usb_pipe_desc_t default_control_pipe = { 370 .endpoint_no = 0, 371 .transfer_type = USB_TRANSFER_CONTROL, 372 .direction = USB_DIRECTION_BOTH, 373 .max_transfer_size = CTRL_PIPE_MIN_PACKET_SIZE, 374 .transfer_buffer_policy = DMA_POLICY_STRICT, 375 }; 376 377 /** Initialize USB default control pipe. 378 * 379 * This one is special because it must not be registered, it is registered 380 * automatically. 272 381 * 273 382 * @param pipe Endpoint pipe to be initialized. 383 * @param bus_session Endpoint pipe to be initialized. 274 384 * @return Error code. 275 385 */ … … 277 387 usb_dev_session_t *bus_session) 278 388 { 279 assert(pipe);280 281 const errno_t rc = usb_pipe_initialize(pipe, 0, USB_TRANSFER_CONTROL,282 CTRL_PIPE_MIN_PACKET_SIZE, USB_DIRECTION_BOTH, 1, bus_session); 283 389 const errno_t ret = usb_pipe_initialize(pipe, bus_session); 390 if (ret) 391 return ret; 392 393 pipe->desc = default_control_pipe; 284 394 pipe->auto_reset_halt = true; 285 395 286 return rc;396 return EOK; 287 397 } 288 398 … … 290 400 * 291 401 * @param pipe Pipe to be registered. 292 * @param interval Polling interval. 293 * @return Error code. 294 */ 295 errno_t usb_pipe_register(usb_pipe_t *pipe, unsigned interval) 402 * @param ep_desc Matched endpoint descriptor 403 * @param comp_desc Matched superspeed companion descriptro, if any 404 * @return Error code. 405 */ 406 errno_t usb_pipe_register(usb_pipe_t *pipe, 407 const usb_standard_endpoint_descriptor_t *ep_desc, 408 const usb_superspeed_endpoint_companion_descriptor_t *comp_desc) 409 { 410 assert(pipe); 411 assert(pipe->bus_session); 412 assert(ep_desc); 413 414 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 415 if (!exch) 416 return ENOMEM; 417 418 usb_endpoint_descriptors_t descriptors = { 0 }; 419 420 #define COPY(field) descriptors.endpoint.field = ep_desc->field 421 COPY(endpoint_address); 422 COPY(attributes); 423 COPY(max_packet_size); 424 COPY(poll_interval); 425 #undef COPY 426 427 #define COPY(field) descriptors.companion.field = comp_desc->field 428 if (comp_desc) { 429 COPY(max_burst); 430 COPY(attributes); 431 COPY(bytes_per_interval); 432 } 433 #undef COPY 434 435 const errno_t ret = usbhc_register_endpoint(exch, 436 &pipe->desc, &descriptors); 437 async_exchange_end(exch); 438 return ret; 439 } 440 441 /** Revert endpoint registration with the host controller. 442 * 443 * @param pipe Pipe to be unregistered. 444 * @return Error code. 445 */ 446 errno_t usb_pipe_unregister(usb_pipe_t *pipe) 296 447 { 297 448 assert(pipe); … … 300 451 if (!exch) 301 452 return ENOMEM; 302 const errno_t ret = usb_register_endpoint(exch, pipe->endpoint_no, 303 pipe->transfer_type, pipe->direction, pipe->max_packet_size,304 pipe->packets, interval); 453 454 const errno_t ret = usbhc_unregister_endpoint(exch, &pipe->desc); 455 305 456 async_exchange_end(exch); 306 457 return ret; 307 458 } 308 459 309 /** Revert endpoint registration with the host controller.310 *311 * @param pipe Pipe to be unregistered.312 * @return Error code.313 */314 errno_t usb_pipe_unregister(usb_pipe_t *pipe)315 {316 assert(pipe);317 assert(pipe->bus_session);318 async_exch_t *exch = async_exchange_begin(pipe->bus_session);319 if (!exch)320 return ENOMEM;321 const errno_t ret = usb_unregister_endpoint(exch, pipe->endpoint_no,322 pipe->direction);323 async_exchange_end(exch);324 return ret;325 }326 327 460 /** 328 461 * @}
Note:
See TracChangeset
for help on using the changeset viewer.