The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / drivers / usb / nt4compat / usbdriver / ohci.c
1 /**
2 * ohci.c - USB driver stack project
3 *
4 * Copyright (c) 2007 Aleksey Bragin <aleksey@reactos.org>
5 * based on some code by Zhiming <mypublic99@yahoo.com>
6 *
7 * This program/include file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program/include file is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program (in the main directory of the distribution, the file
19 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
20 * Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include "usbdriver.h"
24 #include "ehci.h"
25 #include "ohci.h"
26
27 PDEVICE_OBJECT ohci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path,
28 ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr);
29 //BOOLEAN ohci_release(PDEVICE_OBJECT pdev);
30 //static VOID ohci_stop(PEHCI_DEV ehci);
31 PDEVICE_OBJECT ohci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path,
32 PUSB_DEV_MANAGER dev_mgr);
33 PDEVICE_OBJECT ohci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr);
34 //BOOLEAN ohci_delete_device(PDEVICE_OBJECT pdev);
35 //VOID ohci_get_capabilities(PEHCI_DEV ehci, PBYTE base);
36 //BOOLEAN NTAPI ohci_isr(PKINTERRUPT interrupt, PVOID context);
37 //BOOLEAN ohci_start(PHCD hcd);
38 VOID ohci_init_hcd_interface(POHCI_DEV ohci);
39 BOOLEAN ohci_rh_reset_port(PHCD hcd, UCHAR port_idx);
40 VOID ohci_generic_urb_completion(PURB purb, PVOID context);
41
42 // shared with EHCI
43 NTSTATUS ehci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
44 PUSB_DEV_MANAGER ehci_get_dev_mgr(PHCD hcd);
45 VOID ehci_set_dev_mgr(PHCD hcd, PUSB_DEV_MANAGER dev_mgr);
46 VOID ehci_set_id(PHCD hcd, UCHAR id);
47 UCHAR ehci_get_id(PHCD hcd);
48 UCHAR ehci_alloc_addr(PHCD hcd);
49 VOID ehci_free_addr(PHCD hcd, UCHAR addr);
50 BOOLEAN NTAPI ehci_cal_cpu_freq(PVOID context);
51
52 VOID rh_timer_svc_int_completion(PUSB_DEV pdev, PVOID context);
53 VOID rh_timer_svc_reset_port_completion(PUSB_DEV pdev, PVOID context);
54
55 extern USB_DEV_MANAGER g_dev_mgr;
56
57 /* wrap-aware logic morphed from <linux/jiffies.h> */
58 #define tick_before(t1,t2) ((SHORT)(((SHORT)(t1))-((SHORT)(t2))) < 0)
59
60 #define OHCI_READ_PORT_ULONG( pul ) ( *pul )
61 #define OHCI_WRITE_PORT_ULONG( pul, src ) \
62 {\
63 *pul = ( ULONG )src;\
64 }
65
66 #define OHCI_READ_PORT_UCHAR( pch ) ( *pch )
67 #define OHCI_WRITE_PORT_UCHAR( pch, src ) ( *pch = ( UCHAR )src )
68 #define OHCI_READ_PORT_USHORT( psh ) ( *psh )
69 #define OHCI_WRITE_PORT_USHORT( psh, src ) ( *psh = ( USHORT )src )
70
71 /* AMD-756 (D2 rev) reports corrupt register contents in some cases.
72 * The erratum (#4) description is incorrect. AMD's workaround waits
73 * till some bits (mostly reserved) are clear; ok for all revs.
74 */
75 #define read_roothub(hc, register, mask) ({ \
76 ULONG temp = OHCI_READ_PORT_ULONG(&((hc)->regs->roothub.register)); \
77 if (temp == -1) \
78 /*disable (hc)*/; \
79 /*else if (hc->flags & OHCI_QUIRK_AMD756) \
80 while (temp & mask) \
81 temp = ohci_readl (hc, &hc->regs->roothub.register); */ \
82 temp; })
83
84 static ULONG roothub_a (POHCI_DEV hc)
85 { return read_roothub (hc, a, 0xfc0fe000); }
86 /*
87 static inline u32 roothub_b (struct ohci_hcd *hc)
88 { return ohci_readl (hc, &hc->regs->roothub.b); }
89 static inline u32 roothub_status (struct ohci_hcd *hc)
90 { return ohci_readl (hc, &hc->regs->roothub.status); }
91 static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
92 { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
93 */
94
95
96 /* For initializing controller (mask in an HCFS mode too) */
97 #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
98 #define OHCI_INTR_INIT \
99 (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
100
101 /* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling,
102 * not necessarily continuous ... to guard against resume signaling.
103 * The short timeout is safe for non-root hubs, and is backward-compatible
104 * with earlier Linux hosts.
105 */
106 #ifdef CONFIG_USB_SUSPEND
107 #define PORT_RESET_MSEC 50
108 #else
109 #define PORT_RESET_MSEC 10
110 #endif
111
112 /* this timer value might be vendor-specific ... */
113 #define PORT_RESET_HW_MSEC 10
114
115 #define DEFAULT_ENDP( enDP ) \
116 ( enDP->flags & USB_ENDP_FLAG_DEFAULT_ENDP )
117
118 #define dev_from_endp( enDP ) \
119 ( DEFAULT_ENDP( enDP )\
120 ? ( ( PUSB_DEV )( enDP )->pusb_if )\
121 : ( ( enDP )->pusb_if->pusb_config->pusb_dev ) )
122
123 #define endp_state( enDP ) ( ( enDP )->flags & USB_ENDP_FLAG_STAT_MASK )
124
125 #define endp_num( enDP ) \
126 ( DEFAULT_ENDP( enDP )\
127 ? 0 \
128 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & 0x0f ) )
129
130 #define endp_dir( enDP ) \
131 ( DEFAULT_ENDP( enDP )\
132 ? 0L\
133 : ( ( enDP )->pusb_endp_desc->bEndpointAddress & USB_DIR_IN ) )
134
135 #define dev_set_state( pdEV, staTE ) \
136 ( pdEV->flags = ( ( pdEV )->flags & ( ~USB_DEV_STATE_MASK ) ) | ( staTE ) )
137
138 #define endp_max_packet_size( enDP ) \
139 ( DEFAULT_ENDP( enDP )\
140 ? ( ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc ? \
141 ( ( PUSB_DEV )enDP->pusb_if )->pusb_dev_desc->bMaxPacketSize0\
142 : 8 )\
143 : ( enDP->pusb_endp_desc->wMaxPacketSize & 0x7ff ) )
144
145 #define endp_mult_count( endp ) ( ( ( endp->pusb_endp_desc->wMaxPacketSize & 0x1800 ) >> 11 ) + 1 )
146
147 #define get_parent_hs_hub( pDEV, parent_HUB, port_IDX ) \
148 {\
149 parent_HUB = pDEV->parent_dev;\
150 port_IDX = pdev->port_idx;\
151 while( parent_HUB )\
152 {\
153 if( ( parent_HUB->flags & USB_DEV_CLASS_MASK ) != USB_DEV_CLASS_HUB )\
154 {\
155 parent_HUB = NULL;\
156 break;\
157 }\
158 if( ( parent_HUB->flags & USB_DEV_FLAG_HIGH_SPEED ) == 0 )\
159 {\
160 port_IDX = parent_HUB->port_idx;\
161 parent_HUB = parent_HUB->parent_dev;\
162 continue;\
163 }\
164 break;\
165 }\
166 }
167
168 VOID
169 ohci_wait_ms(POHCI_DEV ohci, LONG ms)
170 {
171 LARGE_INTEGER lms;
172 if (ms <= 0)
173 return;
174
175 lms.QuadPart = -10 * ms;
176 KeSetTimer(&ohci->reset_timer, lms, NULL);
177
178 KeWaitForSingleObject(&ohci->reset_timer, Executive, KernelMode, FALSE, NULL);
179
180 return;
181 }
182
183 PDEVICE_OBJECT ohci_probe(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path,
184 PUSB_DEV_MANAGER dev_mgr)
185 {
186 LONG bus, i, j, ret = 0;
187 PCI_SLOT_NUMBER slot_num;
188 PPCI_COMMON_CONFIG pci_config;
189 PDEVICE_OBJECT pdev;
190 BYTE buffer[sizeof(PCI_COMMON_CONFIG)];
191 POHCI_DEVICE_EXTENSION pdev_ext;
192
193 slot_num.u.AsULONG = 0;
194 pci_config = (PPCI_COMMON_CONFIG) buffer;
195 pdev = NULL;
196
197 //scan the bus to find ohci controller
198 for(bus = 0; bus < 2; bus++) /*enum only bus0 and bus1 */
199 {
200 for(i = 0; i < PCI_MAX_DEVICES; i++)
201 {
202 slot_num.u.bits.DeviceNumber = i;
203 for(j = 0; j < PCI_MAX_FUNCTIONS; j++)
204 {
205 slot_num.u.bits.FunctionNumber = j;
206
207 ret = HalGetBusData(PCIConfiguration,
208 bus, slot_num.u.AsULONG, pci_config, PCI_COMMON_HDR_LENGTH);
209
210 /* Don't look further on this device */
211 if ((ret == 0) || (ret == 2))
212 break;
213
214 if (pci_config->BaseClass == 0x0c && pci_config->SubClass == 0x03
215 && pci_config->ProgIf == 0x10)
216 {
217 // we found our usb host controller( OHCI ), create device
218 pdev = ohci_alloc(drvr_obj, reg_path, ((bus << 8) | (i << 3) | j), dev_mgr);
219
220 if (!pdev)
221 continue;
222 }
223 }
224
225 if (ret == 0)
226 break;
227 }
228 }
229
230 if (pdev)
231 {
232 pdev_ext = pdev->DeviceExtension;
233 if (pdev_ext)
234 {
235 // acquire higher irql to eliminate pre-empty
236 //KeSynchronizeExecution(pdev_ext->ohci_int, ehci_cal_cpu_freq, NULL);
237 }
238 }
239 return NULL;
240 }
241
242 BOOLEAN ohci_mem_init (POHCI_DEVICE_EXTENSION dev_ext)
243 {
244 dev_ext->ohci->td_cache = HalAllocateCommonBuffer(dev_ext->padapter,
245 sizeof(OHCI_TD), &dev_ext->ohci->td_logic_addr, FALSE);
246
247 if (!dev_ext->ohci->td_cache)
248 return FALSE;
249
250 dev_ext->ohci->ed_cache = HalAllocateCommonBuffer(dev_ext->padapter,
251 sizeof(OHCI_ED), &dev_ext->ohci->ed_logic_addr, FALSE);
252
253 if (!dev_ext->ohci->ed_cache)
254 {
255 HalFreeCommonBuffer(dev_ext->padapter, sizeof(OHCI_TD), dev_ext->ohci->td_logic_addr,
256 dev_ext->ohci->td_cache, FALSE);
257 return FALSE;
258 }
259
260 return TRUE;
261 }
262
263
264 PDEVICE_OBJECT
265 ohci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PUSB_DEV_MANAGER dev_mgr)
266 {
267 LONG frd_num, prd_num;
268 PDEVICE_OBJECT pdev = NULL;
269 POHCI_DEVICE_EXTENSION pdev_ext;
270 ULONG addr_space;
271 //ULONG vector;
272 LONG bus;
273 //KIRQL irql;
274 //KAFFINITY affinity;
275
276 DEVICE_DESCRIPTION dev_desc;
277 CM_PARTIAL_RESOURCE_DESCRIPTOR *pprd;
278 PCI_SLOT_NUMBER slot_num;
279 NTSTATUS status;
280
281 pdev = ohci_create_device(drvr_obj, dev_mgr);
282
283 if (pdev == NULL)
284 return NULL;
285
286 pdev_ext = pdev->DeviceExtension;
287
288 pdev_ext->pci_addr = bus_addr;
289 bus = (bus_addr >> 8);
290
291 slot_num.u.AsULONG = 0;
292 slot_num.u.bits.DeviceNumber = ((bus_addr & 0xff) >> 3);
293 slot_num.u.bits.FunctionNumber = (bus_addr & 0x07);
294
295 //now create adapter object
296 RtlZeroMemory(&dev_desc, sizeof(dev_desc));
297
298 dev_desc.Version = DEVICE_DESCRIPTION_VERSION;
299 dev_desc.Master = TRUE;
300 dev_desc.ScatterGather = TRUE;
301 dev_desc.Dma32BitAddresses = TRUE;
302 dev_desc.BusNumber = bus;
303 dev_desc.InterfaceType = PCIBus;
304 dev_desc.MaximumLength = EHCI_MAX_SIZE_TRANSFER;
305 pdev_ext->map_regs = 2; // we do not use it seriously
306 pdev_ext->padapter = HalGetAdapter(&dev_desc, &pdev_ext->map_regs);
307
308 DbgPrint("ohci_alloc(): reg_path=0x%x, \n \
309 ohci_alloc(): bus=0x%x, bus_addr=0x%x \n \
310 ohci_alloc(): slot_num=0x%x \n \
311 ", (DWORD) reg_path, (DWORD) bus, (DWORD) bus_addr, (DWORD) slot_num.u.AsULONG);
312
313 //let's allocate resources for this device
314 DbgPrint("ohci_alloc(): about to assign slot res\n");
315 if ((status = HalAssignSlotResources(reg_path, NULL, //no class name yet
316 drvr_obj, NULL, //no support of another ehci controller
317 PCIBus,
318 bus, slot_num.u.AsULONG, &pdev_ext->res_list)) != STATUS_SUCCESS)
319 {
320 DbgPrint("ohci_alloc(): error assign slot res, 0x%x\n", status);
321 #if 0
322 release_adapter(pdev_ext->padapter);
323 pdev_ext->padapter = NULL;
324 ohci_delete_device(pdev);
325 #endif
326 return NULL;
327 }
328
329 //parse the resource list
330 for(frd_num = 0; frd_num < (LONG) pdev_ext->res_list->Count; frd_num++)
331 {
332 for(prd_num = 0; prd_num < (LONG) pdev_ext->res_list->List[frd_num].PartialResourceList.Count;
333 prd_num++)
334 {
335 pprd = &pdev_ext->res_list->List[frd_num].PartialResourceList.PartialDescriptors[prd_num];
336 if (pprd->Type == CmResourceTypePort)
337 {
338 RtlCopyMemory(&pdev_ext->res_port, &pprd->u.Port, sizeof(pprd->u.Port));
339
340 }
341 else if (pprd->Type == CmResourceTypeInterrupt)
342 {
343 RtlCopyMemory(&pdev_ext->res_interrupt, &pprd->u.Interrupt, sizeof(pprd->u.Interrupt));
344 }
345 else if (pprd->Type == CmResourceTypeMemory)
346 {
347 RtlCopyMemory(&pdev_ext->res_memory, &pprd->u.Memory, sizeof(pprd->u.Memory));
348 }
349 }
350 }
351
352 //for port, translate them to system address
353 addr_space = 0;
354 if (HalTranslateBusAddress(PCIBus, bus, pdev_ext->res_port.Start, &addr_space, //io space
355 &pdev_ext->ohci->ohci_reg_base) != (BOOLEAN) TRUE)
356 {
357 DbgPrint("ohci_alloc(): error, can not translate bus address\n");
358 #if 0
359 release_adapter(pdev_ext->padapter);
360 pdev_ext->padapter = NULL;
361 ehci_delete_device(pdev);
362 #endif
363 return NULL;
364 }
365
366 DbgPrint("ohci_alloc(): address space=0x%x\n, reg_base=0x%x\n",
367 addr_space, pdev_ext->ohci->ohci_reg_base.u.LowPart);
368
369 if (addr_space == 0)
370 {
371 //port has been mapped to memory space
372 pdev_ext->ohci->port_mapped = TRUE;
373 pdev_ext->ohci->port_base = (PBYTE) MmMapIoSpace(pdev_ext->ohci->ohci_reg_base,
374 pdev_ext->res_port.Length, FALSE);
375
376 //fatal error can not map the registers
377 if (pdev_ext->ohci->port_base == NULL)
378 {
379 #if 0
380 release_adapter(pdev_ext->padapter);
381 pdev_ext->padapter = NULL;
382 ehci_delete_device(pdev);
383 #endif
384 return NULL;
385 }
386 }
387 else
388 {
389 //io space
390 pdev_ext->ohci->port_mapped = FALSE;
391 pdev_ext->ohci->port_base = (PBYTE) pdev_ext->ohci->ohci_reg_base.LowPart;
392 }
393
394 //before we connect the interrupt, we have to init ohci
395 pdev_ext->ohci->pdev_ext = pdev_ext;
396 pdev_ext->ohci->regs = (POHCI_REGS)pdev_ext->ohci->port_base;
397
398 KeInitializeTimer(&pdev_ext->ohci->reset_timer);
399
400 // take it over from SMM/BIOS/whoever has it
401 if (OHCI_READ_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_CONTROL)) & OHCI_CTRL_IR)
402 {
403 ULONG temp;
404
405 DbgPrint("USB HC TakeOver from BIOS/SMM\n");
406
407 /* this timeout is arbitrary. we make it long, so systems
408 * depending on usb keyboards may be usable even if the
409 * BIOS/SMM code seems pretty broken.
410 */
411 temp = 500; /* arbitrary: five seconds */
412
413 OHCI_WRITE_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_INTRENABLE), OHCI_INTR_OC);
414 OHCI_WRITE_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_CMDSTATUS), OHCI_OCR);
415
416 while (OHCI_READ_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_CONTROL)) & OHCI_CTRL_IR)
417 {
418 ohci_wait_ms(pdev_ext->ohci, 10);
419 if (--temp == 0) {
420 DbgPrint("USB HC takeover failed!"
421 " (BIOS/SMM bug)\n");
422 return NULL;
423 }
424 }
425 //ohci_usb_reset (ohci);
426 }
427
428 /* Disable HC interrupts */
429 OHCI_WRITE_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_INTRDISABLE), OHCI_INTR_MIE);
430 // flush the writes
431 (VOID)OHCI_READ_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_CONTROL));
432
433 /* Read the number of ports unless overridden */
434 pdev_ext->ohci->num_ports = roothub_a(pdev_ext->ohci) & RH_A_NDP;
435
436 DbgPrint("OHCI: %d ports\n", pdev_ext->ohci->num_ports);
437
438 pdev_ext->ohci->hcca = HalAllocateCommonBuffer(pdev_ext->padapter,
439 sizeof(*pdev_ext->ohci->hcca), &pdev_ext->ohci->hcca_logic_addr, FALSE);
440
441 if (!pdev_ext->ohci->hcca)
442 {
443 DbgPrint("OHCI: HCCA allocation failed!\n");
444 return NULL;
445 }
446
447 if (!ohci_mem_init(pdev_ext))
448 {
449 DbgPrint("OHCI: Mem init failed!\n");
450 return NULL;
451 }
452
453 #if 0
454 if (ehci_init_schedule(pdev_ext->ehci, pdev_ext->padapter) == FALSE)
455 {
456 release_adapter(pdev_ext->padapter);
457 pdev_ext->padapter = NULL;
458 ehci_delete_device(pdev);
459 return NULL;
460 }
461 #endif
462
463 InitializeListHead(&pdev_ext->ohci->urb_list);
464 KeInitializeSpinLock(&pdev_ext->ohci->pending_endp_list_lock);
465 InitializeListHead(&pdev_ext->ohci->pending_endp_list);
466
467 ohci_dbg_print(DBGLVL_MAXIMUM, ("ohci_alloc(): pending_endp_list=0x%x\n",
468 &pdev_ext->ohci->pending_endp_list));
469
470 init_pending_endp_pool(&pdev_ext->ohci->pending_endp_pool);
471
472 #if 0
473 vector = HalGetInterruptVector(PCIBus,
474 bus,
475 pdev_ext->res_interrupt.level,
476 pdev_ext->res_interrupt.vector, &irql, &affinity);
477
478 //connect the interrupt
479 DbgPrint("ehci_alloc(): the int=0x%x\n", vector);
480 if ((status = IoConnectInterrupt(&pdev_ext->ehci_int, ehci_isr, pdev_ext->ehci, NULL, //&pdev_ext->ehci->frame_list_lock,
481 vector, irql, irql, LevelSensitive, TRUE, //share the vector
482 affinity, FALSE)) //No float save
483 != STATUS_SUCCESS)
484 {
485 DbgPrint("ehci_alloc(): Failed to connect interrupt, status = 0x%x!\n", status);
486 ehci_release(pdev);
487 return NULL;
488 }
489
490 KeInitializeDpc(&pdev_ext->ehci_dpc, ehci_dpc_callback, (PVOID) pdev_ext->ehci);
491 #endif
492
493 return pdev;
494 }
495
496 PDEVICE_OBJECT
497 ohci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
498 {
499 NTSTATUS status;
500 PDEVICE_OBJECT pdev;
501 POHCI_DEVICE_EXTENSION pdev_ext;
502
503 UNICODE_STRING dev_name;
504 UNICODE_STRING symb_name;
505
506 STRING string, another_string;
507 CHAR str_dev_name[64], str_symb_name[64];
508 UCHAR hcd_id;
509
510 if (drvr_obj == NULL)
511 return NULL;
512
513 //note: hcd count wont increment till the hcd is registered in dev_mgr
514 sprintf(str_dev_name, "%s%d", OHCI_DEVICE_NAME, dev_mgr->hcd_count);
515 sprintf(str_symb_name, "%s%d", OHCI_DOS_DEVICE_NAME, dev_mgr->hcd_count);
516
517 RtlInitString(&string, str_dev_name);
518 RtlAnsiStringToUnicodeString(&dev_name, &string, TRUE);
519
520 pdev = NULL;
521 status = IoCreateDevice(drvr_obj,
522 sizeof(OHCI_DEVICE_EXTENSION) + sizeof(OHCI_DEV),
523 &dev_name, FILE_OHCI_DEV_TYPE, 0, FALSE, &pdev);
524
525 if (status != STATUS_SUCCESS || pdev == NULL)
526 {
527 RtlFreeUnicodeString(&dev_name);
528 ehci_dbg_print(DBGLVL_MAXIMUM, ("ohci_create_device(): error create device 0x%x\n", status));
529 return NULL;
530 }
531
532 pdev_ext = pdev->DeviceExtension;
533 RtlZeroMemory(pdev_ext, sizeof(OHCI_DEVICE_EXTENSION) + sizeof(OHCI_DEV));
534
535 pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_HCD;
536 pdev_ext->dev_ext_hdr.dispatch = ehci_dispatch_irp;
537 pdev_ext->dev_ext_hdr.start_io = NULL; //we do not support startio
538 pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
539
540 pdev_ext->pdev_obj = pdev;
541 pdev_ext->pdrvr_obj = drvr_obj;
542
543 pdev_ext->ohci = (POHCI_DEV) & (pdev_ext[1]);
544
545 RtlInitString(&another_string, str_symb_name);
546 RtlAnsiStringToUnicodeString(&symb_name, &another_string, TRUE);
547 //RtlInitUnicodeString( &symb_name, DOS_DEVICE_NAME );
548
549 IoCreateSymbolicLink(&symb_name, &dev_name);
550
551 ehci_dbg_print(DBGLVL_MAXIMUM,
552 ("ohci_create_device(): dev=0x%x\n, pdev_ext= 0x%x, ehci=0x%x, dev_mgr=0x%x\n", pdev,
553 pdev_ext, pdev_ext->ohci, dev_mgr));
554
555 RtlFreeUnicodeString(&dev_name);
556 RtlFreeUnicodeString(&symb_name);
557
558 //register with dev_mgr though it is not initilized
559 ohci_init_hcd_interface(pdev_ext->ohci);
560 hcd_id = dev_mgr_register_hcd(dev_mgr, &pdev_ext->ohci->hcd_interf);
561
562 pdev_ext->ohci->hcd_interf.hcd_set_id(&pdev_ext->ohci->hcd_interf, hcd_id);
563 pdev_ext->ohci->hcd_interf.hcd_set_dev_mgr(&pdev_ext->ohci->hcd_interf, dev_mgr);
564
565 return pdev;
566 }
567
568 BOOLEAN
569 ohci_start(PHCD hcd)
570 {
571 ULONG temp, mask;
572 //PBYTE base;
573 //PEHCI_USBCMD_CONTENT usbcmd;
574 POHCI_DEV ohci;
575 ULONG hc_control;
576
577 if (hcd == NULL)
578 return FALSE;
579
580 ohci = struct_ptr(hcd, OHCI_DEV, hcd_interf);
581
582 /* Reset USB nearly "by the book". RemoteWakeupConnected
583 * saved if boot firmware (BIOS/SMM/...) told us it's connected
584 * (for OHCI integrated on mainboard, it normally is)
585 */
586 hc_control = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->control);
587 DbgPrint("OHCI: resetting from state %x, control = 0x%x\n",
588 (hc_control & OHCI_CTRL_HCFS),
589 hc_control);
590
591 //if (hc_control & OHCI_CTRL_RWC
592 // && !(ohci->flags & OHCI_QUIRK_AMD756))
593 // ohci_to_hcd(ohci)->can_wakeup = 1;
594
595 switch (hc_control & OHCI_CTRL_HCFS) {
596 case OHCI_USB_OPER:
597 temp = 0;
598 break;
599 case OHCI_USB_SUSPEND:
600 case OHCI_USB_RESUME:
601 hc_control &= OHCI_CTRL_RWC;
602 hc_control |= OHCI_USB_RESUME;
603 temp = 10 /* msec wait */;
604 break;
605 // case OHCI_USB_RESET:
606 default:
607 hc_control &= OHCI_CTRL_RWC;
608 hc_control |= OHCI_USB_RESET;
609 temp = 50 /* msec wait */;
610 break;
611 }
612 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->control, hc_control);
613
614 // flush the writes
615 (VOID)OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->control);
616
617 ohci_wait_ms(ohci, temp);
618 temp = roothub_a (ohci);
619 if (!(temp & RH_A_NPS)) {
620 /* power down each port */
621 for (temp = 0; temp < ohci->num_ports; temp++)
622 {
623 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus [temp], RH_PS_LSDA);
624 }
625 }
626 // flush those writes
627 (VOID)OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->control);
628 RtlZeroMemory(ohci->hcca, sizeof(OHCI_HCCA));
629
630 /* 2msec timelimit here means no irqs/preempt */
631 //spin_lock_irq (&ohci->lock);
632
633 //retry:
634 /* HC Reset requires max 10 us delay */
635 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->cmdstatus, OHCI_HCR);
636 temp = 30; /* ... allow extra time */
637 while ((OHCI_READ_PORT_ULONG ((PULONG)&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
638 if (--temp == 0) {
639 //spin_unlock_irq (&ohci->lock);
640 //ohci_err (ohci, "USB HC reset timed out!\n");
641 DbgPrint("OHCI: USB HC reset timed out!\n");
642 return FALSE;
643 }
644 KeStallExecutionProcessor(1);
645 }
646
647 /* now we're in the SUSPEND state ... must go OPERATIONAL
648 * within 2msec else HC enters RESUME
649 *
650 * ... but some hardware won't init fmInterval "by the book"
651 * (SiS, OPTi ...), so reset again instead. SiS doesn't need
652 * this if we write fmInterval after we're OPERATIONAL.
653 * Unclear about ALi, ServerWorks, and others ... this could
654 * easily be a longstanding bug in chip init on Linux.
655 */
656 #if 0
657 if (ohci->flags & OHCI_QUIRK_INITRESET) {
658 ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
659 // flush those writes
660 (void) ohci_readl (ohci, &ohci->regs->control);
661 }
662 #endif
663 /* Tell the controller where the control and bulk lists are
664 * The lists are empty now. */
665 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->ed_controlhead, 0);
666 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->ed_bulkhead, 0);
667
668 /* a reset clears this */
669 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->hcca, (ULONG)ohci->hcca_logic_addr.LowPart);
670
671 //periodic_reinit (ohci);
672
673 /* start controller operations */
674 hc_control &= OHCI_CTRL_RWC;
675 hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
676 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->control, hc_control);
677 //ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
678
679 /* wake on ConnectStatusChange, matching external hubs */
680 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.status, RH_HS_DRWE);
681
682 /* Choose the interrupts we care about now, others later on demand */
683 mask = OHCI_INTR_INIT;
684 //OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->intrstatus, mask);
685 //OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->intrenable, mask);
686
687 /* handle root hub init quirks ... */
688 temp = roothub_a(ohci);
689 temp &= ~(RH_A_PSM | RH_A_OCPM);
690 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.status, RH_HS_LPSC);
691 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.b, (temp & RH_A_NPS) ? 0 : RH_B_PPCM);
692 // flush those writes
693 (VOID)OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->control);
694
695 //spin_unlock_irq (&ohci->lock);
696
697 // POTPGT delay is bits 24-31, in 2 ms units.
698 ohci_wait_ms(ohci, (temp >> 23) & 0x1fe);
699 //ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
700
701
702 // Debug code follows!
703 /*(VOID)ohci_rh_reset_port(hcd, 1);
704 (VOID)ohci_rh_reset_port(hcd, 2);
705 (VOID)ohci_rh_reset_port(hcd, 3);
706 (VOID)ohci_rh_reset_port(hcd, 4);*/
707 // Debug code ends!
708
709
710 return TRUE;
711 }
712
713 static VOID NTAPI
714 ohci_cancel_pending_endp_urb(IN PVOID Parameter)
715 {
716 PLIST_ENTRY abort_list;
717 PUSB_DEV pdev;
718 PURB purb;
719 USE_BASIC_NON_PENDING_IRQL;
720
721 abort_list = (PLIST_ENTRY) Parameter;
722
723 if (abort_list == NULL)
724 return;
725
726 while (IsListEmpty(abort_list) == FALSE)
727 {
728 //these devs are protected by purb's ref-count
729 purb = (PURB) RemoveHeadList(abort_list);
730 pdev = purb->pdev;
731 // purb->status is set when they are added to abort_list
732
733 ohci_generic_urb_completion(purb, purb->context);
734
735 lock_dev(pdev, FALSE);
736 pdev->ref_count--;
737 unlock_dev(pdev, FALSE);
738 }
739 usb_free_mem(abort_list);
740 return;
741 }
742
743 static NTSTATUS
744 ohci_internal_submit_bulk(POHCI_DEV ohci, PURB purb)
745 {
746 return STATUS_SUCCESS;
747 }
748
749 static NTSTATUS
750 ohci_internal_submit_ctrl(POHCI_DEV ohci, PURB purb)
751 {
752 return STATUS_SUCCESS;
753 }
754
755 static NTSTATUS
756 ohci_internal_submit_int(POHCI_DEV ohci, PURB purb)
757 {
758 return STATUS_SUCCESS;
759 }
760
761 static NTSTATUS
762 ohci_internal_submit_iso(POHCI_DEV ohci, PURB purb)
763 {
764 return STATUS_SUCCESS;
765 }
766
767
768 static BOOLEAN
769 ohci_process_pending_endp(POHCI_DEV ehci)
770 {
771 PUSB_DEV pdev;
772 LIST_ENTRY temp_list, abort_list;
773 PLIST_ENTRY pthis;
774 PURB purb;
775 PUSB_ENDPOINT pendp;
776 NTSTATUS can_submit = STATUS_SUCCESS;
777 PWORK_QUEUE_ITEM pwork_item;
778 PLIST_ENTRY cancel_list;
779 PUSB_DEV pparent = NULL;
780 UCHAR port_idx = 0;
781 BOOLEAN tt_needed;
782 UCHAR hub_addr = 0;
783 USE_BASIC_IRQL;
784
785 if (ehci == NULL)
786 return FALSE;
787
788 InitializeListHead(&temp_list);
789 InitializeListHead(&abort_list);
790
791 purb = NULL;
792 ohci_dbg_print(DBGLVL_MEDIUM, ("ohci_process_pending_endp(): entering..., ehci=0x%x\n", ehci));
793
794 lock_pending_endp_list(&ehci->pending_endp_list_lock);
795 while (IsListEmpty(&ehci->pending_endp_list) == FALSE)
796 {
797
798 ehci_dbg_print(DBGLVL_MAXIMUM, ("ohci_process_pending_endp(): pending_endp_list=0x%x\n",
799 &ehci->pending_endp_list));
800
801 tt_needed = FALSE;
802 pthis = RemoveHeadList(&ehci->pending_endp_list);
803 pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
804 pdev = dev_from_endp(pendp);
805 lock_dev(pdev, TRUE);
806
807 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
808 {
809 unlock_dev(pdev, TRUE);
810 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
811 //delegate to ehci_remove_device for remiving the purb queue on the endpoint
812 continue;
813 }
814 if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
815 {
816 // prepare split transaction
817 unlock_dev(pdev, TRUE);
818
819 // pparent won't be removed when pending_endp_list_lock is acquired.
820 get_parent_hs_hub(pdev, pparent, port_idx);
821
822 if (pparent == NULL)
823 {
824 TRAP();
825 ehci_dbg_print(DBGLVL_MEDIUM,
826 ("ohci_process_pending_endp(): full/low speed device with no parent!!!\n"));
827 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
828 continue;
829 }
830
831 if (hub_lock_tt(pparent, port_idx, (UCHAR) endp_type(pendp)) == FALSE)
832 {
833 lock_dev(pdev, TRUE);
834 if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
835 {
836 // reinsert the pending-endp to the list
837 InsertTailList(&temp_list, pthis);
838 unlock_dev(pdev, TRUE);
839 }
840 else
841 {
842 // delegate to ehci_remove_device for purb removal
843 unlock_dev(pdev, TRUE);
844 free_pending_endp(&ehci->pending_endp_pool,
845 struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
846 }
847 continue;
848 }
849
850 // backup the hub address for future use
851 hub_addr = pparent->dev_addr;
852
853 lock_dev(pdev, TRUE);
854 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
855 {
856 unlock_dev(pdev, TRUE);
857 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
858 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
859 continue;
860 }
861 tt_needed = TRUE;
862 // go on processing
863 }
864
865 if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
866 {
867 while (IsListEmpty(&pendp->urb_list) == FALSE)
868 {
869 purb = (PURB) RemoveHeadList(&pendp->urb_list);
870 purb->status = USB_STATUS_ENDPOINT_HALTED;
871 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
872 }
873 InitializeListHead(&pendp->urb_list);
874 unlock_dev(pdev, TRUE);
875 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
876 if (tt_needed)
877 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
878 continue;
879 }
880
881 if (IsListEmpty(&pendp->urb_list) == FALSE)
882 {
883 purb = (PURB) RemoveHeadList(&pendp->urb_list);
884 ASSERT(purb);
885 }
886 else
887 {
888 InitializeListHead(&pendp->urb_list);
889 unlock_dev(pdev, TRUE);
890 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
891 if (tt_needed)
892 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
893 continue;
894 }
895
896 if (tt_needed)
897 {
898 ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr = hub_addr;
899 ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx = port_idx;
900 }
901
902 // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
903 switch (endp_type(pendp))
904 {
905 case USB_ENDPOINT_XFER_BULK:
906 {
907 can_submit = ohci_internal_submit_bulk(ehci, purb);
908 break;
909 }
910 case USB_ENDPOINT_XFER_CONTROL:
911 {
912 can_submit = ohci_internal_submit_ctrl(ehci, purb);
913 break;
914 }
915 case USB_ENDPOINT_XFER_INT:
916 {
917 can_submit = ohci_internal_submit_int(ehci, purb);
918 break;
919 }
920 case USB_ENDPOINT_XFER_ISOC:
921 {
922 can_submit = ohci_internal_submit_iso(ehci, purb);
923 break;
924 }
925 }
926
927 if (can_submit == STATUS_NO_MORE_ENTRIES)
928 {
929 //no enough bandwidth or tds
930 InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
931 InsertTailList(&temp_list, pthis);
932 }
933 else
934 {
935 // otherwise error or success
936 free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
937
938 if (can_submit != STATUS_SUCCESS)
939 {
940 //abort these URBs
941 InsertTailList(&abort_list, (LIST_ENTRY *) purb);
942 purb->status = can_submit;
943 }
944 }
945 unlock_dev(pdev, TRUE);
946 if (can_submit != STATUS_SUCCESS && tt_needed)
947 {
948 hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
949 }
950 }
951
952 if (IsListEmpty(&temp_list) == FALSE)
953 {
954 //re-append them to the pending_endp_list
955 ListFirst(&temp_list, pthis);
956 RemoveEntryList(&temp_list);
957 MergeList(&ehci->pending_endp_list, pthis);
958 }
959 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
960
961 if (IsListEmpty(&abort_list) == FALSE)
962 {
963 PLIST_ENTRY pthis;
964 cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
965 ASSERT(cancel_list);
966
967 ListFirst(&abort_list, pthis);
968 RemoveEntryList(&abort_list);
969 InsertTailList(pthis, cancel_list);
970
971 pwork_item = (PWORK_QUEUE_ITEM) & cancel_list[1];
972
973 // we do not need to worry the ehci_cancel_pending_endp_urb running when the
974 // driver is unloading since purb-reference count will prevent the dev_mgr to
975 // quit till all the reference count to the dev drop to zero.
976 ExInitializeWorkItem(pwork_item, ohci_cancel_pending_endp_urb, (PVOID) cancel_list);
977 ExQueueWorkItem(pwork_item, DelayedWorkQueue);
978 }
979 return TRUE;
980 }
981
982 NTSTATUS
983 ohci_rh_submit_urb(PUSB_DEV pdev, PURB purb)
984 {
985 PUSB_DEV_MANAGER dev_mgr;
986 PTIMER_SVC ptimer;
987 PUSB_CTRL_SETUP_PACKET psetup;
988 POHCI_DEV ohci;
989 NTSTATUS status;
990 PHUB2_EXTENSION hub_ext;
991 PUSB_PORT_STATUS ps, psret;
992 UCHAR port_count;
993 ULONG i;
994
995 USE_NON_PENDING_IRQL;
996 if (pdev == NULL || purb == NULL)
997 return STATUS_INVALID_PARAMETER;
998
999 dev_mgr = dev_mgr_from_dev(pdev);
1000
1001 KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
1002 lock_dev(pdev, FALSE);
1003 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1004 {
1005 unlock_dev(pdev, FALSE);
1006 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
1007 return STATUS_DEVICE_DOES_NOT_EXIST;
1008 }
1009
1010 ohci = ohci_from_hcd(pdev->hcd);
1011 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
1012
1013 hub_ext = ((PHUB2_EXTENSION) pdev->dev_ext);
1014 port_count = ohci->num_ports;
1015
1016 switch (endp_type(purb->pendp))
1017 {
1018 case USB_ENDPOINT_XFER_CONTROL:
1019 {
1020 if (psetup->bmRequestType == 0xa3 && psetup->bRequest == USB_REQ_GET_STATUS)
1021 {
1022 //get-port-status
1023 if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength < 4)
1024 {
1025 purb->status = STATUS_INVALID_PARAMETER;
1026 break;
1027 }
1028
1029 ps = &hub_ext->rh_port_status[psetup->wIndex];
1030 psret = (PUSB_PORT_STATUS) purb->data_buffer;
1031
1032 status =
1033 OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[psetup->wIndex-1]);
1034
1035 ps->wPortStatus = 0;
1036
1037 if (status & RH_PS_CCS)
1038 {
1039 ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
1040 }
1041 if (status & RH_PS_PES)
1042 {
1043 ps->wPortStatus |= USB_PORT_STAT_ENABLE;
1044 //ps->wPortStatus |= USB_PORT_STAT_HIGH_SPEED; // ehci spec
1045 }
1046 if (status & RH_PS_PRS)
1047 {
1048 ps->wPortStatus |= USB_PORT_STAT_RESET;
1049 }
1050 if (status & RH_PS_PSS)
1051 {
1052 ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
1053 }
1054 if (status & RH_PS_LSDA)
1055 {
1056 ps->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
1057 }
1058
1059 //always power on
1060 ps->wPortStatus |= USB_PORT_STAT_POWER;
1061
1062 //now set change field
1063 if ((status & RH_PS_CSC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
1064 {
1065 ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
1066 }
1067 if ((status & RH_PS_PESC) && !(ps->wPortStatus & USB_PORT_STAT_LOW_SPEED))
1068 {
1069 ps->wPortChange |= USB_PORT_STAT_C_ENABLE;
1070 }
1071
1072 //don't touch other fields, might be filled by
1073 //other function
1074
1075 usb_dbg_print(DBGLVL_MAXIMUM,
1076 ("ohci_rh_submit_urb(): get port status, wPortStatus=0x%x, wPortChange=0x%x, address=0x%x\n",
1077 ps->wPortStatus, ps->wPortChange, ps));
1078
1079 psret->wPortChange = ps->wPortChange;
1080 psret->wPortStatus = ps->wPortStatus;
1081
1082 purb->status = STATUS_SUCCESS;
1083
1084 break;
1085 }
1086 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_CLEAR_FEATURE)
1087 {
1088 //clear-port-feature
1089 if (psetup->wIndex == 0 || psetup->wIndex > port_count)
1090 {
1091 purb->status = STATUS_INVALID_PARAMETER;
1092 break;
1093 }
1094
1095 i = psetup->wIndex - 1;
1096 ps = &hub_ext->rh_port_status[psetup->wIndex];
1097
1098 purb->status = STATUS_SUCCESS;
1099 switch (psetup->wValue)
1100 {
1101 case USB_PORT_FEAT_C_CONNECTION:
1102 {
1103 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i], RH_PS_CSC);
1104 status = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i]);
1105 usb_dbg_print(DBGLVL_MAXIMUM,
1106 ("ohci_rh_submit_urb(): clear csc, port%d=0x%x\n", psetup->wIndex, status));
1107 ps->wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
1108 break;
1109 }
1110 case USB_PORT_FEAT_C_ENABLE:
1111 {
1112 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i], RH_PS_PESC);
1113 status = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i]);
1114 usb_dbg_print(DBGLVL_MAXIMUM,
1115 ("ohci_rh_submit_urb(): clear pec, port%d=0x%x\n", psetup->wIndex, status));
1116 ps->wPortChange &= ~USB_PORT_STAT_C_ENABLE;
1117 break;
1118 }
1119 case USB_PORT_FEAT_C_RESET:
1120 {
1121 ps->wPortChange &= ~USB_PORT_STAT_C_RESET;
1122 //the reset signal is down in rh_timer_svc_reset_port_completion
1123 // enable or not is set by host controller
1124 // status = EHCI_READ_PORT_ULONG( ( PUSHORT ) ( ehci->port_base + i ) );
1125 usb_dbg_print(DBGLVL_MAXIMUM,
1126 ("ohci_rh_submit_urb(): clear pr, enable pe, port%d=0x%x\n",
1127 psetup->wIndex, 0));
1128 break;
1129 }
1130 case USB_PORT_FEAT_ENABLE:
1131 {
1132 ps->wPortStatus &= ~USB_PORT_STAT_ENABLE;
1133 OHCI_WRITE_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i], RH_PS_PES);
1134 status = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[i]);
1135 usb_dbg_print(DBGLVL_MAXIMUM,
1136 ("ohci_rh_submit_urb(): clear pe, port%d=0x%x\n", psetup->wIndex, status));
1137 break;
1138 }
1139 default:
1140 purb->status = STATUS_UNSUCCESSFUL;
1141 }
1142
1143 break;
1144 }
1145 else if (psetup->bmRequestType == 0xd3 && psetup->bRequest == HUB_REQ_GET_STATE)
1146 {
1147 // get bus state
1148 if (psetup->wIndex == 0 || psetup->wIndex > port_count || psetup->wLength == 0)
1149 {
1150 purb->status = STATUS_INVALID_PARAMETER;
1151 break;
1152 }
1153 #if 0
1154 i = EHCI_PORTSC + 4 * (psetup->wIndex - 1); // USBPORTSC1;
1155 status = EHCI_READ_PORT_ULONG((PULONG) (ehci->port_base + i));
1156 purb->data_buffer[0] = (status & USBPORTSC_LS);
1157
1158 // reverse the order
1159 purb->data_buffer[0] ^= 0x3;
1160 #endif
1161 purb->status = STATUS_SUCCESS;
1162 break;
1163 }
1164 else if (psetup->bmRequestType == 0x23 && psetup->bRequest == USB_REQ_SET_FEATURE)
1165 {
1166 //reset port
1167 if (psetup->wValue != USB_PORT_FEAT_RESET)
1168 {
1169 purb->status = STATUS_INVALID_PARAMETER;
1170 ehci_dbg_print(DBGLVL_MAXIMUM,
1171 ("ohci_rh_submit_urb(): set feature with wValue=0x%x\n", psetup->wValue));
1172 break;
1173 }
1174
1175 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
1176 ptimer->threshold = 0; // within [ 50ms, 60ms ], one tick is 10 ms
1177 ptimer->context = (ULONG) purb;
1178 ptimer->pdev = pdev;
1179 ptimer->func = rh_timer_svc_reset_port_completion;
1180
1181 //start the timer
1182 pdev->ref_count += 2; //one for timer and one for purb
1183
1184 status =
1185 OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->roothub.portstatus[psetup->wIndex-1]);
1186
1187 usb_dbg_print(DBGLVL_MAXIMUM,
1188 ("ohci_rh_submit_urb(): reset port, port%d=0x%x\n", psetup->wIndex, status));
1189 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
1190 purb->status = STATUS_PENDING;
1191 }
1192 else
1193 {
1194 purb->status = STATUS_INVALID_PARAMETER;
1195 }
1196 break;
1197 }
1198 case USB_ENDPOINT_XFER_INT:
1199 {
1200 ptimer = alloc_timer_svc(&dev_mgr->timer_svc_pool, 1);
1201 ptimer->threshold = RH_INTERVAL;
1202 ptimer->context = (ULONG) purb;
1203 ptimer->pdev = pdev;
1204 ptimer->func = rh_timer_svc_int_completion;
1205
1206 //start the timer
1207 InsertTailList(&dev_mgr->timer_svc_list, &ptimer->timer_svc_link);
1208
1209 //usb_dbg_print(DBGLVL_MAXIMUM,
1210 // ("ehci_rh_submit_urb(): current rh's ref_count=0x%x\n", pdev->ref_count));
1211 pdev->ref_count += 2; //one for timer and one for purb
1212
1213 purb->status = STATUS_PENDING;
1214 break;
1215 }
1216 case USB_ENDPOINT_XFER_BULK:
1217 case USB_ENDPOINT_XFER_ISOC:
1218 default:
1219 {
1220 purb->status = STATUS_INVALID_PARAMETER;
1221 break;
1222 }
1223 }
1224 unlock_dev(pdev, FALSE);
1225 KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);
1226 return purb->status;
1227 }
1228
1229 NTSTATUS
1230 ohci_submit_urb(POHCI_DEV ehci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1231 {
1232 int i;
1233 PUHCI_PENDING_ENDP pending_endp;
1234 NTSTATUS status;
1235 USE_BASIC_IRQL;
1236
1237 if (ehci == NULL)
1238 return STATUS_INVALID_PARAMETER;
1239
1240 if (pdev == NULL || pendp == NULL || purb == NULL)
1241 {
1242 // give a chance to those pending urb, especially for clearing hub tt
1243 ohci_process_pending_endp(ehci);
1244 return STATUS_INVALID_PARAMETER;
1245 }
1246
1247 lock_pending_endp_list(&ehci->pending_endp_list_lock);
1248 lock_dev(pdev, TRUE);
1249
1250 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1251 {
1252 status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
1253 goto LBL_OUT;
1254 }
1255
1256 if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
1257 {
1258 unlock_dev(pdev, TRUE);
1259 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
1260 status = ohci_rh_submit_urb(pdev, purb);
1261 return status;
1262 }
1263
1264 if (pendp)
1265 purb->pendp = pendp;
1266 else
1267 purb->pendp = &pdev->default_endp;
1268
1269 if (dev_from_endp(purb->pendp) != pdev)
1270 {
1271 status = purb->status = STATUS_INVALID_PARAMETER;
1272 goto LBL_OUT;
1273 }
1274
1275 if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
1276 {
1277 status = purb->status = USB_STATUS_ENDPOINT_HALTED;
1278 goto LBL_OUT;
1279 }
1280
1281 if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
1282 {
1283 // wait one ms
1284 usb_wait_ms_dpc(1);
1285 }
1286
1287 purb->pdev = pdev;
1288 purb->rest_bytes = purb->data_length;
1289
1290 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
1291 purb->bytes_to_transfer = (purb->data_length > EHCI_MAX_SIZE_TRANSFER ? EHCI_MAX_SIZE_TRANSFER : purb->data_length); //multiple transfer for large data block
1292 else
1293 purb->bytes_to_transfer = purb->data_length;
1294
1295 ehci_dbg_print(DBGLVL_MEDIUM, ("ohci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));
1296
1297 purb->bytes_transfered = 0;
1298 InitializeListHead(&purb->trasac_list);
1299 purb->last_finished_td = &purb->trasac_list;
1300 purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
1301 purb->flags |= URB_FLAG_STATE_PENDING;
1302
1303
1304 i = IsListEmpty(&pendp->urb_list);
1305 InsertTailList(&pendp->urb_list, &purb->urb_link);
1306
1307 pdev->ref_count++; //for purb reference
1308
1309 if (i == FALSE)
1310 {
1311 //there is purb pending, simply queue it and return
1312 status = purb->status = STATUS_PENDING;
1313 goto LBL_OUT;
1314 }
1315 else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
1316 {
1317 //
1318 //No purb waiting but purb overlap not allowed,
1319 //so leave it in queue and return, will be scheduled
1320 //later
1321 //
1322 status = purb->status = STATUS_PENDING;
1323 goto LBL_OUT;
1324 }
1325
1326 pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
1327 if (pending_endp == NULL)
1328 {
1329 //panic
1330 status = purb->status = STATUS_UNSUCCESSFUL;
1331 goto LBL_OUT2;
1332 }
1333
1334 pending_endp->pendp = purb->pendp;
1335 InsertTailList(&ehci->pending_endp_list, (PLIST_ENTRY) pending_endp);
1336
1337 unlock_dev(pdev, TRUE);
1338 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
1339
1340 ohci_process_pending_endp(ehci);
1341 return STATUS_PENDING;
1342
1343 LBL_OUT2:
1344 pdev->ref_count--;
1345 RemoveEntryList((PLIST_ENTRY) purb);
1346
1347 LBL_OUT:
1348 unlock_dev(pdev, TRUE);
1349 unlock_pending_endp_list(&ehci->pending_endp_list_lock);
1350 ohci_process_pending_endp(ehci);
1351 return status;
1352 }
1353
1354 ULONG
1355 ohci_get_type(PHCD hcd)
1356 {
1357 return HCD_TYPE_OHCI; // ( hcd->flags & HCD_TYPE_MASK );
1358 }
1359
1360 NTSTATUS
1361 ohci_submit_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1362 {
1363 return ohci_submit_urb(ohci_from_hcd(hcd), pdev, pendp, purb);
1364 }
1365
1366 PUSB_DEV
1367 ohci_get_root_hub(PHCD hcd)
1368 {
1369 return ohci_from_hcd(hcd)->root_hub;
1370 }
1371
1372 VOID
1373 ohci_set_root_hub(PHCD hcd, PUSB_DEV root_hub)
1374 {
1375 if (hcd == NULL || root_hub == NULL)
1376 return;
1377 ohci_from_hcd(hcd)->root_hub = root_hub;
1378 return;
1379 }
1380
1381 BOOLEAN
1382 ohci_remove_device2(PHCD hcd, PUSB_DEV pdev)
1383 {
1384 if (hcd == NULL || pdev == NULL)
1385 return FALSE;
1386
1387 return FALSE;
1388 //return ehci_remove_device(ehci_from_hcd(hcd), pdev);
1389 }
1390
1391 BOOLEAN
1392 ohci_hcd_release(PHCD hcd)
1393 {
1394 POHCI_DEV ohci;
1395 POHCI_DEVICE_EXTENSION pdev_ext;
1396
1397 if (hcd == NULL)
1398 return FALSE;
1399
1400 ohci = ohci_from_hcd(hcd);
1401 pdev_ext = ohci->pdev_ext;
1402 return FALSE;//ehci_release(pdev_ext->pdev_obj);
1403 }
1404
1405 NTSTATUS
1406 ohci_cancel_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
1407 {
1408 POHCI_DEV ohci;
1409 if (hcd == NULL)
1410 return STATUS_INVALID_PARAMETER;
1411
1412 ohci = ohci_from_hcd(hcd);
1413 DbgPrint("ohci_cancel_urb2 called, but not implemented!\n");
1414 return STATUS_UNSUCCESSFUL;//ehci_cancel_urb(ehci, pdev, pendp, purb);
1415 }
1416
1417 VOID
1418 ohci_generic_urb_completion(PURB purb, PVOID context)
1419 {
1420 PUSB_DEV pdev;
1421 BOOLEAN is_ctrl = FALSE;
1422 USE_NON_PENDING_IRQL;
1423
1424 old_irql = KeGetCurrentIrql();
1425 if (old_irql > DISPATCH_LEVEL)
1426 TRAP();
1427
1428 if (old_irql < DISPATCH_LEVEL)
1429 KeRaiseIrql(DISPATCH_LEVEL, &old_irql);
1430
1431 pdev = purb->pdev;
1432 if (purb == NULL)
1433 goto LBL_LOWER_IRQL;
1434
1435 if (pdev == NULL)
1436 goto LBL_LOWER_IRQL;
1437
1438 lock_dev(pdev, TRUE);
1439
1440 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
1441 {
1442 // no need to do following statistics
1443 unlock_dev(pdev, TRUE);
1444 goto LBL_CLIENT_PROCESS;
1445 }
1446 if (usb_error(purb->status))
1447 {
1448 pdev->error_count++;
1449 }
1450
1451 if (purb->pendp == &pdev->default_endp)
1452 {
1453 if (usb_halted(purb->status))
1454 {
1455 pdev->time_out_count++;
1456 if (pdev->time_out_count > 3)
1457 {
1458 dev_set_state(pdev, USB_DEV_STATE_ZOMB);
1459 ohci_dbg_print(DBGLVL_MAXIMUM,
1460 ("ohci_generic_urb_completion(): contiguous error 3 times, dev 0x%x is deactivated\n",
1461 pdev));
1462 }
1463 }
1464 else
1465 pdev->time_out_count = 0;
1466
1467 }
1468
1469 if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_CONTROL)
1470 is_ctrl = TRUE;
1471
1472 unlock_dev(pdev, TRUE);
1473
1474 LBL_CLIENT_PROCESS:
1475 if (!is_ctrl)
1476 {
1477 if (purb->completion)
1478 purb->completion(purb, context);
1479 }
1480 else
1481 {
1482 if (purb->ctrl_req_context.ctrl_stack_count == 0)
1483 {
1484 if (purb->completion)
1485 purb->completion(purb, context);
1486 }
1487 else
1488 {
1489 // pstack = &purb->ctrl_req_stack[ purb->ctrl_req_context.ctrl_cur_stack ];
1490 // if( pstack->urb_completion )
1491 // pstack->urb_completion( purb, pstack->context );
1492 usb_call_ctrl_completion(purb);
1493 }
1494 }
1495
1496 LBL_LOWER_IRQL:
1497 if (old_irql < DISPATCH_LEVEL)
1498 KeLowerIrql(old_irql);
1499
1500 return;
1501 }
1502
1503 BOOLEAN
1504 ohci_rh_reset_port(PHCD hcd, UCHAR port_idx)
1505 {
1506 POHCI_DEV ohci;
1507 ULONG status, temp;
1508 PULONG PortStatus;
1509 USHORT Now, ResetDone;
1510
1511 if (hcd == NULL)
1512 return FALSE;
1513
1514 ohci = ohci_from_hcd(hcd);
1515
1516 if (port_idx < 1 || port_idx > ohci->num_ports)
1517 return FALSE;
1518
1519 port_idx--;
1520
1521 PortStatus = &ohci->regs->roothub.portstatus[port_idx];
1522
1523 Now = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->fmnumber);
1524 ResetDone = Now + PORT_RESET_MSEC;
1525
1526 /* build a "continuous enough" reset signal, with up to
1527 * 3msec gap between pulses. scheduler HZ==100 must work;
1528 * this might need to be deadline-scheduled.
1529 */
1530 do {
1531 /* spin until any current reset finishes */
1532 for (;;) {
1533 temp = OHCI_READ_PORT_ULONG(PortStatus);
1534 if (!(temp & RH_PS_PRS))
1535 break;
1536 usb_wait_us_dpc(500);
1537 }
1538
1539 if (!(temp & RH_PS_CCS))
1540 break;
1541 if (temp & RH_PS_PRSC)
1542 {
1543 OHCI_WRITE_PORT_ULONG(PortStatus, RH_PS_PRSC);
1544 }
1545
1546 /* start the next reset, sleep till it's probably done */
1547 OHCI_WRITE_PORT_ULONG(PortStatus, RH_PS_PRS);
1548 usb_wait_ms_dpc(PORT_RESET_HW_MSEC);
1549 Now = OHCI_READ_PORT_ULONG((PULONG)&ohci->regs->fmnumber);
1550 } while (tick_before(Now, ResetDone));
1551
1552 status = OHCI_READ_PORT_ULONG((PULONG)(&ohci->regs->roothub.portstatus[port_idx]));
1553 usb_dbg_print(DBGLVL_MAXIMUM, ("ohci_rh_reset_port(): status after written=0x%x\n", status));
1554 return TRUE;
1555 }
1556
1557 BOOLEAN
1558 ohci_rh_get_dev_change(PHCD hcd, PBYTE buf) //must have the rh dev_lock acquired
1559 {
1560 POHCI_DEV ohci;
1561 LONG i;
1562 ULONG status;
1563
1564 if (hcd == NULL)
1565 return FALSE;
1566
1567 ohci = ohci_from_hcd(hcd);
1568
1569 for(i = 0; i < ohci->num_ports; i++)
1570 {
1571 status = OHCI_READ_PORT_ULONG((PULONG)(&ohci->regs->roothub.portstatus[i]));
1572
1573 if (status != 0)
1574 {
1575 ohci_dbg_print(DBGLVL_MAXIMUM, ("ohci_rh_get_dev_change(): erh port%d status=0x%x\n", i, status));
1576 }
1577
1578 if (status & (RH_PS_PESC | RH_PS_CSC | RH_PS_OCIC))
1579 {
1580 buf[(i + 1) >> 3] |= (1 << ((i + 1) & 7));
1581 }
1582 }
1583 return TRUE;
1584 }
1585
1586
1587 NTSTATUS
1588 ohci_hcd_dispatch(PHCD hcd, LONG disp_code, PVOID param)
1589 {
1590 POHCI_DEV ohci;
1591
1592 if (hcd == NULL)
1593 return STATUS_INVALID_PARAMETER;
1594 ohci = ohci_from_hcd(hcd);
1595
1596 switch (disp_code)
1597 {
1598 case HCD_DISP_READ_PORT_COUNT:
1599 {
1600 if (param == NULL)
1601 return STATUS_INVALID_PARAMETER;
1602 *((PUCHAR) param) = ohci->num_ports;
1603 return STATUS_SUCCESS;
1604 }
1605 case HCD_DISP_READ_RH_DEV_CHANGE:
1606 {
1607 if (ohci_rh_get_dev_change(hcd, param) == FALSE)
1608 return STATUS_INVALID_PARAMETER;
1609 return STATUS_SUCCESS;
1610 }
1611 }
1612
1613 return STATUS_NOT_IMPLEMENTED;
1614 }
1615
1616 VOID
1617 ohci_init_hcd_interface(POHCI_DEV ohci)
1618 {
1619 ohci->hcd_interf.hcd_set_dev_mgr = ehci_set_dev_mgr;
1620 ohci->hcd_interf.hcd_get_dev_mgr = ehci_get_dev_mgr;
1621 ohci->hcd_interf.hcd_get_type = ohci_get_type;
1622 ohci->hcd_interf.hcd_set_id = ehci_set_id;
1623 ohci->hcd_interf.hcd_get_id = ehci_get_id;
1624 ohci->hcd_interf.hcd_alloc_addr = ehci_alloc_addr;
1625 ohci->hcd_interf.hcd_free_addr = ehci_free_addr;
1626 ohci->hcd_interf.hcd_submit_urb = ohci_submit_urb2;
1627 ohci->hcd_interf.hcd_generic_urb_completion = ohci_generic_urb_completion;
1628 ohci->hcd_interf.hcd_get_root_hub = ohci_get_root_hub;
1629 ohci->hcd_interf.hcd_set_root_hub = ohci_set_root_hub;
1630 ohci->hcd_interf.hcd_remove_device = ohci_remove_device2;
1631 ohci->hcd_interf.hcd_rh_reset_port = ohci_rh_reset_port;
1632 ohci->hcd_interf.hcd_release = ohci_hcd_release;
1633 ohci->hcd_interf.hcd_cancel_urb = ohci_cancel_urb2;
1634 ohci->hcd_interf.hcd_start = ohci_start;
1635 ohci->hcd_interf.hcd_dispatch = ohci_hcd_dispatch;
1636
1637 ohci->hcd_interf.flags = HCD_TYPE_OHCI; //hcd types | hcd id
1638 }
1639