Changes in / [f82cc1a8:960ff451] in mainline
- Location:
- uspace/drv/uhci-hcd
- Files:
-
- 3 added
- 2 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/Makefile
rf82cc1a8 r960ff451 33 33 34 34 SOURCES = \ 35 callback.c \ 35 36 iface.c \ 36 37 main.c \ … … 39 40 uhci.c \ 40 41 uhci_struct/transfer_descriptor.c \ 41 pci.c \ 42 tracker.c 42 pci.c 43 43 44 44 include $(USPACE_PREFIX)/Makefile.common -
uspace/drv/uhci-hcd/iface.c
rf82cc1a8 r960ff451 106 106 usbhc_iface_transfer_out_callback_t callback, void *arg) 107 107 { 108 size_t max_packet_size = 8; 109 dev_speed_t speed = FULL_SPEED; 110 111 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_INTERRUPT, 112 max_packet_size, speed, data, size, NULL, callback, arg); 113 if (!tracker) 114 return ENOMEM; 115 tracker_control_read_data_old(tracker); 116 return EOK; 108 assert(dev); 109 uhci_t *hc = dev_to_uhci(dev); 110 assert(hc); 111 return uhci_transfer(hc, dev, target, USB_TRANSFER_INTERRUPT, 0, USB_PID_OUT, 112 false, data, size, callback, NULL, arg); 117 113 } 118 114 /*----------------------------------------------------------------------------*/ … … 121 117 usbhc_iface_transfer_in_callback_t callback, void *arg) 122 118 { 123 size_t max_packet_size = 8; 124 dev_speed_t speed = FULL_SPEED; 125 126 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_INTERRUPT, 127 max_packet_size, speed, data, size, callback, NULL, arg); 128 if (!tracker) 129 return ENOMEM; 130 tracker_control_read_data_old(tracker); 131 return EOK; 132 } 133 /*----------------------------------------------------------------------------*/ 134 static int control_write(device_t *dev, usb_target_t target, 135 void *setup_data, size_t setup_size, void *data, size_t size, 136 usbhc_iface_transfer_out_callback_t callback, void *arg) 137 { 138 size_t max_packet_size = size; 139 dev_speed_t speed = FULL_SPEED; 140 141 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 142 max_packet_size, speed, data, size, NULL, callback, arg); 143 if (!tracker) 144 return ENOMEM; 145 tracker_control_write(tracker, setup_data, setup_size); 146 return EOK; 147 } 148 /*----------------------------------------------------------------------------*/ 149 static int control_read(device_t *dev, usb_target_t target, 150 void *setup_data, size_t setup_size, void *data, size_t size, 151 usbhc_iface_transfer_in_callback_t callback, void *arg) 152 { 153 size_t max_packet_size = size; 154 dev_speed_t speed = FULL_SPEED; 155 156 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 157 max_packet_size, speed, data, size, callback, NULL, arg); 158 if (!tracker) 159 return ENOMEM; 160 tracker_control_read(tracker, setup_data, setup_size); 161 return EOK; 119 assert(dev); 120 uhci_t *hc = dev_to_uhci(dev); 121 assert(hc); 122 return uhci_transfer(hc, dev, target, USB_TRANSFER_INTERRUPT, 0, USB_PID_IN, 123 false, data, size, NULL, callback, arg); 162 124 } 163 125 /*----------------------------------------------------------------------------*/ … … 166 128 usbhc_iface_transfer_out_callback_t callback, void *arg) 167 129 { 168 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 169 8, FULL_SPEED, data, size, NULL, callback, arg); 170 if (!tracker) 171 return ENOMEM; 172 tracker_control_setup_old(tracker); 173 return EOK; 130 assert(dev); 131 uhci_t *hc = dev_to_uhci(dev); 132 assert(hc); 133 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 0, USB_PID_SETUP, 134 false, data, size, callback, NULL, arg); 174 135 } 175 136 /*----------------------------------------------------------------------------*/ … … 178 139 usbhc_iface_transfer_out_callback_t callback, void *arg) 179 140 { 180 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 181 size, FULL_SPEED, data, size, NULL, callback, arg); 182 if (!tracker) 183 return ENOMEM; 184 tracker_control_write_data_old(tracker); 185 return EOK; 141 assert(dev); 142 uhci_t *hc = dev_to_uhci(dev); 143 assert(hc); 144 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 1, USB_PID_OUT, 145 false, data, size, callback, NULL, arg); 186 146 } 187 147 /*----------------------------------------------------------------------------*/ … … 189 149 usbhc_iface_transfer_in_callback_t callback, void *arg) 190 150 { 191 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 192 0, FULL_SPEED, NULL, 0, callback, NULL, arg); 193 if (!tracker) 194 return ENOMEM; 195 tracker_control_write_status_old(tracker); 196 return EOK; 151 assert(dev); 152 uhci_t *hc = dev_to_uhci(dev); 153 assert(hc); 154 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 0, USB_PID_IN, 155 false, NULL, 0, NULL, callback, arg); 197 156 } 198 157 /*----------------------------------------------------------------------------*/ … … 201 160 usbhc_iface_transfer_out_callback_t callback, void *arg) 202 161 { 203 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 204 8, FULL_SPEED, data, size, NULL, callback, arg); 205 if (!tracker) 206 return ENOMEM; 207 tracker_control_setup_old(tracker); 208 return EOK; 162 assert(dev); 163 uhci_t *hc = dev_to_uhci(dev); 164 assert(hc); 165 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 0, USB_PID_SETUP, 166 false, data, size, callback, NULL, arg); 209 167 } 210 168 /*----------------------------------------------------------------------------*/ … … 213 171 usbhc_iface_transfer_in_callback_t callback, void *arg) 214 172 { 215 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL, 216 size, FULL_SPEED, data, size, callback, NULL, arg); 217 if (!tracker) 218 return ENOMEM; 219 tracker_control_read_data_old(tracker); 220 return EOK; 173 assert(dev); 174 uhci_t *hc = dev_to_uhci(dev); 175 assert(hc); 176 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 1, USB_PID_IN, 177 false, data, size, NULL, callback, arg); 221 178 } 222 179 /*----------------------------------------------------------------------------*/ … … 224 181 usbhc_iface_transfer_out_callback_t callback, void *arg) 225 182 { 226 tracker_t *tracker = tracker_get(dev, target, USB_TRANSFER_CONTROL,227 0, FULL_SPEED, NULL, 0, NULL, callback, arg);228 if (!tracker)229 return ENOMEM;230 tracker_control_read_status_old(tracker);231 return EOK; 232 } 233 /*----------------------------------------------------------------------------*/ 183 assert(dev); 184 uhci_t *hc = dev_to_uhci(dev); 185 assert(hc); 186 return uhci_transfer(hc, dev, target, USB_TRANSFER_CONTROL, 0, USB_PID_OUT, 187 false, NULL, 0, callback, NULL, arg); 188 } 189 190 234 191 usbhc_iface_t uhci_iface = { 235 192 .tell_address = get_address, … … 243 200 .interrupt_out = interrupt_out, 244 201 .interrupt_in = interrupt_in, 245 246 .control_read = control_read,247 .control_write = control_write,248 202 249 203 .control_write_setup = control_write_setup, -
uspace/drv/uhci-hcd/transfer_list.c
rf82cc1a8 r960ff451 41 41 { 42 42 assert(instance); 43 instance->first = NULL; 44 instance->last = NULL; 43 45 instance->next = NULL; 44 46 instance->name = name; … … 64 66 } 65 67 /*----------------------------------------------------------------------------*/ 66 void transfer_list_add_tracker(transfer_list_t *instance, tracker_t *tracker) 68 int transfer_list_append( 69 transfer_list_t *instance, transfer_descriptor_t *transfer) 67 70 { 68 71 assert(instance); 69 assert(tra cker);72 assert(transfer); 70 73 71 uint32_t pa = (uintptr_t)addr_to_phys(tra cker->td);74 uint32_t pa = (uintptr_t)addr_to_phys(transfer); 72 75 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 73 76 77 /* empty list */ 78 if (instance->first == NULL) { 79 assert(instance->last == NULL); 80 instance->first = instance->last = transfer; 81 } else { 82 assert(instance->last); 83 instance->last->next_va = transfer; 84 85 assert(instance->last->next & LINK_POINTER_TERMINATE_FLAG); 86 instance->last->next = (pa & LINK_POINTER_ADDRESS_MASK); 87 instance->last = transfer; 88 } 89 90 assert(instance->queue_head); 74 91 if (instance->queue_head->element & LINK_POINTER_TERMINATE_FLAG) { 75 /* there is nothing scheduled */ 76 instance->last_tracker = tracker; 77 instance->queue_head->element = pa; 78 return; 92 instance->queue_head->element = (pa & LINK_POINTER_ADDRESS_MASK); 79 93 } 80 /* now we can be sure that last_tracker is a valid pointer */ 81 instance->last_tracker->td->next = pa; 82 instance->last_tracker = tracker; 83 84 /* check again, may be use atomic compare and swap */ 85 // if (instance->queue_head->element & LINK_POINTER_TERMINATE_FLAG) { 86 // instance->queue_head->element = pa; 87 // } 94 usb_log_debug("Successfully added transfer to the hc queue %s.\n", 95 instance->name); 96 return EOK; 88 97 } 89 98 /** -
uspace/drv/uhci-hcd/transfer_list.h
rf82cc1a8 r960ff451 36 36 37 37 #include "uhci_struct/queue_head.h" 38 #include " tracker.h"38 #include "uhci_struct/transfer_descriptor.h" 39 39 40 40 typedef struct transfer_list 41 41 { 42 tra cker_t *last_tracker;43 42 transfer_descriptor_t *first; 43 transfer_descriptor_t *last; 44 44 queue_head_t *queue_head; 45 45 uint32_t queue_head_pa; … … 58 58 } 59 59 60 61 void transfer_list_add_tracker(transfer_list_t *instance, tracker_t *tracker);60 int transfer_list_append( 61 transfer_list_t *instance, transfer_descriptor_t *transfer); 62 62 63 63 #endif -
uspace/drv/uhci-hcd/uhci.c
rf82cc1a8 r960ff451 42 42 static int uhci_clean_finished(void *arg); 43 43 static int uhci_debug_checker(void *arg); 44 static bool allowed_usb_packet(45 bool low_speed, usb_transfer_type_t, size_t size);46 44 47 45 int uhci_init(uhci_t *instance, void *regs, size_t reg_size) … … 86 84 87 85 const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list); 86 88 87 pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa); 89 90 list_initialize(&instance->tracker_list);91 88 92 89 instance->cleaner = fibril_create(uhci_clean_finished, instance); … … 96 93 fibril_add_ready(instance->debug_checker); 97 94 98 /* Start the hc with large(64 B) packet FSBR */95 /* Start the hc with large(64b) packet FSBR */ 99 96 pio_write_16(&instance->registers->usbcmd, 100 97 UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET); … … 150 147 } 151 148 /*----------------------------------------------------------------------------*/ 152 int uhci_schedule(uhci_t *instance, tracker_t *tracker) 153 { 154 assert(instance); 155 assert(tracker); 156 const int low_speed = (tracker->speed == LOW_SPEED); 157 if (!allowed_usb_packet( 158 low_speed, tracker->transfer_type, tracker->packet_size)) { 159 usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n", 160 low_speed ? "LOW" : "FULL" , tracker->transfer_type, 161 tracker->packet_size); 149 int uhci_transfer( 150 uhci_t *instance, 151 device_t *dev, 152 usb_target_t target, 153 usb_transfer_type_t transfer_type, 154 bool toggle, 155 usb_packet_id pid, 156 bool low_speed, 157 void *buffer, size_t size, 158 usbhc_iface_transfer_out_callback_t callback_out, 159 usbhc_iface_transfer_in_callback_t callback_in, 160 void *arg) 161 { 162 // TODO: Add support for isochronous transfers 163 if (transfer_type == USB_TRANSFER_ISOCHRONOUS) { 164 usb_log_warning("ISO transfer not supported.\n"); 162 165 return ENOTSUP; 163 166 } 164 /* TODO: check available bandwith here */ 165 166 transfer_list_t *list = 167 instance->transfers[low_speed][tracker->transfer_type]; 168 assert(list); 169 transfer_list_add_tracker(list, tracker); 170 list_append(&tracker->link, &instance->tracker_list); 167 168 if (transfer_type == USB_TRANSFER_INTERRUPT 169 && size >= 64) { 170 usb_log_warning("Interrupt transfer too big %zu.\n", size); 171 return ENOTSUP; 172 } 173 174 if (size >= 1024) { 175 usb_log_warning("Transfer too big.\n"); 176 return ENOTSUP; 177 } 178 transfer_list_t *list = instance->transfers[low_speed][transfer_type]; 179 if (!list) { 180 usb_log_warning("UNSUPPORTED transfer %d-%d.\n", low_speed, transfer_type); 181 return ENOTSUP; 182 } 183 184 transfer_descriptor_t *td = NULL; 185 callback_t *job = NULL; 186 int ret = EOK; 187 assert(dev); 188 189 #define CHECK_RET_TRANS_FREE_JOB_TD(message) \ 190 if (ret != EOK) { \ 191 usb_log_error(message); \ 192 if (job) { \ 193 callback_dispose(job); \ 194 } \ 195 if (td) { free32(td); } \ 196 return ret; \ 197 } else (void) 0 198 199 job = callback_get(dev, buffer, size, callback_in, callback_out, arg); 200 ret = job ? EOK : ENOMEM; 201 CHECK_RET_TRANS_FREE_JOB_TD("Failed to allocate callback structure.\n"); 202 203 td = transfer_descriptor_get(3, size, false, target, pid, job->new_buffer); 204 ret = td ? EOK : ENOMEM; 205 CHECK_RET_TRANS_FREE_JOB_TD("Failed to setup transfer descriptor.\n"); 206 207 td->callback = job; 208 209 210 usb_log_debug("Appending a new transfer to queue %s.\n", list->name); 211 212 ret = transfer_list_append(list, td); 213 CHECK_RET_TRANS_FREE_JOB_TD("Failed to append transfer descriptor.\n"); 171 214 172 215 return EOK; 173 216 } 174 /*--------------------------------------------------------------------------- -*/217 /*---------------------------------------------------------------------------*/ 175 218 int uhci_clean_finished(void* arg) 176 219 { … … 180 223 181 224 while(1) { 182 /* tracker iteration */ 183 link_t *current = instance->tracker_list.next; 184 while (current != &instance->tracker_list) 185 { 186 link_t *next = current->next; 187 tracker_t *tracker = list_get_instance(current, tracker_t, link); 188 189 assert(current == &tracker->link); 190 assert(tracker); 191 assert(tracker->next_step); 192 assert(tracker->td); 193 194 if (!transfer_descriptor_is_active(tracker->td)) { 195 usb_log_info("Found inactive tracker with status: %x.\n", 196 tracker->td->status); 197 list_remove(current); 198 tracker->next_step(tracker); 225 usb_log_debug("Running cleaning fibril on: %p.\n", instance); 226 /* iterate all transfer queues */ 227 transfer_list_t *current_list = &instance->transfers_interrupt; 228 while (current_list) { 229 /* Remove inactive transfers from the top of the queue 230 * TODO: should I reach queue head or is this enough? */ 231 volatile transfer_descriptor_t * it = 232 current_list->first; 233 usb_log_debug("Running cleaning fibril on queue: %s (%s).\n", 234 current_list->name, it ? "SOMETHING" : "EMPTY"); 235 236 if (it) { 237 usb_log_debug("First in queue: %p (%x) PA:%x.\n", 238 it, it->status, addr_to_phys((void*)it) ); 239 usb_log_debug("First to send: %x\n", 240 (current_list->queue_head->element) ); 199 241 } 200 current = next; 242 243 while (current_list->first && 244 !(current_list->first->status & TD_STATUS_ERROR_ACTIVE)) { 245 transfer_descriptor_t *transfer = current_list->first; 246 usb_log_info("Inactive transfer calling callback with status %x.\n", 247 transfer->status); 248 current_list->first = transfer->next_va; 249 transfer_descriptor_dispose(transfer); 250 } 251 if (!current_list->first) 252 current_list->last = current_list->first; 253 254 current_list = current_list->next; 201 255 } 202 256 async_usleep(UHCI_CLEANER_TIMEOUT); … … 257 311 return 0; 258 312 } 259 /*----------------------------------------------------------------------------*/260 bool allowed_usb_packet(261 bool low_speed, usb_transfer_type_t transfer, size_t size)262 {263 /* see USB specification chapter 5.5-5.8 for magic numbers used here */264 switch(transfer) {265 case USB_TRANSFER_ISOCHRONOUS:266 return (!low_speed && size < 1024);267 case USB_TRANSFER_INTERRUPT:268 return size <= (low_speed ? 8 : 64);269 case USB_TRANSFER_CONTROL: /* device specifies its own max size */270 return (size <= (low_speed ? 8 : 64));271 case USB_TRANSFER_BULK: /* device specifies its own max size */272 return (!low_speed && size <= 64);273 }274 return false;275 }276 313 /** 277 314 * @} -
uspace/drv/uhci-hcd/uhci.h
rf82cc1a8 r960ff451 37 37 38 38 #include <fibril.h> 39 #include <adt/list.h>40 39 41 40 #include <usb/addrkeep.h> … … 43 42 44 43 #include "transfer_list.h" 45 #include "tracker.h"46 44 47 45 typedef struct uhci_regs { … … 70 68 } regs_t; 71 69 70 #define TRANSFER_QUEUES 4 72 71 #define UHCI_FRAME_LIST_COUNT 1024 73 72 #define UHCI_CLEANER_TIMEOUT 10000 74 #define UHCI_DEBUGER_TIMEOUT 500000 073 #define UHCI_DEBUGER_TIMEOUT 500000 75 74 76 75 typedef struct uhci { … … 79 78 80 79 link_pointer_t *frame_list; 81 82 link_t tracker_list;83 80 84 81 transfer_list_t transfers_bulk_full; … … 111 108 void *arg ); 112 109 113 int uhci_schedule(uhci_t *instance, tracker_t *tracker);114 115 110 static inline uhci_t * dev_to_uhci(device_t *dev) 116 111 { return (uhci_t*)dev->driver_data; } -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
rf82cc1a8 r960ff451 32 32 * @brief UHCI driver 33 33 */ 34 #include <errno.h>35 34 #include <usb/debug.h> 36 35 37 36 #include "transfer_descriptor.h" 38 #include "utils/malloc32.h"39 37 40 38 void transfer_descriptor_init(transfer_descriptor_t *instance, 41 int error_count, size_t size, bool toggle, bool isochronous,42 usb_target_t target,int pid, void *buffer)39 int error_count, size_t size, bool isochronous, usb_target_t target, 40 int pid, void *buffer) 43 41 { 44 42 assert(instance); … … 46 44 instance->next = 47 45 0 | LINK_POINTER_TERMINATE_FLAG; 46 48 47 49 48 assert(size < 1024); … … 59 58 60 59 instance->buffer_ptr = 0; 60 61 instance->next_va = NULL; 62 instance->callback = NULL; 61 63 62 64 if (size) { … … 104 106 return USB_OUTCOME_CRCERROR; 105 107 106 //assert((((status >> TD_STATUS_ERROR_POS) & TD_STATUS_ERROR_MASK)107 //| TD_STATUS_ERROR_RESERVED) == TD_STATUS_ERROR_RESERVED);108 assert((((status >> TD_STATUS_ERROR_POS) & TD_STATUS_ERROR_MASK) 109 | TD_STATUS_ERROR_RESERVED) == TD_STATUS_ERROR_RESERVED); 108 110 return USB_OUTCOME_OK; 109 111 } 110 /*----------------------------------------------------------------------------*/ 111 int transfer_descriptor_status(transfer_descriptor_t *instance)112 113 void transfer_descriptor_fini(transfer_descriptor_t *instance) 112 114 { 113 115 assert(instance); 114 if (convert_outcome(instance->status)) 115 return EINVAL; //TODO: use sane error value here 116 return EOK; 116 callback_run(instance->callback, 117 convert_outcome(instance->status), 118 ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK 119 ); 117 120 } 118 121 /** -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
rf82cc1a8 r960ff451 38 38 #include <usb/usb.h> 39 39 40 #include "utils/malloc32.h" 41 #include "callback.h" 40 42 #include "link_pointer.h" 41 43 … … 84 86 volatile uint32_t buffer_ptr; 85 87 86 /* there is 16 bytes of data available here, according to UHCI 87 * Design guide, according to linux kernel the hardware does not care 88 * we don't use it anyway 88 /* there is 16 bytes of data available here 89 * those are used to store callback pointer 90 * and next pointer. Thus, there is some free space 91 * on 32bits systems. 89 92 */ 93 struct transfer_descriptor *next_va; 94 callback_t *callback; 90 95 } __attribute__((packed)) transfer_descriptor_t; 91 96 92 97 93 98 void transfer_descriptor_init(transfer_descriptor_t *instance, 94 int error_count, size_t size, bool toggle, bool isochronous,95 usb_target_t target,int pid, void *buffer);99 int error_count, size_t size, bool isochronous, usb_target_t target, 100 int pid, void *buffer); 96 101 97 int transfer_descriptor_status(transfer_descriptor_t *instance); 102 static inline transfer_descriptor_t * transfer_descriptor_get( 103 int error_count, size_t size, bool isochronous, usb_target_t target, 104 int pid, void *buffer) 105 { 106 transfer_descriptor_t * instance = 107 malloc32(sizeof(transfer_descriptor_t)); 98 108 99 static inline bool transfer_descriptor_is_active( 100 transfer_descriptor_t *instance) 109 if (instance) 110 transfer_descriptor_init( 111 instance, error_count, size, isochronous, target, pid, buffer); 112 return instance; 113 } 114 115 void transfer_descriptor_fini(transfer_descriptor_t *instance); 116 117 static inline void transfer_descriptor_dispose(transfer_descriptor_t *instance) 101 118 { 102 119 assert(instance); 103 return instance->status & TD_STATUS_ERROR_ACTIVE; 120 transfer_descriptor_fini(instance); 121 free32(instance); 122 } 123 124 static inline void transfer_descriptor_append( 125 transfer_descriptor_t *instance, transfer_descriptor_t *item) 126 { 127 assert(instance); 128 instance->next_va = item; 129 instance->next = (uintptr_t)addr_to_phys( item ) & LINK_POINTER_ADDRESS_MASK; 104 130 } 105 131 #endif
Note:
See TracChangeset
for help on using the changeset viewer.