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 <stdlib.h> 27 #include <string.h> 28 #include "dvb_interface.h" 29 #include "cx23882.h" 30 #include "cx23882_i2c.h" 31 #include "cx22702.h" 32 #include "dtt7592.h" 33 #include "driver.h" 34 #include "config.h" 35 #include "util.h" 36 37 #define TRACE_INTERFACE 38 #ifdef TRACE_INTERFACE 39 #define TRACE dprintf 40 #else 41 #define TRACE(a...) 42 #endif 43 44 45 #if 0 46 static void 47 dump_eeprom(cx23882_device *device) 48 { 49 uint8 d[256+8]; 50 uint8 adr; 51 uint8 *p; 52 int i; 53 status_t res; 54 55 adr = 0; 56 res = i2c_xfer(device->i2c_bus, I2C_ADDR_EEPROM, &adr, 1, d, sizeof(d)); 57 if (res != B_OK) { 58 TRACE("i2c_read failed: %08lx\n", res); 59 return; 60 } 61 for (p = d, i = 0; i < ((int)sizeof(d) / 8); i++, p+= 8) 62 TRACE("EEPROM %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", i * 8, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 63 64 } 65 #endif 66 67 68 status_t 69 interface_attach(void **cookie, const pci_info *info) 70 { 71 cx23882_device *device; 72 uint32 val; 73 int i; 74 75 TRACE("interface_attach\n"); 76 77 device = malloc(sizeof(cx23882_device)); 78 if (!device) 79 return B_NO_MEMORY; 80 *cookie = device; 81 82 // initialize cookie 83 memset(device, 0, sizeof(*device)); 84 device->regs_area = -1; 85 device->dma_buf1_area = -1; 86 device->dma_buf2_area = -1; 87 device->capture_sem = -1; 88 89 device->pci_info = info; 90 91 // enable busmaster and memory mapped access, disable io port access 92 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2); 93 val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS); 94 gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2, val); 95 96 // adjust PCI latency timer 97 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1); 98 TRACE("PCI latency is %02" B_PRIx32 ", changing to %02x\n", val, 99 PCI_LATENCY); 100 gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1, PCI_LATENCY); 101 102 // get IRQ 103 device->irq = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_interrupt_line, 1); 104 if (device->irq == 0 || device->irq == 0xff) { 105 dprintf("cx23882: Error, no IRQ assigned\n"); 106 goto err; 107 } 108 TRACE("IRQ %d\n", device->irq); 109 110 // map registers into memory 111 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, 0x10, 4); 112 val &= PCI_address_memory_32_mask; 113 if (val == 0) { 114 dprintf("cx23882: Error, no memory space assigned\n"); 115 goto err; 116 } 117 TRACE("hardware register address 0x%" B_PRIx32 "\n", val); 118 device->regs_area = map_mem(&device->regs, (addr_t)val, 119 16777216 /* 16 MB */, 0, "cx23882 registers"); 120 if (device->regs_area < B_OK) { 121 dprintf("cx23882: Error, can't map hardware registers\n"); 122 goto err; 123 } 124 TRACE("mapped registers to %p\n", device->regs); 125 126 device->capture_sem = create_sem(0, "cx23882 capture"); 127 128 cx23882_reset(device); 129 130 if (i2c_init(device) < B_OK) { 131 dprintf("cx23882: Error, can't init I2C\n"); 132 } 133 134 135 if (cx23882_init(device) < B_OK) { 136 dprintf("cx23882: Error, can't init hardware\n"); 137 } 138 139 140 for (i = 0; i < 20; i++) 141 if (cx22702_init(device->i2c_bus) == B_OK) 142 break; 143 if (i == 20) { 144 TRACE("cx22702_init failed\n"); 145 goto err; 146 } 147 148 // setup interrupt handler 149 if (install_io_interrupt_handler(device->irq, cx23882_int, device, 0) < B_OK) { 150 dprintf("cx23882: Error, can't install interrupt handler\n"); 151 goto err; 152 } 153 154 // dump_eeprom(device); 155 // dtt7582_test(device->i2c_bus); 156 157 return B_OK; 158 err: 159 free(cookie); 160 return B_ERROR; 161 } 162 163 164 void 165 interface_detach(void *cookie) 166 { 167 cx23882_device *device = cookie; 168 169 i2c_terminate(device); 170 171 if (cx23882_terminate(device) < B_OK) { 172 } 173 174 remove_io_interrupt_handler(device->irq, cx23882_int, device); 175 176 delete_area(device->regs_area); 177 178 delete_sem(device->capture_sem); 179 180 TRACE("interface_detach\n"); 181 } 182 183 184 static void 185 interface_get_interface_info(dvb_interface_info_t *info) 186 { 187 memset(info, 0, sizeof(*info)); 188 info->version = 1; 189 info->flags = 0; 190 info->type = DVB_TYPE_DVB_T; 191 strcpy(info->name, "CX23882"); 192 strcpy(info->info, "Hauppauge WinTV-NOVA-T model 928 driver, Copyright (c) 2005 Marcus Overhagen"); 193 } 194 195 196 status_t 197 interface_ioctl(void *cookie, uint32 op, void *arg, size_t len) 198 { 199 cx23882_device *device = cookie; 200 status_t res; 201 202 switch (op) { 203 case DVB_GET_INTERFACE_INFO: 204 { 205 dvb_interface_info_t info; 206 interface_get_interface_info(&info); 207 if (user_memcpy(arg, &info, sizeof(info)) < B_OK) 208 return B_BAD_ADDRESS; 209 break; 210 } 211 212 case DVB_GET_FREQUENCY_INFO: 213 { 214 dvb_frequency_info_t info; 215 if ((res = cx22702_get_frequency_info(device->i2c_bus, &info)) < B_OK) 216 return res; 217 if (user_memcpy(arg, &info, sizeof(info)) < B_OK) 218 return B_BAD_ADDRESS; 219 break; 220 } 221 222 case DVB_START_CAPTURE: 223 { 224 return cx23882_start_capture(device); 225 } 226 227 case DVB_STOP_CAPTURE: 228 { 229 return cx23882_stop_capture(device); 230 } 231 232 case DVB_SET_TUNING_PARAMETERS: 233 { 234 dvb_tuning_parameters_t params; 235 if (user_memcpy(¶ms, arg, sizeof(params)) < B_OK) 236 return B_BAD_ADDRESS; 237 if ((res = cx22702_set_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) 238 return res; 239 break; 240 } 241 242 case DVB_GET_TUNING_PARAMETERS: 243 { 244 dvb_tuning_parameters_t params; 245 if ((res = cx22702_get_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) 246 return res; 247 if (user_memcpy(arg, ¶ms, sizeof(params)) < B_OK) 248 return B_BAD_ADDRESS; 249 break; 250 } 251 252 case DVB_GET_STATUS: 253 { 254 dvb_status_t status; 255 if ((res = cx22702_get_status(device->i2c_bus, &status)) < B_OK) 256 return res; 257 if (user_memcpy(arg, &status, sizeof(status)) < B_OK) 258 return B_BAD_ADDRESS; 259 break; 260 } 261 262 case DVB_GET_SS: 263 { 264 uint32 value; 265 if ((res = cx22702_get_ss(device->i2c_bus, &value)) < B_OK) 266 return res; 267 if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 268 return B_BAD_ADDRESS; 269 break; 270 } 271 272 case DVB_GET_BER: 273 { 274 uint32 value; 275 if ((res = cx22702_get_ber(device->i2c_bus, &value)) < B_OK) 276 return res; 277 if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 278 return B_BAD_ADDRESS; 279 break; 280 } 281 282 case DVB_GET_SNR: 283 { 284 uint32 value; 285 if ((res = cx22702_get_snr(device->i2c_bus, &value)) < B_OK) 286 return res; 287 if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 288 return B_BAD_ADDRESS; 289 break; 290 } 291 292 case DVB_GET_UPC: 293 { 294 uint32 value; 295 if ((res = cx22702_get_upc(device->i2c_bus, &value)) < B_OK) 296 return res; 297 if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 298 return B_BAD_ADDRESS; 299 break; 300 } 301 302 case DVB_CAPTURE: 303 { 304 dvb_capture_t cap_data; 305 // wait for data ready interrupt, with 100 ms timeout (in case tuning failed, bad reception, etc) 306 if ((res = acquire_sem_etc(device->capture_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 100000)) < B_OK) 307 return res; 308 cap_data.data = device->capture_data; 309 cap_data.size = device->capture_size; 310 cap_data.end_time = device->capture_end_time; 311 if (user_memcpy(arg, &cap_data, sizeof(cap_data)) < B_OK) 312 return B_BAD_ADDRESS; 313 break; 314 } 315 316 default: 317 { 318 TRACE("interface_ioctl\n"); 319 return B_BAD_VALUE; 320 } 321 } 322 323 return B_OK; 324 } 325