📄 synaptics.c
字号:
/* * Synaptics TouchPad PS/2 mouse driver * * 2003 Dmitry Torokhov <dtor@mail.ru> * Added support for pass-through port. Special thanks to Peter Berg Larsen * for explaining various Synaptics quirks. * * 2003 Peter Osterlund <petero2@telia.com> * Ported to 2.5 input device infrastructure. * * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch> * start merging tpconfig and gpm code to a xfree-input module * adding some changes and extensions (ex. 3rd and 4th button) * * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu> * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com> * code for the special synaptics commands (from the tpconfig-source) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * Trademarks are the property of their respective owners. */#include <linux/module.h>#include <linux/input.h>#include <linux/serio.h>#include "psmouse.h"#include "synaptics.h"/* * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, * section 2.3.2, which says that they should be valid regardless of the * actual size of the sensor. */#define XMIN_NOMINAL 1472#define XMAX_NOMINAL 5472#define YMIN_NOMINAL 1408#define YMAX_NOMINAL 4448/***************************************************************************** * Synaptics communications functions ****************************************************************************//* * Send a command to the synpatics touchpad by special commands */static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param){ if (psmouse_sliced_command(psmouse, c)) return -1; if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) return -1; return 0;}/* * 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 (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE)) return -1; return 0;}/* * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros */static int synaptics_model_id(struct psmouse *psmouse){ struct synaptics_data *priv = psmouse->private; unsigned char mi[3]; if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) return -1; priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; return 0;}/* * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros */static int synaptics_capability(struct psmouse *psmouse){ struct synaptics_data *priv = psmouse->private; unsigned char cap[3]; if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) return -1; priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; priv->ext_cap = 0; if (!SYN_CAP_VALID(priv->capabilities)) return -1; /* * Unless capExtended is set the rest of the flags should be ignored */ if (!SYN_CAP_EXTENDED(priv->capabilities)) priv->capabilities = 0; if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { printk(KERN_ERR "Synaptics claims to have extended capabilities," " but I'm not able to read them."); } else { priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) priv->ext_cap &= 0xff0fff; } } return 0;}/* * Identify Touchpad * See also the SYN_ID_* macros */static int synaptics_identify(struct psmouse *psmouse){ struct synaptics_data *priv = psmouse->private; unsigned char id[3]; if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) return -1; priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; if (SYN_ID_IS_SYNAPTICS(priv->identity)) return 0; return -1;}static void print_ident(struct synaptics_data *priv){ printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity)); printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity)); if (SYN_MODEL_ROT180(priv->model_id)) printk(KERN_INFO " 180 degree mounted touchpad\n"); if (SYN_MODEL_PORTRAIT(priv->model_id)) printk(KERN_INFO " portrait touchpad\n"); printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id)); if (SYN_MODEL_NEWABS(priv->model_id)) printk(KERN_INFO " new absolute packet format\n"); if (SYN_MODEL_PEN(priv->model_id)) printk(KERN_INFO " pen detection\n"); if (SYN_CAP_EXTENDED(priv->capabilities)) { printk(KERN_INFO " Touchpad has extended capability bits\n"); if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) printk(KERN_INFO " -> middle button\n"); if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) printk(KERN_INFO " -> four buttons\n"); if (SYN_CAP_MULTIFINGER(priv->capabilities)) printk(KERN_INFO " -> multifinger detection\n"); if (SYN_CAP_PALMDETECT(priv->capabilities)) printk(KERN_INFO " -> palm detection\n"); if (SYN_CAP_PASS_THROUGH(priv->capabilities)) printk(KERN_INFO " -> pass-through port\n"); }}static int synaptics_query_hardware(struct psmouse *psmouse){ int retries = 0; while ((retries++ < 3) && psmouse_reset(psmouse)) printk(KERN_ERR "synaptics reset failed\n"); if (synaptics_identify(psmouse)) return -1; if (synaptics_model_id(psmouse)) return -1; if (synaptics_capability(psmouse)) return -1; return 0;}static int synaptics_set_mode(struct psmouse *psmouse, int mode){ struct synaptics_data *priv = psmouse->private; mode |= SYN_BIT_ABSOLUTE_MODE; if (psmouse_rate >= 80) mode |= SYN_BIT_HIGH_RATE; if (SYN_ID_MAJOR(priv->identity) >= 4) mode |= SYN_BIT_DISABLE_GESTURE; if (SYN_CAP_EXTENDED(priv->capabilities)) mode |= SYN_BIT_W_MODE; if (synaptics_mode_cmd(psmouse, mode)) return -1; return 0;}/***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/static int synaptics_pt_write(struct serio *port, unsigned char c){ struct psmouse *parent = port->driver; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ if (psmouse_sliced_command(parent, c)) return -1; if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) return -1; return 0;}static inline int synaptics_is_pt_packet(unsigned char *buf){ return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;}static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet){ struct psmouse *child = ptport->private; if (child) { if (child->state == PSMOUSE_ACTIVATED) { serio_interrupt(ptport, packet[1], 0, NULL); serio_interrupt(ptport, packet[4], 0, NULL); serio_interrupt(ptport, packet[5], 0, NULL); if (child->type >= PSMOUSE_GENPS) serio_interrupt(ptport, packet[2], 0, NULL); } else if (child->state != PSMOUSE_IGNORE) { serio_interrupt(ptport, packet[1], 0, NULL); } }}static void synaptics_pt_activate(struct psmouse *psmouse){ struct psmouse *child = psmouse->ptport->serio.private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT)) printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n"); }}static void synaptics_pt_create(struct psmouse *psmouse){ struct psmouse_ptport *port; psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); if (!port) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } memset(port, 0, sizeof(struct psmouse_ptport)); port->serio.type = SERIO_PS_PSTHRU; port->serio.name = "Synaptics pass-through"; port->serio.phys = "synaptics-pt/serio0"; port->serio.write = synaptics_pt_write; port->serio.driver = psmouse; port->activate = synaptics_pt_activate;}/***************************************************************************** * Functions to interpret the absolute mode packets ****************************************************************************/static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw){ memset(hw, 0, sizeof(struct synaptics_hw_state)); if (SYN_MODEL_NEWABS(priv->model_id)) { hw->x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]); hw->y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]); hw->z = buf[2]; hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -