TestPS2.h文件: /* * TestPS2.h * * Created on: 2010-1-11 * Author: Administrator */ #ifndef TESTPS2_H_ #define TESTPS2_H_ #include <stdio.h> #include <hw/inout.h> #include <sys/neutrino.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include "TestDebug.h" // // Define commands to the 8042 controller. // #define I8042_WRITE_KEYBOARD_OUTPUT_BUFFER 0xD2 //写键盘输出缓冲区 #define I8042_READ_CONTROLLER_COMMAND_BYTE 0x20 #define I8042_WRITE_CONTROLLER_COMMAND_BYTE 0x60 #define I8042_DISABLE_MOUSE_DEVICE 0xA7 #define I8042_ENABLE_MOUSE_DEVICE 0xA8 #define I8042_AUXILIARY_DEVICE_TEST 0xA9 #define I8042_KEYBOARD_DEVICE_TEST 0xAB #define I8042_DISABLE_KEYBOARD_DEVICE 0xAD #define I8042_ENABLE_KEYBOARD_DEVICE 0xAE #define I8042_WRITE_TO_AUXILIARY_DEVICE 0xD4 #define I8042_KEYBOARD_ECHO_TEST 0xEE #define I8042_MOUSE_SET_WRAP_MODE 0xEE #define I8042_MOUSE_RESET_WRAP_MODE 0xEC #define I8042_MOUSE_DATA_TO_TEST 0x11 //RANDOM SET #define I8042_MOUSE_ENABLE_DATA_REPORTING 0xF4 //使能鼠标 #define I8042_CONTROLLER_SELF_TEST 0xAA //控制器内部自检 #define I8042_MOUSE_READ_ID 0xF2 //读设备ID // // Define data return from the 8042 controller. // unsigned long ps2_keyboard_test(unsigned long device, unsigned long cmd); unsigned long ps2_mouse_test(unsigned long device, unsigned long cmd); #endif /* TESTPS2_H_ */ TestPS2.c /* * TestPS2.c * * Created on: 2010-1-11 * Author: Administrator */ /* * 8042工作原理 * 8042 包含了如下的寄存器 * 一个字节的输入缓冲区,包含从键盘读入的字节,只读; * 一个字节的输出缓冲区,包含要写到键盘的字节,只写; * 一个字节的状态寄存器,8个状态标志,只读; * 一个字节的控制寄存器,7个控制标志,读写; * 前三个寄存器(输入、输出、状态)可以通过0x60和0x64端口直接存取。 * 最后那个寄存器(控制)要使用“Read Command Byte”命令读, * 使用“Write Command Byte”命令写。下表列出周边端口是如何于 8042接口的: * Port Read / Write Function 功能 * 0x60 Read Read Input Buffer 读输入缓冲区 * 0x60 Write Write Output Buffer 写输出缓冲区 * 0x64 Read Read Status Register 读状态寄存器 * 0x64 Write Send Command 发送命令 * * 写0x64端口不会写入到任何特定的寄存器中,但是解释为发送命令给8042。 * 如果命令接收一个参数,则参数被发往0x60端口。 * 同样,命令的任何返回结构可以从0x60 端口读出。 */ #include "TestPS2.h" // // Define the 8042 Controller Status Register bits. // #define INPUT_BUFFER_FULL 0x01 #define OUTPUT_BUFFER_FULL 0x02 #define MOUSE_OUTPUT_BUFFER_FULL 0x20 // PS2控制器(8042)控制寄存器地址 #define PORT_0x64 0x64 // PS2控制器(8042)状态寄存器地址 #define PORT_0x60 0x60 // // keyboard 2nd ID request. // #define ACKNOWLEDGE 0xFA #define RESEND 0xFE #define FAILURE 0xFC // 发送命令到PS2控制器(8042) int send_command_to_8042(unsigned char data) { unsigned char temp; int Count = 0; /* * 为了在下面将data参数发往0x60端口,此时必须检测0x60端口是否可写, * 即输出缓冲区是否满,不满才可以写。 */ do { // 读0x64端口获得8042状态标志 temp = in8(PORT_0x64); Count++; delay(1); } while ((temp & OUTPUT_BUFFER_FULL) && (Count < WAIT_TIMES)); if (Count == WAIT_TIMES) { // 输出缓冲区一直满,0x60无法写 #ifdef __DEBUG__ printf("WriteCommandByte Error! Count is %d/n", Count); #endif return 0; } // 写0x64端口解释为发送命令到8042,其中data参数被发往0x60端口 out8(PORT_0x64, data); return 1; } // 写数据到输出缓冲区 int write_to_buffer(unsigned char data) { unsigned char temp; int Count = 0; /* * 为了在下面将data写入0x60端口,此时必须检测0x60端口是否可写, * 即输出缓冲区是否满,不满才可以写。 */ do { temp = in8(PORT_0x64); Count++; delay(1); } while ((temp & OUTPUT_BUFFER_FULL) && (Count < WAIT_TIMES)); if (Count == WAIT_TIMES) { #ifdef __DEBUG__ printf("KbdWrite Error! Count is %d/n", Count); #endif return 0; } // 写0x60端口就是写数据到输出缓冲区 out8(PORT_0x60, data); return 1; } // 从输入缓冲区读取数据,针对键盘 int kbd_read_from_buffer(unsigned char *data) { unsigned char temp; int Count = 0; unsigned char desiredMask = (unsigned char) (INPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL); /* * 为了从0x60端口读数据,要等到输入缓冲区满之后退出循环 * 此时缓冲区中有内容可供读取 */ do { temp = in8(PORT_0x64); Count++; delay(1); } while (((temp & desiredMask) != INPUT_BUFFER_FULL) && (Count < WAIT_TIMES)); if (Count == WAIT_TIMES) { #ifdef __DEBUG__ printf("KbdRead Error!temp is %d, Count is %d/n", temp, Count); #endif return 0; } // 获得输入缓冲区内容 *data = in8(PORT_0x60); return 1; } // 从输入缓冲区读取数据,针对鼠标 int mouse_read_from_buffer(unsigned char *data) { unsigned char temp; int Count = 0; unsigned char desiredMask = (unsigned char) (INPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL); /* * 为了从0x60端口读数据,要等到输入缓冲区满之后退出循环 * 此时缓冲区中有内容可供读取 */ do { temp = in8(PORT_0x64); Count++; delay(1); } while (((temp & desiredMask) != desiredMask) && (Count < WAIT_TIMES)); if (Count == WAIT_TIMES) { #ifdef __DEBUG__ printf("KbdRead Error!temp is %d, Count is %d/n", temp, Count); #endif return 0; } // 获得输入缓冲区内容 *data = in8(PORT_0x60); return 1; } /* * 测试PS2键盘 */ unsigned long ps2_keyboard_test(unsigned long device, unsigned long cmd) { //读取命令字节 unsigned char CommandByte = 0; //写入的测试字 unsigned char testCodeSend = 0xEE; //返回的测试字 unsigned char testCodeRecv = 0; //设备检测结果码 unsigned char result = DEVICE_ERROR; //标志命令字是否被修改 unsigned char IsCommandByteModified = 0; // 关闭键盘中断 unsigned char master8259 = in8(0x21); out8(0x21, master8259 | 0x02); // 读取键盘上一个命令字 if (!send_command_to_8042(I8042_READ_CONTROLLER_COMMAND_BYTE)) return DEVICE_ERROR; if (!kbd_read_from_buffer(&CommandByte)) return DEVICE_ERROR; #ifdef __DEBUG__ printf("CommandByte is %X/n", CommandByte); #endif if (CommandByte & INPUT_BUFFER_FULL) { //如果输入缓冲区满中断(IBF中断使能) //写新的命令字,禁止IBF中断 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(CommandByte & 0xFE)) { result = DEVICE_ERROR; goto ErrorOut; } //命令字被修改 IsCommandByteModified = 1; } //使用Polling方法检测 if (!send_command_to_8042(I8042_WRITE_KEYBOARD_OUTPUT_BUFFER)) { result = DEVICE_ERROR; goto ErrorOut; } //直接写入测试字符 if (!write_to_buffer(testCodeSend)) { result = DEVICE_ERROR; goto ErrorOut; } //读回测试字 if (!kbd_read_from_buffer(&testCodeRecv)) { result = DEVICE_ERROR; goto ErrorOut; } if (CommandByte & INPUT_BUFFER_FULL) //如果输入缓冲区满中断(键盘IBF中断使能) { //恢复原命令字 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(CommandByte)) { result = DEVICE_ERROR; goto ErrorOut; } } if (testCodeSend == testCodeRecv) { result = DEVICE_NO_ERROR; goto End; } else { result = DEVICE_ERROR; goto End; } ErrorOut: #ifdef __DEBUG__ printf("****Error_______!/n"); #endif if (IsCommandByteModified) //如果命令字被修改 { //恢复原命令字 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(CommandByte)) { result = DEVICE_ERROR; goto ErrorOut; } } End: // 恢复键盘中断 out8(0x21, master8259); return result; } /* * 测试PS2鼠标 */ unsigned long ps2_mouse_test(unsigned long device, unsigned long cmd) { //读取命令字节 unsigned char CommandByte = 0; //标志命令字是否被修改 unsigned char IsCommandByteModified = 0; //发送的测试字 unsigned char testCodeSend = 0x11; //返回的测试字 unsigned char testCodeRecv = 0; //响应字 unsigned char EchoByte = 0; //设备检测结果码 unsigned char result = DEVICE_ERROR; // 关闭键盘中断 unsigned char master8259 = in8(0x21); out8(0x21, master8259 | 0x02); // 关闭鼠标中断 // unsigned char master8259 = in8(0xA1); // out8(0xA1, master8259 | 0x10); //读取键盘命令字 if (!send_command_to_8042(I8042_READ_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!kbd_read_from_buffer(&CommandByte)) { result = DEVICE_ERROR; goto ErrorOut; } #ifdef __DEBUG__ printf("CommandByte is %X/n", CommandByte); #endif if (CommandByte & OUTPUT_BUFFER_FULL) //如果输入缓冲区满中断(鼠标IBF中断使能) { //写新的命令字,禁止鼠标IBF中断 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(CommandByte & 0xFD)) { result = DEVICE_ERROR; goto ErrorOut; } //命令字被修改 IsCommandByteModified = 1; } //使用Polling方法检测 if (!send_command_to_8042(I8042_WRITE_TO_AUXILIARY_DEVICE)) { result = DEVICE_ERROR; goto ErrorOut; } //设置鼠标进入Wrap Mode if (!write_to_buffer(I8042_MOUSE_SET_WRAP_MODE)) { result = DEVICE_ERROR; goto ErrorOut; } //等待鼠标响应,返回0xFA if (!mouse_read_from_buffer(&EchoByte)) { result = DEVICE_ERROR; goto ErrorOut; } if (EchoByte != ACKNOWLEDGE) { result = DEVICE_ERROR; goto ErrorOut; } #ifdef __DEBUG__ printf("Enter Wrap Mode ,0xFA is received/n"); #endif //Now Enter Wrap Mode //发送测试数据 if (!send_command_to_8042(I8042_WRITE_TO_AUXILIARY_DEVICE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(testCodeSend)) { result = DEVICE_ERROR; goto ErrorOut; } //读回测试字 if (!mouse_read_from_buffer(&testCodeRecv)) { result = DEVICE_ERROR; goto ErrorOut; } #ifdef __DEBUG__ printf("testCodeRecv is %d/n", testCodeRecv); #endif //返回进入Wrap Mode 以前的模式 if (!send_command_to_8042(I8042_WRITE_TO_AUXILIARY_DEVICE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(I8042_MOUSE_RESET_WRAP_MODE)) { result = DEVICE_ERROR; goto ErrorOut; } //等待鼠标响应,返回0xFA if (!mouse_read_from_buffer(&EchoByte)) { result = DEVICE_ERROR; goto ErrorOut; } if (EchoByte != ACKNOWLEDGE) { result = DEVICE_ERROR; goto ErrorOut; } #ifdef __DEBUG__ printf("Return to previous Mode ,0xFA is received/n"); #endif //重新使能鼠标 if (!send_command_to_8042(I8042_WRITE_TO_AUXILIARY_DEVICE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(I8042_MOUSE_ENABLE_DATA_REPORTING)) { result = DEVICE_ERROR; goto ErrorOut; } //等待鼠标响应,返回0xFA if (!mouse_read_from_buffer(&EchoByte)) { result = DEVICE_ERROR; goto ErrorOut; } if (EchoByte != ACKNOWLEDGE) { result = DEVICE_ERROR; goto ErrorOut; } if (IsCommandByteModified) //如果输入缓冲区满中断(鼠标IBF中断使能) { //恢复原命令字 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; goto ErrorOut; } if (!write_to_buffer(CommandByte)) { result = DEVICE_ERROR; goto ErrorOut; } } if (testCodeRecv == testCodeSend) { result = DEVICE_NO_ERROR; goto End; } else { result = DEVICE_ERROR; goto ErrorOut; } ErrorOut: #ifdef __DEBUG__ printf("****Error_______!/n"); #endif if (IsCommandByteModified) //如果命令字被修改 { //恢复原命令字 if (!send_command_to_8042(I8042_WRITE_CONTROLLER_COMMAND_BYTE)) { result = DEVICE_ERROR; } if (!write_to_buffer(CommandByte)) { result = DEVICE_ERROR; } } // 恢复键盘中断 End: out8(0x21, master8259); return result; }