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