source: mainline/uspace/drv/uhci-hcd/uhci.c@ 993a1e1

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

uhci-rhd - UHCI Root hub drier as a separated process

this wil deffinitely need a lot of polishing

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