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