source: mainline/uspace/drv/uhci-hcd/uhci.c@ 37ac7bb

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

Renames "uhci"→"uhci-hcd" to prepare RH drier separation

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