xref: /minix/minix/drivers/usb/usbd/hcd/hcd_schedule.c (revision 0a6a1f1d)
1 /*
2  * Implementation of HCD URB scheduler
3  */
4 
5 #include <string.h>				/* memset */
6 
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>
13 
14 
15 /*===========================================================================*
16  *    Required for scheduling                                                *
17  *===========================================================================*/
18 /* TODO: Like in DDEKit but power of 2 */
19 #define HCD_MAX_URBS 16
20 
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];
24 
25 /* Number of URBs stored during operation */
26 static int num_stored_urbs;
27 
28 /* Scheduler thread */
29 static hcd_thread * urb_thread;
30 
31 /* This allows waiting for URB */
32 static hcd_lock * urb_lock;
33 
34 /* This allows waiting for completion */
35 static hcd_lock * handled_lock;
36 
37 /* Makes URB schedule enabled */
38 static int hcd_schedule_urb(hcd_urb *);
39 
40 /* Makes URB schedule disabled */
41 static void hcd_unschedule_urb(hcd_urb *);
42 
43 /* Scheduler task */
44 static void hcd_urb_scheduler_task(void *);
45 
46 /* Completion callback */
47 static void hcd_urb_handled(hcd_urb *);
48 
49 /* Stores URB to be handled */
50 static int hcd_store_urb(hcd_urb *);
51 
52 /* Removes stored URB */
53 static void hcd_remove_urb(hcd_urb *);
54 
55 /* Gets URB to be handled next (based on priority) */
56 static hcd_urb * hcd_get_urb(void);
57 
58 
59 /*===========================================================================*
60  *    usbd_init_scheduler                                                    *
61  *===========================================================================*/
62 int
63 usbd_init_scheduler(void)
64 {
65 	DEBUG_DUMP;
66 
67 	/* Reset everything */
68 	num_stored_urbs = 0;
69 	memset(stored_urb, 0, sizeof(stored_urb));
70 
71 	urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL,
72 					"scheduler");
73 	if (NULL == urb_thread)
74 		goto ERR1;
75 
76 	urb_lock = ddekit_sem_init(0);
77 	if (NULL == urb_lock)
78 		goto ERR2;
79 
80 	handled_lock = ddekit_sem_init(0);
81 	if (NULL == handled_lock)
82 		goto ERR3;
83 
84 	return EXIT_SUCCESS;
85 
86 	ERR3:
87 	ddekit_sem_deinit(urb_lock);
88 	ERR2:
89 	ddekit_thread_terminate(urb_thread);
90 	ERR1:
91 	return EXIT_FAILURE;
92 }
93 
94 
95 /*===========================================================================*
96  *    usbd_deinit_scheduler                                                  *
97  *===========================================================================*/
98 void
99 usbd_deinit_scheduler(void)
100 {
101 	DEBUG_DUMP;
102 
103 	ddekit_sem_deinit(handled_lock);
104 
105 	ddekit_sem_deinit(urb_lock);
106 
107 	ddekit_thread_terminate(urb_thread);
108 }
109 
110 
111 /*===========================================================================*
112  *    hcd_schedule_external_urb                                              *
113  *===========================================================================*/
114 int
115 hcd_schedule_external_urb(hcd_urb * urb)
116 {
117 	DEBUG_DUMP;
118 
119 	return hcd_schedule_urb(urb);
120 }
121 
122 
123 /*===========================================================================*
124  *    hcd_schedule_internal_urb                                              *
125  *===========================================================================*/
126 int
127 hcd_schedule_internal_urb(hcd_urb * urb)
128 {
129 	DEBUG_DUMP;
130 
131 	return hcd_schedule_urb(urb);
132 }
133 
134 
135 /*===========================================================================*
136  *    hcd_schedule_urb                                                       *
137  *===========================================================================*/
138 static int
139 hcd_schedule_urb(hcd_urb * urb)
140 {
141 	DEBUG_DUMP;
142 
143 	/* Tell URB what to call on completion */
144 	urb->handled = hcd_urb_handled;
145 
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;
150 	}
151 
152 	return EXIT_FAILURE;
153 }
154 
155 
156 /*===========================================================================*
157  *    hcd_unschedule_urb                                                     *
158  *===========================================================================*/
159 static void
160 hcd_unschedule_urb(hcd_urb * urb)
161 {
162 	DEBUG_DUMP;
163 
164 	hcd_remove_urb(urb);
165 }
166 
167 
168 /*===========================================================================*
169  *    hcd_urb_scheduler_task                                                 *
170  *===========================================================================*/
171 static void
172 hcd_urb_scheduler_task(void * UNUSED(arg))
173 {
174 	hcd_device_state * current_device;
175 	hcd_urb * current_urb;
176 
177 	DEBUG_DUMP;
178 
179 	for (;;) {
180 		/* Wait for scheduler to unlock on any URB submit */
181 		ddekit_sem_down(urb_lock);
182 
183 		/* Get URB */
184 		current_urb = hcd_get_urb();
185 
186 		/* Get URB's target device */
187 		current_device = current_urb->target_device;
188 
189 		/* Check for mismatch */
190 		USB_ASSERT(NULL != current_urb, "URB missing after URB unlock");
191 
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;
196 
197 			/* Start handling URB event */
198 			hcd_handle_event(current_device, HCD_EVENT_URB,
199 					HCD_UNUSED_VAL);
200 
201 			/* Wait for completion */
202 			ddekit_sem_down(handled_lock);
203 
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();
209 
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);
216 		}
217 	}
218 }
219 
220 
221 /*===========================================================================*
222  *    hcd_urb_handled                                                        *
223  *===========================================================================*/
224 static void
225 hcd_urb_handled(hcd_urb * urb)
226 {
227 	DEBUG_DUMP;
228 
229 	/* This URB will be scheduled no more */
230 	hcd_unschedule_urb(urb);
231 
232 	/* Handling completed */
233 	ddekit_sem_up(handled_lock);
234 }
235 
236 
237 /*===========================================================================*
238  *    hcd_store_urb                                                          *
239  *===========================================================================*/
240 static int
241 hcd_store_urb(hcd_urb * urb)
242 {
243 	int i;
244 
245 	DEBUG_DUMP;
246 
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;
252 		}
253 	}
254 
255 	USB_MSG("No more free URBs");
256 
257 	return EXIT_FAILURE;
258 }
259 
260 /*===========================================================================*
261  *    hcd_remove_urb                                                         *
262  *===========================================================================*/
263 static void
264 hcd_remove_urb(hcd_urb * urb)
265 {
266 	int i;
267 
268 	DEBUG_DUMP;
269 
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;
275 		}
276 	}
277 
278 	USB_ASSERT(0, "URB to be removed, was never stored");
279 }
280 
281 /*===========================================================================*
282  *    hcd_get_urb                                                            *
283  *===========================================================================*/
284 static hcd_urb *
285 hcd_get_urb(void)
286 {
287 	static int i = 0;
288 	int checked;
289 
290 	DEBUG_DUMP;
291 
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;
297 
298 		/* When found */
299 		if (NULL != stored_urb[i])
300 			return stored_urb[i];
301 	}
302 
303 	/* Nothing submitted yet */
304 	return NULL;
305 }
306