1 /* 2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, 8 * merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <KernelExport.h> 26 #include <Drivers.h> 27 #include <Errors.h> 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <string.h> 31 32 #include "config.h" 33 #include "driver.h" 34 #include "dvb_interface.h" 35 36 #define TRACE_DRIVER 37 #ifdef TRACE_DRIVER 38 #define TRACE dprintf 39 #else 40 #define TRACE(a...) 41 #endif 42 43 typedef struct 44 { 45 int vendor; 46 int device; 47 int subvendor; 48 int subdevice; 49 const char *name; 50 } card_info; 51 52 int32 api_version = B_CUR_DRIVER_API_VERSION; 53 pci_module_info * gPci; 54 static char * sDevNameList[MAX_CARDS + 1]; 55 static pci_info * sDevList[MAX_CARDS]; 56 static int32 sOpenMask; 57 58 static card_info sCardTable[] = 59 { 60 { 0x14f1, 0x8802, 0x0070, 0x9002, "Hauppauge WinTV-NOVA-T model 928" }, 61 { /* end */ } 62 }; 63 64 65 typedef struct 66 { 67 void * cookie; 68 int dev_id; 69 } interface_cookie; 70 71 72 static const char * 73 identify_device(const card_info *cards, const pci_info *info) 74 { 75 for (; cards->name; cards++) { 76 if (cards->vendor >= 0 && cards->vendor != info->vendor_id) 77 continue; 78 if (cards->device >= 0 && cards->device != info->device_id) 79 continue; 80 if ((info->header_type & PCI_header_type_mask) != PCI_header_type_generic) 81 continue; 82 if (cards->subvendor >= 0 && cards->subvendor != info->u.h0.subsystem_vendor_id) 83 continue; 84 if (cards->subdevice >= 0 && cards->subdevice != info->u.h0.subsystem_id) 85 continue; 86 return cards->name; 87 } 88 return NULL; 89 } 90 91 92 status_t 93 init_hardware(void) 94 { 95 pci_info info; 96 status_t res; 97 int i; 98 99 TRACE("cx23882: init_hardware()\n"); 100 101 if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) 102 return B_ERROR; 103 for (res = B_ERROR, i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { 104 if (identify_device(sCardTable, &info)) { 105 res = B_OK; 106 break; 107 } 108 } 109 put_module(B_PCI_MODULE_NAME); 110 gPci = NULL; 111 112 return res; 113 } 114 115 116 status_t 117 init_driver(void) 118 { 119 struct pci_info *item; 120 int index; 121 int cards; 122 123 #if defined(DEBUG) && !defined(__HAIKU__) 124 set_dprintf_enabled(true); 125 load_driver_symbols("cx23882"); 126 #endif 127 128 dprintf(INFO); 129 130 item = (pci_info *)malloc(sizeof(pci_info)); 131 if (!item) 132 return B_NO_MEMORY; 133 134 if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) { 135 free(item); 136 return B_ERROR; 137 } 138 139 for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) { 140 const char *info = identify_device(sCardTable, item); 141 if (info) { 142 char name[64]; 143 sprintf(name, "dvb/cx23882/%d", cards + 1); 144 dprintf("cx23882: /dev/%s is a %s\n", name, info); 145 sDevList[cards] = item; 146 sDevNameList[cards] = strdup(name); 147 sDevNameList[cards + 1] = NULL; 148 cards++; 149 item = (pci_info *)malloc(sizeof(pci_info)); 150 if (!item) 151 goto err_outofmem; 152 if (cards == MAX_CARDS) 153 break; 154 } 155 } 156 157 free(item); 158 159 if (!cards) 160 goto err_cards; 161 162 return B_OK; 163 164 err_outofmem: 165 TRACE("cx23882: err_outofmem\n"); 166 for (index = 0; index < cards; index++) { 167 free(sDevList[index]); 168 free(sDevNameList[index]); 169 } 170 err_cards: 171 put_module(B_PCI_MODULE_NAME); 172 return B_ERROR; 173 } 174 175 176 void 177 uninit_driver(void) 178 { 179 int32 i; 180 181 TRACE("cx23882: uninit_driver\n"); 182 183 for (i = 0; sDevNameList[i] != NULL; i++) { 184 free(sDevList[i]); 185 free(sDevNameList[i]); 186 } 187 188 put_module(B_PCI_MODULE_NAME); 189 } 190 191 192 static status_t 193 driver_open(const char *name, uint32 flags, void** _cookie) 194 { 195 interface_cookie *cookie; 196 char *deviceName; 197 status_t status; 198 int dev_id; 199 int mask; 200 201 TRACE("cx23882: driver open\n"); 202 203 for (dev_id = 0; (deviceName = sDevNameList[dev_id]) != NULL; dev_id++) { 204 if (!strcmp(name, deviceName)) 205 break; 206 } 207 if (deviceName == NULL) { 208 TRACE("cx23882: invalid device name\n"); 209 return B_ERROR; 210 } 211 212 // allow only one concurrent access 213 mask = 1 << dev_id; 214 if (atomic_or(&sOpenMask, mask) & mask) 215 return B_BUSY; 216 217 cookie = (interface_cookie *)malloc(sizeof(interface_cookie)); 218 if (!cookie) 219 return B_NO_MEMORY; 220 221 cookie->dev_id = dev_id; 222 status = interface_attach(&cookie->cookie, sDevList[dev_id]); 223 if (status != B_OK) { 224 free(cookie); 225 atomic_and(&sOpenMask, ~(1 << dev_id)); 226 return status; 227 } 228 229 *_cookie = cookie; 230 return B_OK; 231 } 232 233 234 static status_t 235 driver_close(void* cookie) 236 { 237 TRACE("cx23882: driver close enter\n"); 238 interface_detach(((interface_cookie *)cookie)->cookie); 239 TRACE("cx23882: driver close leave\n"); 240 return B_OK; 241 } 242 243 244 static status_t 245 driver_free(void* cookie) 246 { 247 TRACE("cx23882: driver free\n"); 248 atomic_and(&sOpenMask, ~(1 << ((interface_cookie *)cookie)->dev_id)); 249 free(cookie); 250 return B_OK; 251 } 252 253 254 static status_t 255 driver_read(void* cookie, off_t position, void *buf, size_t* num_bytes) 256 { 257 TRACE("cx23882: driver read\n"); 258 *num_bytes = 0; // required by design for read hook! 259 return B_ERROR; 260 } 261 262 263 static status_t 264 driver_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 265 { 266 TRACE("cx23882: driver write\n"); 267 *num_bytes = 0; // not sure if required for write hook 268 return B_ERROR; 269 } 270 271 272 static status_t 273 driver_control(void *cookie, uint32 op, void *arg, size_t len) 274 { 275 // TRACE("cx23882: driver control\n"); 276 return interface_ioctl(((interface_cookie *)cookie)->cookie, op, arg, len); 277 } 278 279 280 static device_hooks 281 sDeviceHooks = { 282 driver_open, 283 driver_close, 284 driver_free, 285 driver_control, 286 driver_read, 287 driver_write, 288 }; 289 290 291 const char** 292 publish_devices(void) 293 { 294 return (const char**)sDevNameList; 295 } 296 297 298 device_hooks* 299 find_device(const char* name) 300 { 301 return &sDeviceHooks; 302 } 303