source: mainline/uspace/drv/uhci/uhci.c@ 10f479ae

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

Added toggle bit parameter.

Removed uhci_* specific functions, use uhci_transfer directly

  • Property mode set to 100644
File size: 5.8 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);
13
14int uhci_init(device_t *device, void *regs)
15{
16 assert(device);
17 uhci_print_info("Initializing device at address %p.\n", device);
18
19#define CHECK_RET_FREE_INSTANCE(message...) \
20 if (ret != EOK) { \
21 uhci_print_error(message); \
22 if (instance) { \
23 free(instance); \
24 } \
25 return ret; \
26 } else (void) 0
27
28 /* create instance */
29 uhci_t *instance = malloc(sizeof(uhci_t));
30 int ret = instance ? EOK : ENOMEM;
31 CHECK_RET_FREE_INSTANCE("Failed to allocate uhci driver instance.\n");
32
33 bzero(instance, sizeof(uhci_t));
34
35 /* init address keeper(libusb) */
36 usb_address_keeping_init(&instance->address_manager, USB11_ADDRESS_MAX);
37 uhci_print_verbose("Initialized address manager.\n");
38
39 /* allow access to hc control registers */
40 regs_t *io;
41 ret = pio_enable(regs, sizeof(regs_t), (void**)&io);
42 CHECK_RET_FREE_INSTANCE("Failed to gain access to registers at %p.\n", io);
43 instance->registers = io;
44 uhci_print_verbose("Device registers accessible.\n");
45
46 /* init transfer lists */
47 ret = uhci_init_transfer_lists(instance->transfers);
48 CHECK_RET_FREE_INSTANCE("Failed to initialize transfer lists.\n");
49 uhci_print_verbose("Transfer lists initialized.\n");
50
51 /* init root hub */
52 ret = uhci_root_hub_init(&instance->root_hub, device,
53 (char*)regs + UHCI_ROOT_HUB_PORT_REGISTERS_OFFSET);
54 CHECK_RET_FREE_INSTANCE("Failed to initialize root hub driver.\n");
55
56 uhci_print_verbose("Initializing frame list.\n");
57 instance->frame_list =
58 memallign32(sizeof(link_pointer_t) * UHCI_FRAME_LIST_COUNT, 4096);
59 if (instance->frame_list == NULL) {
60 uhci_print_error("Failed to allocate frame list pointer.\n");
61 uhci_root_hub_fini(&instance->root_hub);
62 free(instance);
63 return ENOMEM;
64 }
65
66 /* initialize all frames to point to the first queue head */
67 unsigned i = 0;
68 const uint32_t queue =
69 instance->transfers[USB_TRANSFER_INTERRUPT].queue_head_pa
70 | LINK_POINTER_QUEUE_HEAD_FLAG;
71 for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
72 instance->frame_list[i] = queue;
73 }
74
75 const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
76
77 pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
78
79 instance->cleaner = fibril_create(uhci_clean_finished, instance);
80 fibril_add_ready(instance->cleaner);
81
82 device->driver_data = instance;
83 return EOK;
84}
85/*----------------------------------------------------------------------------*/
86int uhci_init_transfer_lists(transfer_list_t transfers[])
87{
88 //TODO:refactor
89 transfers[USB_TRANSFER_ISOCHRONOUS].first = NULL;
90 transfers[USB_TRANSFER_ISOCHRONOUS].last = NULL;
91
92 int ret;
93 ret = transfer_list_init(&transfers[USB_TRANSFER_BULK], NULL);
94 if (ret != EOK) {
95 uhci_print_error("Failed to initialize bulk queue.\n");
96 return ret;
97 }
98
99 ret = transfer_list_init(
100 &transfers[USB_TRANSFER_CONTROL], &transfers[USB_TRANSFER_BULK]);
101 if (ret != EOK) {
102 uhci_print_error("Failed to initialize control queue.\n");
103 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
104 return ret;
105 }
106
107 ret = transfer_list_init(
108 &transfers[USB_TRANSFER_INTERRUPT], &transfers[USB_TRANSFER_CONTROL]);
109 if (ret != EOK) {
110 uhci_print_error("Failed to initialize interrupt queue.\n");
111 transfer_list_fini(&transfers[USB_TRANSFER_CONTROL]);
112 transfer_list_fini(&transfers[USB_TRANSFER_BULK]);
113 return ret;
114 }
115
116 return EOK;
117}
118/*----------------------------------------------------------------------------*/
119int uhci_transfer(
120 device_t *dev,
121 usb_target_t target,
122 usb_transfer_type_t transfer_type,
123 bool toggle,
124 usb_packet_id pid,
125 void *buffer, size_t size,
126 usbhc_iface_transfer_out_callback_t callback_out,
127 usbhc_iface_transfer_in_callback_t callback_in,
128 void *arg )
129{
130 // TODO: Add support for isochronous transfers
131 if (transfer_type == USB_TRANSFER_ISOCHRONOUS)
132 return ENOTSUP;
133
134 if (size >= 1024)
135 return ENOTSUP;
136
137 transfer_descriptor_t *td = NULL;
138 callback_t *job = NULL;
139 int ret = EOK;
140
141#define CHECK_RET_TRANS_FREE_JOB_TD(message) \
142 if (ret != EOK) { \
143 uhci_print_error(message); \
144 if (job) { \
145 callback_dispose(job); \
146 } \
147 if (td) { free32(td); } \
148 return ret; \
149 } else (void) 0
150
151
152 job = callback_get(dev, buffer, size, callback_in, callback_out, arg);
153 ret = job ? EOK : ENOMEM;
154 CHECK_RET_TRANS_FREE_JOB_TD("Failed to allocate callback structure.\n");
155
156 td = transfer_descriptor_get(3, size, false, target, pid);
157 ret = td ? EOK : ENOMEM;
158 CHECK_RET_TRANS_FREE_JOB_TD("Failed to setup transfer descriptor.\n");
159
160 td->callback = job;
161
162 assert(dev);
163 uhci_t *instance = (uhci_t*)dev->driver_data;
164 assert(instance);
165
166 ret = transfer_list_append(&instance->transfers[transfer_type], td);
167 CHECK_RET_TRANS_FREE_JOB_TD("Failed to append transfer descriptor.\n");
168
169 return EOK;
170}
171/*----------------------------------------------------------------------------*/
172int uhci_clean_finished(void* arg)
173{
174 uhci_print_verbose("Started cleaning fibril.\n");
175 uhci_t *instance = (uhci_t*)arg;
176 assert(instance);
177
178 while(1) {
179 uhci_print_verbose("Running cleaning fibril on %p.\n", instance);
180 /* iterate all transfer queues */
181 usb_transfer_type_t i = USB_TRANSFER_BULK;
182 for (; i > USB_TRANSFER_ISOCHRONOUS; --i) {
183 /* Remove inactive transfers from the top of the queue
184 * TODO: should I reach queue head or is this enough? */
185 while (instance->transfers[i].first &&
186 !(instance->transfers[i].first->status & TD_STATUS_ERROR_ACTIVE)) {
187 transfer_descriptor_t *transfer = instance->transfers[i].first;
188 uhci_print_verbose("Cleaning fibril found inactive transport.");
189 instance->transfers[i].first = transfer->next_va;
190 transfer_descriptor_dispose(transfer);
191 }
192 if (!instance->transfers[i].first)
193 instance->transfers[i].last = instance->transfers[i].first;
194 }
195 async_usleep(1000000);
196 }
197 return EOK;
198}
Note: See TracBrowser for help on using the repository browser.