source: mainline/uspace/drv/uhci/uhci.c@ 5286a2c

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

Reduced debug level and made times shorter

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