root/drivers/input/gameport/lightning.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. l4_wait_ready
  2. l4_cooked_read
  3. l4_open
  4. l4_getcal
  5. l4_setcal
  6. l4_calibrate
  7. l4_create_ports
  8. l4_add_card
  9. l4_init
  10. l4_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) 1998-2001 Vojtech Pavlik
   4  */
   5 
   6 /*
   7  * PDPI Lightning 4 gamecard driver for Linux.
   8  */
   9 
  10 /*
  11  */
  12 
  13 #include <asm/io.h>
  14 #include <linux/delay.h>
  15 #include <linux/errno.h>
  16 #include <linux/ioport.h>
  17 #include <linux/kernel.h>
  18 #include <linux/module.h>
  19 #include <linux/init.h>
  20 #include <linux/gameport.h>
  21 
  22 #define L4_PORT                 0x201
  23 #define L4_SELECT_ANALOG        0xa4
  24 #define L4_SELECT_DIGITAL       0xa5
  25 #define L4_SELECT_SECONDARY     0xa6
  26 #define L4_CMD_ID               0x80
  27 #define L4_CMD_GETCAL           0x92
  28 #define L4_CMD_SETCAL           0x93
  29 #define L4_ID                   0x04
  30 #define L4_BUSY                 0x01
  31 #define L4_TIMEOUT              80      /* 80 us */
  32 
  33 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  34 MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
  35 MODULE_LICENSE("GPL");
  36 
  37 struct l4 {
  38         struct gameport *gameport;
  39         unsigned char port;
  40 };
  41 
  42 static struct l4 l4_ports[8];
  43 
  44 /*
  45  * l4_wait_ready() waits for the L4 to become ready.
  46  */
  47 
  48 static int l4_wait_ready(void)
  49 {
  50         unsigned int t = L4_TIMEOUT;
  51 
  52         while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
  53         return -(t <= 0);
  54 }
  55 
  56 /*
  57  * l4_cooked_read() reads data from the Lightning 4.
  58  */
  59 
  60 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
  61 {
  62         struct l4 *l4 = gameport->port_data;
  63         unsigned char status;
  64         int i, result = -1;
  65 
  66         outb(L4_SELECT_ANALOG, L4_PORT);
  67         outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
  68 
  69         if (inb(L4_PORT) & L4_BUSY) goto fail;
  70         outb(l4->port & 3, L4_PORT);
  71 
  72         if (l4_wait_ready()) goto fail;
  73         status = inb(L4_PORT);
  74 
  75         for (i = 0; i < 4; i++)
  76                 if (status & (1 << i)) {
  77                         if (l4_wait_ready()) goto fail;
  78                         axes[i] = inb(L4_PORT);
  79                         if (axes[i] > 252) axes[i] = -1;
  80                 }
  81 
  82         if (status & 0x10) {
  83                 if (l4_wait_ready()) goto fail;
  84                 *buttons = inb(L4_PORT) & 0x0f;
  85         }
  86 
  87         result = 0;
  88 
  89 fail:   outb(L4_SELECT_ANALOG, L4_PORT);
  90         return result;
  91 }
  92 
  93 static int l4_open(struct gameport *gameport, int mode)
  94 {
  95         struct l4 *l4 = gameport->port_data;
  96 
  97         if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
  98                 return -1;
  99         outb(L4_SELECT_ANALOG, L4_PORT);
 100         return 0;
 101 }
 102 
 103 /*
 104  * l4_getcal() reads the L4 with calibration values.
 105  */
 106 
 107 static int l4_getcal(int port, int *cal)
 108 {
 109         int i, result = -1;
 110 
 111         outb(L4_SELECT_ANALOG, L4_PORT);
 112         outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
 113         if (inb(L4_PORT) & L4_BUSY)
 114                 goto out;
 115 
 116         outb(L4_CMD_GETCAL, L4_PORT);
 117         if (l4_wait_ready())
 118                 goto out;
 119 
 120         if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
 121                 goto out;
 122 
 123         if (l4_wait_ready())
 124                 goto out;
 125         outb(port & 3, L4_PORT);
 126 
 127         for (i = 0; i < 4; i++) {
 128                 if (l4_wait_ready())
 129                         goto out;
 130                 cal[i] = inb(L4_PORT);
 131         }
 132 
 133         result = 0;
 134 
 135 out:    outb(L4_SELECT_ANALOG, L4_PORT);
 136         return result;
 137 }
 138 
 139 /*
 140  * l4_setcal() programs the L4 with calibration values.
 141  */
 142 
 143 static int l4_setcal(int port, int *cal)
 144 {
 145         int i, result = -1;
 146 
 147         outb(L4_SELECT_ANALOG, L4_PORT);
 148         outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
 149         if (inb(L4_PORT) & L4_BUSY)
 150                 goto out;
 151 
 152         outb(L4_CMD_SETCAL, L4_PORT);
 153         if (l4_wait_ready())
 154                 goto out;
 155 
 156         if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
 157                 goto out;
 158 
 159         if (l4_wait_ready())
 160                 goto out;
 161         outb(port & 3, L4_PORT);
 162 
 163         for (i = 0; i < 4; i++) {
 164                 if (l4_wait_ready())
 165                         goto out;
 166                 outb(cal[i], L4_PORT);
 167         }
 168 
 169         result = 0;
 170 
 171 out:    outb(L4_SELECT_ANALOG, L4_PORT);
 172         return result;
 173 }
 174 
 175 /*
 176  * l4_calibrate() calibrates the L4 for the attached device, so
 177  * that the device's resistance fits into the L4's 8-bit range.
 178  */
 179 
 180 static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
 181 {
 182         int i, t;
 183         int cal[4];
 184         struct l4 *l4 = gameport->port_data;
 185 
 186         if (l4_getcal(l4->port, cal))
 187                 return -1;
 188 
 189         for (i = 0; i < 4; i++) {
 190                 t = (max[i] * cal[i]) / 200;
 191                 t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
 192                 axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
 193                 axes[i] = (axes[i] > 252) ? 252 : axes[i];
 194                 cal[i] = t;
 195         }
 196 
 197         if (l4_setcal(l4->port, cal))
 198                 return -1;
 199 
 200         return 0;
 201 }
 202 
 203 static int __init l4_create_ports(int card_no)
 204 {
 205         struct l4 *l4;
 206         struct gameport *port;
 207         int i, idx;
 208 
 209         for (i = 0; i < 4; i++) {
 210 
 211                 idx = card_no * 4 + i;
 212                 l4 = &l4_ports[idx];
 213 
 214                 if (!(l4->gameport = port = gameport_allocate_port())) {
 215                         printk(KERN_ERR "lightning: Memory allocation failed\n");
 216                         while (--i >= 0) {
 217                                 gameport_free_port(l4->gameport);
 218                                 l4->gameport = NULL;
 219                         }
 220                         return -ENOMEM;
 221                 }
 222                 l4->port = idx;
 223 
 224                 port->port_data = l4;
 225                 port->open = l4_open;
 226                 port->cooked_read = l4_cooked_read;
 227                 port->calibrate = l4_calibrate;
 228 
 229                 gameport_set_name(port, "PDPI Lightning 4");
 230                 gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
 231 
 232                 if (idx == 0)
 233                         port->io = L4_PORT;
 234         }
 235 
 236         return 0;
 237 }
 238 
 239 static int __init l4_add_card(int card_no)
 240 {
 241         int cal[4] = { 255, 255, 255, 255 };
 242         int i, rev, result;
 243         struct l4 *l4;
 244 
 245         outb(L4_SELECT_ANALOG, L4_PORT);
 246         outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
 247 
 248         if (inb(L4_PORT) & L4_BUSY)
 249                 return -1;
 250         outb(L4_CMD_ID, L4_PORT);
 251 
 252         if (l4_wait_ready())
 253                 return -1;
 254 
 255         if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
 256                 return -1;
 257 
 258         if (l4_wait_ready())
 259                 return -1;
 260         if (inb(L4_PORT) != L4_ID)
 261                 return -1;
 262 
 263         if (l4_wait_ready())
 264                 return -1;
 265         rev = inb(L4_PORT);
 266 
 267         if (!rev)
 268                 return -1;
 269 
 270         result = l4_create_ports(card_no);
 271         if (result)
 272                 return result;
 273 
 274         printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
 275                 card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
 276 
 277         for (i = 0; i < 4; i++) {
 278                 l4 = &l4_ports[card_no * 4 + i];
 279 
 280                 if (rev > 0x28)         /* on 2.9+ the setcal command works correctly */
 281                         l4_setcal(l4->port, cal);
 282                 gameport_register_port(l4->gameport);
 283         }
 284 
 285         return 0;
 286 }
 287 
 288 static int __init l4_init(void)
 289 {
 290         int i, cards = 0;
 291 
 292         if (!request_region(L4_PORT, 1, "lightning"))
 293                 return -EBUSY;
 294 
 295         for (i = 0; i < 2; i++)
 296                 if (l4_add_card(i) == 0)
 297                         cards++;
 298 
 299         outb(L4_SELECT_ANALOG, L4_PORT);
 300 
 301         if (!cards) {
 302                 release_region(L4_PORT, 1);
 303                 return -ENODEV;
 304         }
 305 
 306         return 0;
 307 }
 308 
 309 static void __exit l4_exit(void)
 310 {
 311         int i;
 312         int cal[4] = { 59, 59, 59, 59 };
 313 
 314         for (i = 0; i < 8; i++)
 315                 if (l4_ports[i].gameport) {
 316                         l4_setcal(l4_ports[i].port, cal);
 317                         gameport_unregister_port(l4_ports[i].gameport);
 318                 }
 319 
 320         outb(L4_SELECT_ANALOG, L4_PORT);
 321         release_region(L4_PORT, 1);
 322 }
 323 
 324 module_init(l4_init);
 325 module_exit(l4_exit);

/* [<][>][^][v][top][bottom][index][help] */