Changes in uspace/lib/usbdev/src/pipes.c [1d758fc:b7fd2a0] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/pipes.c
r1d758fc rb7fd2a0 36 36 #include <usb/dev/request.h> 37 37 #include <usb/usb.h> 38 #include <usb /dma_buffer.h>38 #include <usb_iface.h> 39 39 40 40 #include <assert.h> 41 #include <bitops.h>42 41 #include <async.h> 43 #include <as.h>44 42 #include <errno.h> 45 43 #include <mem.h> … … 53 51 assert(pipe != NULL); 54 52 55 if (!pipe->auto_reset_halt || (pipe-> desc.endpoint_no != 0)) {53 if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) { 56 54 return; 57 55 } … … 59 57 /* Prevent infinite recursion. */ 60 58 pipe->auto_reset_halt = false; 61 usb_ pipe_clear_halt(pipe, pipe);59 usb_request_clear_endpoint_halt(pipe, 0); 62 60 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 purposes70 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;164 61 } 165 62 … … 173 70 * @param[out] data_buffer Buffer for incoming data. 174 71 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes). 175 * @param[out] data_transfer red_size Number of bytes that were actually176 * transfer red during the DATA stage.72 * @param[out] data_transfered_size Number of bytes that were actually 73 * transfered during the DATA stage. 177 74 * @return Error code. 178 75 */ 179 76 errno_t usb_pipe_control_read(usb_pipe_t *pipe, 180 77 const void *setup_buffer, size_t setup_buffer_size, 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; 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; 200 113 } 201 114 … … 216 129 { 217 130 assert(pipe); 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); 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; 252 162 } 253 163 … … 257 167 * @param[out] buffer Buffer where to store the data. 258 168 * @param[in] size Size of the buffer (in bytes). 259 * @param[out] size_transfer red Number of bytes that were actually transferred.169 * @param[out] size_transfered Number of bytes that were actually transfered. 260 170 * @return Error code. 261 171 */ 262 172 errno_t usb_pipe_read(usb_pipe_t *pipe, 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; 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; 279 209 } 280 210 … … 289 219 { 290 220 assert(pipe); 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); 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; 350 243 } 351 244 … … 353 246 * 354 247 * @param pipe Endpoint pipe to be initialized. 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 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; 362 265 pipe->auto_reset_halt = false; 363 266 pipe->bus_session = bus_session; … … 366 269 } 367 270 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. 271 /** Initialize USB endpoint pipe as the default zero control pipe. 379 272 * 380 273 * @param pipe Endpoint pipe to be initialized. 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; 274 * @return Error code. 275 */ 276 errno_t usb_pipe_initialize_default_control(usb_pipe_t *pipe, 277 usb_dev_session_t *bus_session) 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 391 284 pipe->auto_reset_halt = true; 392 285 393 return EOK;286 return rc; 394 287 } 395 288 … … 397 290 * 398 291 * @param pipe Pipe to be registered. 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) 292 * @param interval Polling interval. 293 * @return Error code. 294 */ 295 errno_t usb_pipe_register(usb_pipe_t *pipe, unsigned interval) 404 296 { 405 297 assert(pipe); 406 298 assert(pipe->bus_session); 407 assert(ep_desc);408 409 299 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 410 300 if (!exch) 411 301 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); 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); 431 305 async_exchange_end(exch); 432 306 return ret; … … 445 319 if (!exch) 446 320 return ENOMEM; 447 448 const errno_t ret = usbhc_unregister_endpoint(exch, &pipe->desc); 449 321 const errno_t ret = usb_unregister_endpoint(exch, pipe->endpoint_no, 322 pipe->direction); 450 323 async_exchange_end(exch); 451 324 return ret;
Note:
See TracChangeset
for help on using the changeset viewer.