Commit 361d16e2 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/disk1/davem/BK/sparcwork-2.5

into nuts.ninka.net:/disk1/davem/BK/sparc-2.5
parents e2990ed5 e241138a
...@@ -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
......
...@@ -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);
......
...@@ -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) {
......
...@@ -17,7 +17,7 @@ config WATCHDOG ...@@ -17,7 +17,7 @@ config WATCHDOG
implementation entirely in software (which can sometimes fail to implementation entirely in software (which can sometimes fail to
reboot the machine) and a driver for hardware watchdog boards, which reboot the machine) and a driver for hardware watchdog boards, which
are more robust and can also keep track of the temperature inside are more robust and can also keep track of the temperature inside
your computer. For details, read <file:Documentation/watchdog.txt> your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
in the kernel source. in the kernel source.
The watchdog is usually used together with the watchdog daemon The watchdog is usually used together with the watchdog daemon
...@@ -114,7 +114,7 @@ config PCWATCHDOG ...@@ -114,7 +114,7 @@ config PCWATCHDOG
This card simply watches your kernel to make sure it doesn't freeze, This card simply watches your kernel to make sure it doesn't freeze,
and if it does, it reboots your computer after a certain amount of and if it does, it reboots your computer after a certain amount of
time. This driver is like the WDT501 driver but for different time. This driver is like the WDT501 driver but for different
hardware. Please read <file:Documentation/pcwd-watchdog.txt>. The PC hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
watchdog cards can be ordered from <http://www.berkprod.com/>. watchdog cards can be ordered from <http://www.berkprod.com/>.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
......
...@@ -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);
......
...@@ -3910,7 +3910,6 @@ static void bond_free_all(void) ...@@ -3910,7 +3910,6 @@ static void bond_free_all(void)
unregister_netdevice(dev); unregister_netdevice(dev);
bond_deinit(dev); bond_deinit(dev);
free_netdev(dev);
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -4008,6 +4007,8 @@ static int __init bond_init(struct net_device *dev) ...@@ -4008,6 +4007,8 @@ static int __init bond_init(struct net_device *dev)
bond_create_proc_info(bond); bond_create_proc_info(bond);
#endif #endif
dev->destructor = free_netdev;
list_add_tail(&bond->bond_list, &bond_dev_list); list_add_tail(&bond->bond_list, &bond_dev_list);
return 0; return 0;
......
...@@ -1092,8 +1092,12 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) ...@@ -1092,8 +1092,12 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
{ {
struct el3_private *lp = (struct el3_private *)dev->priv; struct el3_private *lp = (struct el3_private *)dev->priv;
if (netif_device_present(dev)) if (netif_device_present(dev)) {
unsigned long flags;
spin_lock_irqsave(&lp->window_lock, flags);
update_stats(dev); update_stats(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
}
return &lp->stats; return &lp->stats;
} }
...@@ -1105,7 +1109,6 @@ static void update_stats(struct net_device *dev) ...@@ -1105,7 +1109,6 @@ static void update_stats(struct net_device *dev)
{ {
struct el3_private *lp = (struct el3_private *)dev->priv; struct el3_private *lp = (struct el3_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr; ioaddr_t ioaddr = dev->base_addr;
unsigned long flags;
u8 rx, tx, up; u8 rx, tx, up;
DEBUG(2, "%s: updating the statistics.\n", dev->name); DEBUG(2, "%s: updating the statistics.\n", dev->name);
...@@ -1113,8 +1116,6 @@ static void update_stats(struct net_device *dev) ...@@ -1113,8 +1116,6 @@ static void update_stats(struct net_device *dev)
if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */ if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
return; return;
spin_lock_irqsave(&lp->window_lock, flags);
/* Unlike the 3c509 we need not turn off stats updates while reading. */ /* Unlike the 3c509 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */ /* Switch to the stats window, and read everything. */
EL3WINDOW(6); EL3WINDOW(6);
...@@ -1139,7 +1140,6 @@ static void update_stats(struct net_device *dev) ...@@ -1139,7 +1140,6 @@ static void update_stats(struct net_device *dev)
lp->stats.tx_bytes += tx + ((up & 0xf0) << 12); lp->stats.tx_bytes += tx + ((up & 0xf0) << 12);
EL3WINDOW(1); EL3WINDOW(1);
spin_unlock_irqrestore(&lp->window_lock, flags);
} }
static int el3_rx(struct net_device *dev, int worklimit) static int el3_rx(struct net_device *dev, int worklimit)
...@@ -1281,6 +1281,8 @@ static int el3_close(struct net_device *dev) ...@@ -1281,6 +1281,8 @@ static int el3_close(struct net_device *dev)
DEBUG(2, "%s: shutting down ethercard.\n", dev->name); DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
if (DEV_OK(link)) { if (DEV_OK(link)) {
unsigned long flags;
/* Turn off statistics ASAP. We update lp->stats below. */ /* Turn off statistics ASAP. We update lp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD); outw(StatsDisable, ioaddr + EL3_CMD);
...@@ -1290,8 +1292,9 @@ static int el3_close(struct net_device *dev) ...@@ -1290,8 +1292,9 @@ static int el3_close(struct net_device *dev)
/* Note: Switching to window 0 may disable the IRQ. */ /* Note: Switching to window 0 may disable the IRQ. */
EL3WINDOW(0); EL3WINDOW(0);
spin_lock_irqsave(&lp->window_lock, flags);
update_stats(dev); update_stats(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
} }
link->open--; link->open--;
......
...@@ -107,7 +107,7 @@ config TMS380TR ...@@ -107,7 +107,7 @@ config TMS380TR
config TMSPCI config TMSPCI
tristate "Generic TMS380 PCI support" tristate "Generic TMS380 PCI support"
depends on TR && TMS380TR!=n && PCI depends on TR && TMS380TR && PCI
---help--- ---help---
This tms380 module supports generic TMS380-based PCI cards. This tms380 module supports generic TMS380-based PCI cards.
...@@ -122,7 +122,7 @@ config TMSPCI ...@@ -122,7 +122,7 @@ config TMSPCI
config SKISA config SKISA
tristate "SysKonnect TR4/16 ISA support" tristate "SysKonnect TR4/16 ISA support"
depends on TR && TMS380TR!=n && ISA depends on TR && TMS380TR && ISA
help help
This tms380 module supports SysKonnect TR4/16 ISA cards. This tms380 module supports SysKonnect TR4/16 ISA cards.
...@@ -134,7 +134,7 @@ config SKISA ...@@ -134,7 +134,7 @@ config SKISA
config PROTEON config PROTEON
tristate "Proteon ISA support" tristate "Proteon ISA support"
depends on TR && TMS380TR!=n && ISA depends on TR && TMS380TR && ISA
help help
This tms380 module supports Proteon ISA cards. This tms380 module supports Proteon ISA cards.
...@@ -147,7 +147,7 @@ config PROTEON ...@@ -147,7 +147,7 @@ config PROTEON
config ABYSS config ABYSS
tristate "Madge Smart 16/4 PCI Mk2 support" tristate "Madge Smart 16/4 PCI Mk2 support"
depends on TR && TMS380TR!=n && PCI depends on TR && TMS380TR && PCI
help help
This tms380 module supports the Madge Smart 16/4 PCI Mk2 This tms380 module supports the Madge Smart 16/4 PCI Mk2
cards (51-02). cards (51-02).
...@@ -157,7 +157,7 @@ config ABYSS ...@@ -157,7 +157,7 @@ config ABYSS
config MADGEMC config MADGEMC
tristate "Madge Smart 16/4 Ringnode MicroChannel" tristate "Madge Smart 16/4 Ringnode MicroChannel"
depends on TR && TMS380TR!=n && MCA depends on TR && TMS380TR && MCA
help help
This tms380 module supports the Madge Smart 16/4 MC16 and MC32 This tms380 module supports the Madge Smart 16/4 MC16 and MC32
MicroChannel adapters. MicroChannel adapters.
......
...@@ -85,8 +85,8 @@ static const int multicast_filter_limit = 32; ...@@ -85,8 +85,8 @@ static const int multicast_filter_limit = 32;
#define PKT_BUF_SZ 1536 #define PKT_BUF_SZ 1536
#define DRV_MODULE_NAME "typhoon" #define DRV_MODULE_NAME "typhoon"
#define DRV_MODULE_VERSION "1.5.1" #define DRV_MODULE_VERSION "1.5.2"
#define DRV_MODULE_RELDATE "03/06/26" #define DRV_MODULE_RELDATE "03/11/25"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define ERR_PFX KERN_ERR PFX #define ERR_PFX KERN_ERR PFX
...@@ -127,7 +127,7 @@ static const int multicast_filter_limit = 32; ...@@ -127,7 +127,7 @@ static const int multicast_filter_limit = 32;
static char version[] __devinitdata = static char version[] __devinitdata =
"typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("David Dillow <dillowd@y12.doe.gov>"); MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(rx_copybreak, "i");
...@@ -146,11 +146,12 @@ struct typhoon_card_info { ...@@ -146,11 +146,12 @@ struct typhoon_card_info {
int capabilities; int capabilities;
}; };
#define TYPHOON_CRYPTO_NONE 0 #define TYPHOON_CRYPTO_NONE 0x00
#define TYPHOON_CRYPTO_DES 1 #define TYPHOON_CRYPTO_DES 0x01
#define TYPHOON_CRYPTO_3DES 2 #define TYPHOON_CRYPTO_3DES 0x02
#define TYPHOON_CRYPTO_VARIABLE 4 #define TYPHOON_CRYPTO_VARIABLE 0x04
#define TYPHOON_FIBER 8 #define TYPHOON_FIBER 0x08
#define TYPHOON_WAKEUP_NEEDS_RESET 0x10
enum typhoon_cards { enum typhoon_cards {
TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR, TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR,
...@@ -307,7 +308,8 @@ enum state_values { ...@@ -307,7 +308,8 @@ enum state_values {
/* We'll wait up to six seconds for a reset, and half a second normally. /* We'll wait up to six seconds for a reset, and half a second normally.
*/ */
#define TYPHOON_UDELAY 50 #define TYPHOON_UDELAY 50
#define TYPHOON_RESET_TIMEOUT (6 * HZ) #define TYPHOON_RESET_TIMEOUT_SLEEP (6 * HZ)
#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY) #define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
...@@ -375,10 +377,12 @@ static int ...@@ -375,10 +377,12 @@ static int
typhoon_reset(unsigned long ioaddr, int wait_type) typhoon_reset(unsigned long ioaddr, int wait_type)
{ {
int i, err = 0; int i, err = 0;
int timeout = TYPHOON_RESET_TIMEOUT; int timeout;
if(wait_type == WaitNoSleep) if(wait_type == WaitNoSleep)
timeout = (timeout * 1000000) / (HZ * TYPHOON_UDELAY); timeout = TYPHOON_RESET_TIMEOUT_NOSLEEP;
else
timeout = TYPHOON_RESET_TIMEOUT_SLEEP;
writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
...@@ -1858,6 +1862,11 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events) ...@@ -1858,6 +1862,11 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events)
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0) if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0)
return -ETIMEDOUT; return -ETIMEDOUT;
/* Since we cannot monitor the status of the link while sleeping,
* tell the world it went away.
*/
netif_carrier_off(tp->dev);
pci_enable_wake(tp->pdev, state, 1); pci_enable_wake(tp->pdev, state, 1);
pci_disable_device(pdev); pci_disable_device(pdev);
return pci_set_power_state(pdev, state); return pci_set_power_state(pdev, state);
...@@ -1872,8 +1881,13 @@ typhoon_wakeup(struct typhoon *tp, int wait_type) ...@@ -1872,8 +1881,13 @@ typhoon_wakeup(struct typhoon *tp, int wait_type)
pci_set_power_state(pdev, 0); pci_set_power_state(pdev, 0);
pci_restore_state(pdev, tp->pci_state); pci_restore_state(pdev, tp->pci_state);
/* Post 2.x.x versions of the Sleep Image require a reset before
* we can download the Runtime Image. But let's not make users of
* the old firmware pay for the reset.
*/
writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND); writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0 ||
(tp->capabilities & TYPHOON_WAKEUP_NEEDS_RESET))
return typhoon_reset(ioaddr, wait_type); return typhoon_reset(ioaddr, wait_type);
return 0; return 0;
...@@ -2251,7 +2265,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2251,7 +2265,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void *shared; void *shared;
dma_addr_t shared_dma; dma_addr_t shared_dma;
struct cmd_desc xp_cmd; struct cmd_desc xp_cmd;
struct resp_desc xp_resp; struct resp_desc xp_resp[3];
int i; int i;
int err = 0; int err = 0;
...@@ -2380,15 +2394,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2380,15 +2394,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS); INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
if(typhoon_issue_command(tp, 1, &xp_cmd, 1, &xp_resp) < 0) { if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
printk(ERR_PFX "%s: cannot read MAC address\n", printk(ERR_PFX "%s: cannot read MAC address\n",
pci_name(pdev)); pci_name(pdev));
err = -EIO; err = -EIO;
goto error_out_reset; goto error_out_reset;
} }
*(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp.parm1)); *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
*(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp.parm2)); *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
if(!is_valid_ether_addr(dev->dev_addr)) { if(!is_valid_ether_addr(dev->dev_addr)) {
printk(ERR_PFX "%s: Could not obtain valid ethernet address, " printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
...@@ -2396,6 +2410,28 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2396,6 +2410,28 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset; goto error_out_reset;
} }
/* Read the Sleep Image version last, so the response is valid
* later when we print out the version reported.
*/
INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
printk(ERR_PFX "%s: Could not get Sleep Image version\n",
pdev->slot_name);
goto error_out_reset;
}
tp->capabilities = typhoon_card_info[card_id].capabilities;
tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
/* Typhoon 1.0 Sleep Images return one response descriptor to the
* READ_VERSIONS command. Those versions are OK after waking up
* from sleep without needing a reset. Typhoon 1.1+ Sleep Images
* seem to need a little extra help to get started. Since we don't
* know how to nudge it along, just kick it.
*/
if(xp_resp[0].numDesc != 0)
tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
if(typhoon_sleep(tp, 3, 0) < 0) { if(typhoon_sleep(tp, 3, 0) < 0) {
printk(ERR_PFX "%s: cannot put adapter to sleep\n", printk(ERR_PFX "%s: cannot put adapter to sleep\n",
pci_name(pdev)); pci_name(pdev));
...@@ -2403,9 +2439,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2403,9 +2439,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset; goto error_out_reset;
} }
tp->capabilities = typhoon_card_info[card_id].capabilities;
tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
dev->open = typhoon_open; dev->open = typhoon_open;
dev->hard_start_xmit = typhoon_start_tx; dev->hard_start_xmit = typhoon_start_tx;
...@@ -2442,6 +2475,32 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2442,6 +2475,32 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x\n", dev->dev_addr[i]); printk("%2.2x\n", dev->dev_addr[i]);
/* xp_resp still contains the response to the READ_VERSIONS command.
* For debugging, let the user know what version he has.
*/
if(xp_resp[0].numDesc == 0) {
/* This is the Typhoon 1.0 type Sleep Image, last 16 bits
* of version is Month/Day of build.
*/
u16 monthday = le32_to_cpu(xp_resp[0].parm2) & 0xffff;
printk(KERN_INFO "%s: Typhoon 1.0 Sleep Image built "
"%02u/%02u/2000\n", dev->name, monthday >> 8,
monthday & 0xff);
} else if(xp_resp[0].numDesc == 2) {
/* This is the Typhoon 1.1+ type Sleep Image
*/
u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
u8 *ver_string = (u8 *) &xp_resp[1];
ver_string[25] = 0;
printk(KERN_INFO "%s: Typhoon 1.1+ Sleep Image version "
"%u.%u.%u.%u %s\n", dev->name, HIPQUAD(sleep_ver),
ver_string);
} else {
printk(KERN_WARNING "%s: Unknown Sleep Image version "
"(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
le32_to_cpu(xp_resp[0].parm2));
}
return 0; return 0;
error_out_reset: error_out_reset:
......
...@@ -748,13 +748,13 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -748,13 +748,13 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
if(priv->station_state != STATION_STATE_READY) { if(priv->station_state != STATION_STATE_READY) {
priv->stats.tx_errors++; priv->stats.tx_errors++;
return 0; goto done;
} }
if (priv->card && priv->present_callback && if (priv->card && priv->present_callback &&
!(*priv->present_callback)(priv->card)) { !(*priv->present_callback)(priv->card)) {
priv->stats.tx_errors++; priv->stats.tx_errors++;
return 0; goto done;
} }
/* first ensure the timer func cannot run */ /* first ensure the timer func cannot run */
...@@ -804,6 +804,8 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -804,6 +804,8 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock); spin_unlock_bh(&priv->timerlock);
done:
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
......
...@@ -97,6 +97,7 @@ static Scsi_Host_Template piix_sht = { ...@@ -97,6 +97,7 @@ static Scsi_Host_Template piix_sht = {
.proc_name = DRV_NAME, .proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY, .dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config, .slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
}; };
static struct ata_port_operations piix_pata_ops = { static struct ata_port_operations piix_pata_ops = {
......
...@@ -1619,7 +1619,7 @@ static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) ...@@ -1619,7 +1619,7 @@ static void ata_dev_set_pio(struct ata_port *ap, unsigned int device)
static void ata_sg_clean(struct ata_queued_cmd *qc) static void ata_sg_clean(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
struct scatterlist *sg = qc->sg; struct scatterlist *sg = qc->sg;
int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
...@@ -1635,8 +1635,8 @@ static void ata_sg_clean(struct ata_queued_cmd *qc) ...@@ -1635,8 +1635,8 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
if (cmd->use_sg) if (cmd->use_sg)
pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir); pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir);
else else
pci_unmap_single(ap->host_set->pdev, sg[0].dma_address, pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]),
sg[0].length, dir); sg_dma_len(&sg[0]), dir);
qc->flags &= ~ATA_QCFLAG_SG; qc->flags &= ~ATA_QCFLAG_SG;
qc->sg = NULL; qc->sg = NULL;
...@@ -1659,8 +1659,8 @@ void ata_fill_sg(struct ata_queued_cmd *qc) ...@@ -1659,8 +1659,8 @@ void ata_fill_sg(struct ata_queued_cmd *qc)
assert(qc->n_elem > 0); assert(qc->n_elem > 0);
for (i = 0; i < qc->n_elem; i++) { for (i = 0; i < qc->n_elem; i++) {
ap->prd[i].addr = cpu_to_le32(sg[i].dma_address); ap->prd[i].addr = cpu_to_le32(sg_dma_address(&sg[i]));
ap->prd[i].flags_len = cpu_to_le32(sg[i].length); ap->prd[i].flags_len = cpu_to_le32(sg_dma_len(&sg[i]));
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", VPRINTK("PRD[%u] = (0x%X, 0x%X)\n",
i, le32_to_cpu(ap->prd[i].addr), le32_to_cpu(ap->prd[i].flags_len)); i, le32_to_cpu(ap->prd[i].addr), le32_to_cpu(ap->prd[i].flags_len));
} }
...@@ -1681,7 +1681,7 @@ void ata_fill_sg(struct ata_queued_cmd *qc) ...@@ -1681,7 +1681,7 @@ void ata_fill_sg(struct ata_queued_cmd *qc)
static int ata_sg_setup_one(struct ata_queued_cmd *qc) static int ata_sg_setup_one(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
struct scatterlist *sg = qc->sg; struct scatterlist *sg = qc->sg;
unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
...@@ -1691,12 +1691,12 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) ...@@ -1691,12 +1691,12 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
sg->page = virt_to_page(cmd->request_buffer); sg->page = virt_to_page(cmd->request_buffer);
sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK; sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK;
sg->length = cmd->request_bufflen; sg_dma_len(sg) = cmd->request_bufflen;
if (!have_sg) if (!have_sg)
return 0; return 0;
sg->dma_address = pci_map_single(ap->host_set->pdev, sg_dma_address(sg) = pci_map_single(ap->host_set->pdev,
cmd->request_buffer, cmd->request_buffer,
cmd->request_bufflen, dir); cmd->request_bufflen, dir);
...@@ -1720,7 +1720,7 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) ...@@ -1720,7 +1720,7 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
static int ata_sg_setup(struct ata_queued_cmd *qc) static int ata_sg_setup(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
struct scatterlist *sg; struct scatterlist *sg;
int n_elem; int n_elem;
unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
...@@ -1872,7 +1872,7 @@ static void ata_pio_sector(struct ata_port *ap) ...@@ -1872,7 +1872,7 @@ static void ata_pio_sector(struct ata_port *ap)
{ {
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
struct scatterlist *sg; struct scatterlist *sg;
Scsi_Cmnd *cmd; struct scsi_cmnd *cmd;
unsigned char *buf; unsigned char *buf;
u8 status; u8 status;
...@@ -1917,7 +1917,7 @@ static void ata_pio_sector(struct ata_port *ap) ...@@ -1917,7 +1917,7 @@ static void ata_pio_sector(struct ata_port *ap)
qc->cursg_ofs++; qc->cursg_ofs++;
if (cmd->use_sg) if (cmd->use_sg)
if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg[qc->cursg].length) { if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
qc->cursg++; qc->cursg++;
qc->cursg_ofs = 0; qc->cursg_ofs = 0;
} }
...@@ -2092,7 +2092,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, ...@@ -2092,7 +2092,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late) void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int tag, do_clear = 0; unsigned int tag, do_clear = 0;
assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */ assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */
...@@ -2163,7 +2163,7 @@ static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append) ...@@ -2163,7 +2163,7 @@ static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append)
int ata_qc_issue(struct ata_queued_cmd *qc) int ata_qc_issue(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int dma = qc->flags & ATA_QCFLAG_DMA; unsigned int dma = qc->flags & ATA_QCFLAG_DMA;
ata_dev_select(ap, qc->dev->devno, 1, 0); ata_dev_select(ap, qc->dev->devno, 1, 0);
...@@ -2719,7 +2719,7 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) ...@@ -2719,7 +2719,7 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
if (do_unregister) if (do_unregister)
scsi_remove_host(sh); /* FIXME: check return val */ scsi_remove_host(sh);
ata_thread_kill(ap); /* FIXME: check return val */ ata_thread_kill(ap); /* FIXME: check return val */
...@@ -3204,7 +3204,6 @@ void ata_pci_remove_one (struct pci_dev *pdev) ...@@ -3204,7 +3204,6 @@ void ata_pci_remove_one (struct pci_dev *pdev)
for (i = 0; i < host_set->n_ports; i++) { for (i = 0; i < host_set->n_ports; i++) {
ap = host_set->ports[i]; ap = host_set->ports[i];
/* FIXME: check return val */
scsi_remove_host(ap->host); scsi_remove_host(ap->host);
} }
...@@ -3215,13 +3214,10 @@ void ata_pci_remove_one (struct pci_dev *pdev) ...@@ -3215,13 +3214,10 @@ void ata_pci_remove_one (struct pci_dev *pdev)
host_set->ports[0]->ops->host_stop(host_set); host_set->ports[0]->ops->host_stop(host_set);
for (i = 0; i < host_set->n_ports; i++) { for (i = 0; i < host_set->n_ports; i++) {
Scsi_Host_Template *sht;
ap = host_set->ports[i]; ap = host_set->ports[i];
sht = ap->host->hostt;
ata_scsi_release(ap->host); ata_scsi_release(ap->host);
scsi_host_put(ap->host); /* FIXME: check return val */ scsi_host_put(ap->host);
} }
pci_release_regions(pdev); pci_release_regions(pdev);
...@@ -3279,6 +3275,7 @@ int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits) ...@@ -3279,6 +3275,7 @@ int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0; return (tmp == bits->val) ? 1 : 0;
} }
/** /**
* ata_init - * ata_init -
* *
...@@ -3304,6 +3301,7 @@ module_init(ata_init); ...@@ -3304,6 +3301,7 @@ module_init(ata_init);
*/ */
EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_device_add);
EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete);
......
...@@ -32,10 +32,33 @@ ...@@ -32,10 +32,33 @@
#include "libata.h" #include "libata.h"
/**
* ata_std_bios_param - generic bios head/sector/cylinder calculator
* used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS)
* mapping. Some situations may arise where the disk is not
* bootable if this is not used.
*
* LOCKING:
*
* RETURNS:
*
*/
int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
{
geom[0] = 255;
geom[1] = 63;
geom[2] = capacity / (geom[0] * geom[1]);
return 0;
}
struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
struct ata_device *dev, struct ata_device *dev,
Scsi_Cmnd *cmd, struct scsi_cmnd *cmd,
void (*done)(Scsi_Cmnd *)) void (*done)(struct scsi_cmnd *))
{ {
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
...@@ -69,7 +92,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, ...@@ -69,7 +92,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
void ata_to_sense_error(struct ata_queued_cmd *qc) void ata_to_sense_error(struct ata_queued_cmd *qc)
{ {
Scsi_Cmnd *cmd = qc->scsicmd; struct scsi_cmnd *cmd = qc->scsicmd;
cmd->result = SAM_STAT_CHECK_CONDITION; cmd->result = SAM_STAT_CHECK_CONDITION;
...@@ -282,7 +305,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd, ...@@ -282,7 +305,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd,
*/ */
void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev, void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev,
Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
unsigned int cmd_size) unsigned int cmd_size)
{ {
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
...@@ -332,7 +355,7 @@ void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev, ...@@ -332,7 +355,7 @@ void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev,
* Length of response buffer. * Length of response buffer.
*/ */
static unsigned int ata_scsi_rbuf_get(Scsi_Cmnd *cmd, u8 **buf_out) static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
{ {
u8 *buf; u8 *buf;
unsigned int buflen; unsigned int buflen;
...@@ -363,7 +386,7 @@ static unsigned int ata_scsi_rbuf_get(Scsi_Cmnd *cmd, u8 **buf_out) ...@@ -363,7 +386,7 @@ static unsigned int ata_scsi_rbuf_get(Scsi_Cmnd *cmd, u8 **buf_out)
* spin_lock_irqsave(host_set lock) * spin_lock_irqsave(host_set lock)
*/ */
static inline void ata_scsi_rbuf_put(Scsi_Cmnd *cmd) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd)
{ {
if (cmd->use_sg) { if (cmd->use_sg) {
struct scatterlist *sg; struct scatterlist *sg;
...@@ -394,7 +417,7 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, ...@@ -394,7 +417,7 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
{ {
u8 *rbuf; u8 *rbuf;
unsigned int buflen, rc; unsigned int buflen, rc;
Scsi_Cmnd *cmd = args->cmd; struct scsi_cmnd *cmd = args->cmd;
buflen = ata_scsi_rbuf_get(cmd, &rbuf); buflen = ata_scsi_rbuf_get(cmd, &rbuf);
rc = actor(args, rbuf, buflen); rc = actor(args, rbuf, buflen);
...@@ -817,7 +840,7 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, ...@@ -817,7 +840,7 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
* spin_lock_irqsave(host_set lock) * spin_lock_irqsave(host_set lock)
*/ */
void ata_scsi_badcmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), u8 asc, u8 ascq) void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
{ {
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
cmd->result = SAM_STAT_CHECK_CONDITION; cmd->result = SAM_STAT_CHECK_CONDITION;
...@@ -847,7 +870,7 @@ void ata_scsi_badcmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), u8 asc, u8 ascq) ...@@ -847,7 +870,7 @@ void ata_scsi_badcmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), u8 asc, u8 ascq)
*/ */
static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev, static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev,
Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{ {
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
u8 *scsicmd = cmd->cmnd, status; u8 *scsicmd = cmd->cmnd, status;
...@@ -958,7 +981,7 @@ static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev, ...@@ -958,7 +981,7 @@ static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev,
* Zero. * Zero.
*/ */
int ata_scsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{ {
u8 *scsicmd = cmd->cmnd; u8 *scsicmd = cmd->cmnd;
struct ata_port *ap; struct ata_port *ap;
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
struct ata_scsi_args { struct ata_scsi_args {
struct ata_port *ap; struct ata_port *ap;
struct ata_device *dev; struct ata_device *dev;
Scsi_Cmnd *cmd; struct scsi_cmnd *cmd;
void (*done)(Scsi_Cmnd *); void (*done)(struct scsi_cmnd *);
}; };
...@@ -51,7 +51,7 @@ extern void ata_thread_wake(struct ata_port *ap, unsigned int thr_state); ...@@ -51,7 +51,7 @@ extern void ata_thread_wake(struct ata_port *ap, unsigned int thr_state);
/* libata-scsi.c */ /* libata-scsi.c */
extern void ata_to_sense_error(struct ata_queued_cmd *qc); extern void ata_to_sense_error(struct ata_queued_cmd *qc);
extern void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev, extern void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev,
Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
unsigned int cmd_size); unsigned int cmd_size);
extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_error(struct Scsi_Host *host);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
...@@ -74,19 +74,19 @@ extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, ...@@ -74,19 +74,19 @@ extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen); unsigned int buflen);
extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen); unsigned int buflen);
extern void ata_scsi_badcmd(Scsi_Cmnd *cmd, extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
void (*done)(Scsi_Cmnd *), void (*done)(struct scsi_cmnd *),
u8 asc, u8 ascq); u8 asc, u8 ascq);
extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
unsigned int (*actor) (struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args,
u8 *rbuf, unsigned int buflen)); u8 *rbuf, unsigned int buflen));
static inline void ata_bad_scsiop(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{ {
ata_scsi_badcmd(cmd, done, 0x20, 0x00); ata_scsi_badcmd(cmd, done, 0x20, 0x00);
} }
static inline void ata_bad_cdb(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{ {
ata_scsi_badcmd(cmd, done, 0x24, 0x00); ata_scsi_badcmd(cmd, done, 0x24, 0x00);
} }
......
...@@ -34,10 +34,8 @@ ...@@ -34,10 +34,8 @@
#include <linux/libata.h> #include <linux/libata.h>
#include <asm/io.h> #include <asm/io.h>
#undef DIRECT_HDMA
#define DRV_NAME "sata_promise" #define DRV_NAME "sata_promise"
#define DRV_VERSION "0.86" #define DRV_VERSION "0.89"
enum { enum {
...@@ -82,6 +80,42 @@ enum { ...@@ -82,6 +80,42 @@ enum {
PDC_FLAG_20621 = (1 << 30), /* we have a 20621 */ PDC_FLAG_20621 = (1 << 30), /* we have a 20621 */
PDC_HDMA_RESET = (1 << 11), /* HDMA reset */ PDC_HDMA_RESET = (1 << 11), /* HDMA reset */
PDC_MAX_HDMA = 32,
PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
PDC_MAX_DIMM_MODULE = 0x02,
PDC_I2C_CONTROL_OFFSET = 0x48,
PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
PDC_DIMM0_CONTROL_OFFSET = 0x80,
PDC_DIMM1_CONTROL_OFFSET = 0x84,
PDC_SDRAM_CONTROL_OFFSET = 0x88,
PDC_I2C_WRITE = 0x00000000,
PDC_I2C_READ = 0x00000040,
PDC_I2C_START = 0x00000080,
PDC_I2C_MASK_INT = 0x00000020,
PDC_I2C_COMPLETE = 0x00010000,
PDC_I2C_NO_ACK = 0x00100000,
PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
PDC_DIMM_SPD_ROW_NUM = 3,
PDC_DIMM_SPD_COLUMN_NUM = 4,
PDC_DIMM_SPD_MODULE_ROW = 5,
PDC_DIMM_SPD_TYPE = 11,
PDC_DIMM_SPD_FRESH_RATE = 12,
PDC_DIMM_SPD_BANK_NUM = 17,
PDC_DIMM_SPD_CAS_LATENCY = 18,
PDC_DIMM_SPD_ATTRIBUTE = 21,
PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
PDC_DIMM_SPD_SYSTEM_FREQ = 126,
PDC_CTL_STATUS = 0x08,
PDC_DIMM_WINDOW_CTLR = 0x0C,
PDC_GENERAL_CTLR = 0x484,
}; };
...@@ -91,6 +125,19 @@ struct pdc_port_priv { ...@@ -91,6 +125,19 @@ struct pdc_port_priv {
dma_addr_t pkt_dma; dma_addr_t pkt_dma;
}; };
struct pdc_host_priv {
void *dimm_mmio;
unsigned int doing_hdma;
unsigned int hdma_prod;
unsigned int hdma_cons;
struct {
struct ata_queued_cmd *qc;
unsigned int seq;
unsigned long pkt_ofs;
} hdma[32];
};
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
...@@ -114,6 +161,18 @@ static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); ...@@ -114,6 +161,18 @@ static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
static void pdc20621_host_stop(struct ata_host_set *host_set); static void pdc20621_host_stop(struct ata_host_set *host_set);
static inline void pdc_dma_complete (struct ata_port *ap, static inline void pdc_dma_complete (struct ata_port *ap,
struct ata_queued_cmd *qc); struct ata_queued_cmd *qc);
static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
u32 device, u32 subaddr, u32 *pdata);
static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
#ifdef ATA_VERBOSE_DEBUG
static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
void *psource, u32 offset, u32 size);
#endif
static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
void *psource, u32 offset, u32 size);
static Scsi_Host_Template pdc_sata_sht = { static Scsi_Host_Template pdc_sata_sht = {
...@@ -131,6 +190,7 @@ static Scsi_Host_Template pdc_sata_sht = { ...@@ -131,6 +190,7 @@ static Scsi_Host_Template pdc_sata_sht = {
.proc_name = DRV_NAME, .proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY, .dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config, .slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
}; };
static struct ata_port_operations pdc_sata_ops = { static struct ata_port_operations pdc_sata_ops = {
...@@ -235,10 +295,11 @@ static struct pci_driver pdc_sata_pci_driver = { ...@@ -235,10 +295,11 @@ static struct pci_driver pdc_sata_pci_driver = {
static void pdc20621_host_stop(struct ata_host_set *host_set) static void pdc20621_host_stop(struct ata_host_set *host_set)
{ {
void *mmio = host_set->private_data; struct pdc_host_priv *hpriv = host_set->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
assert(mmio != NULL); iounmap(dimm_mmio);
iounmap(mmio); kfree(hpriv);
} }
static int pdc_port_start(struct ata_port *ap) static int pdc_port_start(struct ata_port *ap)
...@@ -256,6 +317,7 @@ static int pdc_port_start(struct ata_port *ap) ...@@ -256,6 +317,7 @@ static int pdc_port_start(struct ata_port *ap)
rc = -ENOMEM; rc = -ENOMEM;
goto err_out; goto err_out;
} }
memset(pp, 0, sizeof(*pp));
pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma); pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
if (!pp->pkt) { if (!pp->pkt) {
...@@ -589,7 +651,8 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) ...@@ -589,7 +651,8 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data; struct pdc_port_priv *pp = ap->private_data;
void *mmio = ap->host_set->mmio_base; void *mmio = ap->host_set->mmio_base;
void *dimm_mmio = ap->host_set->private_data; struct pdc_host_priv *hpriv = ap->host_set->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
unsigned int portno = ap->port_no; unsigned int portno = ap->port_no;
unsigned int i, last, idx, total_len = 0, sgt_len; unsigned int i, last, idx, total_len = 0, sgt_len;
u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
...@@ -605,8 +668,8 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) ...@@ -605,8 +668,8 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
last = qc->n_elem; last = qc->n_elem;
idx = 0; idx = 0;
for (i = 0; i < last; i++) { for (i = 0; i < last; i++) {
buf[idx++] = cpu_to_le32(sg[i].dma_address); buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
buf[idx++] = cpu_to_le32(sg[i].length); buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
total_len += sg[i].length; total_len += sg[i].length;
} }
buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT); buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
...@@ -643,49 +706,68 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) ...@@ -643,49 +706,68 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
} }
#ifdef DIRECT_HDMA static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
static void pdc20621_push_hdma(struct ata_queued_cmd *qc) unsigned int seq,
u32 pkt_ofs)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
struct ata_host_set *host_set = ap->host_set; struct ata_host_set *host_set = ap->host_set;
unsigned int port_no = ap->port_no;
void *mmio = host_set->mmio_base; void *mmio = host_set->mmio_base;
unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE);
u32 tmp;
unsigned int host_sg = PDC_20621_DIMM_BASE +
(PDC_DIMM_WINDOW_STEP * port_no) +
PDC_DIMM_HOST_PRD;
unsigned int dimm_sg = PDC_20621_DIMM_BASE +
(PDC_DIMM_WINDOW_STEP * port_no) +
PDC_DIMM_HPKT_PRD;
/* hard-code chip #0 */ /* hard-code chip #0 */
mmio += PDC_CHIP0_OFS; mmio += PDC_CHIP0_OFS;
tmp = readl(mmio + PDC_HDMA_CTLSTAT) & 0xffffff00; writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
tmp |= port_no + 1 + 4; /* seq. ID */ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
if (!rw)
tmp |= (1 << 6); /* hdma data direction */
writel(tmp, mmio + PDC_HDMA_CTLSTAT); /* note: stops DMA, if active */
readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
writel(host_sg, mmio + 0x108); writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
writel(dimm_sg, mmio + 0x10C); readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
writel(0, mmio + 0x128); }
tmp |= (1 << 7); static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
writel(tmp, mmio + PDC_HDMA_CTLSTAT); unsigned int seq,
readl(mmio + PDC_HDMA_CTLSTAT); /* flush */ u32 pkt_ofs)
{
struct ata_port *ap = qc->ap;
struct pdc_host_priv *pp = ap->host_set->private_data;
unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
if (!pp->doing_hdma) {
__pdc20621_push_hdma(qc, seq, pkt_ofs);
pp->doing_hdma = 1;
return;
}
pp->hdma[idx].qc = qc;
pp->hdma[idx].seq = seq;
pp->hdma[idx].pkt_ofs = pkt_ofs;
pp->hdma_prod++;
}
static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_host_priv *pp = ap->host_set->private_data;
unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
/* if nothing on queue, we're done */
if (pp->hdma_prod == pp->hdma_cons) {
pp->doing_hdma = 0;
return;
}
__pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
pp->hdma[idx].pkt_ofs);
pp->hdma_cons++;
} }
#endif
#ifdef ATA_VERBOSE_DEBUG #ifdef ATA_VERBOSE_DEBUG
static void pdc20621_dump_hdma(struct ata_queued_cmd *qc) static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
unsigned int port_no = ap->port_no; unsigned int port_no = ap->port_no;
void *dimm_mmio = ap->host_set->private_data; struct pdc_host_priv *hpriv = ap->host_set->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP); dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
dimm_mmio += PDC_DIMM_HOST_PKT; dimm_mmio += PDC_DIMM_HOST_PKT;
...@@ -724,23 +806,17 @@ static void pdc20621_dma_start(struct ata_queued_cmd *qc) ...@@ -724,23 +806,17 @@ static void pdc20621_dma_start(struct ata_queued_cmd *qc)
wmb(); /* flush PRD, pkt writes */ wmb(); /* flush PRD, pkt writes */
writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
if (doing_hdma) { if (doing_hdma) {
pdc20621_dump_hdma(qc); pdc20621_dump_hdma(qc);
#ifdef DIRECT_HDMA pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
pdc20621_push_hdma(qc); VPRINTK("queued ofs 0x%x (%u), seq %u\n",
#else
writel(port_ofs + PDC_DIMM_HOST_PKT,
mmio + PDC_HDMA_PKT_SUBMIT);
readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
#endif
VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
port_ofs + PDC_DIMM_HOST_PKT, port_ofs + PDC_DIMM_HOST_PKT,
port_ofs + PDC_DIMM_HOST_PKT, port_ofs + PDC_DIMM_HOST_PKT,
seq); seq);
} else { } else {
writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
writel(port_ofs + PDC_DIMM_ATA_PKT, writel(port_ofs + PDC_DIMM_ATA_PKT,
(void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
...@@ -771,6 +847,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, ...@@ -771,6 +847,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
pdc_dma_complete(ap, qc); pdc_dma_complete(ap, qc);
pdc20621_pop_hdma(qc);
} }
/* step one - exec ATA command */ /* step one - exec ATA command */
...@@ -781,15 +858,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, ...@@ -781,15 +858,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
/* submit hdma pkt */ /* submit hdma pkt */
pdc20621_dump_hdma(qc); pdc20621_dump_hdma(qc);
writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); pdc20621_push_hdma(qc, seq,
readl(mmio + PDC_20621_SEQCTL + (seq * 4)); port_ofs + PDC_DIMM_HOST_PKT);
#ifdef DIRECT_HDMA
pdc20621_push_hdma(qc);
#else
writel(port_ofs + PDC_DIMM_HOST_PKT,
mmio + PDC_HDMA_PKT_SUBMIT);
readl(mmio + PDC_HDMA_PKT_SUBMIT);
#endif
} }
handled = 1; handled = 1;
break; break;
...@@ -814,6 +884,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, ...@@ -814,6 +884,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
pdc_dma_complete(ap, qc); pdc_dma_complete(ap, qc);
pdc20621_pop_hdma(qc);
} }
handled = 1; handled = 1;
break; break;
...@@ -1098,11 +1169,373 @@ static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base) ...@@ -1098,11 +1169,373 @@ static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
port->ctl_addr = base + 0x38; port->ctl_addr = base + 0x38;
} }
#ifdef ATA_VERBOSE_DEBUG
static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
void *mmio = pe->mmio_base;
struct pdc_host_priv *hpriv = pe->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
page_mask = 0x00;
window_size = 0x2000 * 4; /* 32K byte uchar size */
idx = (u16) (offset / window_size);
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
offset -= (idx * window_size);
idx++;
dist = ((long) (window_size - (offset + size))) >= 0 ? size :
(long) (window_size - offset);
memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
dist);
psource += dist;
size -= dist;
for (; (long) size >= (long) window_size ;) {
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
memcpy_fromio((char *) psource, (char *) (dimm_mmio),
window_size / 4);
psource += window_size;
size -= window_size;
idx ++;
}
if (size) {
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
memcpy_fromio((char *) psource, (char *) (dimm_mmio),
size / 4);
}
}
#endif
static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
void *mmio = pe->mmio_base;
struct pdc_host_priv *hpriv = pe->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
page_mask = 0x00;
window_size = 0x2000 * 4; /* 32K byte uchar size */
idx = (u16) (offset / window_size);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
offset -= (idx * window_size);
idx++;
dist = ((long) (window_size - (offset + size))) >= 0 ? size :
(long) (window_size - offset);
memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
psource += dist;
size -= dist;
for (; (long) size >= (long) window_size ;) {
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
memcpy_toio((char *) (dimm_mmio), (char *) psource,
window_size / 4);
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
psource += window_size;
size -= window_size;
idx ++;
}
if (size) {
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
writel(0x01, mmio + PDC_GENERAL_CTLR);
readl(mmio + PDC_GENERAL_CTLR);
}
}
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
u32 subaddr, u32 *pdata)
{
void *mmio = pe->mmio_base;
u32 i2creg = 0;
u32 status;
u32 count =0;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
i2creg |= device << 24;
i2creg |= subaddr << 16;
/* Set the device and subaddress */
writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
/* Write Control to perform read operation, mask int */
writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
mmio + PDC_I2C_CONTROL_OFFSET);
for (count = 0; count <= 1000; count ++) {
status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
if (status & PDC_I2C_COMPLETE) {
status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
break;
} else if (count == 1000)
return 0;
}
*pdata = (status >> 8) & 0x000000ff;
return 1;
}
static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
{
u32 data=0 ;
if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
if (data == 100)
return 100;
} else
return 0;
if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
if(data <= 0x75)
return 133;
} else
return 0;
return 0;
}
static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
{
u32 spd0[50];
u32 data = 0;
int size, i;
u8 bdimmsize;
void *mmio = pe->mmio_base;
static const struct {
unsigned int reg;
unsigned int ofs;
} pdc_i2c_read_data [] = {
{ PDC_DIMM_SPD_TYPE, 11 },
{ PDC_DIMM_SPD_FRESH_RATE, 12 },
{ PDC_DIMM_SPD_COLUMN_NUM, 4 },
{ PDC_DIMM_SPD_ATTRIBUTE, 21 },
{ PDC_DIMM_SPD_ROW_NUM, 3 },
{ PDC_DIMM_SPD_BANK_NUM, 17 },
{ PDC_DIMM_SPD_MODULE_ROW, 5 },
{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
{ PDC_DIMM_SPD_CAS_LATENCY, 18 },
};
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
pdc_i2c_read_data[i].reg,
&spd0[pdc_i2c_read_data[i].ofs]);
data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
((((spd0[27] + 9) / 10) - 1) << 8) ;
data |= (((((spd0[29] > spd0[28])
? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
if (spd0[18] & 0x08)
data |= ((0x03) << 14);
else if (spd0[18] & 0x04)
data |= ((0x02) << 14);
else if (spd0[18] & 0x01)
data |= ((0x01) << 14);
else
data |= (0 << 14);
/*
Calculate the size of bDIMMSize (power of 2) and
merge the DIMM size by program start/end address.
*/
bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
data |= (((size / 16) - 1) << 16);
data |= (0 << 23);
data |= 8;
writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
return size;
}
static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
{
u32 data, spd0;
int error, i;
void *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
/*
Set To Default : DIMM Module Global Control Register (0x022259F1)
DIMM Arbitration Disable (bit 20)
DIMM Data/Control Output Driving Selection (bit12 - bit15)
Refresh Enable (bit 17)
*/
data = 0x022259F1;
writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
/* Turn on for ECC */
pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
data |= (0x01 << 16);
writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
printk(KERN_ERR "Local DIMM ECC Enabled\n");
}
/* DIMM Initialization Select/Enable (bit 18/19) */
data &= (~(1<<18));
data |= (1<<19);
writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
error = 1;
for (i = 1; i <= 10; i++) { /* polling ~5 secs */
data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
if (!(data & (1<<19))) {
error = 0;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((i * 100) * HZ / 1000);
}
return error;
}
static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
{
int speed, size, length;
u32 addr,spd0,pci_status;
u32 tmp=0;
void *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
/* Initialize PLL. */
pci_status = 0x8a531824;
writel(pci_status, mmio + PDC_CTL_STATUS);
readl(mmio + PDC_CTL_STATUS);
/*
Read SPD of DIMM by I2C interface,
and program the DIMM Module Controller.
*/
if (!(speed = pdc20621_detect_dimm(pe))) {
printk(KERN_ERR "Detect Local DIMM Fail\n");
return 1; /* DIMM error */
}
VPRINTK("Local DIMM Speed = %d\n", speed);
/* Programming DIMM0 Module Control Register (index_CID0:80h) */
size = pdc20621_prog_dimm0(pe);
VPRINTK("Local DIMM Size = %dMB\n",size);
/* Programming DIMM Module Global Control Register (index_CID0:88h) */
if (pdc20621_prog_dimm_global(pe)) {
printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
return 1;
}
#ifdef ATA_VERBOSE_DEBUG
{
u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
'1','.','1','0',
'9','8','0','3','1','6','1','2',0,0};
u8 test_parttern2[40] = {0};
pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
}
#endif
/* ECC initiliazation. */
pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
VPRINTK("Start ECC initialization\n");
addr = 0;
length = size * 1024 * 1024;
while (addr < length) {
pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
sizeof(u32));
addr += sizeof(u32);
}
VPRINTK("Finish ECC initialization\n");
}
return 0;
}
static void pdc_20621_init(struct ata_probe_ent *pe) static void pdc_20621_init(struct ata_probe_ent *pe)
{ {
u32 tmp; u32 tmp;
void *mmio = pe->mmio_base; void *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS; mmio += PDC_CHIP0_OFS;
/* /*
...@@ -1170,6 +1603,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1170,6 +1603,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
struct ata_probe_ent *probe_ent = NULL; struct ata_probe_ent *probe_ent = NULL;
unsigned long base; unsigned long base;
void *mmio_base, *dimm_mmio = NULL; void *mmio_base, *dimm_mmio = NULL;
struct pdc_host_priv *hpriv = NULL;
unsigned int board_idx = (unsigned int) ent->driver_data; unsigned int board_idx = (unsigned int) ent->driver_data;
unsigned int have_20621 = (board_idx == board_20621); unsigned int have_20621 = (board_idx == board_20621);
int rc; int rc;
...@@ -1212,12 +1646,22 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1212,12 +1646,22 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
base = (unsigned long) mmio_base; base = (unsigned long) mmio_base;
if (have_20621) { if (have_20621) {
hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
rc = -ENOMEM;
goto err_out_iounmap;
}
memset(hpriv, 0, sizeof(*hpriv));
dimm_mmio = ioremap(pci_resource_start(pdev, 4), dimm_mmio = ioremap(pci_resource_start(pdev, 4),
pci_resource_len(pdev, 4)); pci_resource_len(pdev, 4));
if (!dimm_mmio) { if (!dimm_mmio) {
kfree(hpriv);
rc = -ENOMEM; rc = -ENOMEM;
goto err_out_iounmap; goto err_out_iounmap;
} }
hpriv->dimm_mmio = dimm_mmio;
} }
probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->sht = pdc_port_info[board_idx].sht;
...@@ -1231,7 +1675,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1231,7 +1675,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
probe_ent->mmio_base = mmio_base; probe_ent->mmio_base = mmio_base;
if (have_20621) { if (have_20621) {
probe_ent->private_data = dimm_mmio; probe_ent->private_data = hpriv;
base += PDC_CHIP0_OFS; base += PDC_CHIP0_OFS;
} }
...@@ -1268,9 +1712,14 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1268,9 +1712,14 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
pci_set_master(pdev); pci_set_master(pdev);
/* initialize adapter */ /* initialize adapter */
if (have_20621) if (have_20621) {
/* initialize local dimm */
if (pdc20621_dimm_init(probe_ent)) {
rc = -ENOMEM;
goto err_out_iounmap_dimm;
}
pdc_20621_init(probe_ent); pdc_20621_init(probe_ent);
else } else
pdc_host_init(board_idx, probe_ent); pdc_host_init(board_idx, probe_ent);
/* FIXME: check ata_device_add return value */ /* FIXME: check ata_device_add return value */
...@@ -1279,6 +1728,9 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1279,6 +1728,9 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
return 0; return 0;
err_out_iounmap_dimm: /* only get to this label if 20621 */
kfree(hpriv);
iounmap(dimm_mmio);
err_out_iounmap: err_out_iounmap:
iounmap(mmio_base); iounmap(mmio_base);
err_out_free_ent: err_out_free_ent:
......
...@@ -87,6 +87,7 @@ static Scsi_Host_Template sil_sht = { ...@@ -87,6 +87,7 @@ static Scsi_Host_Template sil_sht = {
.proc_name = DRV_NAME, .proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY, .dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config, .slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
}; };
static struct ata_port_operations sil_ops = { static struct ata_port_operations sil_ops = {
......
...@@ -219,6 +219,7 @@ static Scsi_Host_Template k2_sata_sht = { ...@@ -219,6 +219,7 @@ static Scsi_Host_Template k2_sata_sht = {
#ifdef CONFIG_ALL_PPC #ifdef CONFIG_ALL_PPC
.proc_info = k2_sata_proc_info .proc_info = k2_sata_proc_info
#endif #endif
.bios_param = ata_std_bios_param,
}; };
......
...@@ -78,6 +78,7 @@ static Scsi_Host_Template svia_sht = { ...@@ -78,6 +78,7 @@ static Scsi_Host_Template svia_sht = {
.proc_name = DRV_NAME, .proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY, .dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config, .slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
}; };
static struct ata_port_operations svia_sata_ops = { static struct ata_port_operations svia_sata_ops = {
......
...@@ -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.
*/ */
......
...@@ -1354,6 +1354,9 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1354,6 +1354,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_A4TECH 0x09DA #define USB_VENDOR_ID_A4TECH 0x09DA
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
struct hid_blacklist { struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
...@@ -1403,6 +1406,7 @@ struct hid_blacklist { ...@@ -1403,6 +1406,7 @@ struct hid_blacklist {
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -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. */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <linux/ata.h> #include <linux/ata.h>
/* /*
* compile-time options * compile-time options
*/ */
...@@ -66,8 +67,6 @@ ...@@ -66,8 +67,6 @@
/* defines only for the constants which don't work well as enums */ /* defines only for the constants which don't work well as enums */
#define ATA_TAG_POISON 0xfafbfcfdU #define ATA_TAG_POISON 0xfafbfcfdU
#define ATA_DMA_BOUNDARY 0xffffUL
#define ATA_DMA_MASK 0xffffffffULL
enum { enum {
/* various global constants */ /* various global constants */
...@@ -171,6 +170,7 @@ enum { ...@@ -171,6 +170,7 @@ enum {
}; };
/* forward declarations */ /* forward declarations */
struct scsi_device;
struct ata_port_operations; struct ata_port_operations;
struct ata_port; struct ata_port;
struct ata_queued_cmd; struct ata_queued_cmd;
...@@ -247,8 +247,8 @@ struct ata_queued_cmd { ...@@ -247,8 +247,8 @@ struct ata_queued_cmd {
struct ata_port *ap; struct ata_port *ap;
struct ata_device *dev; struct ata_device *dev;
Scsi_Cmnd *scsicmd; struct scsi_cmnd *scsicmd;
void (*scsidone)(Scsi_Cmnd *); void (*scsidone)(struct scsi_cmnd *);
struct list_head node; struct list_head node;
unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned long flags; /* ATA_QCFLAG_xxx */
...@@ -403,7 +403,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i ...@@ -403,7 +403,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i
extern void ata_pci_remove_one (struct pci_dev *pdev); extern void ata_pci_remove_one (struct pci_dev *pdev);
extern int ata_device_add(struct ata_probe_ent *ent); extern int ata_device_add(struct ata_probe_ent *ent);
extern int ata_scsi_detect(Scsi_Host_Template *sht); extern int ata_scsi_detect(Scsi_Host_Template *sht);
extern int ata_scsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_error(struct Scsi_Host *host);
extern int ata_scsi_release(struct Scsi_Host *host); extern int ata_scsi_release(struct Scsi_Host *host);
extern int ata_scsi_slave_config(struct scsi_device *sdev); extern int ata_scsi_slave_config(struct scsi_device *sdev);
...@@ -427,6 +427,9 @@ extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc); ...@@ -427,6 +427,9 @@ extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc);
extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late);
extern void ata_eng_timeout(struct ata_port *ap); extern void ata_eng_timeout(struct ata_port *ap);
extern int ata_std_bios_param(struct scsi_device *sdev,
struct block_device *bdev,
sector_t capacity, int geom[]);
static inline unsigned long msecs_to_jiffies(unsigned long msecs) static inline unsigned long msecs_to_jiffies(unsigned long msecs)
......
...@@ -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);
......
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