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