X-Git-Url: http://git.jankratochvil.net/?p=reactos.git;a=blobdiff_plain;f=drivers%2Finput%2Fsermouse%2Fsermouse.c;h=c1f6356b170917fba7014cb228d333b50caaac67;hp=2772b5de8b0564fcfb45bb6e64bbec2e8a0d56a4;hb=HEAD;hpb=7c0db166f81fbe8c8b913d7f26048e337d383605 diff --git a/drivers/input/sermouse/sermouse.c b/drivers/input/sermouse/sermouse.c index 2772b5d..c1f6356 100644 --- a/drivers/input/sermouse/sermouse.c +++ b/drivers/input/sermouse/sermouse.c @@ -1,484 +1,351 @@ /* - * Mouse driver 0.0.6 + * Serial Mouse driver 0.0.8 * Written by Jason Filby (jasonfilby@yahoo.com) + * And heavily rewritten by Filip Navara (xnavara@volny.cz) * For ReactOS (www.reactos.com) * - * Note: The serial.o driver must be loaded before loading this driver - * - * Known Limitations: - * Only supports Microsoft mice on COM port 1 - * - * Following information obtained from Tomi Engdahl (then@delta.hut.fi), - * http://www.hut.fi/~then/mytexts/mouse.html - * - * Microsoft serial mouse - * - * Serial data parameters: - * 1200bps, 7 databits, 1 stop-bit - * - * Data packet format: - * Data packet is 3 byte packet. It is send to the computer every time mouse - * state changes (mouse moves or keys are pressed/released). - * D7 D6 D5 D4 D3 D2 D1 D0 - * 1. X 1 LB RB Y7 Y6 X7 X6 - * 2. X 0 X5 X4 X3 X2 X1 X0 - * 3. X 0 Y5 Y4 Y3 Y2 Y1 Y0 - * - * Note: The bit marked with X is 0 if the mouse received with 7 databits - * and 2 stop bits format. It is also possible to use 8 databits and 1 stop - * bit format for receiving. In this case X gets value 1. The safest thing - * to get everything working is to use 7 databits and 1 stopbit when - * receiving mouse information (and if you are making mouse then send out - * 7 databits and 2 stop bits). - * The byte marked with 1. is send first, then the others. The bit D6 in - * the first byte is used for syncronizing the software to mouse packets - * if it goes out of sync. - * - * LB is the state of the left button (1 means pressed down) - * RB is the state of the right button (1 means pressed down) - * X7-X0 movement in X direction since last packet (signed byte) - * Y7-Y0 movement in Y direction since last packet (signed byte) - * - * Mouse identification - * When DTR line is toggled, mouse should send one data byte containing - * letter 'M' (ascii 77). - * - * - * Logitech serial mouse - * - * Logitech uses the Microsoft serial mouse protocol in their mouses (for - * example Logitech Pilot mouse and others). The origianal protocol supports - * only two buttons, but logitech as added third button to some of their - * mouse models. To make this possible logitech has made one extension to - * the protocol. - * I have not seen any documentation about the exact documents, but here is - * what I have found out: The information of the third button state is sent - * using one extra byte which is send after the normal packet when needed. - * Value 32 (dec) is sent every time when the center button is pressed down. - * It is also sent every time with the data packet when center button is kept - * down and the mouse data packet is sent for other reasons. When center - * button is released, the mouse sends the normal data packet followed by - * data bythe which has value 0 (dec). As you can see the extra data byte - * is sent only when you mess with the center button. - * - * - * Mouse systems mouse - * - * Serial data parameters: - * 1200bps, 8 databits, 1 stop-bit - * - * Data packet format: - * D7 D6 D5 D4 D3 D2 D1 D0 - * 1. 1 0 0 0 0 LB CB RB - * 2. X7 X6 X5 X4 X3 X2 X1 X0 - * 3. Y7 Y6 Y5 Y4 Y3 Y4 Y1 Y0 - * 4. X7' X6' X5' X4' X3' X2' X1' X0' - * 5. Y7' Y6' Y5' Y4' Y3' Y4' Y1' Y0' - * - * LB is left button state (0 = pressed, 1 = released) - * CB is center button state (0 = pressed, 1 = released) - * RB is right button state (0 = pressed, 1 = released) - * X7-X0 movement in X direction since last packet in signed byte - * format (-128..+127), positive direction right - * Y7-Y0 movement in Y direction since last packet in signed byte - * format (-128..+127), positive direction up - * X7'-X0' movement in X direction since sending of X7-X0 packet in - * signed byte format (-128..+127), positive direction right - * Y7'-Y0' movement in Y direction since sending of Y7-Y0 packet in - * signed byte format (-128..+127), positive direction up - * - * The last two bytes in the packet (bytes 4 and 5) contains information - * about movement data changes which have occured after data bytes 2 and 3 - * have been sent. - * + * Technical information about mouse protocols can be found + * in the file sermouse.txt. */ #include #include -#define MOUSE_IRQ_COM1 4 -#define MOUSE_IRQ_COM2 3 - -#define MOUSE_PORT_COM1 0x3f8 -#define MOUSE_PORT_COM2 0x2f8 - -typedef struct _DEVICE_EXTENSION { - PDEVICE_OBJECT DeviceObject; - ULONG ActiveQueue; - ULONG InputDataCount[2]; - MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE]; - CLASS_INFORMATION ClassInformation; - - PKINTERRUPT MouseInterrupt; - KDPC IsrDpc; -} DEVICE_EXTENSION, *PDEVICE_EXTENSION; - -static unsigned int MOUSE_IRQ = MOUSE_IRQ_COM1; -static unsigned int MOUSE_COM = MOUSE_PORT_COM1; - -static unsigned int bytepos=0, coordinate; -static unsigned char mpacket[3]; -static unsigned char mouse_button1, mouse_button2; +/* + * Compile time options + */ -// Previous button state -static ULONG PreviousButtons = 0; +/* Support for the IOCTL_MOUSE_QUERY_ATTRIBUTES I/O control code */ +#define SERMOUSE_QUERYATTRIBUTES_SUPPORT +/* Check for mouse on COM1? */ +#define SERMOUSE_COM1_SUPPORT +/* Check for mouse on COM2? */ +//#define SERMOUSE_COM2_SUPPORT +/* Create \??\Mouse* symlink for device? */ +#define SERMOUSE_MOUSESYMLINK_SUPPORT -BOOLEAN STDCALL -microsoft_mouse_handler(IN PKINTERRUPT Interrupt, PVOID ServiceContext) -{ - PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext; - PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - PMOUSE_INPUT_DATA Input; - ULONG Queue, ButtonsDiff; - unsigned int mbyte; - int change_x; - int change_y; - UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 2); - - /* Is the interrupt for us? */ - if (0 != (InterruptId & 0x01)) - { - return FALSE; - } - - /* Not a Receive Data Available interrupt? */ - if (0 == (InterruptId & 0x04)) - { - return TRUE; - } - - /* Read all available data and process */ - while (0 != (READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 5) & 0x01)) - { - mbyte = READ_PORT_UCHAR((PUCHAR)MOUSE_COM); +/* + * Definitions + */ - /* Synchronize */ - if (0x40 == (mbyte & 0x40)) - bytepos=0; +#define MOUSE_IRQ_COM1 4 +#define MOUSE_IRQ_COM2 3 +#define MOUSE_PORT_COM1 0x3f8 +#define MOUSE_PORT_COM2 0x2f8 + +/* Maximum value plus one for \Device\PointerClass* device name */ +#define POINTER_PORTS_MAXIMUM 8 +/* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */ +#define SUFFIX_MAXIMUM_SIZE (1 * sizeof(WCHAR)) + +/* No Mouse */ +#define MOUSE_TYPE_NONE 0 +/* Microsoft Mouse with 2 buttons */ +#define MOUSE_TYPE_MICROSOFT 1 +/* Logitech Mouse with 3 buttons */ +#define MOUSE_TYPE_LOGITECH 2 +/* Microsoft Wheel Mouse (aka Z Mouse) */ +#define MOUSE_TYPE_WHEELZ 3 +/* Mouse Systems Mouse */ +#define MOUSE_TYPE_MOUSESYSTEMS 4 + +/* Size for packet buffer used in interrupt routine */ +#define PACKET_BUFFER_SIZE 4 + +/* Hardware byte mask for left button */ +#define LEFT_BUTTON_MASK 0x20 +/* Hardware to Microsoft specific code byte shift for left button */ +#define LEFT_BUTTON_SHIFT 5 +/* Hardware byte mask for right button */ +#define RIGHT_BUTTON_MASK 0x10 +/* Hardware to Microsoft specific code byte shift for right button */ +#define RIGHT_BUTTON_SHIFT 3 +/* Hardware byte mask for middle button */ +#define MIDDLE_BUTTON_MASK 0x20 +/* Hardware to Microsoft specific code byte shift for middle button */ +#define MIDDLE_BUTTON_SHIFT 3 + +/* Microsoft byte mask for left button */ +#define MOUSE_BUTTON_LEFT 0x01 +/* Microsoft byte mask for right button */ +#define MOUSE_BUTTON_RIGHT 0x02 +/* Microsoft byte mask for middle button */ +#define MOUSE_BUTTON_MIDDLE 0x04 - mpacket[bytepos] = (mbyte & 0x7f); - bytepos++; +/* + * Structures + */ - /* Process packet if complete */ - if (3 == bytepos) - { - /* Set local variables for DeviceObject and DeviceExtension */ - DeviceObject = (PDEVICE_OBJECT)ServiceContext; - DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; - Queue = DeviceExtension->ActiveQueue % 2; - - /* Prevent buffer overflow */ - if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE) - { - continue; - } - - Input = &DeviceExtension->MouseInputData[Queue] - [DeviceExtension->InputDataCount[Queue]]; - - /* Retrieve change in x and y from packet */ - change_x = (int)(signed char)((mpacket[0] & 0x03) << 6) + mpacket[1]; - change_y = (int)(signed char)((mpacket[0] & 0x0c) << 4) + mpacket[2]; - - /* Some mice need this */ - if (1 == coordinate) - { - change_x-=128; - change_y-=128; - } - -#if 0 - /* Change to signed */ - if (128 <= change_x) - { - change_x = change_x - 256; - } - if (128 <= change_y) - { - change_y = change_y - 256; - } +typedef struct _DEVICE_EXTENSION { + PDEVICE_OBJECT DeviceObject; + ULONG ActiveQueue; + ULONG InputDataCount[2]; + MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE]; + CLASS_INFORMATION ClassInformation; + PKINTERRUPT MouseInterrupt; + KDPC IsrDpc; + ULONG MousePort; + ULONG MouseType; + UCHAR PacketBuffer[PACKET_BUFFER_SIZE]; + ULONG PacketBufferPosition; + ULONG PreviousButtons; +#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT + MOUSE_ATTRIBUTES AttributesInformation; #endif +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; - Input->LastX = 2 * change_x; - Input->LastY = - 3 * change_y; - - /* Retrieve mouse button status from packet */ - mouse_button1 = mpacket[0] & 0x20; - mouse_button2 = mpacket[0] & 0x10; - - /* Determine the current state of the buttons */ - Input->RawButtons = mouse_button1 + mouse_button2; - - /* Determine ButtonFlags */ - Input->ButtonFlags = 0; - ButtonsDiff = PreviousButtons ^ Input->RawButtons; +/* + * Functions + */ - if (0 != (ButtonsDiff & 0x20)) - { - if (0 != (Input->RawButtons & 0x20)) - { - Input->ButtonFlags |= MOUSE_BUTTON_1_DOWN; - } - else +void ClearMouse(ULONG Port) +{ + /* Waits until the mouse calms down but also quits out after a while + * in case some destructive user wants to keep moving the mouse + * before we're done */ + unsigned int Restarts = 0, i; + for (i = 0; i < 60000; i++) { - Input->ButtonFlags |= MOUSE_BUTTON_1_UP; + unsigned Temp = READ_PORT_UCHAR((PUCHAR)Port); + if (Temp != 0) + { + Restarts++; + if (Restarts < 300000) + i = 0; + else + i = 60000; + } } - } +} - if (0 != (ButtonsDiff & 0x10)) - { - if (0 != (Input->RawButtons & 0x10)) +BOOLEAN STDCALL +SerialMouseInterruptService(IN PKINTERRUPT Interrupt, PVOID ServiceContext) +{ + PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext; + PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; + UCHAR *PacketBuffer = DeviceExtension->PacketBuffer; + ULONG MousePort = DeviceExtension->MousePort; + UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MousePort + 2); + UCHAR RecievedByte; + ULONG Queue; + PMOUSE_INPUT_DATA Input; + ULONG ButtonsDifference; + + /* Is the interrupt for us? */ + if ((InterruptId & 0x01) == 0x01) { - Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN; + return FALSE; } - else + + /* Not a Receive Data Available interrupt? */ + if ((InterruptId & 0x04) == 0) { - Input->ButtonFlags |= MOUSE_BUTTON_2_UP; + return TRUE; } - } - bytepos=0; - - /* Send the Input data to the Mouse Class driver */ - DeviceExtension->InputDataCount[Queue]++; - KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL); - - /* Copy RawButtons to Previous Buttons for Input */ - PreviousButtons = Input->RawButtons; - } - } - - return TRUE; -} - -void InitializeMouseHardware(unsigned int mtype) -{ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, 0x80); /* set DLAB on */ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM, 0x60); /* speed LO byte */ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* speed HI byte */ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, mtype); /* 2=MS Mouse; 3=Mouse systems mouse */ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* set comm and DLAB to 0 */ - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 4, 0x09); /* DR int enable */ - - (void) READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5); /* clear error bits */ -} - -int DetMicrosoft(void) -{ - char tmp, ind; - int buttons=0, i, timeout=250; - LARGE_INTEGER Timeout; - - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 0x0b); - tmp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM); - - /* Check the first four bytes for signs that this is an MS mouse */ - for(i=0; i<4; i++) { - while(((READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5) & 1)==0) && (timeout>0)) - { - Timeout.QuadPart = 1; - KeDelayExecutionThread (KernelMode, FALSE, &Timeout); - timeout--; - } - ind=READ_PORT_UCHAR((PUCHAR)MOUSE_COM); - if(ind==0x33) buttons=3; - if(ind==0x4d) buttons=2; - } - - return buttons; -} - -int CheckMouseType(unsigned int mtype) -{ - unsigned int retval=0; - - InitializeMouseHardware(mtype); - if(mtype==2) retval=DetMicrosoft(); - if(mtype==3) { - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 11); - retval=3; - } - WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 1); - - return retval; -} + /* Read all available data and process */ + while ((READ_PORT_UCHAR((PUCHAR)MousePort + 5) & 0x01) != 0) + { + RecievedByte = READ_PORT_UCHAR((PUCHAR)MousePort); -void ClearMouse(void) -{ - /* Waits until the mouse calms down but also quits out after a while - * in case some destructive user wants to keep moving the mouse - * before we're done */ - - unsigned int restarts=0, i; - for (i=0; i<60000; i++) - { - unsigned temp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM); - if(temp!=0) { - restarts++; - if(restarts<300000) { - i=0; - } else - { - i=60000; - } - } - } -} + /* Synchronize */ + if ((RecievedByte & 0x40) == 0x40) + DeviceExtension->PacketBufferPosition = 0; -BOOLEAN InitializeMouse(PDEVICE_OBJECT DeviceObject) -{ - int mbuttons=0, gotmouse=0; - PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - ULONG MappedIrq; - KIRQL Dirql; - KAFFINITY Affinity; - - /* Check for Microsoft mouse (2 buttons) */ - if(CheckMouseType(2)!=0) - { - gotmouse=1; - DbgPrint("Microsoft Mouse Detected\n"); - ClearMouse(); - coordinate=0; - } - - /* Check for Microsoft Systems mouse (3 buttons) */ - if(gotmouse==0) { - if(CheckMouseType(3)!=0) - { - gotmouse=1; - DbgPrint("Mouse Systems Mouse Detected\n"); - ClearMouse(); - coordinate=1; - } - } + PacketBuffer[DeviceExtension->PacketBufferPosition] = + (RecievedByte & 0x7f); + ++DeviceExtension->PacketBufferPosition; - if(gotmouse==0) return FALSE; + /* Process packet if complete */ + if (DeviceExtension->PacketBufferPosition >= 3) + { + Queue = DeviceExtension->ActiveQueue % 2; + + /* Prevent buffer overflow */ + if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE) + continue; - DeviceExtension->ActiveQueue = 0; - MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity); + Input = &DeviceExtension->MouseInputData[Queue][DeviceExtension->InputDataCount[Queue]]; - IoConnectInterrupt(&DeviceExtension->MouseInterrupt, microsoft_mouse_handler, - DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE, - Affinity, FALSE); + if (DeviceExtension->PacketBufferPosition == 3) + { + /* Retrieve change in x and y from packet */ + Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6)); + Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4)); + + /* Determine the current state of the buttons */ + Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) | + ((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) | + ((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT); + } else + if (DeviceExtension->PacketBufferPosition == 4) + { + DeviceExtension->PacketBufferPosition = 0; + /* If middle button state changed than report event */ + if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^ + (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE)) + { + Input->RawButtons ^= MOUSE_BUTTON_MIDDLE; + Input->LastX = 0; + Input->LastY = 0; + } + else + { + continue; + } + } + + /* Determine ButtonFlags */ + Input->ButtonFlags = 0; + ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons; + + if (ButtonsDifference != 0) + { + if (ButtonsDifference & MOUSE_BUTTON_LEFT) + { + if (Input->RawButtons & MOUSE_BUTTON_LEFT) + Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN; + else + Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP; + } + if (ButtonsDifference & MOUSE_BUTTON_RIGHT) + { + if (Input->RawButtons & MOUSE_BUTTON_RIGHT) + Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN; + else + Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP; + } + if (ButtonsDifference & MOUSE_BUTTON_MIDDLE) + { + if (Input->RawButtons & MOUSE_BUTTON_MIDDLE) + Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN; + else + Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP; + } + } + + /* Send the Input data to the Mouse Class driver */ + DeviceExtension->InputDataCount[Queue]++; + KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL); + + /* Copy RawButtons to Previous Buttons for Input */ + DeviceExtension->PreviousButtons = Input->RawButtons; + } + } - return TRUE; + return TRUE; } -VOID SerialMouseInitializeDataQueue(PVOID Context) +VOID +SerialMouseInitializeDataQueue(PVOID Context) { } BOOLEAN STDCALL MouseSynchronizeRoutine(PVOID Context) { - PIRP Irp = (PIRP)Context; - PMOUSE_INPUT_DATA rec = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer; - PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); - ULONG NrToRead = stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA); - int i; - - if ((stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA))==NrToRead) - { - return(TRUE); - } - - return(FALSE); + return TRUE; } VOID STDCALL SerialMouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp) { - PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp)) - { - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - IoStartNextPacket(DeviceObject, FALSE); - } + if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp)) + { + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + IoStartNextPacket(DeviceObject, FALSE); + } } NTSTATUS STDCALL SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { - PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - NTSTATUS status; + PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS Status; - switch(Stack->Parameters.DeviceIoControl.IoControlCode) - { - case IOCTL_INTERNAL_MOUSE_CONNECT: - - DeviceExtension->ClassInformation = - *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer); - - /* Reinitialize the port input data queue synchronously */ - KeSynchronizeExecution(DeviceExtension->MouseInterrupt, - (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, DeviceExtension); - - status = STATUS_SUCCESS; - break; + switch (Stack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_INTERNAL_MOUSE_CONNECT: + DeviceExtension->ClassInformation = + *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer); + + /* Reinitialize the port input data queue synchronously */ + KeSynchronizeExecution(DeviceExtension->MouseInterrupt, + (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, + DeviceExtension); + + Status = STATUS_SUCCESS; + break; + +#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT + case IOCTL_MOUSE_QUERY_ATTRIBUTES: + if (Stack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MOUSE_ATTRIBUTES)) + { + *(PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer = + DeviceExtension->AttributesInformation; + Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); + Status = STATUS_SUCCESS; + } else { + Status = STATUS_BUFFER_TOO_SMALL; + } + break; +#endif - default: - status = STATUS_INVALID_DEVICE_REQUEST; - break; - } + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } - Irp->IoStatus.Status = status; - if (status == STATUS_PENDING) { - IoMarkIrpPending(Irp); - IoStartPacket(DeviceObject, Irp, NULL, NULL); - } else { - IoCompleteRequest(Irp, IO_NO_INCREMENT); - } + Irp->IoStatus.Status = Status; + if (Status == STATUS_PENDING) + { + IoMarkIrpPending(Irp); + IoStartPacket(DeviceObject, Irp, NULL, NULL); + } + else + { + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } - return status; + return Status; } NTSTATUS STDCALL SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { - PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); - NTSTATUS Status; - static BOOLEAN AlreadyOpened = FALSE; - - switch (stk->MajorFunction) - { - case IRP_MJ_CREATE: - if (AlreadyOpened == TRUE) - { - Status = STATUS_SUCCESS; - } + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS Status; + + switch (Stack->MajorFunction) + { + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + Status = STATUS_SUCCESS; + break; + + default: + DbgPrint("NOT IMPLEMENTED\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (Status == STATUS_PENDING) + { + IoMarkIrpPending(Irp); + } else - { - Status = STATUS_SUCCESS; - AlreadyOpened = TRUE; - } - break; - - case IRP_MJ_CLOSE: - Status = STATUS_SUCCESS; - break; - - default: - DbgPrint("NOT IMPLEMENTED\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - } - - if (Status==STATUS_PENDING) - { - IoMarkIrpPending(Irp); - } - else - { - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp,IO_NO_INCREMENT); - } - return(Status); + { + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; } VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) @@ -497,45 +364,245 @@ VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID C DeviceExtension->InputDataCount[Queue] = 0; } +void InitializeSerialPort(ULONG Port, unsigned int LineControl) +{ + WRITE_PORT_UCHAR((PUCHAR)Port + 3, 0x80); /* set DLAB on */ + WRITE_PORT_UCHAR((PUCHAR)Port, 0x60); /* speed LO byte */ + WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0); /* speed HI byte */ + WRITE_PORT_UCHAR((PUCHAR)Port + 3, LineControl); + WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0); /* set comm and DLAB to 0 */ + WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x09); /* DR int enable */ + (void) READ_PORT_UCHAR((PUCHAR)Port + 5); /* clear error bits */ +} + +ULONG DetectMicrosoftMouse(ULONG Port) +{ + CHAR Buffer[4]; + ULONG i; + ULONG TimeOut = 250; + UCHAR LineControl; + + /* Shutdown mouse or something like that */ + LineControl = READ_PORT_UCHAR((PUCHAR)Port + 4); + WRITE_PORT_UCHAR((PUCHAR)Port + 4, (LineControl & ~0x02) | 0x01); + KeStallExecutionProcessor(500000); + + /* Clear buffer */ + while (READ_PORT_UCHAR((PUCHAR)Port + 5) & 0x01) + (void)READ_PORT_UCHAR((PUCHAR)Port); + + /* Send modem control with 'Data Terminal Ready', 'Request To Send' and + * 'Output Line 2' message. This enables mouse to identify. */ + WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x0b); + /* Wait 10 milliseconds for the mouse getting ready */ + KeStallExecutionProcessor(10000); + + /* Read first four bytes, which contains Microsoft Mouse signs */ + for (i = 0; i < 4; i++) + { + while (((READ_PORT_UCHAR((PUCHAR)Port + 5) & 1) == 0) && (TimeOut > 0)) + { + KeStallExecutionProcessor(1000); + --TimeOut; + if (TimeOut == 0) + return MOUSE_TYPE_NONE; + } + Buffer[i] = READ_PORT_UCHAR((PUCHAR)Port); + } + + /* Check that four bytes for signs */ + for (i = 0; i < 4; ++i) + { + /* Sign for Microsoft Ballpoint */ + if (Buffer[i] == 'B') + { + DbgPrint("Microsoft Ballpoint device detected"); + DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET"); + return MOUSE_TYPE_NONE; + } else + /* Sign for Microsoft Mouse protocol followed by button specifier */ + if (Buffer[i] == 'M') + { + if (i == 3) + { + /* Overflow Error */ + return MOUSE_TYPE_NONE; + } + switch (Buffer[i + 1]) + { + case '3': + DbgPrint("Microsoft Mouse with 3-buttons detected\n"); + return MOUSE_TYPE_LOGITECH; + case 'Z': + DbgPrint("Microsoft Wheel Mouse detected\n"); + return MOUSE_TYPE_WHEELZ; + /* case '2': */ + default: + DbgPrint("Microsoft Mouse with 2-buttons detected\n"); + return MOUSE_TYPE_MICROSOFT; + } + } + } + + return MOUSE_TYPE_NONE; +} + +PDEVICE_OBJECT +AllocatePointerDevice(PDRIVER_OBJECT DriverObject) +{ + PDEVICE_OBJECT DeviceObject; + UNICODE_STRING DeviceName; + UNICODE_STRING SuffixString; + UNICODE_STRING SymlinkName; + PDEVICE_EXTENSION DeviceExtension; + ULONG Suffix; + NTSTATUS Status; + + /* Allocate buffer for full device name */ + RtlInitUnicodeString(&DeviceName, NULL); + DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL); + DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength); + RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U); + + /* Allocate buffer for device name suffix */ + RtlInitUnicodeString(&SuffixString, NULL); + SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL); + SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength); + + /* Generate full qualified name with suffix */ + for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix) + { + RtlIntegerToUnicodeString(Suffix, 10, &SuffixString); + RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer); + Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), + &DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject); + /* Device successfully created, leave the cyclus */ + if (NT_SUCCESS(Status)) + break; + DeviceName.Length -= SuffixString.Length; + } + + ExFreePool(DeviceName.Buffer); + + /* Couldn't create device */ + if (!NT_SUCCESS(Status)) + { + ExFreePool(SuffixString.Buffer); + return NULL; + } + + DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO; + +#ifdef SERMOUSE_MOUSESYMLINK_SUPPORT + /* Create symlink */ + /* FIXME: Why? FiN 20/08/2003 */ + RtlInitUnicodeString(&SymlinkName, NULL); + SymlinkName.MaximumLength = sizeof(L"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL); + SymlinkName.Buffer = ExAllocatePool(PagedPool, SymlinkName.MaximumLength); + RtlAppendUnicodeToString(&SymlinkName, L"\\??\\Mouse"); + RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer); + IoCreateSymbolicLink(&SymlinkName, &DeviceName); +#endif + ExFreePool(SuffixString.Buffer); + + DeviceExtension = DeviceObject->DeviceExtension; + KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject); + + return DeviceObject; +} + +BOOLEAN +InitializeMouse(ULONG Port, ULONG Irq, PDRIVER_OBJECT DriverObject) +{ + PDEVICE_EXTENSION DeviceExtension; + PDEVICE_OBJECT DeviceObject; + ULONG MappedIrq; + KIRQL Dirql; + KAFFINITY Affinity; + ULONG MouseType; + + /* Try to detect mouse on specified port */ + InitializeSerialPort(Port, 2); + MouseType = DetectMicrosoftMouse(Port); + + /* Enable interrupts */ + WRITE_PORT_UCHAR((PUCHAR)(Port) + 1, 1); + ClearMouse(Port); + + /* No mouse, no need to continue */ + if (MouseType == MOUSE_TYPE_NONE) + return FALSE; + + /* Allocate new device */ + DeviceObject = AllocatePointerDevice(DriverObject); + if (!DeviceObject) + { + DbgPrint("Oops, couldn't creat device object.\n"); + return FALSE; + } + DeviceExtension = DeviceObject->DeviceExtension; + + /* Setup device extension structure */ + DeviceExtension->ActiveQueue = 0; + DeviceExtension->MouseType = MouseType; + DeviceExtension->MousePort = Port; + DeviceExtension->PacketBufferPosition = 0; + DeviceExtension->PreviousButtons = 0; +#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT + switch (MouseType) + { + case MOUSE_TYPE_MICROSOFT: + DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 2; + break; + case MOUSE_TYPE_LOGITECH: + DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 3; + break; + case MOUSE_TYPE_WHEELZ: + DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 3; + break; + }; + DeviceExtension->AttributesInformation.SampleRate = 40; + DeviceExtension->AttributesInformation.InputDataQueueLength = MOUSE_BUFFER_SIZE; +#endif + + MappedIrq = HalGetInterruptVector(Internal, 0, 0, Irq, &Dirql, &Affinity); + + IoConnectInterrupt( + &DeviceExtension->MouseInterrupt, SerialMouseInterruptService, + DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE, + Affinity, FALSE); + + return TRUE; +} + NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { - PDEVICE_OBJECT DeviceObject; - UNICODE_STRING DeviceName; - UNICODE_STRING SymlinkName; - PDEVICE_EXTENSION DeviceExtension; - - DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseDispatch; - DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl; - DriverObject->DriverStartIo = SerialMouseStartIo; - - RtlInitUnicodeStringFromLiteral(&DeviceName, - L"\\Device\\Mouse"); /* FIXME: find correct device name */ - IoCreateDevice(DriverObject, - sizeof(DEVICE_EXTENSION), - &DeviceName, - FILE_DEVICE_SERIAL_MOUSE_PORT, - 0, - TRUE, - &DeviceObject); - DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO; - - if(InitializeMouse(DeviceObject) == TRUE) - { - DbgPrint("Serial Mouse Driver 0.0.5\n"); - } else { - IoDeleteDevice(DeviceObject); - DbgPrint("Serial mouse not found.\n"); - return STATUS_UNSUCCESSFUL; - } - - RtlInitUnicodeStringFromLiteral(&SymlinkName, - L"\\??\\Mouse"); /* FIXME: find correct device name */ - IoCreateSymbolicLink(&SymlinkName, &DeviceName); - - DeviceExtension = DeviceObject->DeviceExtension; - KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject); - - return(STATUS_SUCCESS); + BOOL MouseFound = FALSE; + + DbgPrint("Serial Mouse Driver 0.0.8\n"); +#ifdef SERMOUSE_COM1_SUPPORT + DbgPrint("Trying to find mouse on COM1\n"); + MouseFound |= InitializeMouse(MOUSE_PORT_COM1, MOUSE_IRQ_COM1, DriverObject); +#endif +#ifdef SERMOUSE_COM2_SUPPORT + DbgPrint("Trying to find mouse on COM2\n"); + MouseFound |= InitializeMouse(MOUSE_PORT_COM2, MOUSE_IRQ_COM2, DriverObject); +#endif + + if (!MouseFound) + { + DbgPrint("No serial mouse found.\n"); + return STATUS_UNSUCCESSFUL; + } + + DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)SerialMouseDispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)SerialMouseDispatch; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SerialMouseInternalDeviceControl; + DriverObject->DriverStartIo = SerialMouseStartIo; + + return STATUS_SUCCESS; }