root/drivers/input/gameport/ns558.c

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

DEFINITIONS

This source file includes following definitions.
  1. ns558_isa_probe
  2. ns558_pnp_probe
  3. ns558_init
  4. ns558_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) 1999-2001 Vojtech Pavlik
   4  *  Copyright (c) 1999 Brian Gerst
   5  */
   6 
   7 /*
   8  * NS558 based standard IBM game port driver for Linux
   9  */
  10 
  11 /*
  12  */
  13 
  14 #include <asm/io.h>
  15 
  16 #include <linux/module.h>
  17 #include <linux/ioport.h>
  18 #include <linux/init.h>
  19 #include <linux/delay.h>
  20 #include <linux/gameport.h>
  21 #include <linux/slab.h>
  22 #include <linux/pnp.h>
  23 
  24 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  25 MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
  26 MODULE_LICENSE("GPL");
  27 
  28 static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
  29                                     0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
  30 
  31 struct ns558 {
  32         int type;
  33         int io;
  34         int size;
  35         struct pnp_dev *dev;
  36         struct gameport *gameport;
  37         struct list_head node;
  38 };
  39 
  40 static LIST_HEAD(ns558_list);
  41 
  42 /*
  43  * ns558_isa_probe() tries to find an isa gameport at the
  44  * specified address, and also checks for mirrors.
  45  * A joystick must be attached for this to work.
  46  */
  47 
  48 static int ns558_isa_probe(int io)
  49 {
  50         int i, j, b;
  51         unsigned char c, u, v;
  52         struct ns558 *ns558;
  53         struct gameport *port;
  54 
  55 /*
  56  * No one should be using this address.
  57  */
  58 
  59         if (!request_region(io, 1, "ns558-isa"))
  60                 return -EBUSY;
  61 
  62 /*
  63  * We must not be able to write arbitrary values to the port.
  64  * The lower two axis bits must be 1 after a write.
  65  */
  66 
  67         c = inb(io);
  68         outb(~c & ~3, io);
  69         if (~(u = v = inb(io)) & 3) {
  70                 outb(c, io);
  71                 release_region(io, 1);
  72                 return -ENODEV;
  73         }
  74 /*
  75  * After a trigger, there must be at least some bits changing.
  76  */
  77 
  78         for (i = 0; i < 1000; i++) v &= inb(io);
  79 
  80         if (u == v) {
  81                 outb(c, io);
  82                 release_region(io, 1);
  83                 return -ENODEV;
  84         }
  85         msleep(3);
  86 /*
  87  * After some time (4ms) the axes shouldn't change anymore.
  88  */
  89 
  90         u = inb(io);
  91         for (i = 0; i < 1000; i++)
  92                 if ((u ^ inb(io)) & 0xf) {
  93                         outb(c, io);
  94                         release_region(io, 1);
  95                         return -ENODEV;
  96                 }
  97 /*
  98  * And now find the number of mirrors of the port.
  99  */
 100 
 101         for (i = 1; i < 5; i++) {
 102 
 103                 release_region(io & (-1 << (i - 1)), (1 << (i - 1)));
 104 
 105                 if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
 106                         break;                          /* Don't disturb anyone */
 107 
 108                 outb(0xff, io & (-1 << i));
 109                 for (j = b = 0; j < 1000; j++)
 110                         if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
 111                 msleep(3);
 112 
 113                 if (b > 300) {                          /* We allow 30% difference */
 114                         release_region(io & (-1 << i), (1 << i));
 115                         break;
 116                 }
 117         }
 118 
 119         i--;
 120 
 121         if (i != 4) {
 122                 if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
 123                         return -EBUSY;
 124         }
 125 
 126         ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
 127         port = gameport_allocate_port();
 128         if (!ns558 || !port) {
 129                 printk(KERN_ERR "ns558: Memory allocation failed.\n");
 130                 release_region(io & (-1 << i), (1 << i));
 131                 kfree(ns558);
 132                 gameport_free_port(port);
 133                 return -ENOMEM;
 134         }
 135 
 136         ns558->io = io;
 137         ns558->size = 1 << i;
 138         ns558->gameport = port;
 139 
 140         port->io = io;
 141         gameport_set_name(port, "NS558 ISA Gameport");
 142         gameport_set_phys(port, "isa%04x/gameport0", io & (-1 << i));
 143 
 144         gameport_register_port(port);
 145 
 146         list_add(&ns558->node, &ns558_list);
 147 
 148         return 0;
 149 }
 150 
 151 #ifdef CONFIG_PNP
 152 
 153 static const struct pnp_device_id pnp_devids[] = {
 154         { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
 155         { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
 156         { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
 157         { .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
 158         { .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
 159         { .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
 160         { .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
 161         { .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
 162         { .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
 163         { .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
 164         { .id = "CTL7001", .driver_data = 0 }, /* SB16 */
 165         { .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
 166         { .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
 167         { .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
 168         { .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
 169         { .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
 170         { .id = "ESS6880", .driver_data = 0 }, /* ES688 */
 171         { .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
 172         { .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
 173         { .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
 174         { .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
 175         { .id = "PNPb02f", .driver_data = 0 }, /* Generic */
 176         { .id = "", },
 177 };
 178 
 179 MODULE_DEVICE_TABLE(pnp, pnp_devids);
 180 
 181 static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 182 {
 183         int ioport, iolen;
 184         struct ns558 *ns558;
 185         struct gameport *port;
 186 
 187         if (!pnp_port_valid(dev, 0)) {
 188                 printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
 189                 return -ENODEV;
 190         }
 191 
 192         ioport = pnp_port_start(dev, 0);
 193         iolen = pnp_port_len(dev, 0);
 194 
 195         if (!request_region(ioport, iolen, "ns558-pnp"))
 196                 return -EBUSY;
 197 
 198         ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
 199         port = gameport_allocate_port();
 200         if (!ns558 || !port) {
 201                 printk(KERN_ERR "ns558: Memory allocation failed\n");
 202                 kfree(ns558);
 203                 gameport_free_port(port);
 204                 return -ENOMEM;
 205         }
 206 
 207         ns558->io = ioport;
 208         ns558->size = iolen;
 209         ns558->dev = dev;
 210         ns558->gameport = port;
 211 
 212         gameport_set_name(port, "NS558 PnP Gameport");
 213         gameport_set_phys(port, "pnp%s/gameport0", dev_name(&dev->dev));
 214         port->dev.parent = &dev->dev;
 215         port->io = ioport;
 216 
 217         gameport_register_port(port);
 218 
 219         list_add_tail(&ns558->node, &ns558_list);
 220         return 0;
 221 }
 222 
 223 static struct pnp_driver ns558_pnp_driver = {
 224         .name           = "ns558",
 225         .id_table       = pnp_devids,
 226         .probe          = ns558_pnp_probe,
 227 };
 228 
 229 #else
 230 
 231 static struct pnp_driver ns558_pnp_driver;
 232 
 233 #endif
 234 
 235 static int __init ns558_init(void)
 236 {
 237         int i = 0;
 238         int error;
 239 
 240         error = pnp_register_driver(&ns558_pnp_driver);
 241         if (error && error != -ENODEV)  /* should be ENOSYS really */
 242                 return error;
 243 
 244 /*
 245  * Probe ISA ports after PnP, so that PnP ports that are already
 246  * enabled get detected as PnP. This may be suboptimal in multi-device
 247  * configurations, but saves hassle with simple setups.
 248  */
 249 
 250         while (ns558_isa_portlist[i])
 251                 ns558_isa_probe(ns558_isa_portlist[i++]);
 252 
 253         return list_empty(&ns558_list) && error ? -ENODEV : 0;
 254 }
 255 
 256 static void __exit ns558_exit(void)
 257 {
 258         struct ns558 *ns558, *safe;
 259 
 260         list_for_each_entry_safe(ns558, safe, &ns558_list, node) {
 261                 gameport_unregister_port(ns558->gameport);
 262                 release_region(ns558->io & ~(ns558->size - 1), ns558->size);
 263                 kfree(ns558);
 264         }
 265 
 266         pnp_unregister_driver(&ns558_pnp_driver);
 267 }
 268 
 269 module_init(ns558_init);
 270 module_exit(ns558_exit);

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