Changeset 5fd9c30 in mainline for uspace/drv/bus/usb/xhci/transfers.c
- Timestamp:
- 2017-10-21T20:52:56Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 766043c
- Parents:
- 74b852b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/transfers.c
r74b852b r5fd9c30 108 108 } 109 109 110 xhci_transfer_t* xhci_transfer_ alloc(usb_transfer_batch_t* batch) {111 xhci_transfer_t* transfer = malloc(sizeof(xhci_transfer_t));110 xhci_transfer_t* xhci_transfer_create(endpoint_t* ep) { 111 xhci_transfer_t* transfer = calloc(1, sizeof(xhci_transfer_t)); 112 112 if (!transfer) 113 113 return NULL; 114 114 115 memset(transfer, 0, sizeof(xhci_transfer_t));116 transfer->batch = batch; 115 usb_transfer_batch_init(&transfer->batch, ep); 116 117 117 link_initialize(&transfer->link); 118 transfer->hc_buffer = batch->buffer_size > 0 ? malloc32(batch->buffer_size) : NULL;119 118 120 119 return transfer; 121 120 } 122 121 123 void xhci_transfer_fini(xhci_transfer_t* transfer) { 124 if (transfer) { 125 if (transfer->batch->buffer_size > 0) 126 free32(transfer->hc_buffer); 127 128 usb_transfer_batch_destroy(transfer->batch); 129 130 free(transfer); 131 } 132 } 133 134 int xhci_schedule_control_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 135 { 136 if (!batch->setup_size) { 137 usb_log_error("Missing setup packet for the control transfer."); 138 return EINVAL; 139 } 140 if (batch->ep->transfer_type != USB_TRANSFER_CONTROL) { 141 /* This method only works for control transfers. */ 142 usb_log_error("Attempted to schedule a control transfer to non control endpoint."); 143 return EINVAL; 144 } 145 146 usb_device_request_setup_packet_t* setup = 147 (usb_device_request_setup_packet_t*) batch->setup_buffer; 148 149 /* For the TRB formats, see xHCI specification 6.4.1.2 */ 150 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 151 152 if (!transfer->direction) { 153 // Sending stuff from host to device, we need to copy the actual data. 154 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 155 } 156 157 xhci_trb_t trbs[3]; 158 int trbs_used = 0; 122 void xhci_transfer_destroy(xhci_transfer_t* transfer) 123 { 124 assert(transfer); 125 126 if (transfer->hc_buffer) 127 free32(transfer->hc_buffer); 128 129 free(transfer); 130 } 131 132 static xhci_trb_ring_t *get_ring(xhci_hc_t *hc, xhci_transfer_t *transfer) 133 { 134 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 135 uint8_t slot_id = xhci_ep->device->slot_id; 136 137 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 138 assert(ring); 139 return ring; 140 } 141 142 static int schedule_control(xhci_hc_t* hc, xhci_transfer_t* transfer) 143 { 144 usb_transfer_batch_t *batch = &transfer->batch; 145 xhci_trb_ring_t *ring = get_ring(hc, transfer); 146 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 147 148 usb_device_request_setup_packet_t* setup = &batch->setup.packet; 149 150 xhci_trb_t trbs[3]; 151 int trbs_used = 0; 159 152 160 153 xhci_trb_t *trb_setup = trbs + trbs_used++; … … 178 171 xhci_trb_t *trb_data = NULL; 179 172 if (setup->length > 0) { 180 181 173 trb_data = trbs + trbs_used++; 174 xhci_trb_clean(trb_data); 182 175 183 176 trb_data->parameter = addr_to_phys(transfer->hc_buffer); … … 191 184 TRB_CTRL_SET_TRB_TYPE(*trb_data, XHCI_TRB_TYPE_DATA_STAGE); 192 185 193 transfer->direction= REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)186 int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type) 194 187 ? STAGE_IN : STAGE_OUT; 195 TRB_CTRL_SET_DIR(*trb_data, transfer->direction);188 TRB_CTRL_SET_DIR(*trb_data, stage_dir); 196 189 } 197 190 … … 207 200 TRB_CTRL_SET_DIR(*trb_status, get_status_direction_flag(trb_setup, setup->request_type, setup->length)); 208 201 209 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);210 uint8_t slot_id = xhci_ep->device->slot_id;211 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];212 213 int err = xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys);214 if (err != EOK)215 return err;216 217 list_append(&transfer->link, &hc->transfers);218 219 202 // Issue a Configure Endpoint command, if needed. 220 203 if (configure_endpoint_needed(setup)) { 221 // TODO: figure out the best time to issue this command 222 // FIXME: on fail, we need to "cancel" in-flight TRBs and remove transfer from the list 223 err = xhci_device_configure(xhci_ep->device, hc); 224 if (err != EOK) 225 return err; 226 } 227 228 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbels start at 1 */ 229 return hc_ring_doorbell(hc, slot_id, target); 230 } 231 232 int xhci_schedule_bulk_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 233 { 234 if (batch->setup_size) { 235 usb_log_warning("Setup packet present for a bulk transfer. Ignored."); 236 } 237 if (batch->ep->transfer_type != USB_TRANSFER_BULK) { 238 /* This method only works for bulk transfers. */ 239 usb_log_error("Attempted to schedule a bulk transfer to non bulk endpoint."); 240 return EINVAL; 241 } 242 243 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 244 if (!transfer->direction) { 245 // Sending stuff from host to device, we need to copy the actual data. 246 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 247 } 248 204 const int err = xhci_device_configure(xhci_ep->device, hc); 205 if (err) 206 return err; 207 } 208 209 return xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys); 210 } 211 212 static int schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer) 213 { 249 214 xhci_trb_t trb; 250 215 xhci_trb_clean(&trb); … … 252 217 253 218 // data size (sent for OUT, or buffer size) 254 TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);219 TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size); 255 220 // FIXME: TD size 4.11.2.4 256 221 TRB_CTRL_SET_TD_SIZE(trb, 1); … … 261 226 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL); 262 227 263 xhci_endpoint_t *xhci_ep = xhci_endpoint_get( batch->ep);228 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 264 229 uint8_t slot_id = xhci_ep->device->slot_id; 265 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint]; 266 267 xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 268 list_append(&transfer->link, &hc->transfers); 269 270 // TODO: target = endpoint | stream_id << 16 271 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 272 return hc_ring_doorbell(hc, slot_id, target); 273 } 274 275 int xhci_schedule_interrupt_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 276 { 277 if (batch->setup_size) { 278 usb_log_warning("Setup packet present for a interrupt transfer. Ignored."); 279 } 280 if (batch->ep->transfer_type != USB_TRANSFER_INTERRUPT) { 281 /* This method only works for interrupt transfers. */ 282 usb_log_error("Attempted to schedule a interrupt transfer to non interrupt endpoint."); 283 return EINVAL; 284 } 285 286 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 287 if (!transfer->direction) { 288 // Sending stuff from host to device, we need to copy the actual data. 289 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 290 } 291 230 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 231 232 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 233 } 234 235 static int schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer) 236 { 292 237 xhci_trb_t trb; 293 238 xhci_trb_clean(&trb); … … 295 240 296 241 // data size (sent for OUT, or buffer size) 297 TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);242 TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size); 298 243 // FIXME: TD size 4.11.2.4 299 244 TRB_CTRL_SET_TD_SIZE(trb, 1); … … 304 249 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL); 305 250 306 xhci_endpoint_t *xhci_ep = xhci_endpoint_get( batch->ep);251 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 307 252 uint8_t slot_id = xhci_ep->device->slot_id; 308 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint]; 309 310 xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 311 list_append(&transfer->link, &hc->transfers); 312 313 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 314 return hc_ring_doorbell(hc, slot_id, target); 315 } 316 317 int xhci_schedule_isochronous_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 318 { 319 if (batch->setup_size) { 320 usb_log_warning("Setup packet present for a isochronous transfer. Ignored."); 321 } 322 if (batch->ep->transfer_type != USB_TRANSFER_ISOCHRONOUS) { 323 /* This method only works for isochronous transfers. */ 324 usb_log_error("Attempted to schedule a isochronous transfer to non isochronous endpoint."); 325 return EINVAL; 326 } 327 328 /* TODO: Implement me. */ 329 usb_log_error("Isochronous transfers are not yet implemented!"); 330 return ENOTSUP; 253 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 254 255 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 256 } 257 258 static int schedule_isochronous(xhci_hc_t* hc, xhci_transfer_t* transfer) 259 { 260 /* TODO: Implement me. */ 261 usb_log_error("Isochronous transfers are not yet implemented!"); 262 return ENOTSUP; 331 263 } 332 264 … … 352 284 353 285 list_remove(transfer_link); 354 usb_transfer_batch_t *batch = transfer->batch; 355 356 const int err = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK; 357 const size_t size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb); 358 usb_transfer_batch_finish_error(batch, transfer->hc_buffer, size, err); 359 xhci_transfer_fini(transfer); 286 usb_transfer_batch_t *batch = &transfer->batch; 287 288 batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK; 289 batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb); 290 291 if (batch->dir == USB_DIRECTION_IN) { 292 assert(batch->buffer); 293 assert(batch->transfered_size <= batch->buffer_size); 294 memcpy(batch->buffer, transfer->hc_buffer, batch->transfered_size); 295 } 296 297 usb_transfer_batch_finish(batch); 360 298 return EOK; 361 299 } 300 301 typedef int (*transfer_handler)(xhci_hc_t *, xhci_transfer_t *); 302 303 static const transfer_handler transfer_handlers[] = { 304 [USB_TRANSFER_CONTROL] = schedule_control, 305 [USB_TRANSFER_ISOCHRONOUS] = schedule_isochronous, 306 [USB_TRANSFER_BULK] = schedule_bulk, 307 [USB_TRANSFER_INTERRUPT] = schedule_interrupt, 308 }; 309 310 int xhci_transfer_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch) 311 { 312 assert(hc); 313 314 xhci_transfer_t *transfer = xhci_transfer_from_batch(batch); 315 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep); 316 uint8_t slot_id = xhci_ep->device->slot_id; 317 318 assert(xhci_ep); 319 assert(slot_id); 320 321 const usb_transfer_type_t type = batch->ep->transfer_type; 322 assert(type >= 0 && type < ARRAY_SIZE(transfer_handlers)); 323 assert(transfer_handlers[type]); 324 325 if (batch->buffer_size > 0) { 326 transfer->hc_buffer = malloc32(batch->buffer_size); 327 } 328 329 if (batch->dir != USB_DIRECTION_IN) { 330 // Sending stuff from host to device, we need to copy the actual data. 331 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 332 } 333 334 const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer); 335 if (err) 336 return err; 337 338 list_append(&transfer->link, &hc->transfers); 339 340 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 341 return hc_ring_doorbell(hc, slot_id, target); 342 }
Note:
See TracChangeset
for help on using the changeset viewer.