Commit ff3c0388 authored by Steve French's avatar Steve French

Merge bk://linux.bkbits.net/linux-2.5

into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs
parents 6ecc87a7 501a9693
...@@ -896,8 +896,8 @@ running once the system is up. ...@@ -896,8 +896,8 @@ running once the system is up.
psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports
per second. per second.
psmouse.resetafter= psmouse.resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many [HW,MOUSE] Try to reset the device after so many bad packets
bad packets (0 = never). (0 = never).
psmouse.resolution= psmouse.resolution=
[HW,MOUSE] Set desired mouse resolution, in dpi. [HW,MOUSE] Set desired mouse resolution, in dpi.
psmouse.smartscroll= psmouse.smartscroll=
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -75,7 +76,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) ...@@ -75,7 +76,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
return 0; return 0;
} }
void __flush_dcache_page(struct page *page) static void __flush_dcache_page(struct page *page)
{ {
struct address_space *mapping = page_mapping(page); struct address_space *mapping = page_mapping(page);
struct mm_struct *mm = current->active_mm; struct mm_struct *mm = current->active_mm;
...@@ -111,6 +112,17 @@ void __flush_dcache_page(struct page *page) ...@@ -111,6 +112,17 @@ void __flush_dcache_page(struct page *page)
flush_dcache_mmap_unlock(mapping); flush_dcache_mmap_unlock(mapping);
} }
void flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping(page);
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
else
__flush_dcache_page(page);
}
EXPORT_SYMBOL(flush_dcache_page);
static void static void
make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
{ {
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
EXPORT_SYMBOL(__flush_dcache_page);
#ifndef MULTI_CPU #ifndef MULTI_CPU
EXPORT_SYMBOL(cpu_dcache_clean_area); EXPORT_SYMBOL(cpu_dcache_clean_area);
EXPORT_SYMBOL(cpu_set_pte); EXPORT_SYMBOL(cpu_set_pte);
...@@ -28,7 +26,6 @@ EXPORT_SYMBOL_NOVERS(__cpuc_flush_kern_all); ...@@ -28,7 +26,6 @@ EXPORT_SYMBOL_NOVERS(__cpuc_flush_kern_all);
EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_all); EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_all);
EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_range); EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_range);
EXPORT_SYMBOL_NOVERS(__cpuc_coherent_kern_range); EXPORT_SYMBOL_NOVERS(__cpuc_coherent_kern_range);
EXPORT_SYMBOL_NOVERS(__cpuc_flush_dcache_page);
#else #else
EXPORT_SYMBOL(cpu_cache); EXPORT_SYMBOL(cpu_cache);
#endif #endif
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README, # To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk # or contact rmk@arm.linux.org.uk
# #
# Last update: Thu Apr 29 19:06:33 2004 # Last update: Fri May 28 13:17:46 2004
# #
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
# #
...@@ -509,7 +509,7 @@ s3c5500 MACH_S3C5500 S3C5500 498 ...@@ -509,7 +509,7 @@ s3c5500 MACH_S3C5500 S3C5500 498
smdk5500 MACH_SMDK5500 SMDK5500 499 smdk5500 MACH_SMDK5500 SMDK5500 499
signalsync MACH_SIGNALSYNC SIGNALSYNC 500 signalsync MACH_SIGNALSYNC SIGNALSYNC 500
nbc MACH_NBC NBC 501 nbc MACH_NBC NBC 501
er4525 MACH_ER4525 ER4525 502 kodiak MACH_KODIAK KODIAK 502
netbookpro MACH_NETBOOKPRO NETBOOKPRO 503 netbookpro MACH_NETBOOKPRO NETBOOKPRO 503
hw90200 MACH_HW90200 HW90200 504 hw90200 MACH_HW90200 HW90200 504
condor MACH_CONDOR CONDOR 505 condor MACH_CONDOR CONDOR 505
...@@ -533,3 +533,16 @@ emc1000 MACH_EMC1000 EMC1000 522 ...@@ -533,3 +533,16 @@ emc1000 MACH_EMC1000 EMC1000 522
tidsc25 MACH_TIDSC25 TIDSC25 523 tidsc25 MACH_TIDSC25 TIDSC25 523
akcpmxl MACH_AKCPMXL AKCPMXL 524 akcpmxl MACH_AKCPMXL AKCPMXL 524
av3xx MACH_AV3XX AV3XX 525 av3xx MACH_AV3XX AV3XX 525
avila MACH_AVILA AVILA 526
pxa_mpm10 MACH_PXA_MPM10 PXA_MPM10 527
pxa_kyanite MACH_PXA_KYANITE PXA_KYANITE 528
sgold MACH_SGOLD SGOLD 529
oscar MACH_OSCAR OSCAR 530
epxa4usb2 MACH_EPXA4USB2 EPXA4USB2 531
xsengine MACH_XSENGINE XSENGINE 532
ip600 MACH_IP600 IP600 533
mcan2 MACH_MCAN2 MCAN2 534
ddi_blueridge MACH_DDI_BLUERIDGE DDI_BLUERIDGE 535
skyminder MACH_SKYMINDER SKYMINDER 536
lpd79520 MACH_LPD79520 LPD79520 537
edb9302 MACH_EDB9302 EDB9302 538
...@@ -783,6 +783,7 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={ ...@@ -783,6 +783,7 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
{ exploding_pnp_bios, "ASUS P4P800", { /* PnPBIOS GPF on boot */ { exploding_pnp_bios, "ASUS P4P800", { /* PnPBIOS GPF on boot */
MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
MATCH(DMI_BOARD_NAME, "P4P800"), MATCH(DMI_BOARD_NAME, "P4P800"),
NO_MATCH, NO_MATCH
} }, } },
/* Machines which have problems handling enabled local APICs */ /* Machines which have problems handling enabled local APICs */
......
...@@ -66,6 +66,17 @@ void flush_hash_one_pte(pte_t *ptep) ...@@ -66,6 +66,17 @@ void flush_hash_one_pte(pte_t *ptep)
flush_hash_pages(mm->context, addr, ptephys, 1); flush_hash_pages(mm->context, addr, ptephys, 1);
} }
/*
* Called by ptep_set_access_flags, must flush on CPUs for which the
* DSI handler can't just "fixup" the TLB on a write fault
*/
void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr)
{
if (Hash != 0)
return;
_tlbie(addr);
}
/* /*
* Called at the end of a mmu_gather operation to make sure the * Called at the end of a mmu_gather operation to make sure the
* TLB flush is completely done. * TLB flush is completely done.
......
...@@ -4525,7 +4525,7 @@ static int mgsl_init_tty(void) ...@@ -4525,7 +4525,7 @@ static int mgsl_init_tty(void)
/* enumerate user specified ISA adapters /* enumerate user specified ISA adapters
*/ */
static int mgsl_enum_isa_devices(void) static void mgsl_enum_isa_devices(void)
{ {
struct mgsl_struct *info; struct mgsl_struct *info;
int i; int i;
......
...@@ -41,9 +41,16 @@ config INPUT_MOUSEDEV ...@@ -41,9 +41,16 @@ config INPUT_MOUSEDEV
module will be called mousedev. module will be called mousedev.
config INPUT_MOUSEDEV_PSAUX config INPUT_MOUSEDEV_PSAUX
bool "Provide legacy /dev/psaux device" if EMBEDDED bool "Provide legacy /dev/psaux device"
default y default y
depends on INPUT_MOUSEDEV depends on INPUT_MOUSEDEV
---help---
Say Y here if you want your mouse also be accessible as char device
10:1 - /dev/psaux. The data available through /dev/psaux is exactly
the same as the data from /dev/input/mice.
If unsure, say Y.
config INPUT_MOUSEDEV_SCREEN_X config INPUT_MOUSEDEV_SCREEN_X
int "Horizontal screen resolution" int "Horizontal screen resolution"
......
...@@ -126,7 +126,7 @@ static int evdev_open(struct inode * inode, struct file * file) ...@@ -126,7 +126,7 @@ static int evdev_open(struct inode * inode, struct file * file)
int i = iminor(inode) - EVDEV_MINOR_BASE; int i = iminor(inode) - EVDEV_MINOR_BASE;
int accept_err; int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i]) if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
return -ENODEV; return -ENODEV;
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
...@@ -175,7 +175,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count ...@@ -175,7 +175,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
return -EAGAIN; return -EAGAIN;
retval = wait_event_interruptible(list->evdev->wait, retval = wait_event_interruptible(list->evdev->wait,
list->head != list->tail && list->evdev->exist); list->head != list->tail || (!list->evdev->exist));
if (retval) if (retval)
return retval; return retval;
......
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
MODULE_LICENSE("GPL");
/* /*
* Constants. * Constants.
*/ */
...@@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs ...@@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs
* packet processing routine. * packet processing routine.
*/ */
static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struc pt_regs *regs) static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
{ {
struct twidjoy *twidjoy = serio->private; struct twidjoy *twidjoy = serio->private;
...@@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned ...@@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
if ((data & 0x80) == 0) if ((data & 0x80) == 0)
twidjoy->idx = 0; /* this byte starts a new packet */ twidjoy->idx = 0; /* this byte starts a new packet */
else if (twidjoy->idx == 0) else if (twidjoy->idx == 0)
return; /* wrong MSB -- ignore this byte */ return IRQ_HANDLED; /* wrong MSB -- ignore this byte */
if (twidjoy->idx < TWIDJOY_MAX_LENGTH) if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
twidjoy->data[twidjoy->idx++] = data; twidjoy->data[twidjoy->idx++] = data;
...@@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned ...@@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
twidjoy->idx = 0; twidjoy->idx = 0;
} }
return; return IRQ_HANDLED;
} }
/* /*
......
...@@ -109,7 +109,7 @@ struct kbd98 { ...@@ -109,7 +109,7 @@ struct kbd98 {
struct jis_kbd_conv jis[16]; struct jis_kbd_conv jis[16];
}; };
void kbd98_interrupt(struct serio *serio, unsigned char data, irqreturn_t kbd98_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs) unsigned int flags, struct pt_regs *regs)
{ {
struct kbd98 *kbd98 = serio->private; struct kbd98 *kbd98 = serio->private;
...@@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
switch (data) { switch (data) {
case KBD98_RET_ACK: case KBD98_RET_ACK:
kbd98->ack = 1; kbd98->ack = 1;
return; goto out;
case KBD98_RET_NAK: case KBD98_RET_NAK:
kbd98->ack = -1; kbd98->ack = -1;
return; goto out;
} }
if (kbd98->cmdcnt) { if (kbd98->cmdcnt) {
kbd98->cmdbuf[--kbd98->cmdcnt] = data; kbd98->cmdbuf[--kbd98->cmdcnt] = data;
return; goto out;
} }
scancode = data & KBD98_KEY; scancode = data & KBD98_KEY;
...@@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
keycode = kbd98->jis[i].emul[kbd98->shift].keycode; keycode = kbd98->jis[i].emul[kbd98->shift].keycode;
if (keycode == KBD98_KEY_NULL) if (keycode == KBD98_KEY_NULL)
return; break;
if (press) { if (press) {
kbd98->emul.scancode = scancode; kbd98->emul.scancode = scancode;
...@@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
} }
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
return; break;
case KEY_CAPSLOCK: case KEY_CAPSLOCK:
input_report_key(&kbd98->dev, keycode, 1); input_report_key(&kbd98->dev, keycode, 1);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
input_report_key(&kbd98->dev, keycode, 0); input_report_key(&kbd98->dev, keycode, 0);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
return; break;
case KBD98_KEY_NULL: case KBD98_KEY_NULL:
return; break;
case 0: case 0:
printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n", printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n",
data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed"); data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed");
return; break;
default: default:
input_report_key(&kbd98->dev, keycode, press); input_report_key(&kbd98->dev, keycode, press);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
break;
} }
out:
return IRQ_HANDLED;
} }
/* /*
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/timer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
...@@ -173,22 +172,24 @@ struct atkbd { ...@@ -173,22 +172,24 @@ struct atkbd {
unsigned char keycode[512]; unsigned char keycode[512];
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct timer_list timer;
char name[64]; char name[64];
char phys[32]; char phys[32];
unsigned short id;
unsigned char set;
unsigned int translated:1;
unsigned int extra:1;
unsigned int write:1;
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
unsigned char set;
unsigned char extra;
unsigned char release;
int lastkey;
volatile signed char ack; volatile signed char ack;
unsigned char emul; unsigned char emul;
unsigned short id; unsigned int resend:1;
unsigned char write; unsigned int release:1;
unsigned char translated; unsigned int bat_xl:1;
unsigned char resend; unsigned int enabled:1;
unsigned char bat_xl;
unsigned int last; unsigned int last;
unsigned long time; unsigned long time;
}; };
...@@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
goto out; goto out;
} }
if (!atkbd->enabled)
goto out;
if (atkbd->translated) { if (atkbd->translated) {
if (atkbd->emul || if (atkbd->emul ||
...@@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
case ATKBD_KEY_NULL: case ATKBD_KEY_NULL:
break; break;
case ATKBD_KEY_UNKNOWN: case ATKBD_KEY_UNKNOWN:
printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
"like XFree86, might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
} else {
printk(KERN_WARNING "atkbd.c: Unknown key %s "
"(%s set %d, code %#x on %s).\n",
atkbd->release ? "released" : "pressed", atkbd->release ? "released" : "pressed",
atkbd->translated ? "translated" : "raw", atkbd->translated ? "translated" : "raw",
atkbd->set, code, serio->phys); atkbd->set, code, serio->phys);
if (atkbd->translated && atkbd->set == 2 && code == 0x7a) printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access" "to make it known.\n",
" hardware directly.\n"); code & 0x80 ? "e0" : "", code & 0x7f);
else }
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f);
break; break;
case ATKBD_SCR_1: case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2; scroll = 1 - atkbd->release * 2;
...@@ -745,6 +754,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -745,6 +754,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->id = 0xab00; atkbd->id = 0xab00;
} }
atkbd->enabled = 1;
if (atkbd->extra) { if (atkbd->extra) {
atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
sprintf(atkbd->name, "AT Set 2 Extra keyboard"); sprintf(atkbd->name, "AT Set 2 Extra keyboard");
......
...@@ -14,6 +14,25 @@ ...@@ -14,6 +14,25 @@
#include "psmouse.h" #include "psmouse.h"
#include "logips2pp.h" #include "logips2pp.h"
/* Logitech mouse types */
#define PS2PP_KIND_WHEEL 1
#define PS2PP_KIND_MX 2
#define PS2PP_KIND_TP3 3
/* Logitech mouse features */
#define PS2PP_WHEEL 0x01
#define PS2PP_HWHEEL 0x02
#define PS2PP_SIDE_BTN 0x04
#define PS2PP_EXTRA_BTN 0x08
#define PS2PP_TASK_BTN 0x10
#define PS2PP_NAV_BTN 0x20
struct ps2pp_info {
const int model;
unsigned const int kind;
unsigned const int features;
};
/* /*
* Process a PS2++ or PS2T++ packet. * Process a PS2++ or PS2T++ packet.
*/ */
...@@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse)
packet[0] &= 0x0f; packet[0] &= 0x0f;
packet[1] = 0; packet[1] = 0;
packet[2] = 0; packet[2] = 0;
} }
} }
...@@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse)
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
{ {
unsigned char d; if (psmouse_sliced_command(psmouse, command))
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1; return -1;
for (i = 6; i >= 0; i -= 2) {
d = (command >> i) & 3;
if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
return -1; return -1;
...@@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse) ...@@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
if (psmouse_smartscroll == 1) if (psmouse_smartscroll < 2) {
param[0] = 1; /* 0 - disabled, 1 - enabled */
else param[0] = psmouse_smartscroll;
if (psmouse_smartscroll > 2)
return;
/* else leave param[0] == 0 to disable */
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
}
} }
/* /*
...@@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse) ...@@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse)
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
} }
/* static struct ps2pp_info *get_model_info(unsigned char model)
* Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
* touchpad.
*/
static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
{ {
int i; static struct ps2pp_info ps2pp_list[] = {
static struct _logips2_list { { 12, 0, PS2PP_SIDE_BTN},
const int model; { 13, 0, 0 },
unsigned const int features; { 40, 0, PS2PP_SIDE_BTN },
} logips2pp_list [] = { { 41, 0, PS2PP_SIDE_BTN },
{ 12, PS2PP_4BTN}, { 42, 0, PS2PP_SIDE_BTN },
{ 13, 0 }, { 43, 0, PS2PP_SIDE_BTN },
{ 40, PS2PP_4BTN }, { 50, 0, 0 },
{ 41, PS2PP_4BTN }, { 51, 0, 0 },
{ 42, PS2PP_4BTN }, { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 43, PS2PP_4BTN }, { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 50, 0 }, { 61, PS2PP_KIND_MX,
{ 51, 0 }, PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
{ 52, PS2PP_4BTN | PS2PP_WHEEL }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */
{ 53, PS2PP_WHEEL }, { 73, 0, PS2PP_SIDE_BTN },
{ 61, PS2PP_WHEEL | PS2PP_MX }, /* MX700 */ { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 73, PS2PP_4BTN }, { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 75, PS2PP_WHEEL }, { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 76, PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 80, PS2PP_4BTN | PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 81, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_WHEEL }, { 96, 0, 0 },
{ 88, PS2PP_WHEEL }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
{ 96, 0 }, { 100, PS2PP_KIND_MX,
{ 97, 0 }, PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
{ 100 , PS2PP_WHEEL | PS2PP_MX }, /* MX510 */ PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */
{ 112 , PS2PP_WHEEL | PS2PP_MX }, /* MX500 */ { 112, PS2PP_KIND_MX,
{ 114 , PS2PP_WHEEL | PS2PP_MX | PS2PP_MX310 }, /* MX310 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */
{ 114, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN |
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */
{ } { }
}; };
int i;
psmouse->vendor = "Logitech"; for (i = 0; ps2pp_list[i].model; i++)
psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); if (model == ps2pp_list[i].model)
return &ps2pp_list[i];
if (param[1] < 3) return NULL;
clear_bit(BTN_MIDDLE, psmouse->dev.keybit); }
if (param[1] < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
psmouse->type = PSMOUSE_PS2; /*
* Set up input device's properties based on the detected mouse model.
*/
for (i = 0; logips2pp_list[i].model; i++){ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
if (logips2pp_list[i].model == psmouse->model){ {
psmouse->type = PSMOUSE_PS2PP; if (model_info->features & PS2PP_SIDE_BTN)
if (logips2pp_list[i].features & PS2PP_4BTN)
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
if (logips2pp_list[i].features & PS2PP_WHEEL){ if (model_info->features & PS2PP_EXTRA_BTN)
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->name = "Wheel Mouse";
}
if (logips2pp_list[i].features & PS2PP_MX) {
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (model_info->features & PS2PP_TASK_BTN)
set_bit(BTN_TASK, psmouse->dev.keybit); set_bit(BTN_TASK, psmouse->dev.keybit);
if (!(logips2pp_list[i].features & PS2PP_MX310)){
set_bit(BTN_BACK, psmouse->dev.keybit); if (model_info->features & PS2PP_NAV_BTN) {
set_bit(BTN_FORWARD, psmouse->dev.keybit); set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
} }
if (model_info->features & PS2PP_WHEEL)
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (model_info->features & PS2PP_HWHEEL)
set_bit(REL_HWHEEL, psmouse->dev.relbit);
switch (model_info->kind) {
case PS2PP_KIND_WHEEL:
psmouse->name = "Wheel Mouse";
break;
case PS2PP_KIND_MX:
psmouse->name = "MX Mouse"; psmouse->name = "MX Mouse";
} break;
case PS2PP_KIND_TP3:
psmouse->name = "TouchPad 3";
break; break;
} }
} }
/* /*
* Do Logitech PS2++ / PS2T++ magic init. * Logitech magic init. Detect whether the mouse is a Logitech one
* and its exact model and try turning on extended protocol for ones
* that support it.
*/ */
if (psmouse->type == PSMOUSE_PS2PP) {
if (psmouse->model == 97) { /* TouchPad 3 */ int ps2pp_init(struct psmouse *psmouse, int set_properties)
{
unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons;
struct ps2pp_info *model_info;
set_bit(REL_WHEEL, psmouse->dev.relbit); param[0] = 0;
set_bit(REL_HWHEEL, psmouse->dev.relbit); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
if (param[1] != 0) {
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
buttons = param[1];
model_info = get_model_info(model);
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ /*
* Do Logitech PS2++ / PS2T++ magic init.
*/
if (model == 97) { /* Touch Pad 3 */
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ /* Enable features */
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ /* Enable PS2++ */
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0; param[0] = 0;
if (!psmouse_command(psmouse, param, 0x13d1) && if (!psmouse_command(psmouse, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
psmouse->name = "TouchPad 3"; protocol = PSMOUSE_PS2TPP;
return PSMOUSE_PS2TPP;
} }
} else { } else if (get_model_info(model) != NULL) {
param[0] = param[1] = param[2] = 0; param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
ps2pp_cmd(psmouse, param, 0xDB); ps2pp_cmd(psmouse, param, 0xDB);
if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && if ((param[0] & 0x78) == 0x48 &&
(param[2] & 3) == ((param[1] >> 2) & 3)) { (param[1] & 0xf3) == 0xc2 &&
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
ps2pp_set_smartscroll(psmouse); ps2pp_set_smartscroll(psmouse);
return PSMOUSE_PS2PP; protocol = PSMOUSE_PS2PP;
}
} }
} }
return 0; if (set_properties) {
} psmouse->vendor = "Logitech";
psmouse->model = model;
/* if (buttons < 3)
* Logitech magic init. clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
*/ if (buttons < 2)
int ps2pp_detect(struct psmouse *psmouse) clear_bit(BTN_RIGHT, psmouse->dev.keybit);
{
unsigned char param[4];
param[0] = 0; if (model_info)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2pp_set_model_properties(psmouse, model_info);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); }
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); }
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0; return protocol;
} }
...@@ -11,13 +11,8 @@ ...@@ -11,13 +11,8 @@
#ifndef _LOGIPS2PP_H #ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H #define _LOGIPS2PP_H
#define PS2PP_4BTN 0x01
#define PS2PP_WHEEL 0x02
#define PS2PP_MX 0x04
#define PS2PP_MX310 0x08
struct psmouse;
void ps2pp_process_packet(struct psmouse *psmouse); void ps2pp_process_packet(struct psmouse *psmouse);
void ps2pp_set_800dpi(struct psmouse *psmouse); void ps2pp_set_800dpi(struct psmouse *psmouse);
int ps2pp_detect(struct psmouse *psmouse); int ps2pp_init(struct psmouse *psmouse, int set_properties);
#endif #endif
...@@ -43,9 +43,9 @@ int psmouse_smartscroll = 1; ...@@ -43,9 +43,9 @@ int psmouse_smartscroll = 1;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0); module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
unsigned int psmouse_resetafter; static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0); module_param_named(resetafter, psmouse_resetafter, uint, 0);
MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never)."); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
__obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_noext");
__obsolete_setup("psmouse_resolution="); __obsolete_setup("psmouse_resolution=");
...@@ -56,15 +56,22 @@ __obsolete_setup("psmouse_rate="); ...@@ -56,15 +56,22 @@ __obsolete_setup("psmouse_rate=");
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
/* /*
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and * psmouse_process_byte() analyzes the PS/2 data stream and reports
* reports relevant events to the input module. * relevant events to the input module once full packet has arrived.
*/ */
static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs) static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{ {
struct input_dev *dev = &psmouse->dev; struct input_dev *dev = &psmouse->dev;
unsigned char *packet = psmouse->packet; unsigned char *packet = psmouse->packet;
if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS))
return PSMOUSE_GOOD_DATA;
/*
* Full packet accumulated, process it
*/
input_regs(dev, regs); input_regs(dev, regs);
/* /*
...@@ -112,6 +119,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs ...@@ -112,6 +119,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
input_sync(dev); input_sync(dev);
return PSMOUSE_FULL_PACKET;
} }
/* /*
...@@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs) unsigned char data, unsigned int flags, struct pt_regs *regs)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
psmouse_ret_t rc;
if (psmouse->state == PSMOUSE_IGNORE) if (psmouse->state == PSMOUSE_IGNORE)
goto out; goto out;
...@@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (psmouse->pktcnt == 2) { if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) { if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE; psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio); serio_reconnect(serio);
goto out; goto out;
} }
if (psmouse->type == PSMOUSE_SYNAPTICS) { if (psmouse->type == PSMOUSE_SYNAPTICS) {
...@@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
} }
} }
if (psmouse->type == PSMOUSE_SYNAPTICS) { rc = psmouse->protocol_handler(psmouse, regs);
/*
* The synaptics driver has its own resync logic, switch (rc) {
* so it needs to receive all bytes one at a time. case PSMOUSE_BAD_DATA:
*/ printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
synaptics_process_byte(psmouse, regs); psmouse->name, psmouse->phys, psmouse->pktcnt);
goto out; psmouse->pktcnt = 0;
if (++psmouse->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->serio);
} }
break;
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) { case PSMOUSE_FULL_PACKET:
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
goto out; if (psmouse->out_of_sync) {
psmouse->out_of_sync = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
}
break;
case PSMOUSE_GOOD_DATA:
break;
} }
out: out:
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -288,6 +311,30 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -288,6 +311,30 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
} }
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
* or Synaptics touchpads. The command is encoded as:
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command.
*/
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
{
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3;
if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
return 0;
}
/* /*
* psmouse_reset() resets the mouse into power-on state. * psmouse_reset() resets the mouse into power-on state.
*/ */
...@@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse)
* the mouse may have. * the mouse may have.
*/ */
static int psmouse_extensions(struct psmouse *psmouse) static int psmouse_extensions(struct psmouse *psmouse,
unsigned int max_proto, int set_properties)
{ {
int synaptics_hardware = 0; int synaptics_hardware = 0;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
/* /*
* Try Synaptics TouchPad * Try Synaptics TouchPad
*/ */
if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) { if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
synaptics_hardware = 1; synaptics_hardware = 1;
if (set_properties) {
psmouse->vendor = "Synaptics"; psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad"; psmouse->name = "TouchPad";
}
if (psmouse_max_proto > PSMOUSE_IMEX) { if (max_proto > PSMOUSE_IMEX) {
if (synaptics_init(psmouse) == 0) if (!set_properties || synaptics_init(psmouse) == 0)
return PSMOUSE_SYNAPTICS; return PSMOUSE_SYNAPTICS;
/* /*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2). * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so * Unfortunately Logitech/Genius probes confuse some firmware versions so
* we'll have to skip them. * we'll have to skip them.
*/ */
psmouse_max_proto = PSMOUSE_IMEX; max_proto = PSMOUSE_IMEX;
} }
/* /*
* Make sure that touchpad is in relative mode, gestures (taps) are enabled * Make sure that touchpad is in relative mode, gestures (taps) are enabled
...@@ -395,35 +442,46 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -395,35 +442,46 @@ static int psmouse_extensions(struct psmouse *psmouse)
synaptics_reset(psmouse); synaptics_reset(psmouse);
} }
if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
if (set_properties) {
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->vendor = "Genius"; psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse"; psmouse->name = "Wheel Mouse";
}
return PSMOUSE_GENPS; return PSMOUSE_GENPS;
} }
if (psmouse_max_proto > PSMOUSE_IMEX) { if (max_proto > PSMOUSE_IMEX) {
int type = ps2pp_detect(psmouse); int type = ps2pp_init(psmouse, set_properties);
if (type) if (type > PSMOUSE_PS2)
return type; return type;
} }
if (psmouse_max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) { if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (psmouse_max_proto >= PSMOUSE_IMEX && if (set_properties) {
im_explorer_detect(psmouse)) { set_bit(REL_WHEEL, psmouse->dev.relbit);
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (!psmouse->name)
psmouse->name = "Explorer Mouse"; psmouse->name = "Explorer Mouse";
}
return PSMOUSE_IMEX; return PSMOUSE_IMEX;
} }
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
if (set_properties) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (!psmouse->name)
psmouse->name = "Wheel Mouse"; psmouse->name = "Wheel Mouse";
}
return PSMOUSE_IMPS; return PSMOUSE_IMPS;
} }
...@@ -473,12 +531,7 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -473,12 +531,7 @@ static int psmouse_probe(struct psmouse *psmouse)
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
/* return 0;
* And here we try to determine if it has any extensions over the
* basic PS/2 3-button mouse.
*/
return psmouse->type = psmouse_extensions(psmouse);
} }
/* /*
...@@ -616,7 +669,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -616,7 +669,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
psmouse->serio = serio; psmouse->serio = serio;
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
...@@ -628,13 +680,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -628,13 +680,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return; return;
} }
if (psmouse_probe(psmouse) <= 0) { if (psmouse_probe(psmouse) < 0) {
serio_close(serio); serio_close(serio);
kfree(psmouse); kfree(psmouse);
serio->private = NULL; serio->private = NULL;
return; return;
} }
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
if (!psmouse->vendor)
psmouse->vendor = "Generic";
if (!psmouse->name)
psmouse->name = "Mouse";
if (!psmouse->protocol_handler)
psmouse->protocol_handler = psmouse_process_byte;
sprintf(psmouse->devname, "%s %s %s", sprintf(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0", sprintf(psmouse->phys, "%s/input0",
...@@ -668,27 +728,24 @@ static int psmouse_reconnect(struct serio *serio) ...@@ -668,27 +728,24 @@ static int psmouse_reconnect(struct serio *serio)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
struct serio_dev *dev = serio->dev; struct serio_dev *dev = serio->dev;
int old_type;
if (!dev || !psmouse) { if (!dev || !psmouse) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
return -1; return -1;
} }
old_type = psmouse->type;
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0; psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
if (psmouse->reconnect) { if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse)) if (psmouse->reconnect(psmouse))
return -1; return -1;
} else if (psmouse_probe(psmouse) != old_type) } else if (psmouse_probe(psmouse) < 0 ||
psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
return -1; return -1;
/* ok, the device type (and capabilities) match the old one, /* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization * we can continue using it, complete intialization
*/ */
psmouse->type = old_type;
psmouse_initialize(psmouse); psmouse_initialize(psmouse);
if (psmouse->ptport) { if (psmouse->ptport) {
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
#define PSMOUSE_ACTIVATED 1 #define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2 #define PSMOUSE_IGNORE 2
/* psmouse protocol handler return codes */
typedef enum {
PSMOUSE_BAD_DATA,
PSMOUSE_GOOD_DATA,
PSMOUSE_FULL_PACKET
} psmouse_ret_t;
struct psmouse; struct psmouse;
struct psmouse_ptport { struct psmouse_ptport {
...@@ -45,6 +52,7 @@ struct psmouse { ...@@ -45,6 +52,7 @@ struct psmouse {
unsigned char type; unsigned char type;
unsigned char model; unsigned char model;
unsigned long last; unsigned long last;
unsigned long out_of_sync;
unsigned char state; unsigned char state;
char acking; char acking;
volatile char ack; volatile char ack;
...@@ -52,6 +60,7 @@ struct psmouse { ...@@ -52,6 +60,7 @@ struct psmouse {
char devname[64]; char devname[64];
char phys[32]; char phys[32];
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse); int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse);
}; };
...@@ -65,10 +74,10 @@ struct psmouse { ...@@ -65,10 +74,10 @@ struct psmouse {
#define PSMOUSE_SYNAPTICS 7 #define PSMOUSE_SYNAPTICS 7
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse); int psmouse_reset(struct psmouse *psmouse);
extern int psmouse_smartscroll; extern int psmouse_smartscroll;
extern unsigned int psmouse_rate; extern unsigned int psmouse_rate;
extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */ #endif /* _PSMOUSE_H */
...@@ -43,34 +43,12 @@ ...@@ -43,34 +43,12 @@
* Synaptics communications functions * Synaptics communications functions
****************************************************************************/ ****************************************************************************/
/*
* Use the Synaptics extended ps/2 syntax to write a special command byte.
* special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
* and synaptics_mode_cmd)
*/
static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
{
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3;
if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
return 0;
}
/* /*
* Send a command to the synpatics touchpad by special commands * Send a command to the synpatics touchpad by special commands
*/ */
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
{ {
if (synaptics_special_cmd(psmouse, c)) if (psmouse_sliced_command(psmouse, c))
return -1; return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
...@@ -84,7 +62,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) ...@@ -84,7 +62,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
{ {
unsigned char param[1]; unsigned char param[1];
if (synaptics_special_cmd(psmouse, mode)) if (psmouse_sliced_command(psmouse, mode))
return -1; return -1;
param[0] = SYN_PS_SET_MODE2; param[0] = SYN_PS_SET_MODE2;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
...@@ -118,17 +96,31 @@ static int synaptics_capability(struct psmouse *psmouse) ...@@ -118,17 +96,31 @@ static int synaptics_capability(struct psmouse *psmouse)
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1; return -1;
priv->capabilities = (cap[0]<<16) | (cap[1]<<8) | cap[2]; priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
priv->ext_cap = 0; priv->ext_cap = 0;
if (!SYN_CAP_VALID(priv->capabilities)) if (!SYN_CAP_VALID(priv->capabilities))
return -1; return -1;
if (SYN_EXT_CAP_REQUESTS(priv->capabilities)) { /*
* 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)) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities," printk(KERN_ERR "Synaptics claims to have extended capabilities,"
" but I'm not able to read them."); " but I'm not able to read them.");
} else } else {
priv->ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2]; 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; return 0;
} }
...@@ -167,11 +159,12 @@ static void print_ident(struct synaptics_data *priv) ...@@ -167,11 +159,12 @@ static void print_ident(struct synaptics_data *priv)
if (SYN_CAP_EXTENDED(priv->capabilities)) { if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n"); printk(KERN_INFO " Touchpad has extended capability bits\n");
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) <= 8)
printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
(int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
else if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) 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"); printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities)) if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n"); printk(KERN_INFO " -> multifinger detection\n");
...@@ -219,21 +212,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) ...@@ -219,21 +212,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode)
/***************************************************************************** /*****************************************************************************
* Synaptics pass-through PS/2 port support * Synaptics pass-through PS/2 port support
****************************************************************************/ ****************************************************************************/
static int synaptics_pt_open(struct serio *port)
{
return 0;
}
static void synaptics_pt_close(struct serio *port)
{
}
static int synaptics_pt_write(struct serio *port, unsigned char c) static int synaptics_pt_write(struct serio *port, unsigned char c)
{ {
struct psmouse *parent = port->driver; struct psmouse *parent = port->driver;
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
if (synaptics_special_cmd(parent, c)) if (psmouse_sliced_command(parent, c))
return -1; return -1;
if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
return -1; return -1;
...@@ -289,165 +273,11 @@ static void synaptics_pt_create(struct psmouse *psmouse) ...@@ -289,165 +273,11 @@ static void synaptics_pt_create(struct psmouse *psmouse)
port->serio.name = "Synaptics pass-through"; port->serio.name = "Synaptics pass-through";
port->serio.phys = "synaptics-pt/serio0"; port->serio.phys = "synaptics-pt/serio0";
port->serio.write = synaptics_pt_write; port->serio.write = synaptics_pt_write;
port->serio.open = synaptics_pt_open;
port->serio.close = synaptics_pt_close;
port->serio.driver = psmouse; port->serio.driver = psmouse;
port->activate = synaptics_pt_activate; port->activate = synaptics_pt_activate;
} }
/*****************************************************************************
* Driver initialization/cleanup functions
****************************************************************************/
static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
set_bit(axis, dev->absbit);
}
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
set_bit(EV_ABS, dev->evbit);
set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(ABS_TOOL_WIDTH, dev->absbit);
set_bit(EV_KEY, dev->evbit);
set_bit(BTN_TOUCH, dev->keybit);
set_bit(BTN_TOOL_FINGER, dev->keybit);
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
set_bit(BTN_LEFT, dev->keybit);
set_bit(BTN_RIGHT, dev->keybit);
set_bit(BTN_FORWARD, dev->keybit);
set_bit(BTN_BACK, dev->keybit);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
/*
* if nExtBtn is greater than 8 it should be considered
* invalid and treated as 0
*/
break;
case 8:
set_bit(BTN_7, dev->keybit);
set_bit(BTN_6, dev->keybit);
case 6:
set_bit(BTN_5, dev->keybit);
set_bit(BTN_4, dev->keybit);
case 4:
set_bit(BTN_3, dev->keybit);
set_bit(BTN_2, dev->keybit);
case 2:
set_bit(BTN_1, dev->keybit);
set_bit(BTN_0, dev->keybit);
break;
}
}
clear_bit(EV_REL, dev->evbit);
clear_bit(REL_X, dev->relbit);
clear_bit(REL_Y, dev->relbit);
}
void synaptics_reset(struct psmouse *psmouse)
{
/* reset touchpad back to relative mode, gestures enabled */
synaptics_mode_cmd(psmouse, 0);
}
static void synaptics_disconnect(struct psmouse *psmouse)
{
synaptics_reset(psmouse);
kfree(psmouse->private);
}
static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
if (!synaptics_detect(psmouse))
return -1;
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
return -1;
}
if (old_priv.identity != priv->identity ||
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
old_priv.ext_cap != priv->ext_cap)
return -1;
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
return -1;
}
return 0;
}
int synaptics_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47;
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
goto init_fail;
}
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
goto init_fail;
}
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse);
print_ident(priv);
set_input_params(&psmouse->dev, priv);
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
return 0;
init_fail:
kfree(priv);
return -1;
}
/***************************************************************************** /*****************************************************************************
* Functions to interpret the absolute mode packets * Functions to interpret the absolute mode packets
****************************************************************************/ ****************************************************************************/
...@@ -471,17 +301,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -471,17 +301,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0; hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0;
if (SYN_CAP_EXTENDED(priv->capabilities) &&
(SYN_CAP_FOUR_BUTTON(priv->capabilities))) { if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
hw->up = ((buf[3] & 0x01)) ? 1 : 0; hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->left)
hw->up = !hw->up; if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
hw->down = ((buf[3] & 0x02)) ? 1 : 0; hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->right) hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
hw->down = !hw->down;
} }
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
((buf[3] & 2) ? !hw->right : hw->right)) { ((buf[0] ^ buf[3]) & 0x02)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default: default:
/* /*
...@@ -490,17 +320,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -490,17 +320,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
*/ */
break; break;
case 8: case 8:
hw->b7 = ((buf[5] & 0x08)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
hw->b6 = ((buf[4] & 0x08)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
case 6: case 6:
hw->b5 = ((buf[5] & 0x04)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
hw->b4 = ((buf[4] & 0x04)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
case 4: case 4:
hw->b3 = ((buf[5] & 0x02)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
hw->b2 = ((buf[4] & 0x02)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
case 2: case 2:
hw->b1 = ((buf[5] & 0x01)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
hw->b0 = ((buf[4] & 0x01)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
} }
} }
} else { } else {
...@@ -525,6 +355,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -525,6 +355,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
struct synaptics_hw_state hw; struct synaptics_hw_state hw;
int num_fingers; int num_fingers;
int finger_width; int finger_width;
int i;
synaptics_parse_hw_state(psmouse->packet, priv, &hw); synaptics_parse_hw_state(psmouse->packet, priv, &hw);
...@@ -572,30 +403,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -572,30 +403,18 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_report_key(dev, BTN_LEFT, hw.left); input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right); input_report_key(dev, BTN_RIGHT, hw.right);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
input_report_key(dev, BTN_MIDDLE, hw.middle);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
input_report_key(dev, BTN_FORWARD, hw.up); input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down); input_report_key(dev, BTN_BACK, hw.down);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
/*
* if nExtBtn is greater than 8 it should be considered
* invalid and treated as 0
*/
break;
case 8:
input_report_key(dev, BTN_7, hw.b7);
input_report_key(dev, BTN_6, hw.b6);
case 6:
input_report_key(dev, BTN_5, hw.b5);
input_report_key(dev, BTN_4, hw.b4);
case 4:
input_report_key(dev, BTN_3, hw.b3);
input_report_key(dev, BTN_2, hw.b2);
case 2:
input_report_key(dev, BTN_1, hw.b1);
input_report_key(dev, BTN_0, hw.b0);
break;
} }
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
input_sync(dev); input_sync(dev);
} }
...@@ -607,6 +426,9 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha ...@@ -607,6 +426,9 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
if (idx < 0 || idx > 4)
return 0;
switch (pkt_type) { switch (pkt_type) {
case SYN_NEWABS: case SYN_NEWABS:
case SYN_NEWABS_RELAXED: case SYN_NEWABS_RELAXED:
...@@ -637,7 +459,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) ...@@ -637,7 +459,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
return SYN_NEWABS_STRICT; return SYN_NEWABS_STRICT;
} }
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{ {
struct input_dev *dev = &psmouse->dev; struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private; struct synaptics_data *priv = psmouse->private;
...@@ -645,11 +467,6 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -645,11 +467,6 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
input_regs(dev, regs); input_regs(dev, regs);
if (psmouse->pktcnt >= 6) { /* Full packet received */ if (psmouse->pktcnt >= 6) { /* Full packet received */
if (priv->out_of_sync) {
priv->out_of_sync = 0;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
}
if (unlikely(priv->pkt_type == SYN_NEWABS)) if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse); priv->pkt_type = synaptics_detect_pkt_type(psmouse);
...@@ -657,16 +474,142 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -657,16 +474,142 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
else else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
psmouse->pktcnt = 0;
return PSMOUSE_FULL_PACKET;
} else if (psmouse->pktcnt && }
!synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
psmouse->pktcnt = 0; PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
if (++priv->out_of_sync == psmouse_resetafter) { }
psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "synaptics: issuing reconnect request\n"); /*****************************************************************************
serio_reconnect(psmouse->serio); * Driver initialization/cleanup functions
****************************************************************************/
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(ABS_TOOL_WIDTH, dev->absbit);
set_bit(EV_KEY, dev->evbit);
set_bit(BTN_TOUCH, dev->keybit);
set_bit(BTN_TOOL_FINGER, dev->keybit);
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
set_bit(BTN_LEFT, dev->keybit);
set_bit(BTN_RIGHT, dev->keybit);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
set_bit(BTN_MIDDLE, dev->keybit);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
set_bit(BTN_FORWARD, dev->keybit);
set_bit(BTN_BACK, dev->keybit);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
set_bit(BTN_0 + i, dev->keybit);
clear_bit(EV_REL, dev->evbit);
clear_bit(REL_X, dev->relbit);
clear_bit(REL_Y, dev->relbit);
}
void synaptics_reset(struct psmouse *psmouse)
{
/* reset touchpad back to relative mode, gestures enabled */
synaptics_mode_cmd(psmouse, 0);
}
static void synaptics_disconnect(struct psmouse *psmouse)
{
synaptics_reset(psmouse);
kfree(psmouse->private);
}
static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
if (!synaptics_detect(psmouse))
return -1;
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
return -1;
}
if (old_priv.identity != priv->identity ||
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
old_priv.ext_cap != priv->ext_cap)
return -1;
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
return -1;
}
return 0;
}
int synaptics_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47;
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
goto init_fail;
} }
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
goto init_fail;
} }
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse);
print_ident(priv);
set_input_params(&psmouse->dev, priv);
psmouse->protocol_handler = synaptics_process_byte;
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
return 0;
init_fail:
kfree(priv);
return -1;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#ifndef _SYNAPTICS_H #ifndef _SYNAPTICS_H
#define _SYNAPTICS_H #define _SYNAPTICS_H
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_detect(struct psmouse *psmouse); extern int synaptics_detect(struct psmouse *psmouse);
extern int synaptics_init(struct psmouse *psmouse); extern int synaptics_init(struct psmouse *psmouse);
extern void synaptics_reset(struct psmouse *psmouse); extern void synaptics_reset(struct psmouse *psmouse);
...@@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse); ...@@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse);
/* synaptics capability bits */ /* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) #define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18))
#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) #define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) #define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */ /* synaptics modes query bits */
...@@ -86,18 +86,12 @@ struct synaptics_hw_state { ...@@ -86,18 +86,12 @@ struct synaptics_hw_state {
int y; int y;
int z; int z;
int w; int w;
int left; unsigned int left:1;
int right; unsigned int right:1;
int up; unsigned int middle:1;
int down; unsigned int up:1;
int b0; unsigned int down:1;
int b1; unsigned char ext_buttons;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
}; };
struct synaptics_data { struct synaptics_data {
...@@ -108,7 +102,6 @@ struct synaptics_data { ...@@ -108,7 +102,6 @@ struct synaptics_data {
unsigned long int identity; /* Identification */ unsigned long int identity; /* Identification */
/* Data for normal processing */ /* Data for normal processing */
unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */ int old_w; /* Previous w value */
unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char pkt_type; /* packet type - old, new, etc */
}; };
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Input driver to ExplorerPS/2 device driver module. * Input driver to ExplorerPS/2 device driver module.
* *
* Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as published by
...@@ -47,15 +48,24 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; ...@@ -47,15 +48,24 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0); module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution"); MODULE_PARM_DESC(yres, "Vertical screen resolution");
struct mousedev_motion {
int dx, dy, dz;
};
struct mousedev { struct mousedev {
int exist; int exist;
int open; int open;
int minor; int minor;
int misc;
char name[16]; char name[16];
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
struct input_handle handle; struct input_handle handle;
struct mousedev_motion packet;
unsigned long buttons;
unsigned int pkt_count;
int old_x[4], old_y[4];
unsigned int touch;
}; };
struct mousedev_list { struct mousedev_list {
...@@ -63,13 +73,10 @@ struct mousedev_list { ...@@ -63,13 +73,10 @@ struct mousedev_list {
struct mousedev *mousedev; struct mousedev *mousedev;
struct list_head node; struct list_head node;
int dx, dy, dz; int dx, dy, dz;
int old_x[4], old_y[4];
unsigned long buttons; unsigned long buttons;
signed char ps2[6]; signed char ps2[6];
unsigned char ready, buffer, bufsiz; unsigned char ready, buffer, bufsiz;
unsigned char mode, imexseq, impsseq; unsigned char mode, imexseq, impsseq;
unsigned int pkt_count;
unsigned char touch;
}; };
#define MOUSEDEV_SEQ_LEN 6 #define MOUSEDEV_SEQ_LEN 6
...@@ -82,135 +89,157 @@ static struct input_handler mousedev_handler; ...@@ -82,135 +89,157 @@ static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct mousedev mousedev_mix; static struct mousedev mousedev_mix;
#define fx(i) (list->old_x[(list->pkt_count - (i)) & 03]) #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (list->old_y[(list->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value) static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
{ {
int size; if (mousedev->touch) {
int touchpad;
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit);
switch (code) { switch (code) {
case ABS_X: case ABS_X:
if (touchpad) {
if (list->touch) {
fx(0) = value; fx(0) = value;
if (list->pkt_count >= 2) if (mousedev->pkt_count >= 2)
list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
if (size == 0) size = xres;
list->dx += (value * xres - list->old_x[0]) / size;
list->old_x[0] += list->dx * size;
}
break; break;
case ABS_Y: case ABS_Y:
if (touchpad) {
if (list->touch) {
fy(0) = value; fy(0) = value;
if (list->pkt_count >= 2) if (mousedev->pkt_count >= 2)
list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
if (size == 0) size = yres;
list->dy -= (value * yres - list->old_y[0]) / size;
list->old_y[0] -= list->dy * size;
}
break; break;
} }
}
} }
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
{ {
struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; int size;
struct mousedev **mousedev = mousedevs;
struct mousedev_list *list;
int index, wake;
while (*mousedev) {
wake = 0; switch (code) {
case ABS_X:
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
if (size == 0) size = xres;
mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size;
mousedev->old_x[0] = mousedev->packet.dx * size;
break;
list_for_each_entry(list, &(*mousedev)->list, node) case ABS_Y:
switch (type) { size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
case EV_ABS: if (size == 0) size = yres;
mousedev_abs_event(handle, list, code, value); mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size;
mousedev->old_y[0] = mousedev->packet.dy * size;
break; break;
}
}
case EV_REL: static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
switch (code) { switch (code) {
case REL_X: list->dx += value; break; case REL_X: mousedev->packet.dx += value; break;
case REL_Y: list->dy -= value; break; case REL_Y: mousedev->packet.dy -= value; break;
case REL_WHEEL: if (list->mode) list->dz -= value; break; case REL_WHEEL: mousedev->packet.dz -= value; break;
} }
break; }
case EV_KEY: static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { {
/* Handle touchpad data */ int index;
list->touch = value;
if (!list->touch)
list->pkt_count = 0;
break;
}
switch (code) { switch (code) {
case BTN_TOUCH: case BTN_TOUCH:
case BTN_0: case BTN_0:
case BTN_FORWARD: case BTN_FORWARD:
case BTN_LEFT: index = 0; break; case BTN_LEFT: index = 0; break;
case BTN_4:
case BTN_EXTRA: if (list->mode == 2) { index = 4; break; }
case BTN_STYLUS: case BTN_STYLUS:
case BTN_1: case BTN_1:
case BTN_RIGHT: index = 1; break; case BTN_RIGHT: index = 1; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: if (list->mode == 2) { index = 3; break; }
case BTN_2: case BTN_2:
case BTN_STYLUS2: case BTN_STYLUS2:
case BTN_MIDDLE: index = 2; break; case BTN_MIDDLE: index = 2; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: index = 3; break;
case BTN_4:
case BTN_EXTRA: index = 4; break;
default: return; default: return;
} }
switch (value) {
case 0: clear_bit(index, &list->buttons); break;
case 1: set_bit(index, &list->buttons); break;
case 2: return;
}
break;
case EV_SYN: if (value) {
switch (code) { set_bit(index, &mousedev->buttons);
case SYN_REPORT: set_bit(index, &mousedev_mix.buttons);
if (list->touch) { } else {
list->pkt_count++; clear_bit(index, &mousedev->buttons);
/* Input system eats duplicate events, clear_bit(index, &mousedev_mix.buttons);
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
} }
}
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{
struct mousedev_list *list;
list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx;
list->dy += packet->dy;
list->dz += packet->dz;
list->buttons = mousedev->buttons;
list->ready = 1; list->ready = 1;
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
wake = 1; }
wake_up_interruptible(&mousedev->wait);
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
case EV_ABS:
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_event(mousedev, code, value);
else
mousedev_abs_event(handle->dev, mousedev, code, value);
break; break;
case EV_REL:
mousedev_rel_event(mousedev, code, value);
break;
case EV_KEY:
if (value != 2) {
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
/* Handle touchpad data */
mousedev->touch = value;
if (!mousedev->touch)
mousedev->pkt_count = 0;
} }
else
mousedev_key_event(mousedev, code, value);
}
break;
case EV_SYN:
if (code == SYN_REPORT) {
if (mousedev->touch) {
mousedev->pkt_count++;
/* Input system eats duplicate events, but we need all of them
* to do correct averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
} }
if (wake) mousedev_notify_readers(mousedev, &mousedev->packet);
wake_up_interruptible(&((*mousedev)->wait)); mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
mousedev++; memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
}
break;
} }
} }
...@@ -326,6 +355,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off) ...@@ -326,6 +355,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off)
list->dz -= list->ps2[off + 3]; list->dz -= list->ps2[off + 3];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++; list->bufsiz++;
} else {
list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1);
} }
if (list->mode == 1) { if (list->mode == 1) {
...@@ -391,9 +422,9 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -391,9 +422,9 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
list->impsseq = 0; list->impsseq = 0;
list->imexseq = 0; list->imexseq = 0;
list->mode = 0; list->mode = 0;
list->ps2[0] = 0xaa; list->ps2[1] = 0xaa;
list->ps2[1] = 0x00; list->ps2[2] = 0x00;
list->bufsiz = 2; list->bufsiz = 3;
break; break;
} }
...@@ -553,6 +584,7 @@ static struct input_handler mousedev_handler = { ...@@ -553,6 +584,7 @@ static struct input_handler mousedev_handler = {
static struct miscdevice psaux_mouse = { static struct miscdevice psaux_mouse = {
PSMOUSE_MINOR, "psaux", &mousedev_fops PSMOUSE_MINOR, "psaux", &mousedev_fops
}; };
static int psaux_registered;
#endif #endif
static int __init mousedev_init(void) static int __init mousedev_init(void)
...@@ -572,7 +604,7 @@ static int __init mousedev_init(void) ...@@ -572,7 +604,7 @@ static int __init mousedev_init(void)
NULL, "mice"); NULL, "mice");
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(mousedev_mix.misc = !misc_register(&psaux_mouse))) if (!(psaux_registered = !misc_register(&psaux_mouse)))
printk(KERN_WARNING "mice: could not misc_register the device\n"); printk(KERN_WARNING "mice: could not misc_register the device\n");
#endif #endif
...@@ -584,7 +616,7 @@ static int __init mousedev_init(void) ...@@ -584,7 +616,7 @@ static int __init mousedev_init(void)
static void __exit mousedev_exit(void) static void __exit mousedev_exit(void)
{ {
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (mousedev_mix.misc) if (psaux_registered)
misc_deregister(&psaux_mouse); misc_deregister(&psaux_mouse);
#endif #endif
devfs_remove("input/mice"); devfs_remove("input/mice");
......
...@@ -172,3 +172,4 @@ module_exit(power_exit); ...@@ -172,3 +172,4 @@ module_exit(power_exit);
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input Power Management driver"); MODULE_DESCRIPTION("Input Power Management driver");
MODULE_LICENSE("GPL");
...@@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED; ...@@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED;
static struct serio kbd98_port; static struct serio kbd98_port;
extern struct pt_regs *kbd_pt_regs; extern struct pt_regs *kbd_pt_regs;
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/* /*
* kbd98_flush() flushes all data that may be in the keyboard buffers * kbd98_flush() flushes all data that may be in the keyboard buffers
...@@ -143,7 +143,7 @@ static struct serio kbd98_port = ...@@ -143,7 +143,7 @@ static struct serio kbd98_port =
* to the upper layers. * to the upper layers.
*/ */
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
unsigned char data; unsigned char data;
...@@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&kbd98io_lock, flags); spin_unlock_irqrestore(&kbd98io_lock, flags);
serio_interrupt(&kbd98_port, data, 0, regs); serio_interrupt(&kbd98_port, data, 0, regs);
return IRQ_HANDLED;
} }
int __init kbd98io_init(void) int __init kbd98io_init(void)
......
...@@ -474,8 +474,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux ...@@ -474,8 +474,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9) if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1; return -1;
param = 0xa4; param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) {
/*
* Do another loop test with the 0x5a value. Doing anything else upsets
* Profusion/ServerWorks OSB4 chipsets.
*/
param = 0x5a;
i8042_command(&param, I8042_CMD_AUX_LOOP);
return -1; return -1;
}
if (mux_version) if (mux_version)
*mux_version = ~param; *mux_version = ~param;
...@@ -532,8 +541,8 @@ static int __init i8042_check_mux(struct i8042_values *values) ...@@ -532,8 +541,8 @@ static int __init i8042_check_mux(struct i8042_values *values)
return -1; return -1;
/* Workaround for broken chips which seem to support MUX, but in reality don't. */ /* Workaround for broken chips which seem to support MUX, but in reality don't. */
/* They all report version 12.10 */ /* They all report version 10.12 */
if (mux_version == 0xCA) if (mux_version == 0xAC)
return -1; return -1;
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
...@@ -868,7 +877,7 @@ static int i8042_controller_resume(void) ...@@ -868,7 +877,7 @@ static int i8042_controller_resume(void)
static int i8042_notify_sys(struct notifier_block *this, unsigned long code, static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
i8042_controller_cleanup(); i8042_controller_cleanup();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -997,8 +1006,6 @@ void __exit i8042_exit(void) ...@@ -997,8 +1006,6 @@ void __exit i8042_exit(void)
sysdev_class_unregister(&kbc_sysclass); sysdev_class_unregister(&kbc_sysclass);
} }
del_timer_sync(&i8042_timer);
i8042_controller_cleanup(); i8042_controller_cleanup();
if (i8042_kbd_values.exists) if (i8042_kbd_values.exists)
...@@ -1010,6 +1017,7 @@ void __exit i8042_exit(void) ...@@ -1010,6 +1017,7 @@ void __exit i8042_exit(void)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists) if (i8042_mux_values[i].exists)
serio_unregister_port(i8042_mux_port + i); serio_unregister_port(i8042_mux_port + i);
del_timer_sync(&i8042_timer);
i8042_platform_exit(); i8042_platform_exit();
} }
......
...@@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c) ...@@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0; return 0;
} }
static int parkbd_open(struct serio *port)
{
return 0;
}
static void parkbd_close(struct serio *port)
{
}
static struct serio parkbd_port = static struct serio parkbd_port =
{ {
.write = parkbd_write, .write = parkbd_write,
.open = parkbd_open,
.close = parkbd_close,
.name = parkbd_name, .name = parkbd_name,
.phys = parkbd_phys, .phys = parkbd_phys,
}; };
......
...@@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int q40kbd_open(struct serio *port)
{
return 0;
}
static void q40kbd_close(struct serio *port)
{
}
static struct serio q40kbd_port = static struct serio q40kbd_port =
{ {
.type = SERIO_8042, .type = SERIO_8042,
.name = "Q40 kbd port", .name = "Q40 kbd port",
.phys = "Q40", .phys = "Q40",
.write = NULL, .write = NULL,
.open = q40kbd_open,
.close = q40kbd_close,
}; };
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, static irqreturn_t q40kbd_interrupt(int irq, void *dev_id,
......
...@@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev) ...@@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev)
int serio_open(struct serio *serio, struct serio_dev *dev) int serio_open(struct serio *serio, struct serio_dev *dev)
{ {
serio->dev = dev; serio->dev = dev;
if (serio->open(serio)) { if (serio->open && serio->open(serio)) {
serio->dev = NULL; serio->dev = NULL;
return -1; return -1;
} }
...@@ -303,6 +303,7 @@ int serio_open(struct serio *serio, struct serio_dev *dev) ...@@ -303,6 +303,7 @@ int serio_open(struct serio *serio, struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio) void serio_close(struct serio *serio)
{ {
if (serio->close)
serio->close(serio); serio->close(serio);
serio->dev = NULL; serio->dev = NULL;
} }
......
...@@ -48,11 +48,6 @@ static int serport_serio_write(struct serio *serio, unsigned char data) ...@@ -48,11 +48,6 @@ static int serport_serio_write(struct serio *serio, unsigned char data)
return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
} }
static int serport_serio_open(struct serio *serio)
{
return 0;
}
static void serport_serio_close(struct serio *serio) static void serport_serio_close(struct serio *serio)
{ {
struct serport *serport = serio->driver; struct serport *serport = serio->driver;
...@@ -87,7 +82,6 @@ static int serport_ldisc_open(struct tty_struct *tty) ...@@ -87,7 +82,6 @@ static int serport_ldisc_open(struct tty_struct *tty)
serport->serio.type = SERIO_RS232; serport->serio.type = SERIO_RS232;
serport->serio.write = serport_serio_write; serport->serio.write = serport_serio_write;
serport->serio.open = serport_serio_open;
serport->serio.close = serport_serio_close; serport->serio.close = serport_serio_close;
serport->serio.driver = serport; serport->serio.driver = serport;
......
...@@ -125,11 +125,9 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) ...@@ -125,11 +125,9 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&gunze->dev); init_input_dev(&gunze->dev);
gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72; input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
gunze->serio = serio; gunze->serio = serio;
serio->private = gunze; serio->private = gunze;
......
...@@ -45,6 +45,10 @@ ...@@ -45,6 +45,10 @@
#include <asm/arch/hardware.h> #include <asm/arch/hardware.h>
#include <asm/arch/irqs.h> #include <asm/arch/irqs.h>
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("H3600 touchscreen driver");
MODULE_LICENSE("GPL");
/* /*
* Definitions & global arrays. * Definitions & global arrays.
*/ */
...@@ -103,7 +107,7 @@ struct h3600_dev { ...@@ -103,7 +107,7 @@ struct h3600_dev {
char phys[32]; char phys[32];
}; };
static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{ {
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id; struct input_dev *dev = (struct input_dev *) dev_id;
...@@ -111,9 +115,11 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -111,9 +115,11 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_regs(dev, regs); input_regs(dev, regs);
input_report_key(dev, KEY_ENTER, down); input_report_key(dev, KEY_ENTER, down);
input_sync(dev); input_sync(dev);
return IRQ_HANDLED;
} }
static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{ {
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id; struct input_dev *dev = (struct input_dev *) dev_id;
...@@ -126,6 +132,8 @@ static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -126,6 +132,8 @@ static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_report_key(dev, KEY_SUSPEND, 1); input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down); input_report_key(dev, KEY_SUSPEND, down);
input_sync(dev); input_sync(dev);
return IRQ_HANDLED;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -141,7 +149,7 @@ enum flite_pwr { ...@@ -141,7 +149,7 @@ enum flite_pwr {
* h3600_flite_power: enables or disables power to frontlight, using last bright */ * h3600_flite_power: enables or disables power to frontlight, using last bright */
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{ {
unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness); unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
struct h3600_dev *ts = dev->private; struct h3600_dev *ts = dev->private;
/* Must be in this order */ /* Must be in this order */
...@@ -317,8 +325,8 @@ static int state; ...@@ -317,8 +325,8 @@ static int state;
#define STATE_DATA 2 /* state where we decode data */ #define STATE_DATA 2 /* state where we decode data */
#define STATE_EOF 3 /* state where we decode checksum or EOF */ #define STATE_EOF 3 /* state where we decode checksum or EOF */
static void h3600ts_interrupt(struct serio *serio, unsigned char data, static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags) unsigned int flags, struct pt_regs *regs)
{ {
struct h3600_dev *ts = serio->private; struct h3600_dev *ts = serio->private;
...@@ -329,7 +337,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -329,7 +337,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
case STATE_SOF: case STATE_SOF:
if (data == CHAR_SOF) if (data == CHAR_SOF)
state = STATE_ID; state = STATE_ID;
return; break;
case STATE_ID: case STATE_ID:
ts->event = (data & 0xf0) >> 4; ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf); ts->len = (data & 0xf);
...@@ -339,7 +347,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -339,7 +347,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break; break;
} }
ts->chksum = data; ts->chksum = data;
state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF; state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break; break;
case STATE_DATA: case STATE_DATA:
ts->chksum += data; ts->chksum += data;
...@@ -349,13 +357,15 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -349,13 +357,15 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break; break;
case STATE_EOF: case STATE_EOF:
state = STATE_SOF; state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum ) if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts); h3600ts_process_packet(ts, regs);
break; break;
default: default:
printk("Error3\n"); printk("Error3\n");
break; break;
} }
return IRQ_HANDLED;
} }
/* /*
...@@ -378,8 +388,8 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -378,8 +388,8 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&ts->dev); init_input_dev(&ts->dev);
/* Device specific stuff */ /* Device specific stuff */
set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES ); set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE ); set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
...@@ -397,17 +407,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -397,17 +407,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
kfree(ts); kfree(ts);
return; return;
} }
/* Now we have things going we setup our input device */ /* Now we have things going we setup our input device */
ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
ts->dev.ledbit[0] = BIT(LED_SLEEP); ts->dev.ledbit[0] = BIT(LED_SLEEP);
input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0);
ts->dev.absmin[ABS_X] = 60; ts->dev.absmin[ABS_Y] = 35; input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0);
ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024;
ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0;
ts->serio = serio;
serio->private = ts;
set_bit(KEY_RECORD, ts->dev.keybit); set_bit(KEY_RECORD, ts->dev.keybit);
set_bit(KEY_Q, ts->dev.keybit); set_bit(KEY_Q, ts->dev.keybit);
...@@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
ts->serio = serio;
serio->private = ts;
sprintf(ts->phys, "%s/input0", serio->phys); sprintf(ts->phys, "%s/input0", serio->phys);
ts->dev.event = h3600ts_event; ts->dev.event = h3600ts_event;
......
...@@ -122,6 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, ...@@ -122,6 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
cmap.red = &red; cmap.red = &red;
cmap.green = &green; cmap.green = &green;
cmap.blue = &blue; cmap.blue = &blue;
cmap.transp = NULL;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
int err; int err;
......
...@@ -291,17 +291,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr) ...@@ -291,17 +291,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr)
* about to change to user space. This is the same method as used on SPARC64. * about to change to user space. This is the same method as used on SPARC64.
* See update_mmu_cache for the user space part. * See update_mmu_cache for the user space part.
*/ */
extern void __flush_dcache_page(struct page *); extern void flush_dcache_page(struct page *);
static inline void flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping(page);
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
else
__flush_dcache_page(page);
}
#define flush_dcache_mmap_lock(mapping) \ #define flush_dcache_mmap_lock(mapping) \
spin_lock_irq(&(mapping)->tree_lock) spin_lock_irq(&(mapping)->tree_lock)
......
...@@ -555,8 +555,12 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) ...@@ -555,8 +555,12 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW); (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
pte_update(ptep, 0, bits); pte_update(ptep, 0, bits);
} }
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
__ptep_set_access_flags(__ptep, __entry, __dirty) do { \
__ptep_set_access_flags(__ptep, __entry, __dirty); \
flush_tlb_page_nohash(__vma, __address); \
} while(0)
/* /*
* Macro to mark a page protection value as "uncacheable". * Macro to mark a page protection value as "uncacheable".
......
...@@ -29,6 +29,9 @@ static inline void flush_tlb_mm(struct mm_struct *mm) ...@@ -29,6 +29,9 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma, static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr) unsigned long vmaddr)
{ _tlbie(vmaddr); } { _tlbie(vmaddr); }
static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
unsigned long vmaddr)
{ _tlbie(vmaddr); }
static inline void flush_tlb_range(struct vm_area_struct *vma, static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ __tlbia(); } { __tlbia(); }
...@@ -44,6 +47,9 @@ static inline void flush_tlb_mm(struct mm_struct *mm) ...@@ -44,6 +47,9 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma, static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr) unsigned long vmaddr)
{ _tlbie(vmaddr); } { _tlbie(vmaddr); }
static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
unsigned long vmaddr)
{ _tlbie(vmaddr); }
static inline void flush_tlb_range(struct mm_struct *mm, static inline void flush_tlb_range(struct mm_struct *mm,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ __tlbia(); } { __tlbia(); }
...@@ -56,6 +62,7 @@ struct mm_struct; ...@@ -56,6 +62,7 @@ struct mm_struct;
struct vm_area_struct; struct vm_area_struct;
extern void flush_tlb_mm(struct mm_struct *mm); extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end); unsigned long end);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
......
...@@ -428,7 +428,10 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) ...@@ -428,7 +428,10 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
:"cc"); :"cc");
} }
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
__ptep_set_access_flags(__ptep, __entry, __dirty) do { \
__ptep_set_access_flags(__ptep, __entry, __dirty); \
flush_tlb_page_nohash(__vma, __address); \
} while(0)
/* /*
* Macro to mark a page protection value as "uncacheable". * Macro to mark a page protection value as "uncacheable".
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* *
* - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page * - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB
* - flush_tlb_range(vma, start, end) flushes a range of pages * - flush_tlb_range(vma, start, end) flushes a range of pages
* - flush_tlb_kernel_range(start, end) flushes a range of kernel pages * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
* - flush_tlb_pgtables(mm, start, end) flushes a range of page tables * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
...@@ -39,6 +40,7 @@ static inline void flush_tlb_pending(void) ...@@ -39,6 +40,7 @@ static inline void flush_tlb_pending(void)
#define flush_tlb_mm(mm) flush_tlb_pending() #define flush_tlb_mm(mm) flush_tlb_pending()
#define flush_tlb_page(vma, addr) flush_tlb_pending() #define flush_tlb_page(vma, addr) flush_tlb_pending()
#define flush_tlb_page_nohash(vma, addr) do { } while (0)
#define flush_tlb_range(vma, start, end) \ #define flush_tlb_range(vma, start, end) \
do { (void)(start); flush_tlb_pending(); } while (0) do { (void)(start); flush_tlb_pending(); } while (0)
#define flush_tlb_kernel_range(start, end) flush_tlb_pending() #define flush_tlb_kernel_range(start, end) flush_tlb_pending()
......
...@@ -749,8 +749,6 @@ struct ff_effect { ...@@ -749,8 +749,6 @@ struct ff_effect {
#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \ #define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode]))) ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
#define init_input_dev(dev) do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0)
#define SET_INPUT_KEYCODE(dev, scancode, val) \ #define SET_INPUT_KEYCODE(dev, scancode, val) \
({ unsigned __old; \ ({ unsigned __old; \
switch (dev->keycodesize) { \ switch (dev->keycodesize) { \
...@@ -915,6 +913,12 @@ struct input_handle { ...@@ -915,6 +913,12 @@ struct input_handle {
#define to_handle(n) container_of(n,struct input_handle,d_node) #define to_handle(n) container_of(n,struct input_handle,d_node)
#define to_handle_h(n) container_of(n,struct input_handle,h_node) #define to_handle_h(n) container_of(n,struct input_handle,h_node)
static inline void init_input_dev(struct input_dev *dev)
{
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
}
void input_register_device(struct input_dev *); void input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *); void input_unregister_device(struct input_dev *);
...@@ -932,14 +936,51 @@ int input_flush_device(struct input_handle* handle, struct file* file); ...@@ -932,14 +936,51 @@ int input_flush_device(struct input_handle* handle, struct file* file);
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) {
#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) input_event(dev, EV_KEY, code, !!value);
#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) }
#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c)
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
#define input_regs(a,b) do { (a)->regs = (b); } while (0) {
#define input_sync(a) do { input_event(a, EV_SYN, SYN_REPORT, 0); (a)->regs = NULL; } while (0) input_event(dev, EV_REL, code, value);
}
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF, code, value);
}
static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
}
static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
{
dev->regs = regs;
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
dev->regs = NULL;
}
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
dev->absbit[LONG(axis)] |= BIT(axis);
}
extern struct class_simple *input_class; extern struct class_simple *input_class;
......
...@@ -171,6 +171,12 @@ extern void nf_reinject(struct sk_buff *skb, ...@@ -171,6 +171,12 @@ extern void nf_reinject(struct sk_buff *skb,
struct nf_info *info, struct nf_info *info,
unsigned int verdict); unsigned int verdict);
extern inline struct ipt_target *
ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern inline struct ip6t_target *
ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern inline struct arpt_target *
arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *); extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
......
...@@ -17,4 +17,5 @@ ...@@ -17,4 +17,5 @@
#define NF_ARP_FORWARD 2 #define NF_ARP_FORWARD 2
#define NF_ARP_NUMHOOKS 3 #define NF_ARP_NUMHOOKS 3
static DECLARE_MUTEX(arpt_mutex);
#endif /* __LINUX_ARP_NETFILTER_H */ #endif /* __LINUX_ARP_NETFILTER_H */
...@@ -283,6 +283,8 @@ struct ipt_get_entries ...@@ -283,6 +283,8 @@ struct ipt_get_entries
struct ipt_entry entrytable[0]; struct ipt_entry entrytable[0];
}; };
extern struct semaphore ipt_mutex;
/* Standard return verdict, or do jump. */ /* Standard return verdict, or do jump. */
#define IPT_STANDARD_TARGET "" #define IPT_STANDARD_TARGET ""
/* Error verdict. */ /* Error verdict. */
...@@ -334,6 +336,7 @@ ipt_get_target(struct ipt_entry *e) ...@@ -334,6 +336,7 @@ ipt_get_target(struct ipt_entry *e)
/* /*
* Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions.
*/ */
static DECLARE_MUTEX(ipt_mutex);
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/init.h> #include <linux/init.h>
...@@ -406,6 +409,11 @@ struct ipt_target ...@@ -406,6 +409,11 @@ struct ipt_target
struct module *me; struct module *me;
}; };
extern struct ipt_target *
ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern struct arpt_target *
arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern int ipt_register_target(struct ipt_target *target); extern int ipt_register_target(struct ipt_target *target);
extern void ipt_unregister_target(struct ipt_target *target); extern void ipt_unregister_target(struct ipt_target *target);
......
...@@ -106,6 +106,8 @@ struct ip6t_counters ...@@ -106,6 +106,8 @@ struct ip6t_counters
u_int64_t pcnt, bcnt; /* Packet and byte counters */ u_int64_t pcnt, bcnt; /* Packet and byte counters */
}; };
static DECLARE_MUTEX(ip6t_mutex);
/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */ /* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
#define IP6T_F_PROTO 0x01 /* Set if rule cares about upper #define IP6T_F_PROTO 0x01 /* Set if rule cares about upper
protocols */ protocols */
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define _LINUX_WATCHDOG_H #define _LINUX_WATCHDOG_H
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/types.h>
#define WATCHDOG_IOCTL_BASE 'W' #define WATCHDOG_IOCTL_BASE 'W'
......
...@@ -970,6 +970,9 @@ extern int tcp_sync_mss(struct sock *sk, u32 pmtu); ...@@ -970,6 +970,9 @@ extern int tcp_sync_mss(struct sock *sk, u32 pmtu);
extern const char timer_bug_msg[]; extern const char timer_bug_msg[];
/* tcp_diag.c */
extern void tcp_get_info(struct sock *, struct tcp_info *);
/* Read 'sendfile()'-style from a TCP socket */ /* Read 'sendfile()'-style from a TCP socket */
typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
unsigned int, size_t); unsigned int, size_t);
......
...@@ -762,6 +762,13 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) ...@@ -762,6 +762,13 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
load = source_load(cpu); load = source_load(cpu);
this_load = target_load(this_cpu); this_load = target_load(this_cpu);
/*
* If sync wakeup then subtract the (maximum possible) effect of
* the currently running task from the load of the current CPU:
*/
if (sync)
this_load -= SCHED_LOAD_SCALE;
/* Don't pull the task off an idle CPU to a busy one */ /* Don't pull the task off an idle CPU to a busy one */
if (load < SCHED_LOAD_SCALE && load + this_load > SCHED_LOAD_SCALE if (load < SCHED_LOAD_SCALE && load + this_load > SCHED_LOAD_SCALE
&& this_load > load) && this_load > load)
......
...@@ -56,7 +56,6 @@ do { \ ...@@ -56,7 +56,6 @@ do { \
#endif #endif
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
static DECLARE_MUTEX(arpt_mutex);
#define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0) #define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
#define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0) #define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
...@@ -388,12 +387,12 @@ find_inlist_lock(struct list_head *head, ...@@ -388,12 +387,12 @@ find_inlist_lock(struct list_head *head,
} }
#endif #endif
static inline struct arpt_table *find_table_lock(const char *name, int *error, struct semaphore *mutex) static inline struct arpt_table *arpt_find_table_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex);
} }
static inline struct arpt_target *find_target_lock(const char *name, int *error, struct semaphore *mutex) struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex);
} }
...@@ -543,7 +542,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i ...@@ -543,7 +542,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
} }
t = arpt_get_target(e); t = arpt_get_target(e);
target = find_target_lock(t->u.user.name, &ret, &arpt_mutex); target = arpt_find_target_lock(t->u.user.name, &ret, &arpt_mutex);
if (!target) { if (!target) {
duprintf("check_entry: `%s' not found\n", t->u.user.name); duprintf("check_entry: `%s' not found\n", t->u.user.name);
goto out; goto out;
...@@ -843,7 +842,7 @@ static int get_entries(const struct arpt_get_entries *entries, ...@@ -843,7 +842,7 @@ static int get_entries(const struct arpt_get_entries *entries,
int ret; int ret;
struct arpt_table *t; struct arpt_table *t;
t = find_table_lock(entries->name, &ret, &arpt_mutex); t = arpt_find_table_lock(entries->name, &ret, &arpt_mutex);
if (t) { if (t) {
duprintf("t->private->number = %u\n", duprintf("t->private->number = %u\n",
t->private->number); t->private->number);
...@@ -909,7 +908,7 @@ static int do_replace(void __user *user, unsigned int len) ...@@ -909,7 +908,7 @@ static int do_replace(void __user *user, unsigned int len)
duprintf("arp_tables: Translated table\n"); duprintf("arp_tables: Translated table\n");
t = find_table_lock(tmp.name, &ret, &arpt_mutex); t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex);
if (!t) if (!t)
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
...@@ -1002,7 +1001,7 @@ static int do_add_counters(void __user *user, unsigned int len) ...@@ -1002,7 +1001,7 @@ static int do_add_counters(void __user *user, unsigned int len)
goto free; goto free;
} }
t = find_table_lock(tmp.name, &ret, &arpt_mutex); t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex);
if (!t) if (!t)
goto free; goto free;
...@@ -1075,7 +1074,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len ...@@ -1075,7 +1074,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break; break;
} }
name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
t = find_table_lock(name, &ret, &arpt_mutex); t = arpt_find_table_lock(name, &ret, &arpt_mutex);
if (t) { if (t) {
struct arpt_getinfo info; struct arpt_getinfo info;
...@@ -1323,6 +1322,7 @@ static void __exit fini(void) ...@@ -1323,6 +1322,7 @@ static void __exit fini(void)
EXPORT_SYMBOL(arpt_register_table); EXPORT_SYMBOL(arpt_register_table);
EXPORT_SYMBOL(arpt_unregister_table); EXPORT_SYMBOL(arpt_unregister_table);
EXPORT_SYMBOL(arpt_do_table); EXPORT_SYMBOL(arpt_do_table);
EXPORT_SYMBOL(arpt_find_target_lock);
EXPORT_SYMBOL(arpt_register_target); EXPORT_SYMBOL(arpt_register_target);
EXPORT_SYMBOL(arpt_unregister_target); EXPORT_SYMBOL(arpt_unregister_target);
......
...@@ -61,9 +61,6 @@ do { \ ...@@ -61,9 +61,6 @@ do { \
#endif #endif
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
/* Mutex protects lists (only traversed in user context). */
static DECLARE_MUTEX(ipt_mutex);
/* Must have mutex */ /* Must have mutex */
#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
...@@ -461,7 +458,7 @@ find_inlist_lock(struct list_head *head, ...@@ -461,7 +458,7 @@ find_inlist_lock(struct list_head *head,
#endif #endif
static inline struct ipt_table * static inline struct ipt_table *
find_table_lock(const char *name, int *error, struct semaphore *mutex) ipt_find_table_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&ipt_tables, name, "iptable_", error, mutex); return find_inlist_lock(&ipt_tables, name, "iptable_", error, mutex);
} }
...@@ -472,8 +469,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) ...@@ -472,8 +469,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex)
return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex); return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex);
} }
static inline struct ipt_target * struct ipt_target *
find_target_lock(const char *name, int *error, struct semaphore *mutex) ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex);
} }
...@@ -688,7 +685,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, ...@@ -688,7 +685,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
goto cleanup_matches; goto cleanup_matches;
t = ipt_get_target(e); t = ipt_get_target(e);
target = find_target_lock(t->u.user.name, &ret, &ipt_mutex); target = ipt_find_target_lock(t->u.user.name, &ret, &ipt_mutex);
if (!target) { if (!target) {
duprintf("check_entry: `%s' not found\n", t->u.user.name); duprintf("check_entry: `%s' not found\n", t->u.user.name);
goto cleanup_matches; goto cleanup_matches;
...@@ -1025,7 +1022,7 @@ get_entries(const struct ipt_get_entries *entries, ...@@ -1025,7 +1022,7 @@ get_entries(const struct ipt_get_entries *entries,
int ret; int ret;
struct ipt_table *t; struct ipt_table *t;
t = find_table_lock(entries->name, &ret, &ipt_mutex); t = ipt_find_table_lock(entries->name, &ret, &ipt_mutex);
if (t) { if (t) {
duprintf("t->private->number = %u\n", duprintf("t->private->number = %u\n",
t->private->number); t->private->number);
...@@ -1092,7 +1089,7 @@ do_replace(void __user *user, unsigned int len) ...@@ -1092,7 +1089,7 @@ do_replace(void __user *user, unsigned int len)
duprintf("ip_tables: Translated table\n"); duprintf("ip_tables: Translated table\n");
t = find_table_lock(tmp.name, &ret, &ipt_mutex); t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex);
if (!t) if (!t)
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
...@@ -1195,7 +1192,7 @@ do_add_counters(void __user *user, unsigned int len) ...@@ -1195,7 +1192,7 @@ do_add_counters(void __user *user, unsigned int len)
goto free; goto free;
} }
t = find_table_lock(tmp.name, &ret, &ipt_mutex); t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex);
if (!t) if (!t)
goto free; goto free;
...@@ -1270,7 +1267,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1270,7 +1267,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
} }
name[IPT_TABLE_MAXNAMELEN-1] = '\0'; name[IPT_TABLE_MAXNAMELEN-1] = '\0';
t = find_table_lock(name, &ret, &ipt_mutex); t = ipt_find_table_lock(name, &ret, &ipt_mutex);
if (t) { if (t) {
struct ipt_getinfo info; struct ipt_getinfo info;
...@@ -1855,6 +1852,7 @@ EXPORT_SYMBOL(ipt_unregister_match); ...@@ -1855,6 +1852,7 @@ EXPORT_SYMBOL(ipt_unregister_match);
EXPORT_SYMBOL(ipt_do_table); EXPORT_SYMBOL(ipt_do_table);
EXPORT_SYMBOL(ipt_register_target); EXPORT_SYMBOL(ipt_register_target);
EXPORT_SYMBOL(ipt_unregister_target); EXPORT_SYMBOL(ipt_unregister_target);
EXPORT_SYMBOL(ipt_find_target_lock);
module_init(init); module_init(init);
module_exit(fini); module_exit(fini);
...@@ -66,8 +66,6 @@ do { \ ...@@ -66,8 +66,6 @@ do { \
#endif #endif
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
/* Mutex protects lists (only traversed in user context). */
static DECLARE_MUTEX(ip6t_mutex);
/* Must have mutex */ /* Must have mutex */
#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
...@@ -544,7 +542,7 @@ find_inlist_lock(struct list_head *head, ...@@ -544,7 +542,7 @@ find_inlist_lock(struct list_head *head,
#endif #endif
static inline struct ip6t_table * static inline struct ip6t_table *
find_table_lock(const char *name, int *error, struct semaphore *mutex) ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex); return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
} }
...@@ -555,8 +553,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) ...@@ -555,8 +553,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex)
return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
} }
static inline struct ip6t_target * struct ip6t_target *
find_target_lock(const char *name, int *error, struct semaphore *mutex) ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
{ {
return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
} }
...@@ -771,7 +769,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, ...@@ -771,7 +769,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
goto cleanup_matches; goto cleanup_matches;
t = ip6t_get_target(e); t = ip6t_get_target(e);
target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex); target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
if (!target) { if (!target) {
duprintf("check_entry: `%s' not found\n", t->u.user.name); duprintf("check_entry: `%s' not found\n", t->u.user.name);
goto cleanup_matches; goto cleanup_matches;
...@@ -1111,7 +1109,7 @@ get_entries(const struct ip6t_get_entries *entries, ...@@ -1111,7 +1109,7 @@ get_entries(const struct ip6t_get_entries *entries,
int ret; int ret;
struct ip6t_table *t; struct ip6t_table *t;
t = find_table_lock(entries->name, &ret, &ip6t_mutex); t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
if (t) { if (t) {
duprintf("t->private->number = %u\n", duprintf("t->private->number = %u\n",
t->private->number); t->private->number);
...@@ -1174,7 +1172,7 @@ do_replace(void __user *user, unsigned int len) ...@@ -1174,7 +1172,7 @@ do_replace(void __user *user, unsigned int len)
duprintf("ip_tables: Translated table\n"); duprintf("ip_tables: Translated table\n");
t = find_table_lock(tmp.name, &ret, &ip6t_mutex); t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
if (!t) if (!t)
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
...@@ -1276,7 +1274,7 @@ do_add_counters(void __user *user, unsigned int len) ...@@ -1276,7 +1274,7 @@ do_add_counters(void __user *user, unsigned int len)
goto free; goto free;
} }
t = find_table_lock(tmp.name, &ret, &ip6t_mutex); t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
if (!t) if (!t)
goto free; goto free;
...@@ -1351,7 +1349,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1351,7 +1349,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
} }
name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
t = find_table_lock(name, &ret, &ip6t_mutex); t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
if (t) { if (t) {
struct ip6t_getinfo info; struct ip6t_getinfo info;
...@@ -1964,6 +1962,7 @@ static void __exit fini(void) ...@@ -1964,6 +1962,7 @@ static void __exit fini(void)
EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_register_table);
EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_unregister_table);
EXPORT_SYMBOL(ip6t_do_table); EXPORT_SYMBOL(ip6t_do_table);
EXPORT_SYMBOL(ip6t_find_target_lock);
EXPORT_SYMBOL(ip6t_register_match); EXPORT_SYMBOL(ip6t_register_match);
EXPORT_SYMBOL(ip6t_unregister_match); EXPORT_SYMBOL(ip6t_unregister_match);
EXPORT_SYMBOL(ip6t_register_target); EXPORT_SYMBOL(ip6t_register_target);
......
...@@ -493,7 +493,7 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) ...@@ -493,7 +493,7 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
rpc_release_client(clnt); rpc_release_client(clnt);
kfree(obj.data); kfree(obj.data);
dprintk("RPC: gss_pipe_downcall returning length %u\n", mlen); dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen);
return mlen; return mlen;
err: err:
if (ctx) if (ctx)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment