v2.4.7.8 -> v2.4.8
[opensuse:kernel.git] / drivers / sound / emu10k1 / joystick.c
1 /*
2  **********************************************************************
3  *     joystick.c - Creative EMU10K1 Joystick port driver
4  *     Copyright 2000 Rui Sousa.
5  *
6  **********************************************************************
7  *
8  *     Date                 Author          Summary of changes
9  *     ----                 ------          ------------------
10  *     April  1, 2000       Rui Sousa       initial version 
11  *     April 28, 2000       Rui Sousa       fixed a kernel oops,
12  *                                          make use of kcompat24 for
13  *                                          2.2 kernels compatibility.
14  *     May    1, 2000       Rui Sousa       improved kernel compatibility
15  *                                          layer.
16  *
17  **********************************************************************
18  *
19  *     This program is free software; you can redistribute it and/or
20  *     modify it under the terms of the GNU General Public License as
21  *     published by the Free Software Foundation; either version 2 of
22  *     the License, or (at your option) any later version.
23  *
24  *     This program is distributed in the hope that it will be useful,
25  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *     GNU General Public License for more details.
28  *
29  *     You should have received a copy of the GNU General Public
30  *     License along with this program; if not, write to the Free
31  *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
32  *     USA.
33  *
34  **********************************************************************/
35
36 #include <linux/module.h>
37 #include <linux/init.h>
38 #include <linux/version.h>
39 #include <linux/pci.h>
40 #include <linux/slab.h>
41 #include <linux/ioport.h>
42 #include <linux/list.h>
43
44 #define DRIVER_VERSION "0.3.1"
45
46 #ifndef PCI_VENDOR_ID_CREATIVE
47 #define PCI_VENDOR_ID_CREATIVE 0x1102
48 #endif
49
50 #ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1_JOYSTICK
51 #define PCI_DEVICE_ID_CREATIVE_EMU10K1_JOYSTICK 0x7002
52 #endif
53
54 /* PCI function 1 registers, address = <val> + PCIBASE1 */
55
56 #define JOYSTICK1               0x00            /* Analog joystick port register                */
57 #define JOYSTICK2               0x01            /* Analog joystick port register                */
58 #define JOYSTICK3               0x02            /* Analog joystick port register                */
59 #define JOYSTICK4               0x03            /* Analog joystick port register                */
60 #define JOYSTICK5               0x04            /* Analog joystick port register                */
61 #define JOYSTICK6               0x05            /* Analog joystick port register                */
62 #define JOYSTICK7               0x06            /* Analog joystick port register                */
63 #define JOYSTICK8               0x07            /* Analog joystick port register                */
64
65 /* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write.      */
66 /* When reading, use these bitfields: */
67 #define JOYSTICK_BUTTONS        0x0f            /* Joystick button data                         */
68 #define JOYSTICK_COMPARATOR     0xf0            /* Joystick comparator data                     */
69
70 #define NR_DEV 5
71
72 static int io[NR_DEV] = { 0, };
73
74 enum {
75         EMU10K1_JOYSTICK = 0
76 };
77
78 static char *card_names[] = {
79         "EMU10K1 Joystick Port"
80 };
81
82 static struct pci_device_id emu10k1_joy_pci_tbl[] __devinitdata = {
83         {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1_JOYSTICK,
84          PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1_JOYSTICK},
85         {0,}
86 };
87
88 MODULE_DEVICE_TABLE(pci, emu10k1_joy_pci_tbl);
89
90 struct emu10k1_joy_card {
91         struct list_head list;
92
93         struct pci_dev *pci_dev;
94         unsigned long iobase;
95         unsigned long length;
96         u8 addr_changed;
97 };
98
99 static LIST_HEAD(emu10k1_joy_devs);
100 static unsigned int devindex = 0;
101
102 /* Driver initialization routine */
103 static int __devinit emu10k1_joy_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
104 {
105         struct emu10k1_joy_card *card;
106         u16 model;
107         u8 chiprev;
108
109         if ((card = kmalloc(sizeof(struct emu10k1_joy_card), GFP_KERNEL)) == NULL) {
110                 printk(KERN_ERR "emu10k1-joy: out of memory\n");
111                 return -ENOMEM;
112         }
113         memset(card, 0, sizeof(struct emu10k1_joy_card));
114
115         if (pci_enable_device(pci_dev)) {
116                 printk(KERN_ERR "emu10k1-joy: couldn't enable device\n");
117                 kfree(card);
118                 return -ENODEV;
119         }
120
121         card->iobase = pci_resource_start(pci_dev, 0); 
122         card->length = pci_resource_len(pci_dev, 0);
123
124         if (request_region(card->iobase, card->length, card_names[pci_id->driver_data])
125             == NULL) {
126                 printk(KERN_ERR "emu10k1-joy: IO space in use\n");
127                 kfree(card);
128                 return -ENODEV;
129         }
130
131         pci_set_drvdata(pci_dev, card);
132
133         card->pci_dev = pci_dev;
134         card->addr_changed = 0;
135
136         pci_read_config_byte(pci_dev, PCI_REVISION_ID, &chiprev);
137         pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &model);
138
139         printk(KERN_INFO "emu10k1-joy: %s rev %d model 0x%x found, IO at 0x%04lx-0x%04lx\n",
140                 card_names[pci_id->driver_data], chiprev, model, card->iobase,
141                 card->iobase + card->length - 1);
142
143         if (io[devindex]) {
144                 if ((io[devindex] & ~0x18) != 0x200) {
145                         printk(KERN_ERR "emu10k1-joy: invalid io value\n");
146                         release_region(card->iobase, card->length);
147                         kfree(card);
148                         return -ENODEV;
149                 }
150
151                 card->addr_changed = 1;
152                 pci_write_config_dword(pci_dev, PCI_BASE_ADDRESS_0, io[devindex]);
153                 printk(KERN_INFO "emu10k1-joy: IO ports mirrored at 0x%03x\n", io[devindex]);
154         }
155
156         list_add(&card->list, &emu10k1_joy_devs);
157         devindex++;
158
159         return 0;
160 }
161
162 static void __devexit emu10k1_joy_remove(struct pci_dev *pci_dev)
163 {
164         struct emu10k1_joy_card *card = pci_get_drvdata(pci_dev);
165
166         if(card->addr_changed)
167                 pci_write_config_dword(pci_dev, PCI_BASE_ADDRESS_0, card->iobase);
168
169         release_region(card->iobase, card->length);
170
171         list_del(&card->list);
172         kfree(card);
173         pci_set_drvdata(pci_dev, NULL);
174 }
175
176 MODULE_PARM(io, "1-" __MODULE_STRING(NR_DEV) "i");
177 MODULE_PARM_DESC(io, "sets joystick port address");
178 MODULE_AUTHOR("Rui Sousa (Email to: emu10k1-devel@opensource.creative.com)");
179 MODULE_DESCRIPTION("Creative EMU10K1 PCI Joystick Port v" DRIVER_VERSION
180                    "\nCopyright (C) 2000 Rui Sousa");
181
182 static struct pci_driver emu10k1_joy_pci_driver = {
183         name:"emu10k1 joystick",
184         id_table:emu10k1_joy_pci_tbl,
185         probe:emu10k1_joy_probe,
186         remove:emu10k1_joy_remove,
187 };
188
189 static int __init emu10k1_joy_init_module(void)
190 {
191         printk(KERN_INFO "Creative EMU10K1 PCI Joystick Port, version " DRIVER_VERSION ", " __TIME__
192                " " __DATE__ "\n");
193
194         return pci_module_init(&emu10k1_joy_pci_driver);
195 }
196
197 static void __exit emu10k1_joy_cleanup_module(void)
198 {
199         pci_unregister_driver(&emu10k1_joy_pci_driver);
200         return;
201 }
202
203 module_init(emu10k1_joy_init_module);
204 module_exit(emu10k1_joy_cleanup_module);