Changeset b991d37 in mainline
- Timestamp:
- 2011-08-31T16:41:11Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ff6dd73
- Parents:
- 96e2d01
- Location:
- uspace/drv/bus/usb/uhci
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r96e2d01 rb991d37 128 128 link_t *item = list_first(&done); 129 129 list_remove(item); 130 u sb_transfer_batch_t *batch =131 list_get_instance(item, usb_transfer_batch_t, link);132 u sb_transfer_batch_finish(batch);130 uhci_transfer_batch_t *batch = 131 uhci_transfer_batch_from_link(item); 132 uhci_transfer_batch_call_dispose(batch); 133 133 } 134 134 } … … 382 382 assert(instance); 383 383 assert(batch); 384 int ret = batch_init_uhci(batch); 385 if (ret != EOK) { 386 return ret; 384 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 385 if (!uhci_batch) { 386 usb_log_error("Failed to create UHCI transfer structures.\n"); 387 return ENOMEM; 387 388 } 388 389 … … 390 391 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 391 392 assert(list); 392 transfer_list_add_batch(list, batch);393 transfer_list_add_batch(list, uhci_batch); 393 394 394 395 return EOK; -
uspace/drv/bus/usb/uhci/transfer_list.c
r96e2d01 rb991d37 39 39 40 40 #include "transfer_list.h" 41 #include "uhci_batch.h"42 41 43 42 static void transfer_list_remove_batch( 44 transfer_list_t *instance, u sb_transfer_batch_t *batch);43 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch); 45 44 /*----------------------------------------------------------------------------*/ 46 45 /** Initialize transfer list structures. … … 107 106 */ 108 107 void transfer_list_add_batch( 109 transfer_list_t *instance, usb_transfer_batch_t *batch) 110 { 111 assert(instance); 112 assert(batch); 113 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch); 108 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch) 109 { 110 assert(instance); 111 assert(uhci_batch); 112 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, 113 uhci_batch->usb_batch); 114 114 115 115 fibril_mutex_lock(&instance->guard); 116 116 117 qh_t *last_qh = NULL; 117 /* Assume there is nothing scheduled */ 118 qh_t *last_qh = instance->queue_head; 119 /* There is something scheduled */ 120 if (!list_empty(&instance->batch_list)) { 121 last_qh = uhci_transfer_batch_from_link( 122 list_last(&instance->batch_list))->qh; 123 } 118 124 /* Add to the hardware queue. */ 119 if (list_empty(&instance->batch_list)) { 120 /* There is nothing scheduled */ 121 last_qh = instance->queue_head; 122 } else { 123 /* There is something scheduled */ 124 usb_transfer_batch_t *last = usb_transfer_batch_from_link( 125 list_last(&instance->batch_list)); 126 last_qh = batch_qh(last); 127 } 128 const uint32_t pa = addr_to_phys(batch_qh(batch)); 125 const uint32_t pa = addr_to_phys(uhci_batch->qh); 129 126 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 130 127 … … 133 130 134 131 /* keep link */ 135 batch_qh(batch)->next = last_qh->next;136 qh_set_next_qh(last_qh, batch_qh(batch));132 uhci_batch->qh->next = last_qh->next; 133 qh_set_next_qh(last_qh, uhci_batch->qh); 137 134 138 135 /* Make sure the pointer is updated */ … … 140 137 141 138 /* Add to the driver's list */ 142 list_append(& batch->link, &instance->batch_list);139 list_append(&uhci_batch->link, &instance->batch_list); 143 140 144 141 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " scheduled in queue %s.\n", 145 batch, USB_TRANSFER_BATCH_ARGS(*batch), instance->name); 142 uhci_batch, USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 143 instance->name); 146 144 fibril_mutex_unlock(&instance->guard); 147 145 } … … 158 156 159 157 fibril_mutex_lock(&instance->guard); 160 link_t *current = instance->batch_list.head.next;161 while (current != &instance->batch_list.head) {158 link_t *current = list_first(&instance->batch_list); 159 while (current && current != &instance->batch_list.head) { 162 160 link_t * const next = current->next; 163 u sb_transfer_batch_t *batch =164 u sb_transfer_batch_from_link(current);165 166 if ( batch_is_complete(batch)) {161 uhci_transfer_batch_t *batch = 162 uhci_transfer_batch_from_link(current); 163 164 if (uhci_transfer_batch_is_complete(batch)) { 167 165 /* Save for processing */ 168 166 transfer_list_remove_batch(instance, batch); … … 183 181 while (!list_empty(&instance->batch_list)) { 184 182 link_t * const current = list_first(&instance->batch_list); 185 u sb_transfer_batch_t *batch =186 u sb_transfer_batch_from_link(current);183 uhci_transfer_batch_t *batch = 184 uhci_transfer_batch_from_link(current); 187 185 transfer_list_remove_batch(instance, batch); 188 usb_transfer_batch_finish_error(batch, EINTR); 186 batch->usb_batch->error = EINTR; 187 uhci_transfer_batch_call_dispose(batch); 189 188 } 190 189 fibril_mutex_unlock(&instance->guard); … … 199 198 */ 200 199 void transfer_list_remove_batch( 201 transfer_list_t *instance, u sb_transfer_batch_t *batch)200 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch) 202 201 { 203 202 assert(instance); 204 203 assert(instance->queue_head); 205 assert( batch);206 assert( batch_qh(batch));204 assert(uhci_batch); 205 assert(uhci_batch->qh); 207 206 assert(fibril_mutex_is_locked(&instance->guard)); 208 207 209 usb_log_debug2( 210 "Queue %s: removing batch(%p).\n", instance->name, batch); 211 212 const char *qpos = NULL; 213 qh_t *prev_qh = NULL; 208 usb_log_debug2("Queue %s: removing batch(%p).\n", 209 instance->name, uhci_batch->usb_batch); 210 211 /* Assume I'm the first */ 212 const char *qpos = "FIRST"; 213 qh_t *prev_qh = instance->queue_head; 214 214 /* Remove from the hardware queue */ 215 if (list_first(&instance->batch_list) == &batch->link) { 216 /* I'm the first one here */ 217 prev_qh = instance->queue_head; 218 qpos = "FIRST"; 219 } else { 220 /* The thing before me is a batch too */ 221 usb_transfer_batch_t *prev = 222 usb_transfer_batch_from_link(batch->link.prev); 223 prev_qh = batch_qh(prev); 215 if (list_first(&instance->batch_list) != &uhci_batch->link) { 216 /* There is a batch in front of me */ 217 prev_qh = 218 uhci_transfer_batch_from_link(uhci_batch->link.prev)->qh; 224 219 qpos = "NOT FIRST"; 225 220 } 226 221 assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK) 227 == addr_to_phys( batch_qh(batch)));228 prev_qh->next = batch_qh(batch)->next;222 == addr_to_phys(uhci_batch->qh)); 223 prev_qh->next = uhci_batch->qh->next; 229 224 230 225 /* Make sure the pointer is updated */ … … 232 227 233 228 /* Remove from the batch list */ 234 list_remove(& batch->link);229 list_remove(&uhci_batch->link); 235 230 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " removed (%s) " 236 231 "from %s, next: %x.\n", 237 batch, USB_TRANSFER_BATCH_ARGS(*batch),238 qpos, instance->name, batch_qh(batch)->next);232 uhci_batch, USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 233 qpos, instance->name, uhci_batch->qh->next); 239 234 } 240 235 /** -
uspace/drv/bus/usb/uhci/transfer_list.h
r96e2d01 rb991d37 36 36 37 37 #include <fibril_synch.h> 38 #include <usb/host/batch.h>39 38 40 39 #include "hw_struct/queue_head.h" 41 40 #include "uhci_batch.h" 42 41 /** Structure maintaining both hw queue and software list 43 42 * of currently executed transfers … … 46 45 /** Guard against multiple add/remove races */ 47 46 fibril_mutex_t guard; 48 /** UHCI hw structure represe ting this queue */47 /** UHCI hw structure representing this queue */ 49 48 qh_t *queue_head; 50 49 /** Assigned name, for nicer debug output */ … … 58 57 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next); 59 58 void transfer_list_add_batch( 60 transfer_list_t *instance, u sb_transfer_batch_t *batch);59 transfer_list_t *instance, uhci_transfer_batch_t *batch); 61 60 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done); 62 61 void transfer_list_abort_all(transfer_list_t *instance); -
uspace/drv/bus/usb/uhci/uhci_batch.c
r96e2d01 rb991d37 44 44 45 45 #define DEFAULT_ERROR_COUNT 3 46 static void batch_control_write(usb_transfer_batch_t *instance); 47 static void batch_control_read(usb_transfer_batch_t *instance); 48 49 static void batch_interrupt_in(usb_transfer_batch_t *instance); 50 static void batch_interrupt_out(usb_transfer_batch_t *instance); 51 52 static void batch_bulk_in(usb_transfer_batch_t *instance); 53 static void batch_bulk_out(usb_transfer_batch_t *instance); 54 55 static void batch_setup_control(usb_transfer_batch_t *batch) 56 { 57 // TODO Find a better way to do this 58 if (batch->setup_buffer[0] & (1 << 7)) 59 batch_control_read(batch); 60 else 61 batch_control_write(batch); 62 } 63 64 void (*batch_setup[4][3])(usb_transfer_batch_t*) = 65 { 66 { NULL, NULL, batch_setup_control }, 67 { NULL, NULL, NULL }, 68 { batch_bulk_in, batch_bulk_out, NULL }, 69 { batch_interrupt_in, batch_interrupt_out, NULL }, 70 }; 71 // */ 72 /** UHCI specific data required for USB transfer */ 73 typedef struct uhci_transfer_batch { 74 /** Queue head 75 * This QH is used to maintain UHCI schedule structure and the element 76 * pointer points to the first TD of this batch. 77 */ 78 qh_t *qh; 79 /** List of TDs needed for the transfer */ 80 td_t *tds; 81 /** Number of TDs used by the transfer */ 82 size_t td_count; 83 /** Data buffer, must be accessible by the UHCI hw */ 84 void *device_buffer; 85 } uhci_transfer_batch_t; 86 /*----------------------------------------------------------------------------*/ 87 static void batch_control(usb_transfer_batch_t *instance, 46 47 static void batch_control(uhci_transfer_batch_t *uhci_batch, 88 48 usb_packet_id data_stage, usb_packet_id status_stage); 89 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid); 49 static void batch_data(uhci_transfer_batch_t *uhci_batch, usb_packet_id pid); 50 /*----------------------------------------------------------------------------*/ 51 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch) 52 { 53 if (uhci_batch) { 54 usb_transfer_batch_dispose(uhci_batch->usb_batch); 55 free32(uhci_batch->device_buffer); 56 free(uhci_batch); 57 } 58 } 90 59 /*----------------------------------------------------------------------------*/ 91 60 /** Safely destructs uhci_transfer_batch_t structure … … 93 62 * @param[in] uhci_batch Instance to destroy. 94 63 */ 95 static void uhci_transfer_batch_dispose(void *uhci_batch) 96 { 97 uhci_transfer_batch_t *instance = uhci_batch; 98 assert(instance); 99 free32(instance->device_buffer); 100 free(instance); 101 } 64 void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch) 65 { 66 assert(uhci_batch); 67 assert(uhci_batch->usb_batch); 68 /* Copy data unless we are sure we sent it */ 69 if (uhci_batch->usb_batch->ep->direction != USB_DIRECTION_OUT) { 70 memcpy(uhci_batch->usb_batch->buffer, 71 uhci_transfer_batch_data_buffer(uhci_batch), 72 uhci_batch->usb_batch->buffer_size); 73 } 74 if (uhci_batch->usb_batch->callback_out) 75 usb_transfer_batch_call_out(uhci_batch->usb_batch); 76 if (uhci_batch->usb_batch->callback_in) 77 usb_transfer_batch_call_in(uhci_batch->usb_batch); 78 usb_transfer_batch_finish(uhci_batch->usb_batch); 79 uhci_transfer_batch_dispose(uhci_batch); 80 } 81 /*----------------------------------------------------------------------------*/ 82 static void (*batch_setup[4][3])(uhci_transfer_batch_t*); 102 83 /*----------------------------------------------------------------------------*/ 103 84 /** Allocate memory and initialize internal data structure. … … 119 100 * Initializes parameters needed for the transfer and callback. 120 101 */ 121 int batch_init_uhci(usb_transfer_batch_t *batch) 122 { 102 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 103 { 104 assert((sizeof(td_t) % 16) == 0); 123 105 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 124 106 if (ptr == NULL) { \ 125 107 usb_log_error(message); \ 126 if (uhci_data) { \ 127 uhci_transfer_batch_dispose(uhci_data); \ 128 } \ 129 return ENOMEM; \ 108 uhci_transfer_batch_dispose(uhci_batch); \ 109 return NULL; \ 130 110 } else (void)0 131 111 132 uhci_transfer_batch_t *uhci_ data=112 uhci_transfer_batch_t *uhci_batch = 133 113 calloc(1, sizeof(uhci_transfer_batch_t)); 134 CHECK_NULL_DISPOSE_RETURN(uhci_ data,114 CHECK_NULL_DISPOSE_RETURN(uhci_batch, 135 115 "Failed to allocate UHCI batch.\n"); 136 116 137 uhci_data->td_count = 138 (batch->buffer_size + batch->ep->max_packet_size - 1) 139 / batch->ep->max_packet_size; 140 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 141 uhci_data->td_count += 2; 142 } 143 144 assert((sizeof(td_t) % 16) == 0); 145 const size_t total_size = (sizeof(td_t) * uhci_data->td_count) 146 + sizeof(qh_t) + batch->setup_size + batch->buffer_size; 147 uhci_data->device_buffer = malloc32(total_size); 148 CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer, 117 uhci_batch->td_count = 118 (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1) 119 / usb_batch->ep->max_packet_size; 120 if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 121 uhci_batch->td_count += 2; 122 } 123 124 const size_t total_size = (sizeof(td_t) * uhci_batch->td_count) 125 + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size; 126 uhci_batch->device_buffer = malloc32(total_size); 127 CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer, 149 128 "Failed to allocate UHCI buffer.\n"); 150 bzero(uhci_ data->device_buffer, total_size);151 152 uhci_ data->tds = uhci_data->device_buffer;153 uhci_ data->qh =154 (uhci_ data->device_buffer + (sizeof(td_t) * uhci_data->td_count));155 156 qh_init(uhci_ data->qh);157 qh_set_element_td(uhci_ data->qh, uhci_data->tds);158 159 void * setup=160 uhci_ data->device_buffer + (sizeof(td_t) * uhci_data->td_count)129 bzero(uhci_batch->device_buffer, total_size); 130 131 uhci_batch->tds = uhci_batch->device_buffer; 132 uhci_batch->qh = 133 (uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count)); 134 135 qh_init(uhci_batch->qh); 136 qh_set_element_td(uhci_batch->qh, &uhci_batch->tds[0]); 137 138 void *dest = 139 uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count) 161 140 + sizeof(qh_t); 162 /* Copy SETUP packet data to device buffer */ 163 memcpy(setup, batch->setup_buffer, batch->setup_size); 164 /* Set generic data buffer pointer */ 165 batch->data_buffer = setup + batch->setup_size; 166 batch->private_data_dtor = uhci_transfer_batch_dispose; 167 batch->private_data = uhci_data; 141 /* Copy SETUP packet data to the device buffer */ 142 memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size); 143 dest += usb_batch->setup_size; 144 /* Copy generic data if unless they are provided by the device */ 145 if (usb_batch->ep->direction != USB_DIRECTION_IN) { 146 memcpy(dest, usb_batch->buffer, usb_batch->buffer_size); 147 } 148 uhci_batch->usb_batch = usb_batch; 168 149 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 169 " memory structures ready.\n", batch, 170 USB_TRANSFER_BATCH_ARGS(*batch)); 171 assert(batch_setup[batch->ep->transfer_type][batch->ep->direction]); 172 batch_setup[batch->ep->transfer_type][batch->ep->direction](batch); 173 174 return EOK; 150 " memory structures ready.\n", usb_batch, 151 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 152 assert( 153 batch_setup[usb_batch->ep->transfer_type][usb_batch->ep->direction]); 154 batch_setup[usb_batch->ep->transfer_type][usb_batch->ep->direction]( 155 uhci_batch); 156 157 return uhci_batch; 175 158 } 176 159 /*----------------------------------------------------------------------------*/ … … 184 167 * is reached. 185 168 */ 186 bool batch_is_complete(usb_transfer_batch_t *instance) 187 { 188 assert(instance); 189 uhci_transfer_batch_t *data = instance->private_data; 190 assert(data); 191 192 usb_log_debug2("Batch(%p) checking %zu transfer(s) for completion.\n", 193 instance, data->td_count); 194 instance->transfered_size = 0; 169 bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch) 170 { 171 assert(uhci_batch); 172 assert(uhci_batch->usb_batch); 173 174 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 175 " checking %zu transfer(s) for completion.\n", 176 uhci_batch->usb_batch, 177 USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 178 uhci_batch->td_count); 179 uhci_batch->usb_batch->transfered_size = 0; 195 180 size_t i = 0; 196 for (;i < data->td_count; ++i) {197 if (td_is_active(& data->tds[i])) {181 for (;i < uhci_batch->td_count; ++i) { 182 if (td_is_active(&uhci_batch->tds[i])) { 198 183 return false; 199 184 } 200 185 201 instance->error = td_status(&data->tds[i]); 202 if (instance->error != EOK) { 186 uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]); 187 if (uhci_batch->usb_batch->error != EOK) { 188 assert(uhci_batch->usb_batch->ep != NULL); 189 203 190 usb_log_debug("Batch(%p) found error TD(%zu):%" 204 PRIx32 ".\n", instance, i, data->tds[i].status);205 td_print_status(&data->tds[i]);206 207 assert(instance->ep != NULL); 208 endpoint_toggle_set( instance->ep,209 td_toggle(& data->tds[i]));191 PRIx32 ".\n", uhci_batch->usb_batch, i, 192 uhci_batch->tds[i].status); 193 td_print_status(&uhci_batch->tds[i]); 194 195 endpoint_toggle_set(uhci_batch->usb_batch->ep, 196 td_toggle(&uhci_batch->tds[i])); 210 197 if (i > 0) 211 198 goto substract_ret; … … 213 200 } 214 201 215 instance->transfered_size += td_act_size(&data->tds[i]); 216 if (td_is_short(&data->tds[i])) 202 uhci_batch->usb_batch->transfered_size 203 += td_act_size(&uhci_batch->tds[i]); 204 if (td_is_short(&uhci_batch->tds[i])) 217 205 goto substract_ret; 218 206 } 219 207 substract_ret: 220 instance->transfered_size -= instance->setup_size; 208 uhci_batch->usb_batch->transfered_size 209 -= uhci_batch->usb_batch->setup_size; 221 210 return true; 222 211 } … … 233 222 * Uses generic control function with pids OUT and IN. 234 223 */ 235 static void batch_control_write(usb_transfer_batch_t *instance) 236 { 237 assert(instance); 238 /* We are data out, we are supposed to provide data */ 239 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 240 batch_control(instance, USB_PID_OUT, USB_PID_IN); 241 instance->next_step = usb_transfer_batch_call_out_and_dispose; 242 LOG_BATCH_INITIALIZED(instance, "control write"); 224 static void control_write(uhci_transfer_batch_t *uhci_batch) 225 { 226 batch_control(uhci_batch, USB_PID_OUT, USB_PID_IN); 227 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "control write"); 243 228 } 244 229 /*----------------------------------------------------------------------------*/ … … 249 234 * Uses generic control with pids IN and OUT. 250 235 */ 251 static void batch_control_read(usb_transfer_batch_t *instance) 252 { 253 assert(instance); 254 batch_control(instance, USB_PID_IN, USB_PID_OUT); 255 instance->next_step = usb_transfer_batch_call_in_and_dispose; 256 LOG_BATCH_INITIALIZED(instance, "control read"); 236 static void control_read(uhci_transfer_batch_t *uhci_batch) 237 { 238 batch_control(uhci_batch, USB_PID_IN, USB_PID_OUT); 239 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "control read"); 257 240 } 258 241 /*----------------------------------------------------------------------------*/ … … 263 246 * Data transfer with PID_IN. 264 247 */ 265 static void batch_interrupt_in(usb_transfer_batch_t *instance) 266 { 267 assert(instance); 268 batch_data(instance, USB_PID_IN); 269 instance->next_step = usb_transfer_batch_call_in_and_dispose; 270 LOG_BATCH_INITIALIZED(instance, "interrupt in"); 248 static void interrupt_in(uhci_transfer_batch_t *uhci_batch) 249 { 250 batch_data(uhci_batch, USB_PID_IN); 251 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "interrupt in"); 271 252 } 272 253 /*----------------------------------------------------------------------------*/ … … 277 258 * Data transfer with PID_OUT. 278 259 */ 279 static void batch_interrupt_out(usb_transfer_batch_t *instance) 280 { 281 assert(instance); 282 /* We are data out, we are supposed to provide data */ 283 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 284 batch_data(instance, USB_PID_OUT); 285 instance->next_step = usb_transfer_batch_call_out_and_dispose; 286 LOG_BATCH_INITIALIZED(instance, "interrupt out"); 260 static void interrupt_out(uhci_transfer_batch_t *uhci_batch) 261 { 262 batch_data(uhci_batch, USB_PID_OUT); 263 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "interrupt out"); 287 264 } 288 265 /*----------------------------------------------------------------------------*/ … … 293 270 * Data transfer with PID_IN. 294 271 */ 295 static void batch_bulk_in(usb_transfer_batch_t *instance) 296 { 297 assert(instance); 298 batch_data(instance, USB_PID_IN); 299 instance->next_step = usb_transfer_batch_call_in_and_dispose; 300 LOG_BATCH_INITIALIZED(instance, "bulk in"); 272 static void bulk_in(uhci_transfer_batch_t *uhci_batch) 273 { 274 batch_data(uhci_batch, USB_PID_IN); 275 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "bulk in"); 301 276 } 302 277 /*----------------------------------------------------------------------------*/ … … 307 282 * Data transfer with PID_OUT. 308 283 */ 309 static void batch_bulk_out(usb_transfer_batch_t *instance) 310 { 311 assert(instance); 312 /* We are data out, we are supposed to provide data */ 313 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 314 batch_data(instance, USB_PID_OUT); 315 instance->next_step = usb_transfer_batch_call_out_and_dispose; 316 LOG_BATCH_INITIALIZED(instance, "bulk out"); 284 static void bulk_out(uhci_transfer_batch_t *uhci_batch) 285 { 286 batch_data(uhci_batch, USB_PID_OUT); 287 LOG_BATCH_INITIALIZED(uhci_batch->usb_batch, "bulk out"); 317 288 } 318 289 /*----------------------------------------------------------------------------*/ … … 325 296 * The last transfer is marked with IOC flag. 326 297 */ 327 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid) 328 { 329 assert(instance); 330 uhci_transfer_batch_t *data = instance->private_data; 331 assert(data); 332 333 const bool low_speed = instance->ep->speed == USB_SPEED_LOW; 334 int toggle = endpoint_toggle_get(instance->ep); 298 static void batch_data(uhci_transfer_batch_t *uhci_batch, usb_packet_id pid) 299 { 300 assert(uhci_batch); 301 assert(uhci_batch->usb_batch); 302 303 const bool low_speed = 304 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 305 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 306 const usb_target_t target = { 307 uhci_batch->usb_batch->ep->address, 308 uhci_batch->usb_batch->ep->endpoint }; 309 310 int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep); 335 311 assert(toggle == 0 || toggle == 1); 336 312 337 313 size_t td = 0; 338 size_t remain_size = instance->buffer_size; 339 char *buffer = instance->data_buffer; 314 size_t remain_size = uhci_batch->usb_batch->buffer_size; 315 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 316 340 317 while (remain_size > 0) { 341 318 const size_t packet_size = 342 (instance->ep->max_packet_size > remain_size) ? 343 remain_size : instance->ep->max_packet_size; 344 345 td_t *next_td = (td + 1 < data->td_count) 346 ? &data->tds[td + 1] : NULL; 347 348 349 usb_target_t target = 350 { instance->ep->address, instance->ep->endpoint }; 351 352 assert(td < data->td_count); 319 (remain_size < mps) ? remain_size : mps; 320 321 const td_t *next_td = (td + 1 < uhci_batch->td_count) 322 ? &uhci_batch->tds[td + 1] : NULL; 323 324 assert(td < uhci_batch->td_count); 353 325 td_init( 354 & data->tds[td], DEFAULT_ERROR_COUNT, packet_size,326 &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size, 355 327 toggle, false, low_speed, target, pid, buffer, next_td); 356 328 … … 358 330 toggle = 1 - toggle; 359 331 buffer += packet_size; 360 assert(packet_size <= remain_size);361 332 remain_size -= packet_size; 362 333 } 363 td_set_ioc(& data->tds[td - 1]);364 endpoint_toggle_set( instance->ep, toggle);334 td_set_ioc(&uhci_batch->tds[td - 1]); 335 endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle); 365 336 } 366 337 /*----------------------------------------------------------------------------*/ … … 376 347 * The last transfer is marked with IOC. 377 348 */ 378 static void batch_control(usb_transfer_batch_t *instance, 379 usb_packet_id data_stage, usb_packet_id status_stage) 380 { 381 assert(instance); 382 uhci_transfer_batch_t *data = instance->private_data; 383 assert(data); 384 assert(data->td_count >= 2); 385 386 const bool low_speed = instance->ep->speed == USB_SPEED_LOW; 387 const usb_target_t target = 388 { instance->ep->address, instance->ep->endpoint }; 349 static void batch_control(uhci_transfer_batch_t *uhci_batch, 350 usb_packet_id data_stage_pid, usb_packet_id status_stage_pid) 351 { 352 assert(uhci_batch); 353 assert(uhci_batch->usb_batch); 354 assert(uhci_batch->usb_batch->ep); 355 assert(uhci_batch->td_count >= 2); 356 357 const bool low_speed = 358 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 359 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 360 const usb_target_t target = { 361 uhci_batch->usb_batch->ep->address, 362 uhci_batch->usb_batch->ep->endpoint }; 389 363 390 364 /* setup stage */ 391 365 td_init( 392 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false, 393 low_speed, target, USB_PID_SETUP, instance->setup_buffer, 394 &data->tds[1]); 366 &uhci_batch->tds[0], DEFAULT_ERROR_COUNT, 367 uhci_batch->usb_batch->setup_size, 0, false, 368 low_speed, target, USB_PID_SETUP, 369 uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]); 395 370 396 371 /* data stage */ 397 372 size_t td = 1; 398 373 unsigned toggle = 1; 399 size_t remain_size = instance->buffer_size; 400 char *buffer = instance->data_buffer; 374 size_t remain_size = uhci_batch->usb_batch->buffer_size; 375 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 376 401 377 while (remain_size > 0) { 402 378 const size_t packet_size = 403 (instance->ep->max_packet_size > remain_size) ? 404 remain_size : instance->ep->max_packet_size; 379 (remain_size < mps) ? remain_size : mps; 405 380 406 381 td_init( 407 & data->tds[td], DEFAULT_ERROR_COUNT, packet_size,408 toggle, false, low_speed, target, data_stage ,409 buffer, & data->tds[td + 1]);382 &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size, 383 toggle, false, low_speed, target, data_stage_pid, 384 buffer, &uhci_batch->tds[td + 1]); 410 385 411 386 ++td; 412 387 toggle = 1 - toggle; 413 388 buffer += packet_size; 414 assert(td < data->td_count);415 assert(packet_size <= remain_size);416 389 remain_size -= packet_size; 390 assert(td < uhci_batch->td_count); 417 391 } 418 392 419 393 /* status stage */ 420 assert(td == data->td_count - 1);394 assert(td == uhci_batch->td_count - 1); 421 395 422 396 td_init( 423 & data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,424 target, status_stage , NULL, NULL);425 td_set_ioc(& data->tds[td]);397 &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed, 398 target, status_stage_pid, NULL, NULL); 399 td_set_ioc(&uhci_batch->tds[td]); 426 400 427 401 usb_log_debug2("Control last TD status: %x.\n", 428 data->tds[td].status); 429 } 430 /*----------------------------------------------------------------------------*/ 431 /** Provides access to QH data structure. 432 * 433 * @param[in] instance Batch pointer to use. 434 * @return Pointer to the QH used by the batch. 435 */ 436 qh_t * batch_qh(usb_transfer_batch_t *instance) 437 { 438 assert(instance); 439 uhci_transfer_batch_t *data = instance->private_data; 440 assert(data); 441 return data->qh; 442 } 402 uhci_batch->tds[td].status); 403 } 404 /*----------------------------------------------------------------------------*/ 405 static void batch_setup_control(uhci_transfer_batch_t *uhci_batch) 406 { 407 // TODO Find a better way to do this 408 assert(uhci_batch); 409 assert(uhci_batch->usb_batch); 410 if (uhci_batch->usb_batch->setup_buffer[0] & (1 << 7)) 411 control_read(uhci_batch); 412 else 413 control_write(uhci_batch); 414 } 415 /*----------------------------------------------------------------------------*/ 416 static void (*batch_setup[4][3])(uhci_transfer_batch_t*) = 417 { 418 { NULL, NULL, batch_setup_control }, 419 { NULL, NULL, NULL }, 420 { bulk_in, bulk_out, NULL }, 421 { interrupt_in, interrupt_out, NULL }, 422 }; 443 423 /** 444 424 * @} -
uspace/drv/bus/usb/uhci/uhci_batch.h
r96e2d01 rb991d37 36 36 37 37 #include <usb/host/batch.h> 38 #include <adt/list.h> 38 39 39 40 #include "hw_struct/queue_head.h" 41 #include "hw_struct/transfer_descriptor.h" 40 42 41 int batch_init_uhci(usb_transfer_batch_t *batch); 42 bool batch_is_complete(usb_transfer_batch_t *batch); 43 qh_t * batch_qh(usb_transfer_batch_t *batch); 43 /** UHCI specific data required for USB transfer */ 44 typedef struct uhci_transfer_batch { 45 /** Queue head 46 * This QH is used to maintain UHCI schedule structure and the element 47 * pointer points to the first TD of this batch. 48 */ 49 qh_t *qh; 50 /** List of TDs needed for the transfer */ 51 td_t *tds; 52 /** Number of TDs used by the transfer */ 53 size_t td_count; 54 /** Data buffer, must be accessible by the UHCI hw */ 55 void *device_buffer; 56 /** Generic transfer data */ 57 usb_transfer_batch_t *usb_batch; 58 /** List element */ 59 link_t link; 60 } uhci_transfer_batch_t; 61 62 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch); 63 void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch); 64 bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch); 65 66 static inline void * uhci_transfer_batch_data_buffer( 67 uhci_transfer_batch_t *uhci_batch) 68 { 69 assert(uhci_batch); 70 assert(uhci_batch->usb_batch); 71 assert(uhci_batch->device_buffer); 72 return uhci_batch->device_buffer + sizeof(qh_t) + 73 uhci_batch->td_count * sizeof(td_t) + 74 uhci_batch->usb_batch->setup_size; 75 } 76 /*----------------------------------------------------------------------------*/ 77 static inline void * uhci_transfer_batch_setup_buffer( 78 uhci_transfer_batch_t *uhci_batch) 79 { 80 assert(uhci_batch); 81 assert(uhci_batch->usb_batch); 82 assert(uhci_batch->device_buffer); 83 return uhci_batch->device_buffer + sizeof(qh_t) + 84 uhci_batch->td_count * sizeof(td_t); 85 } 86 /*----------------------------------------------------------------------------*/ 87 static inline uhci_transfer_batch_t *uhci_transfer_batch_from_link(link_t *l) 88 { 89 assert(l); 90 return list_get_instance(l, uhci_transfer_batch_t, link); 91 } 92 44 93 #endif 45 94 /**
Note:
See TracChangeset
for help on using the changeset viewer.