tools/llvm: Do not build with symbols
[minix3.git] / minix / drivers / usb / usbd / hcd / hcd_schedule.c
blobfeacd214e1a57f6209b2fa6b5ca7fb29ee555b3f
1 /*
2 * Implementation of HCD URB scheduler
3 */
5 #include <string.h> /* memset */
7 #include <usbd/hcd_common.h>
8 #include <usbd/hcd_ddekit.h>
9 #include <usbd/hcd_interface.h>
10 #include <usbd/hcd_schedule.h>
11 #include <usbd/usbd_common.h>
12 #include <usbd/usbd_schedule.h>
15 /*===========================================================================*
16 * Required for scheduling *
17 *===========================================================================*/
18 /* TODO: Like in DDEKit but power of 2 */
19 #define HCD_MAX_URBS 16
21 /* TODO: Structure to hold URBs in DDEKit is limited so this is no better
22 * (but because of that, there is no need for another malloc) */
23 static hcd_urb * stored_urb[HCD_MAX_URBS];
25 /* Number of URBs stored during operation */
26 static int num_stored_urbs;
28 /* Scheduler thread */
29 static hcd_thread * urb_thread;
31 /* This allows waiting for URB */
32 static hcd_lock * urb_lock;
34 /* This allows waiting for completion */
35 static hcd_lock * handled_lock;
37 /* Makes URB schedule enabled */
38 static int hcd_schedule_urb(hcd_urb *);
40 /* Makes URB schedule disabled */
41 static void hcd_unschedule_urb(hcd_urb *);
43 /* Scheduler task */
44 static void hcd_urb_scheduler_task(void *);
46 /* Completion callback */
47 static void hcd_urb_handled(hcd_urb *);
49 /* Stores URB to be handled */
50 static int hcd_store_urb(hcd_urb *);
52 /* Removes stored URB */
53 static void hcd_remove_urb(hcd_urb *);
55 /* Gets URB to be handled next (based on priority) */
56 static hcd_urb * hcd_get_urb(void);
59 /*===========================================================================*
60 * usbd_init_scheduler *
61 *===========================================================================*/
62 int
63 usbd_init_scheduler(void)
65 DEBUG_DUMP;
67 /* Reset everything */
68 num_stored_urbs = 0;
69 memset(stored_urb, 0, sizeof(stored_urb));
71 urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL,
72 "scheduler");
73 if (NULL == urb_thread)
74 goto ERR1;
76 urb_lock = ddekit_sem_init(0);
77 if (NULL == urb_lock)
78 goto ERR2;
80 handled_lock = ddekit_sem_init(0);
81 if (NULL == handled_lock)
82 goto ERR3;
84 return EXIT_SUCCESS;
86 ERR3:
87 ddekit_sem_deinit(urb_lock);
88 ERR2:
89 ddekit_thread_terminate(urb_thread);
90 ERR1:
91 return EXIT_FAILURE;
95 /*===========================================================================*
96 * usbd_deinit_scheduler *
97 *===========================================================================*/
98 void
99 usbd_deinit_scheduler(void)
101 DEBUG_DUMP;
103 ddekit_sem_deinit(handled_lock);
105 ddekit_sem_deinit(urb_lock);
107 ddekit_thread_terminate(urb_thread);
111 /*===========================================================================*
112 * hcd_schedule_external_urb *
113 *===========================================================================*/
115 hcd_schedule_external_urb(hcd_urb * urb)
117 DEBUG_DUMP;
119 return hcd_schedule_urb(urb);
123 /*===========================================================================*
124 * hcd_schedule_internal_urb *
125 *===========================================================================*/
127 hcd_schedule_internal_urb(hcd_urb * urb)
129 DEBUG_DUMP;
131 return hcd_schedule_urb(urb);
135 /*===========================================================================*
136 * hcd_schedule_urb *
137 *===========================================================================*/
138 static int
139 hcd_schedule_urb(hcd_urb * urb)
141 DEBUG_DUMP;
143 /* Tell URB what to call on completion */
144 urb->handled = hcd_urb_handled;
146 /* Store and check if scheduler should be unlocked */
147 if (EXIT_SUCCESS == hcd_store_urb(urb)) {
148 ddekit_sem_up(urb_lock);
149 return EXIT_SUCCESS;
152 return EXIT_FAILURE;
156 /*===========================================================================*
157 * hcd_unschedule_urb *
158 *===========================================================================*/
159 static void
160 hcd_unschedule_urb(hcd_urb * urb)
162 DEBUG_DUMP;
164 hcd_remove_urb(urb);
168 /*===========================================================================*
169 * hcd_urb_scheduler_task *
170 *===========================================================================*/
171 static void
172 hcd_urb_scheduler_task(void * UNUSED(arg))
174 hcd_device_state * current_device;
175 hcd_urb * current_urb;
177 DEBUG_DUMP;
179 for (;;) {
180 /* Wait for scheduler to unlock on any URB submit */
181 ddekit_sem_down(urb_lock);
183 /* Get URB */
184 current_urb = hcd_get_urb();
186 /* Get URB's target device */
187 current_device = current_urb->target_device;
189 /* Check for mismatch */
190 USB_ASSERT(NULL != current_urb, "URB missing after URB unlock");
192 /* Check if URB's device is still allocated */
193 if (EXIT_SUCCESS == hcd_check_device(current_device)) {
194 /* Tell device that this is its URB */
195 current_device->urb = current_urb;
197 /* Start handling URB event */
198 hcd_handle_event(current_device, HCD_EVENT_URB,
199 HCD_UNUSED_VAL);
201 /* Wait for completion */
202 ddekit_sem_down(handled_lock);
204 /* TODO: Not enough DDEKit thread priorities
205 * for a better solution */
206 /* Yield, to allow unlocking thread, to continue
207 * before next URB is used */
208 ddekit_yield();
210 /* Makes thread debugging easier */
211 USB_DBG("URB handled, scheduler unlocked");
212 } else {
213 USB_MSG("Device 0x%08X for URB 0x%08X, is unavailable",
214 (int)current_device,
215 (int)current_urb);
221 /*===========================================================================*
222 * hcd_urb_handled *
223 *===========================================================================*/
224 static void
225 hcd_urb_handled(hcd_urb * urb)
227 DEBUG_DUMP;
229 /* This URB will be scheduled no more */
230 hcd_unschedule_urb(urb);
232 /* Handling completed */
233 ddekit_sem_up(handled_lock);
237 /*===========================================================================*
238 * hcd_store_urb *
239 *===========================================================================*/
240 static int
241 hcd_store_urb(hcd_urb * urb)
243 int i;
245 DEBUG_DUMP;
247 for (i = 0; i < HCD_MAX_URBS; i++) {
248 if (NULL == stored_urb[i]) {
249 stored_urb[i] = urb;
250 num_stored_urbs++;
251 return EXIT_SUCCESS;
255 USB_MSG("No more free URBs");
257 return EXIT_FAILURE;
260 /*===========================================================================*
261 * hcd_remove_urb *
262 *===========================================================================*/
263 static void
264 hcd_remove_urb(hcd_urb * urb)
266 int i;
268 DEBUG_DUMP;
270 for (i = 0; i < HCD_MAX_URBS; i++) {
271 if (urb == stored_urb[i]) {
272 stored_urb[i] = NULL;
273 num_stored_urbs--;
274 return;
278 USB_ASSERT(0, "URB to be removed, was never stored");
281 /*===========================================================================*
282 * hcd_get_urb *
283 *===========================================================================*/
284 static hcd_urb *
285 hcd_get_urb(void)
287 static int i = 0;
288 int checked;
290 DEBUG_DUMP;
292 /* TODO: Some priority checking may be here */
293 for (checked = 0; checked < HCD_MAX_URBS; checked++) {
294 /* To avoid starting from 0 every
295 * time (potential starvation) */
296 i = (i + 1) % HCD_MAX_URBS;
298 /* When found */
299 if (NULL != stored_urb[i])
300 return stored_urb[i];
303 /* Nothing submitted yet */
304 return NULL;