* Copyright 2008 Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Alexander Coers Alexander.Coers@gmx.de
* Fredrik ModΓ©en fredrik@modeen.se
* Axel DΓΆrfler axeld@pinc-software.de
*/
#include "driver.h"
#include <stdio.h>
#include <string.h>
#include <KernelExport.h>
#include <PCI.h>
#define TRACE_DRIVER
#ifdef TRACE_DRIVER
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
int32 api_version = B_CUR_DRIVER_API_VERSION;
int num_names = 0;
int num_cards = 0;
char *gDeviceNames[MAX_CARDS + 1];
gameport_info cards[MAX_CARDS];
static status_t
setup_card (gameport_info* card)
{
char * name = card->name;
uint32 command_reg = 0;
area_id area;
int32 base,size;
dprintf (DRIVER_NAME ": setup_card() trying to init structures \n");
command_reg = PCI_command_io || PCI_command_master ;
(*pci->write_pci_config)(card->info.bus,card->info.device,
card->info.function, PCI_command, 2, 0);
base = card->info.u.h0.base_registers[0];
size = card->info.u.h0.base_register_sizes[0];
(*pci->write_pci_config) (card->info.bus,card->info.device,
card->info.function, 0x10, 2, base);
(*pci->write_pci_config) (card->info.bus,card->info.device,
card->info.function, PCI_command, 2, command_reg);
dprintf (DRIVER_NAME ": setup_card() enabled card with i/o regs from "
"0x%04x to 0x%04x \n",base,base+size-1);
if ((*gameport->create_device)((int32)base, &card->joy.driver) < B_OK) {
dprintf (DRIVER_NAME ": setup_card() Gameport setup failed! Failed to "
"load Generic Gameport Module \n");
return B_ERROR;
}
sprintf(card->joy.name1, "joystick/"DRIVER_NAME "/%x", base);
gDeviceNames[num_names++] = card->joy.name1;
gDeviceNames[num_names] = NULL;
return B_OK;
}
extern "C" status_t
init_hardware (void)
{
status_t err = ENODEV;
pci_info info;
int ix = 0;
uint32 buffer;
if (get_module (pci_name, (module_info **)&pci))
return ENOSYS;
while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
if (info.vendor_id == VENDOR_ID_CREATIVE &&
info.device_id == DEVICE_ID_CREATIVE_EMU10K1) {
err = B_OK;
dprintf (DRIVER_NAME ": init_hardware() found one, Revision %02x\n"
,info.revision);
if (!(info.u.h0.subsystem_id == 0x20 ||
info.u.h0.subsystem_id == 0xc400 ||
(info.u.h0.subsystem_id == 0x21 && info.revision < 6))) {
buffer = (*pci->read_io_32)(info.u.h0.base_registers[0] + HCFG);
buffer |= HCFG_JOYENABLE;
(*pci->write_io_32)(info.u.h0.base_registers[0] + HCFG, buffer);
}
Register, others donΒ΄t */
}
ix++;
}
put_module (B_PCI_MODULE_NAME);
return err;
}
extern "C" status_t
init_driver (void)
{
area_id area;
area_info ainfo;
pci_info info;
int ix = 0;
dprintf (DRIVER_NAME ": init_driver() " __DATE__ " " __TIME__ "\n");
if (get_module (pci_name, (module_info **)&pci))
return ENOSYS;
if (get_module (gameport_name, (module_info **)&gameport)) {
dprintf (DRIVER_NAME ": Failed to load Generic Gameport Module \n");
put_module (pci_name);
return ENOSYS;
}
while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
if (info.vendor_id == VENDOR_ID_CREATIVE && (
info.device_id == SBLIVE_ID ||
info.device_id == AUDIGY_ID ||
info.device_id == SBLIVE_DELL_ID)) {
if (num_cards == MAX_CARDS) {
dprintf(DRIVER_NAME ": Too many cards installed!\n");
break;
}
memset(&cards[num_cards], 0, sizeof(gameport_info));
cards[num_cards].info = info;
if (setup_card(&cards[num_cards]))
dprintf(DRIVER_NAME ": Setup of card %ld failed \n",
num_cards + 1);
else
num_cards++;
}
ix++;
}
if (!num_cards) {
dprintf(DRIVER_NAME ": no cards \n");
put_module(pci_name);
return ENODEV;
}
return B_OK;
}
void
uninit_driver (void)
{
int ix = 0;
area_id area;
dprintf (DRIVER_NAME ": uninit_driver()\n");
for (ix = 0; ix < num_cards; ix++) {
area = find_area (AREA_NAME);
if (area >= 0)
delete_area (area);
(*gameport->delete_device)(cards[ix].joy.driver);
}
memset(&cards, 0, sizeof(cards));
put_module (gameport_name);
put_module (pci_name);
num_cards = 0;
}
extern "C" const char**
publish_devices()
{
return (const char **)gDeviceNames;
}
static int
lookup_device_name (const char *name)
{
int i;
for (i = 0; gDeviceNames[i]; i++)
if (!strcmp (gDeviceNames[i], name))
return i;
return -1;
}
static status_t
device_open(const char* name, uint32 flags, void** cookie)
{
int ix;
int offset = -1;
*cookie = NULL;
for (ix = 0; ix < num_cards; ix++) {
if (!strcmp(name, cards[ix].joy.name1)) {
offset = 0;
break;
}
}
if (offset < 0) {
return ENODEV;
}
return (*gameport->open_hook)(cards[ix].joy.driver, flags, cookie);
}
static status_t
device_close(void * cookie)
{
return (*gameport->close_hook)(cookie);
}
static status_t
device_free(void * cookie)
{
return (*gameport->free_hook)(cookie);
}
static status_t
device_control(void * cookie, uint32 iop, void * data, size_t len)
{
return (*gameport->control_hook)(cookie, iop, data, len);
}
static status_t
device_read(void * cookie, off_t pos, void * data, size_t * nread)
{
return (*gameport->read_hook)(cookie, pos, data, nread);
}
static status_t
device_write(void * cookie, off_t pos, const void * data, size_t * nwritten)
{
(*pci->write_io_32) ((int)vaddr,0);
return (*gameport->write_hook)(cookie, pos, data, nwritten);
}
device_hooks gDeviceHooks = {
device_open,
device_close,
device_free,
device_control,
device_read,
device_write,
NULL,
NULL,
NULL,
NULL
};
device_hooks*
find_device(const char* name)
{
if (lookup_device_name (name) >= 0) {
return &gDeviceHooks;
}
return NULL;
}