source: mainline/uspace/drv/uhci/uhci.c@ eb03e92

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

Used get() and dispose() convenience functions

  • Property mode set to 100644
File size: 7.7 KB
Line 
1#include <errno.h>
2#include <usb/debug.h>
3#include <usb/usb.h>
4
5#include "translating_malloc.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 inline int uhci_add_transfer(
14 device_t *dev,
15 usb_target_t target,
16 usb_transfer_type_t transfer_type,
17 usb_packet_id pid,
18 void *buffer, size_t size,
19 usbhc_iface_transfer_out_callback_t callback_out,
20 usbhc_iface_transfer_in_callback_t callback_in,
21 void *arg );
22
23int uhci_init(device_t *device, void *regs)
24{
25 assert(device);
26 uhci_print_info("Initializing device at address %p.\n", device);
27
28#define CHECK_RET_FREE_INSTANCE(message...) \
29 if (ret != EOK) { \
30 uhci_print_error(message); \
31 if (instance) { \
32 free(instance); \
33 } \
34 return ret; \
35 } else (void) 0
36
37 /* create instance */
38 uhci_t *instance = malloc( sizeof(uhci_t) );
39 int ret = instance ? EOK : ENOMEM;
40 CHECK_RET_FREE_INSTANCE("Failed to allocate uhci driver instance.\n");
41
42 bzero(instance, sizeof(uhci_t));
43
44 /* init address keeper(libusb) */
45 usb_address_keeping_init(&instance->address_manager, USB11_ADDRESS_MAX);
46
47 /* allow access to hc control registers */
48 regs_t *io;
49 ret = pio_enable(regs, sizeof(regs_t), (void**)&io);
50 CHECK_RET_FREE_INSTANCE("Failed to gain access to registers at %p.\n", io);
51 instance->registers = io;
52
53 /* init transfer lists */
54 ret = uhci_init_transfer_lists(instance->transfers);
55 CHECK_RET_FREE_INSTANCE("Failed to initialize transfer lists.\n");
56
57 /* init root hub */
58 ret = uhci_root_hub_init(&instance->root_hub, device,
59 (char*)regs + UHCI_ROOT_HUB_PORT_REGISTERS_OFFSET);
60 CHECK_RET_FREE_INSTANCE("Failed to initialize root hub driver.\n");
61
62 instance->frame_list =
63 trans_malloc(sizeof(link_pointer_t) * UHCI_FRAME_LIST_COUNT);
64 if (instance->frame_list == NULL) {
65 uhci_print_error("Failed to allocate frame list pointer.\n");
66 uhci_root_hub_fini(&instance->root_hub);
67 free(instance);
68 return ENOMEM;
69 }
70
71 /* initialize all frames to point to the first queue head */
72 unsigned i = 0;
73 const uint32_t queue =
74 instance->transfers[USB_TRANSFER_INTERRUPT].queue_head_pa
75 | LINK_POINTER_QUEUE_HEAD_FLAG;
76 for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
77 instance->frame_list[i] = queue;
78 }
79
80 const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
81
82 pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
83
84 instance->cleaner = fibril_create(uhci_clean_finished, instance);
85 fibril_add_ready(instance->cleaner);
86
87 device->driver_data = instance;
88 return EOK;
89}
90/*----------------------------------------------------------------------------*/
91int uhci_in(
92 device_t *dev,
93 usb_target_t target,
94 usb_transfer_type_t transfer_type,
95 void *buffer, size_t size,
96 usbhc_iface_transfer_in_callback_t callback, void *arg
97 )
98{
99 uhci_print_info( "transfer IN [%d.%d (%s); %zu]\n",
100 target.address, target.endpoint,
101 usb_str_transfer_type(transfer_type),
102 size);
103 return uhci_add_transfer(
104 dev, target, transfer_type, USB_PID_IN, buffer, size, NULL, callback, arg);
105}
106/*----------------------------------------------------------------------------*/
107int uhci_out(
108 device_t *dev,
109 usb_target_t target,
110 usb_transfer_type_t transfer_type,
111 void *buffer, size_t size,
112 usbhc_iface_transfer_out_callback_t callback, void *arg
113 )
114{
115 uhci_print_info( "transfer OUT [%d.%d (%s); %zu]\n",
116 target.address, target.endpoint,
117 usb_str_transfer_type(transfer_type),
118 size);
119 return uhci_add_transfer(
120 dev, target, transfer_type, USB_PID_OUT, buffer, size, callback, NULL, arg);
121}
122/*----------------------------------------------------------------------------*/
123int uhci_setup(
124 device_t *dev,
125 usb_target_t target,
126 usb_transfer_type_t transfer_type,
127 void *buffer, size_t size,
128 usbhc_iface_transfer_out_callback_t callback, void *arg
129 )
130{
131 uhci_print_info( "transfer SETUP [%d.%d (%s); %zu]\n",
132 target.address, target.endpoint,
133 usb_str_transfer_type(transfer_type),
134 size);
135 uhci_print_info("Setup packet content: %x %x.\n", ((uint8_t*)buffer)[0],
136 ((uint8_t*)buffer)[1]);
137 return uhci_add_transfer( dev,
138 target, transfer_type, USB_PID_SETUP, buffer, size, callback, NULL, arg);
139
140}
141/*----------------------------------------------------------------------------*/
142int uhci_init_transfer_lists(transfer_list_t transfers[])
143{
144 //TODO:refactor
145 transfers[USB_TRANSFER_ISOCHRONOUS].first = NULL;
146 transfers[USB_TRANSFER_ISOCHRONOUS].last = NULL;
147
148 int ret;
149 ret = transfer_list_init(&transfers[USB_TRANSFER_BULK], NULL);
150 if (ret != EOK) {
151 uhci_print_error("Failed to initialize bulk queue.\n");
152 return ret;
153 }
154
155 ret = transfer_list_init(
156 &transfers[USB_TRANSFER_CONTROL], &transfers[USB_TRANSFER_BULK]);
157 if (ret != EOK) {
158 uhci_print_error("Failed to initialize control queue.\n");
159 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
160 return ret;
161 }
162
163 ret = transfer_list_init(
164 &transfers[USB_TRANSFER_INTERRUPT], &transfers[USB_TRANSFER_CONTROL]);
165 if (ret != EOK) {
166 uhci_print_error("Failed to initialize interrupt queue.\n");
167 transfer_list_fini(&transfers[USB_TRANSFER_CONTROL]);
168 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
169 return ret;
170 }
171
172 return EOK;
173}
174/*----------------------------------------------------------------------------*/
175static inline int uhci_add_transfer(
176 device_t *dev,
177 usb_target_t target,
178 usb_transfer_type_t transfer_type,
179 usb_packet_id pid,
180 void *buffer, size_t size,
181 usbhc_iface_transfer_out_callback_t callback_out,
182 usbhc_iface_transfer_in_callback_t callback_in,
183 void *arg )
184{
185 // TODO: Add support for isochronous transfers
186 if (transfer_type == USB_TRANSFER_ISOCHRONOUS)
187 return ENOTSUP;
188
189 if (size >= 1024)
190 return ENOTSUP;
191
192 transfer_descriptor_t *td = NULL;
193 callback_t *job = NULL;
194 int ret = EOK;
195
196#define CHECK_RET_TRANS_FREE_JOB_TD(message) \
197 if (ret != EOK) { \
198 uhci_print_error(message); \
199 if (job) { \
200 callback_fini(job); \
201 trans_free(job); \
202 } \
203 if (td) { trans_free(td); } \
204 return ret; \
205 } else (void) 0
206
207
208 job = malloc(sizeof(callback_t));
209 ret= job ? EOK : ENOMEM;
210 CHECK_RET_TRANS_FREE_JOB_TD("Failed to allocate callback structure.\n");
211
212 ret = callback_init(job, dev, buffer, size, callback_in, callback_out, arg);
213 CHECK_RET_TRANS_FREE_JOB_TD("Failed to initialize callback structure.\n");
214
215 td = transfer_descriptor_get(3, size, false, target, pid);
216 ret = td ? EOK : ENOMEM;
217 CHECK_RET_TRANS_FREE_JOB_TD("Failed to setup transfer descriptor.\n");
218
219 td->callback = job;
220
221 assert(dev);
222 uhci_t *instance = (uhci_t*)dev->driver_data;
223 assert(instance);
224
225 ret = transfer_list_append(&instance->transfers[transfer_type], td);
226 CHECK_RET_TRANS_FREE_JOB_TD("Failed to append transfer descriptor.\n");
227
228 return EOK;
229}
230/*----------------------------------------------------------------------------*/
231int uhci_clean_finished(void* arg)
232{
233 uhci_print_verbose("Started cleaning fibril.\n");
234 uhci_t *instance = (uhci_t*)arg;
235 assert(instance);
236
237 while(1) {
238 uhci_print_verbose("Running cleaning fibril on %p.\n", instance);
239 /* iterate all transfer queues */
240 usb_transfer_type_t i = USB_TRANSFER_BULK;
241 for (; i > USB_TRANSFER_ISOCHRONOUS; --i) {
242 /* Remove inactive transfers from the top of the queue
243 * TODO: should I reach queue head or is this enough? */
244 while (instance->transfers[i].first &&
245 !(instance->transfers[i].first->status & TD_STATUS_ERROR_ACTIVE)) {
246 transfer_descriptor_t *transfer = instance->transfers[i].first;
247 uhci_print_verbose("Cleaning fibril found inactive transport.");
248 instance->transfers[i].first = transfer->next_va;
249 transfer_descriptor_fini(transfer);
250 trans_free(transfer);
251 }
252 if (!instance->transfers[i].first)
253 instance->transfers[i].last = instance->transfers[i].first;
254 }
255
256 async_usleep(1000000);
257 }
258 return EOK;
259}
Note: See TracBrowser for help on using the repository browser.