Changeset e67c50a in mainline for uspace/drv/bus/usb/ohci/ohci_batch.c
- Timestamp:
- 2018-02-01T21:13:23Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 64ce0c1
- Parents:
- 3e6ff9a
- git-author:
- Ondřej Hlavatý <aearsis@…> (2018-02-01 21:13:22)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2018-02-01 21:13:23)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/ohci_batch.c
r3e6ff9a re67c50a 56 56 { 57 57 assert(ohci_batch); 58 if (ohci_batch->tds) { 59 const ohci_endpoint_t *ohci_ep = 60 ohci_endpoint_get(ohci_batch->base.ep); 61 assert(ohci_ep); 62 for (unsigned i = 0; i < ohci_batch->td_count; ++i) { 63 if (ohci_batch->tds[i] != ohci_ep->td) 64 free32(ohci_batch->tds[i]); 65 } 66 free(ohci_batch->tds); 67 } 68 free32(ohci_batch->device_buffer); 58 dma_buffer_free(&ohci_batch->ohci_dma_buffer); 69 59 free(ohci_batch); 70 60 } … … 101 91 { 102 92 assert(ohci_batch); 103 104 const size_t setup_size = (ohci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)105 ? USB_SETUP_PACKET_SIZE106 : 0;107 108 93 usb_transfer_batch_t *usb_batch = &ohci_batch->base; 94 95 if (!batch_setup[usb_batch->ep->transfer_type]) 96 return ENOTSUP; 109 97 110 98 ohci_batch->td_count = (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1) … … 115 103 } 116 104 117 /* We need an extra place for TD that was left at ED */ 118 ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t*)); 119 if (!ohci_batch->tds) { 120 usb_log_error("Failed to allocate OHCI transfer descriptors."); 105 /* Alloc one more to NULL terminate */ 106 ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t *)); 107 if (!ohci_batch->tds) 121 108 return ENOMEM; 122 } 123 124 /* Add TD left over by the previous transfer */ 125 ohci_batch->ed = ohci_endpoint_get(usb_batch->ep)->ed; 126 ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td; 127 128 for (unsigned i = 1; i <= ohci_batch->td_count; ++i) { 129 ohci_batch->tds[i] = malloc32(sizeof(td_t)); 130 if (!ohci_batch->tds[i]) { 131 usb_log_error("Failed to allocate TD %d.", i); 132 return ENOMEM; 133 } 134 } 135 136 /* NOTE: OHCI is capable of handling buffer that crosses page boundaries 137 * it is, however, not capable of handling buffer that occupies more 138 * than two pages (the first page is computed using start pointer, the 139 * other using the end pointer) */ 140 if (setup_size + usb_batch->buffer_size > 0) { 141 /* Use one buffer for setup and data stage */ 142 ohci_batch->device_buffer = 143 malloc32(setup_size + usb_batch->buffer_size); 144 if (!ohci_batch->device_buffer) { 145 usb_log_error("Failed to allocate device buffer"); 146 return ENOMEM; 147 } 148 /* Copy setup data */ 149 memcpy(ohci_batch->device_buffer, usb_batch->setup.buffer, setup_size); 150 /* Copy generic data */ 151 if (usb_batch->dir == USB_DIRECTION_OUT) 152 memcpy( 153 ohci_batch->device_buffer + setup_size, 154 usb_batch->buffer, usb_batch->buffer_size); 155 } 156 157 assert(batch_setup[usb_batch->ep->transfer_type]); 109 110 const size_t td_size = ohci_batch->td_count * sizeof(td_t); 111 const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) 112 ? USB_SETUP_PACKET_SIZE 113 : 0; 114 115 if (dma_buffer_alloc(&ohci_batch->ohci_dma_buffer, td_size + setup_size + usb_batch->buffer_size)) { 116 usb_log_error("Failed to allocate OHCI DMA buffer."); 117 return ENOMEM; 118 } 119 120 td_t *tds = ohci_batch->ohci_dma_buffer.virt; 121 122 for (size_t i = 0; i < ohci_batch->td_count; i++) 123 ohci_batch->tds[i] = &tds[i]; 124 125 /* Presence of this terminator makes TD initialization easier */ 126 ohci_batch->tds[ohci_batch->td_count] = NULL; 127 128 ohci_batch->setup_buffer = (void *) (&tds[ohci_batch->td_count]); 129 memcpy(ohci_batch->setup_buffer, usb_batch->setup.buffer, setup_size); 130 131 ohci_batch->data_buffer = ohci_batch->setup_buffer + setup_size; 132 if (usb_batch->dir == USB_DIRECTION_OUT) 133 memcpy(ohci_batch->data_buffer, usb_batch->buffer, usb_batch->buffer_size); 134 158 135 batch_setup[usb_batch->ep->transfer_type](ohci_batch); 159 136 … … 174 151 assert(ohci_batch); 175 152 153 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep); 154 assert(ohci_ep); 155 176 156 usb_log_debug("Batch %p checking %zu td(s) for completion.", 177 157 &ohci_batch->base, ohci_batch->td_count); 178 158 usb_log_debug2("ED: %08x:%08x:%08x:%08x.", 179 ohci_ batch->ed->status, ohci_batch->ed->td_head,180 ohci_ batch->ed->td_tail, ohci_batch->ed->next);181 182 if (!ed_inactive(ohci_ batch->ed) && ed_transfer_pending(ohci_batch->ed))159 ohci_ep->ed->status, ohci_ep->ed->td_head, 160 ohci_ep->ed->td_tail, ohci_ep->ed->next); 161 162 if (!ed_inactive(ohci_ep->ed) && ed_transfer_pending(ohci_ep->ed)) 183 163 return false; 184 164 … … 188 168 /* Assume all data got through */ 189 169 ohci_batch->base.transferred_size = ohci_batch->base.buffer_size; 190 191 /* Assume we will leave the last(unused) TD behind */192 unsigned leave_td = ohci_batch->td_count;193 170 194 171 /* Check all TDs */ … … 217 194 } else { 218 195 usb_log_debug("Batch %p found error TD(%zu):%08x.", 219 &ohci_batch->base, i, 220 ohci_batch->tds[i]->status); 196 &ohci_batch->base, i, ohci_batch->tds[i]->status); 221 197 222 198 /* ED should be stopped because of errors */ 223 assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0); 224 225 /* Now we have a problem: we don't know what TD 226 * the head pointer points to, the retiring rules 227 * described in specs say it should be the one after 228 * the failed one so set the tail pointer accordingly. 229 * It will be the one TD we leave behind. 199 assert((ohci_ep->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0); 200 201 /* We don't care where the processing stopped, we just 202 * need to make sure it's not using any of the TDs owned 203 * by the transfer. 204 * 205 * As the chain is terminated by a TD in ownership of 206 * the EP, set it. 230 207 */ 231 leave_td = i + 1; 232 233 /* Check TD assumption */ 234 assert(ed_head_td(ohci_batch->ed) == 235 addr_to_phys(ohci_batch->tds[leave_td])); 236 237 /* Set tail to the same TD */ 238 ed_set_tail_td(ohci_batch->ed, 239 ohci_batch->tds[leave_td]); 240 241 /* Clear possible ED HALT */ 242 ed_clear_halt(ohci_batch->ed); 208 ed_set_head_td(ohci_ep->ed, ohci_ep->tds[0]); 209 210 /* Clear the halted condition for the next transfer */ 211 ed_clear_halt(ohci_ep->ed); 243 212 break; 244 213 } … … 247 216 ohci_batch->base.buffer_size); 248 217 249 const size_t setup_size = (ohci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)250 ? USB_SETUP_PACKET_SIZE251 : 0;252 253 218 if (ohci_batch->base.dir == USB_DIRECTION_IN) 254 219 memcpy(ohci_batch->base.buffer, 255 ohci_batch->d evice_buffer + setup_size,220 ohci_batch->data_buffer, 256 221 ohci_batch->base.transferred_size); 257 222 258 /* Store the remaining TD */ 223 /* Make sure that we are leaving the right TD behind */ 224 assert(addr_to_phys(ohci_ep->tds[0]) == ed_tail_td(ohci_ep->ed)); 225 assert(ed_tail_td(ohci_ep->ed) == ed_head_td(ohci_ep->ed)); 226 227 return true; 228 } 229 230 /** Starts execution of the TD list 231 * 232 * @param[in] ohci_batch Batch structure to use 233 */ 234 void ohci_transfer_batch_commit(const ohci_transfer_batch_t *ohci_batch) 235 { 236 assert(ohci_batch); 237 259 238 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep); 260 assert(ohci_ep); 261 ohci_ep->td = ohci_batch->tds[leave_td]; 262 263 /* Make sure that we are leaving the right TD behind */ 264 assert(addr_to_phys(ohci_ep->td) == ed_head_td(ohci_batch->ed)); 265 assert(addr_to_phys(ohci_ep->td) == ed_tail_td(ohci_batch->ed)); 266 267 return true; 268 } 269 270 /** Starts execution of the TD list 271 * 272 * @param[in] ohci_batch Batch structure to use 273 */ 274 void ohci_transfer_batch_commit(const ohci_transfer_batch_t *ohci_batch) 275 { 276 assert(ohci_batch); 277 ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]); 239 240 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.", ohci_ep->ed, 241 ohci_ep->ed->status, ohci_ep->ed->td_tail, 242 ohci_ep->ed->td_head, ohci_ep->ed->next); 243 244 /* 245 * According to spec, we need to copy the first TD to the currently 246 * enqueued one. 247 */ 248 memcpy(ohci_ep->tds[0], ohci_batch->tds[0], sizeof(td_t)); 249 ohci_batch->tds[0] = ohci_ep->tds[0]; 250 251 td_t *last = ohci_batch->tds[ohci_batch->td_count - 1]; 252 td_set_next(last, ohci_ep->tds[1]); 253 254 ed_set_tail_td(ohci_ep->ed, ohci_ep->tds[1]); 255 256 /* Swap the EP TDs for the next transfer */ 257 td_t *tmp = ohci_ep->tds[0]; 258 ohci_ep->tds[0] = ohci_ep->tds[1]; 259 ohci_ep->tds[1] = tmp; 278 260 } 279 261 … … 294 276 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 295 277 296 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.", ohci_batch->ed,297 ohci_batch->ed->status, ohci_batch->ed->td_tail,298 ohci_batch->ed->td_head, ohci_batch->ed->next);299 278 static const usb_direction_t reverse_dir[] = { 300 279 [USB_DIRECTION_IN] = USB_DIRECTION_OUT, … … 303 282 304 283 int toggle = 0; 305 const char* buffer = ohci_batch->device_buffer;306 284 const usb_direction_t data_dir = dir; 307 285 const usb_direction_t status_dir = reverse_dir[dir]; … … 310 288 td_init( 311 289 ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH, 312 buffer, USB_SETUP_PACKET_SIZE, toggle);290 ohci_batch->setup_buffer, USB_SETUP_PACKET_SIZE, toggle); 313 291 usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.", 314 292 ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp, 315 293 ohci_batch->tds[0]->next, ohci_batch->tds[0]->be); 316 buffer += USB_SETUP_PACKET_SIZE;317 294 318 295 /* Data stage */ 319 296 size_t td_current = 1; 297 const char* buffer = ohci_batch->data_buffer; 320 298 size_t remain_size = ohci_batch->base.buffer_size; 321 299 while (remain_size > 0) { … … 370 348 usb_direction_t dir = ohci_batch->base.dir; 371 349 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 372 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.", ohci_batch->ed,373 ohci_batch->ed->status, ohci_batch->ed->td_tail,374 ohci_batch->ed->td_head, ohci_batch->ed->next);375 350 376 351 size_t td_current = 0; 377 352 size_t remain_size = ohci_batch->base.buffer_size; 378 char *buffer = ohci_batch->d evice_buffer;353 char *buffer = ohci_batch->data_buffer; 379 354 while (remain_size > 0) { 380 355 const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
Note:
See TracChangeset
for help on using the changeset viewer.