Commit 8a2e73e1 authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/spare/repo/linux-2.5

into redhat.com:/spare/repo/net-drivers-2.5
parents 7e223b72 dbf8623b
...@@ -790,7 +790,8 @@ running once the system is up. ...@@ -790,7 +790,8 @@ running once the system is up.
before loading. before loading.
See Documentation/ramdisk.txt. See Documentation/ramdisk.txt.
psmouse_noext [HW,MOUSE] Disable probing for PS2 mouse protocol extensions psmouse_proto= [HW,MOUSE] Highest PS2 mouse protocol extension to
probe for (bare|imps|exps).
psmouse_resetafter= psmouse_resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many [HW,MOUSE] Try to reset Synaptics Touchpad after so many
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 6 PATCHLEVEL = 6
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -test11 EXTRAVERSION =
# *DOCUMENTATION* # *DOCUMENTATION*
# To see a list of typical targets execute "make help" # To see a list of typical targets execute "make help"
......
...@@ -505,6 +505,20 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) ...@@ -505,6 +505,20 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs)
return 1; return 1;
} }
int can_request_irq(unsigned int irq, unsigned long irqflags)
{
struct irqaction *action;
if (irq >= NR_IRQS)
return 0;
action = irq_desc[irq].action;
if (action) {
if (irqflags & action->flags & SA_SHIRQ)
action = NULL;
}
return !action;
}
/** /**
* request_irq - allocate an interrupt line * request_irq - allocate an interrupt line
* @irq: Interrupt line to allocate * @irq: Interrupt line to allocate
......
...@@ -541,8 +541,10 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long ...@@ -541,8 +541,10 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long
goto survive; goto survive;
} }
if (retval != 1) if (retval != 1) {
up_read(&current->mm->mmap_sem);
break; break;
}
maddr = kmap_atomic(pg, KM_USER0); maddr = kmap_atomic(pg, KM_USER0);
memcpy(maddr + offset, from, len); memcpy(maddr + offset, from, len);
......
...@@ -695,11 +695,6 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev) ...@@ -695,11 +695,6 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
return NULL; return NULL;
} }
static irqreturn_t pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
return IRQ_NONE;
}
static int pcibios_lookup_irq(struct pci_dev *dev, int assign) static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{ {
u8 pin; u8 pin;
...@@ -761,13 +756,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -761,13 +756,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
if (!(mask & (1 << i))) if (!(mask & (1 << i)))
continue; continue;
if (pirq_penalty[i] < pirq_penalty[newirq] && if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, SA_SHIRQ))
!request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
free_irq(i, dev);
newirq = i; newirq = i;
} }
} }
}
DBG(" -> newirq=%d", newirq); DBG(" -> newirq=%d", newirq);
/* Check if it is hardcoded */ /* Check if it is hardcoded */
......
...@@ -2460,7 +2460,7 @@ static int __end_that_request_first(struct request *req, int uptodate, ...@@ -2460,7 +2460,7 @@ static int __end_that_request_first(struct request *req, int uptodate,
if (!uptodate) { if (!uptodate) {
error = -EIO; error = -EIO;
if (!(req->flags & REQ_QUIET)) if (blk_fs_request(req) && !(req->flags & REQ_QUIET))
printk("end_request: I/O error, dev %s, sector %llu\n", printk("end_request: I/O error, dev %s, sector %llu\n",
req->rq_disk ? req->rq_disk->disk_name : "?", req->rq_disk ? req->rq_disk->disk_name : "?",
(unsigned long long)req->sector); (unsigned long long)req->sector);
......
...@@ -150,7 +150,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -150,7 +150,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
struct request *rq; struct request *rq;
struct bio *bio; struct bio *bio;
char sense[SCSI_SENSE_BUFFERSIZE]; char sense[SCSI_SENSE_BUFFERSIZE];
unsigned char cdb[BLK_MAX_CDB];
void *buffer; void *buffer;
if (hdr->interface_id != 'S') if (hdr->interface_id != 'S')
...@@ -167,9 +166,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -167,9 +166,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
if (hdr->dxfer_len > (q->max_sectors << 9)) if (hdr->dxfer_len > (q->max_sectors << 9))
return -EIO; return -EIO;
if (copy_from_user(cdb, hdr->cmdp, hdr->cmd_len))
return -EFAULT;
reading = writing = 0; reading = writing = 0;
buffer = NULL; buffer = NULL;
bio = NULL; bio = NULL;
...@@ -220,7 +216,7 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -220,7 +216,7 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
* fill in request structure * fill in request structure
*/ */
rq->cmd_len = hdr->cmd_len; rq->cmd_len = hdr->cmd_len;
memcpy(rq->cmd, cdb, hdr->cmd_len); memcpy(rq->cmd, hdr->cmdp, hdr->cmd_len);
if (sizeof(rq->cmd) != hdr->cmd_len) if (sizeof(rq->cmd) != hdr->cmd_len)
memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len); memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len);
...@@ -436,12 +432,23 @@ int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long ar ...@@ -436,12 +432,23 @@ int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long ar
break; break;
case SG_IO: { case SG_IO: {
struct sg_io_hdr hdr; struct sg_io_hdr hdr;
unsigned char cdb[BLK_MAX_CDB], *old_cdb;
if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr))) {
err = -EFAULT; err = -EFAULT;
if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr)))
break; break;
} err = -EINVAL;
if (hdr.cmd_len > sizeof(rq->cmd))
break;
err = -EFAULT;
if (copy_from_user(cdb, hdr.cmdp, hdr.cmd_len))
break;
old_cdb = hdr.cmdp;
hdr.cmdp = cdb;
err = sg_io(q, bdev, &hdr); err = sg_io(q, bdev, &hdr);
hdr.cmdp = old_cdb;
if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr))) if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr)))
err = -EFAULT; err = -EFAULT;
break; break;
......
...@@ -941,16 +941,16 @@ static unsigned short x86_keycodes[256] = ...@@ -941,16 +941,16 @@ static unsigned short x86_keycodes[256] =
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90, 80, 81, 82, 83, 84, 93, 86, 87, 88, 94, 95, 85,259,375,260, 90,
284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, 284,285,309,311,312, 91,327,328,329,331,333,335,336,337,338,339,
367,288,302,304,350, 92,334,512,116,377,109,111,373,347,348,349, 367,288,302,304,350, 89,334,326,116,377,109,111,126,347,348,349,
360, 93, 94, 95, 98,376,100,101,321,316,354,286,289,102,351,355, 360,261,262,263,298,376,100,101,321,316,373,286,289,102,351,355,
103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361, 103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361,
291,108,381,281,290,272,292,305,280, 99,112,257,258,359,270,114, 291,108,381,281,290,272,292,305,280, 99,112,257,258,359,113,114,
118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269, 264,117,271,374,379,115,125,273,121,123, 92,265,266,267,268,269,
271,273,276,277,278,282,283,295,296,297,299,300,301,293,303,307, 120,119,118,277,278,282,283,295,296,297,299,300,301,293,303,307,
308,310,313,314,315,317,318,319,320,357,322,323,324,325,326,330, 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
332,340,365,342,343,344,345,346,356,113,341,368,369,370,371,372 }; 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
#ifdef CONFIG_MAC_EMUMOUSEBTN #ifdef CONFIG_MAC_EMUMOUSEBTN
extern int mac_hid_mouse_emulate_buttons(int, int, int); extern int mac_hid_mouse_emulate_buttons(int, int, int);
...@@ -972,11 +972,18 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, ...@@ -972,11 +972,18 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
if (keycode > 255 || !x86_keycodes[keycode]) if (keycode > 255 || !x86_keycodes[keycode])
return -1; return -1;
if (keycode == KEY_PAUSE) { switch (keycode) {
case KEY_PAUSE:
put_queue(vc, 0xe1); put_queue(vc, 0xe1);
put_queue(vc, 0x1d | up_flag); put_queue(vc, 0x1d | up_flag);
put_queue(vc, 0x45 | up_flag); put_queue(vc, 0x45 | up_flag);
return 0; return 0;
case KEY_LANG1:
if (!up_flag) put_queue(vc, 0xf1);
return 0;
case KEY_LANG2:
if (!up_flag) put_queue(vc, 0xf2);
return 0;
} }
if (keycode == KEY_SYSRQ && sysrq_alt) { if (keycode == KEY_SYSRQ && sysrq_alt) {
......
...@@ -799,6 +799,10 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) ...@@ -799,6 +799,10 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
* sector... If we got here the error is not correctable */ * sector... If we got here the error is not correctable */
ide_dump_status (drive, "media error (bad sector)", stat); ide_dump_status (drive, "media error (bad sector)", stat);
do_end_request = 1; do_end_request = 1;
} else if (sense_key == BLANK_CHECK) {
/* Disk appears blank ?? */
ide_dump_status (drive, "media error (blank)", stat);
do_end_request = 1;
} else if ((err & ~ABRT_ERR) != 0) { } else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler /* Go to the default handler
for other errors. */ for other errors. */
......
...@@ -501,6 +501,7 @@ struct cdrom_info { ...@@ -501,6 +501,7 @@ struct cdrom_info {
#define ILLEGAL_REQUEST 0x05 #define ILLEGAL_REQUEST 0x05
#define UNIT_ATTENTION 0x06 #define UNIT_ATTENTION 0x06
#define DATA_PROTECT 0x07 #define DATA_PROTECT 0x07
#define BLANK_CHECK 0x08
#define ABORTED_COMMAND 0x0b #define ABORTED_COMMAND 0x0b
#define MISCOMPARE 0x0e #define MISCOMPARE 0x0e
...@@ -578,7 +579,7 @@ const char * const sense_key_texts[16] = { ...@@ -578,7 +579,7 @@ const char * const sense_key_texts[16] = {
"Illegal request", "Illegal request",
"Unit attention", "Unit attention",
"Data protect", "Data protect",
"(reserved)", "Blank check",
"(reserved)", "(reserved)",
"(reserved)", "(reserved)",
"Aborted command", "Aborted command",
......
...@@ -447,6 +447,7 @@ void input_register_device(struct input_dev *dev) ...@@ -447,6 +447,7 @@ void input_register_device(struct input_dev *dev)
list_add_tail(&dev->node, &input_dev_list); list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node) list_for_each_entry(handler, &input_handler_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev))) if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id))) if ((handle = handler->connect(handler, dev, id)))
input_link_handle(handle); input_link_handle(handle);
...@@ -507,6 +508,7 @@ void input_register_handler(struct input_handler *handler) ...@@ -507,6 +508,7 @@ void input_register_handler(struct input_handler *handler)
list_add_tail(&handler->node, &input_handler_list); list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node) list_for_each_entry(dev, &input_dev_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev))) if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id))) if ((handle = handler->connect(handler, dev, id)))
input_link_handle(handle); input_link_handle(handle);
......
...@@ -380,10 +380,6 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct ...@@ -380,10 +380,6 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
struct joydev *joydev; struct joydev *joydev;
int i, j, t, minor; int i, j, t, minor;
/* Avoid tablets */
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
return NULL;
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
if (minor == JOYDEV_MINORS) { if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n"); printk(KERN_ERR "joydev: no more free joydev devices\n");
...@@ -464,6 +460,15 @@ static void joydev_disconnect(struct input_handle *handle) ...@@ -464,6 +460,15 @@ static void joydev_disconnect(struct input_handle *handle)
joydev_free(joydev); joydev_free(joydev);
} }
static struct input_device_id joydev_blacklist[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
}, /* Avoid itouchpads, touchscreens and tablets */
{ }, /* Terminating entry */
};
static struct input_device_id joydev_ids[] = { static struct input_device_id joydev_ids[] = {
{ {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
...@@ -493,6 +498,7 @@ static struct input_handler joydev_handler = { ...@@ -493,6 +498,7 @@ static struct input_handler joydev_handler = {
.minor = JOYDEV_MINOR_BASE, .minor = JOYDEV_MINOR_BASE,
.name = "joydev", .name = "joydev",
.id_table = joydev_ids, .id_table = joydev_ids,
.blacklist = joydev_blacklist,
}; };
static int __init joydev_init(void) static int __init joydev_init(void)
......
...@@ -48,33 +48,30 @@ static int atkbd_softrepeat; ...@@ -48,33 +48,30 @@ static int atkbd_softrepeat;
*/ */
static unsigned char atkbd_set2_keycode[512] = { static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42,182, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
0, 46, 45, 32, 18, 5, 4, 91, 90, 57, 47, 33, 20, 19, 6, 0, 0, 56, 42,182, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
91, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, 0, 46, 45, 32, 18, 5, 4,186, 0, 57, 47, 33, 20, 19, 6, 85,
0, 49, 48, 35, 34, 21, 7, 89, 0, 0, 50, 36, 22, 8, 9, 90,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, 0,181, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0,194,
85, 86, 90, 91, 92, 93, 14, 94, 95, 79,183, 75, 71,121, 0,123, 0, 86,193,192,184, 0, 14,185, 0, 79,182, 75, 71,124, 0, 0,
82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
0, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
217,100,255, 0, 97,165,164, 0,156, 0, 0,140,115, 0, 0,125, 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
173,114, 0,113,152,163,151,126,128,166, 0,140, 0,147, 0,127, 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
159,167,115,160,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
157, 0,114,166,168, 0, 0,213,155, 0, 98,113, 0,163, 0,138, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
226, 0, 0, 0, 0, 0,153,140, 0,255, 96, 0, 0, 0,143, 0, 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 0, 0, 0, 65, 99,
}; };
static unsigned char atkbd_set3_keycode[512] = { static unsigned char atkbd_set3_keycode[512] = {
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
...@@ -83,14 +80,10 @@ static unsigned char atkbd_set3_keycode[512] = { ...@@ -83,14 +80,10 @@ static unsigned char atkbd_set3_keycode[512] = {
113,114, 40, 84, 26, 13, 87, 99, 97, 54, 28, 27, 43, 84, 88, 70, 113,114, 40, 84, 26, 13, 87, 99, 97, 54, 28, 27, 43, 84, 88, 70,
108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85, 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85,
89, 90, 91, 92, 74,185,184,182, 0, 0, 0,125,126,127,112, 0, 89, 90, 91, 92, 74,185,184,182, 0, 0, 0,125,126,127,112, 0,
0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
148,149,147,140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148,149,147,140
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255
}; };
static unsigned char atkbd_unxlate_table[128] = { static unsigned char atkbd_unxlate_table[128] = {
...@@ -125,6 +118,9 @@ static unsigned char atkbd_unxlate_table[128] = { ...@@ -125,6 +118,9 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_RET_EMULX 0x80 #define ATKBD_RET_EMULX 0x80
#define ATKBD_RET_EMUL1 0xe1 #define ATKBD_RET_EMUL1 0xe1
#define ATKBD_RET_RELEASE 0xf0 #define ATKBD_RET_RELEASE 0xf0
#define ATKBD_RET_HANGUEL 0xf1
#define ATKBD_RET_HANJA 0xf2
#define ATKBD_RET_ERR 0xff
#define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_NULL 255 #define ATKBD_KEY_NULL 255
...@@ -156,6 +152,17 @@ struct atkbd { ...@@ -156,6 +152,17 @@ struct atkbd {
unsigned long time; unsigned long time;
}; };
static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
{
input_regs(dev, regs);
if (value == 3) {
input_report_key(dev, code, 1);
input_report_key(dev, code, 0);
} else
input_event(dev, EV_KEY, code, value);
input_sync(dev);
}
/* /*
* atkbd_interrupt(). Here takes place processing of data received from * atkbd_interrupt(). Here takes place processing of data received from
* the keyboard into events. * the keyboard into events.
...@@ -184,6 +191,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -184,6 +191,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->resend = 0; atkbd->resend = 0;
#endif #endif
if (!atkbd->ack)
switch (code) { switch (code) {
case ATKBD_RET_ACK: case ATKBD_RET_ACK:
atkbd->ack = 1; atkbd->ack = 1;
...@@ -193,36 +201,25 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -193,36 +201,25 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
goto out; goto out;
} }
if (atkbd->translated) do { if (atkbd->cmdcnt) {
atkbd->cmdbuf[--atkbd->cmdcnt] = code;
if (atkbd->emul != 1) { goto out;
if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
break;
if (code == ATKBD_RET_BAT) {
if (!atkbd->bat_xl)
break;
atkbd->bat_xl = 0;
}
if (code == (ATKBD_RET_BAT & 0x7f))
atkbd->bat_xl = 1;
}
if (code < 0x80) {
code = atkbd_unxlate_table[code];
break;
} }
if (atkbd->cmdcnt) if (atkbd->translated) {
break;
code = atkbd_unxlate_table[code & 0x7f]; if (atkbd->emul ||
atkbd->release = 1; !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
} while (0); code == ATKBD_RET_ERR ||
(code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
atkbd->release = code >> 7;
code &= 0x7f;
}
if (atkbd->cmdcnt) { if (!atkbd->emul &&
atkbd->cmdbuf[--atkbd->cmdcnt] = code; (code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
goto out; atkbd->bat_xl = !atkbd->release;
} }
switch (code) { switch (code) {
...@@ -238,22 +235,33 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -238,22 +235,33 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
case ATKBD_RET_RELEASE: case ATKBD_RET_RELEASE:
atkbd->release = 1; atkbd->release = 1;
goto out; goto out;
case ATKBD_RET_HANGUEL:
atkbd_report_key(&atkbd->dev, regs, KEY_LANG1, 3);
goto out;
case ATKBD_RET_HANJA:
atkbd_report_key(&atkbd->dev, regs, KEY_LANG2, 3);
goto out;
case ATKBD_RET_ERR:
printk(KERN_WARNING "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
goto out;
} }
if (atkbd->set != 3)
code = (code & 0x7f) | ((code & 0x80) << 1);
if (atkbd->emul) { if (atkbd->emul) {
if (--atkbd->emul) if (--atkbd->emul)
goto out; goto out;
code |= 0x100; code |= (atkbd->set != 3) ? 0x80 : 0x100;
} }
switch (atkbd->keycode[code]) { switch (atkbd->keycode[code]) {
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, data %#x, on %s).\n", 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, data, serio->phys); atkbd->set, code, serio->phys);
break; break;
default: default:
value = atkbd->release ? 0 : value = atkbd->release ? 0 :
...@@ -273,9 +281,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -273,9 +281,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
break; break;
} }
input_regs(&atkbd->dev, regs); atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
input_event(&atkbd->dev, EV_KEY, atkbd->keycode[code], value);
input_sync(&atkbd->dev);
} }
atkbd->release = 0; atkbd->release = 0;
...@@ -369,10 +375,11 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -369,10 +375,11 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{ {
struct atkbd *atkbd = dev->private; struct atkbd *atkbd = dev->private;
struct { int p; u8 v; } period[] = const short period[32] =
{ {30, 0x00}, {25, 0x02}, {20, 0x04}, {15, 0x08}, {10, 0x0c}, {7, 0x10}, {5, 0x14}, {0, 0x14} }; { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
struct { int d; u8 v; } delay[] = 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
{ {1000, 0x60}, {750, 0x40}, {500, 0x20}, {250, 0x00}, {0, 0x00} }; const short delay[4] =
{ 250, 500, 750, 1000 };
char param[2]; char param[2];
int i, j; int i, j;
...@@ -406,11 +413,11 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -406,11 +413,11 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
if (atkbd_softrepeat) return 0; if (atkbd_softrepeat) return 0;
i = j = 0; i = j = 0;
while (period[i].p > dev->rep[REP_PERIOD]) i++; while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
while (delay[j].d > dev->rep[REP_DELAY]) j++; while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++;
dev->rep[REP_PERIOD] = period[i].p; dev->rep[REP_PERIOD] = period[i];
dev->rep[REP_DELAY] = delay[j].d; dev->rep[REP_DELAY] = delay[j];
param[0] = period[i].v | delay[j].v; param[0] = i | (j << 5);
atkbd_command(atkbd, param, ATKBD_CMD_SETREP); atkbd_command(atkbd, param, ATKBD_CMD_SETREP);
return 0; return 0;
...@@ -623,6 +630,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -623,6 +630,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.rep[REP_PERIOD] = 33; atkbd->dev.rep[REP_PERIOD] = 33;
} }
atkbd->ack = 1;
atkbd->serio = serio; atkbd->serio = serio;
init_input_dev(&atkbd->dev); init_input_dev(&atkbd->dev);
...@@ -665,16 +673,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -665,16 +673,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
sprintf(atkbd->phys, "%s/input0", serio->phys); sprintf(atkbd->phys, "%s/input0", serio->phys);
if (atkbd->set == 3) if (atkbd->translated) {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); for (i = 0; i < 128; i++) {
else atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
}
} else if (atkbd->set == 2) {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
}
atkbd->dev.name = atkbd->name; atkbd->dev.name = atkbd->name;
atkbd->dev.phys = atkbd->phys; atkbd->dev.phys = atkbd->phys;
atkbd->dev.id.bustype = BUS_I8042; atkbd->dev.id.bustype = BUS_I8042;
atkbd->dev.id.vendor = 0x0001; atkbd->dev.id.vendor = 0x0001;
atkbd->dev.id.product = atkbd->set; atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set;
atkbd->dev.id.version = atkbd->id; atkbd->dev.id.version = atkbd->id;
for (i = 0; i < 512; i++) for (i = 0; i < 512; i++)
...@@ -686,10 +700,62 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -686,10 +700,62 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
} }
/*
* atkbd_reconnect() tries to restore keyboard into a sane state and is
* most likely called on resume.
*/
static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = serio->private;
struct serio_dev *dev = serio->dev;
int i;
if (!dev) {
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
if (atkbd->write) {
if (atkbd_probe(atkbd))
return -1;
atkbd->set = atkbd_set_3(atkbd);
atkbd_enable(atkbd);
} else {
atkbd->set = 2;
atkbd->id = 0xab00;
}
/*
* Here we probably should check if the keyboard has the same set that
* it had before and bail out if it's different. But this will most likely
* cause new keyboard device be created... and for the user it will look
* like keyboard is lost
*/
if (atkbd->translated) {
for (i = 0; i < 128; i++) {
atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
}
} else if (atkbd->set == 2) {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
}
for (i = 0; i < 512; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
set_bit(atkbd->keycode[i], atkbd->dev.keybit);
return 0;
}
static struct serio_dev atkbd_dev = { static struct serio_dev atkbd_dev = {
.interrupt = atkbd_interrupt, .interrupt = atkbd_interrupt,
.connect = atkbd_connect, .connect = atkbd_connect,
.reconnect = atkbd_reconnect,
.disconnect = atkbd_disconnect, .disconnect = atkbd_disconnect,
.cleanup = atkbd_cleanup, .cleanup = atkbd_cleanup,
}; };
...@@ -709,9 +775,17 @@ static int __init atkbd_setup_reset(char *str) ...@@ -709,9 +775,17 @@ static int __init atkbd_setup_reset(char *str)
if (ints[0] > 0) atkbd_reset = ints[1]; if (ints[0] > 0) atkbd_reset = ints[1];
return 1; return 1;
} }
static int __init atkbd_setup_softrepeat(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0) atkbd_softrepeat = ints[1];
return 1;
}
__setup("atkbd_set=", atkbd_setup_set); __setup("atkbd_set=", atkbd_setup_set);
__setup("atkbd_reset", atkbd_setup_reset); __setup("atkbd_reset", atkbd_setup_reset);
__setup("atkbd_softrepeat=", atkbd_setup_softrepeat);
#endif #endif
int __init atkbd_init(void) int __init atkbd_init(void)
......
...@@ -23,27 +23,18 @@ config MOUSE_PS2 ...@@ -23,27 +23,18 @@ config MOUSE_PS2
mice with wheels and extra buttons, Microsoft, Logitech or Genius mice with wheels and extra buttons, Microsoft, Logitech or Genius
compatible. compatible.
Synaptics TouchPad users might be interested in a specialized
XFree86 driver at:
http://w1.894.telia.com/~u89404340/touchpad/index.html
and a new verion of GPM at:
http://www.geocities.com/dt_or/gpm/gpm.html
to take advantage of the advanced features of the touchpad.
If unsure, say Y. If unsure, say Y.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called psmouse. module will be called psmouse.
config MOUSE_PS2_SYNAPTICS
bool "Synaptics TouchPad"
default n
depends on INPUT && INPUT_MOUSE && MOUSE_PS2
---help---
Say Y here if you have a Synaptics TouchPad connected to your system.
This touchpad is found on many modern laptop computers.
Note that you also need a user space driver to interpret the data
generated by the kernel. A compatible driver for XFree86 is available
from http://w1.894.telia.com/~u89404340/touchpad/index.html
The gpm program is not yet able to interpret the data from this
driver, so if you need to use the touchpad in the console, you have to
say N for now.
config MOUSE_SERIAL config MOUSE_SERIAL
tristate "Serial mouse" tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE depends on INPUT && INPUT_MOUSE
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h>
#include "psmouse.h" #include "psmouse.h"
#include "logips2pp.h" #include "logips2pp.h"
...@@ -142,7 +143,7 @@ void ps2pp_set_800dpi(struct psmouse *psmouse) ...@@ -142,7 +143,7 @@ void ps2pp_set_800dpi(struct psmouse *psmouse)
* touchpad. * touchpad.
*/ */
int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
{ {
int i; int i;
static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 };
...@@ -226,3 +227,22 @@ int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) ...@@ -226,3 +227,22 @@ int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
return 0; return 0;
} }
/*
* Logitech magic init.
*/
int ps2pp_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
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);
return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0;
}
...@@ -13,5 +13,5 @@ ...@@ -13,5 +13,5 @@
struct psmouse; 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_model(struct psmouse *psmouse, unsigned char *param); int ps2pp_detect(struct psmouse *psmouse);
#endif #endif
...@@ -12,35 +12,44 @@ ...@@ -12,35 +12,44 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pm.h>
#include "psmouse.h" #include "psmouse.h"
#include "synaptics.h" #include "synaptics.h"
#include "logips2pp.h" #include "logips2pp.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_DESCRIPTION("PS/2 mouse driver");
MODULE_PARM(psmouse_noext, "1i");
MODULE_PARM_DESC(psmouse_noext, "Disable any protocol extensions. Useful for KVM switches.");
MODULE_PARM(psmouse_resolution, "i");
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_rate, "i");
MODULE_PARM_DESC(psmouse_rate, "Report rate, in reports per second.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
MODULE_PARM(psmouse_resetafter, "i");
MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int psmouse_noext; static int psmouse_noext;
module_param(psmouse_noext, int, 0);
MODULE_PARM_DESC(psmouse_noext, "[DEPRECATED] Disable any protocol extensions. Useful for KVM switches.");
static char *psmouse_proto;
static unsigned int psmouse_max_proto = -1UL;
module_param(psmouse_proto, charp, 0);
MODULE_PARM_DESC(psmouse_proto, "Highest protocol extension to probe (bare, imps, exps). Useful for KVM switches.");
int psmouse_resolution = 200; int psmouse_resolution = 200;
module_param(psmouse_resolution, uint, 0);
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
unsigned int psmouse_rate = 100; unsigned int psmouse_rate = 100;
module_param(psmouse_rate, uint, 0);
MODULE_PARM_DESC(psmouse_rate, "Report rate, in reports per second.");
int psmouse_smartscroll = 1; int psmouse_smartscroll = 1;
module_param(psmouse_smartscroll, bool, 0);
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
unsigned int psmouse_resetafter; unsigned int psmouse_resetafter;
module_param(psmouse_resetafter, uint, 0);
MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
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"};
...@@ -139,7 +148,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -139,7 +148,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
goto out; goto out;
} }
if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { if (psmouse->state == PSMOUSE_ACTIVATED &&
psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
...@@ -257,46 +267,12 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -257,46 +267,12 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
} }
/* /*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol * Genius NetMouse magic init.
* the mouse may have.
*/ */
static int genius_detect(struct psmouse *psmouse)
static int psmouse_extensions(struct psmouse *psmouse)
{ {
unsigned char param[4]; unsigned char param[4];
param[0] = 0;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
if (psmouse_noext)
return PSMOUSE_PS2;
/*
* Try Synaptics TouchPad magic ID
*/
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);
if (param[1] == 0x47) {
psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad";
if (!synaptics_init(psmouse))
return PSMOUSE_SYNAPTICS;
else
return PSMOUSE_PS2;
}
/*
* Try Genius NetMouse magic init.
*/
param[0] = 3; param[0] = 3;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
...@@ -304,38 +280,15 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -304,38 +280,15 @@ static int psmouse_extensions(struct psmouse *psmouse)
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) { return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55;
}
set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse";
return PSMOUSE_GENPS;
}
/*
* Try Logitech magic ID.
*/
param[0] = 0;
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]) {
int type = ps2pp_detect_model(psmouse, param);
if (type)
return type;
}
/* /*
* Try IntelliMouse magic init. * IntelliMouse magic init.
*/ */
static int intellimouse_detect(struct psmouse *psmouse)
{
unsigned char param[2];
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
...@@ -345,13 +298,15 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -345,13 +298,15 @@ static int psmouse_extensions(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
if (param[0] == 3) { return param[0] == 3;
}
set_bit(REL_WHEEL, psmouse->dev.relbit);
/* /*
* Try IntelliMouse/Explorer magic init. * Try IntelliMouse/Explorer magic init.
*/ */
static int im_explorer_detect(struct psmouse *psmouse)
{
unsigned char param[2];
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
...@@ -361,8 +316,63 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -361,8 +316,63 @@ static int psmouse_extensions(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
if (param[0] == 4) { return param[0] == 4;
}
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
*/
static int psmouse_extensions(struct psmouse *psmouse)
{
int synaptics_hardware = 0;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
/*
* Try Synaptics TouchPad
*/
if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
synaptics_hardware = 1;
psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad";
if (psmouse_max_proto > PSMOUSE_IMEX) {
if (synaptics_init(psmouse) == 0)
return PSMOUSE_SYNAPTICS;
/*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so
* we'll have to skip them.
*/
psmouse_max_proto = PSMOUSE_IMEX;
}
}
if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse";
return PSMOUSE_GENPS;
}
if (psmouse_max_proto > PSMOUSE_IMEX) {
int type = ps2pp_detect(psmouse);
if (type)
return type;
}
if (psmouse_max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (psmouse_max_proto >= PSMOUSE_IMEX &&
im_explorer_detect(psmouse)) {
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);
...@@ -378,6 +388,15 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -378,6 +388,15 @@ static int psmouse_extensions(struct psmouse *psmouse)
* Okay, all failed, we have a standard mouse here. The number of the buttons * Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3. * is still a question, though. We assume 3.
*/ */
if (synaptics_hardware) {
/*
* We detected Synaptics hardware but it did not respond to IMPS/2 probes.
* We need to reset the touchpad because if there is a track point on the
* pass through port it could get disabled while probing for protocol
* extensions.
*/
psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
}
return PSMOUSE_PS2; return PSMOUSE_PS2;
} }
...@@ -468,7 +487,7 @@ static void psmouse_initialize(struct psmouse *psmouse) ...@@ -468,7 +487,7 @@ static void psmouse_initialize(struct psmouse *psmouse)
* We set the mouse report rate, resolution and scaling. * We set the mouse report rate, resolution and scaling.
*/ */
if (!psmouse_noext) { if (psmouse_max_proto != PSMOUSE_PS2) {
psmouse_set_rate(psmouse); psmouse_set_rate(psmouse);
psmouse_set_resolution(psmouse); psmouse_set_resolution(psmouse);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
...@@ -513,45 +532,30 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -513,45 +532,30 @@ static void psmouse_disconnect(struct serio *serio)
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
psmouse->state = PSMOUSE_IGNORE; psmouse->state = PSMOUSE_IGNORE;
synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
kfree(psmouse);
}
/*
* Reinitialize mouse hardware after software suspend.
*/
static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
{
struct psmouse *psmouse = dev->data;
struct serio_dev *ser_dev = psmouse->serio->dev;
synaptics_disconnect(psmouse); if (psmouse->ptport) {
if (psmouse->ptport->deactivate)
psmouse->ptport->deactivate(psmouse);
__serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */
kfree(psmouse->ptport);
psmouse->ptport = NULL;
}
/* We need to reopen the serio port to reinitialize the i8042 controller */ if (psmouse->disconnect)
serio_close(psmouse->serio); psmouse->disconnect(psmouse);
serio_open(psmouse->serio, ser_dev);
/* Probe and re-initialize the mouse */ input_unregister_device(&psmouse->dev);
psmouse_probe(psmouse); serio_close(serio);
psmouse_initialize(psmouse); kfree(psmouse);
synaptics_pt_init(psmouse);
psmouse_activate(psmouse);
return 0;
} }
/* /*
* psmouse_connect() is a callback from the serio module when * psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found. * an unhandled serio port is found.
*/ */
static void psmouse_connect(struct serio *serio, struct serio_dev *dev) static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{ {
struct psmouse *psmouse; struct psmouse *psmouse;
struct pm_dev *pmdev;
if ((serio->type & SERIO_TYPE) != SERIO_8042 && if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
...@@ -572,7 +576,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -572,7 +576,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
serio->private = psmouse; serio->private = psmouse;
if (serio_open(serio, dev)) { if (serio_open(serio, dev)) {
kfree(psmouse); kfree(psmouse);
return; return;
...@@ -584,12 +587,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -584,12 +587,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return; return;
} }
pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
if (pmdev) {
psmouse->dev.pm_dev = pmdev;
pmdev->data = psmouse;
}
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",
...@@ -608,59 +605,87 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -608,59 +605,87 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse_initialize(psmouse); psmouse_initialize(psmouse);
synaptics_pt_init(psmouse); if (psmouse->ptport) {
printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys);
__serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */
if (psmouse->ptport->activate)
psmouse->ptport->activate(psmouse);
}
psmouse_activate(psmouse);
}
static int psmouse_reconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
struct serio_dev *dev = serio->dev;
int old_type = psmouse->type;
if (!dev) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
psmouse->state = PSMOUSE_NEW_DEVICE;
psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse))
return -1;
} else if (psmouse_probe(psmouse) != old_type)
return -1;
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
*/
psmouse->type = old_type;
psmouse_initialize(psmouse);
if (psmouse->ptport) {
if (psmouse_reconnect(&psmouse->ptport->serio)) {
__serio_unregister_port(&psmouse->ptport->serio);
__serio_register_port(&psmouse->ptport->serio);
if (psmouse->ptport->activate)
psmouse->ptport->activate(psmouse);
}
}
psmouse_activate(psmouse); psmouse_activate(psmouse);
return 0;
} }
static struct serio_dev psmouse_dev = { static struct serio_dev psmouse_dev = {
.interrupt = psmouse_interrupt, .interrupt = psmouse_interrupt,
.connect = psmouse_connect, .connect = psmouse_connect,
.reconnect = psmouse_reconnect,
.disconnect = psmouse_disconnect, .disconnect = psmouse_disconnect,
.cleanup = psmouse_cleanup, .cleanup = psmouse_cleanup,
}; };
#ifndef MODULE static inline void psmouse_parse_proto(void)
static int __init psmouse_noext_setup(char *str)
{
psmouse_noext = 1;
return 1;
}
static int __init psmouse_resolution_setup(char *str)
{
get_option(&str, &psmouse_resolution);
return 1;
}
static int __init psmouse_smartscroll_setup(char *str)
{
get_option(&str, &psmouse_smartscroll);
return 1;
}
static int __init psmouse_resetafter_setup(char *str)
{ {
get_option(&str, &psmouse_resetafter); if (psmouse_noext) {
return 1; printk(KERN_WARNING "psmouse: 'psmouse_noext' option is deprecated, please use 'psmouse_proto'\n");
} psmouse_max_proto = PSMOUSE_PS2;
}
static int __init psmouse_rate_setup(char *str) /* even is psmouse_noext is present psmouse_proto overrides it */
{ if (psmouse_proto) {
get_option(&str, &psmouse_rate); if (!strcmp(psmouse_proto, "bare"))
return 1; psmouse_max_proto = PSMOUSE_PS2;
else if (!strcmp(psmouse_proto, "imps"))
psmouse_max_proto = PSMOUSE_IMPS;
else if (!strcmp(psmouse_proto, "exps"))
psmouse_max_proto = PSMOUSE_IMEX;
else
printk(KERN_ERR "psmouse: unknown protocol type '%s'\n", psmouse_proto);
}
} }
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
__setup("psmouse_resetafter=", psmouse_resetafter_setup);
__setup("psmouse_rate=", psmouse_rate_setup);
#endif
int __init psmouse_init(void) int __init psmouse_init(void)
{ {
psmouse_parse_proto();
serio_register_device(&psmouse_dev); serio_register_device(&psmouse_dev);
return 0; return 0;
} }
......
...@@ -22,10 +22,20 @@ ...@@ -22,10 +22,20 @@
#define PSMOUSE_ACTIVATED 1 #define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2 #define PSMOUSE_IGNORE 2
struct psmouse;
struct psmouse_ptport {
struct serio serio;
void (*activate)(struct psmouse *parent);
void (*deactivate)(struct psmouse *parent);
};
struct psmouse { struct psmouse {
void *private; void *private;
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct psmouse_ptport *ptport;
char *vendor; char *vendor;
char *name; char *name;
unsigned char cmdbuf[8]; unsigned char cmdbuf[8];
...@@ -41,6 +51,9 @@ struct psmouse { ...@@ -41,6 +51,9 @@ struct psmouse {
char error; char error;
char devname[64]; char devname[64];
char phys[32]; char phys[32];
int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse);
}; };
#define PSMOUSE_PS2 1 #define PSMOUSE_PS2 1
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* Synaptics TouchPad PS/2 mouse driver * Synaptics TouchPad PS/2 mouse driver
* *
* 2003 Dmitry Torokhov <dtor@mail.ru> * 2003 Dmitry Torokhov <dtor@mail.ru>
* Added support for pass-through port * Added support for pass-through port. Special thanks to Peter Berg Larsen
* for explaining various Synaptics quirks.
* *
* 2003 Peter Osterlund <petero2@telia.com> * 2003 Peter Osterlund <petero2@telia.com>
* Ported to 2.5 input device infrastructure. * Ported to 2.5 input device infrastructure.
...@@ -194,9 +195,7 @@ static void print_ident(struct synaptics_data *priv) ...@@ -194,9 +195,7 @@ static void print_ident(struct synaptics_data *priv)
static int synaptics_query_hardware(struct psmouse *psmouse) static int synaptics_query_hardware(struct psmouse *psmouse)
{ {
struct synaptics_data *priv = psmouse->private;
int retries = 0; int retries = 0;
int mode;
while ((retries++ < 3) && synaptics_reset(psmouse)) while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n"); printk(KERN_ERR "synaptics reset failed\n");
...@@ -208,7 +207,14 @@ static int synaptics_query_hardware(struct psmouse *psmouse) ...@@ -208,7 +207,14 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
if (synaptics_capability(psmouse)) if (synaptics_capability(psmouse))
return -1; return -1;
mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE; return 0;
}
static int synaptics_set_mode(struct psmouse *psmouse, int mode)
{
struct synaptics_data *priv = psmouse->private;
mode |= SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
if (SYN_ID_MAJOR(priv->identity) >= 4) if (SYN_ID_MAJOR(priv->identity) >= 4)
mode |= SYN_BIT_DISABLE_GESTURE; mode |= SYN_BIT_DISABLE_GESTURE;
if (SYN_CAP_EXTENDED(priv->capabilities)) if (SYN_CAP_EXTENDED(priv->capabilities))
...@@ -265,49 +271,38 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet ...@@ -265,49 +271,38 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
} }
} }
int synaptics_pt_init(struct psmouse *psmouse) static void synaptics_pt_activate(struct psmouse *psmouse)
{ {
struct synaptics_data *priv = psmouse->private; struct psmouse *child = psmouse->ptport->serio.private;
struct serio *port;
struct psmouse *child;
if (psmouse->type != PSMOUSE_SYNAPTICS) /* adjust the touchpad to child's choice of protocol */
return -1; if (child && child->type >= PSMOUSE_GENPS) {
if (!SYN_CAP_EXTENDED(priv->capabilities)) if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
return -1; printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
if (!SYN_CAP_PASS_THROUGH(priv->capabilities)) }
return -1; }
static void synaptics_pt_create(struct psmouse *psmouse)
{
struct psmouse_ptport *port;
priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL); psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL);
if (!port) { if (!port) {
printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n"); printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
return -1; return;
} }
memset(port, 0, sizeof(struct serio)); memset(port, 0, sizeof(struct psmouse_ptport));
port->type = SERIO_PS_PSTHRU;
port->name = "Synaptics pass-through";
port->phys = "synaptics-pt/serio0";
port->write = synaptics_pt_write;
port->open = synaptics_pt_open;
port->close = synaptics_pt_close;
port->driver = psmouse;
printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys); port->serio.type = SERIO_PS_PSTHRU;
serio_register_slave_port(port); port->serio.name = "Synaptics pass-through";
port->serio.phys = "synaptics-pt/serio0";
port->serio.write = synaptics_pt_write;
port->serio.open = synaptics_pt_open;
port->serio.close = synaptics_pt_close;
port->serio.driver = psmouse;
/* adjust the touchpad to child's choice of protocol */ port->activate = synaptics_pt_activate;
child = port->private;
if (child && child->type >= PSMOUSE_GENPS) {
if (synaptics_mode_cmd(psmouse, (SYN_BIT_ABSOLUTE_MODE |
SYN_BIT_HIGH_RATE |
SYN_BIT_DISABLE_GESTURE |
SYN_BIT_FOUR_BYTE_CLIENT |
SYN_BIT_W_MODE)))
printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
}
return 0;
} }
/***************************************************************************** /*****************************************************************************
...@@ -371,13 +366,57 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -371,13 +366,57 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
clear_bit(REL_Y, dev->relbit); clear_bit(REL_Y, dev->relbit);
} }
int synaptics_init(struct psmouse *psmouse) static void synaptics_disconnect(struct psmouse *psmouse)
{ {
struct synaptics_data *priv; synaptics_mode_cmd(psmouse, 0);
kfree(psmouse->private);
}
#ifndef CONFIG_MOUSE_PS2_SYNAPTICS 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; return -1;
#endif }
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); psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -385,13 +424,24 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -385,13 +424,24 @@ int synaptics_init(struct psmouse *psmouse)
memset(priv, 0, sizeof(struct synaptics_data)); memset(priv, 0, sizeof(struct synaptics_data));
if (synaptics_query_hardware(psmouse)) { if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n"); 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; goto init_fail;
} }
if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse);
print_ident(priv); print_ident(priv);
set_input_params(&psmouse->dev, priv); set_input_params(&psmouse->dev, priv);
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
return 0; return 0;
init_fail: init_fail:
...@@ -399,36 +449,13 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -399,36 +449,13 @@ int synaptics_init(struct psmouse *psmouse)
return -1; return -1;
} }
void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
synaptics_mode_cmd(psmouse, 0);
if (priv->ptport) {
serio_unregister_slave_port(priv->ptport);
kfree(priv->ptport);
}
kfree(priv);
}
}
/***************************************************************************** /*****************************************************************************
* Functions to interpret the absolute mode packets * Functions to interpret the absolute mode packets
****************************************************************************/ ****************************************************************************/
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{ {
hw->up = 0; memset(hw, 0, sizeof(struct synaptics_hw_state));
hw->down = 0;
hw->b0 = 0;
hw->b1 = 0;
hw->b2 = 0;
hw->b3 = 0;
hw->b4 = 0;
hw->b5 = 0;
hw->b6 = 0;
hw->b7 = 0;
if (SYN_MODEL_NEWABS(priv->model_id)) { if (SYN_MODEL_NEWABS(priv->model_id)) {
hw->x = (((buf[3] & 0x10) << 8) | hw->x = (((buf[3] & 0x10) << 8) |
...@@ -570,64 +597,47 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -570,64 +597,47 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_sync(dev); input_sync(dev);
} }
static int synaptics_validate_byte(struct psmouse *psmouse)
{
static unsigned char newabs_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
struct synaptics_data *priv = psmouse->private;
int idx = psmouse->pktcnt - 1;
if (SYN_MODEL_NEWABS(priv->model_id))
return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
else
return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
}
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) void 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;
unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
int newabs = SYN_MODEL_NEWABS(priv->model_id);
input_regs(dev, regs); input_regs(dev, regs);
switch (psmouse->pktcnt) { if (psmouse->pktcnt >= 6) { /* Full packet received */
case 1:
if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
goto bad_sync;
}
break;
case 2:
if (!newabs && ((data & 0x60) != 0x00)) {
printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
goto bad_sync;
}
break;
case 4:
if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
goto bad_sync;
}
break;
case 5:
if (!newabs && ((data & 0x60) != 0x00)) {
printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
goto bad_sync;
}
break;
default:
if (psmouse->pktcnt < 6)
break; /* Wait for full packet */
if (priv->out_of_sync) { if (priv->out_of_sync) {
priv->out_of_sync = 0; priv->out_of_sync = 0;
printk(KERN_NOTICE "Synaptics driver resynced.\n"); printk(KERN_NOTICE "Synaptics driver resynced.\n");
} }
if (priv->ptport && synaptics_is_pt_packet(psmouse->packet)) if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
synaptics_pass_pt_packet(priv->ptport, psmouse->packet); synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
else else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
break;
}
return;
bad_sync: } else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) {
priv->out_of_sync++; printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) { if (++priv->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE; psmouse->state = PSMOUSE_IGNORE;
serio_rescan(psmouse->serio); printk(KERN_NOTICE "synaptics: issuing reconnect request\n");
serio_reconnect(psmouse->serio);
}
} }
} }
...@@ -9,11 +9,9 @@ ...@@ -9,11 +9,9 @@
#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 void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_detect(struct psmouse *psmouse);
extern int synaptics_init(struct psmouse *psmouse); extern int synaptics_init(struct psmouse *psmouse);
extern int synaptics_pt_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics queries */ /* synaptics queries */
#define SYN_QUE_IDENTIFY 0x00 #define SYN_QUE_IDENTIFY 0x00
...@@ -105,8 +103,6 @@ struct synaptics_data { ...@@ -105,8 +103,6 @@ struct synaptics_data {
/* Data for normal processing */ /* Data for normal processing */
unsigned int out_of_sync; /* # of packets out of sync */ unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */ int old_w; /* Previous w value */
struct serio *ptport; /* pass-through port */
}; };
#endif /* _SYNAPTICS_H */ #endif /* _SYNAPTICS_H */
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/pm.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -25,19 +28,23 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); ...@@ -25,19 +28,23 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(i8042_noaux, "1i"); static unsigned int i8042_noaux;
MODULE_PARM(i8042_nomux, "1i"); module_param(i8042_noaux, bool, 0);
MODULE_PARM(i8042_unlock, "1i");
MODULE_PARM(i8042_reset, "1i");
MODULE_PARM(i8042_direct, "1i");
MODULE_PARM(i8042_dumbkbd, "1i");
static int i8042_reset; static unsigned int i8042_nomux;
static int i8042_noaux; module_param(i8042_nomux, bool, 0);
static int i8042_nomux;
static int i8042_unlock; static unsigned int i8042_unlock;
static int i8042_direct; module_param(i8042_unlock, bool, 0);
static int i8042_dumbkbd;
static unsigned int i8042_reset;
module_param(i8042_reset, bool, 0);
static unsigned int i8042_direct;
module_param(i8042_direct, bool, 0);
static unsigned int i8042_dumbkbd;
module_param(i8042_dumbkbd, bool, 0);
#undef DEBUG #undef DEBUG
#include "i8042.h" #include "i8042.h"
...@@ -59,6 +66,9 @@ static struct serio i8042_aux_port; ...@@ -59,6 +66,9 @@ static struct serio i8042_aux_port;
static unsigned char i8042_initial_ctr; static unsigned char i8042_initial_ctr;
static unsigned char i8042_ctr; static unsigned char i8042_ctr;
static unsigned char i8042_mux_open; static unsigned char i8042_mux_open;
static unsigned char i8042_mux_present;
static unsigned char i8042_sysdev_initialized;
static struct pm_dev *i8042_pm_dev;
struct timer_list i8042_timer; struct timer_list i8042_timer;
/* /*
...@@ -214,16 +224,41 @@ static int i8042_aux_write(struct serio *port, unsigned char c) ...@@ -214,16 +224,41 @@ static int i8042_aux_write(struct serio *port, unsigned char c)
} }
/* /*
* i8042_open() is called when a port is open by the higher layer. * i8042_activate_port() enables port on a chip.
* It allocates the interrupt and enables it in the chip.
*/ */
static int i8042_open(struct serio *port) static int i8042_activate_port(struct serio *port)
{ {
struct i8042_values *values = port->driver; struct i8042_values *values = port->driver;
i8042_flush(); i8042_flush();
/*
* Enable port again here because it is disabled if we are
* resuming (normally it is enabled already).
*/
i8042_ctr &= ~values->disable;
i8042_ctr |= values->irqen;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
i8042_ctr &= ~values->irqen;
return -1;
}
return 0;
}
/*
* i8042_open() is called when a port is open by the higher layer.
* It allocates the interrupt and calls i8042_enable_port.
*/
static int i8042_open(struct serio *port)
{
struct i8042_values *values = port->driver;
if (values->mux != -1) if (values->mux != -1)
if (i8042_mux_open++) if (i8042_mux_open++)
return 0; return 0;
...@@ -231,21 +266,26 @@ static int i8042_open(struct serio *port) ...@@ -231,21 +266,26 @@ static int i8042_open(struct serio *port)
if (request_irq(values->irq, i8042_interrupt, if (request_irq(values->irq, i8042_interrupt,
SA_SHIRQ, "i8042", i8042_request_irq_cookie)) { SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name); printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
values->exists = 0; goto irq_fail;
serio_unregister_port(port);
return -1;
} }
i8042_ctr |= values->irqen; if (i8042_activate_port(port)) {
printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", values->name);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { goto activate_fail;
printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
return -1;
} }
i8042_interrupt(0, NULL, NULL); i8042_interrupt(0, NULL, NULL);
return 0; return 0;
activate_fail:
free_irq(values->irq, i8042_request_irq_cookie);
irq_fail:
values->exists = 0;
serio_unregister_port_delayed(port);
return -1;
} }
/* /*
...@@ -393,145 +433,78 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -393,145 +433,78 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} }
/* /*
* i8042_controller init initializes the i8042 controller, and, * i8042_enable_mux_mode checks whether the controller has an active
* most importantly, sets it into non-xlated mode if that's * multiplexor and puts the chip into Multiplexed (as opposed to
* desired. * Legacy) mode.
*/ */
static int __init i8042_controller_init(void) static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux_version)
{ {
unsigned char param;
/* /*
* Test the i8042. We need to know if it thinks it's working correctly * Get rid of bytes in the queue.
* before doing anything else.
*/ */
i8042_flush(); i8042_flush();
if (i8042_reset) {
unsigned char param;
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
return -1;
}
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
return -1;
}
}
/* /*
* Save the CTR for restoral on unload / reboot. * Internal loopback test - send three bytes, they should come back from the
* mouse interface, the last should be version. Note that we negate mouseport
* command responses for the i8042_check_aux() routine.
*/ */
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { param = 0xf0;
printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
return -1; return -1;
} param = 0x56;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
i8042_initial_ctr = i8042_ctr;
/*
* Disable the keyboard interface and interrupt.
*/
i8042_ctr |= I8042_CTR_KBDDIS;
i8042_ctr &= ~I8042_CTR_KBDINT;
/*
* Handle keylock.
*/
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
* bother enabling translating and be happy.
*/
if (~i8042_ctr & I8042_CTR_XLATE)
i8042_direct = 1;
/*
* Set nontranslated mode for the kbd interface if requested by an option.
* After this the kbd interface becomes a simple serial in/out, like the aux
* interface is. We don't do this by default, since it can confuse notebook
* BIOSes.
*/
if (i8042_direct) {
i8042_ctr &= ~I8042_CTR_XLATE;
i8042_kbd_port.type = SERIO_8042;
}
/*
* Write CTR back.
*/
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
return -1; return -1;
} param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
return -1;
if (mux_version)
*mux_version = ~param;
return 0; return 0;
} }
/* /*
* Here we try to reset everything back to a state in which the BIOS will be * i8042_enable_mux_ports enables 4 individual AUX ports after
* able to talk to the hardware when rebooting. * the controller has been switched into Multiplexed mode
*/ */
void i8042_controller_cleanup(void) static int i8042_enable_mux_ports(struct i8042_values *values)
{ {
unsigned char param;
int i; int i;
i8042_flush();
/* /*
* Reset anything that is connected to the ports. * Disable all muxed ports by disabling AUX.
*/
if (i8042_kbd_values.exists)
serio_cleanup(&i8042_kbd_port);
if (i8042_aux_values.exists)
serio_cleanup(&i8042_aux_port);
for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists)
serio_cleanup(i8042_mux_port + i);
/*
* Reset the controller.
*/ */
if (i8042_reset) { i8042_ctr |= I8042_CTR_AUXDIS;
unsigned char param; i8042_ctr &= ~I8042_CTR_AUXINT;
if (i8042_command(&param, I8042_CMD_CTL_TEST)) if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
return -1;
} }
/* /*
* Restore the original control register setting. * Enable all muxed ports.
*/ */
i8042_ctr = i8042_initial_ctr; for (i = 0; i < 4; i++) {
i8042_command(&param, I8042_CMD_MUX_PFX + i);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) i8042_command(&param, I8042_CMD_AUX_ENABLE);
printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); }
return 0;
} }
/* /*
* i8042_check_mux() checks whether the controller supports the PS/2 Active * i8042_check_mux() checks whether the controller supports the PS/2 Active
* Multiplexing specification by Synaptics, Phoenix, Insyde and * Multiplexing specification by Synaptics, Phoenix, Insyde and
...@@ -540,66 +513,31 @@ void i8042_controller_cleanup(void) ...@@ -540,66 +513,31 @@ void i8042_controller_cleanup(void)
static int __init i8042_check_mux(struct i8042_values *values) static int __init i8042_check_mux(struct i8042_values *values)
{ {
unsigned char param;
static int i8042_check_mux_cookie; static int i8042_check_mux_cookie;
int i; unsigned char mux_version;
/* /*
* Check if AUX irq is available. * Check if AUX irq is available.
*/ */
if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ, if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
"i8042", &i8042_check_mux_cookie)) "i8042", &i8042_check_mux_cookie))
return -1; return -1;
free_irq(values->irq, &i8042_check_mux_cookie); free_irq(values->irq, &i8042_check_mux_cookie);
/* if (i8042_enable_mux_mode(values, &mux_version))
* Get rid of bytes in the queue.
*/
i8042_flush();
/*
* Internal loopback test - send three bytes, they should come back from the
* mouse interface, the last should be version. Note that we negate mouseport
* command responses for the i8042_check_aux() routine.
*/
param = 0xf0;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
return -1;
param = 0x56;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1;
param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
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",
(~param >> 4) & 0xf, ~param & 0xf); (mux_version >> 4) & 0xf, mux_version & 0xf);
/*
* Disable all muxed ports by disabling AUX.
*/
i8042_ctr |= I8042_CTR_AUXDIS;
i8042_ctr &= ~I8042_CTR_AUXINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) if (i8042_enable_mux_ports(values))
return -1; return -1;
/* i8042_mux_present = 1;
* Enable all muxed ports.
*/
for (i = 0; i < 4; i++) {
i8042_command(&param, I8042_CMD_MUX_PFX + i);
i8042_command(&param, I8042_CMD_AUX_ENABLE);
}
return 0; return 0;
} }
/* /*
* i8042_check_aux() applies as much paranoia as it can at detecting * i8042_check_aux() applies as much paranoia as it can at detecting
* the presence of an AUX interface. * the presence of an AUX interface.
...@@ -675,6 +613,7 @@ static int __init i8042_check_aux(struct i8042_values *values) ...@@ -675,6 +613,7 @@ static int __init i8042_check_aux(struct i8042_values *values)
return 0; return 0;
} }
/* /*
* i8042_port_register() marks the device as existing, * i8042_port_register() marks the device as existing,
* registers it, and reports to the user. * registers it, and reports to the user.
...@@ -691,63 +630,205 @@ static int __init i8042_port_register(struct i8042_values *values, struct serio ...@@ -691,63 +630,205 @@ static int __init i8042_port_register(struct i8042_values *values, struct serio
return -1; return -1;
} }
serio_register_port(port);
printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
values->name, values->name,
(unsigned long) I8042_DATA_REG, (unsigned long) I8042_DATA_REG,
(unsigned long) I8042_COMMAND_REG, (unsigned long) I8042_COMMAND_REG,
values->irq); values->irq);
serio_register_port(port);
return 0; return 0;
} }
static void i8042_timer_func(unsigned long data) static void i8042_timer_func(unsigned long data)
{ {
i8042_interrupt(0, NULL, NULL); i8042_interrupt(0, NULL, NULL);
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
} }
#ifndef MODULE
static int __init i8042_setup_reset(char *str) /*
{ * i8042_controller init initializes the i8042 controller, and,
i8042_reset = 1; * most importantly, sets it into non-xlated mode if that's
return 1; * desired.
} */
static int __init i8042_setup_noaux(char *str)
{ static int i8042_controller_init(void)
i8042_noaux = 1;
i8042_nomux = 1;
return 1;
}
static int __init i8042_setup_nomux(char *str)
{ {
if (i8042_noaux)
i8042_nomux = 1; i8042_nomux = 1;
return 1; /*
} * Test the i8042. We need to know if it thinks it's working correctly
static int __init i8042_setup_unlock(char *str) * before doing anything else.
{ */
i8042_unlock = 1;
return 1; i8042_flush();
if (i8042_reset) {
unsigned char param;
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
return -1;
}
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
return -1;
}
}
/*
* Save the CTR for restoral on unload / reboot.
*/
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
return -1;
}
i8042_initial_ctr = i8042_ctr;
/*
* Disable the keyboard interface and interrupt.
*/
i8042_ctr |= I8042_CTR_KBDDIS;
i8042_ctr &= ~I8042_CTR_KBDINT;
/*
* Handle keylock.
*/
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
* bother enabling translating and be happy.
*/
if (~i8042_ctr & I8042_CTR_XLATE)
i8042_direct = 1;
/*
* Set nontranslated mode for the kbd interface if requested by an option.
* After this the kbd interface becomes a simple serial in/out, like the aux
* interface is. We don't do this by default, since it can confuse notebook
* BIOSes.
*/
if (i8042_direct) {
i8042_ctr &= ~I8042_CTR_XLATE;
i8042_kbd_port.type = SERIO_8042;
}
/*
* Write CTR back.
*/
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
return -1;
}
return 0;
} }
static int __init i8042_setup_direct(char *str)
/*
* Here we try to reset everything back to a state in which the BIOS will be
* able to talk to the hardware when rebooting.
*/
void i8042_controller_cleanup(void)
{ {
i8042_direct = 1; int i;
return 1;
i8042_flush();
/*
* Reset anything that is connected to the ports.
*/
if (i8042_kbd_values.exists)
serio_cleanup(&i8042_kbd_port);
if (i8042_aux_values.exists)
serio_cleanup(&i8042_aux_port);
for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists)
serio_cleanup(i8042_mux_port + i);
/*
* Reset the controller.
*/
if (i8042_reset) {
unsigned char param;
if (i8042_command(&param, I8042_CMD_CTL_TEST))
printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
}
/*
* Restore the original control register setting.
*/
i8042_ctr = i8042_initial_ctr;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
} }
static int __init i8042_setup_dumbkbd(char *str)
/*
* Here we try to reset everything back to a state in which suspended
*/
static int i8042_controller_resume(void)
{ {
i8042_dumbkbd = 1; int i;
return 1;
if (i8042_controller_init()) {
printk(KERN_ERR "i8042: resume failed\n");
return -1;
}
if (i8042_mux_present)
if (i8042_enable_mux_mode(&i8042_aux_values, NULL) ||
i8042_enable_mux_ports(&i8042_aux_values)) {
printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't wotk.\n");
}
/*
* Reconnect anything that was connected to the ports.
*/
if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0)
serio_reconnect(&i8042_kbd_port);
if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0)
serio_reconnect(&i8042_aux_port);
for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0)
serio_reconnect(i8042_mux_port + i);
return 0;
} }
__setup("i8042_reset", i8042_setup_reset);
__setup("i8042_noaux", i8042_setup_noaux);
__setup("i8042_nomux", i8042_setup_nomux);
__setup("i8042_unlock", i8042_setup_unlock);
__setup("i8042_direct", i8042_setup_direct);
__setup("i8042_dumbkbd", i8042_setup_dumbkbd);
#endif
/* /*
* We need to reset the 8042 back to original mode on system shutdown, * We need to reset the 8042 back to original mode on system shutdown,
...@@ -769,6 +850,35 @@ static struct notifier_block i8042_notifier= ...@@ -769,6 +850,35 @@ static struct notifier_block i8042_notifier=
0 0
}; };
/*
* Resume handler for the new PM scheme (driver model)
*/
static int i8042_resume(struct sys_device *dev)
{
return i8042_controller_resume();
}
static struct sysdev_class kbc_sysclass = {
set_kset_name("i8042"),
.resume = i8042_resume,
};
static struct sys_device device_i8042 = {
.id = 0,
.cls = &kbc_sysclass,
};
/*
* Resume handler for the old PM scheme (APM)
*/
static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dummy)
{
if (request == PM_RESUME)
return i8042_controller_resume();
return 0;
}
static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index)
{ {
memcpy(port, &i8042_aux_port, sizeof(struct serio)); memcpy(port, &i8042_aux_port, sizeof(struct serio));
...@@ -817,6 +927,15 @@ int __init i8042_init(void) ...@@ -817,6 +927,15 @@ int __init i8042_init(void)
i8042_timer.function = i8042_timer_func; i8042_timer.function = i8042_timer_func;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
if (sysdev_class_register(&kbc_sysclass) == 0) {
if (sys_device_register(&device_i8042) == 0)
i8042_sysdev_initialized = 1;
else
sysdev_class_unregister(&kbc_sysclass);
}
i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback);
register_reboot_notifier(&i8042_notifier); register_reboot_notifier(&i8042_notifier);
return 0; return 0;
...@@ -828,6 +947,14 @@ void __exit i8042_exit(void) ...@@ -828,6 +947,14 @@ void __exit i8042_exit(void)
unregister_reboot_notifier(&i8042_notifier); unregister_reboot_notifier(&i8042_notifier);
if (i8042_pm_dev)
pm_unregister(i8042_pm_dev);
if (i8042_sysdev_initialized) {
sys_device_unregister(&device_i8042);
sysdev_class_unregister(&kbc_sysclass);
}
del_timer(&i8042_timer); del_timer(&i8042_timer);
i8042_controller_cleanup(); i8042_controller_cleanup();
......
...@@ -49,14 +49,17 @@ MODULE_LICENSE("GPL"); ...@@ -49,14 +49,17 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_register_slave_port); EXPORT_SYMBOL(serio_register_port_delayed);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_slave_port); EXPORT_SYMBOL(serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_unregister_port);
EXPORT_SYMBOL(serio_register_device); EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device); EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_rescan);
EXPORT_SYMBOL(serio_reconnect);
struct serio_event { struct serio_event {
int type; int type;
...@@ -83,10 +86,22 @@ static void serio_find_dev(struct serio *serio) ...@@ -83,10 +86,22 @@ static void serio_find_dev(struct serio *serio)
} }
#define SERIO_RESCAN 1 #define SERIO_RESCAN 1
#define SERIO_RECONNECT 2
#define SERIO_REGISTER_PORT 3
#define SERIO_UNREGISTER_PORT 4
static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited); static DECLARE_COMPLETION(serio_exited);
static void serio_invalidate_pending_events(struct serio *serio)
{
struct serio_event *event;
list_for_each_entry(event, &serio_event_list, node)
if (event->serio == serio)
event->serio = NULL;
}
void serio_handle_events(void) void serio_handle_events(void)
{ {
struct list_head *node, *next; struct list_head *node, *next;
...@@ -95,17 +110,35 @@ void serio_handle_events(void) ...@@ -95,17 +110,35 @@ void serio_handle_events(void)
list_for_each_safe(node, next, &serio_event_list) { list_for_each_safe(node, next, &serio_event_list) {
event = container_of(node, struct serio_event, node); event = container_of(node, struct serio_event, node);
down(&serio_sem);
if (event->serio == NULL)
goto event_done;
switch (event->type) { switch (event->type) {
case SERIO_REGISTER_PORT :
__serio_register_port(event->serio);
break;
case SERIO_UNREGISTER_PORT :
__serio_unregister_port(event->serio);
break;
case SERIO_RECONNECT :
if (event->serio->dev && event->serio->dev->reconnect)
if (event->serio->dev->reconnect(event->serio) == 0)
break;
/* reconnect failed - fall through to rescan */
case SERIO_RESCAN : case SERIO_RESCAN :
down(&serio_sem);
if (event->serio->dev && event->serio->dev->disconnect) if (event->serio->dev && event->serio->dev->disconnect)
event->serio->dev->disconnect(event->serio); event->serio->dev->disconnect(event->serio);
serio_find_dev(event->serio); serio_find_dev(event->serio);
up(&serio_sem);
break; break;
default: default:
break; break;
} }
event_done:
up(&serio_sem);
list_del_init(node); list_del_init(node);
kfree(event); kfree(event);
} }
...@@ -130,18 +163,27 @@ static int serio_thread(void *nothing) ...@@ -130,18 +163,27 @@ static int serio_thread(void *nothing)
complete_and_exit(&serio_exited, 0); complete_and_exit(&serio_exited, 0);
} }
void serio_rescan(struct serio *serio) static void serio_queue_event(struct serio *serio, int event_type)
{ {
struct serio_event *event; struct serio_event *event;
if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
return; event->type = event_type;
event->type = SERIO_RESCAN;
event->serio = serio; event->serio = serio;
list_add_tail(&event->node, &serio_event_list); list_add_tail(&event->node, &serio_event_list);
wake_up(&serio_wait); wake_up(&serio_wait);
}
}
void serio_rescan(struct serio *serio)
{
serio_queue_event(serio, SERIO_RESCAN);
}
void serio_reconnect(struct serio *serio)
{
serio_queue_event(serio, SERIO_RECONNECT);
} }
irqreturn_t serio_interrupt(struct serio *serio, irqreturn_t serio_interrupt(struct serio *serio,
...@@ -163,17 +205,26 @@ irqreturn_t serio_interrupt(struct serio *serio, ...@@ -163,17 +205,26 @@ irqreturn_t serio_interrupt(struct serio *serio,
void serio_register_port(struct serio *serio) void serio_register_port(struct serio *serio)
{ {
down(&serio_sem); down(&serio_sem);
list_add_tail(&serio->node, &serio_list); __serio_register_port(serio);
serio_find_dev(serio);
up(&serio_sem); up(&serio_sem);
} }
/* /*
* Same as serio_register_port but does not try to acquire serio_sem. * Submits register request to kseriod for subsequent execution.
* Should be used when registering a serio from other input device's * Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
*/
void serio_register_port_delayed(struct serio *serio)
{
serio_queue_event(serio, SERIO_REGISTER_PORT);
}
/*
* Should only be called directly if serio_sem has already been taken,
* for example when unregistering a serio from other input device's
* connect() function. * connect() function.
*/ */
void serio_register_slave_port(struct serio *serio) void __serio_register_port(struct serio *serio)
{ {
list_add_tail(&serio->node, &serio_list); list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio); serio_find_dev(serio);
...@@ -182,19 +233,28 @@ void serio_register_slave_port(struct serio *serio) ...@@ -182,19 +233,28 @@ void serio_register_slave_port(struct serio *serio)
void serio_unregister_port(struct serio *serio) void serio_unregister_port(struct serio *serio)
{ {
down(&serio_sem); down(&serio_sem);
list_del_init(&serio->node); __serio_unregister_port(serio);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
up(&serio_sem); up(&serio_sem);
} }
/* /*
* Same as serio_unregister_port but does not try to acquire serio_sem. * Submits unregister request to kseriod for subsequent execution.
* Should be used when unregistering a serio from other input device's * Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
*/
void serio_unregister_port_delayed(struct serio *serio)
{
serio_queue_event(serio, SERIO_UNREGISTER_PORT);
}
/*
* Should only be called directly if serio_sem has already been taken,
* for example when unregistering a serio from other input device's
* disconnect() function. * disconnect() function.
*/ */
void serio_unregister_slave_port(struct serio *serio) void __serio_unregister_port(struct serio *serio)
{ {
serio_invalidate_pending_events(serio);
list_del_init(&serio->node); list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect) if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio); serio->dev->disconnect(serio);
......
...@@ -16,9 +16,13 @@ ...@@ -16,9 +16,13 @@
* General Public License for more details. * General Public License for more details.
* *
******************************************************************************/ ******************************************************************************/
#define QLA1280_VERSION "3.23.37" #define QLA1280_VERSION "3.23.37.1"
/***************************************************************************** /*****************************************************************************
Revision History: Revision History:
Rev 3.23.37.1 December 17, 2003, Jes Sorensen
- Delete completion queue from srb if mailbox command failed to
to avoid qla1280_done completeting qla1280_error_action's
obsolete context
Rev 3.23.37 October 1, 2003, Jes Sorensen Rev 3.23.37 October 1, 2003, Jes Sorensen
- Make MMIO depend on CONFIG_X86_VISWS instead of yet another - Make MMIO depend on CONFIG_X86_VISWS instead of yet another
random CONFIG option random CONFIG option
...@@ -1464,8 +1468,15 @@ qla1280_error_action(Scsi_Cmnd * cmd, enum action action) ...@@ -1464,8 +1468,15 @@ qla1280_error_action(Scsi_Cmnd * cmd, enum action action)
/* If we didn't manage to issue the action, or we have no /* If we didn't manage to issue the action, or we have no
* command to wait for, exit here */ * command to wait for, exit here */
if (result == FAILED || handle == NULL || if (result == FAILED || handle == NULL ||
handle == (unsigned char *)INVALID_HANDLE) handle == (unsigned char *)INVALID_HANDLE) {
/*
* Clear completion queue to avoid qla1280_done() trying
* to complete the command at a later stage after we
* have exited the current context
*/
sp->wait = NULL;
goto leave; goto leave;
}
/* set up a timer just in case we're really jammed */ /* set up a timer just in case we're really jammed */
init_timer(&timer); init_timer(&timer);
......
...@@ -261,7 +261,6 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) ...@@ -261,7 +261,6 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
spin_lock(&ps->lock); spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed); list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock); spin_unlock(&ps->lock);
wake_up(&ps->wait);
if (as->signr) { if (as->signr) {
sinfo.si_signo = as->signr; sinfo.si_signo = as->signr;
sinfo.si_errno = as->urb->status; sinfo.si_errno = as->urb->status;
...@@ -269,6 +268,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) ...@@ -269,6 +268,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
sinfo.si_addr = (void *)as->userurb; sinfo.si_addr = (void *)as->userurb;
send_sig_info(as->signr, &sinfo, as->task); send_sig_info(as->signr, &sinfo, as->task);
} }
wake_up(&ps->wait);
} }
static void destroy_async (struct dev_state *ps, struct list_head *list) static void destroy_async (struct dev_state *ps, struct list_head *list)
......
...@@ -692,6 +692,9 @@ static int hub_port_status(struct usb_device *dev, int port, ...@@ -692,6 +692,9 @@ static int hub_port_status(struct usb_device *dev, int port,
struct usb_hub *hub = usb_get_intfdata(dev->actconfig->interface[0]); struct usb_hub *hub = usb_get_intfdata(dev->actconfig->interface[0]);
int ret; int ret;
if (!hub)
return -ENODEV;
ret = get_port_status(dev, port + 1, &hub->status->port); ret = get_port_status(dev, port + 1, &hub->status->port);
if (ret < 0) if (ret < 0)
dev_err (hubdev (dev), dev_err (hubdev (dev),
...@@ -926,7 +929,6 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -926,7 +929,6 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
break; break;
} }
hub->children[port] = dev;
dev->state = USB_STATE_POWERED; dev->state = USB_STATE_POWERED;
/* Reset the device, and detect its speed */ /* Reset the device, and detect its speed */
...@@ -979,8 +981,10 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -979,8 +981,10 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
dev->dev.parent = dev->parent->dev.parent->parent; dev->dev.parent = dev->parent->dev.parent->parent;
/* Run it through the hoops (find a driver, etc) */ /* Run it through the hoops (find a driver, etc) */
if (!usb_new_device(dev, &hub->dev)) if (!usb_new_device(dev, &hub->dev)) {
hub->children[port] = dev;
goto done; goto done;
}
/* Free the configuration if there was an error */ /* Free the configuration if there was an error */
usb_put_dev(dev); usb_put_dev(dev);
...@@ -989,7 +993,6 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -989,7 +993,6 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
delay = HUB_LONG_RESET_TIME; delay = HUB_LONG_RESET_TIME;
} }
hub->children[port] = NULL;
hub_port_disable(hub, port); hub_port_disable(hub, port);
done: done:
up(&usb_address0_sem); up(&usb_address0_sem);
...@@ -1342,6 +1345,7 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1342,6 +1345,7 @@ int usb_physical_reset_device(struct usb_device *dev)
dev->devpath, ret); dev->devpath, ret);
return ret; return ret;
} }
dev->state = USB_STATE_CONFIGURED;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf = dev->actconfig->interface[i]; struct usb_interface *intf = dev->actconfig->interface[i];
......
...@@ -1120,6 +1120,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1120,6 +1120,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
if (err) { if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n", dev_err(&dev->dev, "can't set config #%d, error %d\n",
dev->config[0].desc.bConfigurationValue, err); dev->config[0].desc.bConfigurationValue, err);
device_del(&dev->dev);
goto fail; goto fail;
} }
......
...@@ -2182,6 +2182,9 @@ static int uhci_reset(struct usb_hcd *hcd) ...@@ -2182,6 +2182,9 @@ static int uhci_reset(struct usb_hcd *hcd)
uhci->io_addr = (unsigned long) hcd->regs; uhci->io_addr = (unsigned long) hcd->regs;
/* Turn off all interrupts */
outw(0, uhci->io_addr + USBINTR);
/* Maybe kick BIOS off this hardware. Then reset, so we won't get /* Maybe kick BIOS off this hardware. Then reset, so we won't get
* interrupts from any previous setup. * interrupts from any previous setup.
*/ */
......
...@@ -18,13 +18,15 @@ config USB_MDC800 ...@@ -18,13 +18,15 @@ config USB_MDC800
module will be called mdc800. module will be called mdc800.
config USB_SCANNER config USB_SCANNER
tristate "USB Scanner support" tristate "USB Scanner support (OBSOLETE)"
depends on USB depends on USB
help help
Say Y here if you want to connect a USB scanner to your computer's Say Y here if you want to connect a USB scanner to your computer's
USB port. Please read <file:Documentation/usb/scanner.txt> for more USB port. Please read <file:Documentation/usb/scanner.txt> for more
information. information.
This driver has been obsoleted by support via libusb.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called scanner. module will be called scanner.
......
...@@ -324,7 +324,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs) ...@@ -324,7 +324,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs)
urb = acep->urbp; urb = acep->urbp;
dbg ("auerchain_complete: submitting next urb from chain"); dbg ("auerchain_complete: submitting next urb from chain");
urb->status = 0; /* needed! */ urb->status = 0; /* needed! */
result = usb_submit_urb(urb, GFP_KERNEL); result = usb_submit_urb(urb, GFP_ATOMIC);
/* check for submit errors */ /* check for submit errors */
if (result) { if (result) {
...@@ -402,7 +402,7 @@ static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int ea ...@@ -402,7 +402,7 @@ static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int ea
if (acep) { if (acep) {
dbg("submitting urb immediate"); dbg("submitting urb immediate");
urb->status = 0; /* needed! */ urb->status = 0; /* needed! */
result = usb_submit_urb(urb, GFP_KERNEL); result = usb_submit_urb(urb, GFP_ATOMIC);
/* check for submit errors */ /* check for submit errors */
if (result) { if (result) {
urb->status = result; urb->status = result;
......
...@@ -493,12 +493,15 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -493,12 +493,15 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
return retval; return retval;
} }
static void __serial_close(struct usb_serial_port *port, struct file *filp) static void serial_close(struct tty_struct *tty, struct file * filp)
{ {
if (!port->open_count) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
dbg ("%s - port not opened", __FUNCTION__); struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return; return;
}
dbg("%s - port %d", __FUNCTION__, port->number);
--port->open_count; --port->open_count;
if (port->open_count <= 0) { if (port->open_count <= 0) {
...@@ -506,30 +509,18 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp) ...@@ -506,30 +509,18 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp)
* port is being closed by the last owner */ * port is being closed by the last owner */
port->serial->type->close(port, filp); port->serial->type->close(port, filp);
port->open_count = 0; port->open_count = 0;
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
} }
module_put(port->serial->type->owner); module_put(port->serial->type->owner);
kobject_put(&port->serial->kobj); kobject_put(&port->serial->kobj);
} }
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
dbg("%s - port %d", __FUNCTION__, port->number);
/* if disconnect beat us to the punch here, there's nothing to do */
if (tty && tty->driver_data) {
__serial_close(port, filp);
tty->driver_data = NULL;
}
port->tty = NULL;
}
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{ {
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
...@@ -848,19 +839,6 @@ static void destroy_serial (struct kobject *kobj) ...@@ -848,19 +839,6 @@ static void destroy_serial (struct kobject *kobj)
dbg ("%s - %s", __FUNCTION__, kobj->name); dbg ("%s - %s", __FUNCTION__, kobj->name);
serial = to_usb_serial(kobj); serial = to_usb_serial(kobj);
/* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port->tty != NULL) {
port->tty->driver_data = NULL;
while (port->open_count > 0) {
__serial_close(port, NULL);
}
port->tty = NULL;
}
}
serial_shutdown (serial); serial_shutdown (serial);
/* return the minor range that this device had */ /* return the minor range that this device had */
...@@ -1242,7 +1220,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1242,7 +1220,7 @@ int usb_serial_probe(struct usb_interface *interface,
/* register all of the individual ports with the driver core */ /* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) { for (i = 0; i < num_ports; ++i) {
port = serial->port[i]; port = serial->port[i];
port->dev.parent = &serial->dev->dev; port->dev.parent = &interface->dev;
port->dev.driver = NULL; port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type; port->dev.bus = &usb_serial_bus_type;
port->dev.release = &port_release; port->dev.release = &port_release;
......
...@@ -387,7 +387,7 @@ static int datafab_id_device(struct us_data *us, ...@@ -387,7 +387,7 @@ static int datafab_id_device(struct us_data *us,
// we'll go ahead and extract the media capacity while we're here... // we'll go ahead and extract the media capacity while we're here...
// //
rc = datafab_bulk_read(us, reply, sizeof(reply)); rc = datafab_bulk_read(us, reply, 512);
if (rc == USB_STOR_XFER_GOOD) { if (rc == USB_STOR_XFER_GOOD) {
// capacity is at word offset 57-58 // capacity is at word offset 57-58
// //
......
...@@ -317,7 +317,7 @@ static int jumpshot_id_device(struct us_data *us, ...@@ -317,7 +317,7 @@ static int jumpshot_id_device(struct us_data *us,
} }
// read the reply // read the reply
rc = jumpshot_bulk_read(us, reply, sizeof(reply)); rc = jumpshot_bulk_read(us, reply, 512);
if (rc != USB_STOR_XFER_GOOD) { if (rc != USB_STOR_XFER_GOOD) {
rc = USB_STOR_TRANSPORT_ERROR; rc = USB_STOR_TRANSPORT_ERROR;
goto leave; goto leave;
......
...@@ -24,6 +24,7 @@ extern void disable_irq(unsigned int); ...@@ -24,6 +24,7 @@ extern void disable_irq(unsigned int);
extern void disable_irq_nosync(unsigned int); extern void disable_irq_nosync(unsigned int);
extern void enable_irq(unsigned int); extern void enable_irq(unsigned int);
extern void release_x86_irqs(struct task_struct *); extern void release_x86_irqs(struct task_struct *);
extern int can_request_irq(unsigned int, unsigned long flags);
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
......
...@@ -870,6 +870,7 @@ struct input_handler { ...@@ -870,6 +870,7 @@ struct input_handler {
char *name; char *name;
struct input_device_id *id_table; struct input_device_id *id_table;
struct input_device_id *blacklist;
struct list_head h_list; struct list_head h_list;
struct list_head node; struct list_head node;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define __LINUX_KEYBOARD_H #define __LINUX_KEYBOARD_H
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/input.h>
#define KG_SHIFT 0 #define KG_SHIFT 0
#define KG_CTRL 2 #define KG_CTRL 2
...@@ -17,7 +16,7 @@ ...@@ -17,7 +16,7 @@
#define NR_SHIFT 9 #define NR_SHIFT 9
#define NR_KEYS (KEY_MAX+1) #define NR_KEYS 255
#define MAX_NR_KEYMAPS 256 #define MAX_NR_KEYMAPS 256
/* This means 128Kb if all keymaps are allocated. Only the superuser /* This means 128Kb if all keymaps are allocated. Only the superuser
may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */ may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
......
...@@ -49,6 +49,7 @@ struct serio_dev { ...@@ -49,6 +49,7 @@ struct serio_dev {
irqreturn_t (*interrupt)(struct serio *, unsigned char, irqreturn_t (*interrupt)(struct serio *, unsigned char,
unsigned int, struct pt_regs *); unsigned int, struct pt_regs *);
void (*connect)(struct serio *, struct serio_dev *dev); void (*connect)(struct serio *, struct serio_dev *dev);
int (*reconnect)(struct serio *);
void (*disconnect)(struct serio *); void (*disconnect)(struct serio *);
void (*cleanup)(struct serio *); void (*cleanup)(struct serio *);
...@@ -58,12 +59,15 @@ struct serio_dev { ...@@ -58,12 +59,15 @@ struct serio_dev {
int serio_open(struct serio *serio, struct serio_dev *dev); int serio_open(struct serio *serio, struct serio_dev *dev);
void serio_close(struct serio *serio); void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio); void serio_rescan(struct serio *serio);
void serio_reconnect(struct serio *serio);
irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs); irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
void serio_register_port(struct serio *serio); void serio_register_port(struct serio *serio);
void serio_register_slave_port(struct serio *serio); void serio_register_port_delayed(struct serio *serio);
void __serio_register_port(struct serio *serio);
void serio_unregister_port(struct serio *serio); void serio_unregister_port(struct serio *serio);
void serio_unregister_slave_port(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio);
void __serio_unregister_port(struct serio *serio);
void serio_register_device(struct serio_dev *dev); void serio_register_device(struct serio_dev *dev);
void serio_unregister_device(struct serio_dev *dev); void serio_unregister_device(struct serio_dev *dev);
......
...@@ -1470,6 +1470,7 @@ void scheduling_functions_start_here(void) { } ...@@ -1470,6 +1470,7 @@ void scheduling_functions_start_here(void) { }
*/ */
asmlinkage void schedule(void) asmlinkage void schedule(void)
{ {
long *switch_count;
task_t *prev, *next; task_t *prev, *next;
runqueue_t *rq; runqueue_t *rq;
prio_array_t *array; prio_array_t *array;
...@@ -1516,33 +1517,26 @@ asmlinkage void schedule(void) ...@@ -1516,33 +1517,26 @@ asmlinkage void schedule(void)
* if entering off of a kernel preemption go straight * if entering off of a kernel preemption go straight
* to picking the next task. * to picking the next task.
*/ */
if (unlikely(preempt_count() & PREEMPT_ACTIVE)) switch_count = &prev->nivcsw;
goto pick_next_task; if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
switch_count = &prev->nvcsw;
switch (prev->state) { if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
case TASK_INTERRUPTIBLE: unlikely(signal_pending(prev))))
if (unlikely(signal_pending(prev))) {
prev->state = TASK_RUNNING; prev->state = TASK_RUNNING;
break; else
}
default:
deactivate_task(prev, rq); deactivate_task(prev, rq);
prev->nvcsw++;
break;
case TASK_RUNNING:
prev->nivcsw++;
} }
pick_next_task:
if (unlikely(!rq->nr_running)) { if (unlikely(!rq->nr_running)) {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
load_balance(rq, 1, cpu_to_node_mask(smp_processor_id())); load_balance(rq, 1, cpu_to_node_mask(smp_processor_id()));
if (rq->nr_running)
goto pick_next_task;
#endif #endif
if (!rq->nr_running) {
next = rq->idle; next = rq->idle;
rq->expired_timestamp = 0; rq->expired_timestamp = 0;
goto switch_tasks; goto switch_tasks;
} }
}
array = rq->active; array = rq->active;
if (unlikely(!array->nr_active)) { if (unlikely(!array->nr_active)) {
...@@ -1588,6 +1582,7 @@ asmlinkage void schedule(void) ...@@ -1588,6 +1582,7 @@ asmlinkage void schedule(void)
next->timestamp = now; next->timestamp = now;
rq->nr_switches++; rq->nr_switches++;
rq->curr = next; rq->curr = next;
++*switch_count;
prepare_arch_switch(rq, next); prepare_arch_switch(rq, next);
prev = context_switch(rq, prev, next); prev = context_switch(rq, prev, next);
......
...@@ -236,8 +236,6 @@ static void unlink(struct kobject * kobj) ...@@ -236,8 +236,6 @@ static void unlink(struct kobject * kobj)
list_del_init(&kobj->entry); list_del_init(&kobj->entry);
up_write(&kobj->kset->subsys->rwsem); up_write(&kobj->kset->subsys->rwsem);
} }
if (kobj->parent)
kobject_put(kobj->parent);
kobject_put(kobj); kobject_put(kobj);
} }
...@@ -274,9 +272,11 @@ int kobject_add(struct kobject * kobj) ...@@ -274,9 +272,11 @@ int kobject_add(struct kobject * kobj)
kobj->parent = parent; kobj->parent = parent;
error = create_dir(kobj); error = create_dir(kobj);
if (error) if (error) {
unlink(kobj); unlink(kobj);
else { if (parent)
kobject_put(parent);
} else {
/* If this kobj does not belong to a kset, /* If this kobj does not belong to a kset,
try to find a parent that does. */ try to find a parent that does. */
top_kobj = kobj; top_kobj = kobj;
...@@ -452,6 +452,7 @@ void kobject_cleanup(struct kobject * kobj) ...@@ -452,6 +452,7 @@ void kobject_cleanup(struct kobject * kobj)
{ {
struct kobj_type * t = get_ktype(kobj); struct kobj_type * t = get_ktype(kobj);
struct kset * s = kobj->kset; struct kset * s = kobj->kset;
struct kobject * parent = kobj->parent;
pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
if (kobj->k_name != kobj->name) if (kobj->k_name != kobj->name)
...@@ -461,6 +462,8 @@ void kobject_cleanup(struct kobject * kobj) ...@@ -461,6 +462,8 @@ void kobject_cleanup(struct kobject * kobj)
t->release(kobj); t->release(kobj);
if (s) if (s)
kset_put(s); kset_put(s);
if (parent)
kobject_put(parent);
} }
/** /**
......
...@@ -52,6 +52,13 @@ static int do_usb_entry(const char *filename, ...@@ -52,6 +52,13 @@ static int do_usb_entry(const char *filename,
id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo); id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi); id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
/*
* Some modules (visor) have empty slots as placeholder for
* run-time specification that results in catch-all alias
*/
if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
return 1;
strcpy(alias, "usb:"); strcpy(alias, "usb:");
ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
id->idVendor); id->idVendor);
......
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