- Create another branch for networking fixes
[reactos.git] / drivers / usb / nt4compat / usbdriver / ehci.c
1 /**
2 * ehci.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23 #include "ehci.h"
24
25 //----------------------------------------------------------
26 // ehci routines
27 //#define DEMO
28
29 #define DEFAULT_ENDP( enDP ) \
30 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
31
32 #define dev_from_endp( enDP ) \
33 ( DEFAULT_ENDP( enDP )\
34 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
35 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
36
37 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
38
39 #define endp_num( enDP ) \
40 ( DEFAULT_ENDP( enDP )\
41 ? 0 \
42 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
43
44 #define endp_dir( enDP ) \
45 ( DEFAULT_ENDP( enDP )\
46 ? 0L\
47 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) ? 1 : 0 )
48
49 #define dev_set_state( pdEV, staTE ) \
50 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
51
52 #define endp_max_packet_size( enDP ) \
53 ( DEFAULT_ENDP( enDP )\
54 ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
55 ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
56 : 8 )\
57 : ( enDP->pusb_endp_desc->wMaxPacketSize & 0x7ff ) )
58
59 #define endp_mult_count( endp ) ( ( ( endp->pusb_endp_desc->wMaxPacketSize & 0x1800 ) >> 11 ) + 1 )
60
61 #if 0
62 /* WTF?! */
63 #define release_adapter( padapTER ) \
64 {\
65 ( ( padapTER ) ); \
66 }
67 #else
68 #define release_adapter( padapTER ) (void)(padapTER)
69 #endif
70
71 #define get_int_idx( _urb, _idx ) \
72 {\
73 UCHAR interVAL;\
74 interVAL = ( UCHAR )( ( _urb )->pipe >> 24 );\
75 for( _idx = 1; _idx < 9; _idx++ )\
76 {\
77 interVAL >>= 1;\
78 if( !interVAL )\
79 break;\
80 }\
81 _idx --;\
82 }
83
84 #define ehci_insert_urb_to_schedule( eHCI, pURB, rET ) \
85 {\
86 SYNC_PARAM sync_param;\
87 sync_param.ehci = eHCI;\
88 sync_param.context = ( pURB );\
89 sync_param.ret = FALSE;\
90 \
91 rET = KeSynchronizeExecution( eHCI->pdev_ext->ehci_int, ehci_sync_insert_urb_schedule, &sync_param );\
92 }
93
94 #define EHCI_ERROR_INT ( STS_FATAL | STS_ERR )
95 #define EHCI_QH_ERROR( qh_contENT ) ( ( qh_contENT )->cur_qtd.status & ( QTD_STS_HALT | QTD_STS_DBE | QTD_STS_BABBLE | QTD_STS_XACT | QTD_STS_MMF ) )
96 #define EHCI_QTD_ERROR( qtd_contENT ) ( ( qtd_contENT )->status & ( QTD_STS_HALT | QTD_STS_DBE | QTD_STS_BABBLE | QTD_STS_XACT | QTD_STS_MMF ) )
97
98 #define EHCI_READ_PORT_ULONG( pul ) ( *pul )
99 #define EHCI_WRITE_PORT_ULONG( pul, src ) \
100 {\
101 ULONG cmd_reg;\
102 *pul = ( ULONG )src;\
103 cmd_reg = EHCI_READ_PORT_ULONG( ehci->port_base + EHCI_USBCMD );\
104 if( cmd_reg == 0 )\
105 cmd_reg++;\
106 }
107
108 #define EHCI_READ_PORT_UCHAR( pch ) ( *pch )
109 #define EHCI_WRITE_PORT_UCHAR( pch, src ) ( *pch = ( UCHAR )src )
110
111 #define EHCI_READ_PORT_USHORT( psh ) ( *psh )
112 #define EHCI_WRITE_PORT_USHORT( psh, src ) ( *psh = ( USHORT )src )
113
114 #define press_doorbell( eHCI ) \
115 {\
116 ULONG tmp;\
117 tmp = EHCI_READ_PORT_ULONG( ( PULONG )( ( eHCI )->port_base + EHCI_USBCMD ) );\
118 tmp |= CMD_IAAD;\
119 EHCI_WRITE_PORT_ULONG( ( PULONG )( ( eHCI )->port_base + EHCI_USBCMD ), tmp );\
120 }
121 #define ehci_from_hcd( hCD ) ( struct_ptr( ( hCD ), EHCI_DEV, hcd_interf ) )
122
123 #define qh_from_list_entry( pentry ) ( ( PEHCI_QH )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, elem_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
124 #define qtd_from_list_entry( pentry ) ( ( PEHCI_QTD )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, elem_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
125 #define itd_from_list_entry( pentry ) ( ( PEHCI_ITD )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, elem_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
126 #define sitd_from_list_entry( pentry ) ( ( PEHCI_SITD )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, elem_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
127 #define fstn_from_list_entry( pentry ) ( ( PEHCI_FSTN )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, elem_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
128
129 #define qh_from_schedule( pentry ) ( ( PEHCI_QH )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, sched_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
130 #define itd_from_schedule( pentry ) ( ( PEHCI_ITD )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, sched_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
131 #define sitd_from_schedule( pentry ) ( ( PEHCI_SITD )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, sched_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
132 #define fstn_from_schedule( pentry ) ( ( PEHCI_FSTN )( ( ( ULONG )struct_ptr( pentry, EHCI_ELEM_LINKS, sched_link )->phys_part ) & PHYS_PART_ADDR_MASK ) )
133
134 #define elem_type( ptr, from_list ) ( from_list ? ( ( ( ( ULONG )struct_ptr( ptr, EHCI_ELEM_LINKS, elem_link)->phys_part ) & PHYS_PART_TYPE_MASK ) >> 1 ) \
135 : ( ( ( ( ULONG )struct_ptr( ptr, EHCI_ELEM_LINKS, sched_link)->phys_part ) & PHYS_PART_TYPE_MASK ) >> 1 ) )
136
137 // #define elem_type_list_entry( pentry ) ( ( qh_from_schedule( pentry )->hw_next & 0x06 ) >> 1 )
138 #define elem_type_list_entry( pentry ) ( elem_type( pentry, TRUE ) )
139
140 #define get_parent_hs_hub( pDEV, parent_HUB, port_IDX ) \
141 {\
142 parent_HUB = pDEV->parent_dev;\
143 port_IDX = pdev->port_idx;\
144 while( parent_HUB )\
145 {\
146 if( ( parent_HUB->flags & USB_DEV_CLASS_MASK ) != USB_DEV_CLASS_HUB )\
147 {\
148 parent_HUB = NULL;\
149 break;\
150 }\
151 if( ( parent_HUB->flags & USB_DEV_FLAG_HIGH_SPEED ) == 0 )\
152 {\
153 port_IDX = parent_HUB->port_idx;\
154 parent_HUB = parent_HUB->parent_dev;\
155 continue;\
156 }\
157 break;\
158 }\
159 }
160
161 #define init_elem_phys_part( pelnk ) RtlZeroMemory( ( PVOID )( ( ( ULONG )( pelnk )->phys_part ) & PHYS_PART_ADDR_MASK ), get_elem_phys_part_size( ( ( ( ULONG )( pelnk )->phys_part ) & 0x06 ) >> 1 ) )
162 #define REAL_INTERVAL ( 1 << pipe_content->interval )
163
164 #define elem_safe_free( ptHIS, single ) \
165 {\
166 UCHAR em_type; \
167 em_type = ( UCHAR )elem_type( ptHIS, TRUE ); \
168 if( ptHIS )\
169 {\
170 if( em_type == INIT_LIST_FLAG_QTD )\
171 {\
172 elem_pool_lock( qtd_pool, TRUE );\
173 if( single )\
174 elem_pool_free_elem( qtd_from_list_entry( ptHIS )->elem_head_link );\
175 else \
176 elem_pool_free_elems( qtd_from_list_entry( ptHIS )->elem_head_link );\
177 elem_pool_unlock( qtd_pool, TRUE );\
178 }\
179 else if( em_type == INIT_LIST_FLAG_ITD )\
180 {\
181 elem_pool_lock( itd_pool, TRUE );\
182 if( single )\
183 elem_pool_free_elem( itd_from_list_entry( ptHIS )->elem_head_link );\
184 else \
185 elem_pool_free_elems( itd_from_list_entry( ptHIS )->elem_head_link );\
186 elem_pool_unlock( itd_pool, TRUE );\
187 }\
188 else if( em_type == INIT_LIST_FLAG_SITD )\
189 {\
190 elem_pool_lock( sitd_pool, TRUE );\
191 if( single )\
192 elem_pool_free_elem( sitd_from_list_entry( ptHIS )->elem_head_link );\
193 else \
194 elem_pool_free_elems( sitd_from_list_entry( ptHIS )->elem_head_link );\
195 elem_pool_unlock( sitd_pool, TRUE );\
196 }\
197 else if( em_type == INIT_LIST_FLAG_FSTN )\
198 {\
199 elem_pool_lock( fstn_pool, TRUE );\
200 if( single )\
201 elem_pool_free_elem( fstn_from_list_entry( ptHIS )->elem_head_link );\
202 else \
203 elem_pool_free_elems( fstn_from_list_entry( ptHIS )->elem_head_link );\
204 elem_pool_unlock( fstn_pool, TRUE );\
205 }\
206 else if( em_type == INIT_LIST_FLAG_QH )\
207 {\
208 elem_pool_lock( qh_pool, TRUE );\
209 if( single )\
210 elem_pool_free_elem( qh_from_list_entry( ptHIS )->elem_head_link );\
211 else \
212 elem_pool_free_elems( qh_from_list_entry( ptHIS )->elem_head_link );\
213 elem_pool_unlock( qh_pool, TRUE );\
214 }\
215 }\
216 }
217
218 #ifndef min
219 #define min( a, b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
220 #endif
221 #ifndef max
222 #define max( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
223 #endif
224
225 #define CLR_RH2_PORTSTAT( port_idx, x ) \
226 {\
227 PULONG addr; \
228 addr = ( PULONG )( ehci->port_base + port_idx ); \
229 status = EHCI_READ_PORT_ULONG( addr ); \
230 status = ( status & 0xfffffd5 ) & ~( x ); \
231 EHCI_WRITE_PORT_ULONG( addr, ( ULONG )status ); \
232 }
233
234 #define SET_RH2_PORTSTAT( port_idx, x ) \
235 {\
236 PULONG addr; \
237 addr = ( PULONG )( ehci->port_base + port_idx ); \
238 status = EHCI_READ_PORT_ULONG( addr ); \
239 if( x & PORT_PR ) \
240 status = ( status & 0xffffffd1 ) | ( x ); \
241 else \
242 status = ( status & 0xffffffd5 ) | ( x ); \
243 EHCI_WRITE_PORT_ULONG( addr, ( ULONG )status ); \
244 }
245
246 #define ehci_from_hcd( hCD ) ( struct_ptr( ( hCD ), EHCI_DEV, hcd_interf ) )
247 #define ehci_from_dev( dEV ) ( ehci_from_hcd( dEV->hcd ) )
248
249 #define ehci_copy_overlay( pQHC, pTDC ) \
250 {\
251 LONG td_size;\
252 PEHCI_QH pqh1;\
253 PEHCI_QTD ptd1;\
254 pqh1 = ( PEHCI_QH )( pQHC );\
255 ptd1 = ( PEHCI_QTD )( pTDC );\
256 td_size = get_elem_phys_part_size( INIT_LIST_FLAG_QTD );\
257 ( pQHC )->cur_qtd_ptr = ptd1->phys_addr;\
258 RtlZeroMemory( &( pQHC )->cur_qtd, td_size );\
259 ( pQHC )->cur_qtd.data_toggle = ( pTDC )->data_toggle;\
260 pqh1->hw_qtd_next = ptd1->phys_addr;\
261 pqh1->hw_alt_next = EHCI_PTR_TERM;\
262 }
263
264 //declarations
265 typedef struct
266 {
267 union
268 {
269 PUHCI_DEV uhci;
270 PEHCI_DEV ehci;
271 };
272 PVOID context;
273 ULONG ret;
274
275 } SYNC_PARAM, *PSYNC_PARAM;
276
277 PDEVICE_OBJECT
278 ehci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
279
280 BOOLEAN ehci_init_schedule(PEHCI_DEV ehci, PADAPTER_OBJECT padapter);
281
282 BOOLEAN ehci_release(PDEVICE_OBJECT pdev);
283
284 static VOID ehci_stop(PEHCI_DEV ehci);
285
286 BOOLEAN ehci_destroy_schedule(PEHCI_DEV ehci);
287
288 BOOLEAN NTAPI ehci_sync_insert_urb_schedule(PVOID context);
289
290 VOID ehci_init_hcd_interface(PEHCI_DEV ehci);
291
292 NTSTATUS ehci_rh_submit_urb(PUSB_DEV rh, PURB purb);
293
294 NTSTATUS ehci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
295
296 VOID ehci_generic_urb_completion(PURB purb, PVOID context);
297
298 static NTSTATUS ehci_internal_submit_bulk(PEHCI_DEV ehci, PURB purb);
299
300 static NTSTATUS ehci_internal_submit_int(PEHCI_DEV ehci, PURB purb);
301
302 static NTSTATUS ehci_internal_submit_ctrl(PEHCI_DEV ehci, PURB purb);
303
304 static NTSTATUS ehci_internal_submit_iso(PEHCI_DEV ehci, PURB purb);
305
306 static ULONG ehci_scan_iso_error(PEHCI_DEV ehci, PURB purb);
307
308 BOOLEAN ehci_claim_bandwidth(PEHCI_DEV ehci, PURB purb, BOOLEAN claim_bw); //true to claim band-width, false to free band-width
309
310 static VOID ehci_insert_bulk_schedule(PEHCI_DEV ehci, PURB purb);
311
312 #define ehci_insert_control_schedule ehci_insert_bulk_schedule
313
314 static VOID ehci_insert_int_schedule(PEHCI_DEV ehci, PURB purb);
315
316 static VOID ehci_insert_iso_schedule(PEHCI_DEV ehci, PURB purb);
317
318 #define ehci_remove_control_from_schedule ehci_remove_bulk_from_schedule
319
320 PDEVICE_OBJECT ehci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr);
321
322 PDEVICE_OBJECT ehci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr);
323
324 BOOLEAN ehci_delete_device(PDEVICE_OBJECT pdev);
325
326 VOID ehci_get_capabilities(PEHCI_DEV ehci, PBYTE base);
327
328 BOOLEAN NTAPI ehci_isr(PKINTERRUPT interrupt, PVOID context);
329
330 BOOLEAN ehci_start(PHCD hcd);
331
332 extern VOID rh_timer_svc_reset_port_completion(PUSB_DEV dev, PVOID context);
333
334 extern VOID rh_timer_svc_int_completion(PUSB_DEV dev, PVOID context);
335
336 extern USB_DEV_MANAGER g_dev_mgr;
337
338 #ifndef INCLUDE_EHCI
339 ULONG debug_level = DBGLVL_MAXIMUM;
340 PDRIVER_OBJECT usb_driver_obj = NULL;
341
342 //pending endpoint pool funcs
343 VOID
344 ehci_wait_ms(PEHCI_DEV ehci, LONG ms)
345 {
346 LARGE_INTEGER lms;
347 if (ms <= 0)
348 return;
349
350 lms.QuadPart = -10 * ms;
351 KeSetTimer(&ehci->reset_timer, lms, NULL);
352
353 KeWaitForSingleObject(&ehci->reset_timer, Executive, KernelMode, FALSE, NULL);
354
355 return;
356 }
357
358 BOOLEAN
359 init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
360 {
361 int i;
362 if (pool == NULL)
363 return FALSE;
364
365 pool->pending_endp_array =
366 usb_alloc_mem(NonPagedPool, sizeof(UHCI_PENDING_ENDP) * UHCI_MAX_PENDING_ENDPS);
367 InitializeListHead(&pool->free_que);
368 pool->free_count = 0;
369 pool->total_count = UHCI_MAX_PENDING_ENDPS;
370 KeInitializeSpinLock(&pool->pool_lock);
371
372 for(i = 0; i < MAX_TIMER_SVCS; i++)
373 {
374 free_pending_endp(pool, &pool->pending_endp_array[i]);
375 }
376
377 return TRUE;
378
379 }
380
381 BOOLEAN
382 free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp)
383 {
384 if (pool == NULL || pending_endp == NULL)
385 {
386 return FALSE;
387 }
388
389 RtlZeroMemory(pending_endp, sizeof(UHCI_PENDING_ENDP));
390 InsertTailList(&pool->free_que, (PLIST_ENTRY) & pending_endp->endp_link);
391 pool->free_count++;
392
393 return TRUE;
394 }
395
396 PUHCI_PENDING_ENDP
397 alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count)
398 {
399 PUHCI_PENDING_ENDP new;
400 if (pool == NULL || count != 1)
401 return NULL;
402
403 if (pool->free_count <= 0)
404 return NULL;
405
406 new = (PUHCI_PENDING_ENDP) RemoveHeadList(&pool->free_que);
407 pool->free_count--;
408 return new;
409 }
410
411 BOOLEAN
412 destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
413 {
414 if (pool == NULL)
415 return FALSE;
416
417 InitializeListHead(&pool->free_que);
418 pool->free_count = pool->total_count = 0;
419 usb_free_mem(pool->pending_endp_array);
420 pool->pending_endp_array = NULL;
421
422 return TRUE;
423
424 }
425 #else
426 #define ehci_wait_ms uhci_wait_ms
427 extern VOID uhci_wait_ms(PEHCI_DEV ehci, LONG ms);
428
429 extern BOOLEAN init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool);
430
431 extern BOOLEAN free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp);
432
433 extern PUHCI_PENDING_ENDP alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count);
434
435 extern BOOLEAN destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool);
436
437 #endif
438
439 //end of pending endpoint pool funcs
440
441 static VOID NTAPI
442 ehci_cancel_pending_endp_urb(IN PVOID Parameter)
443 {
444 PLIST_ENTRY abort_list;
445 PUSB_DEV pdev;
446 PURB purb;
447 USE_BASIC_NON_PENDING_IRQL;
448
449 abort_list = (PLIST_ENTRY) Parameter;
450
451 if (abort_list == NULL)
452 return;
453
454 while (IsListEmpty(abort_list) == FALSE)
455 {
456 //these devs are protected by purb's ref-count
457 purb = (PURB) RemoveHeadList(abort_list);
458 pdev = purb->pdev;
459 // purb->status is set when they are added to abort_list
460
461 ehci_generic_urb_completion(purb, purb->context);
462
463 lock_dev(pdev, FALSE);
464 pdev->ref_count--;
465 unlock_dev(pdev, FALSE);
466 }
467 usb_free_mem(abort_list);
468 return;
469 }
470
471 static BOOLEAN
472 ehci_process_pending_endp(PEHCI_DEV ehci)
473 {
474 PUSB_DEV pdev;
475 LIST_ENTRY temp_list, abort_list;
476 PLIST_ENTRY pthis;
477 PURB purb;
478 PUSB_ENDPOINT pendp;
479 NTSTATUS can_submit = STATUS_SUCCESS;
480 PWORK_QUEUE_ITEM pwork_item;
481 PLIST_ENTRY cancel_list;
482 PUSB_DEV pparent = NULL;
483 UCHAR port_idx = 0;
484 BOOLEAN tt_needed;
485 UCHAR hub_addr = 0;
486 USE_BASIC_IRQL;
487
488 if (ehci == NULL)
489 return FALSE;
490
491 InitializeListHead(&temp_list);
492 InitializeListHead(&abort_list);
493
494 purb = NULL;
495 ehci_dbg_print(DBGLVL_MEDIUM, ("ehci_process_pending_endp(): entering..., ehci=0x%x\n", ehci));
496
497 lock_pending_endp_list(&ehci->pending_endp_list_lock);
498 while (IsListEmpty(&ehci->pending_endp_list) == FALSE)
499 {
500
501 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_process_pending_endp(): pending_endp_list=0x%x\n",
502 &ehci->pending_endp_list));
503
504 tt_needed = FALSE;
505 pthis = RemoveHeadList(&ehci->pending_endp_list);
506 pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
507 pdev = dev_from_endp(pendp);
508 lock_dev(pdev, TRUE);
509
510 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
511 {
512 unlock_dev(pdev, TRUE);
513 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
514 //delegate to ehci_remove_device for remiving the purb queue on the endpoint
515 continue;
516 }
517 if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
518 {
519 // prepare split transaction
520 unlock_dev(pdev, TRUE);
521
522 // pparent won't be removed when pending_endp_list_lock is acquired.
523 get_parent_hs_hub(pdev, pparent, port_idx);
524
525 if (pparent == NULL)
526 {
527 TRAP();
528 ehci_dbg_print(DBGLVL_MEDIUM,
529 ("ehci_process_pending_endp(): full/low speed device with no parent!!!\n"));
530 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
531 continue;
532 }
533
534 if (hub_lock_tt(pparent, port_idx, (UCHAR) endp_type(pendp)) == FALSE)
535 {
536 lock_dev(pdev, TRUE);
537 if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
538 {
539 // reinsert the pending-endp to the list
540 InsertTailList(&temp_list, pthis);
541 unlock_dev(pdev, TRUE);
542 }
543 else
544 {
545 // delegate to ehci_remove_device for purb removal
546 unlock_dev(pdev, TRUE);
547 free_pending_endp(&ehci->pending_endp_pool,
548 struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
549 }
550 continue;
551 }
552
553 // backup the hub address for future use
554 hub_addr = pparent->dev_addr;
555
556 lock_dev(pdev, TRUE);
557 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
558 {
559 unlock_dev(pdev, TRUE);
560 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
561 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
562 continue;
563 }
564 tt_needed = TRUE;
565 // go on processing
566 }
567
568 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
569 {
570 while (IsListEmpty(&pendp->urb_list) == FALSE)
571 {
572 purb = (PURB) RemoveHeadList(&pendp->urb_list);
573 purb->status = USB_STATUS_ENDPOINT_HALTED;
574 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
575 }
576 InitializeListHead(&pendp->urb_list);
577 unlock_dev(pdev, TRUE);
578 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
579 if (tt_needed)
580 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
581 continue;
582 }
583
584 if (IsListEmpty(&pendp->urb_list) == FALSE)
585 {
586 purb = (PURB) RemoveHeadList(&pendp->urb_list);
587 ASSERT(purb);
588 }
589 else
590 {
591 InitializeListHead(&pendp->urb_list);
592 unlock_dev(pdev, TRUE);
593 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
594 if (tt_needed)
595 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
596 continue;
597 }
598
599 if (tt_needed)
600 {
601 ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr = hub_addr;
602 ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx = port_idx;
603 }
604
605 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
606 switch (endp_type(pendp))
607 {
608 case USB_ENDPOINT_XFER_BULK:
609 {
610 can_submit = ehci_internal_submit_bulk(ehci, purb);
611 break;
612 }
613 case USB_ENDPOINT_XFER_CONTROL:
614 {
615 can_submit = ehci_internal_submit_ctrl(ehci, purb);
616 break;
617 }
618 case USB_ENDPOINT_XFER_INT:
619 {
620 can_submit = ehci_internal_submit_int(ehci, purb);
621 break;
622 }
623 case USB_ENDPOINT_XFER_ISOC:
624 {
625 can_submit = ehci_internal_submit_iso(ehci, purb);
626 break;
627 }
628 }
629
630 if (can_submit == STATUS_NO_MORE_ENTRIES)
631 {
632 //no enough bandwidth or tds
633 InsertHeadList(&pendp->urb_list, &purb->urb_link);
634 InsertTailList(&temp_list, pthis);
635 }
636 else
637 {
638 // otherwise error or success
639 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
640
641 if (can_submit != STATUS_SUCCESS)
642 {
643 //abort these URBs
644 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
645 purb->status = can_submit;
646 }
647 }
648 unlock_dev(pdev, TRUE);
649 if (can_submit != STATUS_SUCCESS && tt_needed)
650 {
651 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
652 }
653 }
654
655 if (IsListEmpty(&temp_list) == FALSE)
656 {
657 //re-append them to the pending_endp_list
658 ListFirst(&temp_list, pthis);
659 RemoveEntryList(&temp_list);
660 MergeList(&ehci->pending_endp_list, pthis);
661 }
662 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
663
664 if (IsListEmpty(&abort_list) == FALSE)
665 {
666 PLIST_ENTRY pthis;
667 cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
668 ASSERT(cancel_list);
669
670 ListFirst(&abort_list, pthis);
671 RemoveEntryList(&abort_list);
672 InsertTailList(pthis, cancel_list);
673
674 pwork_item = (PWORK_QUEUE_ITEM) & cancel_list[1];
675
676 // we do not need to worry the ehci_cancel_pending_endp_urb running when the
677 // driver is unloading since purb-reference count will prevent the dev_mgr to
678 // quit till all the reference count to the dev drop to zero.
679 ExInitializeWorkItem(pwork_item, ehci_cancel_pending_endp_urb, (PVOID) cancel_list);
680 ExQueueWorkItem(pwork_item, DelayedWorkQueue);
681 }
682 return TRUE;
683 }
684
685 NTSTATUS
686 ehci_submit_urb(PEHCI_DEV ehci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
687 {
688 int i;
689 PUHCI_PENDING_ENDP pending_endp;
690 NTSTATUS status;
691 USE_BASIC_IRQL;
692
693 if (ehci == NULL)
694 return STATUS_INVALID_PARAMETER;
695
696 if (pdev == NULL || pendp == NULL || purb == NULL)
697 {
698 // give a chance to those pending urb, especially for clearing hub tt
699 ehci_process_pending_endp(ehci);
700 return STATUS_INVALID_PARAMETER;
701 }
702
703 lock_pending_endp_list(&ehci->pending_endp_list_lock);
704 lock_dev(pdev, TRUE);
705
706 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
707 {
708 status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
709 goto LBL_OUT;
710 }
711
712 if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
713 {
714 unlock_dev(pdev, TRUE);
715 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
716 status = ehci_rh_submit_urb(pdev, purb);
717 return status;
718 }
719
720 if (pendp)
721 purb->pendp = pendp;
722 else
723 purb->pendp = &pdev->default_endp;
724
725 if (dev_from_endp(purb->pendp) != pdev)
726 {
727 status = purb->status = STATUS_INVALID_PARAMETER;
728 goto LBL_OUT;
729 }
730
731 if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
732 {
733 status = purb->status = USB_STATUS_ENDPOINT_HALTED;
734 goto LBL_OUT;
735 }
736
737 if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
738 {
739 // wait one ms
740 usb_wait_ms_dpc(1);
741 }
742
743 purb->pdev = pdev;
744 purb->rest_bytes = purb->data_length;
745
746 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
747 purb->bytes_to_transfer = (purb->data_length > EHCI_MAX_SIZE_TRANSFER ? EHCI_MAX_SIZE_TRANSFER : purb->data_length); //multiple transfer for large data block
748 else
749 purb->bytes_to_transfer = purb->data_length;
750
751 ehci_dbg_print(DBGLVL_MEDIUM, ("ehci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
752
753 purb->bytes_transfered = 0;
754 InitializeListHead(&purb->trasac_list);
755 purb->last_finished_td = &purb->trasac_list;
756 purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
757 purb->flags |= URB_FLAG_STATE_PENDING;
758
759
760 i = IsListEmpty(&pendp->urb_list);
761 InsertTailList(&pendp->urb_list, &purb->urb_link);
762
763 pdev->ref_count++; //for purb reference
764
765 if (i == FALSE)
766 {
767 //there is purb pending, simply queue it and return
768 status = purb->status = STATUS_PENDING;
769 goto LBL_OUT;
770 }
771 else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
772 {
773 //
774 //No purb waiting but purb overlap not allowed,
775 //so leave it in queue and return, will be scheduled
776 //later
777 //
778 status = purb->status = STATUS_PENDING;
779 goto LBL_OUT;
780 }
781
782 pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
783 if (pending_endp == NULL)
784 {
785 //panic
786 status = purb->status = STATUS_UNSUCCESSFUL;
787 goto LBL_OUT2;
788 }
789
790 pending_endp->pendp = purb->pendp;
791 InsertTailList(&ehci->pending_endp_list, &pending_endp->endp_link);
792
793 unlock_dev(pdev, TRUE);
794 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
795
796 ehci_process_pending_endp(ehci);
797 return STATUS_PENDING;
798
799 LBL_OUT2:
800 pdev->ref_count--;
801 RemoveEntryList(&purb->urb_link);
802
803 LBL_OUT:
804 unlock_dev(pdev, TRUE);
805 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
806 ehci_process_pending_endp(ehci);
807 return status;
808 }
809
810 static NTSTATUS
811 ehci_set_error_code(PURB purb, ULONG raw_status)
812 {
813 PURB_HS_PIPE_CONTENT pipe_content;
814
815 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
816
817 //test if the purb is canceled
818 if (purb->flags & URB_FLAG_FORCE_CANCEL)
819 {
820 purb->status = STATUS_CANCELLED;
821 }
822 else if (raw_status == 0)
823 purb->status = STATUS_SUCCESS;
824
825 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT ||
826 pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
827 pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL)
828 {
829
830 if (raw_status & QTD_STS_BABBLE)
831 purb->status = USB_STATUS_DATA_OVERRUN;
832
833 else if (raw_status & QTD_STS_HALT)
834 purb->status = USB_STATUS_ENDPOINT_HALTED;
835
836 else if (raw_status & QTD_STS_DBE)
837 purb->status = USB_STATUS_BUFFER_OVERRUN;
838
839 else if (raw_status & QTD_STS_XACT)
840 purb->status = USB_STATUS_CRC; // crc is included in xact err.
841
842 else if (raw_status & QTD_STS_MMF)
843 purb->status = USB_STATUS_BTSTUFF;
844
845 else
846 purb->status = STATUS_UNSUCCESSFUL;
847 }
848 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
849 {
850 if (pipe_content->speed_high)
851 {
852 if (raw_status & ITD_STS_BUFERR)
853 purb->status = USB_STATUS_BUFFER_OVERRUN;
854
855 else if (raw_status & ITD_STS_BABBLE)
856 purb->status = USB_STATUS_BABBLE_DETECTED;
857
858 else if (raw_status & ITD_STS_XACTERR) // Xact Err
859 purb->status = USB_STATUS_CRC;
860
861 else
862 purb->status = STATUS_UNSUCCESSFUL;
863
864 }
865 else
866 {
867 if (raw_status & SITD_STS_ERR) // ERR is received from hub's tt
868 purb->status = USB_STATUS_ERROR;
869
870 else if (raw_status & SITD_STS_DBE)
871 purb->status = USB_STATUS_BUFFER_OVERRUN;
872
873 else if (raw_status & SITD_STS_BABBLE)
874 purb->status = USB_STATUS_BABBLE_DETECTED;
875
876 else if (raw_status & SITD_STS_XACTERR) // Xact Error
877 purb->status = USB_STATUS_CRC;
878
879 else if (raw_status & SITD_STS_MISSFRM) // missing microframe
880 purb->status = USB_STATUS_DATA_TOGGLE_MISMATCH;
881
882 else
883 purb->status = STATUS_UNSUCCESSFUL;
884 }
885 }
886 if (purb->status != STATUS_SUCCESS)
887 {
888 hcd_dbg_print(DBGLVL_MEDIUM, ("ehci_set_error_code(): error status 0x%x\n", raw_status));
889 }
890 return purb->status;
891 }
892
893 static BOOLEAN NTAPI
894 ehci_sync_remove_urb_finished(PVOID context)
895 {
896 PEHCI_DEV ehci;
897 PLIST_ENTRY pthis, pnext, ptemp;
898 PURB purb;
899 PSYNC_PARAM pparam;
900
901 pparam = (PSYNC_PARAM) context;
902 ehci = pparam->ehci;
903 ptemp = (PLIST_ENTRY) pparam->context;
904
905 if (ehci == NULL)
906 {
907 return (UCHAR) (pparam->ret = FALSE);
908 }
909
910 ListFirst(&ehci->urb_list, pthis);
911 while (pthis)
912 {
913 //remove urbs not in the schedule
914 ListNext(&ehci->urb_list, pthis, pnext);
915 purb = (PURB) pthis;
916
917 if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
918 {
919 //finished or canceled( not applied for split bulk ).
920 RemoveEntryList(pthis);
921 InsertTailList(ptemp, pthis);
922 }
923 pthis = pnext;
924 }
925 pparam->ret = TRUE;
926 return (UCHAR) TRUE;
927 }
928
929 VOID NTAPI
930 ehci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
931 {
932 PEHCI_DEV ehci;
933
934 LIST_HEAD temp_list;
935 PLIST_ENTRY pthis, pnext;
936 PURB purb;
937 PEHCI_QH pqh;
938 PEHCI_QTD ptd;
939 PUHCI_PENDING_ENDP pending_endp;
940 PUSB_DEV pdev;
941 PUSB_ENDPOINT pendp;
942
943 BOOLEAN finished;
944 LONG i;
945 ULONG ehci_status, urb_status;
946
947 SYNC_PARAM sync_param;
948 UCHAR ep_type;
949 USE_BASIC_NON_PENDING_IRQL;
950
951 ehci = (PEHCI_DEV) context;
952 if (ehci == NULL)
953 return;
954
955 ehci_status = (ULONG) sysarg1;
956
957 InitializeListHead(&temp_list);
958
959 sync_param.ehci = ehci;
960 sync_param.context = (PVOID) & temp_list;
961
962 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_dpc_callback(): entering..., ehci=0x%x\n", ehci));
963 //remove finished purb from ehci's purb-list
964 KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_remove_urb_finished, &sync_param);
965
966 //release resources( itds, sitds, fstns, tds, and qhs ) allocated for the purb
967 while (IsListEmpty(&temp_list) == FALSE)
968 {
969 //not in any public queue, if do not access into dev, no race
970 //condition will occur
971 purb = (PURB) RemoveHeadList(&temp_list);
972 urb_status = purb->status;
973 ep_type = endp_type(purb->pendp);
974
975 if (ep_type == USB_ENDPOINT_XFER_ISOC)
976 {
977 // collect error for iso transfer
978 urb_status = ehci_scan_iso_error(ehci, purb);
979 }
980
981 //the only place we do not use this lock on non-pending-endp-list data
982 KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
983 while (IsListEmpty(&purb->trasac_list) == FALSE)
984 {
985 UCHAR em_type;
986 pthis = RemoveHeadList(&purb->trasac_list);
987 em_type = (UCHAR) elem_type(pthis, TRUE);
988
989 if (em_type == INIT_LIST_FLAG_QH)
990 {
991 pqh = qh_from_list_entry(pthis);
992 elem_safe_free(pthis, TRUE);
993 }
994 else
995 {
996 //must be an itd, sitd chain
997 InsertHeadList(&purb->trasac_list, pthis);
998 for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
999 {
1000 PEHCI_QTD_CONTENT ptdc = NULL;
1001 PEHCI_ITD_CONTENT pitdc;
1002 PEHCI_SITD_CONTENT psitdc;
1003
1004 em_type = (UCHAR) elem_type(pthis, TRUE);
1005
1006 // accumulate data transfered in tds
1007 if (em_type == INIT_LIST_FLAG_QTD)
1008 {
1009 ptd = qtd_from_list_entry(pthis);
1010 ptdc = (PEHCI_QTD_CONTENT) ptd;
1011 if ((ptdc->status & QTD_STS_ACTIVE) == 0 && ((ptdc->status & QTD_ANY_ERROR) == 0))
1012 purb->bytes_transfered += ptd->bytes_to_transfer;
1013 }
1014 else if (em_type == INIT_LIST_FLAG_ITD)
1015 {
1016 int j;
1017 pitdc = (PEHCI_ITD_CONTENT) itd_from_list_entry(pthis);
1018 for(j = 0; j < 8; j++)
1019 {
1020 if ((pitdc->status_slot[j].status & ITD_STS_ACTIVE) == 0
1021 && (pitdc->status_slot[j].status & ITD_ANY_ERROR) == 0)
1022 purb->bytes_transfered += ptdc->bytes_to_transfer;
1023 }
1024 }
1025 else if (em_type == INIT_LIST_FLAG_SITD)
1026 {
1027 psitdc = (PEHCI_SITD_CONTENT) sitd_from_list_entry(pthis);
1028 if ((psitdc->status & SITD_STS_ACTIVE) == 0 && (psitdc->status & SITD_ANY_ERROR) == 0)
1029 purb->bytes_transfered += ptdc->bytes_to_transfer;
1030 }
1031 ListNext(&purb->trasac_list, pthis, pnext);
1032 pthis = pnext;
1033 }
1034
1035 // check to see if an fstn is there
1036 ListFirstPrev(&purb->trasac_list, pthis);
1037 if (elem_type(pthis, TRUE) == INIT_LIST_FLAG_FSTN)
1038 {
1039 RemoveEntryList(pthis);
1040 elem_safe_free(pthis, TRUE);
1041 }
1042
1043 ListFirst(&purb->trasac_list, pthis);
1044 RemoveEntryList(&purb->trasac_list);
1045
1046 // free the tds
1047 elem_safe_free(pthis, FALSE);
1048
1049 //termination condition
1050 InitializeListHead(&purb->trasac_list);
1051 purb->last_finished_td = NULL;
1052 }
1053 }
1054
1055 if (ep_type == USB_ENDPOINT_XFER_ISOC || ep_type == USB_ENDPOINT_XFER_INT)
1056 ehci_claim_bandwidth(ehci, purb, FALSE); //release band-width
1057
1058 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1059
1060 ehci_set_error_code(purb, urb_status);
1061
1062 pdev = dev_from_endp(purb->pendp);
1063 pendp = purb->pendp;
1064
1065 // perform clear tt buffer if error on full/low bulk/control pipe
1066 if (ep_type == USB_ENDPOINT_XFER_BULK || ep_type == USB_ENDPOINT_XFER_CONTROL)
1067 {
1068 PURB_HS_PIPE_CONTENT pipe_content;
1069 PUSB_DEV phub;
1070 UCHAR port_idx;
1071
1072 get_parent_hs_hub(pdev, phub, port_idx);
1073 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
1074
1075 if (pipe_content->speed_high == 0 && purb->status != STATUS_SUCCESS)
1076 {
1077 // lets schedule an event to clear the tt buffer
1078 hub_post_clear_tt_event(phub, port_idx, purb->pipe);
1079 }
1080 else if (pipe_content->speed_high == 0)
1081 {
1082 if (phub == NULL)
1083 TRAP();
1084 else
1085 {
1086 // release tt if no error
1087 hub_unlock_tt(phub, (UCHAR) port_idx, (UCHAR) pipe_content->trans_type);
1088 }
1089 }
1090 }
1091
1092 finished = TRUE;
1093
1094 //since the ref_count for the purb is not released, we can safely have one
1095 //pointer to dev
1096
1097 if (purb->status == USB_STATUS_BABBLE_DETECTED)
1098 {
1099 usb_dbg_print(DBGLVL_MEDIUM,
1100 ("ehci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
1101 // ehci_start( ehci );
1102 }
1103
1104 if (ehci_status & STS_HALT) //&& !ehci->is_suspended
1105 {
1106 ehci_start(&ehci->hcd_interf);
1107 }
1108
1109 //this will let the new request in ehci_generic_urb_completion to this endp
1110 //be processed rather than queued in the pending_endp_list
1111 lock_dev(pdev, TRUE);
1112 usb_endp_busy_count_dec(pendp);
1113 unlock_dev(pdev, TRUE);
1114
1115 if (usb_success(purb->status) == FALSE)
1116 {
1117 // set error code and complete the purb and purb is invalid from this point
1118 ehci_generic_urb_completion(purb, purb->context);
1119 }
1120 else
1121 {
1122 if (ep_type == USB_ENDPOINT_XFER_BULK)
1123 {
1124 purb->rest_bytes -= purb->bytes_transfered;
1125 if (purb->rest_bytes)
1126 {
1127 finished = FALSE;
1128 }
1129 else
1130 {
1131 ehci_generic_urb_completion(purb, purb->context);
1132 }
1133 }
1134 else
1135 {
1136 ehci_generic_urb_completion(purb, purb->context);
1137 // DbgBreakPoint();
1138 //purb is now invalid
1139 }
1140 }
1141
1142 KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
1143 lock_dev(pdev, TRUE);
1144
1145 if (finished)
1146 pdev->ref_count--;
1147
1148 if (urb_status && ((ep_type == USB_ENDPOINT_XFER_BULK) || (ep_type == USB_ENDPOINT_XFER_INT)))
1149 {
1150 // error on int or bulk pipe, cleared in usb_reset_pipe_completion
1151 pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
1152 pendp->flags |= USB_ENDP_FLAG_STALL;
1153 }
1154
1155 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1156 {
1157 unlock_dev(pdev, TRUE);
1158 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1159 if (finished == FALSE)
1160 {
1161
1162 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1163 ehci_generic_urb_completion(purb, purb->context);
1164
1165 lock_dev(pdev, TRUE);
1166 pdev->ref_count--;
1167 unlock_dev(pdev, TRUE);
1168 }
1169 continue;
1170 }
1171
1172 if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
1173 {
1174 unlock_dev(pdev, TRUE);
1175 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1176 continue;
1177 }
1178 else if (finished == TRUE)
1179 {
1180 //has purb in the endp's purb-list
1181 if (usb_endp_busy_count(pendp) > 0)
1182 {
1183 //the urbs still have chance to be sheduled but not this time
1184 unlock_dev(pdev, TRUE);
1185 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1186 continue;
1187 }
1188 }
1189
1190 if (finished == FALSE)
1191 {
1192 //a split bulk transfer, ( not the high speed split transfer )
1193 purb->bytes_transfered = 0;
1194 purb->bytes_to_transfer =
1195 EHCI_MAX_SIZE_TRANSFER > purb->rest_bytes ? purb->rest_bytes : EHCI_MAX_SIZE_TRANSFER;
1196
1197 //the purb is not finished
1198 purb->flags &= ~URB_FLAG_STATE_MASK;
1199 purb->flags |= URB_FLAG_STATE_PENDING;
1200
1201 InsertHeadList(&pendp->urb_list, &purb->urb_link);
1202 }
1203
1204 pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
1205 if (!pending_endp)
1206 {
1207 unlock_dev(pdev, TRUE);
1208 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1209 return;
1210 }
1211 pending_endp->pendp = pendp;
1212 InsertTailList(&ehci->pending_endp_list, &pending_endp->endp_link);
1213
1214 unlock_dev(pdev, TRUE);
1215 KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
1216 }
1217
1218 //ah...exhausted, let's find some in the pending_endp_list to rock
1219 ehci_process_pending_endp(ehci);
1220 return;
1221 }
1222
1223 static BOOLEAN NTAPI
1224 ehci_sync_cancel_urbs_dev(PVOID context)
1225 {
1226 //cancel all the urbs on one dev
1227 PEHCI_DEV ehci;
1228 PUSB_DEV pdev, dest_dev;
1229 PSYNC_PARAM sync_param;
1230 PLIST_ENTRY pthis, pnext;
1231 LONG count;
1232
1233 sync_param = (PSYNC_PARAM) context;
1234 dest_dev = (PUSB_DEV) sync_param->context;
1235 ehci = sync_param->ehci;
1236
1237 if (ehci == NULL || dest_dev == NULL)
1238 {
1239 return (UCHAR) (sync_param->ret = FALSE);
1240 }
1241 count = 0;
1242 ListFirst(&ehci->urb_list, pthis);
1243 while (pthis)
1244 {
1245 pdev = dev_from_endp(((PURB) pthis)->pendp);
1246 if (pdev == dest_dev)
1247 {
1248 ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
1249 }
1250 ListNext(&ehci->urb_list, pthis, pnext);
1251 pthis = pnext;
1252 count++;
1253 }
1254
1255 if (count)
1256 {
1257 // signal an int for further process
1258 press_doorbell(ehci);
1259 }
1260 return (UCHAR) (sync_param->ret = TRUE);
1261 }
1262
1263 BOOLEAN
1264 ehci_remove_device(PEHCI_DEV ehci, PUSB_DEV dev)
1265 {
1266 PUHCI_PENDING_ENDP ppending_endp;
1267 PLIST_ENTRY pthis, pnext;
1268 PURB purb;
1269 LIST_HEAD temp_list;
1270 int i, j, k;
1271 SYNC_PARAM sync_param;
1272
1273 USE_BASIC_IRQL;
1274
1275 if (ehci == NULL || dev == NULL)
1276 return FALSE;
1277
1278 InitializeListHead(&temp_list);
1279
1280 //free pending endp that has purb queued from pending endp list
1281 lock_pending_endp_list(&ehci->pending_endp_list_lock);
1282
1283 ListFirst(&ehci->pending_endp_list, pthis);
1284
1285 while (pthis)
1286 {
1287 ppending_endp = (PUHCI_PENDING_ENDP) pthis;
1288 ListNext(&ehci->pending_endp_list, pthis, pnext);
1289 if (dev_from_endp(ppending_endp->pendp) == dev)
1290 {
1291 RemoveEntryList(pthis);
1292 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
1293 }
1294 pthis = pnext;
1295 }
1296 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
1297
1298 //cancel all the urbs in the purb-list
1299 sync_param.ehci = ehci;
1300 sync_param.context = (PVOID) dev;
1301
1302 KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_cancel_urbs_dev, &sync_param);
1303
1304 //cancel all the purb in the endp's purb-list
1305 k = 0;
1306 lock_dev(dev, FALSE);
1307 if (dev->usb_config)
1308 {
1309 //only for configed dev
1310 for(i = 0; i < dev->usb_config->if_count; i++)
1311 {
1312 for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
1313 {
1314 ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
1315 while (pthis)
1316 {
1317 ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);
1318
1319 RemoveEntryList(pthis);
1320 InsertHeadList(&temp_list, pthis);
1321 pthis = pnext;
1322 k++;
1323 }
1324
1325 }
1326 }
1327 }
1328 ListFirst(&dev->default_endp.urb_list, pthis);
1329
1330 while (pthis)
1331 {
1332 ListNext(&dev->default_endp.urb_list, pthis, pnext);
1333
1334 RemoveEntryList(pthis);
1335 InsertHeadList(&temp_list, pthis);
1336 pthis = pnext;
1337 k++;
1338 }
1339 unlock_dev(dev, FALSE);
1340
1341 if (IsListEmpty(&temp_list) == FALSE)
1342 {
1343 for(i = 0; i < k; i++)
1344 {
1345 //complete those urbs with error
1346 pthis = RemoveHeadList(&temp_list);
1347 purb = (PURB) pthis;
1348 purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1349 {
1350 ehci_generic_urb_completion(purb, purb->context);
1351 }
1352 }
1353 }
1354
1355 lock_dev(dev, FALSE) dev->ref_count -= k;
1356 unlock_dev(dev, FALSE);
1357
1358 return TRUE;
1359 }
1360
1361 static BOOLEAN
1362 ehci_insert_urb_schedule(PEHCI_DEV ehci, PURB purb)
1363 // must have dev_lock( ehci_process_pending_endp ) and frame_list_lock acquired
1364 {
1365 PURB_HS_PIPE_CONTENT pipe_content;
1366
1367 if (ehci == NULL || purb == NULL)
1368 return FALSE;
1369
1370 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
1371 switch (pipe_content->trans_type)
1372 {
1373 case USB_ENDPOINT_XFER_CONTROL:
1374 ehci_insert_control_schedule(ehci, purb);
1375 break;
1376 case USB_ENDPOINT_XFER_BULK:
1377 ehci_insert_bulk_schedule(ehci, purb);
1378 break;
1379 case USB_ENDPOINT_XFER_INT:
1380 ehci_insert_int_schedule(ehci, purb);
1381 break;
1382 case USB_ENDPOINT_XFER_ISOC:
1383 ehci_insert_iso_schedule(ehci, purb);
1384 break;
1385 default:
1386 return FALSE;
1387 }
1388
1389 purb->flags &= ~URB_FLAG_STATE_MASK;
1390 purb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
1391 InsertTailList(&ehci->urb_list, &purb->urb_link);
1392
1393 return TRUE;
1394 }
1395
1396 static BOOLEAN
1397 ehci_insert_tds_qh(PEHCI_DEV ehci, PEHCI_QH pqh, PEHCI_QTD td_chain)
1398 {
1399 if (pqh == NULL || td_chain == NULL)
1400 return FALSE;
1401
1402 UNREFERENCED_PARAMETER(ehci);
1403
1404 ehci_copy_overlay((PEHCI_QH_CONTENT) pqh, (PEHCI_QTD_CONTENT) td_chain);
1405 InsertTailList(&td_chain->elem_head_link->elem_link, &pqh->elem_head_link->elem_link);
1406 return TRUE;
1407 }
1408
1409 static BOOLEAN
1410 ehci_insert_qh_urb(PURB purb, PEHCI_QH pqh)
1411 {
1412 PLIST_ENTRY pthis, pnext;
1413 if (pqh == NULL || purb == NULL)
1414 return FALSE;
1415
1416 InsertTailList(&pqh->elem_head_link->elem_link, &purb->trasac_list);
1417 ListFirst(&purb->trasac_list, pthis) while (pthis)
1418 {
1419 // note: fstn may in this chain
1420 struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->purb = purb;
1421 ListNext(&purb->trasac_list, pthis, pnext);
1422 pthis = pnext;
1423 }
1424 return TRUE;
1425 }
1426
1427 #define calc_td_count( pURB, start_aDDR, td_coUNT ) \
1428 {\
1429 LONG i, j, k;\
1430 td_coUNT = 0;\
1431 k = ( ( pURB )->bytes_to_transfer + max_packet_size - 1 ) / max_packet_size;\
1432 if( k != 0 )\
1433 {\
1434 LONG packets_per_td, packets_per_page;\
1435 packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;\
1436 packets_per_page = PAGE_SIZE / max_packet_size;\
1437 i = ( ( LONG )&( pURB )->data_buffer[ ( start_aDDR ) ] ) & ( PAGE_SIZE - 1 );\
1438 if( i )\
1439 {\
1440 i = PAGE_SIZE - i;\
1441 j = i & ( max_packet_size - 1 );\
1442 k -= ( EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j ) / max_packet_size;\
1443 if( k < 0 )\
1444 td_coUNT = 1;\
1445 else\
1446 {\
1447 if( j )\
1448 i = packets_per_td - packets_per_page;\
1449 else\
1450 i = packets_per_td;\
1451 td_coUNT = 1 + ( k + i - 1 ) / i; \
1452 }\
1453 }\
1454 else\
1455 {\
1456 td_coUNT = ( k + packets_per_td - 1 ) / packets_per_td;\
1457 }\
1458 }\
1459 }
1460
1461 static BOOLEAN
1462 ehci_fill_td_buf_ptr(PURB purb, LONG start_addr, // start idx into purb->data_buffer
1463 PLIST_ENTRY td_list, LONG td_count, ULONG toggle)
1464 // fill the tds' bytes_to_transfer and hw_buf, return next toggle value: true 1, false 0
1465 {
1466 LONG i, j, k, data_load;
1467 LONG packets_per_td, packets_per_page, bytes_to_transfer, max_packet_size;
1468 PLIST_ENTRY pthis, pnext;
1469 PEHCI_QTD_CONTENT ptdc;
1470 PEHCI_QTD ptd;
1471 PVOID ptr;
1472
1473 if (purb == NULL || td_list == NULL || td_count == 0)
1474 return toggle;
1475
1476 max_packet_size = 1 << ((PURB_HS_PIPE_CONTENT) & purb->pipe)->max_packet_size;
1477 packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;
1478 packets_per_page = PAGE_SIZE / max_packet_size;
1479
1480 pthis = td_list;
1481 bytes_to_transfer = purb->bytes_to_transfer;
1482
1483 i = ((LONG) & (purb)->data_buffer[(start_addr)]) & (PAGE_SIZE - 1);
1484 if (i)
1485 {
1486 i = PAGE_SIZE - i;
1487 j = i & (max_packet_size - 1);
1488 }
1489 else
1490 {
1491 i = j = 0;
1492 }
1493
1494 while (bytes_to_transfer)
1495 {
1496 ptd = qtd_from_list_entry(pthis);
1497 ptd->hw_buf[0] = MmGetPhysicalAddress(&purb->data_buffer[start_addr]).LowPart;
1498 ptdc = (PEHCI_QTD_CONTENT) ptd;
1499
1500 if (i != 0)
1501 {
1502 data_load = (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) < bytes_to_transfer
1503 ? (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) : bytes_to_transfer;
1504
1505 ptdc->bytes_to_transfer = (USHORT) data_load;
1506 ptd->bytes_to_transfer = (USHORT) data_load;
1507
1508 // subtract the header part
1509 data_load -= (i < data_load ? i : data_load);
1510
1511 for(k = 1; data_load > 0; k++)
1512 {
1513 ptr = &purb->data_buffer[start_addr + i + (k - 1) * PAGE_SIZE];
1514 ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
1515 ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
1516 data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
1517 }
1518 }
1519 else
1520 {
1521 // aligned on page boundary
1522 data_load = EHCI_QTD_MAX_TRANS_SIZE < bytes_to_transfer
1523 ? EHCI_QTD_MAX_TRANS_SIZE : bytes_to_transfer;
1524
1525 ptdc->bytes_to_transfer = (USHORT) data_load;
1526 ptd->bytes_to_transfer = (USHORT) data_load;
1527
1528 data_load -= (PAGE_SIZE < data_load ? PAGE_SIZE : data_load);
1529
1530 for(k = 1; data_load > 0; k++)
1531 {
1532 ptr = &purb->data_buffer[start_addr + k * PAGE_SIZE];
1533 ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
1534 ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
1535 data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
1536 }
1537 }
1538 ptdc->data_toggle = toggle;
1539 if (((ptdc->bytes_to_transfer + max_packet_size - 1) / max_packet_size) & 1)
1540 {
1541 //only odd num of transactions has effect
1542 toggle ^= 1;
1543 }
1544 start_addr += ptdc->bytes_to_transfer;
1545 bytes_to_transfer -= ptdc->bytes_to_transfer;
1546 ListNext(td_list, pthis, pnext);
1547 pthis = pnext;
1548 i = j;
1549 }
1550 return toggle;
1551 }
1552
1553 static NTSTATUS
1554 ehci_internal_submit_bulk(PEHCI_DEV ehci, PURB purb)
1555 //
1556 // assume that the purb has its rest_bytes and bytes_to_transfer set
1557 // and bytes_transfered is zeroed.
1558 // dev_lock must be acquired outside
1559 // purb comes from dev's endpoint purb-list. it is already removed from
1560 // the endpoint purb-list.
1561 //
1562 {
1563
1564 LONG max_packet_size, td_count, offset, bytes_to_transfer;
1565 PBYTE start_addr;
1566 PEHCI_QTD ptd;
1567 PEHCI_QH pqh;
1568 LIST_ENTRY td_list, *pthis, *pnext;
1569 BOOLEAN old_toggle, toggle, ret;
1570 UCHAR pid;
1571 LONG i, j;
1572 PURB_HS_PIPE_CONTENT pipe_content;
1573 PEHCI_QTD_CONTENT ptdc;
1574 PEHCI_QH_CONTENT pqhc;
1575 PEHCI_ELEM_LINKS pelnk;
1576 PEHCI_ELEM_LINKS plnk;
1577
1578 if (ehci == NULL || purb == NULL)
1579 return STATUS_INVALID_PARAMETER;
1580
1581 max_packet_size = endp_max_packet_size(purb->pendp);
1582 if (purb->bytes_to_transfer == 0)
1583 {
1584 return STATUS_INVALID_PARAMETER;
1585 }
1586
1587 start_addr = &purb->data_buffer[purb->data_length - purb->rest_bytes];
1588 calc_td_count(purb, purb->data_length - purb->rest_bytes, td_count);
1589
1590 elem_pool_lock(qtd_pool, TRUE);
1591 pelnk = elem_pool_alloc_elems(qtd_pool, td_count);
1592 elem_pool_unlock(qtd_pool, TRUE);
1593
1594 if (pelnk == NULL)
1595 {
1596 return STATUS_UNSUCCESSFUL;
1597 }
1598 ptd = (PEHCI_QTD) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
1599
1600 InitializeListHead(&td_list);
1601 InsertTailList(&ptd->elem_head_link->elem_link, &td_list);
1602
1603 ListFirst(&td_list, pthis);
1604 ListNext(&td_list, pthis, pnext);
1605
1606 offset = 0;
1607
1608 old_toggle = toggle = (purb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
1609 bytes_to_transfer = purb->bytes_to_transfer;
1610 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_internal_submit_bulk():dev toggle=%d\n", toggle));
1611
1612 for(i = 1; i < 16; i++)
1613 {
1614 if ((max_packet_size >> i) == 0)
1615 break;
1616 }
1617 i--;
1618 i &= 0xf;
1619
1620 purb->pipe = 0;
1621 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
1622 pipe_content->max_packet_size = i;
1623 pipe_content->endp_addr = endp_num(purb->pendp);
1624 pipe_content->dev_addr = dev_from_endp(purb->pendp)->dev_addr;
1625 pipe_content->trans_dir = endp_dir(purb->pendp);
1626 pipe_content->trans_type = USB_ENDPOINT_XFER_BULK;
1627 pipe_content->data_toggle = toggle;
1628 pipe_content->speed_high = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0;
1629 pipe_content->speed_low = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;
1630
1631 pid = (((ULONG) purb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? QTD_PID_IN : QTD_PID_OUT);
1632
1633 i = ((ULONG) start_addr) & (PAGE_SIZE - 1); // header part within first page
1634 if (i)
1635 {
1636 i = PAGE_SIZE - i;
1637 if (i < purb->bytes_to_transfer)
1638 j = i & (max_packet_size - 1);
1639 else
1640 j = 0;
1641 }
1642 else
1643 j = 0;
1644
1645 // fill the page pointer and toggle
1646
1647 toggle = ehci_fill_td_buf_ptr(purb, purb->data_length - purb->rest_bytes, pthis, td_count, toggle);
1648 while (pthis)
1649 {
1650 ptd = qtd_from_list_entry(pthis);
1651 ptdc = (PEHCI_QTD_CONTENT) ptd;
1652
1653 // ptdc->alt_terminal = 1;
1654 // ptdc->alt_qtd = 0;
1655 ptd->hw_alt_next = EHCI_PTR_TERM;
1656 ptdc->pid = pid;
1657
1658 // ptd->elem_head_link->purb = purb; will be filled later
1659 ptdc->err_count = 3;
1660 ptdc->status = 0x80; // active, and do_start_split for split transfer
1661 ptdc->cur_page = 0;
1662 // ptdc->data_toggle = toggle;
1663
1664 if (pnext)
1665 {
1666 ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
1667 }
1668 else
1669 {
1670 //Last one, enable ioc and short packet detect if necessary
1671 ptd->hw_next = EHCI_PTR_TERM;
1672 ptdc->ioc = TRUE;
1673 if (bytes_to_transfer < max_packet_size && (pid == QTD_PID_IN))
1674 {
1675 //ptd->status |= TD_CTRL_SPD;
1676 }
1677 }
1678
1679 pthis = pnext;
1680
1681 if (pthis)
1682 ListNext(&td_list, pthis, pnext);
1683 }
1684
1685 ListFirst(&td_list, pthis);
1686 RemoveEntryList(&td_list);
1687
1688 elem_pool_lock(qh_pool, TRUE);
1689
1690 plnk = elem_pool_alloc_elem(qh_pool);
1691 if (plnk == NULL)
1692 {
1693 // free the qtds
1694 elem_safe_free(pthis, TRUE);
1695 if (qh_pool) elem_pool_unlock(qh_pool, TRUE);
1696 return STATUS_UNSUCCESSFUL;
1697 }
1698
1699 pqh = (PEHCI_QH) ((ULONG) plnk->phys_part & PHYS_PART_ADDR_MASK);
1700 elem_pool_unlock(qh_pool, TRUE);
1701
1702 if (pqh == NULL)
1703 {
1704 // free the qtds
1705 elem_safe_free(pthis, TRUE);
1706 return STATUS_NO_MORE_ENTRIES;
1707
1708 }
1709
1710 purb->td_count = td_count;
1711 pqhc = (PEHCI_QH_CONTENT) pqh;
1712 pqh->hw_next = EHCI_PTR_TERM; // filled later
1713 pqhc->dev_addr = pipe_content->dev_addr;
1714 pqhc->inactive = 0;
1715 pqhc->endp_addr = pipe_content->endp_addr;
1716 pqhc->data_toggle = 0; //pipe_content->data_toggle;
1717 pqhc->is_async_head = 0;
1718 pqhc->max_packet_size = (1 << pipe_content->max_packet_size);
1719 pqhc->is_ctrl_endp = 0;
1720 pqhc->reload_counter = EHCI_NAK_RL_COUNT;
1721
1722 if (pipe_content->speed_high)
1723 pqhc->endp_spd = USB_SPEED_HIGH;
1724 else if (pipe_content->speed_low)
1725 pqhc->endp_spd = USB_SPEED_LOW;
1726 else
1727 pqhc->endp_spd = USB_SPEED_FULL;
1728
1729 pqh->hw_info2 = 0;
1730 pqhc->mult = 1;
1731 pqh->hw_current = 0;
1732 pqh->hw_qtd_next = 0; // filled later
1733 pqh->hw_alt_next = EHCI_PTR_TERM;
1734 pqh->hw_token = 0; //indicate to advance queue before execution
1735
1736 if (!pipe_content->speed_high)
1737 {
1738 pqhc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
1739 pqhc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
1740 }
1741
1742 ptd = qtd_from_list_entry(pthis);
1743 ehci_insert_tds_qh(ehci, pqh, ptd);
1744 ehci_insert_qh_urb(purb, pqh);
1745 purb->pendp->flags =
1746 (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
1747 usb_endp_busy_count_inc(purb->pendp);
1748 ehci_insert_urb_to_schedule(ehci, purb, ret);
1749
1750 if (ret == FALSE)
1751 {
1752 // undo all we have done
1753 ListFirst(&pqh->elem_head_link->elem_link, pthis);
1754
1755 RemoveEntryList(&purb->trasac_list);
1756 RemoveEntryList(&pqh->elem_head_link->elem_link); //remove qh from td_chain
1757
1758 elem_safe_free(pthis, FALSE);
1759 elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);
1760
1761 InitializeListHead(&purb->trasac_list);
1762 // usb_endp_busy_count_dec( purb->pendp ); // the decrement is done in the dpc callback
1763 purb->pendp->flags =
1764 (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
1765 return STATUS_UNSUCCESSFUL;
1766 }
1767 return STATUS_SUCCESS;
1768 }
1769
1770 static NTSTATUS
1771 ehci_internal_submit_ctrl(PEHCI_DEV ehci, PURB purb)
1772 {
1773
1774 LIST_ENTRY td_list, *pthis, *pnext;
1775 LONG i, td_count;
1776 LONG toggle;
1777 LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;
1778
1779 PEHCI_QTD ptd;
1780 PEHCI_QH pqh;
1781 PEHCI_QH_CONTENT pqhc;
1782 UCHAR dev_addr;
1783 BOOLEAN ret;
1784 PURB_HS_PIPE_CONTENT pipe_content;
1785 PEHCI_QTD_CONTENT ptdc;
1786 PEHCI_ELEM_LINKS pelnk;
1787 PUSB_DEV pdev;
1788
1789 if (ehci == NULL || purb == NULL)
1790 return STATUS_INVALID_PARAMETER;
1791
1792 bytes_rest = purb->rest_bytes;
1793 bytes_to_transfer = purb->bytes_to_transfer;
1794 max_packet_size = endp_max_packet_size(purb->pendp);
1795 start_idx = purb->data_length - purb->rest_bytes;
1796
1797 calc_td_count(purb, start_idx, td_count);
1798 td_count += 2; // add setup td and handshake td
1799
1800 elem_pool_lock(qtd_pool, TRUE);
1801 pelnk = elem_pool_alloc_elems(qtd_pool, td_count);
1802 elem_pool_unlock(qtd_pool, TRUE);
1803
1804 if (pelnk == NULL)
1805 {
1806 return STATUS_NO_MORE_ENTRIES;
1807 }
1808
1809 InsertTailList(&pelnk->elem_link, &td_list);
1810 ListFirst(&td_list, pthis);
1811 ListNext(&td_list, pthis, pnext);
1812
1813 ptd = qtd_from_list_entry(pthis);
1814
1815 pdev = dev_from_endp(purb->pendp);
1816 dev_addr = pdev->dev_addr;
1817
1818 if (dev_state(pdev) <= USB_DEV_STATE_RESET) //only valid for control transfer
1819 dev_addr = 0;
1820
1821 usb_dbg_print(DBGLVL_MAXIMUM, ("ehci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr));
1822
1823 // fill the setup packet
1824 ptdc = (PEHCI_QTD_CONTENT) ptd;
1825 ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
1826 ptd->hw_alt_next = EHCI_PTR_TERM;
1827 ptdc->status = 0x80; // active
1828 ptdc->pid = QTD_PID_SETUP;
1829 ptdc->err_count = 3;
1830 ptdc->cur_page = 0;
1831 ptdc->ioc = 0;
1832 ptdc->bytes_to_transfer = sizeof(USB_CTRL_SETUP_PACKET);
1833 ptdc->data_toggle = 0;
1834 ptd->hw_buf[0] = MmGetPhysicalAddress(purb->setup_packet).LowPart;
1835
1836 for(i = 1; i < 16; i++)
1837 {
1838 if ((max_packet_size >> i) == 0)
1839 break;
1840 }
1841 i--;
1842 i &= 0xf;
1843
1844 purb->pipe = 0;
1845 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
1846 pipe_content->max_packet_size = i;
1847 pipe_content->endp_addr = endp_num(purb->pendp);
1848 pipe_content->dev_addr = dev_addr;
1849 pipe_content->speed_low = (pdev->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;
1850 pipe_content->speed_high = (pdev->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0;
1851 pipe_content->trans_type = USB_ENDPOINT_XFER_CONTROL;
1852
1853 pthis = pnext;
1854 ListNext(&td_list, pthis, pnext);
1855
1856 // all the tds's toggle and data_buffer pointer is filled here
1857 toggle = 1;
1858 ehci_fill_td_buf_ptr(purb, start_idx, pthis, td_count - 2, toggle);
1859
1860 for(i = 0; ((i < td_count - 2) && pthis); i++)
1861 {
1862 //construct tds for DATA packets of data stage.
1863 ptd = qtd_from_list_entry(pthis);
1864 ptdc = (PEHCI_QTD_CONTENT) ptd;
1865 ptd->hw_alt_next = EHCI_PTR_TERM;
1866 ptdc->status = 0x80; // active and startXSplit
1867 ptdc->pid = ((purb->setup_packet[0] & USB_DIR_IN) ? QTD_PID_IN : QTD_PID_OUT);
1868 ptdc->err_count = 3;
1869 ptdc->cur_page = 0;
1870 ptdc->ioc = 0;
1871
1872 if (pnext)
1873 ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
1874 else
1875 ptd->hw_next = EHCI_PTR_TERM;
1876
1877 pthis = pnext;
1878 if (pthis)
1879 ListNext(&td_list, pthis, pnext);
1880 }
1881
1882 if (pthis)
1883 ptd->hw_next = qtd_from_list_entry(pthis)->phys_addr;
1884 else
1885 TRAP();
1886
1887 // ListFirstPrev( &td_list, pthis );
1888 ptd = qtd_from_list_entry(pthis);
1889
1890 //the last is an IN transaction
1891 ptdc = (PEHCI_QTD_CONTENT) ptd;
1892 ptd->hw_alt_next = EHCI_PTR_TERM;
1893 ptdc->status = 0x80;
1894 ptdc->pid = ((td_count > 2)
1895 ? ((purb->setup_packet[0] & USB_DIR_IN) ? QTD_PID_OUT : QTD_PID_IN) : QTD_PID_IN);
1896
1897 ptdc->err_count = 3;
1898 ptdc->cur_page = 0;
1899 ptdc->ioc = 1;
1900 ptdc->bytes_to_transfer = 0;
1901 ptdc->data_toggle = 1;
1902 ptd->hw_next = EHCI_PTR_TERM;
1903
1904 ListFirst(&td_list, pthis);
1905 RemoveEntryList(&td_list);
1906
1907 ptd = qtd_from_list_entry(pthis);
1908 elem_pool_lock(qh_pool, TRUE);
1909 pelnk = elem_pool_alloc_elem(qh_pool);
1910 elem_pool_unlock(qh_pool, TRUE);
1911
1912 if (pelnk == NULL)
1913 {
1914 elem_safe_free(pthis, FALSE);
1915 return STATUS_NO_MORE_ENTRIES;
1916
1917 }
1918 pqh = (PEHCI_QH) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
1919 pqhc = (PEHCI_QH_CONTENT) pqh;
1920
1921 pqh->hw_alt_next = pqh->hw_next = EHCI_PTR_TERM;
1922
1923 pqhc->dev_addr = dev_addr;
1924 pqhc->inactive = 0;
1925 pqhc->endp_addr = endp_num(purb->pendp);
1926
1927 if (pipe_content->speed_high)
1928 pqhc->endp_spd = USB_SPEED_HIGH;
1929 else if (pipe_content->speed_low)
1930 pqhc->endp_spd = USB_SPEED_LOW;
1931 else
1932 pqhc->endp_spd = USB_SPEED_FULL;
1933
1934 pqhc->data_toggle = 1; // use dt from qtd
1935 pqhc->is_async_head = 0;
1936 pqhc->max_packet_size = endp_max_packet_size(purb->pendp);
1937
1938 if (pipe_content->speed_high == 0)
1939 pqhc->is_ctrl_endp = 1;
1940 else
1941 pqhc->is_ctrl_endp = 0;
1942
1943 pqhc->reload_counter = EHCI_NAK_RL_COUNT;
1944
1945 // DWORD 2
1946 pqh->hw_info2 = 0;
1947 pqhc->mult = 1;
1948
1949 if (!pipe_content->speed_high)
1950 {
1951 pqhc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
1952 pqhc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
1953 }
1954
1955 purb->td_count = td_count;
1956
1957 ehci_insert_tds_qh(ehci, pqh, ptd);
1958 ehci_insert_qh_urb(purb, pqh);
1959
1960 usb_endp_busy_count_inc(purb->pendp);
1961 ehci_insert_urb_to_schedule(ehci, purb, ret);
1962
1963 if (ret == FALSE)
1964 {
1965 RemoveEntryList(&purb->trasac_list);
1966 RemoveEntryList(&pqh->elem_head_link->elem_link);
1967
1968 elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);
1969 elem_safe_free(pthis, FALSE);
1970
1971 InitializeListHead(&purb->trasac_list);
1972 // usb_endp_busy_count_dec( purb->pendp );
1973 return STATUS_UNSUCCESSFUL;
1974 }
1975 return STATUS_SUCCESS;
1976 }
1977
1978 static NTSTATUS
1979 ehci_internal_submit_int(PEHCI_DEV ehci, PURB purb)
1980 {
1981 LONG i, max_packet_size;
1982 PEHCI_QTD ptd;
1983 BOOLEAN ret;
1984 PUSB_DEV pdev;
1985 PURB_HS_PIPE_CONTENT pipe_content;
1986 UCHAR mult_trans, toggle, old_toggle;
1987 PEHCI_ELEM_LINKS pelnk;
1988 PEHCI_QTD_CONTENT ptdc;
1989 PEHCI_QH pqh;
1990 PEHCI_QH_CONTENT pqhc;
1991 PEHCI_FSTN pfstn;
1992
1993 if (ehci == NULL || purb == NULL)
1994 return STATUS_INVALID_PARAMETER;
1995
1996 old_toggle = toggle = (purb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
1997 max_packet_size = endp_max_packet_size(purb->pendp);
1998 pdev = dev_from_endp(purb->pendp);
1999
2000 if (max_packet_size == 0 || max_packet_size > 64)
2001 return STATUS_INVALID_PARAMETER;
2002
2003 if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
2004 {
2005 if (max_packet_size < purb->data_length)
2006 return STATUS_INVALID_PARAMETER;
2007
2008 for(i = 1; i < 16; i++)
2009 {
2010 if ((((ULONG) purb->pendp->pusb_endp_desc->bInterval) >> i) == 0)
2011 break;
2012 }
2013 i--;
2014 mult_trans = 1;
2015 }
2016 else
2017 {
2018 mult_trans = endp_mult_count(purb->pendp);
2019 if (max_packet_size * endp_mult_count(purb->pendp) < purb->data_length)
2020 return STATUS_INVALID_PARAMETER;
2021 i = purb->pendp->pusb_endp_desc->bInterval - 1;
2022 }
2023
2024 purb->pipe = 0;
2025 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
2026 pipe_content->interval = i;
2027 pipe_content->trans_type = USB_ENDPOINT_XFER_INT; // bit 0-1
2028 pipe_content->speed_high = (pdev->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0; // bit 5
2029 pipe_content->speed_low = (pdev->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0; // bit 6
2030 pipe_content->trans_dir = endp_dir(purb->pendp); // bit 7
2031 pipe_content->dev_addr = pdev->dev_addr; // bit 8-14
2032 pipe_content->endp_addr = endp_num(purb->pendp); // bit 15-18
2033 pipe_content->data_toggle = 1; // bit 19
2034 pipe_content->mult_count = mult_trans;
2035
2036 // pipe_content->start_uframe : 3; // bit 28-30 will be filled later
2037
2038 for(i = 1; i <= 16; i++)
2039 {
2040 if (((ULONG) max_packet_size) >> i)
2041 continue;
2042 else
2043 break;
2044 }
2045 i--;
2046 i &= 0xf;
2047
2048 pipe_content->max_packet_size = i; // bit 20-23 log2( max_packet_size )
2049
2050 if (ehci_claim_bandwidth(ehci, purb, TRUE) == FALSE)
2051 {
2052 // can not allocate bandwidth for it
2053 return STATUS_UNSUCCESSFUL;
2054 }
2055
2056 // one qtd is enough
2057 elem_pool_lock(qtd_pool, TRUE);
2058 pelnk = elem_pool_alloc_elem(qtd_pool);
2059 elem_pool_unlock(qtd_pool, TRUE);
2060
2061 if (pelnk == NULL)
2062 {
2063 ehci_claim_bandwidth(ehci, purb, FALSE);
2064 return STATUS_NO_MORE_ENTRIES;
2065 }
2066
2067 ptd = (PEHCI_QTD) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
2068 ptdc = (PEHCI_QTD_CONTENT) ptd;
2069 ptd->hw_next = EHCI_PTR_TERM;
2070 // DWORD 1
2071 ptd->hw_alt_next = EHCI_PTR_TERM;
2072 // DWORD 2
2073 ptdc->status = 0x80;
2074 ptdc->pid = pipe_content->trans_dir ? QTD_PID_IN : QTD_PID_OUT;
2075 ptdc->err_count = 3;
2076 ptdc->cur_page = 0;
2077 ptdc->ioc = 1;
2078 ptdc->bytes_to_transfer = purb->data_length;
2079 toggle = (UCHAR) ehci_fill_td_buf_ptr(purb, 0, &pelnk->elem_link, 1, toggle);
2080
2081 elem_pool_lock(qh_pool, TRUE);
2082 pelnk = elem_pool_alloc_elem(qh_pool);
2083 elem_pool_unlock(qh_pool, TRUE);
2084 if (pelnk == NULL)
2085 {
2086 elem_safe_free(&ptd->elem_head_link->elem_link, TRUE);
2087 InitializeListHead(&purb->trasac_list);
2088 ehci_claim_bandwidth(ehci, purb, FALSE);
2089 return STATUS_NO_MORE_ENTRIES;
2090 }
2091 pqh = (PEHCI_QH) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
2092 pqhc = (PEHCI_QH_CONTENT) pqh;
2093
2094 pqh->hw_next = EHCI_PTR_TERM;
2095 pqhc->dev_addr = pdev->dev_addr;
2096 pqhc->inactive = 0;
2097 pqhc->endp_addr = endp_num(purb->pendp);
2098
2099 if (pipe_content->speed_high)
2100 pqhc->endp_spd = USB_SPEED_HIGH;
2101 else if (pipe_content->speed_low)
2102 pqhc->endp_spd = USB_SPEED_LOW;
2103 else
2104 pqhc->endp_spd = USB_SPEED_FULL;
2105
2106 pqhc->data_toggle = 0;
2107 pqhc->is_async_head = 0;
2108 pqhc->max_packet_size = endp_max_packet_size(purb->pendp);
2109 pqhc->is_ctrl_endp = 0;
2110 pqhc->reload_counter = 0;
2111
2112 // DWORD 2
2113 pqh->hw_info2 = 0;
2114 pqhc->mult = mult_trans;
2115
2116 if (pipe_content->speed_high)
2117 {
2118 if (pipe_content->interval == 0) // one poll per uframe
2119 pqhc->s_mask = 0xff;
2120 else if (pipe_content->interval == 1) // one poll every 2 uframe
2121 pqhc->s_mask = pipe_content->start_uframe == 0 ? 0x55 : 0xbb;
2122 else if (pipe_content->interval == 2)
2123 {
2124 pqhc->s_mask = 0x11;
2125 pqhc->s_mask <<= pipe_content->start_uframe;
2126 }
2127 else
2128 {
2129 pqhc->s_mask = 1 << (pipe_content->start_uframe);
2130 }
2131 pqhc->c_mask = 0;
2132 }
2133 else // full/low speed
2134 {
2135 pqhc->s_mask = 1 << pipe_content->start_uframe;
2136 if (pipe_content->start_uframe < 4)
2137 {
2138 pqhc->c_mask = 0x07 << (pipe_content->start_uframe + 2);
2139 }
2140 else if (pipe_content->start_uframe == 4)
2141 {
2142 pqhc->c_mask = 0xc1;
2143 }
2144 else if (pipe_content->start_uframe >= 5)
2145 {
2146 // we need fstn
2147 pqhc->c_mask = 0x03;
2148 if (pipe_content->start_uframe == 5)
2149 {
2150 pqhc->c_mask |= 0x80;
2151 }
2152 }
2153 if (pipe_content->start_uframe >= 4)
2154 {
2155 // chain an fstn
2156 elem_pool_lock(fstn_pool, TRUE);
2157 pelnk = elem_pool_alloc_elem(fstn_pool);
2158 elem_pool_unlock(fstn_pool, TRUE);
2159 if (pelnk == NULL)
2160 {
2161 elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);
2162 elem_safe_free(&ptd->elem_head_link->elem_link, TRUE);
2163 InitializeListHead(&purb->trasac_list);
2164 ehci_claim_bandwidth(ehci, purb, FALSE);
2165 return STATUS_NO_MORE_ENTRIES;
2166 }
2167 pfstn = (PEHCI_FSTN) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
2168 pfstn->hw_prev = ptd->phys_addr;
2169 pfstn->elem_head_link->purb = purb;
2170 InsertTailList(&ptd->elem_head_link->elem_link, &pfstn->elem_head_link->elem_link);
2171 }
2172 pqhc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
2173 pqhc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
2174 }
2175
2176 // DWORD 3
2177 purb->td_count = 1;
2178
2179 InitializeListHead(&purb->trasac_list);
2180 ehci_insert_tds_qh(ehci, pqh, ptd);
2181 ehci_insert_qh_urb(purb, pqh);
2182
2183 purb->pendp->flags = (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle << 31);
2184 usb_endp_busy_count_inc(purb->pendp);
2185
2186 ehci_insert_urb_to_schedule(ehci, purb, ret);
2187
2188 if (ret == FALSE)
2189 {
2190 RemoveEntryList(&purb->trasac_list);
2191 RemoveEntryList(&pqh->elem_head_link->elem_link);
2192
2193 elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);
2194 // an fstn may follow the td
2195 elem_safe_free(&ptd->elem_head_link->elem_link, FALSE);
2196
2197 InitializeListHead(&purb->trasac_list);
2198 ehci_claim_bandwidth(ehci, purb, FALSE);
2199
2200 purb->pendp->flags = (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | ((toggle ^ 1) << 31);
2201 // usb_endp_busy_count_dec( purb->pendp );
2202
2203 return STATUS_UNSUCCESSFUL;
2204 }
2205
2206 return STATUS_SUCCESS;
2207 }
2208
2209
2210 static NTSTATUS
2211 ehci_internal_submit_iso(PEHCI_DEV ehci, PURB purb)
2212 {
2213 LONG i, j, td_count, temp;
2214 PEHCI_ITD pitd;
2215 PEHCI_SITD psitd;
2216 PEHCI_SITD_CONTENT psitdc;
2217 PEHCI_ITD_CONTENT pitdc;
2218 LIST_ENTRY td_list, *pthis, *pnext, *pprev;
2219 BOOLEAN ret;
2220 PURB_HS_PIPE_CONTENT pipe_content;
2221 PUSB_DEV pdev;
2222 PEHCI_ELEM_LINKS pelnk;
2223
2224 if (ehci == NULL || purb == NULL)
2225 return STATUS_INVALID_PARAMETER;
2226
2227 if (purb->iso_frame_count == 0)
2228 return STATUS_INVALID_PARAMETER;
2229
2230 pdev = dev_from_endp(purb->pendp);
2231 purb->pipe = 0;
2232 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
2233 pipe_content->trans_type = USB_ENDPOINT_XFER_ISOC; // bit 0-1
2234 pipe_content->speed_high = (pdev->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0; // bit 5
2235 pipe_content->speed_low = 0; // bit 6
2236 pipe_content->trans_dir = endp_dir(purb->pendp); // bit 7
2237 pipe_content->dev_addr = pdev->dev_addr; // bit 8-14
2238 pipe_content->endp_addr = endp_num(purb->pendp); // bit 15-18
2239 pipe_content->data_toggle = 0; // bit 19
2240
2241 ret = FALSE;
2242 purb->params[0] = j = endp_max_packet_size(purb->pendp);
2243
2244 if (pipe_content->speed_high == 0)
2245 {
2246 // check to see if the frame data is too long to transfer
2247 if (purb->iso_frame_count >= (LONG) ehci->frame_count)
2248 return STATUS_INVALID_PARAMETER;
2249
2250 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
2251 {
2252 if (purb->iso_packet_desc[i].length > j)
2253 return STATUS_INVALID_PARAMETER;
2254 }
2255 }
2256 else
2257 {
2258 // excess the frame count limit
2259 if (purb->iso_frame_count >= (LONG) (ehci->frame_count << 3))
2260 return STATUS_INVALID_PARAMETER;
2261
2262 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
2263 {
2264 if (purb->iso_packet_desc[i].length > j * endp_mult_count(purb->pendp)) // 3 is max mult-transaction count
2265 return STATUS_INVALID_PARAMETER;
2266 }
2267
2268 pipe_content->mult_count = endp_mult_count(purb->pendp);
2269 }
2270
2271 pipe_content->max_packet_size = 0; // bit 20-23 log( max_packet_size ), not correct, should not be used
2272
2273 if (pipe_content->speed_high == 0)
2274 {
2275 for(i = 1; i < 16; i++)
2276 {
2277 if ((((ULONG) purb->pendp->pusb_endp_desc->bInterval) >> i) == 0)
2278 break;
2279 }
2280 i--;
2281 }
2282 else
2283 {
2284 i = purb->pendp->pusb_endp_desc->bInterval - 1;
2285 }
2286
2287 pipe_content->interval = i; // bit 24-27 the same definition as in USB2.0 spec, for high or full/low speed
2288
2289 if (ehci_claim_bandwidth(ehci, purb, TRUE) == FALSE)
2290 return STATUS_UNSUCCESSFUL;
2291
2292 if (pipe_content->speed_high == 0)
2293 {
2294 td_count = purb->iso_frame_count;
2295
2296 // test to see if the last td needs one more sitd for pure complete-split
2297 if (pipe_content->trans_dir == 0)
2298 {
2299 j = (purb->iso_packet_desc[purb->iso_frame_count - 1].length + 187) / 188;
2300 if (purb->iso_packet_desc[purb->iso_frame_count - 1].params.start_uframe + 1 + j >= 8)
2301 {
2302 td_count++;
2303 ret = TRUE;
2304 }
2305 }
2306 elem_pool_lock(itd_pool, TRUE);
2307 pelnk = elem_pool_alloc_elems(itd_pool, td_count);
2308 elem_pool_unlock(itd_pool, TRUE);
2309
2310 }
2311 else
2312 {
2313 i = REAL_INTERVAL;
2314 if (pipe_content->interval >= 3)
2315 {
2316 td_count = purb->iso_frame_count;
2317 j = 0;
2318 }
2319 else
2320 {
2321 j = purb->iso_start_frame & 0x07;
2322 if (j == 0)
2323 {
2324 td_count = (purb->iso_frame_count + 8 / i - 1) * i / 8;
2325 }
2326 else
2327 {
2328 j = 1 + (7 - j) / i; // the leading packets from the 8-trans boundary
2329 td_count = (j >= (LONG) purb->iso_frame_count ?
2330 1 : 1 + (purb->iso_frame_count - j + 8 / i - 1) * i / 8);
2331 }
2332 }
2333
2334 elem_pool_lock(sitd_pool, TRUE);
2335 pelnk = elem_pool_alloc_elems(sitd_pool, td_count);
2336 elem_pool_unlock(sitd_pool, TRUE);
2337 }
2338
2339 if (pelnk == NULL)
2340 {
2341 ehci_claim_bandwidth(ehci, purb, FALSE);
2342 return STATUS_NO_MORE_ENTRIES;
2343 }
2344
2345 InsertTailList(&pelnk->elem_link, &td_list);
2346 ListFirst(&td_list, pthis);
2347 pprev = pthis;
2348 purb->td_count = td_count;
2349
2350 //set up offset for high speed and interval == 1
2351 if (pipe_content->speed_high && pipe_content->interval == 0)
2352 {
2353 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
2354 {
2355 if (i == 0)
2356 purb->iso_packet_desc[i].offset = 0;
2357 else
2358 purb->iso_packet_desc[i].offset = purb->iso_packet_desc[i - 1].offset +
2359 purb->iso_packet_desc[i].length;
2360 }
2361 }
2362
2363 i = 0, temp = 0;
2364
2365 while (pthis)
2366 {
2367 init_elem_phys_part(struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link));
2368 if (pipe_content->speed_high)
2369 {
2370 LONG start_uframe, k;
2371 LONG l, pk_idx, offset, start_uf, td_length;
2372 PULONG pbuf;
2373 ULONG phys_addr[8];
2374
2375 pitd = itd_from_list_entry(pthis);
2376 pitdc = (PEHCI_ITD_CONTENT) pitd;
2377 start_uframe = purb->iso_start_frame & 0x07;
2378
2379 // will be filled later
2380 pitd->hw_next = EHCI_PTR_TERM;
2381
2382 // DWORD 9;
2383 pitdc->dev_addr = pdev->dev_addr;
2384 pitdc->endp_num = endp_num(purb->pendp);
2385
2386 pitdc->max_packet_size = endp_max_packet_size(purb->pendp);
2387 pitdc->io_dir = pipe_content->trans_dir;
2388 pitdc->mult = endp_mult_count(purb->pendp);
2389
2390 pbuf = pitd->hw_bufp;
2391 RtlZeroMemory(phys_addr, sizeof(phys_addr));
2392
2393 if (pipe_content->interval < 3)
2394 {
2395 // this indicates one itd schedules more than one uframes
2396 // for multiple transactions described by iso_packet_desc
2397 if (i == 0)
2398 k = td_count == 1 ? purb->iso_frame_count : j; // the first itd
2399 else
2400 k = (LONG) (purb->iso_frame_count - i) <= 8 / REAL_INTERVAL
2401 ? (purb->iso_frame_count - i) : 8 / REAL_INTERVAL;
2402
2403 // j is the header transactions out of the interval
2404 // aligned transactions per td
2405 if (j > 0 && i == 0) // handle the first itd
2406 start_uf = start_uframe;
2407 else
2408 start_uf = start_uframe % REAL_INTERVAL;
2409 }
2410 else
2411 {
2412 k = 1, start_uf = start_uframe & 0x07;
2413 }
2414
2415
2416 // calculate the data to transfer with this td
2417 td_length = 0;
2418 for(l = start_uf, pk_idx = i; pk_idx < i + k; pk_idx++, l += REAL_INTERVAL)
2419 {
2420 td_length += purb->iso_packet_desc[pk_idx].length;
2421 phys_addr[l] =
2422 MmGetPhysicalAddress(&purb->data_buffer[purb->iso_packet_desc[pk_idx].offset]).LowPart;
2423 }
2424
2425 // fill the page pointer, and offset
2426 if (pipe_content->interval != 0)
2427 {
2428 for(l = start_uf, pk_idx = i; pk_idx < i + k; pk_idx++, l += REAL_INTERVAL)
2429 {
2430 pitdc->status_slot[l].offset = phys_addr[l] & (PAGE_SIZE - 1);
2431 pbuf[l >> pipe_content->interval] |= phys_addr[l] & (~(PAGE_SIZE - 1));
2432 pitdc->status_slot[l].page_sel = l >> pipe_content->interval;
2433 pitdc->status_slot[l].status = 0x08;
2434 pitdc->status_slot[l].trans_length = purb->iso_packet_desc[pk_idx].length;
2435 if (PAGE_SIZE - pitdc->status_slot[l].offset <
2436 (ULONG) purb->iso_packet_desc[pk_idx].length)
2437 {
2438 // fill the next page buf, we can not simply add
2439 // PAGE_SIZE to the phys_addr[ l ].
2440 pbuf[(l >> pipe_content->interval) + 1] |=
2441 MmGetPhysicalAddress((PBYTE)
2442 (((ULONG) & purb->
2443 data_buffer[purb->iso_packet_desc[pk_idx].
2444 offset]) & (~(PAGE_SIZE - 1))) +
2445 PAGE_SIZE).LowPart;
2446 }
2447 }
2448 }
2449 else // interval == 0
2450 {
2451 LONG m, n = 0, n2 = 0;
2452 // fill the page buffer first
2453 // calculate the page buffer needed
2454 offset = phys_addr[0] & (PAGE_SIZE - 1);
2455 if (offset != 0)
2456 {
2457 offset = PAGE_SIZE - offset;
2458 l = 1 + (td_length - offset + PAGE_SIZE - 1) / PAGE_SIZE;
2459 }
2460 else
2461 {
2462 l = (td_length + PAGE_SIZE - 1) / PAGE_SIZE;
2463 }
2464
2465 if (l > 7)
2466 TRAP();
2467
2468 // fill the hw_bufp array and PG field, pk_idx is index into hw_bufp
2469 for(pk_idx = 0; pk_idx < l; pk_idx++)
2470 {
2471 if (pk_idx == 0)
2472 {
2473 offset = phys_addr[start_uf] & (~(PAGE_SIZE - 1));
2474 pbuf[pk_idx] |= offset;
2475 n = pk_idx;
2476 pitdc->status_slot[0].page_sel = n;
2477 n2 = start_uf;
2478 }
2479 else
2480 {
2481 // scan to find if the buf pointer already filled in the td
2482 // since interval = 1, we do not need k * REAL_INTERVAL
2483 // k is transaction count for current td,
2484 // n is hw_bufp( pbuf ) index
2485 // n2 is the last phys_addr index we stopped
2486 for(m = n2; m < start_uf + k; m++)
2487 {
2488 // we can not determine the phys_addr[ x ] is piror
2489 // to offset if it is less than offset.
2490 // because phys_addr is discrete.
2491 // if( ( phys_addr[ m ] & ( ~( PAGE_SIZE - 1 ) ) ) < offset )
2492 // continue;
2493
2494 if ((phys_addr[m] & (~(PAGE_SIZE - 1))) == (ULONG) offset)
2495 {
2496 pitdc->status_slot[m].page_sel = n;
2497 continue;
2498 }
2499 break;
2500 }
2501
2502 if (m == start_uf + k)
2503 TRAP();
2504
2505 offset = phys_addr[m] & (~(PAGE_SIZE - 1));
2506 pbuf[pk_idx] |= offset;
2507 n = pk_idx;
2508 n2 = m;
2509 pitdc->status_slot[m].page_sel = n;
2510 }
2511 }
2512 // fill offset and others
2513 for(l = start_uf, pk_idx = i; l < start_uf + k; l++, pk_idx++)
2514 {
2515 pitdc->status_slot[l].offset = (phys_addr[l] & (PAGE_SIZE - 1));
2516 pitdc->status_slot[l].status = 0x08;
2517 pitdc->status_slot[l].trans_length = purb->iso_packet_desc[pk_idx].length;
2518 }
2519 // exhausted
2520 }
2521 i += k;
2522 }
2523 else // full/low speed
2524 {
2525 psitd = sitd_from_list_entry(pthis);
2526 psitdc = (PEHCI_SITD_CONTENT) psitd;
2527 psitd->hw_next = EHCI_PTR_TERM;
2528
2529 // DWORD 1;
2530 psitdc->dev_addr = pdev->dev_addr;
2531 psitdc->endp_num = endp_num(purb->pendp);
2532 psitdc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
2533 psitdc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
2534 psitdc->io_dir = endp_dir(purb->pendp);
2535
2536 psitdc->status &= 0x80; // in DWORD 3
2537
2538 // DWORD 2;
2539 j = (purb->iso_packet_desc[i].length + 187) / 188;
2540
2541 if (psitdc->io_dir == 0)
2542 {
2543 for(; j > 0; j--)
2544 {
2545 psitdc->s_mask |= (1 << (j - 1));
2546 }
2547 psitdc->s_mask <<= purb->iso_packet_desc[i].params.start_uframe & 0x07;
2548 psitdc->c_mask = 0;
2549 }
2550 else
2551 {
2552 LONG k;
2553
2554 psitdc->s_mask = 1 << purb->iso_packet_desc[i].params.start_uframe & 0x07;
2555 // iso split case 2b: ehci spec 1.0
2556 if (j == 6)
2557 j = 5;
2558
2559 j = j - 1 + 2; // actual complete-split count
2560
2561 psitdc->c_mask |= temp >> 8; // the previous sitd's complete split
2562 if (temp >> 8) // link back for sitd split completion
2563 {
2564 psitd->hw_backpointer = sitd_from_list_entry(pprev)->phys_addr;
2565 psitdc->status &= 0x82;
2566 }
2567 else
2568 {
2569 psitd->hw_backpointer = EHCI_PTR_TERM;
2570 }
2571
2572 for(k = temp = 0; k < j; k++)
2573 {
2574 temp |= 1 << k;
2575 }
2576
2577 temp <<= ((purb->iso_packet_desc[i].params.start_uframe & 0x07) + 2);
2578
2579 // only uframe zero and one have complete split for prev sitd
2580 if ((temp >> 8) > 3)
2581 TRAP();
2582
2583 psitdc->c_mask |= temp & 0xff;
2584 }
2585
2586 // DWORD 3:
2587 psitdc->c_prog_mask = 0;
2588 psitdc->bytes_to_transfer = purb->iso_packet_desc[i].length;
2589 psitdc->page_sel = 0;
2590 psitdc->ioc = 0;
2591
2592 // DWORD 4;
2593 j = (ULONG) ((PBYTE) purb->data_buffer + purb->iso_packet_desc[i].offset);
2594 psitd->hw_tx_results2 = MmGetPhysicalAddress((PVOID) j).LowPart;
2595
2596 // DWORD 5;
2597 if (PAGE_SIZE - (j & (PAGE_SIZE - 1)) < (ULONG) purb->iso_packet_desc[i].length)
2598 {
2599 // need to fill another slot
2600 psitdc->page1 =
2601 MmGetPhysicalAddress((PVOID) ((j & ~(PAGE_SIZE - 1)) + PAGE_SIZE)).LowPart >> 12;
2602 }
2603
2604 if (purb->iso_packet_desc[i].length > 188)
2605 psitdc->trans_pos = 0x00;
2606 else if (purb->iso_packet_desc[i].length <= 188)
2607 psitdc->trans_pos = 0x01;
2608
2609 if (psitdc->io_dir == 0)
2610 psitdc->trans_count = (purb->iso_packet_desc[i].length + 187) / 188;
2611
2612 }
2613 ListNext(&td_list, pthis, pnext);
2614 pprev = pthis;
2615 pthis = pnext;
2616
2617 }
2618
2619 if (pipe_content->speed_high == 0)
2620 {
2621 // has an extra sitd to fill at the tail
2622 if (ret)
2623 {
2624 ListFirstPrev(&td_list, pthis);
2625 init_elem_phys_part(struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link));
2626
2627 psitd = sitd_from_list_entry(pthis);
2628 psitdc = (PEHCI_SITD_CONTENT) psitd;
2629 psitd->hw_next = EHCI_PTR_TERM;
2630
2631 // DWORD 1;
2632 psitdc->dev_addr = pdev->dev_addr;
2633 psitdc->endp_num = endp_num(purb->pendp);
2634 psitdc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
2635 psitdc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
2636 psitdc->io_dir = endp_dir(purb->pendp);
2637
2638 psitdc->status &= 0x80; // in DWORD 3
2639
2640 // DWORD 2;
2641 psitdc->s_mask = 0x04; // uframe 2, random selection
2642
2643 psitdc->c_mask = 0x70; // complete split at uframe 4, 5, 6
2644 ListFirstPrev(pthis, pprev);
2645 psitd->hw_backpointer = sitd_from_list_entry(pprev)->phys_addr;
2646 psitdc->status &= 0x82;
2647
2648 // DWORD 3:
2649 psitdc->c_prog_mask = 0;
2650 psitdc->bytes_to_transfer = 1; // purb->iso_packet_desc[ purb->iso_frame_count - 1 ].length;
2651 psitdc->page_sel = 0;
2652
2653 j = (ULONG) ((PBYTE) purb->data_buffer + purb->iso_packet_desc[purb->iso_frame_count - 1].offset);
2654 // the last byte is overridden.
2655 j += purb->iso_packet_desc[purb->iso_frame_count - 1].length - 1;
2656 psitd->hw_tx_results2 = MmGetPhysicalAddress((PVOID) j).LowPart;
2657 }
2658
2659 // set the interrupt
2660 ListFirstPrev(&td_list, pthis);
2661 psitdc = (PEHCI_SITD_CONTENT) sitd_from_list_entry(pthis);
2662 psitdc->ioc = 1;
2663 }
2664 else
2665 {
2666 // set the ioc
2667 ListFirstPrev(&td_list, pthis);
2668 pitdc = (PEHCI_ITD_CONTENT) itd_from_list_entry(pthis);
2669 for(i = 7; i >= 0; i--)
2670 {
2671 if (pitdc->status_slot[i].status == 0x08)
2672 {
2673 pitdc->status_slot[i].ioc = 1;
2674 break;
2675 }
2676 }
2677 if (i < 0)
2678 TRAP();
2679 }
2680
2681 ListFirst(&td_list, pthis);
2682 // ListFirst( &purb->trasac_list, pthis )
2683 RemoveEntryList(&td_list);
2684 InsertTailList(pthis, &purb->trasac_list);
2685
2686 while (pthis)
2687 {
2688 // fill the purb ptr
2689 struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->purb = purb;
2690 ListNext(&purb->trasac_list, pthis, pnext);
2691 pthis = pnext;
2692 }
2693
2694 //indirectly guarded by pending_endp_list_lock
2695 usb_endp_busy_count_inc(purb->pendp);
2696 ehci_insert_urb_to_schedule(ehci, purb, ret);
2697
2698 if (ret == FALSE)
2699 {
2700 // usb_endp_busy_count_dec( purb->pendp );
2701
2702 ListFirst(&purb->trasac_list, pthis);
2703 RemoveEntryList(&purb->trasac_list);
2704
2705 elem_safe_free(pthis, FALSE);
2706 ehci_claim_bandwidth(ehci, purb, FALSE);
2707 return STATUS_UNSUCCESSFUL;
2708 }
2709 return STATUS_SUCCESS;
2710 }
2711
2712 BOOLEAN NTAPI
2713 //this function used as the KeSynchronizeExecution param to delegate control to ehci_insert_urb_schedule
2714 ehci_sync_insert_urb_schedule(PVOID context)
2715 {
2716 PSYNC_PARAM sync_param;
2717 PEHCI_DEV ehci;
2718 PURB purb;
2719
2720 sync_param = (PSYNC_PARAM) context;
2721 if (sync_param == NULL)
2722 return FALSE;
2723
2724 ehci = sync_param->ehci;
2725 purb = (PURB) sync_param->context;
2726
2727 if (ehci == NULL || purb == NULL)
2728 return (UCHAR) (sync_param->ret = FALSE);
2729
2730 return (UCHAR) (sync_param->ret = ehci_insert_urb_schedule(ehci, purb));
2731 }
2732
2733 static BOOLEAN NTAPI
2734 ehci_sync_cancel_urb(PVOID context)
2735 {
2736 //cancel a single purb
2737 PEHCI_DEV ehci;
2738 PSYNC_PARAM sync_param;
2739 PURB purb2, dest_urb;
2740 PLIST_ENTRY pthis, pnext;
2741 BOOLEAN found = FALSE;
2742
2743 if (context == NULL)
2744 return FALSE;
2745
2746 sync_param = (PSYNC_PARAM) context;
2747 ehci = sync_param->ehci;
2748 dest_urb = (PURB) sync_param->context;
2749
2750 if (ehci == NULL || dest_urb == NULL)
2751 return (UCHAR) (sync_param->ret = FALSE);
2752
2753 ListFirst(&ehci->urb_list, pthis);
2754 while (pthis)
2755 {
2756 purb2 = (PURB) pthis;
2757 if (purb2 == dest_urb)
2758 {
2759 found = TRUE;
2760 purb2->flags |= URB_FLAG_FORCE_CANCEL;
2761 break;
2762 }
2763 ListNext(&ehci->urb_list, pthis, pnext);
2764 pthis = pnext;
2765 }
2766
2767 if (found)
2768 {
2769 press_doorbell(ehci);
2770 }
2771 return (UCHAR) (sync_param->ret = found);
2772 }
2773
2774 NTSTATUS
2775 ehci_cancel_urb(PEHCI_DEV ehci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
2776 //note any fields of the purb can not be referenced unless it is found in some queue
2777 {
2778 PLIST_ENTRY pthis, pnext;
2779 BOOLEAN found;
2780 PURB purb2;
2781
2782 SYNC_PARAM sync_param;
2783
2784 USE_BASIC_NON_PENDING_IRQL;
2785
2786 if (ehci == NULL || purb == NULL || pdev == NULL || pendp == NULL)
2787 return STATUS_INVALID_PARAMETER;
2788
2789 lock_dev(pdev, FALSE);
2790
2791 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2792 {
2793 unlock_dev(pdev, FALSE);
2794 //delegate to remove device for this job
2795 return STATUS_DEVICE_DOES_NOT_EXIST;
2796 }
2797
2798 if (dev_from_endp(pendp) != pdev)
2799 {
2800 unlock_dev(pdev, FALSE);
2801 return STATUS_INVALID_PARAMETER;
2802 }
2803
2804 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
2805 {
2806 //it will be canceled in ehci_process_pending_endp
2807 unlock_dev(pdev, FALSE);
2808 return USB_STATUS_ENDPOINT_HALTED;
2809 }
2810
2811 found = FALSE;
2812 ListFirst(&pendp->urb_list, pthis);
2813 while (pthis)
2814 {
2815 purb2 = (PURB) pthis;
2816 if (purb2 == purb)
2817 {
2818 found = TRUE;
2819 RemoveEntryList(pthis);
2820 InitializeListHead(pthis);
2821 break;
2822 }
2823 ListNext(&pendp->urb_list, pthis, pnext);
2824 pthis = pnext;
2825 }
2826 unlock_dev(pdev, FALSE);
2827
2828 if (found)
2829 {
2830 purb->status = STATUS_CANCELLED;
2831
2832 ehci_generic_urb_completion(purb, purb->context);
2833
2834 lock_dev(pdev, FALSE);
2835 pdev->ref_count--;
2836 unlock_dev(pdev, FALSE);
2837 return STATUS_SUCCESS;
2838 }
2839
2840 // search the purb in the purb-list and try to cancel
2841 sync_param.ehci = ehci;
2842 sync_param.context = purb;
2843
2844 KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_cancel_urb, &sync_param);
2845
2846 found = sync_param.ret;
2847
2848 if (found)
2849 return USB_STATUS_CANCELING;
2850
2851 return STATUS_INVALID_PARAMETER;
2852 }
2853
2854 VOID
2855 ehci_generic_urb_completion(PURB purb, PVOID context)
2856 {
2857 PUSB_DEV pdev;
2858 BOOLEAN is_ctrl = FALSE;
2859 USE_NON_PENDING_IRQL;
2860
2861 old_irql = KeGetCurrentIrql();
2862 if (old_irql > DISPATCH_LEVEL)
2863 TRAP();
2864
2865 if (old_irql < DISPATCH_LEVEL)
2866 KeRaiseIrql(DISPATCH_LEVEL, &old_irql);
2867
2868 pdev = purb->pdev;
2869 if (purb == NULL)
2870 goto LBL_LOWER_IRQL;
2871
2872 if (pdev == NULL)
2873 goto LBL_LOWER_IRQL;
2874
2875 lock_dev(pdev, TRUE);
2876
2877 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2878 {
2879 // no need to do following statistics
2880 unlock_dev(pdev, TRUE);
2881 goto LBL_CLIENT_PROCESS;
2882 }
2883 if (usb_error(purb->status))
2884 {
2885 pdev->error_count++;
2886 }
2887
2888 if (purb->pendp == &pdev->default_endp)
2889 {
2890 if (usb_halted(purb->status))
2891 {
2892 pdev->time_out_count++;
2893 if (pdev->time_out_count > 3)
2894 {
2895 dev_set_state(pdev, USB_DEV_STATE_ZOMB);
2896 ehci_dbg_print(DBGLVL_MAXIMUM,
2897 ("ehci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
2898 pdev));
2899 }
2900 }
2901 else
2902 pdev->time_out_count = 0;
2903
2904 }
2905
2906 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_CONTROL)
2907 is_ctrl = TRUE;
2908
2909 unlock_dev(pdev, TRUE);
2910
2911 LBL_CLIENT_PROCESS:
2912 if (!is_ctrl)
2913 {
2914 if (purb->completion)
2915 purb->completion(purb, context);
2916 }
2917 else
2918 {
2919 if (purb->ctrl_req_context.ctrl_stack_count == 0)
2920 {
2921 if (purb->completion)
2922 purb->completion(purb, context);
2923 }
2924 else
2925 {
2926 // pstack = &purb->ctrl_req_stack[ purb->ctrl_req_context.ctrl_cur_stack ];
2927 // if( pstack->urb_completion )
2928 // pstack->urb_completion( purb, pstack->context );
2929 usb_call_ctrl_completion(purb);
2930 }
2931 }
2932
2933 LBL_LOWER_IRQL:
2934 if (old_irql < DISPATCH_LEVEL)
2935 KeLowerIrql(old_irql);
2936
2937 return;
2938 }
2939
2940 NTSTATUS
2941 ehci_rh_submit_urb(PUSB_DEV pdev, PURB purb)
2942 {
2943 PUSB_DEV_MANAGER dev_mgr;
2944 PTIMER_SVC ptimer;
2945 PUSB_CTRL_SETUP_PACKET psetup;
2946 PEHCI_DEV ehci;
2947 NTSTATUS status;
2948 PHUB2_EXTENSION hub_ext;
2949 PUSB_PORT_STATUS ps, psret;
2950 LONG i;
2951 UCHAR port_count;
2952
2953 USE_NON_PENDING_IRQL;
2954 if (pdev == NULL || purb == NULL)
2955 return STATUS_INVALID_PARAMETER;
2956
2957 dev_mgr = dev_mgr_from_dev(pdev);
2958
2959 KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
2960 lock_dev(pdev, FALSE);
2961 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
2962 {
2963 unlock_dev(pdev, FALSE);
2964 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
2965 return STATUS_DEVICE_DOES_NOT_EXIST;
2966 }
2967
2968 ehci = ehci_from_hcd(pdev->hcd);
2969 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
2970
2971 hub_ext = ((PHUB2_EXTENSION) pdev->dev_ext);
2972 port_count = (UCHAR) ((PEHCI_HCS_CONTENT) & ehci->ehci_caps.hcs_params)->port_count;
2973
2974 switch (endp_type(purb->pendp))
2975 {
2976 case USB_ENDPOINT_XFER_CONTROL:
2977 {
2978 if (psetup->bmRequestType == 0xa3 && psetup->bRequest == USB_REQ_GET_STATUS)
2979 {
2980 //get-port-status
2981 if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength < 4)
2982 {
2983 purb->status = STATUS_INVALID_PARAMETER;
2984 break;
2985 }
2986
2987 i = EHCI_PORTSC + 4 * (psetup->wIndex - 1); // USBPORTSC1;
2988 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
2989 ps = &hub_ext->rh_port_status[psetup->wIndex];
2990
2991 psret = (PUSB_PORT_STATUS) purb->data_buffer;
2992 ps->wPortStatus = 0;
2993
2994 if (status & PORT_CCS)
2995 {
2996 ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
2997 }
2998 if (status & PORT_PE)
2999 {
3000 ps->wPortStatus |= USB_PORT_STAT_ENABLE;
3001 ps->wPortStatus |= USB_PORT_STAT_HIGH_SPEED; // ehci spec
3002 }
3003 if (status & PORT_PR)
3004 {
3005 ps->wPortStatus |= USB_PORT_STAT_RESET;
3006 }
3007 if (status & PORT_SUSP)
3008 {
3009 ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
3010 }
3011 if (PORT_USB11(status))
3012 {
3013 ps->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
3014 }
3015
3016 //always power on
3017 ps->wPortStatus |= USB_PORT_STAT_POWER;
3018
3019 //now set change field
3020 if ((status & PORT_CSC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
3021 {
3022 ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
3023 }
3024 if ((status & PORT_PEC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
3025 {
3026 ps->wPortChange |= USB_PORT_STAT_C_ENABLE;
3027 }
3028
3029 //don't touch other fields, might be filled by
3030 //other function
3031
3032 usb_dbg_print(DBGLVL_MAXIMUM,
3033 ("ehci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
3034 ps->wPortStatus, ps->wPortChange, ps));
3035
3036 psret->wPortChange = ps->wPortChange;
3037 psret->wPortStatus = ps->wPortStatus;
3038
3039 purb->status = STATUS_SUCCESS;
3040
3041 break;
3042 }
3043 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_CLEAR_FEATURE)
3044 {
3045 //clear-port-feature
3046 if (psetup->wIndex == 0 || psetup->wIndex > port_count)
3047 {
3048 purb->status = STATUS_INVALID_PARAMETER;
3049 break;
3050 }
3051
3052 i = EHCI_PORTSC + 4 * (psetup->wIndex - 1); // USBPORTSC1;
3053 ps = &hub_ext->rh_port_status[psetup->wIndex];
3054
3055 purb->status = STATUS_SUCCESS;
3056 switch (psetup->wValue)
3057 {
3058 case USB_PORT_FEAT_C_CONNECTION:
3059 {
3060 SET_RH2_PORTSTAT(i, USBPORTSC_CSC);
3061 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3062 usb_dbg_print(DBGLVL_MAXIMUM,
3063 ("ehci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup->wIndex));
3064 ps->wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
3065 break;
3066 }
3067 case USB_PORT_FEAT_C_ENABLE:
3068 {
3069 SET_RH2_PORTSTAT(i, USBPORTSC_PEC);
3070 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3071 usb_dbg_print(DBGLVL_MAXIMUM,
3072 ("ehci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup->wIndex));
3073 ps->wPortChange &= ~USB_PORT_STAT_C_ENABLE;
3074 break;
3075 }
3076 case USB_PORT_FEAT_C_RESET:
3077 {
3078 ps->wPortChange &= ~USB_PORT_STAT_C_RESET;
3079 //the reset signal is down in rh_timer_svc_reset_port_completion
3080 // enable or not is set by host controller
3081 // status = EHCI_READ_PORT_ULONG( ( PUSHORT ) ( ehci->port_base + i ) );
3082 usb_dbg_print(DBGLVL_MAXIMUM,
3083 ("ehci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
3084 psetup->wIndex));
3085 break;
3086 }
3087 case USB_PORT_FEAT_ENABLE:
3088 {
3089 ps->wPortStatus &= ~USB_PORT_STAT_ENABLE;
3090 CLR_RH2_PORTSTAT(i, USBPORTSC_PE);
3091 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3092 usb_dbg_print(DBGLVL_MAXIMUM,
3093 ("ehci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup->wIndex));
3094 break;
3095 }
3096 default:
3097 purb->status = STATUS_UNSUCCESSFUL;
3098 }
3099 break;
3100 }
3101 else if (psetup->bmRequestType == 0xd3 && psetup->bRequest == HUB_REQ_GET_STATE)
3102 {
3103 // get bus state
3104 if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength == 0)
3105 {
3106 purb->status = STATUS_INVALID_PARAMETER;
3107 break;
3108 }
3109
3110 i = EHCI_PORTSC + 4 * (psetup->wIndex - 1); // USBPORTSC1;
3111 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3112 purb->data_buffer[0] = (status & USBPORTSC_LS);
3113
3114 // reverse the order
3115 purb->data_buffer[0] ^= 0x3;
3116 purb->status = STATUS_SUCCESS;
3117 break;
3118 }
3119 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_SET_FEATURE)
3120 {
3121 //reset port
3122 if (psetup->wValue != USB_PORT_FEAT_RESET)
3123 {
3124 purb->status = STATUS_INVALID_PARAMETER;
3125 ehci_dbg_print(DBGLVL_MAXIMUM,
3126 ("ehci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup->wValue));
3127 break;
3128 }
3129
3130 i = EHCI_PORTSC + 4 * (psetup->wIndex - 1); // USBPORTSC1;
3131
3132 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3133 if (!ptimer)
3134 {
3135 purb->status = STATUS_NO_MEMORY;
3136 break;
3137 }
3138
3139 ptimer->threshold = 0; // within [ 50ms, 60ms ], one tick is 10 ms
3140 ptimer->context = (ULONG) purb;
3141 ptimer->pdev = pdev;
3142 ptimer->func = rh_timer_svc_reset_port_completion;
3143
3144 //start the timer
3145 pdev->ref_count += 2; //one for timer and one for purb
3146
3147 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3148 usb_dbg_print(DBGLVL_MAXIMUM,
3149 ("ehci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup->wIndex, status));
3150 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3151 purb->status = STATUS_PENDING;
3152 }
3153 else
3154 {
3155 purb->status = STATUS_INVALID_PARAMETER;
3156 }
3157 break;
3158 }
3159 case USB_ENDPOINT_XFER_INT:
3160 {
3161 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
3162 if (!ptimer)
3163 {
3164 purb->status = STATUS_NO_MEMORY;
3165 break;
3166 }
3167 ptimer->threshold = RH_INTERVAL;
3168 ptimer->context = (ULONG) purb;
3169 ptimer->pdev = pdev;
3170 ptimer->func = rh_timer_svc_int_completion;
3171
3172 //start the timer
3173 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
3174
3175 usb_dbg_print(DBGLVL_MAXIMUM,
3176 ("ehci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev->ref_count));
3177 pdev->ref_count += 2; //one for timer and one for purb
3178
3179 purb->status = STATUS_PENDING;
3180 break;
3181 }
3182 case USB_ENDPOINT_XFER_BULK:
3183 case USB_ENDPOINT_XFER_ISOC:
3184 default:
3185 {
3186 purb->status = STATUS_INVALID_PARAMETER;
3187 break;
3188 }
3189 }
3190 unlock_dev(pdev, FALSE);
3191 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
3192 return purb->status;
3193 }
3194
3195 //must have rh dev_lock acquired
3196 BOOLEAN
3197 ehci_rh_reset_port(PHCD hcd, UCHAR port_idx)
3198 {
3199 ULONG i;
3200 PEHCI_DEV ehci;
3201 ULONG status;
3202 UCHAR port_count;
3203
3204 if (hcd == NULL)
3205 return FALSE;
3206
3207 ehci = ehci_from_hcd(hcd);
3208 port_count = (UCHAR) ((PEHCI_HCS_CONTENT) & ehci->ehci_caps.hcs_params)->port_count;
3209
3210 if (port_idx < 1 || port_idx > port_count)
3211 return FALSE;
3212
3213 i = (ULONG) (EHCI_PORTSC + 4 * (port_idx - 1));
3214
3215 // assert the reset signal,(implicitly disable the port)
3216 SET_RH2_PORTSTAT(i, PORT_PR);
3217
3218 usb_wait_ms_dpc(50);
3219 // clear the reset signal, delay port enable till clearing port feature
3220 CLR_RH2_PORTSTAT(i, PORT_PR);
3221
3222 // wait the port stable
3223 usb_wait_ms_dpc(2);
3224
3225 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3226 if (!(status & PORT_PE))
3227 {
3228 // release the ownership from ehci to companion hc
3229 status |= PORT_OWNER;
3230 EHCI_WRITE_PORT_ULONG((PULONG) (ehci->port_base + i), status);
3231 // the host controller will set PORTSC automatically
3232 return FALSE;
3233 }
3234 usb_wait_us_dpc(10);
3235 // SET_RH_PORTSTAT( i, PORT_PE );
3236
3237 //recovery time 10ms
3238 usb_wait_ms_dpc(10);
3239
3240 // clear PORT_PEC and PORT_PCC
3241 SET_RH2_PORTSTAT(i, 0x0a);
3242
3243 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
3244 usb_dbg_print(DBGLVL_MAXIMUM, ("ehci_rh_reset_port(): status after written=0x%x\n", status));
3245 return TRUE;
3246 }
3247
3248 NTSTATUS
3249 ehci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp)
3250 {
3251 PEHCI_DEVICE_EXTENSION pdev_ext;
3252 PUSB_DEV_MANAGER dev_mgr;
3253 PEHCI_DEV ehci;
3254
3255 pdev_ext = DeviceObject->DeviceExtension;
3256 ehci = pdev_ext->ehci;
3257
3258 dev_mgr = ehci->hcd_interf.hcd_get_dev_mgr(&ehci->hcd_interf);
3259 return dev_mgr_dispatch(dev_mgr, irp);
3260 }
3261
3262 //the following are for hcd interface methods
3263 VOID
3264 ehci_set_dev_mgr(PHCD hcd, PUSB_DEV_MANAGER dev_mgr)
3265 {
3266 hcd->dev_mgr = dev_mgr;
3267 }
3268
3269 PUSB_DEV_MANAGER
3270 ehci_get_dev_mgr(PHCD hcd)
3271 {
3272 return hcd->dev_mgr;
3273 }
3274
3275 ULONG
3276 ehci_get_type(PHCD hcd)
3277 {
3278 return HCD_TYPE_EHCI; // ( hcd->flags & HCD_TYPE_MASK );
3279 }
3280
3281 VOID
3282 ehci_set_id(PHCD hcd, UCHAR id)
3283 {
3284 hcd->flags &= ~HCD_ID_MASK;
3285 hcd->flags |= (HCD_ID_MASK & id);
3286 }
3287
3288 UCHAR
3289 ehci_get_id(PHCD hcd)
3290 {
3291 return (UCHAR) (hcd->flags & HCD_ID_MASK);
3292 }
3293
3294
3295 UCHAR
3296 ehci_alloc_addr(PHCD hcd)
3297 {
3298 LONG i;
3299 if (hcd == NULL)
3300 return 0;
3301
3302 for(i = 1; i < MAX_DEVS; i++)
3303 {
3304 if (hcd->dev_addr_map[i >> 3] & (1 << (i & 7)))
3305 {
3306 continue;
3307 }
3308 else
3309 {
3310 break;
3311 }
3312 }
3313
3314 if (i >= MAX_DEVS)
3315 return 0xff;
3316
3317 hcd->dev_addr_map[i >> 3] |= (1 << (i & 7));
3318 hcd->conn_count++;
3319 return (BYTE) i;
3320 }
3321
3322 VOID
3323 ehci_free_addr(PHCD hcd, UCHAR addr)
3324 {
3325 if (addr & 0x80)
3326 return;
3327
3328 if (hcd == NULL)
3329 return;
3330
3331 hcd->dev_addr_map[addr >> 3] &= ~(1 << (addr & 7));
3332 return;
3333
3334 }
3335
3336 NTSTATUS
3337 ehci_submit_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3338 {
3339 return ehci_submit_urb(ehci_from_hcd(hcd), pdev, pendp, purb);
3340 }
3341
3342 PUSB_DEV
3343 ehci_get_root_hub(PHCD hcd)
3344 {
3345 return ehci_from_hcd(hcd)->root_hub;
3346 }
3347
3348 VOID
3349 ehci_set_root_hub(PHCD hcd, PUSB_DEV root_hub)
3350 {
3351 if (hcd == NULL || root_hub == NULL)
3352 return;
3353 ehci_from_hcd(hcd)->root_hub = root_hub;
3354 return;
3355 }
3356
3357 BOOLEAN
3358 ehci_remove_device2(PHCD hcd, PUSB_DEV pdev)
3359 {
3360 if (hcd == NULL || pdev == NULL)
3361 return FALSE;
3362
3363 return ehci_remove_device(ehci_from_hcd(hcd), pdev);
3364 }
3365
3366 BOOLEAN
3367 ehci_hcd_release(PHCD hcd)
3368 {
3369 PEHCI_DEV ehci;
3370 PEHCI_DEVICE_EXTENSION pdev_ext;
3371
3372 if (hcd == NULL)
3373 return FALSE;
3374
3375 ehci = ehci_from_hcd(hcd);
3376 pdev_ext = ehci->pdev_ext;
3377 return ehci_release(pdev_ext->pdev_obj);
3378 }
3379
3380 NTSTATUS
3381 ehci_cancel_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
3382 {
3383 PEHCI_DEV ehci;
3384 if (hcd == NULL)
3385 return STATUS_INVALID_PARAMETER;
3386
3387 ehci = ehci_from_hcd(hcd);
3388 return ehci_cancel_urb(ehci, pdev, pendp, purb);
3389 }
3390
3391 BOOLEAN
3392 ehci_rh_get_dev_change(PHCD hcd, PBYTE buf) //must have the rh dev_lock acquired
3393 {
3394 PEHCI_DEV ehci;
3395 LONG port_count, i;
3396 ULONG status;
3397
3398 if (hcd == NULL)
3399 return FALSE;
3400
3401 ehci = ehci_from_hcd(hcd);
3402 port_count = HCS_N_PORTS(ehci->ehci_caps.hcs_params);
3403 for(i = 0; i < port_count; i++)
3404 {
3405 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + EHCI_PORTSC + (i << 2)));
3406 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_rh_get_dev_change(): erh port%d status=0x%x\n", i, status));
3407
3408 if (status & (PORT_PEC | PORT_CSC | PORT_OCC))
3409 {
3410 buf[(i + 1) >> 3] |= (1 << ((i + 1) & 7));
3411 }
3412 }
3413 return TRUE;
3414 }
3415
3416 NTSTATUS
3417 ehci_hcd_dispatch(PHCD hcd, LONG disp_code, PVOID param)
3418 {
3419 PEHCI_DEV ehci;
3420
3421 if (hcd == NULL)
3422 return STATUS_INVALID_PARAMETER;
3423 ehci = ehci_from_hcd(hcd);
3424 switch (disp_code)
3425 {
3426 case HCD_DISP_READ_PORT_COUNT:
3427 {
3428 if (param == NULL)
3429 return STATUS_INVALID_PARAMETER;
3430 *((PUCHAR) param) = (UCHAR) HCS_N_PORTS(ehci->ehci_caps.hcs_params);
3431 return STATUS_SUCCESS;
3432 }
3433 case HCD_DISP_READ_RH_DEV_CHANGE:
3434 {
3435 if (ehci_rh_get_dev_change(hcd, param) == FALSE)
3436 return STATUS_INVALID_PARAMETER;
3437 return STATUS_SUCCESS;
3438 }
3439 }
3440 return STATUS_NOT_IMPLEMENTED;
3441 }
3442
3443 //------------------------------------------------------------------------------
3444 // EHCI routines follows
3445 //
3446 VOID ehci_init_int8_qh(PEHCI_QH_CONTENT qh);
3447
3448 BOOLEAN NTAPI
3449 ehci_cal_cpu_freq(PVOID context)
3450 {
3451 usb_cal_cpu_freq();
3452 return TRUE;
3453 }
3454
3455 PDEVICE_OBJECT
3456 ehci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, PUSB_DEV_MANAGER dev_mgr)
3457 {
3458 LONG bus, i, j, ret = 0;
3459 PCI_SLOT_NUMBER slot_num;
3460 PPCI_COMMON_CONFIG pci_config;
3461 PDEVICE_OBJECT pdev;
3462 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
3463 PEHCI_DEVICE_EXTENSION pdev_ext;
3464
3465 slot_num.u.AsULONG = 0;
3466 pci_config = (PPCI_COMMON_CONFIG) buffer;
3467 pdev = NULL;
3468
3469 //scan the bus to find ehci controller
3470 for(bus = 0; bus < 3; bus++) /* enum bus0-bus2 */
3471 {
3472 for(i = 0; i < PCI_MAX_DEVICES; i++)
3473 {
3474 slot_num.u.bits.DeviceNumber = i;
3475 for(j = 0; j < PCI_MAX_FUNCTIONS; j++)
3476 {
3477 slot_num.u.bits.FunctionNumber = j;
3478
3479 ret = HalGetBusData(PCIConfiguration,
3480 bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);
3481
3482 if (ret == 0) /*no this bus */
3483 break;
3484
3485 if (ret == 2) /*no device on the slot */
3486 break;
3487
3488 if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03
3489 && pci_config->ProgIf == 0x20)
3490 {
3491 //well, we find our usb host controller( EHCI ), create device
3492 pdev = ehci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
3493
3494 if (!pdev)
3495 continue;
3496 }
3497 }
3498
3499 if (ret == 0)
3500 break;
3501 }
3502 }
3503
3504 if (pdev)
3505 {
3506 pdev_ext = pdev->DeviceExtension;
3507 if (pdev_ext)
3508 {
3509 // acquire higher irql to eliminate pre-empty
3510 KeSynchronizeExecution(pdev_ext->ehci_int, ehci_cal_cpu_freq, NULL);
3511 }
3512 }
3513 return pdev;
3514 }
3515
3516 PDEVICE_OBJECT
3517 ehci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
3518 {
3519
3520 LONG frd_num, prd_num;
3521 PDEVICE_OBJECT pdev;
3522 PEHCI_DEVICE_EXTENSION pdev_ext;
3523 ULONG vector, addr_space;
3524 LONG bus, i;
3525 KIRQL irql;
3526 KAFFINITY affinity;
3527
3528 DEVICE_DESCRIPTION dev_desc;
3529 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
3530 PCI_SLOT_NUMBER slot_num;
3531 NTSTATUS status;
3532
3533
3534 pdev = ehci_create_device(drvr_obj, dev_mgr);
3535
3536 if (pdev == NULL)
3537 return NULL;
3538
3539 pdev_ext = pdev->DeviceExtension;
3540
3541 pdev_ext->pci_addr = bus_addr;
3542 bus = (bus_addr >> 8);
3543
3544 slot_num.u.AsULONG = 0;
3545 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
3546 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
3547
3548 //now create adapter object
3549 RtlZeroMemory(&dev_desc, sizeof(dev_desc));
3550
3551 dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
3552 dev_desc.Master = TRUE;
3553 dev_desc.ScatterGather = TRUE;
3554 dev_desc.Dma32BitAddresses = TRUE;
3555 dev_desc.BusNumber = bus;
3556 dev_desc.InterfaceType = PCIBus;
3557 dev_desc.MaximumLength = EHCI_MAX_SIZE_TRANSFER;
3558
3559 pdev_ext->map_regs = 2; // we do not use it seriously
3560
3561 pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);
3562
3563 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_alloc(): padapter=0x%x\n", pdev_ext->padapter));
3564 if (pdev_ext->padapter == NULL)
3565 {
3566 //fatal error
3567 ehci_delete_device(pdev);
3568 return NULL;
3569 }
3570
3571 DbgPrint("ehci_alloc(): reg_path=0x%x, \n \
3572 ehci_alloc(): PCIBus=0x%x, bus=0x%x, bus_addr=0x%x \n \
3573 ehci_alloc(): slot_num=0x%x, &res_list=0x%x \n \
3574 ehci_alloc(): adapter=0x%x \n", (DWORD) reg_path, (DWORD) PCIBus, (DWORD) bus, (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG, (DWORD) & pdev_ext->res_list, pdev_ext->padapter);
3575
3576 //let's allocate resources for this device
3577 DbgPrint("ehci_alloc(): about to assign slot res\n");
3578 if ((status = HalAssignSlotResources(reg_path, NULL, //no class name yet
3579 drvr_obj, NULL, //no support of another ehci controller
3580 PCIBus,
3581 bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
3582 {
3583 DbgPrint("ehci_alloc(): error assign slot res, 0x%x\n", status);
3584 release_adapter(pdev_ext->padapter);
3585 pdev_ext->padapter = NULL;
3586 ehci_delete_device(pdev);
3587 return NULL;
3588 }
3589
3590 //parse the resource list
3591 for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
3592 {
3593 for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
3594 prd_num++)
3595 {
3596 pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
3597 if (pprd->Type == CmResourceTypePort)
3598 {
3599 RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
3600
3601 }
3602 else if (pprd->Type == CmResourceTypeInterrupt)
3603 {
3604 RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
3605 }
3606 else if (pprd->Type == CmResourceTypeMemory)
3607 {
3608 RtlCopyMemory(&pdev_ext->res_memory, &pprd->u.Memory, sizeof(pprd->u.Memory));
3609 }
3610 }
3611 }
3612
3613 //for port, translate them to system address
3614 addr_space = 0;
3615 if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space, //io space
3616 &pdev_ext->ehci->ehci_reg_base) != (BOOLEAN) TRUE)
3617 {
3618 DbgPrint("ehci_alloc(): error, can not translate bus address\n");
3619 release_adapter(pdev_ext->padapter);
3620 pdev_ext->padapter = NULL;
3621 ehci_delete_device(pdev);
3622 return NULL;
3623 }
3624
3625 DbgPrint("ehci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
3626 addr_space, pdev_ext->ehci->ehci_reg_base.u.LowPart);
3627
3628 if (addr_space == 0)
3629 {
3630 //port has been mapped to memory space
3631 pdev_ext->ehci->port_mapped = TRUE;
3632 pdev_ext->ehci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->ehci->ehci_reg_base,
3633 pdev_ext->res_port.Length, FALSE);
3634
3635 //fatal error can not map the registers
3636 if (pdev_ext->ehci->port_base == NULL)
3637 {
3638 release_adapter(pdev_ext->padapter);
3639 pdev_ext->padapter = NULL;
3640 ehci_delete_device(pdev);
3641 return NULL;
3642 }
3643 }
3644 else
3645 {
3646 //io space
3647 pdev_ext->ehci->port_mapped = FALSE;
3648 pdev_ext->ehci->port_base = (PBYTE) pdev_ext->ehci->ehci_reg_base.LowPart;
3649 }
3650
3651 //before we connect the interrupt, we have to init ehci
3652 pdev_ext->ehci->pdev_ext = pdev_ext;
3653
3654 //init ehci_caps
3655 // i = ( ( PEHCI_HCS_CONTENT )( &pdev_ext->ehci->ehci_caps.hcs_params ) )->length;
3656
3657 ehci_get_capabilities(pdev_ext->ehci, pdev_ext->ehci->port_base);
3658 i = pdev_ext->ehci->ehci_caps.length;
3659 pdev_ext->ehci->port_base += i;
3660
3661 if (ehci_init_schedule(pdev_ext->ehci, pdev_ext->padapter) == FALSE)
3662 {
3663 release_adapter(pdev_ext->padapter);
3664 pdev_ext->padapter = NULL;
3665 ehci_delete_device(pdev);
3666 return NULL;
3667 }
3668
3669 InitializeListHead(&pdev_ext->ehci->urb_list);
3670 KeInitializeSpinLock(&pdev_ext->ehci->pending_endp_list_lock);
3671 InitializeListHead(&pdev_ext->ehci->pending_endp_list);
3672
3673 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_alloc(): pending_endp_list=0x%x\n",
3674 &pdev_ext->ehci->pending_endp_list));
3675
3676 init_pending_endp_pool(&pdev_ext->ehci->pending_endp_pool);
3677
3678 KeInitializeTimer(&pdev_ext->ehci->reset_timer);
3679
3680 vector = HalGetInterruptVector(PCIBus,
3681 bus,
3682 pdev_ext->res_interrupt.level,
3683 pdev_ext->res_interrupt.vector, &irql, &affinity);
3684
3685 KeInitializeDpc(&pdev_ext->ehci_dpc, ehci_dpc_callback, (PVOID) pdev_ext->ehci);
3686
3687 //connect the interrupt
3688 DbgPrint("ehci_alloc(): the int=0x%x\n", vector);
3689 if (IoConnectInterrupt(&pdev_ext->ehci_int, ehci_isr, pdev_ext->ehci, NULL, //&pdev_ext->ehci->frame_list_lock,
3690 vector, irql, irql, LevelSensitive, TRUE, //share the vector
3691 affinity, FALSE) //No float save
3692 != STATUS_SUCCESS)
3693 {
3694 ehci_release(pdev);
3695 return NULL;
3696 }
3697
3698 return pdev;
3699 }
3700
3701 PDEVICE_OBJECT
3702 ehci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
3703 {
3704 NTSTATUS status;
3705 PDEVICE_OBJECT pdev;
3706 PEHCI_DEVICE_EXTENSION pdev_ext;
3707
3708 UNICODE_STRING dev_name;
3709 UNICODE_STRING symb_name;
3710
3711 STRING string, another_string;
3712 CHAR str_dev_name[64], str_symb_name[64];
3713 UCHAR hcd_id;
3714
3715 if (drvr_obj == NULL)
3716 return NULL;
3717
3718 //note: hcd count wont increment till the hcd is registered in dev_mgr
3719 sprintf(str_dev_name, "%s%d", EHCI_DEVICE_NAME, dev_mgr->hcd_count);
3720 sprintf(str_symb_name, "%s%d", EHCI_DOS_DEVICE_NAME, dev_mgr->hcd_count);
3721
3722 RtlInitString(&string, str_dev_name);
3723 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
3724
3725 pdev = NULL;
3726 status = IoCreateDevice(drvr_obj,
3727 sizeof(EHCI_DEVICE_EXTENSION) + sizeof(EHCI_DEV),
3728 &dev_name, FILE_EHCI_DEV_TYPE, 0, FALSE, &pdev);
3729
3730 if (status != STATUS_SUCCESS || pdev == NULL)
3731 {
3732 RtlFreeUnicodeString(&dev_name);
3733 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_create_device(): error create device 0x%x\n", status));
3734 return NULL;
3735 }
3736
3737 pdev_ext = pdev->DeviceExtension;
3738 RtlZeroMemory(pdev_ext, sizeof(EHCI_DEVICE_EXTENSION) + sizeof(EHCI_DEV));
3739
3740 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
3741 pdev_ext->dev_ext_hdr.dispatch = ehci_dispatch_irp;
3742 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
3743 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
3744
3745 pdev_ext->pdev_obj = pdev;
3746 pdev_ext->pdrvr_obj = drvr_obj;
3747
3748 pdev_ext->ehci = (PEHCI_DEV) & (pdev_ext[1]);
3749
3750 RtlInitString(&another_string, str_symb_name);
3751 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
3752 //RtlInitUnicodeString( &symb_name, DOS_DEVICE_NAME );
3753
3754 IoCreateSymbolicLink(&symb_name, &dev_name);
3755
3756 ehci_dbg_print(DBGLVL_MAXIMUM,
3757 ("ehci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, ehci=0x%x, dev_mgr=0x%x\n", pdev,
3758 pdev_ext, pdev_ext->ehci, dev_mgr));
3759
3760 RtlFreeUnicodeString(&dev_name);
3761 RtlFreeUnicodeString(&symb_name);
3762
3763 //register with dev_mgr though it is not initilized
3764 ehci_init_hcd_interface(pdev_ext->ehci);
3765 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->ehci->hcd_interf);
3766
3767 pdev_ext->ehci->hcd_interf.hcd_set_id(&pdev_ext->ehci->hcd_interf, hcd_id);
3768 pdev_ext->ehci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->ehci->hcd_interf, dev_mgr);
3769
3770 return pdev;
3771
3772 }
3773
3774 VOID
3775 ehci_init_hcd_interface(PEHCI_DEV ehci)
3776 {
3777 ehci->hcd_interf.hcd_set_dev_mgr = ehci_set_dev_mgr;
3778 ehci->hcd_interf.hcd_get_dev_mgr = ehci_get_dev_mgr;
3779 ehci->hcd_interf.hcd_get_type = ehci_get_type;
3780 ehci->hcd_interf.hcd_set_id = ehci_set_id;
3781 ehci->hcd_interf.hcd_get_id = ehci_get_id;
3782 ehci->hcd_interf.hcd_alloc_addr = ehci_alloc_addr;
3783 ehci->hcd_interf.hcd_free_addr = ehci_free_addr;
3784 ehci->hcd_interf.hcd_submit_urb = ehci_submit_urb2;
3785 ehci->hcd_interf.hcd_generic_urb_completion = ehci_generic_urb_completion;
3786 ehci->hcd_interf.hcd_get_root_hub = ehci_get_root_hub;
3787 ehci->hcd_interf.hcd_set_root_hub = ehci_set_root_hub;
3788 ehci->hcd_interf.hcd_remove_device = ehci_remove_device2;
3789 ehci->hcd_interf.hcd_rh_reset_port = ehci_rh_reset_port;
3790 ehci->hcd_interf.hcd_release = ehci_hcd_release;
3791 ehci->hcd_interf.hcd_cancel_urb = ehci_cancel_urb2;
3792 ehci->hcd_interf.hcd_start = ehci_start;
3793 ehci->hcd_interf.hcd_dispatch = ehci_hcd_dispatch;
3794
3795 ehci->hcd_interf.flags = HCD_TYPE_EHCI; //hcd types | hcd id
3796 }
3797
3798 BOOLEAN
3799 ehci_init_schedule(PEHCI_DEV ehci, PADAPTER_OBJECT padapter)
3800 {
3801 PEHCI_DEVICE_EXTENSION pdev_ext;
3802 BOOLEAN ret = TRUE;
3803 LONG i;
3804 PEHCI_QH_CONTENT pqh_content;
3805 PEHCI_QH pqh;
3806 PEHCI_ELEM_LINKS pelnk;
3807
3808 if (ehci == NULL)
3809 return FALSE;
3810
3811 pdev_ext = ehci->pdev_ext;
3812 if (pdev_ext == NULL)
3813 return FALSE;
3814
3815 // padapter = pdev_ext->padapter;
3816 if (ehci->frame_count == 0)
3817 ehci->frame_count = EHCI_DEFAULT_FRAMES;
3818
3819 // allocate pools
3820 for(i = 0; i < 5; i++)
3821 {
3822 ret = elem_pool_init_pool(&ehci->elem_pools[i], i, padapter);
3823 if (ret == FALSE)
3824 break;
3825 }
3826
3827 if (ret == FALSE)
3828 {
3829 i--;
3830 for(; i >= 0; i--)
3831 elem_pool_destroy_pool(&ehci->elem_pools[i]);
3832 return FALSE;
3833 }
3834
3835 // allocate periodic frame list
3836 ehci->frame_list =
3837 HalAllocateCommonBuffer(padapter,
3838 sizeof(ULONG) * ehci->frame_count, &ehci->frame_list_phys_addr, FALSE);
3839 if (ehci->frame_list == NULL)
3840 goto ERROR_OUT;
3841
3842 RtlZeroMemory(ehci->frame_list, sizeof(ULONG) * ehci->frame_count);
3843 ehci->frame_list_cpu = usb_alloc_mem(NonPagedPool, sizeof(LIST_HEAD) * ehci->frame_count);
3844
3845 if (ehci->frame_list_cpu == NULL)
3846 goto ERROR_OUT;
3847
3848 for(i = 0; i < (LONG) ehci->frame_count; i++)
3849 {
3850 InitializeListHead(&ehci->frame_list_cpu[i].td_link);
3851 }
3852
3853 for(i = 0; i < 8; i++)
3854 {
3855 InitializeListHead(&ehci->periodic_list_cpu[i]);
3856 }
3857
3858 InitializeListHead(&ehci->async_list_cpu);
3859
3860 // init frame band budget array
3861 ehci->frame_bw = usb_alloc_mem(NonPagedPool, sizeof(USHORT) * ehci->frame_count * 8);
3862 if (ehci->frame_bw == NULL)
3863 goto ERROR_OUT;
3864
3865 for(i = 0; i < (LONG) ehci->frame_count * 8; i++)
3866 {
3867 ehci->frame_bw[i] = EHCI_MAX_SYNC_BUS_TIME;
3868 }
3869 ehci->min_bw = EHCI_MAX_SYNC_BUS_TIME;
3870
3871 // chain the 1ms interrupt qh to the schedule
3872 if ((pelnk = elem_pool_alloc_elem(&ehci->elem_pools[EHCI_QH_POOL_IDX])) == NULL)
3873 goto ERROR_OUT;
3874
3875 pqh_content = (PEHCI_QH_CONTENT) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
3876 ehci_init_int8_qh(pqh_content);
3877
3878 // chain qh to the shadow list
3879 InsertTailList(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX], &pelnk->sched_link);
3880
3881 // chain it to the periodic schedule, we use it as a docking point
3882 // for req of 8- uframes request
3883 pqh = (PEHCI_QH) pqh_content;
3884
3885 for(i = 0; i < (LONG) ehci->frame_count; i++)
3886 {
3887 ehci->frame_list[i] = pqh->phys_addr;
3888 }
3889
3890 // allocate fstn
3891 /*if( ( pelnk = elem_pool_alloc_elem( &ehci->elem_pools[ EHCI_FSTN_POOL_IDX ] ) ) == NULL )
3892 goto ERROR_OUT;
3893
3894 pfstn = ( PEHCI_FSTN )( ( ULONG )pelnk->phys_part & PHYS_PART_ADDR_MASK );
3895 pfstn->hw_next = EHCI_PTR_TERM;
3896 pfstn->hw_prev = EHCI_PTR_TERM | ( INIT_LIST_FLAG_QH << 1 );
3897 InsertTailList( &ehci->periodic_list_cpu[ EHCI_SCHED_FSTN_INDEX ], &pelnk->sched_link );
3898 pqh->hw_next = pfstn->phys_addr; */
3899
3900 // allocate for async list head
3901 if ((pelnk = elem_pool_alloc_elem(&ehci->elem_pools[EHCI_QH_POOL_IDX])) == NULL)
3902 goto ERROR_OUT;
3903
3904 // init the async list head
3905 pqh = (PEHCI_QH) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
3906 pqh_content = (PEHCI_QH_CONTENT) pqh;
3907 ehci_init_int8_qh(pqh_content);
3908 pqh->hw_next = pqh->phys_addr;
3909 pqh_content->s_mask = 0;
3910 pqh_content->is_async_head = 1;
3911 pqh_content->endp_addr = 0;
3912 ehci->skel_async_qh = pqh;
3913 InsertTailList(&ehci->async_list_cpu, &pqh->elem_head_link->sched_link);
3914 return TRUE;
3915
3916 ERROR_OUT:
3917 ehci_destroy_schedule(ehci);
3918 return FALSE;
3919 }
3920
3921 BOOLEAN
3922 ehci_destroy_schedule(PEHCI_DEV ehci)
3923 {
3924 LONG i;
3925 if (ehci == NULL)
3926 return FALSE;
3927
3928 if (ehci->frame_bw)
3929 usb_free_mem(ehci->frame_bw);
3930 ehci->frame_bw = NULL;
3931
3932 if (ehci->frame_list_cpu)
3933 usb_free_mem(ehci->frame_list_cpu);
3934 ehci->frame_list_cpu = NULL;
3935
3936 if (ehci->frame_list)
3937 HalFreeCommonBuffer(ehci->pdev_ext->padapter,
3938 sizeof(ULONG) * ehci->frame_count,
3939 ehci->frame_list_phys_addr, ehci->frame_list, FALSE);
3940
3941 ehci->frame_list = NULL;
3942 ehci->frame_list_phys_addr.LowPart = 0;
3943 ehci->frame_list_phys_addr.HighPart = 0;
3944
3945 for(i = 0; i < 5; i++)
3946 elem_pool_destroy_pool(&ehci->elem_pools[i]);
3947
3948 return TRUE;
3949 }
3950
3951 VOID
3952 ehci_init_int8_qh(PEHCI_QH_CONTENT qh)
3953 {
3954 if (qh == NULL)
3955 return;
3956 // DWORD 0
3957 qh->terminal = EHCI_PTR_TERM;
3958 qh->ptr_type = 0;
3959 qh->reserved = 0;
3960 qh->next_link = 0;
3961
3962 // DWORD 1
3963 qh->dev_addr = 126; // a fake addr
3964 qh->inactive = 0;
3965 qh->endp_addr = 1; // a fake endp
3966 qh->endp_spd = USB_SPEED_HIGH;
3967 qh->data_toggle = 0;
3968 qh->is_async_head = 0;
3969 qh->max_packet_size = 64;
3970 qh->is_ctrl_endp = 0;
3971 qh->reload_counter = 0;
3972
3973 // DWORD 2
3974 qh->s_mask = 0x80; // we are interrupt qh
3975 qh->c_mask = 0;
3976 qh->hub_addr = 0;
3977 qh->port_idx = 0;
3978 qh->mult = 1;
3979
3980 // DWORD 3
3981 qh->cur_qtd_ptr = 0; // a terminal
3982
3983 // overlay
3984 // !active and !halted
3985 RtlZeroMemory(&qh->cur_qtd, get_elem_phys_part_size(INIT_LIST_FLAG_QTD));
3986 qh->cur_qtd.alt_terminal = 1; // don't use this
3987 qh->cur_qtd.terminal = 1;
3988 qh->cur_qtd.status = QTD_STS_HALT;
3989 }
3990
3991 VOID
3992 ehci_get_capabilities(PEHCI_DEV ehci, PBYTE base)
3993 // fetch capabilities register from ehci
3994 {
3995 PEHCI_CAPS pcap;
3996 PEHCI_HCS_CONTENT phcs;
3997 LONG i;
3998
3999 if (ehci == NULL)
4000 return;
4001
4002 pcap = &ehci->ehci_caps;
4003 pcap->length = EHCI_READ_PORT_UCHAR((PUCHAR) (base + 0));
4004 pcap->reserved = EHCI_READ_PORT_UCHAR((PUCHAR) (base + 1));
4005 pcap->hci_version = EHCI_READ_PORT_USHORT((PUSHORT) (base + 2));
4006 pcap->hcs_params = EHCI_READ_PORT_ULONG((PULONG) (base + 4));
4007 pcap->hcc_params = EHCI_READ_PORT_ULONG((PULONG) (base + 8));
4008
4009 phcs = (PEHCI_HCS_CONTENT) & pcap->hcs_params;
4010 if (phcs->port_rout_rules)
4011 {
4012 for(i = 0; i < 8; i++)
4013 pcap->portroute[i] = EHCI_READ_PORT_UCHAR((PUCHAR) (base + 12 + i));
4014 }
4015 return;
4016 }
4017
4018 BOOLEAN
4019 ehci_delete_device(PDEVICE_OBJECT pdev)
4020 {
4021 STRING string;
4022 UNICODE_STRING symb_name;
4023 CHAR str_symb_name[64];
4024 PEHCI_DEVICE_EXTENSION pdev_ext;
4025
4026 if (pdev == NULL)
4027 return FALSE;
4028
4029 pdev_ext = pdev->DeviceExtension;
4030
4031 sprintf(str_symb_name,
4032 "%s%d", EHCI_DOS_DEVICE_NAME, pdev_ext->ehci->hcd_interf.hcd_get_id(&pdev_ext->ehci->hcd_interf));
4033
4034 RtlInitString(&string, str_symb_name);
4035 RtlAnsiStringToUnicodeString(&symb_name, &string, TRUE);
4036 IoDeleteSymbolicLink(&symb_name);
4037 RtlFreeUnicodeString(&symb_name);
4038
4039 if (pdev_ext->res_list)
4040 ExFreePool(pdev_ext->res_list); // not allocated by usb_alloc_mem
4041
4042 IoDeleteDevice(pdev);
4043 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_delete_device(): device deleted\n"));
4044 return TRUE;
4045 }
4046
4047 VOID
4048 ehci_stop(PEHCI_DEV ehci)
4049 {
4050 PBYTE base;
4051 PEHCI_USBCMD_CONTENT usbcmd;
4052 LONG tmp;
4053
4054 base = ehci->port_base;
4055 // turn off all the interrupt
4056 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBINTR), 0);
4057 tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
4058 usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
4059 usbcmd->run_stop = 0;
4060 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4061 }
4062
4063 BOOLEAN
4064 ehci_release(PDEVICE_OBJECT pdev)
4065 {
4066 PEHCI_DEVICE_EXTENSION pdev_ext;
4067 PEHCI_DEV ehci;
4068
4069 if (pdev == NULL)
4070 return FALSE;
4071
4072 pdev_ext = pdev->DeviceExtension;
4073
4074 if (pdev_ext == NULL)
4075 return FALSE;
4076
4077 ehci = pdev_ext->ehci;
4078 if (ehci == NULL)
4079 return FALSE;
4080
4081 ehci_stop(ehci);
4082
4083 if (pdev_ext->ehci_int)
4084 {
4085 IoDisconnectInterrupt(pdev_ext->ehci_int);
4086 pdev_ext->ehci_int = NULL;
4087 }
4088 else
4089 TRAP();
4090 destroy_pending_endp_pool(&pdev_ext->ehci->pending_endp_pool);
4091
4092 ehci_destroy_schedule(ehci);
4093
4094 release_adapter(pdev_ext->padapter);
4095 pdev_ext->padapter = NULL;
4096
4097 ehci_delete_device(pdev);
4098
4099 return FALSE;
4100
4101 }
4102
4103 BOOLEAN
4104 ehci_start(PHCD hcd)
4105 {
4106 ULONG tmp;
4107 PBYTE base;
4108 PEHCI_USBCMD_CONTENT usbcmd;
4109 PEHCI_DEV ehci;
4110
4111 if (hcd == NULL)
4112 return FALSE;
4113
4114 ehci = struct_ptr(hcd, EHCI_DEV, hcd_interf);
4115 base = ehci->port_base;
4116
4117 // stop the controller
4118 tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
4119 usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
4120 usbcmd->run_stop = 0;
4121 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4122
4123 // wait the controller stop( ehci spec, 16 microframe )
4124 usb_wait_ms_dpc(2);
4125
4126 // reset the controller
4127 usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
4128 usbcmd->hcreset = TRUE;
4129 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4130
4131 for(;;)
4132 {
4133 // interval.QuadPart = -100 * 10000; // 10 ms
4134 // KeDelayExecutionThread( KernelMode, FALSE, &interval );
4135 KeStallExecutionProcessor(10);
4136 tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
4137 if (!usbcmd->hcreset)
4138 break;
4139 }
4140
4141 // prepare the registers
4142 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_CTRLDSSEGMENT), 0);
4143
4144 // turn on all the int
4145 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBINTR),
4146 EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
4147 // EHCI_USBINTR_FLROVR | \ // it is noisy
4148 // EHCI_USBINTR_PC | // we detect it by polling
4149 );
4150 // write the list base reg
4151 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_PERIODICLISTBASE), ehci->frame_list_phys_addr.LowPart);
4152
4153 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_ASYNCLISTBASE), ehci->skel_async_qh->phys_addr & ~(0x1f));
4154
4155 usbcmd->int_threshold = 1;
4156 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4157
4158 // let's rock
4159 usbcmd->run_stop = 1;
4160 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4161
4162 // set the configuration flag
4163 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_CONFIGFLAG), 1);
4164
4165 // enable the list traversaling
4166 usbcmd->async_enable = 1;
4167 usbcmd->periodic_enable = 1;
4168 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4169
4170 return TRUE;
4171 }
4172
4173 VOID
4174 ehci_run_stop(PEHCI_DEV ehci, BOOLEAN start)
4175 {
4176 PEHCI_USBCMD_CONTENT usbcmd;
4177 PEHCI_USBSTS_CONTENT usbsts;
4178 ULONG tmp;
4179 PBYTE base;
4180
4181 if (ehci == NULL)
4182 return;
4183
4184 base = ehci->port_base;
4185 usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
4186 usbsts = (PEHCI_USBSTS_CONTENT) & tmp;
4187
4188 tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBSTS));
4189 if (start && usbsts->hc_halted == 0)
4190 {
4191 TRAP();
4192 usb_dbg_print(DBGLVL_MEDIUM, ("ehci_run_stop(): WARNING: hc running, can not start again\n"));
4193 return;
4194 }
4195 tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
4196 usbcmd->run_stop = start ? 1 : 0;
4197 EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
4198 if (start)
4199 usb_wait_ms_dpc(2); //ehci spec 16 microframes
4200 }
4201
4202 VOID
4203 ehci_find_min_bandwidth(PEHCI_DEV ehci)
4204 {
4205 LONG i;
4206 if (ehci == NULL)
4207 return;
4208
4209 for(i = 0; i < (LONG) (ehci->frame_count << 3); i++)
4210 {
4211 ehci->min_bw = ehci->min_bw < ehci->frame_bw[i] ? ehci->min_bw : ehci->frame_bw[i];
4212 }
4213 return;
4214 }
4215
4216 BOOLEAN
4217 ehci_claim_bw_for_int(PEHCI_DEV ehci, PURB purb, BOOLEAN release)
4218 // should have pending_endp_list_lock acquired, and purb->pipe prepared
4219 {
4220 PURB_HS_PIPE_CONTENT pipe_content;
4221 LONG i, j;
4222 ULONG interval, bus_time, ss_time, cs_time;
4223 BOOLEAN bw_avail;
4224 ULONG max_packet_size;
4225
4226 if (ehci == NULL || purb == NULL)
4227 return FALSE;
4228
4229 if (purb->pipe == 0)
4230 return FALSE;
4231
4232 bw_avail = FALSE;
4233 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
4234 interval = REAL_INTERVAL;
4235 if (pipe_content->speed_high == 0)
4236 {
4237 // translate to high speed uframe count
4238 interval <<= 3;
4239 }
4240
4241 if (interval > (ehci->frame_count << 3))
4242 interval = (ehci->frame_count << 3);
4243
4244 max_packet_size = (1 << pipe_content->max_packet_size);
4245 if (pipe_content->speed_high)
4246 {
4247 // this is a high speed endp
4248
4249 bus_time = usb_calc_bus_time(USB_SPEED_HIGH,
4250 (pipe_content->trans_dir) << 7,
4251 FALSE, min(purb->data_length, (LONG) max_packet_size));
4252
4253 // multiple transactions per uframe
4254 if (purb->data_length > (LONG) max_packet_size)
4255 {
4256 bus_time *= (purb->data_length) / max_packet_size;
4257 bus_time += usb_calc_bus_time(USB_SPEED_HIGH,
4258 (pipe_content->trans_dir) << 7,
4259 FALSE, purb->data_length % max_packet_size);
4260 }
4261 bus_time = (bus_time + 1) >> 1;
4262
4263 if (release)
4264 {
4265 for(i = pipe_content->start_uframe + (purb->int_start_frame << 3);
4266 i < (LONG) (ehci->frame_count << 3); i += interval)
4267 {
4268 ehci->frame_bw[i] += (USHORT) bus_time;
4269 }
4270 goto LBL_OUT;
4271 }
4272 if (bus_time < ehci->min_bw)
4273 {
4274 // start the poll from uframe zero of each frame
4275 bw_avail = TRUE;
4276 pipe_content->start_uframe = 0;
4277 for(i = 0; i < (LONG) (ehci->frame_count << 3); i += interval)
4278 {
4279 ehci->frame_bw[i] -= (USHORT) bus_time;
4280 if (ehci->frame_bw[i] < ehci->min_bw)
4281 ehci->min_bw = ehci->frame_bw[i];
4282 }
4283 }
4284 else // bother to find a pattern
4285 {
4286 for(j = 0; j < (LONG) interval; j++)
4287 {
4288 for(i = j; i < (LONG) (ehci->frame_count << 3); i += interval)
4289 {
4290 if (ehci->frame_bw[i] < bus_time)
4291 break;
4292 }
4293 if (i > (LONG) (ehci->frame_count << 3))
4294 {
4295 bw_avail = TRUE;
4296 break;
4297 }
4298 }
4299 if (bw_avail)
4300 {
4301 for(i = j; i < (LONG) (ehci->frame_count << 3); i += interval)
4302 {
4303 ehci->frame_bw[i] -= (USHORT) bus_time;
4304 if (ehci->frame_bw[i] < ehci->min_bw)
4305 ehci->min_bw = ehci->frame_bw[i];
4306 }
4307 pipe_content->start_uframe = j & 7;
4308 purb->int_start_frame = j >> 3;
4309 }
4310 }
4311 }
4312 else // full/low speed pipe
4313 {
4314 // split condition is considered
4315 if (pipe_content->trans_dir)
4316 {
4317 // an input interrupt, with handshake
4318 // 55 is 144 - 90 + 1, turnaround time is one byte not the worst case 90 bytes,
4319 // refer to ehci-1.0 table 4-5 p64
4320 ss_time = 231 * 25 / 12;
4321 // cs_time = ( 55 * 8 + ( LONG )( ( ( 19 + 7 * 8 * purb->data_length ) / 6 ) ) ) * 25 / 12;
4322 cs_time = (55 * 8 + (LONG) (((7 * 8 * purb->data_length) / 6))) * 25 / 12;
4323 }
4324 else
4325 {
4326 // according to ehci-1.0 table 4-5 p64
4327 ss_time = (49 * 8 + (LONG) (((7 * 8 * purb->data_length) / 6))) * 25 / 12;
4328 // 287 = 237 + 48( handshake ) + 8( turn around time )
4329 cs_time = 287 * 25 / 12;
4330 }
4331 ss_time >>= 1, cs_time >>= 1;
4332 if (release)
4333 {
4334 for(i = pipe_content->start_uframe + (purb->int_start_frame << 3);
4335 i < (LONG) (ehci->frame_count << 3); i += interval)
4336 {
4337 ehci->frame_bw[i] += (USHORT) ss_time;
4338 ehci->frame_bw[i + 2] += (USHORT) cs_time;
4339 ehci->frame_bw[i + 3] += (USHORT) cs_time;
4340 if ((i & 0x07) != 0x06)
4341 ehci->frame_bw[i + 4] += (USHORT) cs_time;
4342 }
4343 goto LBL_OUT;
4344 }
4345 if (ss_time < ehci->min_bw && cs_time < ehci->min_bw)
4346 {
4347 pipe_content->start_uframe = 0;
4348 bw_avail = TRUE;
4349 for(i = 0; i < (LONG) (ehci->frame_count << 3); i += interval)
4350 {
4351 ehci->frame_bw[i] -= (USHORT) ss_time;
4352 ehci->min_bw = min(ehci->frame_bw[i], ehci->min_bw);
4353 ehci->frame_bw[i + 2] -= (USHORT) cs_time;
4354 ehci->min_bw = min(ehci->frame_bw[i + 2], ehci->min_bw);
4355 ehci->frame_bw[i + 3] -= (USHORT) cs_time;
4356 ehci->min_bw = min(ehci->frame_bw[i + 3], ehci->min_bw);
4357 if ((i & 0x07) != 0x06)
4358 {
4359 ehci->frame_bw[i + 4] -= (USHORT) cs_time;
4360 ehci->min_bw = min(ehci->frame_bw[i + 4], ehci->min_bw);
4361 }
4362 }
4363 }
4364 else
4365 {
4366 for(j = 0; j < (LONG) interval; j++)
4367 {
4368 if ((j & 0x7) == 7) // start-split not allowed at this uframe
4369 continue;
4370
4371 for(i = j; i < (LONG) (ehci->frame_count << 3); i += interval)
4372 {
4373 if (ehci->frame_bw[i] < ss_time)
4374 break;
4375 if (ehci->frame_bw[i + 2] < cs_time)
4376 break;
4377 if (ehci->frame_bw[i + 3] < cs_time)
4378 break;
4379 if ((i & 0x7) != 6)
4380 if (ehci->frame_bw[i + 4] < cs_time)
4381 break;
4382 }
4383 if (i > (LONG) (ehci->frame_count << 3))
4384 {
4385 bw_avail = TRUE;
4386 break;
4387 }
4388 }
4389
4390 pipe_content->start_uframe = j & 7;
4391 purb->int_start_frame = j >> 3;
4392
4393 for(i = j; i < (LONG) (ehci->frame_count << 3); i += interval)
4394 {
4395 ehci->frame_bw[i] -= (USHORT) ss_time;
4396 ehci->min_bw = min(ehci->frame_bw[i], ehci->min_bw);
4397 ehci->frame_bw[i + 2] -= (USHORT) cs_time;
4398 ehci->min_bw = min(ehci->frame_bw[i + 2], ehci->min_bw);
4399 ehci->frame_bw[i + 3] -= (USHORT) cs_time;
4400 ehci->min_bw = min(ehci->frame_bw[i + 3], ehci->min_bw);
4401 if ((i & 0x7) != 6)
4402 {
4403 ehci->frame_bw[i + 4] -= (USHORT) cs_time;
4404 ehci->min_bw = min(ehci->frame_bw[i + 4], ehci->min_bw);
4405 }
4406 }
4407 }
4408 }
4409
4410 LBL_OUT:
4411 if (!release)
4412 return bw_avail;
4413 else
4414 {
4415 ehci_find_min_bandwidth(ehci);
4416 return TRUE;
4417 }
4418 }
4419
4420 LONG
4421 ehci_get_cache_policy(PEHCI_DEV ehci)
4422 {
4423 PEHCI_HCC_CONTENT hcc_content;
4424
4425 hcc_content = (PEHCI_HCC_CONTENT) & ehci->ehci_caps;
4426 if (hcc_content->iso_sched_threshold >= 8)
4427 return 16;
4428 if (hcc_content->iso_sched_threshold == 0)
4429 return 2;
4430 return hcc_content->iso_sched_threshold + 2;
4431 }
4432
4433 // 25/12 is bus-time per bit ( 1000 / 480 )
4434 #define BEST_BUDGET_TIME_UFRAME ( ( 188 * 7 / 6 ) * 25 / 12 )
4435
4436 // in: 231 is sum of split token + host ipg + token, 8 is bus turn-around time, 67 is full speed data token in DATA packet
4437 // out: 49 byte is sum of split token+ host ipg + token + host ipg + data packet
4438 #define iso_max_data_load( dir ) ( dir == USB_DIR_IN ? \
4439 ( ( 188 * 8 - 231 - 8 - 67 + ( 8 - 1 ) ) / 8 ) : ( 188 - 49 ) )
4440
4441 #define iso_uframes_data_load( dir, data_load, uf_cnt )
4442
4443 BOOLEAN
4444 ehci_claim_bw_for_iso(PEHCI_DEV ehci, PURB purb, BOOLEAN release)
4445 {
4446 PURB_HS_PIPE_CONTENT pipe_content;
4447 LONG i, j, k;
4448 ULONG interval, bus_time, ss_time, cs_time, remainder;
4449 BOOLEAN bw_avail;
4450 ULONG cur_uframe, start_uframe = 0, max_time, max_packet_size;
4451 PBYTE base;
4452 if (ehci == NULL || purb == NULL)
4453 return FALSE;
4454
4455 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
4456 base = ehci->port_base;
4457 cur_uframe = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_FRINDEX)) + 1;
4458 bw_avail = FALSE;
4459
4460 max_packet_size = purb->params[0]; //( 1 << pipe_content->max_packet_size );
4461
4462 if (pipe_content->speed_high)
4463 {
4464 interval = REAL_INTERVAL;
4465 if (purb->iso_frame_count == 0 || purb->iso_frame_count + 2 * 8 > (LONG) (ehci->frame_count << 3))
4466 return FALSE;
4467
4468 for(i = 0, max_time = 0; i < (LONG) purb->iso_frame_count; i++)
4469 {
4470 bus_time = usb_calc_bus_time(USB_SPEED_HIGH,
4471 (pipe_content->trans_dir) << 7,
4472 TRUE, min(purb->iso_packet_desc[i].length, (LONG) max_packet_size));
4473 // NOTE: we did not use endp_mult_count here, because the comparison is enough
4474 // to calculate the bandwidth
4475 if (purb->iso_packet_desc[i].length > (LONG) max_packet_size)
4476 {
4477 // multiple transactions per uframe
4478 bus_time *= purb->iso_packet_desc[i].length / max_packet_size;
4479 bus_time += usb_calc_bus_time(USB_SPEED_HIGH,
4480 (pipe_content->trans_dir) << 7,
4481 TRUE, purb->iso_packet_desc[i].length % max_packet_size);
4482 }
4483 bus_time = (bus_time + 1) >> 1;
4484 max_time = max(bus_time, max_time);
4485 purb->iso_packet_desc[i].bus_time = bus_time;
4486 }
4487
4488 if (release)
4489 {
4490 // it is a release operation
4491 for(i = purb->iso_start_frame, k = 0; k < (LONG) purb->iso_frame_count;
4492 k++, i = (i + interval) % (ehci->frame_count << 3))
4493 {
4494 ehci->frame_bw[i] += (USHORT) purb->iso_packet_desc[k].bus_time;
4495 }
4496 ehci_find_min_bandwidth(ehci);
4497 return TRUE;
4498 }
4499
4500 if (max_time < ehci->min_bw)
4501 {
4502 start_uframe = cur_uframe + ehci_get_cache_policy(ehci); // avoid cache
4503 for(i = start_uframe, j = 0; j < (LONG) purb->iso_frame_count;
4504 i = (i + interval) % (ehci->frame_count << 3), j++)
4505 {
4506 ehci->frame_bw[i] -= (USHORT) purb->iso_packet_desc[j].bus_time;
4507 ehci->min_bw = min(ehci->frame_bw[j], ehci->min_bw);
4508 }
4509 purb->iso_start_frame = start_uframe;
4510 return TRUE;
4511 }
4512 else // max_time >= ehci->min_bw
4513 {
4514 for(j = 0; j < (LONG) interval; j++)
4515 {
4516 start_uframe = cur_uframe + ehci_get_cache_policy(ehci) + j;
4517 for(i = start_uframe, k = 0; k < (LONG) purb->iso_frame_count;
4518 k++, i = (i + interval) % (ehci->frame_count << 3))
4519 {
4520 if (ehci->frame_bw[i] < (USHORT) purb->iso_packet_desc[k].bus_time)
4521 {
4522 break;
4523 }
4524 }
4525
4526 if (k < (LONG) purb->iso_frame_count)
4527 continue;
4528 bw_avail = TRUE;
4529 break;
4530 }
4531 if (bw_avail)
4532 {
4533 // allocate the bandwidth
4534 for(i = start_uframe, k = 0; k < (LONG) purb->iso_frame_count;
4535 k++, i = (i + interval) % (ehci->frame_count << 3))
4536 {
4537 ehci->frame_bw[i] -= (USHORT) purb->iso_packet_desc[k].bus_time;
4538 ehci->min_bw = min(ehci->min_bw, ehci->frame_bw[i]);
4539 }
4540 purb->iso_start_frame = start_uframe;
4541 }
4542 }
4543 }
4544 else // not high speed endpoint
4545 {
4546 // split transfer
4547 if (purb->iso_frame_count == 0 || purb->iso_frame_count + 2 > (LONG) ehci->frame_count)
4548 return FALSE;
4549
4550 if (max_packet_size > 1023)
4551 return FALSE;
4552
4553 remainder = 0;
4554
4555 //
4556 // calculate for each frame
4557 // in: 231 is sum of split token + host ipg + token, 8 is bus turn-around time, 67 is full speed data token in DATA packet
4558 // out: 49 byte is sum of split token+ host ipg + token + host ipg + data packet
4559 // bit-stuffing is for high speed bus transfer
4560 //
4561
4562 if (pipe_content->trans_dir)
4563 {
4564 // an input transfer, no handshake
4565 ss_time = 231 * 25 / 12;
4566 // cs_time = ( 231 + 8 + 67 + ( LONG )( ( ( 19 + 7 * 8 * 188 ) / 6 ) ) ) * 25 / 12;
4567 cs_time = (231 + 8 + 67 + (LONG) (((7 * 8 * 188) / 6))) * 25 / 12;
4568 }
4569 else
4570 {
4571 // an output transfer according to ehci-1.0 table 4-5 p64
4572 // ss_time = ( 49 * 8 + ( LONG )( ( ( 19 + 7 * 8 * 188 ) / 6 ) ) ) * 25 / 12;
4573 ss_time = (49 * 8 + (LONG) (((7 * 8 * 188) / 6))) * 25 / 12;
4574 cs_time = 0;
4575 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4576 {
4577 // remainder = ( 49 * 8 + ( LONG )( ( ( 19 + 7 * 8 * ( purb->iso_packet_desc[ i ].length % 188 ) ) / 6 ) ) ) * 25 / 12;
4578 remainder =
4579 (49 * 8 + (LONG) (((7 * 8 * (purb->iso_packet_desc[i].length % 188)) / 6))) * 25 / 12;
4580 remainder >>= 1;
4581 purb->iso_packet_desc[i].params.bus_time = (USHORT) remainder;
4582 }
4583 }
4584
4585 ss_time >>= 1;
4586 cs_time >>= 1;
4587 cur_uframe = (cur_uframe + 7) & (~0x07);
4588
4589 j = ehci->frame_count << 3;
4590 if (release)
4591 {
4592 if (pipe_content->trans_dir)
4593 {
4594 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4595 {
4596 ehci->frame_bw[purb->iso_packet_desc[i].params.start_uframe] += (USHORT) ss_time;
4597 for(k = 0; k < (purb->iso_packet_desc[i].length + 187) / 188; k++)
4598 {
4599 ehci->frame_bw[(cur_uframe + 0x12 + (i << 3) + k) % j] += (USHORT) cs_time;
4600 }
4601
4602 // two extra complete-split
4603 ehci->frame_bw[(cur_uframe + 0x12 + (i << 3) + k) % j] += (USHORT) cs_time;
4604 ehci->frame_bw[(cur_uframe + 0x13 + (i << 3) + k) % j] += (USHORT) cs_time;
4605 }
4606 }
4607 else
4608 {
4609 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4610 {
4611 for(k = 0; k < (purb->iso_packet_desc[i].length + 187) / 188; k++)
4612 {
4613 ehci->frame_bw[(cur_uframe + 0x10 + (i << 3) + k) % j] += (USHORT) ss_time;
4614 }
4615 }
4616 }
4617 ehci_find_min_bandwidth(ehci);
4618 }
4619
4620 // search for available bw
4621 if (ss_time < ehci->min_bw && cs_time < ehci->min_bw)
4622 {
4623 if (pipe_content->trans_dir)
4624 {
4625 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4626 {
4627 ehci->frame_bw[(cur_uframe + 0x10 + (i << 3)) % j] -= (USHORT) ss_time;
4628 ehci->min_bw = min(ehci->frame_bw[(cur_uframe + 0x10 + (i << 3)) % j], ehci->min_bw);
4629
4630 for(k = 0; k < (purb->iso_packet_desc[i].length + 187) / 188; k++)
4631 {
4632 ehci->frame_bw[(cur_uframe + 0x12 + (i << 3) + k) % j] -= (USHORT) cs_time;
4633 ehci->min_bw =
4634 min(ehci->frame_bw[(cur_uframe + 0x12 + (i << 3) + k) % j], ehci->min_bw);
4635 }
4636
4637 // two extra complete-split
4638 ehci->frame_bw[(cur_uframe + 0x12 + (i << 3) + k) % j] -= (USHORT) cs_time;
4639 ehci->min_bw = min(ehci->frame_bw[cur_uframe + 0x12 + (i << 3) + k], ehci->min_bw);
4640 ehci->frame_bw[(cur_uframe + 0x13 + (i << 3) + k) % j] -= (USHORT) cs_time;
4641 ehci->min_bw = min(ehci->frame_bw[cur_uframe + 0x13 + (i << 3) + k], ehci->min_bw);
4642 }
4643 }
4644 else // iso output
4645 {
4646 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4647 {
4648 for(k = 0; k < (purb->iso_packet_desc[i].length + 187) / 188; k++)
4649 {
4650 ehci->frame_bw[(cur_uframe + 0x10 + (i << 3) + k) % j] -= (USHORT) ss_time;
4651 ehci->min_bw =
4652 min(ehci->frame_bw[(cur_uframe + 0x11 + (i << 3) + k) % j], ehci->min_bw);
4653 }
4654 }
4655 }
4656 purb->iso_start_frame = 0;
4657 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4658 {
4659 if (i == 0)
4660 purb->iso_packet_desc[i].params.start_uframe = (USHORT) (cur_uframe + 0x10);
4661 else
4662 purb->iso_packet_desc[i].params.start_uframe =
4663 purb->iso_packet_desc[i - 1].params.start_uframe + 0x8;
4664 }
4665 bw_avail = TRUE;
4666 }
4667 else // take the pain to find one
4668 {
4669 BOOLEAN large;
4670 long temp, base;
4671
4672 for(j = (cur_uframe >> 3) + 2; j != (LONG) (cur_uframe >> 3); j = (j + 1) % ehci->frame_count)
4673 {
4674 temp = 0;
4675
4676 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4677 {
4678 large = purb->iso_packet_desc[i].length > 579;
4679 base = (purb->iso_packet_desc[i].length + 187) / 188;
4680
4681 if (base > 6)
4682 return FALSE;
4683
4684 if (pipe_content->trans_dir)
4685 {
4686 // input split iso, for those large than 579, schedule it at the uframe boundary
4687 for(temp = 0; temp < (large == FALSE) ? (8 - base - 1) : 1; temp++)
4688 {
4689 k = (((j + i) << 3) + temp) % (ehci->frame_count << 3);
4690 if (ehci->frame_bw[k] > ss_time)
4691 continue;
4692
4693 k = base;
4694 while (k != 0)
4695 {
4696 if (ehci->
4697 frame_bw[(((j + i) << 3) + 1 + temp + k) % (ehci->frame_count << 3)] <
4698 cs_time)
4699 break;
4700 k--;
4701 }
4702 if (k > 0) // not available
4703 continue;
4704
4705 // the first following extra cs
4706 k = (((j + i) << 3) + 2 + temp + base) % (ehci->frame_count << 3);
4707 if (ehci->frame_bw[k] < cs_time)
4708 continue;
4709
4710 if (base < 6)
4711 {
4712 // very large one does not have this second extra cs
4713 if (ehci->frame_bw[(k + 1) % (ehci->frame_count << 3)] < cs_time)
4714 continue;
4715 }
4716 }
4717
4718 if (temp == 8 - 1 - base) // no bandwidth for ss
4719 break;
4720 }
4721 else // output
4722 {
4723 // note: 8 - 1 - base has different meaning from the above
4724 // it is to avoid the ss on H-Frame 7, but the above one is
4725 // the latency of the classic bus.
4726 for(temp = 0; temp < 8 - 1 - base; temp++)
4727 {
4728 if (ehci->frame_bw[((j + i) << 3) % (ehci->frame_count << 3) + temp] > ss_time)
4729 continue;
4730
4731 for(k = temp; k < temp + base; k++)
4732 {
4733 if (ehci->frame_bw[((j + i) << 3) % (ehci->frame_count << 3) + k] < ss_time)
4734 break;
4735 }
4736 }
4737
4738 if (temp == 8 - 1 - base)
4739 break;
4740 }
4741
4742 purb->iso_packet_desc[i].params.start_uframe =
4743 (USHORT) ((((j + i) << 3) + temp) % (ehci->frame_count << 3));
4744 // next frame
4745 }
4746 if (i < (LONG) purb->iso_frame_count)
4747 {
4748 // skip to the next section
4749 j = (j + i) % (ehci->frame_count << 3);
4750 continue;
4751 }
4752 bw_avail = TRUE;
4753 break;
4754 }
4755 // FIXME: Should we claim bw for the last complete split sitd? this is not done
4756 // yet.
4757 if (bw_avail)
4758 {
4759 if (pipe_content->trans_dir)
4760 {
4761 // input iso
4762 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4763 {
4764 j = purb->iso_packet_desc[i].length;
4765 temp = (purb->iso_packet_desc[i].params.start_uframe) % (ehci->frame_count << 3);
4766 ehci->frame_bw[temp] -= (USHORT) ss_time;
4767 for(k = 0; k < (j + 187) / 188; j++)
4768 {
4769 ehci->frame_bw[temp + 2 + k] -= (USHORT) cs_time;
4770 }
4771 ehci->frame_bw[temp + 2 + k] -= (USHORT) cs_time;
4772 if ((j + 187) / 188 < 6) //ehci restriction
4773 {
4774 ehci->frame_bw[temp + 3 + k] -= (USHORT) cs_time;
4775 }
4776 }
4777 }
4778 else //output iso
4779 {
4780 for(i = 0; i < (LONG) purb->iso_frame_count; i++)
4781 {
4782 j = purb->iso_packet_desc[i].length;
4783 temp = (purb->iso_packet_desc[i].params.start_uframe) % (ehci->frame_count << 3);
4784 for(k = 0; k < j / 188; j++)
4785 {
4786 ehci->frame_bw[temp + k] -= (USHORT) ss_time;
4787 }
4788 if (j % 188)
4789 ehci->frame_bw[temp + k] -= purb->iso_packet_desc[i].params.bus_time;
4790 }
4791 }
4792 }
4793 }
4794 }
4795 return bw_avail;
4796 }
4797
4798 BOOLEAN
4799 ehci_claim_bandwidth(PEHCI_DEV ehci, PURB purb, BOOLEAN claim_bw) //true to claim band-width, false to free band-width
4800 // should have pending_endp_list_lock acquired, and purb->pipe prepared
4801 {
4802 PURB_HS_PIPE_CONTENT pipe_content;
4803 BOOLEAN ret;
4804
4805 if (ehci == NULL || purb == NULL)
4806 return FALSE;
4807
4808 ret = FALSE;
4809 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
4810 if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
4811 {
4812 ret = ehci_claim_bw_for_iso(ehci, purb, claim_bw ? FALSE : TRUE);
4813 }
4814 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT)
4815 {
4816 ret = ehci_claim_bw_for_int(ehci, purb, claim_bw ? FALSE : TRUE);
4817 }
4818 else
4819 TRAP();
4820 return ret;
4821 }
4822
4823 BOOLEAN
4824 ehci_can_remove(PURB purb, BOOLEAN door_bell_rings, ULONG cur_frame)
4825 // test if the purb can be removed from the schedule, by current frame index and
4826 // purb states
4827 {
4828 PURB_HS_PIPE_CONTENT pipe_content;
4829 ULONG interval;
4830
4831 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
4832 interval = REAL_INTERVAL;
4833
4834 switch (purb->flags & URB_FLAG_STATE_MASK)
4835 {
4836 case URB_FLAG_STATE_PENDING:
4837 {
4838 // not impossible
4839 TRAP();
4840 break;
4841 }
4842 case URB_FLAG_STATE_IN_PROCESS:
4843 {
4844 break;
4845 }
4846 case URB_FLAG_STATE_DOORBELL:
4847 {
4848 if ((pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
4849 pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL) && door_bell_rings == TRUE)
4850 {
4851 return TRUE;
4852 }
4853 else if ((pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
4854 pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL))
4855 {
4856 break;
4857 }
4858 else
4859 {
4860 TRAP();
4861 break;
4862 }
4863 }
4864 case URB_FLAG_STATE_WAIT_FRAME:
4865 {
4866 // need more processing
4867 if ((purb->flags & URB_FLAG_FORCE_CANCEL) == 0)
4868 {
4869 TRAP();
4870 break;
4871 }
4872 if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT)
4873 {
4874 return door_bell_rings;
4875 }
4876 else // isochronous can not be canceled
4877 {
4878 TRAP();
4879 break;
4880 }
4881 }
4882 }
4883 return FALSE;
4884 }
4885
4886 NTSTATUS ehci_remove_urb_from_schedule(PEHCI_DEV ehci, PURB purb);
4887
4888 static VOID
4889 ehci_deactivate_urb(PURB purb)
4890 {
4891 PURB_HS_PIPE_CONTENT pipe_content;
4892 PLIST_ENTRY pthis, pnext;
4893 PEHCI_QH_CONTENT pqh_content;
4894 PEHCI_QTD_CONTENT pqtd_content;
4895
4896 if (purb == NULL)
4897 return;
4898
4899 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
4900 switch (pipe_content->trans_type)
4901 {
4902 case USB_ENDPOINT_XFER_CONTROL:
4903 case USB_ENDPOINT_XFER_BULK:
4904 case USB_ENDPOINT_XFER_INT:
4905 {
4906 ListFirst(&purb->trasac_list, pthis);
4907 pqh_content = (PEHCI_QH_CONTENT) qh_from_list_entry(pthis);
4908 ListNext(&purb->trasac_list, pthis, pnext);
4909 do
4910 {
4911 pqtd_content = (PEHCI_QTD_CONTENT) qtd_from_list_entry(pthis);
4912 if (pqtd_content->status & QTD_STS_ACTIVE)
4913 {
4914 pqtd_content->status &= ~QTD_STS_ACTIVE;
4915 }
4916 ListNext(&purb->trasac_list, pthis, pnext);
4917 pthis = pnext;
4918
4919 }
4920 while (pthis);
4921 break;
4922 }
4923 case USB_ENDPOINT_XFER_ISOC:
4924 {
4925 // fall through
4926 }
4927 default:
4928 TRAP();
4929 }
4930 return;
4931 }
4932
4933 static VOID
4934 ehci_insert_bulk_schedule(PEHCI_DEV ehci, PURB purb)
4935 // list head is only a handle, the qh and qtd are following it.
4936 {
4937 PLIST_ENTRY list_head;
4938 PEHCI_QH pqh, pqhprev, pqhnext;
4939 PLIST_ENTRY pthis, pprev, pnext;
4940
4941 if (ehci == NULL || purb == NULL)
4942 return;
4943
4944 list_head = &purb->trasac_list;
4945 ListFirst(list_head, pthis);
4946 if (pthis == NULL)
4947 return;
4948
4949 if (elem_type_list_entry(pthis) != INIT_LIST_FLAG_QH)
4950 return;
4951
4952 pqh = qh_from_list_entry(pthis);
4953 // the last qh
4954 ListFirstPrev(&ehci->async_list_cpu, pprev);
4955 pqhprev = qh_from_schedule(pprev);
4956
4957 // the first qh
4958 ListFirst(&ehci->async_list_cpu, pnext);
4959 pqhnext = qh_from_schedule(pnext);
4960
4961 if (pprev == &ehci->async_list_cpu)
4962 {
4963 // always a qh in async list
4964 TRAP();
4965 return;
4966 }
4967 pqh->hw_next = pqhnext->phys_addr;
4968 InsertTailList(&ehci->async_list_cpu, &pqh->elem_head_link->sched_link);
4969 pqhprev->hw_next = pqh->phys_addr;
4970 return;
4971 }
4972
4973 static VOID
4974 ehci_remove_bulk_from_schedule(PEHCI_DEV ehci, PURB purb)
4975 // executed in isr, and have frame_list_lock acquired, so
4976 // never try to acquire any spin-lock
4977 // remove the bulk purb from schedule, and mark it not in
4978 // the schedule
4979 {
4980 PLIST_ENTRY list_head;
4981 PEHCI_QH pqh, pqhprev, pqhnext;
4982 PEHCI_QH_CONTENT pqhc;
4983 PLIST_ENTRY pthis, pprev, pnext;
4984
4985 if (ehci == NULL || purb == NULL)
4986 return;
4987
4988 list_head = &purb->trasac_list;
4989 ListFirst(list_head, pthis);
4990 if (pthis == NULL)
4991 {
4992 TRAP();
4993 return;
4994 }
4995 pqh = qh_from_list_entry(pthis);
4996 pqhc = (PEHCI_QH_CONTENT) pqh;
4997
4998 if (pqhc->is_async_head)
4999 TRAP();
5000
5001 ListFirst(&pqh->elem_head_link->sched_link, pnext);
5002 ListFirstPrev(&pqh->elem_head_link->sched_link, pprev);
5003
5004 if (pprev == &ehci->async_list_cpu)
5005 {
5006 // we will at least have a qh with H-bit 1 in the async-list
5007 TRAP();
5008 }
5009 else if (pnext == &ehci->async_list_cpu)
5010 {
5011 // remove the last one
5012 pqhprev = qh_from_schedule(pprev);
5013 ListFirst(&ehci->async_list_cpu, pnext);
5014 pqhnext = qh_from_schedule(pnext);
5015 pqhprev->hw_next = pqhnext->phys_addr;
5016 }
5017 else
5018 {
5019 pqhprev = qh_from_schedule(pprev);
5020 pqhnext = qh_from_schedule(pnext);
5021 pqhprev->hw_next = pqhnext->phys_addr;
5022 }
5023 RemoveEntryList(&pqh->elem_head_link->sched_link);
5024 return;
5025 }
5026
5027
5028 static VOID
5029 ehci_insert_fstn_schedule(PEHCI_DEV ehci, PURB purb)
5030 {
5031
5032 PURB_HS_PIPE_CONTENT pipe_content, pc;
5033 PLIST_ENTRY pthis, list_head, pnext = NULL, pprev;
5034 PEHCI_QH pqhnext;
5035 PEHCI_FSTN pfstn;
5036 PURB purb1;
5037
5038 ULONG interval, start_frame, start_uframe;
5039 LONG i;
5040
5041 if (ehci == NULL || purb == NULL)
5042 return;
5043
5044 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5045 interval = (1 << (pipe_content->interval + 3));
5046 list_head = &purb->trasac_list;
5047 start_frame = purb->int_start_frame;
5048 start_uframe = (start_frame << 3) + 1; //( start_frame << 3 ) + pipe_content->start_uframe;
5049
5050 if ((start_frame << 3) >= interval)
5051 TRAP();
5052
5053 ListFirstPrev(list_head, pprev);
5054
5055 if (elem_type_list_entry(pprev) != INIT_LIST_FLAG_FSTN)
5056 {
5057 TRAP();
5058 return;
5059 }
5060
5061 pfstn = fstn_from_list_entry(pprev);
5062
5063 if (interval == 8)
5064 {
5065 ListFirst(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX], pthis);
5066
5067 // skip the first one
5068 ListNext(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX], pthis, pnext);
5069 pprev = pthis;
5070 pthis = pnext;
5071
5072 while (pthis)
5073 {
5074 purb1 = qh_from_schedule(pthis)->elem_head_link->purb;
5075 pc = (PURB_HS_PIPE_CONTENT) & purb1->pipe;
5076 if (pc->speed_high)
5077 {
5078 TRAP();
5079 return;
5080 }
5081 if ((1 << (pc->interval + 3)) > (LONG) interval)
5082 {
5083 TRAP();
5084 continue;
5085 }
5086 else if ((1 << (pc->interval + 3) < (LONG) interval))
5087 {
5088 break;
5089 }
5090 else if (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN)
5091 {
5092 ListNext(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX], pthis, pnext);
5093 pprev = pthis;
5094 pthis = pnext;
5095 }
5096 else if (pc->start_uframe <= 1)
5097 {
5098 ListNext(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX], pthis, pnext);
5099 pprev = pthis;
5100 pthis = pnext;
5101 }
5102 break;
5103 }
5104 if (pprev == NULL)
5105 {
5106 TRAP();
5107 return;
5108 }
5109 if (pthis == NULL)
5110 {
5111 //the last one
5112 InsertTailList(&ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX],
5113 &pfstn->elem_head_link->sched_link);
5114 }
5115 else
5116 {
5117 if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_FSTN)
5118 {
5119 InsertHeadList(&fstn_from_schedule(pprev)->elem_head_link->sched_link,
5120 &pfstn->elem_head_link->sched_link);
5121 }
5122 else
5123 {
5124 InsertHeadList(&qh_from_schedule(pprev)->elem_head_link->sched_link,
5125 &pfstn->elem_head_link->sched_link);
5126 }
5127 }
5128 pfstn->hw_next = qh_from_schedule(pprev)->hw_next;
5129 qh_from_schedule(pprev)->hw_next = pfstn->phys_addr;
5130 }
5131 else
5132 {
5133 start_frame++;
5134 for(i = start_frame; i < (LONG) start_frame + 1; i += (interval >> 3))
5135 {
5136 list_head = &ehci->frame_list_cpu[i].td_link;
5137 ListFirst(list_head, pthis);
5138
5139 pprev = list_head;
5140 while (pthis)
5141 {
5142 // skip itds and sitds
5143 if (elem_type(pthis, FALSE) == INIT_LIST_FLAG_ITD ||
5144 elem_type(pthis, FALSE) == INIT_LIST_FLAG_SITD)
5145 {
5146 ListNext(list_head, pthis, pnext);
5147 pprev = pthis;
5148 pthis = pnext;
5149 continue;
5150 }
5151 break;
5152 }
5153
5154 while (pthis)
5155 {
5156 // find the insertion point
5157 ULONG u;
5158
5159 pqhnext = qh_from_schedule(pthis);
5160 if (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN)
5161 purb1 = fstn_from_schedule(pthis)->elem_head_link->purb;
5162 else
5163 purb1 = pqhnext->elem_head_link->purb;
5164
5165 if (purb1 == NULL)
5166 TRAP();
5167
5168 pc = (PURB_HS_PIPE_CONTENT) & purb1->pipe;
5169 u = 1 << (pc->speed_high ? (1 << pc->interval) : (1 << (pc->interval + 3)));
5170
5171 if (u > interval)
5172 {
5173 ListNext(list_head, pthis, pnext);
5174 pprev = pthis;
5175 pthis = pnext;
5176 continue;
5177 }
5178 else if (u == interval)
5179 {
5180 if (start_uframe >=
5181 (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN ?
5182 1 : pc->start_uframe) + (purb1->int_start_frame << 3))
5183 {
5184 ListNext(list_head, pthis, pnext);
5185 pprev = pthis;
5186 pthis = pnext;
5187 continue;
5188 }
5189 else
5190 break;
5191 }
5192 else if (u < interval)
5193 {
5194 break;
5195 }
5196 }
5197
5198 if (pprev == list_head)
5199 {
5200 // insert to the list head
5201 pnext = pfstn->elem_head_link->sched_link.Flink = list_head->Flink;
5202 list_head->Flink = &pfstn->elem_head_link->sched_link;
5203 pfstn->hw_next = ehci->frame_list[i]; // point to following node
5204 ehci->frame_list[i] = pfstn->phys_addr;
5205 }
5206 else
5207 {
5208 pnext = pfstn->elem_head_link->sched_link.Flink = pprev->Flink;
5209 pprev->Flink = &pfstn->elem_head_link->sched_link;
5210
5211 // fstn can be handled correctly
5212 pfstn->hw_next = qh_from_schedule(pprev)->hw_next;
5213 qh_from_schedule(pprev)->hw_next = pfstn->phys_addr;
5214 }
5215 }
5216 // the pointer to next node of this fstn is alway same across the frame list.
5217 for(i = start_frame + (interval >> 3); i < (LONG) ehci->frame_count; i += (interval >> 3))
5218 {
5219 pprev = list_head = &ehci->frame_list_cpu[i].td_link;
5220 ListFirst(list_head, pthis);
5221
5222 while (pthis)
5223 {
5224 if (pthis == pnext)
5225 {
5226 break;
5227 }
5228 pprev = pthis;
5229 ListNext(list_head, pthis, pthis);
5230 }
5231
5232 pprev->Flink = &pfstn->elem_head_link->sched_link;
5233 if (pprev == list_head)
5234 ehci->frame_list[i] = pfstn->phys_addr;
5235 else
5236 qh_from_schedule(pprev)->hw_next = pfstn->phys_addr;
5237 }
5238 }
5239 }
5240
5241 static VOID
5242 ehci_remove_fstn_from_schedule(PEHCI_DEV ehci, PURB purb)
5243 {
5244 PURB_HS_PIPE_CONTENT pipe_content;
5245 PLIST_ENTRY pthis, list_head, pnext, pprev;
5246 PEHCI_FSTN pfstn;
5247
5248 ULONG interval, start_frame, start_uframe;
5249 LONG i;
5250
5251 if (ehci == NULL || purb == NULL)
5252 return;
5253
5254 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5255 interval = (1 << (pipe_content->interval + 3));
5256 list_head = &purb->trasac_list;
5257 start_frame = purb->int_start_frame;
5258 start_uframe = 1;
5259
5260 if ((start_frame << 3) >= interval)
5261 TRAP();
5262 start_frame++;
5263
5264 ListFirstPrev(list_head, pprev);
5265 if (elem_type_list_entry(pprev) != INIT_LIST_FLAG_FSTN)
5266 {
5267 TRAP();
5268 return;
5269 }
5270
5271 pfstn = fstn_from_list_entry(pprev);
5272 if (interval < 8)
5273 {
5274 TRAP();
5275 return;
5276 }
5277 if (interval == 8)
5278 {
5279 ListFirstPrev(&pfstn->elem_head_link->sched_link, pprev);
5280 qh_from_schedule(pprev)->hw_next = pfstn->hw_next;
5281 RemoveEntryList(&pfstn->elem_head_link->sched_link);
5282 }
5283 else
5284 {
5285 for(i = start_frame; i < (LONG) ehci->frame_count; i++)
5286 {
5287 ListFirst(&ehci->frame_list_cpu[i].td_link, pthis);
5288 if (pthis == NULL)
5289 {
5290 TRAP();
5291 return;
5292 }
5293 pprev = &ehci->frame_list_cpu[i].td_link;
5294 while (pthis && pthis != &pfstn->elem_head_link->sched_link)
5295 {
5296 pprev = pthis;
5297 ListNext(&ehci->frame_list_cpu[i].td_link, pthis, pnext);
5298 pthis = pnext;
5299 }
5300 if (pthis == NULL)
5301 {
5302 TRAP();
5303 return;
5304 }
5305 qh_from_schedule(pprev)->hw_next = pfstn->hw_next;
5306 pprev->Flink = pfstn->elem_head_link->sched_link.Flink;
5307 }
5308 }
5309 return;
5310 }
5311
5312 static VOID
5313 ehci_insert_int_schedule(PEHCI_DEV ehci, PURB purb)
5314 {
5315 PURB_HS_PIPE_CONTENT pipe_content, pc;
5316 PLIST_ENTRY pthis, list_head, pnext = NULL, pprev;
5317 PEHCI_ELEM_LINKS elem_link;
5318 PEHCI_QH pqh, pqhprev, pqhnext;
5319 PURB purb1;
5320
5321 ULONG interval, u, start_frame, start_uframe;
5322 LONG i;
5323 UCHAR need_fstn;
5324
5325 if (ehci == NULL || purb == NULL)
5326 return;
5327
5328 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5329 interval = REAL_INTERVAL;
5330 start_uframe = (purb->int_start_frame << 3) + pipe_content->start_uframe;
5331 start_frame = purb->int_start_frame;
5332 need_fstn = FALSE;
5333 list_head = &purb->trasac_list;
5334
5335 ListFirst(list_head, pthis);
5336 if (pthis == NULL)
5337 return;
5338
5339 pqh = qh_from_list_entry(pthis);
5340
5341 if (!pipe_content->speed_high)
5342 {
5343 interval = (interval << 3);
5344 ListFirstPrev(list_head, pprev);
5345 if (elem_type_list_entry(pprev) == INIT_LIST_FLAG_FSTN)
5346 need_fstn = TRUE;
5347 }
5348
5349 if (interval < 16)
5350 {
5351 pqhprev = pqhnext = NULL;
5352 if (interval == 1)
5353 {
5354 list_head = &ehci->periodic_list_cpu[EHCI_SCHED_FSTN_INDEX];
5355 ListFirst(list_head, pthis);
5356 InsertTailList(list_head, &pqh->elem_head_link->sched_link);
5357 ListFirstPrev(&pqh->elem_head_link->sched_link, pprev);
5358 pqh->hw_next = EHCI_PTR_TERM;
5359 if (pprev == pthis)
5360 {
5361 fstn_from_schedule(pthis)->hw_next = pqh->phys_addr;
5362 }
5363 else
5364 {
5365 qh_from_schedule(pthis)->hw_next = pqh->phys_addr;
5366 }
5367 }
5368 else // interval == 2 or 4 or 8
5369 {
5370 list_head = &ehci->periodic_list_cpu[EHCI_SCHED_INT8_INDEX];
5371 ListFirst(list_head, pthis);
5372 pprev = NULL;
5373 while (pthis)
5374 {
5375 elem_link = struct_ptr(pthis, EHCI_ELEM_LINKS, sched_link);
5376 purb1 = elem_link->purb;
5377 pc = (PURB_HS_PIPE_CONTENT) purb1->pipe;
5378 u = (pc->speed_high ? (1 << pc->interval) : (1 << (pc->interval + 3)));
5379
5380 if (interval < u)
5381 {
5382 ListFirstPrev(pthis, pprev);
5383 break;
5384 }
5385 else if (interval > u)
5386 {
5387 ListNext(list_head, pthis, pnext);
5388 pprev = pthis;
5389 pthis = pnext;
5390 continue;
5391 }
5392 // FIXME: is this right to fix fstn's start_uf 1???
5393 else if (start_uframe <=
5394 (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN ?
5395 1 : pc->start_uframe) + (purb1->int_start_frame << 3))
5396 {
5397 ListNext(list_head, pthis, pnext);
5398 pprev = pthis;
5399 pthis = pnext;
5400 continue;
5401 }
5402 else // interval is equal, and start_uframe is greater
5403 {
5404 ListFirstPrev(pthis, pprev);
5405 break;
5406 }
5407 }
5408 if (pprev == NULL)
5409 {
5410 // at least one dummy qh is there
5411 TRAP();
5412 }
5413 else if (pnext == NULL)
5414 {
5415 // the last one in this chain, fstn can be handled correctly
5416 InsertTailList(list_head, &pqh->elem_head_link->sched_link);
5417 pqhprev = qh_from_schedule(pprev);
5418 pqh->hw_next = pqhprev->hw_next;
5419 pqhprev->hw_next = pqh->phys_addr;
5420 }
5421 else
5422 {
5423 pqhprev = qh_from_schedule(pprev);
5424 if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_QH)
5425 {
5426 InsertHeadList(&pqhprev->elem_head_link->sched_link, &pqh->elem_head_link->sched_link);
5427 }
5428 else if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_FSTN)
5429 {
5430 InsertHeadList(&fstn_from_schedule(pprev)->elem_head_link->sched_link,
5431 &pqh->elem_head_link->sched_link);
5432 }
5433 pqh->hw_next = pqhprev->hw_next;
5434 pqhprev->hw_next = pqh->phys_addr;
5435 }
5436 }
5437 }
5438 else // interval >= 16
5439 {
5440 if ((start_frame << 3) >= interval)
5441 TRAP();
5442
5443 for(i = start_frame; i < (LONG) start_frame + 1; i += (interval >> 3))
5444 {
5445 list_head = &ehci->frame_list_cpu[i].td_link;
5446 ListFirst(list_head, pthis);
5447
5448 pprev = list_head;
5449 while (pthis)
5450 {
5451 // skip itds and sitds
5452 if (elem_type(pthis, FALSE) == INIT_LIST_FLAG_ITD ||
5453 elem_type(pthis, FALSE) == INIT_LIST_FLAG_SITD)
5454 {
5455 ListNext(list_head, pthis, pnext);
5456 pprev = pthis;
5457 pthis = pnext;
5458 continue;
5459 }
5460 break;
5461 }
5462
5463 while (pthis)
5464 {
5465 // find the insertion point
5466
5467 pqhnext = qh_from_schedule(pthis);
5468 if (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN)
5469 purb1 = fstn_from_schedule(pthis)->elem_head_link->purb;
5470 else
5471 purb1 = pqhnext->elem_head_link->purb;
5472
5473 if (purb1 == NULL)
5474 TRAP();
5475
5476 pc = (PURB_HS_PIPE_CONTENT) & purb1->pipe;
5477 u = 1 << (pc->speed_high ? (1 << pc->interval) : (1 << (pc->interval + 3)));
5478
5479 if (u > interval)
5480 {
5481 ListNext(list_head, pthis, pnext);
5482 pprev = pthis;
5483 pthis = pnext;
5484 continue;
5485 }
5486 else if (u == interval)
5487 {
5488 if (start_uframe >=
5489 (elem_type(pthis, FALSE) == INIT_LIST_FLAG_FSTN ?
5490 1 : pc->start_uframe) + (purb1->int_start_frame << 3))
5491 {
5492 ListNext(list_head, pthis, pnext);
5493 pprev = pthis;
5494 pthis = pnext;
5495 continue;
5496 }
5497 else
5498 break;
5499 }
5500 else if (u < interval)
5501 {
5502 break;
5503 }
5504 }
5505 if (pprev == list_head)
5506 {
5507 // insert to the list head
5508 pnext = pqh->elem_head_link->sched_link.Flink = list_head->Flink;
5509 list_head->Flink = &pqh->elem_head_link->sched_link;
5510 pqh->hw_next = ehci->frame_list[i]; // point to following node
5511 ehci->frame_list[i] = pqh->phys_addr;
5512 }
5513 else
5514 {
5515 pnext = pqh->elem_head_link->sched_link.Flink = pprev->Flink;
5516 pprev->Flink = &pqh->elem_head_link->sched_link;
5517
5518 // fstn can be handled correctly
5519 pqh->hw_next = qh_from_schedule(pprev)->hw_next;
5520 qh_from_schedule(pprev)->hw_next = pqh->phys_addr;
5521 }
5522 }
5523 for(i = start_frame + (interval >> 3); i < (LONG) ehci->frame_count; i += (interval >> 3))
5524 {
5525 pprev = list_head = &ehci->frame_list_cpu[i].td_link;
5526 ListFirst(list_head, pthis);
5527
5528 while (pthis)
5529 {
5530 if (pthis == pnext)
5531 {
5532 break;
5533 }
5534 pprev = pthis;
5535 ListNext(list_head, pthis, pthis);
5536 }
5537
5538 pprev->Flink = &pqh->elem_head_link->sched_link;
5539 if (pprev == list_head)
5540 ehci->frame_list[i] = pqh->phys_addr;
5541 else
5542 qh_from_schedule(pprev)->hw_next = pqh->phys_addr;
5543 }
5544 }
5545
5546 if (need_fstn)
5547 ehci_insert_fstn_schedule(ehci, purb);
5548
5549 return;
5550 }
5551
5552 static VOID
5553 ehci_remove_int_from_schedule(PEHCI_DEV ehci, PURB purb)
5554 {
5555 PURB_HS_PIPE_CONTENT pipe_content;
5556 PLIST_ENTRY pthis, list_head, pnext, pprev, pcur;
5557 PEHCI_QH pqh, pqhprev;
5558
5559 ULONG interval, start_frame, start_uframe;
5560 LONG i;
5561
5562 if (ehci == NULL || purb == NULL)
5563 return;
5564
5565 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5566 interval = REAL_INTERVAL;
5567 start_uframe = (purb->int_start_frame << 3) + pipe_content->start_uframe;
5568 start_frame = purb->int_start_frame;
5569
5570 ListFirst(&purb->trasac_list, pthis);
5571 if (pthis == NULL)
5572 return;
5573
5574 pqh = qh_from_list_entry(pthis);
5575 list_head = &purb->trasac_list;
5576
5577 if (IsListEmpty(list_head))
5578 {
5579 TRAP();
5580 return;
5581 }
5582
5583 if (!pipe_content->speed_high)
5584 {
5585 interval = (interval << 3);
5586 }
5587
5588 if (interval >= 256 * 8)
5589 return;
5590
5591 if (interval < 16)
5592 {
5593 ListFirstPrev(&pqh->elem_head_link->sched_link, pprev);
5594 RemoveEntryList(&pqh->elem_head_link->sched_link);
5595 if (interval > 1)
5596 {
5597 pqhprev = qh_from_schedule(pprev);
5598 pqhprev->hw_next = pqh->hw_next;
5599 }
5600 else
5601 {
5602 ListFirst(&ehci->frame_list_cpu[EHCI_SCHED_FSTN_INDEX].td_link, list_head);
5603 if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_FSTN)
5604 {
5605 fstn_from_schedule(list_head)->hw_next = pqh->hw_next;
5606 }
5607 else
5608 {
5609 qh_from_schedule(pprev)->hw_next = pqh->hw_next;
5610 }
5611 }
5612 }
5613 else if (interval >= 16)
5614 {
5615 ListFirst(list_head, pthis);
5616 pthis = &pqh->elem_head_link->sched_link;
5617
5618 for(i = start_uframe; i < (LONG) (ehci->frame_count << 3); i += interval)
5619 {
5620 ListFirst(&ehci->frame_list_cpu[i].td_link, pcur);
5621 pprev = NULL;
5622 while (pthis != pcur && pcur)
5623 {
5624 ListNext(&ehci->frame_list_cpu[i].td_link, pcur, pnext);
5625 pprev = pcur;
5626 pcur = pnext;
5627 }
5628
5629 if (pcur == NULL)
5630 {
5631 TRAP();
5632 continue;
5633 }
5634 else if (pprev == NULL)
5635 {
5636 // the first one in the frame list
5637 ehci->frame_list_cpu[i].td_link.Flink = pthis->Flink;
5638 ehci->frame_list[i] = qh_from_schedule(pthis)->hw_next;
5639 }
5640 else
5641 {
5642 if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_QH)
5643 {
5644 qh_from_schedule(pprev)->elem_head_link->sched_link.Flink =
5645 pqh->elem_head_link->sched_link.Flink;
5646 qh_from_schedule(pprev)->hw_next = pqh->hw_next;
5647 }
5648 else if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_ITD)
5649 {
5650 itd_from_schedule(pprev)->elem_head_link->sched_link.Flink =
5651 pqh->elem_head_link->sched_link.Flink;
5652 itd_from_schedule(pprev)->hw_next = pqh->hw_next;
5653 }
5654 else if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_SITD)
5655 {
5656 sitd_from_schedule(pprev)->elem_head_link->sched_link.Flink =
5657 pqh->elem_head_link->sched_link.Flink;
5658 sitd_from_schedule(pprev)->hw_next = pqh->hw_next;
5659 }
5660 else if (elem_type(pprev, FALSE) == INIT_LIST_FLAG_FSTN)
5661 {
5662 fstn_from_schedule(pprev)->elem_head_link->sched_link.Flink =
5663 pqh->elem_head_link->sched_link.Flink;
5664 fstn_from_schedule(pprev)->hw_next = pqh->hw_next;
5665 }
5666 else
5667 TRAP();
5668 }
5669 }
5670 }
5671
5672 ListFirstPrev(&purb->trasac_list, pprev);
5673 if (elem_type_list_entry(pprev) == INIT_LIST_FLAG_FSTN)
5674 ehci_remove_fstn_from_schedule(ehci, purb);
5675 return;
5676 }
5677
5678 static VOID
5679 ehci_insert_iso_schedule(PEHCI_DEV ehci, PURB purb)
5680 {
5681 PURB_HS_PIPE_CONTENT pipe_content;
5682 PLIST_ENTRY pthis, list_head, pnext;
5683
5684 ULONG interval, start_frame;
5685 LONG i;
5686
5687 if (ehci == NULL || purb == NULL)
5688 return;
5689
5690 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5691
5692 interval = 8;
5693 if (pipe_content->speed_high)
5694 interval = REAL_INTERVAL;
5695
5696 start_frame = purb->iso_start_frame;
5697
5698 ListFirst(&purb->trasac_list, pthis);
5699 if (pthis == NULL)
5700 {
5701 TRAP();
5702 return;
5703 }
5704
5705 list_head = &purb->trasac_list;
5706 if (IsListEmpty(list_head))
5707 {
5708 TRAP();
5709 return;
5710 }
5711
5712 i = start_frame;
5713 while (pthis)
5714 {
5715 if (pipe_content->speed_high)
5716 {
5717 itd_from_list_entry(pthis)->elem_head_link->sched_link.Flink =
5718 ehci->frame_list_cpu[i].td_link.Flink;
5719 itd_from_list_entry(pthis)->hw_next = ehci->frame_list[i];
5720
5721 ehci->frame_list[i] = itd_from_list_entry(pthis)->phys_addr;
5722 ehci->frame_list_cpu[i].td_link.Flink = pthis;
5723 }
5724 else
5725 {
5726 sitd_from_list_entry(pthis)->elem_head_link->sched_link.Flink =
5727 ehci->frame_list_cpu[i].td_link.Flink;
5728 sitd_from_list_entry(pthis)->hw_next = ehci->frame_list[i];
5729
5730 ehci->frame_list[i] = sitd_from_list_entry(pthis)->phys_addr;
5731 ehci->frame_list_cpu[i].td_link.Flink = pthis;
5732 }
5733
5734 ListNext(list_head, pthis, pnext);
5735 pthis = pnext;
5736
5737 if (interval <= 8)
5738 i++;
5739 else
5740 i += (interval >> 3);
5741 }
5742 return;
5743 }
5744
5745 static VOID
5746 ehci_remove_iso_from_schedule(PEHCI_DEV ehci, PURB purb)
5747 {
5748 PURB_HS_PIPE_CONTENT pipe_content;
5749 PLIST_ENTRY pthis, list_head, pnext, pprev, pcur;
5750
5751 ULONG interval, start_frame;
5752 LONG i;
5753
5754 if (ehci == NULL || purb == NULL)
5755 return;
5756
5757 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5758
5759 interval = 8;
5760 if (pipe_content->speed_high)
5761 interval = REAL_INTERVAL;
5762
5763 start_frame = purb->iso_start_frame;
5764
5765 ListFirst(&purb->trasac_list, pthis);
5766 if (pthis == NULL)
5767 {
5768 TRAP();
5769 return;
5770 }
5771
5772 list_head = &purb->trasac_list;
5773 if (IsListEmpty(list_head))
5774 {
5775 TRAP();
5776 return;
5777 }
5778
5779 i = start_frame;
5780 while (pthis)
5781 {
5782 // for the possible existance of sitd back pointer, we can not use for(...)
5783 ListFirst(&ehci->frame_list_cpu[i].td_link, pcur);
5784 pprev = &ehci->frame_list_cpu[i].td_link;
5785 while (pcur)
5786 {
5787 if (pcur != pthis)
5788 {
5789 ListNext(&ehci->frame_list_cpu[i].td_link, pcur, pnext);
5790 pprev = pcur;
5791 pcur = pnext;
5792 continue;
5793 }
5794 break;
5795 }
5796
5797 if (pcur == NULL)
5798 {
5799 TRAP();
5800 }
5801 pprev->Flink = pcur->Flink;
5802 if (pprev != &ehci->frame_list_cpu[i].td_link)
5803 qh_from_schedule(pprev)->hw_next = qh_from_schedule(pcur)->hw_next;
5804 else
5805 ehci->frame_list[i] = qh_from_schedule(pcur)->hw_next;
5806
5807 ListNext(list_head, pthis, pnext);
5808 pthis = pnext;
5809
5810 if (interval <= 8)
5811 i++;
5812 else
5813 i += (interval >> 3);
5814 }
5815 return;
5816 }
5817
5818 NTSTATUS
5819 ehci_isr_removing_urb(PEHCI_DEV ehci, PURB purb, BOOLEAN doorbell_rings, ULONG cur_frame)
5820 {
5821 UCHAR type;
5822 PLIST_ENTRY pthis;
5823 PURB_HS_PIPE_CONTENT pipe_content;
5824 PEHCI_ITD_CONTENT pitd_content;
5825 PEHCI_SITD_CONTENT psitd_content;
5826 PEHCI_QH_CONTENT pqh_content;
5827 PEHCI_QTD_CONTENT pqtd_content;
5828 LONG i;
5829
5830 if (purb == NULL || ehci == NULL)
5831 return STATUS_INVALID_PARAMETER;
5832
5833 if ((purb->flags & URB_FLAG_STATE_MASK) == URB_FLAG_STATE_FINISHED)
5834 return STATUS_SUCCESS;
5835
5836 type = 0;
5837 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
5838
5839 switch (purb->flags & URB_FLAG_STATE_MASK)
5840 {
5841 case URB_FLAG_STATE_IN_PROCESS:
5842 {
5843 // determine the removal type: complete, error or cancel
5844 ListFirst(&purb->trasac_list, pthis);
5845 if (purb->flags & URB_FLAG_FORCE_CANCEL)
5846 {
5847 type = 3;
5848 }
5849 else
5850 {
5851 if (pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
5852 pipe_content->trans_type == USB_ENDPOINT_XFER_INT ||
5853 pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL)
5854 {
5855 pqh_content =
5856 (PEHCI_QH_CONTENT) ((ULONG) struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->
5857 phys_part & PHYS_PART_ADDR_MASK);
5858 if (EHCI_QH_ERROR(pqh_content))
5859 {
5860 purb->status = pqh_content->cur_qtd.status;
5861 type = 2;
5862 }
5863 else
5864 {
5865 pqtd_content = &pqh_content->cur_qtd;
5866 if (pqtd_content->terminal && ((pqtd_content->status & QTD_STS_ACTIVE) == 0))
5867 {
5868 type = 1;
5869 }
5870 // else, not finished
5871 }
5872 }
5873 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
5874 {
5875 // FIXME: do we need to check if current frame falls out of the
5876 // frame range of iso transfer
5877 // inspect the last td to determine if finished
5878 ListFirstPrev(&purb->trasac_list, pthis);
5879 if (pthis)
5880 {
5881 if (pipe_content->speed_high)
5882 {
5883 pitd_content =
5884 (PEHCI_ITD_CONTENT) ((ULONG) struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->
5885 phys_part & PHYS_PART_ADDR_MASK);
5886 for(i = 0; i < 8; i++)
5887 {
5888 if (pitd_content->status_slot[i].trans_length &&
5889 pitd_content->status_slot[i].status & 0x08)
5890 {
5891 break;
5892 }
5893 }
5894 if (i == 8)
5895 {
5896 // the itds are all inactive
5897 type = 1;
5898 }
5899 }
5900 else
5901 {
5902 psitd_content =
5903 (PEHCI_SITD_CONTENT) ((ULONG) struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->
5904 phys_part & PHYS_PART_ADDR_MASK);
5905 if ((psitd_content->status & 0x80) == 0)
5906 {
5907 type = 1;
5908 }
5909 }
5910 }
5911 else // empty transaction list in purb
5912 TRAP();
5913 }
5914 else // unknown transfer type
5915 TRAP();
5916
5917 } // end of not force cancel
5918
5919 if (type == 0)
5920 return STATUS_SUCCESS;
5921
5922 switch (type)
5923 {
5924 case 1:
5925 {
5926 if (pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL ||
5927 pipe_content->trans_type == USB_ENDPOINT_XFER_BULK)
5928 {
5929 ehci_remove_bulk_from_schedule(ehci, purb);
5930 purb->flags &= ~URB_FLAG_STATE_MASK;
5931 purb->flags |= URB_FLAG_STATE_DOORBELL;
5932 purb->status = 0;
5933 press_doorbell(ehci);
5934 return STATUS_SUCCESS;
5935 }
5936 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
5937 {
5938 ehci_remove_iso_from_schedule(ehci, purb);
5939 }
5940 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT)
5941 {
5942 ehci_remove_int_from_schedule(ehci, purb);
5943 }
5944 else // unknown transfer type
5945 TRAP();
5946
5947 purb->flags &= ~URB_FLAG_STATE_MASK;
5948 purb->flags |= URB_FLAG_STATE_FINISHED;
5949
5950 // notify dpc the purb can be completed;
5951 purb->flags &= ~URB_FLAG_IN_SCHEDULE;
5952 purb->status = 0;
5953
5954 return STATUS_SUCCESS;
5955 }
5956 case 2:
5957 {
5958 if (pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL ||
5959 pipe_content->trans_type == USB_ENDPOINT_XFER_BULK)
5960 {
5961 ehci_deactivate_urb(purb);
5962 ehci_remove_bulk_from_schedule(ehci, purb);
5963 purb->flags &= ~URB_FLAG_STATE_MASK;
5964 purb->flags |= URB_FLAG_STATE_DOORBELL;
5965 press_doorbell(ehci);
5966 }
5967 else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT)
5968 {
5969 ehci_remove_int_from_schedule(ehci, purb);
5970
5971 purb->flags &= ~URB_FLAG_STATE_MASK;
5972 purb->flags |= URB_FLAG_STATE_FINISHED;
5973 purb->flags &= ~URB_FLAG_IN_SCHEDULE;
5974 }
5975 else // unknown transfer or iso transfer
5976 TRAP();
5977 return STATUS_SUCCESS;
5978 }
5979 case 3:
5980 {
5981 if (pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL ||
5982 pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
5983 pipe_content->trans_type == USB_ENDPOINT_XFER_INT)
5984 {
5985 ehci_deactivate_urb(purb);
5986 if (pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
5987 pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL)
5988 ehci_remove_bulk_from_schedule(ehci, purb);
5989 else
5990 ehci_remove_int_from_schedule(ehci, purb);
5991
5992 purb->flags &= ~URB_FLAG_STATE_MASK;
5993 purb->flags |= URB_FLAG_STATE_DOORBELL;
5994
5995 press_doorbell(ehci);
5996
5997 }
5998 else // unknown transfer or iso transfer
5999 DO_NOTHING;
6000 purb->status = 0;
6001 return STATUS_SUCCESS;
6002 }
6003 default:
6004 TRAP();
6005 }
6006 }
6007 case URB_FLAG_STATE_DOORBELL:
6008 {
6009 if (doorbell_rings == FALSE)
6010 return STATUS_SUCCESS;
6011
6012 purb->flags &= ~URB_FLAG_STATE_MASK;
6013 purb->flags |= URB_FLAG_STATE_FINISHED;
6014 purb->flags &= ~URB_FLAG_IN_SCHEDULE;
6015 return STATUS_SUCCESS;
6016 }
6017 }
6018 return STATUS_SUCCESS;
6019 }
6020
6021 static ULONG
6022 ehci_scan_iso_error(PEHCI_DEV ehci, PURB purb)
6023 // we only report the first error of the ITDs, purb->status is the status code
6024 // return the raw status for ehci_set_error_code
6025 {
6026 PURB_HS_PIPE_CONTENT pipe_content;
6027 PEHCI_SITD_CONTENT psitd_content;
6028 PEHCI_ITD_CONTENT pitd_content;
6029 PLIST_ENTRY pthis, pnext;
6030 LONG i;
6031
6032 if (ehci == NULL || purb == NULL)
6033 return 0;
6034
6035 pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
6036 if (pipe_content->trans_type != USB_ENDPOINT_XFER_ISOC)
6037 {
6038 return 0;
6039 }
6040
6041 ListFirst(&purb->trasac_list, pthis);
6042 if (pipe_content->speed_high)
6043 {
6044 while (pthis)
6045 {
6046 pitd_content = (PEHCI_ITD_CONTENT) itd_from_list_entry(pthis);
6047 for(i = 0; i < 8; i++)
6048 {
6049 if (pitd_content->status_slot[i].status & ITD_ANY_ERROR)
6050 break;
6051 }
6052 if (i < 8)
6053 {
6054 // error occured
6055 return purb->status = pitd_content->status_slot[i].status;
6056 }
6057 ListNext(&purb->trasac_list, pthis, pnext);
6058 pthis = pnext;
6059 }
6060 }
6061 else
6062 {
6063 while (pthis)
6064 {
6065 psitd_content = (PEHCI_SITD_CONTENT) sitd_from_list_entry(pthis);
6066 if (psitd_content->status & SITD_ANY_ERROR)
6067 {
6068 // error occured
6069 if (psitd_content->s_mask == 0x04 &&
6070 psitd_content->c_mask == 0x70 && psitd_content->bytes_to_transfer == 1)
6071 return purb->status = 0;
6072
6073 return purb->status = psitd_content->status;
6074 }
6075 ListNext(&purb->trasac_list, pthis, pnext);
6076 pthis = pnext;
6077 }
6078 }
6079 return 0;
6080 }
6081
6082 BOOLEAN NTAPI
6083 ehci_isr(PKINTERRUPT interrupt, PVOID context)
6084 // we can not use endp here for it is within the dev scope, and
6085 // we can not acquire the dev-lock, fortunately we saved some
6086 // info in purb->pipe in ehci_internal_submit_XXX.
6087 {
6088
6089 PEHCI_DEV ehci;
6090 ULONG status;
6091 #if DBG
6092 ULONG urb_count;
6093 #endif
6094 PLIST_ENTRY pthis, pnext;
6095 PURB purb;
6096 BOOLEAN door_bell_rings;
6097 ULONG cur_frame;
6098 /*
6099 * Read the interrupt status, and write it back to clear the
6100 * interrupt cause
6101 */
6102 ehci = (PEHCI_DEV) context;
6103 if (ehci == NULL)
6104 return FALSE;
6105
6106 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + EHCI_USBSTS));
6107 cur_frame = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + EHCI_FRINDEX));
6108
6109 status &= (EHCI_ERROR_INT | STS_INT | STS_IAA);
6110 if (!status) /* shared interrupt, not mine */
6111 {
6112 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_isr(): not our int\n"));
6113 return FALSE;
6114 }
6115
6116 /* clear it */
6117 EHCI_WRITE_PORT_ULONG((PULONG) (ehci->port_base + EHCI_USBSTS), status);
6118
6119 if (status & EHCI_ERROR_INT)
6120 {
6121 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_isr(): current ehci status=0x%x\n", status));
6122 }
6123 else
6124 {
6125 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_isr(): congratulations, no error occurs\n"));
6126 }
6127
6128
6129 if (status & STS_FATAL)
6130 {
6131 DbgPrint("ehci_isr(): host system error, PCI problems?\n");
6132 for(;;);
6133
6134 }
6135
6136 if (status & STS_HALT) //&& !ehci->is_suspended
6137 {
6138 DbgPrint("ehci_isr(): host controller halted. very bad\n");
6139 /* FIXME: Reset the controller, fix the offending TD */
6140 // reset is performed in dpc
6141 }
6142
6143
6144 door_bell_rings = ((status & STS_IAA) != 0);
6145
6146 // scan to remove those due
6147 #if DBG
6148 urb_count = dbg_count_list(&ehci->urb_list);
6149 ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_isr(): urb# in process is %d\n", urb_count));
6150 #endif
6151
6152 ListFirst(&ehci->urb_list, pthis);
6153 while (pthis)
6154 {
6155 purb = (PURB) pthis;
6156 ehci_isr_removing_urb(ehci, purb, door_bell_rings, cur_frame);
6157 ListNext(&ehci->urb_list, pthis, pnext);
6158 pthis = pnext;
6159 }
6160
6161 KeInsertQueueDpc(&ehci->pdev_ext->ehci_dpc, (PVOID) status, 0);
6162 return TRUE;
6163 }
6164
6165 #ifndef INCLUDE_EHCI
6166 VOID
6167 ehci_unload(IN PDRIVER_OBJECT DriverObject)
6168 {
6169 PDEVICE_OBJECT pdev;
6170 PEHCI_DEVICE_EXTENSION pdev_ext;
6171 PUSB_DEV_MANAGER dev_mgr;
6172 LONG i;
6173
6174 pdev = DriverObject->DeviceObject;
6175
6176 if (pdev == NULL)
6177 return;
6178
6179 pdev_ext = pdev->DeviceExtension;
6180 if (pdev_ext == NULL)
6181 return;
6182
6183 dev_mgr = &g_dev_mgr;
6184 if (dev_mgr == NULL)
6185 return;
6186 //
6187 // set the termination flag
6188 //
6189 dev_mgr->term_flag = TRUE;
6190 //
6191 // wake up the thread if it is
6192 //
6193 KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
6194 KeWaitForSingleObject(dev_mgr->pthread, Executive, KernelMode, TRUE, NULL);
6195 ObDereferenceObject(dev_mgr->pthread);
6196 dev_mgr->pthread = NULL;
6197
6198 dev_mgr_release_hcd(dev_mgr);
6199 return;
6200 }
6201
6202 NTSTATUS
6203 generic_dispatch_irp(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
6204 {
6205 PDEVEXT_HEADER dev_ext;
6206
6207 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
6208
6209 if (dev_ext && dev_ext->dispatch)
6210 return dev_ext->dispatch(dev_obj, irp);
6211
6212 irp->IoStatus.Information = 0;
6213
6214 EXIT_DISPATCH(STATUS_UNSUCCESSFUL, irp);
6215 }
6216
6217 VOID
6218 generic_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
6219 {
6220 PDEVEXT_HEADER dev_ext;
6221
6222 KIRQL old_irql;
6223
6224 IoAcquireCancelSpinLock(&old_irql);
6225 if (irp != dev_obj->CurrentIrp || irp->Cancel)
6226 {
6227 IoReleaseCancelSpinLock(old_irql);
6228 return;
6229 }
6230 else
6231 {
6232 IoSetCancelRoutine(irp, NULL);
6233 IoReleaseCancelSpinLock(old_irql);
6234 }
6235
6236 dev_ext = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
6237
6238 if (dev_ext && dev_ext->start_io)
6239 {
6240 dev_ext->start_io(dev_obj, irp);
6241 return;
6242 }
6243
6244 irp->IoStatus.Information = 0;
6245 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
6246
6247 IoStartNextPacket(dev_obj, FALSE);
6248 IoCompleteRequest(irp, IO_NO_INCREMENT);
6249 }
6250
6251 NTSTATUS
6252 NTAPI
6253 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
6254 {
6255 NTSTATUS ntStatus = STATUS_SUCCESS;
6256 BOOLEAN fRes;
6257
6258 #if DBG
6259 // should be done before any debug output is done.
6260 // read our debug verbosity level from the registry
6261 //NetacOD_GetRegistryDword( NetacOD_REGISTRY_PARAMETERS_PATH, //absolute registry path
6262 // L"DebugLevel", // REG_DWORD ValueName
6263 // &gDebugLevel ); // Value receiver
6264
6265 // debug_level = DBGLVL_MAXIMUM;
6266 #endif
6267
6268 ehci_dbg_print_cond(DBGLVL_MINIMUM, DEBUG_UHCI,
6269 ("Entering DriverEntry(), RegistryPath=\n %ws\n", RegistryPath->Buffer));
6270
6271 // Remember our driver object, for when we create our child PDO
6272 usb_driver_obj = DriverObject;
6273
6274 //
6275 // Create dispatch points for create, close, unload
6276 DriverObject->MajorFunction[IRP_MJ_CREATE] = generic_dispatch_irp;
6277 DriverObject->MajorFunction[IRP_MJ_CLOSE] = generic_dispatch_irp;
6278 DriverObject->DriverUnload = ehci_unload;
6279
6280 // User mode DeviceIoControl() calls will be routed here
6281 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = generic_dispatch_irp;
6282 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = generic_dispatch_irp;
6283
6284 // User mode ReadFile()/WriteFile() calls will be routed here
6285 DriverObject->MajorFunction[IRP_MJ_WRITE] = generic_dispatch_irp;
6286 DriverObject->MajorFunction[IRP_MJ_READ] = generic_dispatch_irp;
6287
6288 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = generic_dispatch_irp;
6289 DriverObject->MajorFunction[IRP_MJ_SCSI] = generic_dispatch_irp;
6290 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = generic_dispatch_irp;
6291
6292 DriverObject->DriverStartIo = generic_start_io;
6293 // routines for handling system PNP and power management requests
6294 //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = generic_dispatch_irp;
6295
6296 // The Functional Device Object (FDO) will not be created for PNP devices until
6297 // this routine is called upon device plug-in.
6298 RtlZeroMemory(&g_dev_mgr, sizeof(USB_DEV_MANAGER));
6299 g_dev_mgr.usb_driver_obj = DriverObject;
6300
6301 ehci_probe(DriverObject, RegistryPath, &g_dev_mgr);
6302
6303 if (dev_mgr_strobe(&g_dev_mgr) == FALSE)
6304 {
6305 dev_mgr_release_hcd(&g_dev_mgr);
6306 return STATUS_UNSUCCESSFUL;
6307 }
6308
6309 dev_mgr_start_hcd(&g_dev_mgr);
6310 ehci_dbg_print_cond(DBGLVL_DEFAULT, DEBUG_UHCI, ("DriverEntry(): exiting... (%x)\n", ntStatus));
6311 return STATUS_SUCCESS;
6312 }
6313 #endif
6314
6315 //note: the initialization will be in the following order
6316 // dev_mgr_strobe
6317 // ehci_start
6318
6319 // to kill dev_mgr_thread:
6320 // dev_mgr->term_flag = TRUE;
6321 // KeSetEvent( &dev_mgr->wake_up_event );
6322 // this piece of code must run at passive-level
6323 //
6324 //