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