2 * td.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"
24 #define UHCI_MIN_TD_POOLS 4
26 BOOLEAN
free_td_to_pool(PUHCI_TD_POOL ptd_pool
, PUHCI_TD ptd
); //add tds till pnext == NULL
29 PUHCI_QH
alloc_qh(PUHCI_QH_POOL pqh_pool
); //null if failed
32 init_td_pool(PUHCI_TD_POOL ptd_pool
)
40 if (ptd_pool
->padapter
== NULL
)
43 pages
= sizeof(UHCI_TD
) * UHCI_MAX_POOL_TDS
/ PAGE_SIZE
;
44 RtlZeroMemory(ptd_pool
->td_array
, sizeof(ptd_pool
->td_array
));
45 RtlZeroMemory(ptd_pool
->logic_addr
, sizeof(ptd_pool
->logic_addr
));
47 for(i
= 0; i
< pages
; i
++)
49 ptd_pool
->td_array
[i
] =
50 HalAllocateCommonBuffer(ptd_pool
->padapter
, PAGE_SIZE
, &ptd_pool
->logic_addr
[i
], FALSE
);
51 if (ptd_pool
->td_array
[i
] == NULL
)
55 ptd_pool
->tde_array
= (PTD_EXTENSION
) usb_alloc_mem(NonPagedPool
,
56 sizeof(TD_EXTENSION
) * UHCI_MAX_POOL_TDS
);
58 if (ptd_pool
->tde_array
== NULL
)
61 for(i
= 0; i
< pages
; i
++)
63 RtlZeroMemory(ptd_pool
->td_array
[i
], PAGE_SIZE
);
66 RtlZeroMemory(ptd_pool
->tde_array
, sizeof(TD_EXTENSION
) * UHCI_MAX_POOL_TDS
);
68 ptde
= ptd_pool
->tde_array
;
69 ptd_pool
->free_count
= 0;
70 ptd_pool
->total_count
= UHCI_MAX_POOL_TDS
;
71 InitializeListHead(&ptd_pool
->free_que
);
73 for(i
= 0; i
< UHCI_MAX_POOL_TDS
; i
++)
75 //link tde and the td one by one, fixed since this init
76 ptd_pool
->td_array
[i
>> 7][i
& 0x7f].ptde
= &ptde
[i
];
77 ptde
[i
].ptd
= &ptd_pool
->td_array
[i
>> 7][i
& 0x7f];
78 ptde
[i
].flags
= UHCI_ITEM_FLAG_TD
;
79 ptd_pool
->td_array
[i
>> 7][i
& 0x7f].phy_addr
=
80 ptd_pool
->logic_addr
[i
>> 7].LowPart
+ (i
& 0x7f) * sizeof(UHCI_TD
);
81 ptd_pool
->td_array
[i
>> 7][i
& 0x7f].pool
= ptd_pool
;
82 ptd_pool
->td_array
[i
>> 7][i
& 0x7f].purb
= NULL
;
83 free_td_to_pool(ptd_pool
, &ptd_pool
->td_array
[i
>> 7][i
& 0x7f]);
89 for(i
= 0; i
< pages
; i
++)
91 if (ptd_pool
->td_array
[i
])
93 HalFreeCommonBuffer(ptd_pool
->padapter
,
94 PAGE_SIZE
, ptd_pool
->logic_addr
[i
], ptd_pool
->td_array
[i
], FALSE
);
95 ptd_pool
->td_array
[i
] = NULL
;
96 ptd_pool
->logic_addr
[i
].QuadPart
= 0;
100 if (ptd_pool
->tde_array
)
101 usb_free_mem(ptd_pool
->tde_array
);
103 uhci_dbg_print(DBGLVL_MAXIMUM
, ("init_td_pool(): failed to init the td pool\n"));
106 ptd_pool
->free_count
= ptd_pool
->total_count
= 0;
110 //add tds till pnext == NULL
112 free_td_to_pool(PUHCI_TD_POOL ptd_pool
, PUHCI_TD ptd
)
114 if (ptd_pool
== NULL
|| ptd
== NULL
)
119 ptd
->link
= ptd
->status
= ptd
->info
= ptd
->buffer
= 0;
121 ptd_pool
->free_count
++;
123 InsertTailList(&ptd_pool
->free_que
, &ptd
->ptde
->vert_link
);
133 alloc_td_from_pool(PUHCI_TD_POOL ptd_pool
)
138 if (ptd_pool
== NULL
)
141 if (IsListEmpty(&ptd_pool
->free_que
))
144 temp
= RemoveHeadList(&ptd_pool
->free_que
);
149 ptde
= struct_ptr(temp
, TD_EXTENSION
, vert_link
);
151 ptd_pool
->free_count
--;
153 InitializeListHead(&ptde
->vert_link
);
154 InitializeListHead(&ptde
->hori_link
);
160 //test whether the pool is all free
162 is_pool_free(PUHCI_TD_POOL pool
)
167 if (pool
->free_count
== pool
->total_count
)
174 is_pool_empty(PUHCI_TD_POOL pool
)
179 return (BOOLEAN
) (pool
->free_count
== 0);
183 destroy_td_pool(PUHCI_TD_POOL ptd_pool
)
186 PADAPTER_OBJECT padapter
; //we need this garbage for allocation
188 padapter
= ptd_pool
->padapter
;
190 pages
= sizeof(UHCI_TD
) * UHCI_MAX_POOL_TDS
/ PAGE_SIZE
;
191 if (ptd_pool
&& ptd_pool
->padapter
)
193 usb_free_mem(ptd_pool
->tde_array
);
194 ptd_pool
->tde_array
= NULL
;
195 for(i
= 0; i
< pages
; i
++)
197 if (ptd_pool
->td_array
[i
])
199 HalFreeCommonBuffer(ptd_pool
->padapter
,
200 PAGE_SIZE
, ptd_pool
->logic_addr
[i
], ptd_pool
->td_array
[i
], FALSE
);
201 ptd_pool
->td_array
[i
] = NULL
;
202 ptd_pool
->logic_addr
[i
].QuadPart
= 0;
205 RtlZeroMemory(ptd_pool
, sizeof(UHCI_TD_POOL
));
206 ptd_pool
->padapter
= padapter
;
207 ptd_pool
->free_count
= ptd_pool
->total_count
= 0;
216 init_td_pool_list(PUHCI_TD_POOL_LIST pool_list
, PADAPTER_OBJECT padapter
)
219 RtlZeroMemory(pool_list
, sizeof(UHCI_TD_POOL_LIST
));
220 InitializeListHead(&pool_list
->busy_pools
);
221 InitializeListHead(&pool_list
->free_pools
);
223 pool_list
->free_count
= UHCI_MAX_TD_POOLS
;
224 pool_list
->free_tds
= 0;
226 for(i
= 0; i
< UHCI_MAX_TD_POOLS
; i
++)
228 pool_list
->pool_array
[i
].padapter
= padapter
;
229 InsertTailList(&pool_list
->free_pools
, &pool_list
->pool_array
[i
].pool_link
);
232 KeInitializeSpinLock(&pool_list
->pool_lock
);
233 return expand_pool_list(pool_list
, UHCI_MIN_TD_POOLS
);
237 destroy_td_pool_list(PUHCI_TD_POOL_LIST pool_list
)
240 while (IsListEmpty(&pool_list
->busy_pools
) == FALSE
)
242 pool
= (PUHCI_TD_POOL
) RemoveHeadList(&pool_list
->busy_pools
);
243 destroy_td_pool(pool
);
246 RtlZeroMemory(pool_list
, sizeof(UHCI_TD_POOL_LIST
));
251 expand_pool_list(PUHCI_TD_POOL_LIST pool_list
, LONG pool_count
) //private
256 if (IsListEmpty(&pool_list
->free_pools
) == TRUE
)
259 if (pool_list
->free_count
< pool_count
)
262 for(i
= 0; i
< pool_count
; i
++)
264 pool
= (PUHCI_TD_POOL
) RemoveHeadList(&pool_list
->free_pools
);
266 if (init_td_pool(pool
) == FALSE
)
268 //reverse the allocation
269 InsertHeadList(&pool_list
->free_pools
, &pool
->pool_link
);
270 // collect_garbage( pool_list );
274 InsertTailList(&pool_list
->busy_pools
, &pool
->pool_link
);
275 pool_list
->free_tds
+= UHCI_MAX_POOL_TDS
;
276 pool_list
->free_count
--;
282 collect_garbage(PUHCI_TD_POOL_LIST pool_list
)
284 PLIST_ENTRY prev
, next
;
287 if (pool_list
->free_count
>= UHCI_MAX_TD_POOLS
- UHCI_MIN_TD_POOLS
)
290 ListFirstPrev(&pool_list
->busy_pools
, prev
);
291 ListNext(&pool_list
->busy_pools
, prev
, next
);
293 while (next
&& next
!= &pool_list
->busy_pools
)
295 if (is_pool_free((PUHCI_TD_POOL
) next
))
297 RemoveEntryList(next
);
298 destroy_td_pool((PUHCI_TD_POOL
) next
);
299 InsertTailList(&pool_list
->free_pools
, next
);
300 pool_list
->free_count
++;
301 pool_list
->free_tds
-= UHCI_MAX_POOL_TDS
;
302 ListNext(&pool_list
->busy_pools
, prev
, next
);
303 if (pool_list
->free_count
>= UHCI_MAX_TD_POOLS
- UHCI_MIN_TD_POOLS
)
309 ListNext(&pool_list
->busy_pools
, prev
, next
);
318 get_num_free_tds(PUHCI_TD_POOL_LIST pool_list
)
320 return pool_list
->free_tds
;
325 get_max_free_tds(PUHCI_TD_POOL_LIST pool_list
)
327 return pool_list
->free_tds
+ pool_list
->free_count
* UHCI_MAX_POOL_TDS
;
330 //add tds till pnext == NULL
332 free_td(PUHCI_TD_POOL_LIST pool_list
, PUHCI_TD ptd
)
334 if (pool_list
== NULL
|| ptd
== NULL
)
337 if (free_td_to_pool(ptd
->pool
, ptd
) == FALSE
)
340 pool_list
->free_tds
++;
342 if (is_pool_free(ptd
->pool
))
344 collect_garbage(pool_list
);
351 alloc_td(PUHCI_TD_POOL_LIST pool_list
)
353 PLIST_ENTRY prev
, next
;
356 if (pool_list
== NULL
)
359 if (pool_list
->free_tds
== 0)
361 if (expand_pool_list(pool_list
, 1) == FALSE
)
365 ListFirst(&pool_list
->busy_pools
, prev
);
367 while (prev
&& prev
!= &pool_list
->busy_pools
)
369 if (is_pool_empty((PUHCI_TD_POOL
) prev
) == FALSE
)
371 new_td
= alloc_td_from_pool((PUHCI_TD_POOL
) prev
);
376 pool_list
->free_tds
--;
381 ListNext(&pool_list
->busy_pools
, prev
, next
);
389 alloc_tds(PUHCI_TD_POOL_LIST pool_list
, LONG count
)
391 //return value is a list of tds, vert_link chain.
396 if (pool_list
== NULL
|| count
<= 0)
399 if (count
>= get_max_free_tds(pool_list
))
402 ptd
= alloc_td(pool_list
);
403 if (!ptd
) return NULL
;
405 for(i
= 1; i
< count
; i
++)
407 pnext
= alloc_td(pool_list
);
411 InsertTailList(&ptd
->ptde
->vert_link
, &pnext
->ptde
->vert_link
);
417 uhci_dbg_print(DBGLVL_MEDIUM
, ("alloc_tds(): td pool-list free_tds=0x%x, free pools=0x%x\n",
418 pool_list
->free_tds
, pool_list
->free_count
));
425 free_tds(PUHCI_TD_POOL_LIST pool_list
, PUHCI_TD ptd
)
430 if (pool_list
== NULL
|| ptd
== NULL
)
433 while (IsListEmpty(&ptd
->ptde
->vert_link
) == FALSE
)
435 pthis
= RemoveHeadList(&ptd
->ptde
->vert_link
);
436 ptofree
= ((PTD_EXTENSION
) pthis
)->ptd
;
437 free_td(pool_list
, ptofree
);
440 free_td(pool_list
, ptd
);
447 can_transfer(PUHCI_TD_POOL_LIST pool_list
, LONG td_count
)
449 if (td_count
> get_max_free_tds(pool_list
))
456 lock_td_pool(PUHCI_TD_POOL_LIST pool_list
, BOOLEAN at_dpc
)
459 // KeAcquireSpinLock( &pool_list->pool_lock );
461 // KeAcquireSpinLockAtDpcLevel( &pool_list->pool_lock );
465 unlock_td_pool(PUHCI_TD_POOL_LIST pool_list
, BOOLEAN at_dpc
)
468 // KeReleaseSpinLock( &pool_list->pool_lock );
470 // KeReleaseSpinLockFromDpcLevel( &pool_list->pool_lock );
474 init_qh_pool(PUHCI_QH_POOL pqh_pool
, PADAPTER_OBJECT padapter
)
479 if (pqh_pool
== NULL
|| padapter
== NULL
)
482 pqh_pool
->padapter
= padapter
;
484 pqh_pool
->qhe_array
= (PQH_EXTENSION
) usb_alloc_mem(NonPagedPool
,
485 sizeof(QH_EXTENSION
) * UHCI_MAX_POOL_QHS
);
487 if (pqh_pool
->qhe_array
== NULL
)
491 (PUHCI_QH
) HalAllocateCommonBuffer(padapter
,
492 sizeof(UHCI_QH
) * UHCI_MAX_POOL_QHS
, &pqh_pool
->logic_addr
, FALSE
);
494 if (pqh_pool
->qh_array
== NULL
)
496 usb_free_mem(pqh_pool
->qhe_array
);
497 pqh_pool
->qhe_array
= NULL
;
501 pqhe
= pqh_pool
->qhe_array
;
503 pqh_pool
->free_count
= 0;
504 pqh_pool
->total_count
= UHCI_MAX_POOL_TDS
;
506 KeInitializeSpinLock(&pqh_pool
->pool_lock
);
507 InitializeListHead(&pqh_pool
->free_que
);
510 for(i
= 0; i
< UHCI_MAX_POOL_QHS
; i
++)
512 pqh_pool
->qh_array
[i
].pqhe
= &pqhe
[i
];
513 pqhe
[i
].pqh
= &pqh_pool
->qh_array
[i
];
515 pqh_pool
->qh_array
[i
].phy_addr
= (pqh_pool
->logic_addr
.LowPart
+ (sizeof(UHCI_QH
) * i
)) | UHCI_PTR_QH
;
516 //pqh_pool->qh_array[i].reserved = 0;
518 //always breadth first
519 pqhe
[i
].flags
= UHCI_ITEM_FLAG_QH
;
521 free_qh(pqh_pool
, &pqh_pool
->qh_array
[i
]);
528 //add qhs till pnext == NULL
530 free_qh(PUHCI_QH_POOL pqh_pool
, PUHCI_QH pqh
)
532 if (pqh_pool
== NULL
|| pqh
== NULL
)
535 pqh
->link
= pqh
->element
= 0;
536 pqh
->pqhe
->purb
= NULL
;
537 InsertTailList(&pqh_pool
->free_que
, &pqh
->pqhe
->vert_link
);
538 pqh_pool
->free_count
++;
545 alloc_qh(PUHCI_QH_POOL pqh_pool
)
549 if (pqh_pool
== NULL
)
552 if (IsListEmpty(&pqh_pool
->free_que
))
555 pqhe
= (PQH_EXTENSION
) RemoveHeadList(&pqh_pool
->free_que
);
559 InitializeListHead(&pqhe
->hori_link
);
560 InitializeListHead(&pqhe
->vert_link
);
568 destroy_qh_pool(PUHCI_QH_POOL pqh_pool
)
572 usb_free_mem(pqh_pool
->qhe_array
);
574 HalFreeCommonBuffer(pqh_pool
->padapter
,
575 sizeof(UHCI_QH
) * UHCI_MAX_POOL_QHS
,
576 pqh_pool
->logic_addr
, pqh_pool
->qh_array
, FALSE
);
578 RtlZeroMemory(pqh_pool
, sizeof(UHCI_QH_POOL
));
588 lock_qh_pool(PUHCI_QH_POOL pool
, BOOLEAN at_dpc
)
591 // KeAcquireSpinLock( &pool->pool_lock );
593 // KeAcquireSpinLockAtDpcLevel( &pool->pool_lock );
597 unlock_qh_pool(PUHCI_QH_POOL pool
, BOOLEAN at_dpc
)
600 // KeReleaseSpinLock( &pool->pool_lock );
602 // KeReleaseSpinLockFromDpcLevel( &pool->pool_lock );