int elftouch_ps2_detect(struct psmouse *psmouse, bool set_properties) { struct input_dev *dev = psmouse->dev; unsigned char param[16]; int command, res; param[0]=0x0f4; command = TOUCHKIT_SEND_PARMS(1, 0, TOUCHKIT_CMD); res=ps2_command(&psmouse->ps2dev, param, command); if(res) { return -ENODEV; } param[0]=0x0b0; command = TOUCHKIT_SEND_PARMS(1, 1, TOUCHKIT_CMD); res=ps2_command(&psmouse->ps2dev, param, command); if(res) { return -ENODEV; } if (set_properties) { dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); set_bit(BTN_TOUCH, dev->keybit); input_set_abs_params(dev, ABS_X, 0, ELFTOUCH_MAX_XC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, ELFTOUCH_MAX_YC, 0, 0); psmouse->vendor = "ElfTouch"; psmouse->name = "Touchscreen"; psmouse->protocol_handler = touchkit_ps2_process_byte; psmouse->pktsize = 5; } return 0; }
/* * Device IO: read, write and toggle bit */ static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results) { if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { return -1; } return 0; }
static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val) { if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { return -1; } return 0; }
// device should be disabled static void detect_device(uint port, uchar enable, uchar test, uchar mask) { ps2_device * ps2d; uchar check = 0; ushort type = 0; if (get_config() & mask) { outb(PS2_CMND, enable); if (!(get_config() & mask)) { outb(PS2_CMND, test); do_assert(wait_read()); if (!inb(PS2_DATA)) { ps2_command(port, 0xFF, &check, 1); if (check == 0xAA) { ps2_command(port, 0xF5, NULL, 0); ps2_command(port, 0xF2, (uchar *)(&type), 2); if (type == PS2_NO_DEVICE) { type = PS2_KB_NORMAL; } if (type == PS2_KB_NORMAL || type == PS2_KB_MF2) { ps2_devs[port] = create_stream( sizeof(unsigned), ps2_kb_enable, ps2_kb_disable, ps2_kb_read, NULL ); ps2d = kalloc(sizeof(ps2_device)); ps2d->type = type; ps2d->port = port; ps2_devs[port]->data = ps2d; reg_dev(DEVICE_INPUT, ps2_devs[port]->hndl); enable_device(ps2_devs[port]); } else { ps2_devs[port] = NULL; //TODO: implement } kprintf("PS/2 Device %x detected.\n", type); } } else { outb(PS2_CMND, enable - 1); } } } }
static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) { if (loc < 0x20 || loc >= 0x2F) return -1; if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { return -1; } return 0; }
static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask) { /* Bad things will happen if the loc param isn't in this range */ if (loc < 0x20 || loc >= 0x2F) return -1; if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { return -1; } return 0; }
static void ps2_execute_scheduled_command(void *data) { struct ps2work *ps2work = data; ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); kfree(ps2work); }
int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties) { struct input_dev *dev = psmouse->dev; unsigned char param[3]; int command; param[0] = TOUCHKIT_CMD_LENGTH; param[1] = TOUCHKIT_CMD_ACTIVE; command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD); if (ps2_command(&psmouse->ps2dev, param, command)) return -ENODEV; if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 || param[2] != TOUCHKIT_CMD_ACTIVE) return -ENODEV; if (set_properties) { dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); __set_bit(BTN_TOUCH, dev->keybit); input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); psmouse->vendor = "eGalax"; psmouse->name = "Touchscreen"; psmouse->protocol_handler = touchkit_ps2_process_byte; psmouse->pktsize = 5; } return 0; }
int kbd_command(int command, u8 *param) { dprintf(7, "kbd_command cmd=%x\n", command); int ret = ps2_command(0, command, param); if (ret) dprintf(2, "keyboard command %x failed\n", command); return ret; }
int aux_command(int command, u8 *param) { dprintf(7, "aux_command cmd=%x\n", command); int ret = ps2_command(1, command, param); if (ret) dprintf(2, "mouse command %x failed\n", command); return ret; }
/* * Power-on Reset: Resets all trackpoint parameters, including RAM values, * to defaults. * Returns zero on success, non-zero on failure. */ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) { u8 results[2]; int tries = 0; /* Issue POR command, and repeat up to once if 0xFC00 received */ do { if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR))) return -1; } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2); /* Check for success response -- 0xAA00 */ if (results[0] != 0xAA || results[1] != 0x00) return -ENODEV; return 0; }
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) { unsigned char params[] = { 0, 1, 2, 2, 3 }; if (resolution == 0 || resolution > 400) resolution = 400; ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES); psmouse->resolution = 50 << params[resolution / 100]; }
/* * Set the synaptics touchpad mode byte by special commands */ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) { unsigned char param[1]; if (psmouse_sliced_command(psmouse, mode)) return -1; param[0] = SYN_PS_SET_MODE2; if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) return -1; return 0; }
int synaptics_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; param[0] = 0; ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); if (param[1] != 0x47) return -ENODEV; if (set_properties) { psmouse->vendor = "Synaptics"; psmouse->name = "TouchPad"; } return 0; }
/* void setup_ps2(void) { void ps2_kb_int(void); void ps2_ms_int(void); // TODO determine from ACPI if PS/2 controller exists // disable ps/2 devices outb(PS2_CMND, 0xAD); outb(PS2_CMND, 0xA7); flush_output(); // disable interrupts and translation chg_config(0x43, 0); // ps/2 controller self test outb(PS2_CMND, 0xAA); do_assert(wait_read()); if (inb(PS2_DATA) != 0x55) { kputs("PS/2 Controller self test failed.\n"); return; } // individual device detection detect_device(0, 0xAE, 0xAB, 0x10); detect_device(1, 0xA8, 0xA9, 0x20); // register IRQ's reg_irq(IRQ_PS2_KEYBOARD, ps2_kb_int); reg_irq(IRQ_PS2_MOUSE, ps2_ms_int); // enable ps2 devices ps2_enable(1); ps2_enable(0); } void ps2_enable(uint port) { if (ps2_devices[port] != PS2_NO_DEVICE) { ps2_command(port, 0xF4, NULL, 0); chg_config(0, 1 << port); } else { kputs("Tried to enable non-existant PS/2 device!\n"); } } */ void ps2_kb_enable(device_t * d) { void ps2_kb_int(void); ps2_device * dev = d->data; if (dev->type == PS2_KB_NORMAL || dev->type == PS2_KB_MF2) { ps2_command(dev->port, 0xF4, NULL, 0); chg_config(0, 1 << dev->port); reg_irq(IRQ_PS2_KEYBOARD, ps2_kb_int); } else { //TODO assert(0); } }
static int lifebook_absolute_mode(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param; if (psmouse_reset(psmouse)) return -1; /* Enable absolute output -- ps2_command fails always but if you leave this call out the touchsreen will never send absolute coordinates */ param = 0x07; ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); return 0; }
status_t ps2_open( void* pNode, uint32 nFlags, void **pCookie ) { uint8 nControl; uint32 nFlg; PS2_Port_s* psPort = (PS2_Port_s*)pNode; printk( "ps2_open()\n" ); if ( atomic_inc_and_read( &psPort->nOpenCount ) > 0 ) { atomic_dec( &psPort->nOpenCount ); return( -EBUSY ); } ps2_flush(); psPort->nIrqHandle = request_irq( psPort->nIrq, ps2_interrupt, NULL, 0, "ps2", psPort ); if ( psPort->nIrqHandle < 0 ) { printk( "PS2: Could not get irq %i\n", psPort->nIrq ); atomic_dec( &psPort->nOpenCount ); return( -EBUSY ); } /* Enable device */ if( psPort->bIsAux ) ps2_command( PS2_CMD_AUX_ENABLE ); nFlg = spinlock_disable( &g_sLock ); ps2_read_command( PS2_CMD_RCTR, &nControl ); if( psPort->bIsAux ) { nControl &= ~PS2_CTR_AUXDIS; nControl |= PS2_CTR_AUXINT; } else { nControl &= ~PS2_CTR_KBDDIS; nControl |= PS2_CTR_KBDINT; } ps2_write_command( PS2_CMD_WCTR, nControl ); spinunlock_enable( &g_sLock, nFlg ); atomic_set( &psPort->nBytesReceived, 0 ); atomic_set( &psPort->nInPos, 0 ); atomic_set( &psPort->nOutPos, 0 ); return( 0 ); }
status_t probe_keyboard(void) { uint8 data; status_t status; // This test doesn't work relyable on some notebooks (it reports 0x03) // status = ps2_command(PS2_CTRL_KEYBOARD_TEST, NULL, 0, &data, 1); // if (status != B_OK || data != 0x00) { // INFO("ps2: keyboard test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, 0, &data, 1); if (status != B_OK || data != 0xaa) { INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", status, data); return B_ERROR; } // default settings after keyboard reset: delay = 0x01 (500 ms), // rate = 0x0b (10.9 chr/sec) sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20; sKeyboardRepeatDelay = 500000; // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_ENABLE_KEYBOARD, NULL, 0, NULL, 0); // On my notebook, the keyboard controller does NACK the echo command. // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_ECHO, NULL, 0, &data, 1); // if (status != B_OK || data != 0xee) { // INFO("ps2: keyboard echo test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } // Some controllers set the disble keyboard command bit to "on" after resetting // the keyboard device. Read #7973 #6313 for more details. // So check the command byte now and re-enable the keyboard if it is the case. uint8 cmdbyte = 0; status = ps2_command(PS2_CTRL_READ_CMD, NULL, 0, &cmdbyte, 1); if (status != B_OK) { INFO("ps2: cannot read CMD byte on kbd probe:0x%#08lx\n", status); } else if ((cmdbyte & PS2_BITS_KEYBOARD_DISABLED) == PS2_BITS_KEYBOARD_DISABLED) { cmdbyte &= ~PS2_BITS_KEYBOARD_DISABLED; status = ps2_command(PS2_CTRL_WRITE_CMD, &cmdbyte, 1, NULL, 0); if (status != B_OK) { INFO("ps2: cannot write 0x%02x to CMD byte on kbd probe:0x%08lx\n", cmdbyte, status); } } status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_GET_DEVICE_ID, NULL, 0, sKeyboardIds, sizeof(sKeyboardIds)); if (status != B_OK) { INFO("ps2: cannot read keyboard device id:0x%#08lx\n", status); } return B_OK; }
int ps2_mouse_command(int command, u8 *param) { return ps2_command(1, command, param); }
int ps2_kbd_command(int command, u8 *param) { return ps2_command(0, command, param); }
static status_t ps2_aux_init() { int nError = 0; struct RMREGS rm; /* TODO: Do this without calling the bios */ memset( &rm, 0, sizeof( struct RMREGS ) ); realint( 0x11, &rm ); if( ( rm.EAX & 0x04 ) == 0 ) { printk( "No PS2 mouse present\n" ); return( -EIO ); } memset( &g_sAuxPort, 0, sizeof( g_sAuxPort ) ); g_sAuxPort.bIsAux = true; /* Flush buffer */ ps2_flush(); /* Test loop command */ uint8 nData = 0x5a; nError = ps2_write_read_command( PS2_CMD_AUX_LOOP, &nData ); if( nError < 0 || nData != 0x5a ) { /* According to linux driver the loop test fails on some chipsets */ printk( "PS2 Aux loop test failed (error = %i, data = %x)! Trying test command...\n", nError, (uint)nData ); if( ps2_read_command( PS2_CMD_AUX_TEST, &nData ) < 0 ) { printk( "Failed -> Aux port not present!\n" ); return( -ENOENT ); } printk( "Test command returned %x\n", (uint)nData ); if( nData && nData != 0xfa && nData != 0xff ) { printk( "Invalid return code!\n" ); return( -ENOENT ); } } /* Disable and then enable the auxport */ if( ps2_command( PS2_CMD_AUX_DISABLE ) < 0 ) return( -ENOENT ); if( ps2_command( PS2_CMD_AUX_ENABLE ) < 0 ) return( -ENOENT ); if( ps2_read_command( PS2_CMD_RCTR, &nData ) < 0 || ( nData & PS2_CTR_AUXDIS ) ) return( -EIO ); /* Disable aux port */ nData |= PS2_CTR_AUXDIS; nData &= ~PS2_CTR_AUXINT; /* Write control register */ nError = ps2_write_command( PS2_CMD_WCTR, nData ); if( nError < 0 ) { printk( "PS2 I/O error\n" ); return( -EIO ); } printk( "PS2 AUX port detected\n" ); /* Register device */ g_sAuxPort.bPresent = true; g_sAuxPort.hWait = create_semaphore( "ps2_wait", 0, 0 ); g_sAuxPort.nDevHandle = register_device( "", "isa" ); g_sAuxPort.nIrq = 12; claim_device( g_nDevNum, g_sAuxPort.nDevHandle, "PS/2 Aux port", DEVICE_PORT ); set_device_data( g_sAuxPort.nDevHandle, &g_sAuxPort ); nError = create_device_node( g_nDevNum, g_sAuxPort.nDevHandle, "misc/ps2aux", &g_sOperations, &g_sAuxPort ); if( nError < 0 ) return( -EIO ); return( 0 ); }