Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  FM801 gameport driver for Linux
0004  *
0005  *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
0006  */
0007 
0008 #include <asm/io.h>
0009 #include <linux/delay.h>
0010 #include <linux/errno.h>
0011 #include <linux/ioport.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/pci.h>
0015 #include <linux/slab.h>
0016 #include <linux/gameport.h>
0017 
0018 #define PCI_VENDOR_ID_FORTEMEDIA    0x1319
0019 #define PCI_DEVICE_ID_FM801_GP  0x0802
0020 
0021 #define HAVE_COOKED
0022 
0023 struct fm801_gp {
0024     struct gameport *gameport;
0025     struct resource *res_port;
0026 };
0027 
0028 #ifdef HAVE_COOKED
0029 static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
0030 {
0031     unsigned short w;
0032 
0033     w = inw(gameport->io + 2);
0034     *buttons = (~w >> 14) & 0x03;
0035     axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
0036     w = inw(gameport->io + 4);
0037     axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
0038     w = inw(gameport->io + 6);
0039     *buttons |= ((~w >> 14) & 0x03) << 2;
0040     axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
0041     w = inw(gameport->io + 8);
0042     axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
0043     outw(0xff, gameport->io); /* reset */
0044 
0045         return 0;
0046 }
0047 #endif
0048 
0049 static int fm801_gp_open(struct gameport *gameport, int mode)
0050 {
0051     switch (mode) {
0052 #ifdef HAVE_COOKED
0053     case GAMEPORT_MODE_COOKED:
0054         return 0;
0055 #endif
0056     case GAMEPORT_MODE_RAW:
0057         return 0;
0058     default:
0059         return -1;
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
0066 {
0067     struct fm801_gp *gp;
0068     struct gameport *port;
0069     int error;
0070 
0071     gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
0072     port = gameport_allocate_port();
0073     if (!gp || !port) {
0074         printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
0075         error = -ENOMEM;
0076         goto err_out_free;
0077     }
0078 
0079     error = pci_enable_device(pci);
0080     if (error)
0081         goto err_out_free;
0082 
0083     port->open = fm801_gp_open;
0084 #ifdef HAVE_COOKED
0085     port->cooked_read = fm801_gp_cooked_read;
0086 #endif
0087     gameport_set_name(port, "FM801");
0088     gameport_set_phys(port, "pci%s/gameport0", pci_name(pci));
0089     port->dev.parent = &pci->dev;
0090     port->io = pci_resource_start(pci, 0);
0091 
0092     gp->gameport = port;
0093     gp->res_port = request_region(port->io, 0x10, "FM801 GP");
0094     if (!gp->res_port) {
0095         printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
0096             port->io, port->io + 0x0f);
0097         error = -EBUSY;
0098         goto err_out_disable_dev;
0099     }
0100 
0101     pci_set_drvdata(pci, gp);
0102 
0103     outb(0x60, port->io + 0x0d); /* enable joystick 1 and 2 */
0104     gameport_register_port(port);
0105 
0106     return 0;
0107 
0108  err_out_disable_dev:
0109     pci_disable_device(pci);
0110  err_out_free:
0111     gameport_free_port(port);
0112     kfree(gp);
0113     return error;
0114 }
0115 
0116 static void fm801_gp_remove(struct pci_dev *pci)
0117 {
0118     struct fm801_gp *gp = pci_get_drvdata(pci);
0119 
0120     gameport_unregister_port(gp->gameport);
0121     release_resource(gp->res_port);
0122     kfree(gp);
0123 
0124     pci_disable_device(pci);
0125 }
0126 
0127 static const struct pci_device_id fm801_gp_id_table[] = {
0128     { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0  },
0129     { 0 }
0130 };
0131 MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
0132 
0133 static struct pci_driver fm801_gp_driver = {
0134     .name =     "FM801_gameport",
0135     .id_table = fm801_gp_id_table,
0136     .probe =    fm801_gp_probe,
0137     .remove =   fm801_gp_remove,
0138 };
0139 
0140 module_pci_driver(fm801_gp_driver);
0141 
0142 MODULE_DESCRIPTION("FM801 gameport driver");
0143 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0144 MODULE_LICENSE("GPL");