0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <asm/io.h>
0014 #include <linux/delay.h>
0015 #include <linux/errno.h>
0016 #include <linux/ioport.h>
0017 #include <linux/kernel.h>
0018 #include <linux/module.h>
0019 #include <linux/init.h>
0020 #include <linux/gameport.h>
0021
0022 #define L4_PORT 0x201
0023 #define L4_SELECT_ANALOG 0xa4
0024 #define L4_SELECT_DIGITAL 0xa5
0025 #define L4_SELECT_SECONDARY 0xa6
0026 #define L4_CMD_ID 0x80
0027 #define L4_CMD_GETCAL 0x92
0028 #define L4_CMD_SETCAL 0x93
0029 #define L4_ID 0x04
0030 #define L4_BUSY 0x01
0031 #define L4_TIMEOUT 80
0032
0033 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0034 MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
0035 MODULE_LICENSE("GPL");
0036
0037 struct l4 {
0038 struct gameport *gameport;
0039 unsigned char port;
0040 };
0041
0042 static struct l4 l4_ports[8];
0043
0044
0045
0046
0047
0048 static int l4_wait_ready(void)
0049 {
0050 unsigned int t = L4_TIMEOUT;
0051
0052 while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
0053 return -(t <= 0);
0054 }
0055
0056
0057
0058
0059
0060 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
0061 {
0062 struct l4 *l4 = gameport->port_data;
0063 unsigned char status;
0064 int i, result = -1;
0065
0066 outb(L4_SELECT_ANALOG, L4_PORT);
0067 outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
0068
0069 if (inb(L4_PORT) & L4_BUSY) goto fail;
0070 outb(l4->port & 3, L4_PORT);
0071
0072 if (l4_wait_ready()) goto fail;
0073 status = inb(L4_PORT);
0074
0075 for (i = 0; i < 4; i++)
0076 if (status & (1 << i)) {
0077 if (l4_wait_ready()) goto fail;
0078 axes[i] = inb(L4_PORT);
0079 if (axes[i] > 252) axes[i] = -1;
0080 }
0081
0082 if (status & 0x10) {
0083 if (l4_wait_ready()) goto fail;
0084 *buttons = inb(L4_PORT) & 0x0f;
0085 }
0086
0087 result = 0;
0088
0089 fail: outb(L4_SELECT_ANALOG, L4_PORT);
0090 return result;
0091 }
0092
0093 static int l4_open(struct gameport *gameport, int mode)
0094 {
0095 struct l4 *l4 = gameport->port_data;
0096
0097 if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
0098 return -1;
0099 outb(L4_SELECT_ANALOG, L4_PORT);
0100 return 0;
0101 }
0102
0103
0104
0105
0106
0107 static int l4_getcal(int port, int *cal)
0108 {
0109 int i, result = -1;
0110
0111 outb(L4_SELECT_ANALOG, L4_PORT);
0112 outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
0113 if (inb(L4_PORT) & L4_BUSY)
0114 goto out;
0115
0116 outb(L4_CMD_GETCAL, L4_PORT);
0117 if (l4_wait_ready())
0118 goto out;
0119
0120 if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
0121 goto out;
0122
0123 if (l4_wait_ready())
0124 goto out;
0125 outb(port & 3, L4_PORT);
0126
0127 for (i = 0; i < 4; i++) {
0128 if (l4_wait_ready())
0129 goto out;
0130 cal[i] = inb(L4_PORT);
0131 }
0132
0133 result = 0;
0134
0135 out: outb(L4_SELECT_ANALOG, L4_PORT);
0136 return result;
0137 }
0138
0139
0140
0141
0142
0143 static int l4_setcal(int port, int *cal)
0144 {
0145 int i, result = -1;
0146
0147 outb(L4_SELECT_ANALOG, L4_PORT);
0148 outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
0149 if (inb(L4_PORT) & L4_BUSY)
0150 goto out;
0151
0152 outb(L4_CMD_SETCAL, L4_PORT);
0153 if (l4_wait_ready())
0154 goto out;
0155
0156 if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
0157 goto out;
0158
0159 if (l4_wait_ready())
0160 goto out;
0161 outb(port & 3, L4_PORT);
0162
0163 for (i = 0; i < 4; i++) {
0164 if (l4_wait_ready())
0165 goto out;
0166 outb(cal[i], L4_PORT);
0167 }
0168
0169 result = 0;
0170
0171 out: outb(L4_SELECT_ANALOG, L4_PORT);
0172 return result;
0173 }
0174
0175
0176
0177
0178
0179
0180 static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
0181 {
0182 int i, t;
0183 int cal[4];
0184 struct l4 *l4 = gameport->port_data;
0185
0186 if (l4_getcal(l4->port, cal))
0187 return -1;
0188
0189 for (i = 0; i < 4; i++) {
0190 t = (max[i] * cal[i]) / 200;
0191 t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
0192 axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
0193 axes[i] = (axes[i] > 252) ? 252 : axes[i];
0194 cal[i] = t;
0195 }
0196
0197 if (l4_setcal(l4->port, cal))
0198 return -1;
0199
0200 return 0;
0201 }
0202
0203 static int __init l4_create_ports(int card_no)
0204 {
0205 struct l4 *l4;
0206 struct gameport *port;
0207 int i, idx;
0208
0209 for (i = 0; i < 4; i++) {
0210
0211 idx = card_no * 4 + i;
0212 l4 = &l4_ports[idx];
0213
0214 if (!(l4->gameport = port = gameport_allocate_port())) {
0215 printk(KERN_ERR "lightning: Memory allocation failed\n");
0216 while (--i >= 0) {
0217 gameport_free_port(l4->gameport);
0218 l4->gameport = NULL;
0219 }
0220 return -ENOMEM;
0221 }
0222 l4->port = idx;
0223
0224 port->port_data = l4;
0225 port->open = l4_open;
0226 port->cooked_read = l4_cooked_read;
0227 port->calibrate = l4_calibrate;
0228
0229 gameport_set_name(port, "PDPI Lightning 4");
0230 gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
0231
0232 if (idx == 0)
0233 port->io = L4_PORT;
0234 }
0235
0236 return 0;
0237 }
0238
0239 static int __init l4_add_card(int card_no)
0240 {
0241 int cal[4] = { 255, 255, 255, 255 };
0242 int i, rev, result;
0243 struct l4 *l4;
0244
0245 outb(L4_SELECT_ANALOG, L4_PORT);
0246 outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
0247
0248 if (inb(L4_PORT) & L4_BUSY)
0249 return -1;
0250 outb(L4_CMD_ID, L4_PORT);
0251
0252 if (l4_wait_ready())
0253 return -1;
0254
0255 if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
0256 return -1;
0257
0258 if (l4_wait_ready())
0259 return -1;
0260 if (inb(L4_PORT) != L4_ID)
0261 return -1;
0262
0263 if (l4_wait_ready())
0264 return -1;
0265 rev = inb(L4_PORT);
0266
0267 if (!rev)
0268 return -1;
0269
0270 result = l4_create_ports(card_no);
0271 if (result)
0272 return result;
0273
0274 printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
0275 card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
0276
0277 for (i = 0; i < 4; i++) {
0278 l4 = &l4_ports[card_no * 4 + i];
0279
0280 if (rev > 0x28)
0281 l4_setcal(l4->port, cal);
0282 gameport_register_port(l4->gameport);
0283 }
0284
0285 return 0;
0286 }
0287
0288 static int __init l4_init(void)
0289 {
0290 int i, cards = 0;
0291
0292 if (!request_region(L4_PORT, 1, "lightning"))
0293 return -EBUSY;
0294
0295 for (i = 0; i < 2; i++)
0296 if (l4_add_card(i) == 0)
0297 cards++;
0298
0299 outb(L4_SELECT_ANALOG, L4_PORT);
0300
0301 if (!cards) {
0302 release_region(L4_PORT, 1);
0303 return -ENODEV;
0304 }
0305
0306 return 0;
0307 }
0308
0309 static void __exit l4_exit(void)
0310 {
0311 int i;
0312 int cal[4] = { 59, 59, 59, 59 };
0313
0314 for (i = 0; i < 8; i++)
0315 if (l4_ports[i].gameport) {
0316 l4_setcal(l4_ports[i].port, cal);
0317 gameport_unregister_port(l4_ports[i].gameport);
0318 }
0319
0320 outb(L4_SELECT_ANALOG, L4_PORT);
0321 release_region(L4_PORT, 1);
0322 }
0323
0324 module_init(l4_init);
0325 module_exit(l4_exit);