0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #include <linux/module.h>
0044 #include <linux/parport.h>
0045 #include <linux/slab.h>
0046 #include <linux/init.h>
0047 #include <linux/serio.h>
0048
0049 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0050 MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
0051 MODULE_LICENSE("GPL");
0052
0053 static unsigned int parkbd_pp_no;
0054 module_param_named(port, parkbd_pp_no, int, 0);
0055 MODULE_PARM_DESC(port, "Parallel port the adapter is connected to (default is 0)");
0056
0057 static unsigned int parkbd_mode = SERIO_8042;
0058 module_param_named(mode, parkbd_mode, uint, 0);
0059 MODULE_PARM_DESC(mode, "Mode of operation: XT = 0/AT = 1 (default)");
0060
0061 #define PARKBD_CLOCK 0x01
0062 #define PARKBD_DATA 0x02
0063
0064 static int parkbd_buffer;
0065 static int parkbd_counter;
0066 static unsigned long parkbd_last;
0067 static int parkbd_writing;
0068 static unsigned long parkbd_start;
0069
0070 static struct pardevice *parkbd_dev;
0071 static struct serio *parkbd_port;
0072
0073 static int parkbd_readlines(void)
0074 {
0075 return (parport_read_status(parkbd_dev->port) >> 6) ^ 2;
0076 }
0077
0078 static void parkbd_writelines(int data)
0079 {
0080 parport_write_control(parkbd_dev->port, (~data & 3) | 0x10);
0081 }
0082
0083 static int parkbd_write(struct serio *port, unsigned char c)
0084 {
0085 unsigned char p;
0086
0087 if (!parkbd_mode) return -1;
0088
0089 p = c ^ (c >> 4);
0090 p = p ^ (p >> 2);
0091 p = p ^ (p >> 1);
0092
0093 parkbd_counter = 0;
0094 parkbd_writing = 1;
0095 parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600;
0096
0097 parkbd_writelines(2);
0098
0099 return 0;
0100 }
0101
0102 static void parkbd_interrupt(void *dev_id)
0103 {
0104
0105 if (parkbd_writing) {
0106
0107 if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) {
0108 parkbd_counter = 0;
0109 parkbd_buffer = 0;
0110 parkbd_writing = 0;
0111 parkbd_writelines(3);
0112 return;
0113 }
0114
0115 parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
0116
0117 if (parkbd_counter == 11) {
0118 parkbd_counter = 0;
0119 parkbd_buffer = 0;
0120 parkbd_writing = 0;
0121 parkbd_writelines(3);
0122 }
0123
0124 } else {
0125
0126 if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
0127 parkbd_counter = 0;
0128 parkbd_buffer = 0;
0129 }
0130
0131 parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
0132
0133 if (parkbd_counter == parkbd_mode + 10)
0134 serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
0135 }
0136
0137 parkbd_last = jiffies;
0138 }
0139
0140 static int parkbd_getport(struct parport *pp)
0141 {
0142 struct pardev_cb parkbd_parport_cb;
0143
0144 memset(&parkbd_parport_cb, 0, sizeof(parkbd_parport_cb));
0145 parkbd_parport_cb.irq_func = parkbd_interrupt;
0146 parkbd_parport_cb.flags = PARPORT_FLAG_EXCL;
0147
0148 parkbd_dev = parport_register_dev_model(pp, "parkbd",
0149 &parkbd_parport_cb, 0);
0150
0151 if (!parkbd_dev)
0152 return -ENODEV;
0153
0154 if (parport_claim(parkbd_dev)) {
0155 parport_unregister_device(parkbd_dev);
0156 return -EBUSY;
0157 }
0158
0159 parkbd_start = jiffies;
0160
0161 return 0;
0162 }
0163
0164 static struct serio *parkbd_allocate_serio(void)
0165 {
0166 struct serio *serio;
0167
0168 serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
0169 if (serio) {
0170 serio->id.type = parkbd_mode;
0171 serio->write = parkbd_write;
0172 strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
0173 snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name);
0174 }
0175
0176 return serio;
0177 }
0178
0179 static void parkbd_attach(struct parport *pp)
0180 {
0181 if (pp->number != parkbd_pp_no) {
0182 pr_debug("Not using parport%d.\n", pp->number);
0183 return;
0184 }
0185
0186 if (parkbd_getport(pp))
0187 return;
0188
0189 parkbd_port = parkbd_allocate_serio();
0190 if (!parkbd_port) {
0191 parport_release(parkbd_dev);
0192 parport_unregister_device(parkbd_dev);
0193 return;
0194 }
0195
0196 parkbd_writelines(3);
0197
0198 serio_register_port(parkbd_port);
0199
0200 printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
0201 parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
0202
0203 return;
0204 }
0205
0206 static void parkbd_detach(struct parport *port)
0207 {
0208 if (!parkbd_port || port->number != parkbd_pp_no)
0209 return;
0210
0211 parport_release(parkbd_dev);
0212 serio_unregister_port(parkbd_port);
0213 parport_unregister_device(parkbd_dev);
0214 parkbd_port = NULL;
0215 }
0216
0217 static struct parport_driver parkbd_parport_driver = {
0218 .name = "parkbd",
0219 .match_port = parkbd_attach,
0220 .detach = parkbd_detach,
0221 .devmodel = true,
0222 };
0223 module_parport_driver(parkbd_parport_driver);