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 "version.h" 33 #include "config.h" 34 #include "driver.h" 35 #include "mktime.h" 36 37 #define TRACE_DRIVER 38 #ifdef TRACE_DRIVER 39 #define TRACE dprintf 40 #else 41 #define TRACE(a...) 42 #endif 43 44 typedef struct 45 { 46 int vendor; 47 int device; 48 int subvendor; 49 int subdevice; 50 const char *name; 51 } card_info; 52 53 int32 api_version = B_CUR_DRIVER_API_VERSION; 54 pci_module_info * gPci; 55 static char * sDevNameList[MAX_CARDS + 1]; 56 static pci_info * sDevList[MAX_CARDS]; 57 static int32 sOpenMask; 58 59 static card_info sCardTable[] = 60 { 61 { 0x14f1, 0x8802, 0x0070, 0x9002, "Hauppauge WinTV-NOVA-T model 928" }, 62 { /* end */ } 63 }; 64 65 66 typedef struct 67 { 68 void * cookie; 69 int dev_id; 70 } interface_cookie; 71 72 73 static const char * 74 identify_device(const card_info *cards, const pci_info *info) 75 { 76 for (; cards->name; cards++) { 77 if (cards->vendor >= 0 && cards->vendor != info->vendor_id) 78 continue; 79 if (cards->device >= 0 && cards->device != info->device_id) 80 continue; 81 if ((info->header_type & PCI_header_type_mask) != PCI_header_type_generic) 82 continue; 83 if (cards->subvendor >= 0 && cards->subvendor != info->u.h0.subsystem_vendor_id) 84 continue; 85 if (cards->subdevice >= 0 && cards->subdevice != info->u.h0.subsystem_id) 86 continue; 87 return cards->name; 88 } 89 return NULL; 90 } 91 92 93 status_t 94 init_hardware(void) 95 { 96 pci_info info; 97 status_t res; 98 int i; 99 100 TRACE("cx23882: init_hardware()\n"); 101 102 if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) 103 return B_ERROR; 104 for (res = B_ERROR, i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { 105 if (identify_device(sCardTable, &info)) { 106 res = B_OK; 107 break; 108 } 109 } 110 put_module(B_PCI_MODULE_NAME); 111 gPci = NULL; 112 113 return res; 114 } 115 116 117 status_t 118 init_driver(void) 119 { 120 struct pci_info *item; 121 int index; 122 int cards; 123 124 #ifdef DEBUG 125 set_dprintf_enabled(true); 126 load_driver_symbols("cx23882"); 127 #endif 128 129 dprintf(gBanner); 130 131 item = (pci_info *)malloc(sizeof(pci_info)); 132 if (!item) 133 return B_NO_MEMORY; 134 135 if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) { 136 free(item); 137 return B_ERROR; 138 } 139 140 for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) { 141 const char *info = identify_device(sCardTable, item); 142 if (info) { 143 char name[64]; 144 sprintf(name, "dvb/cx23882/%d", cards + 1); 145 dprintf("cx23882: /dev/%s is a %s\n", name, info); 146 sDevList[cards] = item; 147 sDevNameList[cards] = strdup(name); 148 sDevNameList[cards + 1] = NULL; 149 cards++; 150 item = (pci_info *)malloc(sizeof(pci_info)); 151 if (!item) 152 goto err_outofmem; 153 if (cards == MAX_CARDS) 154 break; 155 } 156 } 157 158 free(item); 159 160 if (!cards) 161 goto err_cards; 162 163 return B_OK; 164 165 err_outofmem: 166 TRACE("cx23882: err_outofmem\n"); 167 for (index = 0; index < cards; index++) { 168 free(sDevList[index]); 169 free(sDevNameList[index]); 170 } 171 err_cards: 172 put_module(B_PCI_MODULE_NAME); 173 return B_ERROR; 174 } 175 176 177 void 178 uninit_driver(void) 179 { 180 int32 i; 181 182 TRACE("cx23882: uninit_driver\n"); 183 184 for (i = 0; sDevNameList[i] != NULL; i++) { 185 free(sDevList[i]); 186 free(sDevNameList[i]); 187 } 188 189 put_module(B_PCI_MODULE_NAME); 190 } 191 192 193 static status_t 194 driver_open(const char *name, uint32 flags, void** _cookie) 195 { 196 interface_cookie *cookie; 197 char *deviceName; 198 status_t status; 199 int dev_id; 200 int mask; 201 202 TRACE("cx23882: driver open\n"); 203 204 for (dev_id = 0; (deviceName = sDevNameList[dev_id]) != NULL; dev_id++) { 205 if (!strcmp(name, deviceName)) 206 break; 207 } 208 if (deviceName == NULL) { 209 TRACE("cx23882: invalid device name\n"); 210 return B_ERROR; 211 } 212 213 // allow only one concurrent access 214 mask = 1 << dev_id; 215 if (atomic_or(&sOpenMask, mask) & mask) 216 return B_BUSY; 217 218 cookie = (interface_cookie *)malloc(sizeof(interface_cookie)); 219 if (!cookie) 220 return B_NO_MEMORY; 221 222 cookie->dev_id = dev_id; 223 status = interface_attach(&cookie->cookie, sDevList[dev_id]); 224 if (status != B_OK) { 225 free(cookie); 226 atomic_and(&sOpenMask, ~(1 << dev_id)); 227 return status; 228 } 229 230 *_cookie = cookie; 231 return B_OK; 232 } 233 234 235 static status_t 236 driver_close(void* cookie) 237 { 238 TRACE("cx23882: driver close\n"); 239 interface_detach(((interface_cookie *)cookie)->cookie); 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 return B_OK; 250 } 251 252 253 static status_t 254 driver_read(void* cookie, off_t position, void *buf, size_t* num_bytes) 255 { 256 TRACE("cx23882: driver read\n"); 257 *num_bytes = 0; // required by design for read hook! 258 return B_ERROR; 259 } 260 261 262 static status_t 263 driver_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 264 { 265 TRACE("cx23882: driver write\n"); 266 *num_bytes = 0; // not sure if required for write hook 267 return B_ERROR; 268 } 269 270 271 static status_t 272 driver_control(void *cookie, uint32 op, void *arg, size_t len) 273 { 274 // TRACE("cx23882: driver control\n"); 275 return interface_ioctl(((interface_cookie *)cookie)->cookie, op, arg, len); 276 } 277 278 279 static device_hooks 280 sDeviceHooks = { 281 driver_open, 282 driver_close, 283 driver_free, 284 driver_control, 285 driver_read, 286 driver_write, 287 }; 288 289 290 const char** 291 publish_devices(void) 292 { 293 return (const char**)sDevNameList; 294 } 295 296 297 device_hooks* 298 find_device(const char* name) 299 { 300 return &sDeviceHooks; 301 } 302