source: mainline/uspace/drv/uhci/uhci.c@ 0535ee4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0535ee4 was 0535ee4, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

Added debug_checker fibril (checks memory structures)

Fixed: Cleaning fibril checks all queues

  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[3515533]1#include <errno.h>
2#include <usb/debug.h>
[18e35a7]3#include <usb/usb.h>
[3515533]4
[de0e6b3]5#include "utils/malloc32.h"
[9600516]6
[bf5a3be]7#include "debug.h"
[3515533]8#include "name.h"
9#include "uhci.h"
10
[9ee87f6]11static int uhci_init_transfer_lists(transfer_list_t list[]);
12static int uhci_clean_finished(void *arg);
[0535ee4]13static int uhci_debug_checker(void *arg);
[7977fa1]14
[3515533]15int uhci_init(device_t *device, void *regs)
16{
[9ee87f6]17 assert(device);
18 uhci_print_info("Initializing device at address %p.\n", device);
19
20#define CHECK_RET_FREE_INSTANCE(message...) \
21 if (ret != EOK) { \
22 uhci_print_error(message); \
23 if (instance) { \
24 free(instance); \
25 } \
26 return ret; \
27 } else (void) 0
[3515533]28
29 /* create instance */
[d93ff502]30 uhci_t *instance = malloc(sizeof(uhci_t));
[9ee87f6]31 int ret = instance ? EOK : ENOMEM;
32 CHECK_RET_FREE_INSTANCE("Failed to allocate uhci driver instance.\n");
33
34 bzero(instance, sizeof(uhci_t));
[3515533]35
[18e35a7]36 /* init address keeper(libusb) */
[9ee87f6]37 usb_address_keeping_init(&instance->address_manager, USB11_ADDRESS_MAX);
[d93ff502]38 uhci_print_verbose("Initialized address manager.\n");
[18e35a7]39
[3515533]40 /* allow access to hc control registers */
41 regs_t *io;
[9ee87f6]42 ret = pio_enable(regs, sizeof(regs_t), (void**)&io);
43 CHECK_RET_FREE_INSTANCE("Failed to gain access to registers at %p.\n", io);
[3515533]44 instance->registers = io;
[d93ff502]45 uhci_print_verbose("Device registers accessible.\n");
[3515533]46
[9ee87f6]47 /* init transfer lists */
48 ret = uhci_init_transfer_lists(instance->transfers);
49 CHECK_RET_FREE_INSTANCE("Failed to initialize transfer lists.\n");
[d93ff502]50 uhci_print_verbose("Transfer lists initialized.\n");
[9ee87f6]51
[3515533]52 /* init root hub */
[9600516]53 ret = uhci_root_hub_init(&instance->root_hub, device,
54 (char*)regs + UHCI_ROOT_HUB_PORT_REGISTERS_OFFSET);
[9ee87f6]55 CHECK_RET_FREE_INSTANCE("Failed to initialize root hub driver.\n");
[9600516]56
[d93ff502]57 uhci_print_verbose("Initializing frame list.\n");
[d1984e0]58 instance->frame_list = get_page();
59// memalign32(sizeof(link_pointer_t) * UHCI_FRAME_LIST_COUNT, 4096);
[9600516]60 if (instance->frame_list == NULL) {
61 uhci_print_error("Failed to allocate frame list pointer.\n");
62 uhci_root_hub_fini(&instance->root_hub);
63 free(instance);
64 return ENOMEM;
65 }
66
[9ee87f6]67 /* initialize all frames to point to the first queue head */
68 unsigned i = 0;
69 const uint32_t queue =
70 instance->transfers[USB_TRANSFER_INTERRUPT].queue_head_pa
71 | LINK_POINTER_QUEUE_HEAD_FLAG;
72 for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
73 instance->frame_list[i] = queue;
74 }
75
[9600516]76 const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
77
78 pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
79
[9ee87f6]80 instance->cleaner = fibril_create(uhci_clean_finished, instance);
81 fibril_add_ready(instance->cleaner);
[3515533]82
[0535ee4]83 instance->debug_checker = fibril_create(uhci_debug_checker, instance);
84 fibril_add_ready(instance->debug_checker);
85
[d1984e0]86 uhci_print_verbose("Starting UHCI HC.\n");
87 uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
88 cmd |= UHCI_CMD_RUN_STOP | UHCI_CMD_CONFIGURE;
89 pio_write_16(&instance->registers->usbcmd, cmd);
90
[3515533]91 device->driver_data = instance;
92 return EOK;
93}
94/*----------------------------------------------------------------------------*/
[9ee87f6]95int uhci_init_transfer_lists(transfer_list_t transfers[])
[643b983]96{
97 //TODO:refactor
98 transfers[USB_TRANSFER_ISOCHRONOUS].first = NULL;
99 transfers[USB_TRANSFER_ISOCHRONOUS].last = NULL;
[b00163f]100
[643b983]101 int ret;
102 ret = transfer_list_init(&transfers[USB_TRANSFER_BULK], NULL);
103 if (ret != EOK) {
[b00163f]104 uhci_print_error("Failed to initialize bulk queue.\n");
[643b983]105 return ret;
106 }
107
108 ret = transfer_list_init(
109 &transfers[USB_TRANSFER_CONTROL], &transfers[USB_TRANSFER_BULK]);
110 if (ret != EOK) {
[b00163f]111 uhci_print_error("Failed to initialize control queue.\n");
[643b983]112 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
113 return ret;
114 }
115
116 ret = transfer_list_init(
117 &transfers[USB_TRANSFER_INTERRUPT], &transfers[USB_TRANSFER_CONTROL]);
118 if (ret != EOK) {
[b00163f]119 uhci_print_error("Failed to initialize interrupt queue.\n");
[643b983]120 transfer_list_fini(&transfers[USB_TRANSFER_CONTROL]);
121 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
122 return ret;
123 }
124
125 return EOK;
126}
[b00163f]127/*----------------------------------------------------------------------------*/
[d93ff502]128int uhci_transfer(
[b00163f]129 device_t *dev,
[d03ade7]130 usb_target_t target,
[b00163f]131 usb_transfer_type_t transfer_type,
[d93ff502]132 bool toggle,
[d03ade7]133 usb_packet_id pid,
[b00163f]134 void *buffer, size_t size,
135 usbhc_iface_transfer_out_callback_t callback_out,
136 usbhc_iface_transfer_in_callback_t callback_in,
[d03ade7]137 void *arg )
[b00163f]138{
139 // TODO: Add support for isochronous transfers
140 if (transfer_type == USB_TRANSFER_ISOCHRONOUS)
141 return ENOTSUP;
142
143 if (size >= 1024)
144 return ENOTSUP;
145
146 transfer_descriptor_t *td = NULL;
147 callback_t *job = NULL;
148 int ret = EOK;
149
150#define CHECK_RET_TRANS_FREE_JOB_TD(message) \
151 if (ret != EOK) { \
152 uhci_print_error(message); \
153 if (job) { \
[45c4f5a]154 callback_dispose(job); \
[b00163f]155 } \
[de0e6b3]156 if (td) { free32(td); } \
[b00163f]157 return ret; \
158 } else (void) 0
159
160
[45c4f5a]161 job = callback_get(dev, buffer, size, callback_in, callback_out, arg);
162 ret = job ? EOK : ENOMEM;
[b00163f]163 CHECK_RET_TRANS_FREE_JOB_TD("Failed to allocate callback structure.\n");
164
[eb03e92]165 td = transfer_descriptor_get(3, size, false, target, pid);
[d03ade7]166 ret = td ? EOK : ENOMEM;
[eb03e92]167 CHECK_RET_TRANS_FREE_JOB_TD("Failed to setup transfer descriptor.\n");
[b00163f]168
169 td->callback = job;
170
171 assert(dev);
172 uhci_t *instance = (uhci_t*)dev->driver_data;
173 assert(instance);
174
175 ret = transfer_list_append(&instance->transfers[transfer_type], td);
176 CHECK_RET_TRANS_FREE_JOB_TD("Failed to append transfer descriptor.\n");
177
178 return EOK;
179}
[9ee87f6]180/*----------------------------------------------------------------------------*/
181int uhci_clean_finished(void* arg)
182{
183 uhci_print_verbose("Started cleaning fibril.\n");
184 uhci_t *instance = (uhci_t*)arg;
185 assert(instance);
[579dec2]186
[9ee87f6]187 while(1) {
[d1984e0]188 uhci_print_verbose("Running cleaning fibril on: %p.\n", instance);
[579dec2]189 /* iterate all transfer queues */
[0535ee4]190 int i = 0;
[d1984e0]191 for (; i < TRANSFER_QUEUES; ++i) {
[579dec2]192 /* Remove inactive transfers from the top of the queue
193 * TODO: should I reach queue head or is this enough? */
[0535ee4]194 volatile transfer_descriptor_t * it =
195 instance->transfers[i].first;
196 uhci_print_verbose("Running cleaning fibril on queue: %p (%s).\n",
197 &instance->transfers[i], it ? "SOMETHING" : "EMPTY");
[579dec2]198 while (instance->transfers[i].first &&
199 !(instance->transfers[i].first->status & TD_STATUS_ERROR_ACTIVE)) {
200 transfer_descriptor_t *transfer = instance->transfers[i].first;
[0535ee4]201 uhci_print_info("Inactive transfer calling callback.\n");
[579dec2]202 instance->transfers[i].first = transfer->next_va;
[de0e6b3]203 transfer_descriptor_dispose(transfer);
[579dec2]204 }
205 if (!instance->transfers[i].first)
206 instance->transfers[i].last = instance->transfers[i].first;
207 }
[0535ee4]208 async_usleep(UHCI_CLEANER_TIMEOUT);
[9ee87f6]209 }
210 return EOK;
211}
[0535ee4]212/*---------------------------------------------------------------------------*/
213int uhci_debug_checker(void *arg)
214{
215 return 0;
216 uhci_t *instance = (uhci_t*)arg;
217 assert(instance);
218 while (1) {
219 uint16_t reg;
220 reg = pio_read_16(&instance->registers->usbcmd);
221 uhci_print_verbose("Command register: %X\n", reg);
222 reg = pio_read_16(&instance->registers->usbsts);
223 uhci_print_verbose("Status register: %X\n", reg);
224 uintptr_t frame_list = pio_read_32(&instance->registers->flbaseadd);
225 uhci_print_verbose("Framelist address: %p vs. %p.\n",
226 frame_list, addr_to_phys(instance->frame_list));
227 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
228 uhci_print_verbose("Framelist item: %d \n", frnum );
229
230 queue_head_t* qh = instance->transfers[USB_TRANSFER_INTERRUPT].queue_head;
231 uhci_print_verbose("Interrupt QH: %p vs. %p.\n",
232 instance->frame_list[frnum], addr_to_phys(qh));
233
234 uhci_print_verbose("Control QH: %p vs. %p.\n", qh->next_queue,
235 addr_to_phys(instance->transfers[USB_TRANSFER_CONTROL].queue_head));
236 qh = instance->transfers[USB_TRANSFER_CONTROL].queue_head;
237
238 uhci_print_verbose("Bulk QH: %p vs. %p.\n", qh->next_queue,
239 addr_to_phys(instance->transfers[USB_TRANSFER_BULK].queue_head));
240
241 async_usleep(UHCI_DEBUGER_TIMEOUT);
242 }
243 return 0;
244}
Note: See TracBrowser for help on using the repository browser.