Changeset 3afb758 in mainline
- Timestamp:
- 2011-08-24T15:23:46Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1a02517
- Parents:
- 5fe0a69
- Location:
- uspace
- Files:
-
- 2 deleted
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/Makefile
r5fe0a69 r3afb758 42 42 43 43 SOURCES = \ 44 iface.c \45 44 main.c \ 46 45 transfer_list.c \ -
uspace/drv/bus/usb/uhci/batch.c
r5fe0a69 r3afb758 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); 46 54 47 55 static void batch_setup_control(usb_transfer_batch_t *batch) … … 93 101 } 94 102 /*----------------------------------------------------------------------------*/ 103 /** Allocate memory and initialize internal data structure. 104 * 105 * @param[in] fun DDF function to pass to callback. 106 * @param[in] ep Communication target 107 * @param[in] buffer Data source/destination. 108 * @param[in] buffer_size Size of the buffer. 109 * @param[in] setup_buffer Setup data source (if not NULL) 110 * @param[in] setup_size Size of setup_buffer (should be always 8) 111 * @param[in] func_in function to call on inbound transfer completion 112 * @param[in] func_out function to call on outbound transfer completion 113 * @param[in] arg additional parameter to func_in or func_out 114 * @return Valid pointer if all structures were successfully created, 115 * NULL otherwise. 116 * 117 * Determines the number of needed transfer descriptors (TDs). 118 * Prepares a transport buffer (that is accessible by the hardware). 119 * Initializes parameters needed for the transfer and callback. 120 */ 95 121 void * uhci_transfer_batch_create(usb_transfer_batch_t *batch) 96 122 { … … 148 174 } 149 175 /*----------------------------------------------------------------------------*/ 150 /** Allocate memory and initialize internal data structure.151 *152 * @param[in] fun DDF function to pass to callback.153 * @param[in] ep Communication target154 * @param[in] buffer Data source/destination.155 * @param[in] buffer_size Size of the buffer.156 * @param[in] setup_buffer Setup data source (if not NULL)157 * @param[in] setup_size Size of setup_buffer (should be always 8)158 * @param[in] func_in function to call on inbound transfer completion159 * @param[in] func_out function to call on outbound transfer completion160 * @param[in] arg additional parameter to func_in or func_out161 * @return Valid pointer if all structures were successfully created,162 * NULL otherwise.163 *164 * Determines the number of needed transfer descriptors (TDs).165 * Prepares a transport buffer (that is accessible by the hardware).166 * Initializes parameters needed for the transfer and callback.167 */168 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,169 char *buffer, size_t buffer_size,170 const char* setup_buffer, size_t setup_size,171 usbhc_iface_transfer_in_callback_t func_in,172 usbhc_iface_transfer_out_callback_t func_out, void *arg)173 {174 assert(ep);175 assert(func_in == NULL || func_out == NULL);176 assert(func_in != NULL || func_out != NULL);177 178 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \179 if (ptr == NULL) { \180 usb_log_error(message); \181 if (uhci_data) { \182 uhci_transfer_batch_dispose(uhci_data); \183 } \184 return NULL; \185 } else (void)0186 187 uhci_transfer_batch_t *uhci_data =188 malloc(sizeof(uhci_transfer_batch_t));189 CHECK_NULL_DISPOSE_RETURN(uhci_data,190 "Failed to allocate UHCI batch.\n");191 bzero(uhci_data, sizeof(uhci_transfer_batch_t));192 193 uhci_data->td_count =194 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;195 if (ep->transfer_type == USB_TRANSFER_CONTROL) {196 uhci_data->td_count += 2;197 }198 199 assert((sizeof(td_t) % 16) == 0);200 const size_t total_size = (sizeof(td_t) * uhci_data->td_count)201 + sizeof(qh_t) + setup_size + buffer_size;202 uhci_data->device_buffer = malloc32(total_size);203 CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,204 "Failed to allocate UHCI buffer.\n");205 bzero(uhci_data->device_buffer, total_size);206 207 uhci_data->tds = uhci_data->device_buffer;208 uhci_data->qh =209 (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));210 211 qh_init(uhci_data->qh);212 qh_set_element_td(uhci_data->qh, uhci_data->tds);213 214 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));215 CHECK_NULL_DISPOSE_RETURN(instance,216 "Failed to allocate batch instance.\n");217 void *setup =218 uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)219 + sizeof(qh_t);220 void *data_buffer = setup + setup_size;221 usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,222 setup, setup_size, func_in, func_out, arg, fun,223 uhci_data, uhci_transfer_batch_dispose);224 225 memcpy(instance->setup_buffer, setup_buffer, setup_size);226 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT227 " memory structures ready.\n", instance,228 USB_TRANSFER_BATCH_ARGS(*instance));229 return instance;230 }231 176 /*----------------------------------------------------------------------------*/ 232 177 /** Check batch TDs for activity. … … 288 233 * Uses generic control function with pids OUT and IN. 289 234 */ 290 void batch_control_write(usb_transfer_batch_t *instance)235 static void batch_control_write(usb_transfer_batch_t *instance) 291 236 { 292 237 assert(instance); … … 304 249 * Uses generic control with pids IN and OUT. 305 250 */ 306 void batch_control_read(usb_transfer_batch_t *instance)251 static void batch_control_read(usb_transfer_batch_t *instance) 307 252 { 308 253 assert(instance); … … 318 263 * Data transfer with PID_IN. 319 264 */ 320 void batch_interrupt_in(usb_transfer_batch_t *instance)265 static void batch_interrupt_in(usb_transfer_batch_t *instance) 321 266 { 322 267 assert(instance); … … 332 277 * Data transfer with PID_OUT. 333 278 */ 334 void batch_interrupt_out(usb_transfer_batch_t *instance)279 static void batch_interrupt_out(usb_transfer_batch_t *instance) 335 280 { 336 281 assert(instance); … … 348 293 * Data transfer with PID_IN. 349 294 */ 350 void batch_bulk_in(usb_transfer_batch_t *instance)295 static void batch_bulk_in(usb_transfer_batch_t *instance) 351 296 { 352 297 assert(instance); … … 362 307 * Data transfer with PID_OUT. 363 308 */ 364 void batch_bulk_out(usb_transfer_batch_t *instance)309 static void batch_bulk_out(usb_transfer_batch_t *instance) 365 310 { 366 311 assert(instance); … … 380 325 * The last transfer is marked with IOC flag. 381 326 */ 382 void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid)327 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid) 383 328 { 384 329 assert(instance); … … 431 376 * The last transfer is marked with IOC. 432 377 */ 433 void batch_control(usb_transfer_batch_t *instance,378 static void batch_control(usb_transfer_batch_t *instance, 434 379 usb_packet_id data_stage, usb_packet_id status_stage) 435 380 { -
uspace/drv/bus/usb/uhci/batch.h
r5fe0a69 r3afb758 39 39 #include "hw_struct/queue_head.h" 40 40 41 usb_transfer_batch_t * batch_get(42 ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,43 const char *setup_buffer, size_t setup_size,44 usbhc_iface_transfer_in_callback_t func_in,45 usbhc_iface_transfer_out_callback_t func_out,46 void *arg);47 48 41 void * uhci_transfer_batch_create(usb_transfer_batch_t *batch); 49 42 void uhci_transfer_batch_dispose(void *uhci_batch); 50 43 51 void batch_dispose(usb_transfer_batch_t *instance);52 53 44 bool batch_is_complete(usb_transfer_batch_t *instance); 54 55 void batch_control_write(usb_transfer_batch_t *instance);56 void batch_control_read(usb_transfer_batch_t *instance);57 58 void batch_interrupt_in(usb_transfer_batch_t *instance);59 void batch_interrupt_out(usb_transfer_batch_t *instance);60 61 void batch_bulk_in(usb_transfer_batch_t *instance);62 void batch_bulk_out(usb_transfer_batch_t *instance);63 45 64 46 qh_t * batch_qh(usb_transfer_batch_t *instance); -
uspace/drv/bus/usb/uhci/hc.c
r5fe0a69 r3afb758 48 48 (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT) 49 49 50 static int schedule(hcd_t *hcd, usb_transfer_batch_t *batch)51 {52 assert(hcd);53 return hc_schedule(hcd->private_data, batch);54 }55 50 56 51 static const irq_cmd_t uhci_irq_commands[] = … … 64 59 }; 65 60 61 static void hc_init_hw(const hc_t *instance); 62 static int hc_init_mem_structures(hc_t *instance); 66 63 static int hc_init_transfer_lists(hc_t *instance); 67 static int hc_init_mem_structures(hc_t *instance); 68 static void hc_init_hw(hc_t *instance); 64 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 69 65 70 66 static int hc_interrupt_emulator(void *arg); … … 102 98 cmds[3].addr = (void*)®isters->usbsts; 103 99 return EOK; 100 } 101 /*----------------------------------------------------------------------------*/ 102 /** Take action based on the interrupt cause. 103 * 104 * @param[in] instance UHCI structure to use. 105 * @param[in] status Value of the status register at the time of interrupt. 106 * 107 * Interrupt might indicate: 108 * - transaction completed, either by triggering IOC, SPD, or an error 109 * - some kind of device error 110 * - resume from suspend state (not implemented) 111 */ 112 void hc_interrupt(hc_t *instance, uint16_t status) 113 { 114 assert(instance); 115 /* Lower 2 bits are transaction error and transaction complete */ 116 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 117 LIST_INITIALIZE(done); 118 transfer_list_remove_finished( 119 &instance->transfers_interrupt, &done); 120 transfer_list_remove_finished( 121 &instance->transfers_control_slow, &done); 122 transfer_list_remove_finished( 123 &instance->transfers_control_full, &done); 124 transfer_list_remove_finished( 125 &instance->transfers_bulk_full, &done); 126 127 while (!list_empty(&done)) { 128 link_t *item = list_first(&done); 129 list_remove(item); 130 usb_transfer_batch_t *batch = 131 list_get_instance(item, usb_transfer_batch_t, link); 132 usb_transfer_batch_finish(batch); 133 } 134 } 135 /* Resume interrupts are not supported */ 136 if (status & UHCI_STATUS_RESUME) { 137 usb_log_error("Resume interrupt!\n"); 138 } 139 140 /* Bits 4 and 5 indicate hc error */ 141 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 142 usb_log_error("UHCI hardware failure!.\n"); 143 ++instance->hw_failures; 144 transfer_list_abort_all(&instance->transfers_interrupt); 145 transfer_list_abort_all(&instance->transfers_control_slow); 146 transfer_list_abort_all(&instance->transfers_control_full); 147 transfer_list_abort_all(&instance->transfers_bulk_full); 148 149 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 150 /* reinitialize hw, this triggers virtual disconnect*/ 151 hc_init_hw(instance); 152 } else { 153 usb_log_fatal("Too many UHCI hardware failures!.\n"); 154 hc_fini(instance); 155 } 156 } 104 157 } 105 158 /*----------------------------------------------------------------------------*/ … … 138 191 usb_log_debug( 139 192 "Device registers at %p (%zuB) accessible.\n", io, reg_size); 140 hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11); 193 194 ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11); 195 CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n", 196 str_error(ret)); 197 141 198 instance->generic.private_data = instance; 142 instance->generic.schedule = schedule;199 instance->generic.schedule = hc_schedule; 143 200 instance->generic.batch_private_ctor = uhci_transfer_batch_create; 144 201 instance->generic.batch_private_dtor = uhci_transfer_batch_dispose; 202 #undef CHECK_RET_DEST_FUN_RETURN 145 203 146 204 ret = hc_init_mem_structures(instance); 147 CHECK_RET_RETURN(ret, 148 "Failed to initialize UHCI memory structures: %s.\n", 149 str_error(ret)); 205 if (ret != EOK) { 206 usb_log_error( 207 "Failed to initialize UHCI memory structures: %s.\n", 208 str_error(ret)); 209 hcd_destroy(&instance->generic); 210 return ret; 211 } 150 212 151 213 hc_init_hw(instance); … … 158 220 159 221 return EOK; 160 #undef CHECK_RET_DEST_FUN_RETURN161 222 } 162 223 /*----------------------------------------------------------------------------*/ … … 166 227 * For magic values see UHCI Design Guide 167 228 */ 168 void hc_init_hw( hc_t *instance)229 void hc_init_hw(const hc_t *instance) 169 230 { 170 231 assert(instance); … … 210 271 * 211 272 * Structures: 212 * - interrupt code (I/O addressses are customized per instance)213 273 * - transfer lists (queue heads need to be accessible by the hw) 214 274 * - frame list page (needs to be one UHCI hw accessible 4K page) … … 217 277 { 218 278 assert(instance); 219 #define CHECK_RET_RETURN(ret, message...) \ 220 if (ret != EOK) { \ 221 usb_log_error(message); \ 222 return ret; \ 223 } else (void) 0 279 280 /* Init USB frame list page */ 281 instance->frame_list = get_page(); 282 if (!instance->frame_list) { 283 return ENOMEM; 284 } 285 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 224 286 225 287 /* Init transfer lists */ 226 288 int ret = hc_init_transfer_lists(instance); 227 CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n"); 289 if (ret != EOK) { 290 usb_log_error("Failed to initialize transfer lists.\n"); 291 return_page(instance->frame_list); 292 return ENOMEM; 293 } 228 294 usb_log_debug("Initialized transfer lists.\n"); 229 295 230 /* Init device keeper */231 usb_device_keeper_init(&instance->manager);232 usb_log_debug("Initialized device keeper.\n");233 234 ret = usb_endpoint_manager_init(&instance->ep_manager,235 BANDWIDTH_AVAILABLE_USB11);236 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",237 str_error(ret));238 239 /* Init USB frame list page*/240 instance->frame_list = get_page();241 if (!instance->frame_list) {242 usb_log_error("Failed to get frame list page.\n");243 usb_endpoint_manager_destroy(&instance->ep_manager);244 return ENOMEM;245 }246 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);247 296 248 297 /* Set all frames to point to the first queue head */ … … 255 304 256 305 return EOK; 257 #undef CHECK_RET_RETURN258 306 } 259 307 /*----------------------------------------------------------------------------*/ … … 328 376 * Checks for bandwidth availability and appends the batch to the proper queue. 329 377 */ 330 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 331 { 378 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 379 { 380 assert(hcd); 381 hc_t *instance = hcd->private_data; 332 382 assert(instance); 333 383 assert(batch); … … 339 389 340 390 return EOK; 341 }342 /*----------------------------------------------------------------------------*/343 /** Take action based on the interrupt cause.344 *345 * @param[in] instance UHCI structure to use.346 * @param[in] status Value of the status register at the time of interrupt.347 *348 * Interrupt might indicate:349 * - transaction completed, either by triggering IOC, SPD, or an error350 * - some kind of device error351 * - resume from suspend state (not implemented)352 */353 void hc_interrupt(hc_t *instance, uint16_t status)354 {355 assert(instance);356 /* Lower 2 bits are transaction error and transaction complete */357 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {358 LIST_INITIALIZE(done);359 transfer_list_remove_finished(360 &instance->transfers_interrupt, &done);361 transfer_list_remove_finished(362 &instance->transfers_control_slow, &done);363 transfer_list_remove_finished(364 &instance->transfers_control_full, &done);365 transfer_list_remove_finished(366 &instance->transfers_bulk_full, &done);367 368 while (!list_empty(&done)) {369 link_t *item = list_first(&done);370 list_remove(item);371 usb_transfer_batch_t *batch =372 list_get_instance(item, usb_transfer_batch_t, link);373 usb_transfer_batch_finish(batch);374 }375 }376 /* Resume interrupts are not supported */377 if (status & UHCI_STATUS_RESUME) {378 usb_log_error("Resume interrupt!\n");379 }380 381 /* Bits 4 and 5 indicate hc error */382 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {383 usb_log_error("UHCI hardware failure!.\n");384 ++instance->hw_failures;385 transfer_list_abort_all(&instance->transfers_interrupt);386 transfer_list_abort_all(&instance->transfers_control_slow);387 transfer_list_abort_all(&instance->transfers_control_full);388 transfer_list_abort_all(&instance->transfers_bulk_full);389 390 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {391 /* reinitialize hw, this triggers virtual disconnect*/392 hc_init_hw(instance);393 } else {394 usb_log_fatal("Too many UHCI hardware failures!.\n");395 hc_fini(instance);396 }397 }398 391 } 399 392 /*----------------------------------------------------------------------------*/ … … 415 408 if (status != 0) 416 409 usb_log_debug2("UHCI status: %x.\n", status); 417 // Qemu fails to report stalled communication418 // see https://bugs.launchpad.net/qemu/+bug/757654419 // This is a simple workaround to force queue processing every time420 // status |= 1;421 410 hc_interrupt(instance, status); 422 411 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); … … 424 413 return EOK; 425 414 } 426 /*--------------------------------------------------------------------------- */415 /*----------------------------------------------------------------------------*/ 427 416 /** Debug function, checks consistency of memory structures. 428 417 * -
uspace/drv/bus/usb/uhci/hc.h
r5fe0a69 r3afb758 39 39 #include <ddi.h> 40 40 41 #include <usb/host/device_keeper.h>42 #include <usb/host/usb_endpoint_manager.h>43 41 #include <usb/host/batch.h> 44 42 #include <usb/host/hcd.h> … … 95 93 /** Main UHCI driver structure */ 96 94 typedef struct hc { 95 /** Generic HCD driver structure */ 97 96 hcd_t generic; 98 /** USB bus driver, devices and addresses */99 usb_device_keeper_t manager;100 /** USB bus driver, endpoints */101 usb_endpoint_manager_t ep_manager;102 97 103 98 /** Addresses of I/O registers */ … … 126 121 unsigned hw_failures; 127 122 } hc_t; 123 128 124 size_t hc_irq_cmd_count(void); 129 125 int hc_get_irq_commands( 130 126 irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size); 127 void hc_interrupt(hc_t *instance, uint16_t status); 131 128 int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts); 132 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);133 void hc_interrupt(hc_t *instance, uint16_t status);134 129 135 130 /** Safely dispose host controller internal structures … … 137 132 * @param[in] instance Host controller structure to use. 138 133 */ 139 static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ }; 140 141 /** Get and cast pointer to the driver data 142 * 143 * @param[in] fun DDF function pointer 144 * @return cast pointer to driver_data 145 */ 146 static inline hc_t * fun_to_hc(ddf_fun_t *fun) 147 { 148 assert(fun); 149 return fun->driver_data; 150 } 134 static inline void hc_fini(hc_t *instance) {} /* TODO: implement*/ 151 135 #endif 152 136 /** -
uspace/drv/bus/usb/uhci/pci.c
r5fe0a69 r3afb758 142 142 { 143 143 assert(device); 144 144 145 145 async_sess_t *parent_sess = 146 146 devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle, … … 148 148 if (!parent_sess) 149 149 return ENOMEM; 150 150 151 151 /* See UHCI design guide for these values p.45, 152 152 * write all WC bits in USB legacy register */ 153 153 const sysarg_t address = 0xc0; 154 154 const sysarg_t value = 0xaf00; 155 155 156 156 async_exch_t *exch = async_exchange_begin(parent_sess); 157 157 158 158 const int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE), 159 159 IPC_M_CONFIG_SPACE_WRITE_16, address, value); 160 160 161 161 async_exchange_end(exch); 162 162 async_hangup(parent_sess); 163 163 164 164 return rc; 165 165 } -
uspace/drv/bus/usb/uhci/uhci.c
r5fe0a69 r3afb758 41 41 42 42 #include "uhci.h" 43 #include "iface.h"44 43 #include "pci.h" 45 44 -
uspace/drv/bus/usb/uhci/utils/malloc32.h
r5fe0a69 r3afb758 102 102 if (free_address == 0) 103 103 return NULL; 104 void * ret= as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,104 void *address = as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE, 105 105 AS_AREA_READ | AS_AREA_WRITE); 106 if ( ret!= free_address)106 if (address != free_address) 107 107 return NULL; 108 return ret; 108 return address; 109 } 110 /*----------------------------------------------------------------------------*/ 111 static inline void return_page(void *page) 112 { 113 if (page) 114 as_area_destroy(page); 109 115 } 110 116 -
uspace/lib/usbhost/include/usb/host/hcd.h
r5fe0a69 r3afb758 61 61 } 62 62 /*----------------------------------------------------------------------------*/ 63 static inline void hcd_destroy(hcd_t *hcd) 64 { 65 usb_endpoint_manager_destroy(&hcd->ep_manager); 66 } 67 /*----------------------------------------------------------------------------*/ 63 68 static inline void reset_ep_if_need( 64 69 hcd_t *hcd, usb_target_t target, const char* setup_data)
Note:
See TracChangeset
for help on using the changeset viewer.