PageRenderTime 44ms CodeModel.GetById 12ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/input/gameport/cs461x.c

https://bitbucket.org/evzijst/gittest
C | 322 lines | 235 code | 59 blank | 28 comment | 29 complexity | aa639f5adb08b1f26ec97ed5bcbaa6df MD5 | raw file
  1/*
  2	The all defines and part of code (such as cs461x_*) are
  3	contributed from ALSA 0.5.8 sources.
  4	See http://www.alsa-project.org/ for sources
  5
  6	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
  7*/
  8
  9#include <asm/io.h>
 10
 11#include <linux/module.h>
 12#include <linux/ioport.h>
 13#include <linux/config.h>
 14#include <linux/init.h>
 15#include <linux/gameport.h>
 16#include <linux/slab.h>
 17#include <linux/pci.h>
 18
 19MODULE_AUTHOR("Victor Krapivin");
 20MODULE_LICENSE("GPL");
 21
 22/*
 23	These options are experimental
 24
 25#define CS461X_FULL_MAP
 26*/
 27
 28
 29#ifndef PCI_VENDOR_ID_CIRRUS
 30#define PCI_VENDOR_ID_CIRRUS            0x1013
 31#endif
 32#ifndef PCI_DEVICE_ID_CIRRUS_4610
 33#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
 34#endif
 35#ifndef PCI_DEVICE_ID_CIRRUS_4612
 36#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
 37#endif
 38#ifndef PCI_DEVICE_ID_CIRRUS_4615
 39#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
 40#endif
 41
 42/* Registers */
 43
 44#define BA0_JSPT                                0x00000480
 45#define BA0_JSCTL                               0x00000484
 46#define BA0_JSC1                                0x00000488
 47#define BA0_JSC2                                0x0000048C
 48#define BA0_JSIO                                0x000004A0
 49
 50/* Bits for JSPT */
 51
 52#define JSPT_CAX                                0x00000001
 53#define JSPT_CAY                                0x00000002
 54#define JSPT_CBX                                0x00000004
 55#define JSPT_CBY                                0x00000008
 56#define JSPT_BA1                                0x00000010
 57#define JSPT_BA2                                0x00000020
 58#define JSPT_BB1                                0x00000040
 59#define JSPT_BB2                                0x00000080
 60
 61/* Bits for JSCTL */
 62
 63#define JSCTL_SP_MASK                           0x00000003
 64#define JSCTL_SP_SLOW                           0x00000000
 65#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
 66#define JSCTL_SP_MEDIUM_FAST                    0x00000002
 67#define JSCTL_SP_FAST                           0x00000003
 68#define JSCTL_ARE                               0x00000004
 69
 70/* Data register pairs masks */
 71
 72#define JSC1_Y1V_MASK                           0x0000FFFF
 73#define JSC1_X1V_MASK                           0xFFFF0000
 74#define JSC1_Y1V_SHIFT                          0
 75#define JSC1_X1V_SHIFT                          16
 76#define JSC2_Y2V_MASK                           0x0000FFFF
 77#define JSC2_X2V_MASK                           0xFFFF0000
 78#define JSC2_Y2V_SHIFT                          0
 79#define JSC2_X2V_SHIFT                          16
 80
 81/* JS GPIO */
 82
 83#define JSIO_DAX                                0x00000001
 84#define JSIO_DAY                                0x00000002
 85#define JSIO_DBX                                0x00000004
 86#define JSIO_DBY                                0x00000008
 87#define JSIO_AXOE                               0x00000010
 88#define JSIO_AYOE                               0x00000020
 89#define JSIO_BXOE                               0x00000040
 90#define JSIO_BYOE                               0x00000080
 91
 92/*
 93   The card initialization code is obfuscated; the module cs461x
 94   need to be loaded after ALSA modules initialized and something
 95   played on the CS 4610 chip (see sources for details of CS4610
 96   initialization code from ALSA)
 97*/
 98
 99/* Card specific definitions */
