11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1998-2001 Vojtech Pavlik 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PDPI Lightning 4 gamecard driver for Linux. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/gameport.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_PORT 0x201 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_SELECT_ANALOG 0xa4 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_SELECT_DIGITAL 0xa5 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_SELECT_SECONDARY 0xa6 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_CMD_ID 0x80 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_CMD_GETCAL 0x92 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_CMD_SETCAL 0x93 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_ID 0x04 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_BUSY 0x01 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L4_TIMEOUT 80 /* 80 us */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver"); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct l4 { 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *gameport; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char port; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct l4 l4_ports[8]; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * l4_wait_ready() waits for the L4 to become ready. 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_wait_ready(void) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int t = L4_TIMEOUT; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -(t <= 0); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * l4_cooked_read() reads data from the Lightning 4. 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct l4 *l4 = gameport->port_data; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, result = -1; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) & L4_BUSY) goto fail; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(l4->port & 3, L4_PORT); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) goto fail; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = inb(L4_PORT); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (1 << i)) { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) goto fail; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds axes[i] = inb(L4_PORT); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (axes[i] > 252) axes[i] = -1; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & 0x10) { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) goto fail; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buttons = inb(L4_PORT) & 0x0f; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = 0; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail: outb(L4_SELECT_ANALOG, L4_PORT); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_open(struct gameport *gameport, int mode) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct l4 *l4 = gameport->port_data; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * l4_getcal() reads the L4 with calibration values. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_getcal(int port, int *cal) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, result = -1; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) & L4_BUSY) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_CMD_GETCAL, L4_PORT); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(port & 3, L4_PORT); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cal[i] = inb(L4_PORT); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: outb(L4_SELECT_ANALOG, L4_PORT); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * l4_setcal() programs the L4 with calibration values. 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_setcal(int port, int *cal) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, result = -1; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) & L4_BUSY) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_CMD_SETCAL, L4_PORT); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(port & 3, L4_PORT); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(cal[i], L4_PORT); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = 0; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: outb(L4_SELECT_ANALOG, L4_PORT); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * l4_calibrate() calibrates the L4 for the attached device, so 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the device's resistance fits into the L4's 8-bit range. 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int l4_calibrate(struct gameport *gameport, int *axes, int *max) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, t; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cal[4]; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct l4 *l4 = gameport->port_data; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_getcal(l4->port, cal)) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = (max[i] * cal[i]) / 200; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = (t < 1) ? 1 : ((t > 255) ? 255 : t); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds axes[i] = (axes[i] > 252) ? 252 : axes[i]; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cal[i] = t; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_setcal(l4->port, cal)) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init l4_create_ports(int card_no) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct l4 *l4; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *port; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, idx; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx = card_no * 4 + i; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4 = &l4_ports[idx]; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(l4->gameport = port = gameport_allocate_port())) { 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "lightning: Memory allocation failed\n"); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--i >= 0) { 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_free_port(l4->gameport); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4->gameport = NULL; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4->port = idx; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->port_data = l4; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->open = l4_open; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->cooked_read = l4_cooked_read; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->calibrate = l4_calibrate; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_name(port, "PDPI Lightning 4"); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx == 0) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->io = L4_PORT; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init l4_add_card(int card_no) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cal[4] = { 255, 255, 255, 255 }; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, rev, result; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct l4 *l4; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_DIGITAL + card_no, L4_PORT); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) & L4_BUSY) 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_CMD_ID, L4_PORT); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(L4_PORT) != L4_ID) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_wait_ready()) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rev = inb(L4_PORT); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rev) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = l4_create_ports(card_no); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n", 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4 = &l4_ports[card_no * 4 + i]; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rev > 0x28) /* on 2.9+ the setcal command works correctly */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4_setcal(l4->port, cal); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_register_port(l4->gameport); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init l4_init(void) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, cards = 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(L4_PORT, 1, "lightning")) 3096a89bc0004c8d9400439db6167c9887456d5d18dAkinobu Mita return -EBUSY; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_add_card(i) == 0) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards++; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cards) { 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(L4_PORT, 1); 3196a89bc0004c8d9400439db6167c9887456d5d18dAkinobu Mita return -ENODEV; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit l4_exit(void) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cal[4] = { 59, 59, 59, 59 }; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l4_ports[i].gameport) { 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l4_setcal(l4_ports[i].port, cal); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_unregister_port(l4_ports[i].gameport); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(L4_SELECT_ANALOG, L4_PORT); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(L4_PORT, 1); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(l4_init); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(l4_exit); 342