Changeset e67c50a in mainline
- Timestamp:
- 2018-02-01T21:13:23Z (7 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)
- Location:
- uspace/drv/bus/usb/ohci
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h
r3e6ff9a re67c50a 165 165 166 166 /** 167 * Set the HeadP of ED. Do not call unless the ED is Halted. 168 * @param instance ED 169 */ 170 static inline void ed_set_head_td(ed_t *instance, const td_t *td) 171 { 172 assert(instance); 173 const uintptr_t pa = addr_to_phys(td); 174 OHCI_MEM32_WR(instance->td_head, pa & ED_TDHEAD_PTR_MASK); 175 } 176 177 /** 167 178 * Set next ED in ED chain. 168 179 * @param instance ED to modify -
uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
r3e6ff9a re67c50a 88 88 } 89 89 90 td_set_next(instance, next); 91 } 92 93 void td_set_next(td_t *instance, const td_t *next) 94 { 90 95 OHCI_MEM32_WR(instance->next, addr_to_phys(next) & TD_NEXT_PTR_MASK); 96 } 91 97 92 }93 98 /** 94 99 * @} -
uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
r3e6ff9a re67c50a 92 92 } __attribute__((packed)) td_t; 93 93 94 void td_init(td_t * instance, const td_t *next,95 usb_direction_t dir, const void *buffer, size_t size, int toggle);94 void td_init(td_t *, const td_t *, usb_direction_t, const void *, size_t, int); 95 void td_set_next(td_t *, const td_t *); 96 96 97 97 /** -
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 -
uspace/drv/bus/usb/ohci/ohci_batch.h
r3e6ff9a re67c50a 38 38 #include <assert.h> 39 39 #include <stdbool.h> 40 #include <usb/dma_buffer.h> 40 41 #include <usb/host/usb_transfer_batch.h> 41 42 … … 47 48 usb_transfer_batch_t base; 48 49 49 /** Endpoint descriptor of the target endpoint. */50 ed_t *ed;51 /** List of TDs needed for the transfer */52 td_t **tds;53 50 /** Number of TDs used by the transfer */ 54 51 size_t td_count; 55 /** Data buffer, must be accessible by the OHCI hw. */ 56 char *device_buffer; 52 53 /** 54 * List of TDs needed for the transfer - together with setup data 55 * backed by the dma buffer. Note that the TD pointers are pointing to 56 * the DMA buffer initially, but as the scheduling must use the first TD 57 * from EP, it is replaced. 58 */ 59 td_t **tds; 60 char *setup_buffer; 61 char *data_buffer; 62 63 dma_buffer_t ohci_dma_buffer; 57 64 } ohci_transfer_batch_t; 58 65 -
uspace/drv/bus/usb/ohci/ohci_bus.c
r3e6ff9a re67c50a 75 75 assert(dev); 76 76 77 ohci_endpoint_t *ohci_ep = malloc(sizeof(ohci_endpoint_t));77 ohci_endpoint_t *ohci_ep = calloc(1, sizeof(ohci_endpoint_t)); 78 78 if (ohci_ep == NULL) 79 79 return NULL; … … 81 81 endpoint_init(&ohci_ep->base, dev, desc); 82 82 83 ohci_ep->ed = malloc32(sizeof(ed_t));84 if ( ohci_ep->ed == NULL) {83 const errno_t err = dma_buffer_alloc(&ohci_ep->dma_buffer, sizeof(ed_t) + 2 * sizeof(td_t)); 84 if (err) { 85 85 free(ohci_ep); 86 86 return NULL; 87 87 } 88 88 89 ohci_ep->td = malloc32(sizeof(td_t)); 90 if (ohci_ep->td == NULL) { 91 free32(ohci_ep->ed); 92 free(ohci_ep); 93 return NULL; 94 } 89 ohci_ep->ed = ohci_ep->dma_buffer.virt; 90 91 ohci_ep->tds[0] = (td_t *) ohci_ep->ed + 1; 92 ohci_ep->tds[1] = ohci_ep->tds[0] + 1; 95 93 96 94 link_initialize(&ohci_ep->eplist_link); … … 109 107 ohci_endpoint_t *instance = ohci_endpoint_get(ep); 110 108 111 free32(instance->ed); 112 free32(instance->td); 109 dma_buffer_free(&instance->dma_buffer); 113 110 free(instance); 114 111 } … … 125 122 return err; 126 123 127 ed_init(ohci_ep->ed, ep, ohci_ep->td );124 ed_init(ohci_ep->ed, ep, ohci_ep->tds[0]); 128 125 hc_enqueue_endpoint(bus->hc, ep); 129 126 endpoint_set_online(ep, &bus->hc->guard); -
uspace/drv/bus/usb/ohci/ohci_bus.h
r3e6ff9a re67c50a 38 38 #include <assert.h> 39 39 #include <adt/list.h> 40 #include <usb/dma_buffer.h> 40 41 #include <usb/host/usb2_bus.h> 41 42 … … 43 44 #include "hw_struct/transfer_descriptor.h" 44 45 45 /** Connector structure linking ED to to prepared TD. */ 46 /** 47 * Connector structure linking ED to to prepared TD. 48 * 49 * OHCI requires new transfers to be appended at the end of a queue. But it has 50 * a weird semantics of a leftover TD, which serves as a placeholder. This left 51 * TD is overwritten with first TD of a new transfer, and the spare one is used 52 * as the next placeholder. Then the two are swapped for the next transaction. 53 */ 46 54 typedef struct ohci_endpoint { 47 55 endpoint_t base; … … 49 57 /** OHCI endpoint descriptor */ 50 58 ed_t *ed; 51 /** Currently enqueued transfer descriptor */ 52 td_t *td; 59 /** TDs to be used at the beginning and end of transaction */ 60 td_t *tds [2]; 61 62 /** Buffer to back ED + 2 TD */ 63 dma_buffer_t dma_buffer; 64 53 65 /** Link in endpoint_list*/ 54 66 link_t eplist_link;
Note:
See TracChangeset
for help on using the changeset viewer.