ReactOS  0.4.13-dev-257-gfabbd7c
pnp.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: drivers/input/i8042prt/pnp.c
5  * PURPOSE: IRP_MJ_PNP operations
6  * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
7  * Copyright 2008 Colin Finck (mail@colinfinck.de)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include "i8042prt.h"
13 
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 /* This is all pretty confusing. There's more than one way to
19  * disable/enable the keyboard. You can send KBD_ENABLE to the
20  * keyboard, and it will start scanning keys. Sending KBD_DISABLE
21  * will disable the key scanning but also reset the parameters to
22  * defaults.
23  *
24  * You can also send 0xAE to the controller for enabling the
25  * keyboard clock line and 0xAD for disabling it. Then it'll
26  * automatically get turned on at the next command. The last
27  * way is by modifying the bit that drives the clock line in the
28  * 'command byte' of the controller. This is almost, but not quite,
29  * the same as the AE/AD thing. The difference can be used to detect
30  * some really old broken keyboard controllers which I hope won't be
31  * necessary.
32  *
33  * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
34  * some kvm switches.
35  */
36 BOOLEAN
38  IN PPORT_DEVICE_EXTENSION DeviceExtension,
39  IN UCHAR FlagsToDisable,
40  IN UCHAR FlagsToEnable)
41 {
42  UCHAR Value;
44 
45  if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE))
46  {
47  WARN_(I8042PRT, "Can't read i8042 mode\n");
48  return FALSE;
49  }
50 
51  Status = i8042ReadDataWait(DeviceExtension, &Value);
52  if (!NT_SUCCESS(Status))
53  {
54  WARN_(I8042PRT, "No response after read i8042 mode\n");
55  return FALSE;
56  }
57 
58  Value &= ~FlagsToDisable;
59  Value |= FlagsToEnable;
60 
61  if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE))
62  {
63  WARN_(I8042PRT, "Can't set i8042 mode\n");
64  return FALSE;
65  }
66 
67  if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
68  {
69  WARN_(I8042PRT, "Can't send i8042 mode\n");
70  return FALSE;
71  }
72 
73  return TRUE;
74 }
75 
76 static NTSTATUS
78  IN PPORT_DEVICE_EXTENSION DeviceExtension)
79 {
81  ULONG ResendIterations;
82  UCHAR Value = 0;
83 
84  /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
85  i8042Flush(DeviceExtension);
88 
89  i8042Flush(DeviceExtension);
90 
91  /* Issue a CTRL_SELF_TEST command to check if this is really an i8042 controller */
92  ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
93  while (ResendIterations--)
94  {
95  if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST))
96  {
97  WARN_(I8042PRT, "Writing CTRL_SELF_TEST command failed\n");
98  return STATUS_IO_TIMEOUT;
99  }
100 
101  Status = i8042ReadDataWait(DeviceExtension, &Value);
102  if (!NT_SUCCESS(Status))
103  {
104  WARN_(I8042PRT, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status);
105  return Status;
106  }
107 
108  if (Value == KBD_SELF_TEST_OK)
109  {
110  INFO_(I8042PRT, "CTRL_SELF_TEST completed successfully!\n");
111  break;
112  }
113  else if (Value == KBD_RESEND)
114  {
115  TRACE_(I8042PRT, "Resending...\n");
117  }
118  else
119  {
120  WARN_(I8042PRT, "Got 0x%02x instead of 0x55\n", Value);
121  return STATUS_IO_DEVICE_ERROR;
122  }
123  }
124 
125  return STATUS_SUCCESS;
126 }
127 
128 static VOID
130  IN PPORT_DEVICE_EXTENSION DeviceExtension)
131 {
133 
134  /* Set LEDs (that is not fatal if some error occurs) */
135  Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE);
136  if (NT_SUCCESS(Status))
137  {
138  Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE);
139  if (!NT_SUCCESS(Status))
140  {
141  WARN_(I8042PRT, "Can't finish SET_LEDS (0x%08lx)\n", Status);
142  return;
143  }
144  }
145  else
146  {
147  WARN_(I8042PRT, "Warning: can't write SET_LEDS (0x%08lx)\n", Status);
148  }
149 
150  /* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug CORE-1713) */
151  if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE | CCB_SYSTEM_FLAG))
152  return;
153 
154  /*
155  * We used to send a KBD_LINE_TEST (0xAB) command, but on at least HP
156  * Pavilion notebooks the response to that command was incorrect.
157  * So now we just assume that a keyboard is attached.
158  */
159  DeviceExtension->Flags |= KEYBOARD_PRESENT;
160 
161  INFO_(I8042PRT, "Keyboard detected\n");
162 }
163 
164 static VOID
166  IN PPORT_DEVICE_EXTENSION DeviceExtension)
167 {
169  UCHAR Value;
170  UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA };
171  UCHAR ReplyByte;
172 
173  /* First do a mouse line test */
174  if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST))
175  {
176  Status = i8042ReadDataWait(DeviceExtension, &Value);
177 
178  if (!NT_SUCCESS(Status) || Value != 0)
179  {
180  WARN_(I8042PRT, "Mouse line test failed\n");
181  goto failure;
182  }
183  }
184 
185  /* Now reset the mouse */
186  i8042Flush(DeviceExtension);
187 
188  if(!i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE))
189  {
190  WARN_(I8042PRT, "Failed to write reset command to mouse\n");
191  goto failure;
192  }
193 
194  /* The implementation of the "Mouse Reset" command differs much from chip to chip.
195 
196  By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not.
197  On success, the next bytes are 0xAA and 0x00.
198 
199  But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA.
200  Only the last byte indicates, whether a mouse is plugged in.
201  It is either sent or not, so there is no byte, which indicates a failure here.
202 
203  After the Mouse Reset command was issued, it usually takes some time until we get a response.
204  So get the first two bytes in a loop. */
205  for (ReplyByte = 0;
206  ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]);
207  ReplyByte++)
208  {
209  ULONG Counter = 500;
210 
211  do
212  {
213  Status = i8042ReadDataWait(DeviceExtension, &Value);
214 
215  if(!NT_SUCCESS(Status))
216  {
217  /* Wait some time before trying again */
219  }
220  } while (Status == STATUS_IO_TIMEOUT && Counter--);
221 
222  if (!NT_SUCCESS(Status))
223  {
224  WARN_(I8042PRT, "No ACK after mouse reset, status 0x%08lx\n", Status);
225  goto failure;
226  }
227  else if (Value != ExpectedReply[ReplyByte])
228  {
229  WARN_(I8042PRT, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value, ExpectedReply[ReplyByte]);
230  goto failure;
231  }
232  }
233 
234  /* Finally get the third byte, but only try it one time (see above).
235  Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */
236  Status = i8042ReadDataWait(DeviceExtension, &Value);
237 
238  if(!NT_SUCCESS(Status))
239  {
240  WARN_(I8042PRT, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status);
241  goto failure;
242  }
243  else if(Value != 0x00)
244  {
245  WARN_(I8042PRT, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value);
246  goto failure;
247  }
248 
249  DeviceExtension->Flags |= MOUSE_PRESENT;
250  INFO_(I8042PRT, "Mouse detected\n");
251  return;
252 
253 failure:
254  /* There is probably no mouse present. On some systems,
255  the probe locks the entire keyboard controller. Let's
256  try to get access to the keyboard again by sending a
257  reset */
258  i8042Flush(DeviceExtension);
259  i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST);
260  i8042ReadDataWait(DeviceExtension, &Value);
261  i8042Flush(DeviceExtension);
262 
263  INFO_(I8042PRT, "Mouse not detected\n");
264 }
265 
266 static NTSTATUS
268  IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
269 {
270  PPORT_DEVICE_EXTENSION PortDeviceExtension;
271  KIRQL DirqlMax;
273 
274  TRACE_(I8042PRT, "i8042ConnectKeyboardInterrupt()\n");
275 
276  PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
277 
278  // Enable keyboard clock line
279  i8042Write(PortDeviceExtension, PortDeviceExtension->ControlPort, KBD_CLK_ENABLE);
280 
281  DirqlMax = MAX(
282  PortDeviceExtension->KeyboardInterrupt.Dirql,
283  PortDeviceExtension->MouseInterrupt.Dirql);
284 
285  INFO_(I8042PRT, "KeyboardInterrupt.Vector %lu\n",
286  PortDeviceExtension->KeyboardInterrupt.Vector);
287  INFO_(I8042PRT, "KeyboardInterrupt.Dirql %lu\n",
288  PortDeviceExtension->KeyboardInterrupt.Dirql);
289  INFO_(I8042PRT, "KeyboardInterrupt.DirqlMax %lu\n",
290  DirqlMax);
291  INFO_(I8042PRT, "KeyboardInterrupt.InterruptMode %s\n",
292  PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
293  INFO_(I8042PRT, "KeyboardInterrupt.ShareInterrupt %s\n",
294  PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no");
295  INFO_(I8042PRT, "KeyboardInterrupt.Affinity 0x%lx\n",
296  PortDeviceExtension->KeyboardInterrupt.Affinity);
298  &PortDeviceExtension->KeyboardInterrupt.Object,
300  DeviceExtension, &PortDeviceExtension->SpinLock,
301  PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax,
302  PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt,
303  PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE);
304  if (!NT_SUCCESS(Status))
305  {
306  WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status);
307  return Status;
308  }
309 
310  if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql)
311  PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
312  PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED;
313  return STATUS_SUCCESS;
314 }
315 
316 static NTSTATUS
318  IN PI8042_MOUSE_EXTENSION DeviceExtension)
319 {
320  PPORT_DEVICE_EXTENSION PortDeviceExtension;
321  KIRQL DirqlMax;
323 
324  TRACE_(I8042PRT, "i8042ConnectMouseInterrupt()\n");
325 
326  Status = i8042MouInitialize(DeviceExtension);
327  if (!NT_SUCCESS(Status))
328  return Status;
329 
330  PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
331  DirqlMax = MAX(
332  PortDeviceExtension->KeyboardInterrupt.Dirql,
333  PortDeviceExtension->MouseInterrupt.Dirql);
334 
335  INFO_(I8042PRT, "MouseInterrupt.Vector %lu\n",
336  PortDeviceExtension->MouseInterrupt.Vector);
337  INFO_(I8042PRT, "MouseInterrupt.Dirql %lu\n",
338  PortDeviceExtension->MouseInterrupt.Dirql);
339  INFO_(I8042PRT, "MouseInterrupt.DirqlMax %lu\n",
340  DirqlMax);
341  INFO_(I8042PRT, "MouseInterrupt.InterruptMode %s\n",
342  PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
343  INFO_(I8042PRT, "MouseInterrupt.ShareInterrupt %s\n",
344  PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no");
345  INFO_(I8042PRT, "MouseInterrupt.Affinity 0x%lx\n",
346  PortDeviceExtension->MouseInterrupt.Affinity);
348  &PortDeviceExtension->MouseInterrupt.Object,
350  DeviceExtension, &PortDeviceExtension->SpinLock,
351  PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax,
352  PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt,
353  PortDeviceExtension->MouseInterrupt.Affinity, FALSE);
354  if (!NT_SUCCESS(Status))
355  {
356  WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status);
357  goto cleanup;
358  }
359 
360  if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql)
361  PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object;
362 
363  PortDeviceExtension->Flags |= MOUSE_INITIALIZED;
365 
366 cleanup:
367  if (!NT_SUCCESS(Status))
368  {
369  PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED;
370  if (PortDeviceExtension->MouseInterrupt.Object)
371  {
372  IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object);
373  PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
374  }
375  }
376  return Status;
377 }
378 
379 static NTSTATUS
381  IN PPORT_DEVICE_EXTENSION DeviceExtension,
382  IN UCHAR FlagsToDisable,
383  IN UCHAR FlagsToEnable)
384 {
385  i8042Flush(DeviceExtension);
386 
387  if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable))
388  return STATUS_UNSUCCESSFUL;
389 
390  return STATUS_SUCCESS;
391 }
392 
393 static NTSTATUS
395  IN PPORT_DEVICE_EXTENSION DeviceExtension)
396 {
398  UCHAR FlagsToDisable = 0;
399  UCHAR FlagsToEnable = 0;
400  KIRQL Irql;
401 
402  if (DeviceExtension->DataPort == 0)
403  {
404  /* Unable to do something at the moment */
405  return STATUS_SUCCESS;
406  }
407 
408  if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT)))
409  {
410  /* Try to detect them */
411  TRACE_(I8042PRT, "Check if the controller is really a i8042\n");
412  Status = i8042BasicDetect(DeviceExtension);
413  if (!NT_SUCCESS(Status))
414  {
415  WARN_(I8042PRT, "i8042BasicDetect() failed with status 0x%08lx\n", Status);
416  return STATUS_UNSUCCESSFUL;
417  }
418 
419  /* First detect the mouse and then the keyboard!
420  If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */
421  TRACE_(I8042PRT, "Detecting mouse\n");
422  i8042DetectMouse(DeviceExtension);
423  TRACE_(I8042PRT, "Detecting keyboard\n");
424  i8042DetectKeyboard(DeviceExtension);
425 
426  INFO_(I8042PRT, "Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
427  INFO_(I8042PRT, "Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");
428 
429  TRACE_(I8042PRT, "Enabling i8042 interrupts\n");
430  if (DeviceExtension->Flags & KEYBOARD_PRESENT)
431  {
432  FlagsToDisable |= CCB_KBD_DISAB;
433  FlagsToEnable |= CCB_KBD_INT_ENAB;
434  }
435  if (DeviceExtension->Flags & MOUSE_PRESENT)
436  {
437  FlagsToDisable |= CCB_MOUSE_DISAB;
438  FlagsToEnable |= CCB_MOUSE_INT_ENAB;
439  }
440 
441  Status = EnableInterrupts(DeviceExtension, FlagsToDisable, FlagsToEnable);
442  if (!NT_SUCCESS(Status))
443  {
444  WARN_(I8042PRT, "EnableInterrupts failed: %lx\n", Status);
445  DeviceExtension->Flags &= ~(KEYBOARD_PRESENT | MOUSE_PRESENT);
446  return Status;
447  }
448  }
449 
450  /* Connect interrupts */
451  if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
452  DeviceExtension->Flags & KEYBOARD_CONNECTED &&
453  DeviceExtension->Flags & KEYBOARD_STARTED &&
454  !(DeviceExtension->Flags & KEYBOARD_INITIALIZED))
455  {
456  /* Keyboard is ready to be initialized */
457  Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
458  if (NT_SUCCESS(Status))
459  {
460  DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
461  }
462  else
463  {
464  WARN_(I8042PRT, "i8042ConnectKeyboardInterrupt failed: %lx\n", Status);
465  }
466  }
467 
468  if (DeviceExtension->Flags & MOUSE_PRESENT &&
469  DeviceExtension->Flags & MOUSE_CONNECTED &&
470  DeviceExtension->Flags & MOUSE_STARTED &&
471  !(DeviceExtension->Flags & MOUSE_INITIALIZED))
472  {
473  /* Mouse is ready to be initialized */
474  Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
475  if (NT_SUCCESS(Status))
476  {
477  DeviceExtension->Flags |= MOUSE_INITIALIZED;
478  }
479  else
480  {
481  WARN_(I8042PRT, "i8042ConnectMouseInterrupt failed: %lx\n", Status);
482  }
483 
484  /* Start the mouse */
485  Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
486  /* HACK: the mouse has already been reset in i8042DetectMouse. This second
487  reset prevents some touchpads/mice from working (Dell D531, D600).
488  See CORE-6901 */
489  if (!(i8042HwFlags & FL_INITHACK))
490  {
492  }
493  KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
494  }
495 
496  return Status;
497 }
498 
499 static NTSTATUS
504 {
505  PFDO_DEVICE_EXTENSION DeviceExtension;
506  PPORT_DEVICE_EXTENSION PortDeviceExtension;
507  PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated;
508  INTERRUPT_DATA InterruptData = { NULL };
509  BOOLEAN FoundDataPort = FALSE;
510  BOOLEAN FoundControlPort = FALSE;
511  BOOLEAN FoundIrq = FALSE;
512  ULONG i;
514 
515  TRACE_(I8042PRT, "i8042PnpStartDevice(%p)\n", DeviceObject);
517  PortDeviceExtension = DeviceExtension->PortDeviceExtension;
518 
519  ASSERT(DeviceExtension->PnpState == dsStopped);
520 
521  if (!AllocatedResources)
522  {
523  WARN_(I8042PRT, "No allocated resources sent to driver\n");
525  }
526  if (AllocatedResources->Count != 1)
527  {
528  WARN_(I8042PRT, "Wrong number of allocated resources sent to driver\n");
530  }
531  if (AllocatedResources->List[0].PartialResourceList.Version != 1
532  || AllocatedResources->List[0].PartialResourceList.Revision != 1
533  || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1
534  || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1)
535  {
536  WARN_(I8042PRT, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
537  AllocatedResources->List[0].PartialResourceList.Version,
538  AllocatedResources->List[0].PartialResourceList.Revision,
539  AllocatedResourcesTranslated->List[0].PartialResourceList.Version,
540  AllocatedResourcesTranslated->List[0].PartialResourceList.Revision);
542  }
543 
544  /* Get Irq and optionally control port and data port */
545  for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
546  {
547  ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
548  ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
549  switch (ResourceDescriptor->Type)
550  {
551  case CmResourceTypePort:
552  {
553  if (ResourceDescriptor->u.Port.Length == 1)
554  {
555  /* We assume that the first resource will
556  * be the control port and the second one
557  * will be the data port...
558  */
559  if (!FoundDataPort)
560  {
561  PortDeviceExtension->DataPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart);
562  INFO_(I8042PRT, "Found data port: %p\n", PortDeviceExtension->DataPort);
563  FoundDataPort = TRUE;
564  }
565  else if (!FoundControlPort)
566  {
567  PortDeviceExtension->ControlPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart);
568  INFO_(I8042PRT, "Found control port: %p\n", PortDeviceExtension->ControlPort);
569  FoundControlPort = TRUE;
570  }
571  else
572  {
573  /* FIXME: implement PS/2 Active Multiplexing */
574  ERR_(I8042PRT, "Unhandled I/O ranges provided: 0x%lx\n", ResourceDescriptor->u.Port.Length);
575  }
576  }
577  else
578  WARN_(I8042PRT, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length);
579  break;
580  }
582  {
583  if (FoundIrq)
585  InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level;
586  InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector;
587  InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity;
588  if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
589  InterruptData.InterruptMode = Latched;
590  else
591  InterruptData.InterruptMode = LevelSensitive;
592  InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared);
593  INFO_(I8042PRT, "Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Level);
594  FoundIrq = TRUE;
595  break;
596  }
597  default:
598  WARN_(I8042PRT, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
599  }
600  }
601 
602  if (!FoundIrq)
603  {
604  WARN_(I8042PRT, "Interrupt resource was not found in allocated resources list\n");
606  }
607  else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort))
608  {
609  WARN_(I8042PRT, "Some required resources were not found in allocated resources list\n");
611  }
612  else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort))
613  {
614  WARN_(I8042PRT, "Too much resources were provided in allocated resources list\n");
616  }
617 
618  switch (DeviceExtension->Type)
619  {
620  case Keyboard:
621  {
623  &PortDeviceExtension->KeyboardInterrupt,
624  &InterruptData,
625  sizeof(INTERRUPT_DATA));
626  PortDeviceExtension->Flags |= KEYBOARD_STARTED;
627  Status = StartProcedure(PortDeviceExtension);
628  break;
629  }
630  case Mouse:
631  {
633  &PortDeviceExtension->MouseInterrupt,
634  &InterruptData,
635  sizeof(INTERRUPT_DATA));
636  PortDeviceExtension->Flags |= MOUSE_STARTED;
637  Status = StartProcedure(PortDeviceExtension);
638  break;
639  }
640  default:
641  {
642  WARN_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type);
643  ASSERT(!(PortDeviceExtension->Flags & KEYBOARD_CONNECTED) || !(PortDeviceExtension->Flags & MOUSE_CONNECTED));
645  }
646  }
647 
648  if (NT_SUCCESS(Status))
649  DeviceExtension->PnpState = dsStarted;
650 
651  return Status;
652 }
653 
654 static VOID
657 {
659  KIRQL OldIrql;
660  PFDO_DEVICE_EXTENSION DeviceExtension;
661 
664 
665  KeAcquireSpinLock(&DriverExtension->DeviceListLock, &OldIrql);
666  RemoveEntryList(&DeviceExtension->ListEntry);
667  KeReleaseSpinLock(&DriverExtension->DeviceListLock, OldIrql);
668 
669  IoDetachDevice(DeviceExtension->LowerDevice);
670 
672 }
673 
677  IN PIRP Irp)
678 {
679  PIO_STACK_LOCATION Stack;
684 
686  MinorFunction = Stack->MinorFunction;
688 
689  switch (MinorFunction)
690  {
691  case IRP_MN_START_DEVICE: /* 0x00 */
692  {
693  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
694 
695  /* Call lower driver (if any) */
697  {
699  if (NT_SUCCESS(Status))
701  DeviceObject,
702  Stack->Parameters.StartDevice.AllocatedResources,
703  Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
704  }
705  else
707  break;
708  }
709  case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x07 */
710  {
711  switch (Stack->Parameters.QueryDeviceRelations.Type)
712  {
713  case BusRelations:
714  {
715  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
717  }
718  case RemovalRelations:
719  {
720  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
722  }
723  default:
724  ERR_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
725  Stack->Parameters.QueryDeviceRelations.Type);
727  }
728  break;
729  }
730  case IRP_MN_QUERY_CAPABILITIES: /* (optional) 0x09 */
731  {
732  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
734  }
735  case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0x0d */
736  {
737  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
739  }
740  case IRP_MN_QUERY_PNP_DEVICE_STATE: /* (optional) 0x14 */
741  {
742  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
744  }
746  {
747  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
749  }
751  {
752  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
754  }
756  {
757  TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
760  return Status;
761  }
762  default:
763  {
764  ERR_(I8042PRT, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction);
766  }
767  }
768 
769  Irp->IoStatus.Information = Information;
770  Irp->IoStatus.Status = Status;
772  return Status;
773 }
#define STATUS_REVISION_MISMATCH
Definition: ntstatus.h:311
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2327
#define CCB_MOUSE_INT_ENAB
Definition: i8042prt.h:260
#define IRP_MN_CANCEL_REMOVE_DEVICE
#define CTRL_SELF_TEST
Definition: i8042prt.h:225
#define MOUSE_PRESENT
Definition: i8042prt.h:72
static NTSTATUS StartProcedure(IN PPORT_DEVICE_EXTENSION DeviceExtension)
Definition: pnp.c:394
#define IN
Definition: typedefs.h:38
static NTSTATUS EnableInterrupts(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN UCHAR FlagsToDisable, IN UCHAR FlagsToEnable)
Definition: pnp.c:380
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define ULongToPtr(ul)
Definition: basetsd.h:92
#define IRP_MN_REMOVE_DEVICE
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define MOU_CMD_RESET
Definition: i8042prt.h:279
KSPIN_LOCK SpinLock
Definition: i8042prt.h:89
#define KEYBOARD_INITIALIZED
Definition: i8042prt.h:71
#define INFO_(ch,...)
Definition: debug.h:159
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@369::@371 Port
_Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PCM_RESOURCE_LIST * AllocatedResources
Definition: ndis.h:4640
#define MOUSE_INITIALIZED
Definition: i8042prt.h:75
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS
DeviceType
Definition: mmdrv.h:41
#define CCB_KBD_DISAB
Definition: i8042prt.h:262
NTSTATUS NTAPI i8042Pnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: pnp.c:675
KAFFINITY Affinity
Definition: i8042prt.h:57
COMMON_DEVICE_EXTENSION Common
Definition: kbdclass.h:42
PKINTERRUPT HighestDIRQLInterrupt
Definition: i8042prt.h:88
LIST_ENTRY ListEntry
Definition: pci.h:82
DRIVER_DISPATCH ForwardIrpAndForget
Definition: i8042prt.h:341
#define ERR_(ch,...)
Definition: debug.h:156
LONG NTSTATUS
Definition: precomp.h:26
#define KEYBOARD_PRESENT
Definition: i8042prt.h:68
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@369 u
BOOLEAN i8042Write(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN PUCHAR addr, IN UCHAR data)
Definition: readwrite.c:199
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
BOOLEAN i8042IsrWritePort(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN UCHAR Value, IN UCHAR SelectCmd OPTIONAL)
Definition: readwrite.c:40
VOID i8042Flush(IN PPORT_DEVICE_EXTENSION DeviceExtension)
Definition: readwrite.c:21
VOID NTAPI IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
Definition: device.c:1295
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@369::@372 Interrupt
#define CCB_TRANSLATE
Definition: i8042prt.h:264
_Out_ PKIRQL Irql
Definition: csq.h:179
#define CmResourceTypePort
Definition: hwresource.cpp:123
struct _FDO_DEVICE_EXTENSION * PFDO_DEVICE_EXTENSION
uint32_t ULONG_PTR
Definition: typedefs.h:63
INTERRUPT_DATA KeyboardInterrupt
Definition: i8042prt.h:85
struct _I8042_DRIVER_EXTENSION * PI8042_DRIVER_EXTENSION
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define MOUSE_STARTED
Definition: i8042prt.h:74
PPORT_DEVICE_EXTENSION PortDeviceExtension
Definition: i8042prt.h:134
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define IRP_MN_QUERY_REMOVE_DEVICE
#define KBD_WRITE_MODE
Definition: i8042prt.h:222
NTSTATUS NTAPI IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject, IN PKSERVICE_ROUTINE ServiceRoutine, IN PVOID ServiceContext, IN PKSPIN_LOCK SpinLock, IN ULONG Vector, IN KIRQL Irql, IN KIRQL SynchronizeIrql, IN KINTERRUPT_MODE InterruptMode, IN BOOLEAN ShareVector, IN KAFFINITY ProcessorEnableMask, IN BOOLEAN FloatingSave)
Definition: irq.c:22
BOOLEAN i8042ChangeMode(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN UCHAR FlagsToDisable, IN UCHAR FlagsToEnable)
Definition: pnp.c:37
#define KBD_SELF_TEST_OK
Definition: i8042prt.h:241
_Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PDEVICE_OBJECT _Inout_opt_ PCM_RESOURCE_LIST _Inout_opt_ PCM_RESOURCE_LIST * AllocatedResourcesTranslated
Definition: ndis.h:4640
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:165
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
VOID NTAPI IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
Definition: irq.c:140
#define CCB_KBD_INT_ENAB
Definition: i8042prt.h:259
#define IoCompleteRequest
Definition: irp.c:1240
ULONG Vector
Definition: i8042prt.h:53
#define KBD_READ_MODE
Definition: i8042prt.h:221
PKINTERRUPT Object
Definition: i8042prt.h:52
#define TRACE_(x)
Definition: compat.h:66
NTSTATUS i8042MouInitialize(IN PI8042_MOUSE_EXTENSION DeviceExtension)
Definition: mouse.c:224
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static NTSTATUS i8042ConnectKeyboardInterrupt(IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
Definition: pnp.c:267
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define IRP_MN_START_DEVICE
BOOLEAN ShareInterrupt
Definition: i8042prt.h:56
#define KEYBOARD_STARTED
Definition: i8042prt.h:70
DRIVER_DISPATCH ForwardIrpAndWait
Definition: i8042prt.h:343
#define KBD_CLK_ENABLE
Definition: i8042prt.h:227
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:148
#define KBD_CMD_SET_LEDS
Definition: i8042prt.h:234
I8042_DEVICE_TYPE Type
Definition: i8042prt.h:122
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
unsigned char UCHAR
Definition: xmlstorage.h:181
#define MOUSE_LINE_TEST
Definition: i8042prt.h:224
#define MOUSE_CONNECTED
Definition: i8042prt.h:73
INTERRUPT_DATA MouseInterrupt
Definition: i8042prt.h:87
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
static VOID i8042RemoveDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: pnp.c:655
static NTSTATUS i8042PnpStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PCM_RESOURCE_LIST AllocatedResources, IN PCM_RESOURCE_LIST AllocatedResourcesTranslated)
Definition: pnp.c:500
#define MOUSE_ACK
Definition: i8042prt.h:285
PVOID NTAPI IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, IN PVOID ClientIdentificationAddress)
Definition: driver.c:1842
NTSTATUS NTAPI i8042SynchWritePort(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN UCHAR Port, IN UCHAR Value, IN BOOLEAN WaitForAck)
Definition: readwrite.c:144
_In_ UCHAR MinorFunction
Definition: pofuncs.h:42
PPCI_DRIVER_EXTENSION DriverExtension
Definition: pci.c:41
Status
Definition: gdiplustypes.h:24
T MAX(T a, T b)
Definition: polytest.cpp:85
ULONG i8042HwFlags
Definition: hwhacks.c:22
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
VOID NTAPI IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: device.c:1250
#define KBD_RESEND
Definition: i8042prt.h:244
enum _I8042_DEVICE_TYPE I8042_DEVICE_TYPE
static NTSTATUS i8042ConnectMouseInterrupt(IN PI8042_MOUSE_EXTENSION DeviceExtension)
Definition: pnp.c:317
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define IRP_MN_QUERY_DEVICE_RELATIONS
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
#define CmResourceTypeInterrupt
Definition: hwresource.cpp:124
static LARGE_INTEGER Counter
Definition: clock.c:43
#define CCB_MOUSE_DISAB
Definition: i8042prt.h:263
DEVICE_STATE PnpState
Definition: i8042prt.h:132
#define CCB_SYSTEM_FLAG
Definition: i8042prt.h:261
#define KEYBOARD_CONNECTED
Definition: i8042prt.h:69
#define CM_RESOURCE_INTERRUPT_LATCHED
Definition: cmtypes.h:144
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
char * cleanup(char *str)
Definition: wpickclick.c:99
NTSTATUS i8042ReadDataWait(IN PPORT_DEVICE_EXTENSION DeviceExtension, OUT PUCHAR Data)
Definition: readwrite.c:95
PDEVICE_OBJECT LowerDevice
Definition: i8042prt.h:130
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
return STATUS_SUCCESS
Definition: btrfs.c:2745
static NTSTATUS i8042BasicDetect(IN PPORT_DEVICE_EXTENSION DeviceExtension)
Definition: pnp.c:77
KSERVICE_ROUTINE i8042KbdInterruptService
Definition: i8042prt.h:320
#define WARN_(ch,...)
Definition: debug.h:157
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:99
#define CTRL_WRITE_MOUSE
Definition: i8042prt.h:228
#define IRP_MN_QUERY_PNP_DEVICE_STATE
KINTERRUPT_MODE InterruptMode
Definition: i8042prt.h:55
Iosb Information
Definition: create.c:4377
#define IRP_MN_QUERY_CAPABILITIES
static VOID i8042DetectMouse(IN PPORT_DEVICE_EXTENSION DeviceExtension)
Definition: pnp.c:165
KSERVICE_ROUTINE i8042MouInterruptService
Definition: i8042prt.h:369
static VOID i8042DetectKeyboard(IN PPORT_DEVICE_EXTENSION DeviceExtension)
Definition: pnp.c:129