100
101#define CS461X_BA0_SIZE         0x2000
102#define CS461X_BA1_DATA0_SIZE   0x3000
103#define CS461X_BA1_DATA1_SIZE   0x3800
104#define CS461X_BA1_PRG_SIZE     0x7000
105#define CS461X_BA1_REG_SIZE     0x0100
106
107#define BA1_SP_DMEM0                            0x00000000
108#define BA1_SP_DMEM1                            0x00010000
109#define BA1_SP_PMEM                             0x00020000
110#define BA1_SP_REG                              0x00030000
111
112#define BA1_DWORD_SIZE          (13 * 1024 + 512)
113#define BA1_MEMORY_COUNT        3
114
115/*
116   Only one CS461x card is still suppoted; the code requires
117   redesign to avoid this limitatuion.
118*/
119
120static unsigned long ba0_addr;
121static unsigned int __iomem *ba0;
122
123#ifdef CS461X_FULL_MAP
124static unsigned long ba1_addr;
125static union ba1_t {
126        struct {
127                unsigned int __iomem *data0;
128                unsigned int __iomem *data1;
129                unsigned int __iomem *pmem;
130                unsigned int __iomem *reg;
131        } name;
132        unsigned int __iomem *idx[4];
133} ba1;
134
135static void cs461x_poke(unsigned long reg, unsigned int val)
136{
137        writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
138}
139
140static unsigned int cs461x_peek(unsigned long reg)
141{
142        return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
143}
144
145#endif
146
147static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
148{
149        writel(val, &ba0[reg >> 2]);
150}
151
152static unsigned int cs461x_peekBA0(unsigned long reg)
153{
154        return readl(&ba0[reg >> 2]);
155}
156
157static int cs461x_free(struct pci_dev *pdev)
158{
159	struct gameport *port = pci_get_drvdata(pdev);
160
161	if (port)
162	    gameport_unregister_port(port);
163
164	if (ba0) iounmap(ba0);
165#ifdef CS461X_FULL_MAP
166	if (ba1.name.data0) iounmap(ba1.name.data0);
167	if (ba1.name.data1) iounmap(ba1.name.data1);
168	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
169	if (ba1.name.reg)   iounmap(ba1.name.reg);
170#endif
171	return 0;
172}
173
174static void cs461x_gameport_trigger(struct gameport *gameport)
175{
176	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
177}
178
179static unsigned char cs461x_gameport_read(struct gameport *gameport)
180{
181	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
182}
183
184static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
185{
186	unsigned js1, js2, jst;
187
188	js1 = cs461x_peekBA0(BA0_JSC1);
189	js2 = cs461x_peekBA0(BA0_JSC2);
190	jst = cs461x_peekBA0(BA0_JSPT);
191
192	*buttons = (~jst >> 4) & 0x0F;
193
194	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
195	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
196	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
197	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
198
199	for(jst=0;jst<4;++jst)
200		if(axes[jst]==0xFFFF) axes[jst] = -1;
201	return 0;
202}
203
204static int cs461x_gameport_open(struct gameport *gameport, int mode)
205{
206	switch (mode) {
207		case GAMEPORT_MODE_COOKED:
208		case GAMEPORT_MODE_RAW:
209			return 0;
210		default:
211			return -1;
212	}
213	return 0;
214}
215
216static struct pci_device_id cs461x_pci_tbl[] = {
217	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
218	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
219	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
220	{ 0, }
221};
222MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
223
224static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
225{
226	int rc;
227	struct gameport* port;
228
229	rc = pci_enable_device(pdev);
230	if (rc) {
231		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
232			pdev->bus->number, pdev->devfn, rc);
233		return rc;
234	}
235
236	ba0_addr = pci_resource_start(pdev, 0);
237#ifdef CS461X_FULL_MAP
238	ba1_addr = pci_resource_start(pdev, 1);
239#endif
240	if (ba0_addr == 0 || ba0_addr == ~0
241#ifdef CS461X_FULL_MAP
242            || ba1_addr == 0 || ba1_addr == ~0
243#endif
244	    ) {
245                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
246#ifdef CS461X_FULL_MAP
247                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
248#endif
249		cs461x_free(pdev);
250                return -ENOMEM;
251        }
252
253	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
254#ifdef CS461X_FULL_MAP
255	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
256	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
257	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
258	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
259
260	if (ba0 == NULL || ba1.name.data0 == NULL ||
261            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
262            ba1.name.reg == NULL) {
263		cs461x_free(pdev);
264                return -ENOMEM;
265        }
266#else
267	if (ba0 == NULL) {
268		cs461x_free(pdev);
269		return -ENOMEM;
270	}
271#endif
272
273	if (!(port = gameport_allocate_port())) {
274		printk(KERN_ERR "cs461x: Memory allocation failed\n");
275		cs461x_free(pdev);
276		return -ENOMEM;
277	}
278
279	pci_set_drvdata(pdev, port);
280
281	port->open = cs461x_gameport_open;
282	port->trigger = cs461x_gameport_trigger;
283	port->read = cs461x_gameport_read;
284	port->cooked_read = cs461x_gameport_cooked_read;
285
286	gameport_set_name(port, "CS416x");
287	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
288	port->dev.parent = &pdev->dev;
289
290	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
291	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
292
293	gameport_register_port(port);
294
295	return 0;
296}
297
298static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
299{
300	cs461x_free(pdev);
301}
302
303static struct pci_driver cs461x_pci_driver = {
304        .name =         "CS461x_gameport",
305        .id_table =     cs461x_pci_tbl,
306        .probe =        cs461x_pci_probe,
307        .remove =       __devexit_p(cs461x_pci_remove),
308};
309
310static int __init cs461x_init(void)
311{
312        return pci_register_driver(&cs461x_pci_driver);
313}
314
315static void __exit cs461x_exit(void)
316{
317        pci_unregister_driver(&cs461x_pci_driver);
318}
319
320module_init(cs461x_init);
321module_exit(cs461x_exit);
322