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
26int32	api_version = B_CUR_DRIVER_API_VERSION;
27
28int num_names = 0;
29int num_cards = 0;
30
31char *gDeviceNames[MAX_CARDS + 1];
32gameport_info cards[MAX_CARDS];
33
34/* setup_card used to initialize cards, structures or hardware */
35static status_t
36setup_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
77extern "C" status_t
78init_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
114extern "C" status_t
115init_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
164void
165uninit_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
183extern "C" const char**
184publish_devices()
185{
186	return (const char **)gDeviceNames;
187}
188
189
190static int
191lookup_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
201static status_t
202device_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
223static status_t
224device_close(void * cookie)
225{
226	return (*gameport->close_hook)(cookie);
227}
228
229
230static status_t
231device_free(void * cookie)
232{
233	return (*gameport->free_hook)(cookie);
234}
235
236
237static status_t
238device_control(void * cookie, uint32 iop, void * data, size_t len)
239{
240	return (*gameport->control_hook)(cookie, iop, data, len);
241}
242
243
244static status_t
245device_read(void * cookie, off_t pos, void * data, size_t * nread)
246{
247	return (*gameport->read_hook)(cookie, pos, data, nread);
248}
249
250
251static status_t
252device_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
258device_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
272device_hooks*
273find_device(const char* name)
274{
275	if (lookup_device_name (name) >= 0) {
276	     return &gDeviceHooks;
277	}
278	return NULL;
279}
280