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