2 * etd.c - USB driver stack project for Windows NT 4.0
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
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.
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.
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
22 #include <usbdriver.h>
25 #define init_elem( ptr, type, ehci_elem_type ) \
27 PEHCI_ELEM_LINKS tmp;\
28 ptr = ( type* )( plist->phys_bufs[ i ] + sizeof( type ) * j );\
29 ptr->hw_next = ehci_elem_type << 1;\
30 if( ehci_elem_type == INIT_LIST_FLAG_QTD )\
32 tmp = ptr->elem_head_link = &plist->elem_head_buf[ i * elms_per_page + j ];\
33 InitializeListHead( &tmp->elem_link );\
34 InitializeListHead( &tmp->sched_link );\
35 InsertTailList( &plist->free_list, &tmp->elem_link );\
36 tmp->list_link = plist;\
37 tmp->pool_link = pinit_ctx->pool;\
38 tmp->phys_part = ( PVOID )( ( ULONG )ptr | ( ehci_elem_type << 1 ) );\
39 if( ehci_elem_type != INIT_LIST_FLAG_QTD )\
40 ptr->phys_addr = ( plist->phys_addrs[ i ].LowPart + sizeof( type ) * j ) | ( ehci_elem_type << 1 );\
42 ptr->phys_addr = plist->phys_addrs[ i ].LowPart + sizeof( type ) * j ;\
45 // get the actual max list count of the pool, two limit, max_elem_pool and max_lists_pool
46 #define get_max_lists_count( pOOL, max_liSTS ) \
49 switch( elem_pool_get_type( pOOL ) )\
51 case INIT_LIST_FLAG_QTD:\
52 ii1 = EHCI_MAX_QTDS_LIST;\
54 case INIT_LIST_FLAG_FSTN:\
55 ii1 = EHCI_MAX_QHS_LIST;\
57 case INIT_LIST_FLAG_SITD:\
58 ii1 = EHCI_MAX_ITDS_LIST;\
60 case INIT_LIST_FLAG_QH: \
61 ii1 = EHCI_MAX_SITDS_LIST;\
63 case INIT_LIST_FLAG_ITD: \
64 ii1 = EHCI_MAX_FSTNS_LIST;\
67 max_liSTS = ( EHCI_MAX_ELEMS_POOL / ii1 ) > EHCI_MAX_LISTS_POOL ? EHCI_MAX_LISTS_POOL : ( EHCI_MAX_ELEMS_POOL / ii1 );\
70 VOID
elem_list_destroy_elem_list(PEHCI_ELEM_LIST plist
);
72 PLIST_ENTRY
elem_list_get_list_head(PEHCI_ELEM_LIST plist
);
74 LONG
elem_list_get_total_count(PEHCI_ELEM_LIST plist
);
76 LONG
elem_list_get_elem_size(PEHCI_ELEM_LIST plist
);
78 LONG
elem_list_get_link_offset(PEHCI_ELEM_LIST plist
);
80 LONG
elem_list_add_ref(PEHCI_ELEM_LIST plist
);
82 LONG
elem_list_release_ref(PEHCI_ELEM_LIST plist
);
84 LONG
elem_list_get_ref(PEHCI_ELEM_LIST plist
);
87 elem_pool_lock(PEHCI_ELEM_POOL pool
, BOOLEAN at_dpc
)
89 UNREFERENCED_PARAMETER(pool
);
90 UNREFERENCED_PARAMETER(at_dpc
);
96 elem_pool_unlock(PEHCI_ELEM_POOL pool
, BOOLEAN at_dpc
)
98 UNREFERENCED_PARAMETER(pool
);
99 UNREFERENCED_PARAMETER(at_dpc
);
105 get_elem_phys_part_size(ULONG type
)
107 // type is INIT_LIST_FLAG_XXX
113 case INIT_LIST_FLAG_ITD
:
116 case INIT_LIST_FLAG_SITD
:
119 case INIT_LIST_FLAG_QTD
:
122 case INIT_LIST_FLAG_QH
:
125 case INIT_LIST_FLAG_FSTN
:
133 elem_list_init_elem_list(PEHCI_ELEM_LIST plist
, LONG init_flags
, PVOID context
, LONG count
)
135 LONG pages
, i
, j
, elms_per_page
;
141 PINIT_ELEM_LIST_CONTEXT pinit_ctx
;
143 UNREFERENCED_PARAMETER(count
);
145 if (plist
== NULL
|| context
== NULL
)
148 RtlZeroMemory(plist
, sizeof(EHCI_ELEM_LIST
));
152 plist
->destroy_list
= elem_list_destroy_elem_list
;
153 plist
->get_list_head
= elem_list_get_list_head
;
154 plist
->get_total_count
= elem_list_get_total_count
;
155 plist
->get_elem_size
= elem_list_get_elem_size
;
156 plist
->get_link_offset
= elem_list_get_link_offset
;
157 plist
->add_ref
= elem_list_add_ref
;
158 plist
->release_ref
= elem_list_release_ref
;
159 plist
->get_ref
= elem_list_get_ref
;
161 InitializeListHead(&plist
->free_list
);
163 switch (init_flags
& 0x0f)
165 case INIT_LIST_FLAG_ITD
:
166 plist
->total_count
= EHCI_MAX_ITDS_LIST
;
167 plist
->elem_size
= sizeof(EHCI_ITD
);
169 case INIT_LIST_FLAG_QH
:
170 plist
->total_count
= EHCI_MAX_QHS_LIST
;
171 plist
->elem_size
= sizeof(EHCI_QH
);
173 case INIT_LIST_FLAG_SITD
:
174 plist
->total_count
= EHCI_MAX_SITDS_LIST
;
175 plist
->elem_size
= sizeof(EHCI_SITD
);
177 case INIT_LIST_FLAG_FSTN
:
178 plist
->total_count
= EHCI_MAX_FSTNS_LIST
;
179 plist
->elem_size
= sizeof(EHCI_FSTN
);
181 case INIT_LIST_FLAG_QTD
:
182 plist
->total_count
= EHCI_MAX_QTDS_LIST
;
183 plist
->elem_size
= sizeof(EHCI_QTD
);
188 if (plist
->elem_size
& 0x1f)
190 plist
->total_count
= 0;
194 plist
->flags
= init_flags
;
195 plist
->parent_pool
= pinit_ctx
->pool
;
196 plist
->padapter
= pinit_ctx
->padapter
;
197 pages
= ((plist
->elem_size
* plist
->total_count
) + (PAGE_SIZE
- 1)) / PAGE_SIZE
;
198 elms_per_page
= PAGE_SIZE
/ plist
->elem_size
;
200 plist
->phys_addrs
= usb_alloc_mem(NonPagedPool
,
201 (sizeof(PHYSICAL_ADDRESS
) + sizeof(PBYTE
)) * pages
+
202 sizeof(EHCI_ELEM_LINKS
) * plist
->total_count
);
204 if (plist
->phys_addrs
== NULL
)
206 plist
->total_count
= 0;
210 plist
->phys_bufs
= (PBYTE
*) & plist
->phys_addrs
[pages
];
211 plist
->elem_head_buf
= (PEHCI_ELEM_LINKS
) & plist
->phys_bufs
[pages
];
212 RtlZeroMemory(plist
->phys_addrs
,
213 (sizeof(PHYSICAL_ADDRESS
) + sizeof(PBYTE
)) * pages
+
214 sizeof(EHCI_ELEM_LINKS
) * plist
->total_count
);
216 for(i
= 0; i
< pages
; i
++)
218 plist
->phys_bufs
[i
] = HalAllocateCommonBuffer(plist
->padapter
,
219 PAGE_SIZE
, &plist
->phys_addrs
[i
], FALSE
);
221 if (plist
->phys_bufs
[i
] == NULL
)
224 for(j
= i
- 1; j
>= 0; j
--)
225 HalFreeCommonBuffer(plist
->padapter
,
226 PAGE_SIZE
, plist
->phys_addrs
[j
], plist
->phys_bufs
[j
], FALSE
);
229 RtlZeroMemory(plist
->phys_bufs
[i
], PAGE_SIZE
);
230 for(j
= 0; j
< elms_per_page
; j
++)
232 switch (init_flags
& 0xf)
234 case INIT_LIST_FLAG_QH
:
236 init_elem(pqh
, EHCI_QH
, INIT_LIST_FLAG_QH
);
239 case INIT_LIST_FLAG_ITD
:
241 init_elem(pitd
, EHCI_ITD
, INIT_LIST_FLAG_ITD
);
244 case INIT_LIST_FLAG_QTD
:
246 init_elem(pqtd
, EHCI_QTD
, INIT_LIST_FLAG_QTD
);
249 case INIT_LIST_FLAG_SITD
:
251 init_elem(psitd
, EHCI_SITD
, INIT_LIST_FLAG_SITD
);
254 case INIT_LIST_FLAG_FSTN
:
256 init_elem(pfstn
, EHCI_FSTN
, INIT_LIST_FLAG_FSTN
);
267 if (plist
->phys_addrs
!= NULL
)
268 usb_free_mem(plist
->phys_addrs
);
270 RtlZeroMemory(plist
, sizeof(EHCI_ELEM_LIST
));
275 elem_list_destroy_elem_list(PEHCI_ELEM_LIST plist
)
282 pages
= (plist
->total_count
* plist
->elem_size
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
283 for(i
= 0; i
< pages
; i
++)
284 HalFreeCommonBuffer(plist
->padapter
, PAGE_SIZE
, plist
->phys_addrs
[i
], plist
->phys_bufs
[i
], FALSE
);
286 usb_free_mem(plist
->phys_addrs
);
287 RtlZeroMemory(plist
, sizeof(EHCI_ELEM_LIST
));
291 elem_list_get_list_head(PEHCI_ELEM_LIST plist
)
295 return &plist
->free_list
;
299 elem_list_get_total_count(PEHCI_ELEM_LIST plist
)
303 return plist
->total_count
;
307 elem_list_get_elem_size(PEHCI_ELEM_LIST plist
)
311 return plist
->elem_size
;
315 elem_list_get_link_offset(PEHCI_ELEM_LIST plist
)
320 return get_elem_phys_part_size(plist
->flags
& 0xf);
324 elem_list_add_ref(PEHCI_ELEM_LIST plist
)
327 return plist
->reference
;
331 elem_list_release_ref(PEHCI_ELEM_LIST plist
)
334 return plist
->reference
;
338 elem_list_get_ref(PEHCI_ELEM_LIST plist
)
340 return plist
->reference
;
348 elem_pool_init_pool(PEHCI_ELEM_POOL pool
, LONG flags
, PVOID context
)
350 INIT_ELEM_LIST_CONTEXT init_ctx
;
352 if (pool
== NULL
|| context
== NULL
)
355 RtlZeroMemory(pool
, sizeof(EHCI_ELEM_POOL
));
357 init_ctx
.pool
= pool
;
358 init_ctx
.padapter
= context
;
360 pool
->elem_lists
[0] = usb_alloc_mem(NonPagedPool
, sizeof(EHCI_ELEM_LIST
));
362 if (pool
->elem_lists
[0] == NULL
)
365 if (elem_list_init_elem_list(pool
->elem_lists
[0], flags
, &init_ctx
, 0) == FALSE
)
367 usb_free_mem(pool
->elem_lists
[0]);
370 pool
->link_offset
= pool
->elem_lists
[0]->get_link_offset(pool
->elem_lists
[0]);
371 pool
->free_count
= pool
->elem_lists
[0]->get_total_count(pool
->elem_lists
[0]);
372 pool
->list_count
= 1;
379 elem_pool_get_link_offset(PEHCI_ELEM_POOL elem_pool
)
381 return elem_pool
->link_offset
;
385 elem_pool_get_total_count(PEHCI_ELEM_POOL elem_pool
)
387 return elem_pool
->elem_lists
[0]->get_total_count(elem_pool
->elem_lists
[0]) * elem_pool
->list_count
;
391 elem_pool_destroy_pool(PEHCI_ELEM_POOL pool
)
396 for(i
= pool
->list_count
- 1; i
>= 0; i
--)
398 pool
->elem_lists
[i
]->destroy_list(pool
->elem_lists
[i
]);
399 usb_free_mem(pool
->elem_lists
[i
]);
400 pool
->elem_lists
[i
] = NULL
;
402 RtlZeroMemory(pool
, sizeof(EHCI_ELEM_POOL
));
407 elem_pool_alloc_elem(PEHCI_ELEM_POOL pool
)
410 PEHCI_ELEM_LIST pel
= NULL
;
412 PEHCI_ELEM_LINKS elnk
;
417 for(i
= 0; i
< pool
->list_count
; i
++)
419 pel
= pool
->elem_lists
[i
];
420 if (pel
->get_ref(pel
) == pel
->get_total_count(pel
))
424 if (i
== pool
->list_count
)
426 if (elem_pool_expand_pool(pool
, pel
->get_total_count(pel
)) == FALSE
)
428 pel
= pool
->elem_lists
[i
];
431 lh
= pel
->get_list_head(pel
);
432 elnk
= (PEHCI_ELEM_LINKS
) RemoveHeadList(lh
);
433 InitializeListHead(&elnk
->elem_link
);
434 InitializeListHead(&elnk
->sched_link
);
443 elem_pool_free_elem(PEHCI_ELEM_LINKS elem_link
)
447 PEHCI_ELEM_POOL pool
;
448 if (elem_link
== NULL
)
450 pool
= elem_link
->pool_link
;
451 lh
= elem_link
->list_link
->get_list_head(elem_link
->list_link
);
454 InsertHeadList(lh
, &elem_link
->elem_link
);
455 ref
= elem_link
->list_link
->release_ref(elem_link
->list_link
);
458 elem_pool_collect_garbage(pool
);
463 elem_pool_is_empty(PEHCI_ELEM_POOL pool
)
469 pel
= pool
->elem_lists
[0];
470 return (BOOLEAN
) (pool
->list_count
== 1 && pool
->free_count
== pel
->get_total_count(pel
));
474 elem_pool_get_free_count(PEHCI_ELEM_POOL pool
)
478 return pool
->free_count
;
482 elem_pool_alloc_elems(PEHCI_ELEM_POOL pool
, LONG count
)
486 LONG i
, alloc_count
, max_pool_lists
;
488 PEHCI_ELEM_LINKS elnk
;
489 // calculate to see if the count is affordable
491 if (pool
== NULL
|| count
<= 0)
494 get_max_lists_count(pool
, max_pool_lists
);
495 InitializeListHead(&lh
);
496 pel
= pool
->elem_lists
[0];
497 if (count
<= pool
->free_count
)
500 alloc_count
= count
- pool
->free_count
;
502 if (alloc_count
> pel
->get_total_count(pel
) * (max_pool_lists
- pool
->list_count
))
505 for(i
= 0; i
< count
; i
++)
507 if ((elnk
= elem_pool_alloc_elem(pool
)) == NULL
)
509 // undo what we have done
510 while (IsListEmpty(&lh
) == FALSE
)
512 pthis
= RemoveHeadList(&lh
);
513 elnk
= struct_ptr(pthis
, EHCI_ELEM_LINKS
, elem_link
);
514 elem_pool_free_elem(elnk
);
518 InsertTailList(&lh
, &elnk
->elem_link
);
520 ListFirst(&lh
, pthis
);
521 elnk
= struct_ptr(pthis
, EHCI_ELEM_LINKS
, elem_link
);
522 RemoveEntryList(&lh
);
527 elem_pool_free_elems(PEHCI_ELEM_LINKS elem_chains
)
529 // note: no list head exists.
531 PEHCI_ELEM_LINKS elnk
;
533 InsertTailList(&elem_chains
->elem_link
, &lh
);
534 while (IsListEmpty(&lh
) == FALSE
)
536 elnk
= (PEHCI_ELEM_LINKS
) RemoveHeadList(&lh
);
537 elem_pool_free_elem(elnk
);
543 elem_pool_get_type(PEHCI_ELEM_POOL pool
)
547 return (pool
->flags
& 0xf);
551 elem_pool_expand_pool(PEHCI_ELEM_POOL pool
, LONG elem_count
)
553 LONG elem_cnt_list
, list_count
, i
, j
;
554 INIT_ELEM_LIST_CONTEXT init_ctx
;
556 if (pool
== NULL
|| elem_count
<= 0 || elem_count
> EHCI_MAX_ELEMS_POOL
)
559 init_ctx
.pool
= pool
;
560 init_ctx
.padapter
= pool
->elem_lists
[0]->padapter
;
562 elem_cnt_list
= pool
->elem_lists
[0]->get_total_count(pool
->elem_lists
[0]);
563 list_count
= (elem_count
+ elem_cnt_list
- 1) / elem_cnt_list
;
564 get_max_lists_count(pool
, i
);
566 if (list_count
+ pool
->list_count
> i
)
569 for(i
= pool
->list_count
; i
< list_count
+ pool
->list_count
; i
++)
571 pool
->elem_lists
[i
] = usb_alloc_mem(NonPagedPool
, sizeof(EHCI_ELEM_LIST
));
572 if (elem_list_init_elem_list(pool
->elem_lists
[i
], pool
->flags
, &init_ctx
, 0) == FALSE
)
576 if (i
< list_count
+ pool
->list_count
)
578 // undo all we have done
579 for(j
= pool
->list_count
; j
< pool
->list_count
+ i
; j
++)
581 pool
->elem_lists
[j
]->destroy_list(pool
->elem_lists
[j
]);
582 usb_free_mem(pool
->elem_lists
[j
]);
583 pool
->elem_lists
[j
] = NULL
;
589 pool
->free_count
+= elem_cnt_list
* list_count
;
590 pool
->list_count
+= list_count
;
595 elem_pool_collect_garbage(PEHCI_ELEM_POOL pool
)
598 LONG free_elem_lists
[EHCI_MAX_LISTS_POOL
- 1];
604 for(i
= 1, fl
= 0; i
< pool
->list_count
; i
++)
606 if (pool
->elem_lists
[i
]->get_ref(pool
->elem_lists
[i
]) == 0)
608 free_elem_lists
[fl
++] = i
;
611 for(j
= fl
- 1; j
>= 0; j
--)
613 pel
= pool
->elem_lists
[free_elem_lists
[j
]];
614 pel
->destroy_list(pel
);
617 for(k
= free_elem_lists
[j
] + 1; k
< pool
->list_count
; k
++)
619 // shrink the elem_lists
620 pool
->elem_lists
[k
- 1] = pool
->elem_lists
[k
];
622 pool
->elem_lists
[k
] = NULL
;
623 pel
= pool
->elem_lists
[0];
624 pool
->free_count
-= pel
->get_total_count(pel
);
631 elem_pool_can_transfer(PEHCI_ELEM_POOL pool
, LONG td_count
)
634 if (pool
== NULL
|| td_count
<= 0)
636 get_max_lists_count(pool
, i
);
637 if ((i
- pool
->list_count
)
638 * pool
->elem_lists
[0]->get_total_count(pool
->elem_lists
[0]) + pool
->free_count
< td_count
)
643 //----------------------------------------------------------