1*0996e64eSFredrik Modeen /*
2*0996e64eSFredrik Modeen * Copyright 2008 Haiku.
3*0996e64eSFredrik Modeen * Distributed under the terms of the MIT License.
4*0996e64eSFredrik Modeen *
5*0996e64eSFredrik Modeen * Authors:
6*0996e64eSFredrik Modeen * Alexander Coers Alexander.Coers@gmx.de
7*0996e64eSFredrik Modeen * Fredrik Modéen fredrik@modeen.se
8*0996e64eSFredrik Modeen * Axel Dörfler axeld@pinc-software.de
9*0996e64eSFredrik Modeen */
10*0996e64eSFredrik Modeen
11*0996e64eSFredrik Modeen #include "driver.h"
12*0996e64eSFredrik Modeen
13*0996e64eSFredrik Modeen #include <stdio.h>
14*0996e64eSFredrik Modeen #include <string.h>
15*0996e64eSFredrik Modeen
16*0996e64eSFredrik Modeen #include <KernelExport.h>
17*0996e64eSFredrik Modeen #include <PCI.h>
18*0996e64eSFredrik Modeen
19*0996e64eSFredrik Modeen #define TRACE_DRIVER
20*0996e64eSFredrik Modeen #ifdef TRACE_DRIVER
21*0996e64eSFredrik Modeen # define TRACE(x) dprintf x
22*0996e64eSFredrik Modeen #else
23*0996e64eSFredrik Modeen # define TRACE(x) ;
24*0996e64eSFredrik Modeen #endif
25*0996e64eSFredrik Modeen
26*0996e64eSFredrik Modeen int32 api_version = B_CUR_DRIVER_API_VERSION;
27*0996e64eSFredrik Modeen
28*0996e64eSFredrik Modeen int num_names = 0;
29*0996e64eSFredrik Modeen int num_cards = 0;
30*0996e64eSFredrik Modeen
31*0996e64eSFredrik Modeen char *gDeviceNames[MAX_CARDS + 1];
32*0996e64eSFredrik Modeen gameport_info cards[MAX_CARDS];
33*0996e64eSFredrik Modeen
34*0996e64eSFredrik Modeen /* setup_card used to initialize cards, structures or hardware */
35*0996e64eSFredrik Modeen static status_t
setup_card(gameport_info * card)36*0996e64eSFredrik Modeen setup_card (gameport_info* card)
37*0996e64eSFredrik Modeen {
38*0996e64eSFredrik Modeen char * name = card->name;
39*0996e64eSFredrik Modeen uint32 command_reg = 0;
40*0996e64eSFredrik Modeen area_id area;
41*0996e64eSFredrik Modeen int32 base,size;
42*0996e64eSFredrik Modeen
43*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": setup_card() trying to init structures \n");
44*0996e64eSFredrik Modeen /* enable PCI i/o */
45*0996e64eSFredrik Modeen command_reg = PCI_command_io || PCI_command_master ;
46*0996e64eSFredrik Modeen
47*0996e64eSFredrik Modeen (*pci->write_pci_config)(card->info.bus,card->info.device,
48*0996e64eSFredrik Modeen card->info.function, PCI_command, 2, 0);
49*0996e64eSFredrik Modeen
50*0996e64eSFredrik Modeen /* disable all i/o -regs and bus_mastering */
51*0996e64eSFredrik Modeen base = card->info.u.h0.base_registers[0];
52*0996e64eSFredrik Modeen size = card->info.u.h0.base_register_sizes[0];
53*0996e64eSFredrik Modeen
54*0996e64eSFredrik Modeen (*pci->write_pci_config) (card->info.bus,card->info.device,
55*0996e64eSFredrik Modeen card->info.function, 0x10, 2, base);
56*0996e64eSFredrik Modeen
57*0996e64eSFredrik Modeen (*pci->write_pci_config) (card->info.bus,card->info.device,
58*0996e64eSFredrik Modeen card->info.function, PCI_command, 2, command_reg);
59*0996e64eSFredrik Modeen
60*0996e64eSFredrik Modeen /* enable i/o- regs and possible bus_mastering */
61*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": setup_card() enabled card with i/o regs from "
62*0996e64eSFredrik Modeen "0x%04x to 0x%04x \n",base,base+size-1);
63*0996e64eSFredrik Modeen
64*0996e64eSFredrik Modeen if ((*gameport->create_device)((int32)base, &card->joy.driver) < B_OK) {
65*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": setup_card() Gameport setup failed! Failed to "
66*0996e64eSFredrik Modeen "load Generic Gameport Module \n");
67*0996e64eSFredrik Modeen return B_ERROR;
68*0996e64eSFredrik Modeen }
69*0996e64eSFredrik Modeen
70*0996e64eSFredrik Modeen sprintf(card->joy.name1, "joystick/"DRIVER_NAME "/%x", base);
71*0996e64eSFredrik Modeen gDeviceNames[num_names++] = card->joy.name1;
72*0996e64eSFredrik Modeen gDeviceNames[num_names] = NULL;
73*0996e64eSFredrik Modeen return B_OK;
74*0996e64eSFredrik Modeen }
75*0996e64eSFredrik Modeen
76*0996e64eSFredrik Modeen
77*0996e64eSFredrik Modeen extern "C" status_t
init_hardware(void)78*0996e64eSFredrik Modeen init_hardware (void)
79*0996e64eSFredrik Modeen {
80*0996e64eSFredrik Modeen status_t err = ENODEV;
81*0996e64eSFredrik Modeen pci_info info;
82*0996e64eSFredrik Modeen int ix = 0;
83*0996e64eSFredrik Modeen uint32 buffer;
84*0996e64eSFredrik Modeen
85*0996e64eSFredrik Modeen /* probe PCI bus */
86*0996e64eSFredrik Modeen if (get_module (pci_name, (module_info **)&pci))
87*0996e64eSFredrik Modeen return ENOSYS;
88*0996e64eSFredrik Modeen while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
89*0996e64eSFredrik Modeen /* look for HARDWARE */
90*0996e64eSFredrik Modeen if (info.vendor_id == VENDOR_ID_CREATIVE &&
91*0996e64eSFredrik Modeen info.device_id == DEVICE_ID_CREATIVE_EMU10K1) {
92*0996e64eSFredrik Modeen err = B_OK;
93*0996e64eSFredrik Modeen
94*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": init_hardware() found one, Revision %02x\n"
95*0996e64eSFredrik Modeen ,info.revision);
96*0996e64eSFredrik Modeen
97*0996e64eSFredrik Modeen if (!(info.u.h0.subsystem_id == 0x20 ||
98*0996e64eSFredrik Modeen info.u.h0.subsystem_id == 0xc400 ||
99*0996e64eSFredrik Modeen (info.u.h0.subsystem_id == 0x21 && info.revision < 6))) {
100*0996e64eSFredrik Modeen buffer = (*pci->read_io_32)(info.u.h0.base_registers[0] + HCFG);
101*0996e64eSFredrik Modeen buffer |= HCFG_JOYENABLE;
102*0996e64eSFredrik Modeen (*pci->write_io_32)(info.u.h0.base_registers[0] + HCFG, buffer);
103*0996e64eSFredrik Modeen }
104*0996e64eSFredrik Modeen /* Some SB-Live cards need to the Joyenable Bit in the config
105*0996e64eSFredrik Modeen Register, others don´t */
106*0996e64eSFredrik Modeen }
107*0996e64eSFredrik Modeen ix++;
108*0996e64eSFredrik Modeen }
109*0996e64eSFredrik Modeen put_module (B_PCI_MODULE_NAME);
110*0996e64eSFredrik Modeen return err;
111*0996e64eSFredrik Modeen }
112*0996e64eSFredrik Modeen
113*0996e64eSFredrik Modeen
114*0996e64eSFredrik Modeen extern "C" status_t
init_driver(void)115*0996e64eSFredrik Modeen init_driver (void)
116*0996e64eSFredrik Modeen {
117*0996e64eSFredrik Modeen area_id area;
118*0996e64eSFredrik Modeen area_info ainfo;
119*0996e64eSFredrik Modeen pci_info info;
120*0996e64eSFredrik Modeen int ix = 0;
121*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": init_driver() " __DATE__ " " __TIME__ "\n");
122*0996e64eSFredrik Modeen
123*0996e64eSFredrik Modeen /* probe PCI bus */
124*0996e64eSFredrik Modeen if (get_module (pci_name, (module_info **)&pci))
125*0996e64eSFredrik Modeen return ENOSYS;
126*0996e64eSFredrik Modeen
127*0996e64eSFredrik Modeen if (get_module (gameport_name, (module_info **)&gameport)) {
128*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": Failed to load Generic Gameport Module \n");
129*0996e64eSFredrik Modeen put_module (pci_name);
130*0996e64eSFredrik Modeen return ENOSYS;
131*0996e64eSFredrik Modeen }
132*0996e64eSFredrik Modeen
133*0996e64eSFredrik Modeen while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
134*0996e64eSFredrik Modeen if (info.vendor_id == VENDOR_ID_CREATIVE && (
135*0996e64eSFredrik Modeen info.device_id == SBLIVE_ID ||
136*0996e64eSFredrik Modeen info.device_id == AUDIGY_ID ||
137*0996e64eSFredrik Modeen info.device_id == SBLIVE_DELL_ID)) {
138*0996e64eSFredrik Modeen
139*0996e64eSFredrik Modeen if (num_cards == MAX_CARDS) {
140*0996e64eSFredrik Modeen dprintf(DRIVER_NAME ": Too many cards installed!\n");
141*0996e64eSFredrik Modeen break;
142*0996e64eSFredrik Modeen }
143*0996e64eSFredrik Modeen
144*0996e64eSFredrik Modeen memset(&cards[num_cards], 0, sizeof(gameport_info));
145*0996e64eSFredrik Modeen cards[num_cards].info = info;
146*0996e64eSFredrik Modeen if (setup_card(&cards[num_cards]))
147*0996e64eSFredrik Modeen dprintf(DRIVER_NAME ": Setup of card %ld failed \n",
148*0996e64eSFredrik Modeen num_cards + 1);
149*0996e64eSFredrik Modeen else
150*0996e64eSFredrik Modeen num_cards++;
151*0996e64eSFredrik Modeen }
152*0996e64eSFredrik Modeen ix++;
153*0996e64eSFredrik Modeen }
154*0996e64eSFredrik Modeen
155*0996e64eSFredrik Modeen if (!num_cards) {
156*0996e64eSFredrik Modeen dprintf(DRIVER_NAME ": no cards \n");
157*0996e64eSFredrik Modeen put_module(pci_name);
158*0996e64eSFredrik Modeen return ENODEV;
159*0996e64eSFredrik Modeen }
160*0996e64eSFredrik Modeen return B_OK;
161*0996e64eSFredrik Modeen }
162*0996e64eSFredrik Modeen
163*0996e64eSFredrik Modeen
164*0996e64eSFredrik Modeen void
uninit_driver(void)165*0996e64eSFredrik Modeen uninit_driver (void)
166*0996e64eSFredrik Modeen {
167*0996e64eSFredrik Modeen int ix = 0;
168*0996e64eSFredrik Modeen area_id area;
169*0996e64eSFredrik Modeen dprintf (DRIVER_NAME ": uninit_driver()\n");
170*0996e64eSFredrik Modeen for (ix = 0; ix < num_cards; ix++) {
171*0996e64eSFredrik Modeen area = find_area (AREA_NAME);
172*0996e64eSFredrik Modeen if (area >= 0)
173*0996e64eSFredrik Modeen delete_area (area);
174*0996e64eSFredrik Modeen (*gameport->delete_device)(cards[ix].joy.driver);
175*0996e64eSFredrik Modeen }
176*0996e64eSFredrik Modeen memset(&cards, 0, sizeof(cards));
177*0996e64eSFredrik Modeen put_module (gameport_name);
178*0996e64eSFredrik Modeen put_module (pci_name);
179*0996e64eSFredrik Modeen num_cards = 0;
180*0996e64eSFredrik Modeen }
181*0996e64eSFredrik Modeen
182*0996e64eSFredrik Modeen
183*0996e64eSFredrik Modeen extern "C" const char**
publish_devices()184*0996e64eSFredrik Modeen publish_devices()
185*0996e64eSFredrik Modeen {
186*0996e64eSFredrik Modeen return (const char **)gDeviceNames;
187*0996e64eSFredrik Modeen }
188*0996e64eSFredrik Modeen
189*0996e64eSFredrik Modeen
190*0996e64eSFredrik Modeen static int
lookup_device_name(const char * name)191*0996e64eSFredrik Modeen lookup_device_name (const char *name)
192*0996e64eSFredrik Modeen {
193*0996e64eSFredrik Modeen int i;
194*0996e64eSFredrik Modeen for (i = 0; gDeviceNames[i]; i++)
195*0996e64eSFredrik Modeen if (!strcmp (gDeviceNames[i], name))
196*0996e64eSFredrik Modeen return i;
197*0996e64eSFredrik Modeen return -1;
198*0996e64eSFredrik Modeen }
199*0996e64eSFredrik Modeen
200*0996e64eSFredrik Modeen
201*0996e64eSFredrik Modeen static status_t
device_open(const char * name,uint32 flags,void ** cookie)202*0996e64eSFredrik Modeen device_open(const char* name, uint32 flags, void** cookie)
203*0996e64eSFredrik Modeen {
204*0996e64eSFredrik Modeen int ix;
205*0996e64eSFredrik Modeen int offset = -1;
206*0996e64eSFredrik Modeen
207*0996e64eSFredrik Modeen *cookie = NULL;
208*0996e64eSFredrik Modeen for (ix = 0; ix < num_cards; ix++) {
209*0996e64eSFredrik Modeen if (!strcmp(name, cards[ix].joy.name1)) {
210*0996e64eSFredrik Modeen offset = 0;
211*0996e64eSFredrik Modeen break;
212*0996e64eSFredrik Modeen }
213*0996e64eSFredrik Modeen }
214*0996e64eSFredrik Modeen
215*0996e64eSFredrik Modeen if (offset < 0) {
216*0996e64eSFredrik Modeen return ENODEV;
217*0996e64eSFredrik Modeen }
218*0996e64eSFredrik Modeen
219*0996e64eSFredrik Modeen return (*gameport->open_hook)(cards[ix].joy.driver, flags, cookie);
220*0996e64eSFredrik Modeen }
221*0996e64eSFredrik Modeen
222*0996e64eSFredrik Modeen
223*0996e64eSFredrik Modeen static status_t
device_close(void * cookie)224*0996e64eSFredrik Modeen device_close(void * cookie)
225*0996e64eSFredrik Modeen {
226*0996e64eSFredrik Modeen return (*gameport->close_hook)(cookie);
227*0996e64eSFredrik Modeen }
228*0996e64eSFredrik Modeen
229*0996e64eSFredrik Modeen
230*0996e64eSFredrik Modeen static status_t
device_free(void * cookie)231*0996e64eSFredrik Modeen device_free(void * cookie)
232*0996e64eSFredrik Modeen {
233*0996e64eSFredrik Modeen return (*gameport->free_hook)(cookie);
234*0996e64eSFredrik Modeen }
235*0996e64eSFredrik Modeen
236*0996e64eSFredrik Modeen
237*0996e64eSFredrik Modeen static status_t
device_control(void * cookie,uint32 iop,void * data,size_t len)238*0996e64eSFredrik Modeen device_control(void * cookie, uint32 iop, void * data, size_t len)
239*0996e64eSFredrik Modeen {
240*0996e64eSFredrik Modeen return (*gameport->control_hook)(cookie, iop, data, len);
241*0996e64eSFredrik Modeen }
242*0996e64eSFredrik Modeen
243*0996e64eSFredrik Modeen
244*0996e64eSFredrik Modeen static status_t
device_read(void * cookie,off_t pos,void * data,size_t * nread)245*0996e64eSFredrik Modeen device_read(void * cookie, off_t pos, void * data, size_t * nread)
246*0996e64eSFredrik Modeen {
247*0996e64eSFredrik Modeen return (*gameport->read_hook)(cookie, pos, data, nread);
248*0996e64eSFredrik Modeen }
249*0996e64eSFredrik Modeen
250*0996e64eSFredrik Modeen
251*0996e64eSFredrik Modeen static status_t
device_write(void * cookie,off_t pos,const void * data,size_t * nwritten)252*0996e64eSFredrik Modeen device_write(void * cookie, off_t pos, const void * data, size_t * nwritten)
253*0996e64eSFredrik Modeen {
254*0996e64eSFredrik Modeen (*pci->write_io_32) ((int)vaddr,0);
255*0996e64eSFredrik Modeen return (*gameport->write_hook)(cookie, pos, data, nwritten);
256*0996e64eSFredrik Modeen }
257*0996e64eSFredrik Modeen
258*0996e64eSFredrik Modeen device_hooks gDeviceHooks = {
259*0996e64eSFredrik Modeen device_open,
260*0996e64eSFredrik Modeen device_close,
261*0996e64eSFredrik Modeen device_free,
262*0996e64eSFredrik Modeen device_control,
263*0996e64eSFredrik Modeen device_read,
264*0996e64eSFredrik Modeen device_write,
265*0996e64eSFredrik Modeen NULL, /* select */
266*0996e64eSFredrik Modeen NULL, /* deselect */
267*0996e64eSFredrik Modeen NULL, /* readv */
268*0996e64eSFredrik Modeen NULL /* writev */
269*0996e64eSFredrik Modeen };
270*0996e64eSFredrik Modeen
271*0996e64eSFredrik Modeen
272*0996e64eSFredrik Modeen device_hooks*
find_device(const char * name)273*0996e64eSFredrik Modeen find_device(const char* name)
274*0996e64eSFredrik Modeen {
275*0996e64eSFredrik Modeen if (lookup_device_name (name) >= 0) {
276*0996e64eSFredrik Modeen return &gDeviceHooks;
277*0996e64eSFredrik Modeen }
278*0996e64eSFredrik Modeen return NULL;
279*0996e64eSFredrik Modeen }
280