1*083a11a3SMarcus Overhagen /* 2*083a11a3SMarcus Overhagen * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de> 3*083a11a3SMarcus Overhagen * 4*083a11a3SMarcus Overhagen * Permission is hereby granted, free of charge, to any person 5*083a11a3SMarcus Overhagen * obtaining a copy of this software and associated documentation 6*083a11a3SMarcus Overhagen * files (the "Software"), to deal in the Software without restriction, 7*083a11a3SMarcus Overhagen * including without limitation the rights to use, copy, modify, 8*083a11a3SMarcus Overhagen * merge, publish, distribute, sublicense, and/or sell copies of 9*083a11a3SMarcus Overhagen * the Software, and to permit persons to whom the Software is 10*083a11a3SMarcus Overhagen * furnished to do so, subject to the following conditions: 11*083a11a3SMarcus Overhagen * 12*083a11a3SMarcus Overhagen * The above copyright notice and this permission notice shall be 13*083a11a3SMarcus Overhagen * included in all copies or substantial portions of the Software. 14*083a11a3SMarcus Overhagen * 15*083a11a3SMarcus Overhagen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*083a11a3SMarcus Overhagen * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17*083a11a3SMarcus Overhagen * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*083a11a3SMarcus Overhagen * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19*083a11a3SMarcus Overhagen * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20*083a11a3SMarcus Overhagen * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21*083a11a3SMarcus Overhagen * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22*083a11a3SMarcus Overhagen * OTHER DEALINGS IN THE SOFTWARE. 23*083a11a3SMarcus Overhagen */ 24*083a11a3SMarcus Overhagen 25*083a11a3SMarcus Overhagen #include <KernelExport.h> 26*083a11a3SMarcus Overhagen #include <stdlib.h> 27*083a11a3SMarcus Overhagen #include "interface.h" 28*083a11a3SMarcus Overhagen #include "cx23882.h" 29*083a11a3SMarcus Overhagen #include "cx22702.h" 30*083a11a3SMarcus Overhagen #include "dtt7592.h" 31*083a11a3SMarcus Overhagen #include "driver.h" 32*083a11a3SMarcus Overhagen #include "config.h" 33*083a11a3SMarcus Overhagen #include "util.h" 34*083a11a3SMarcus Overhagen #include "i2c.h" 35*083a11a3SMarcus Overhagen 36*083a11a3SMarcus Overhagen #define TRACE_INTERFACE 37*083a11a3SMarcus Overhagen #ifdef TRACE_INTERFACE 38*083a11a3SMarcus Overhagen #define TRACE dprintf 39*083a11a3SMarcus Overhagen #else 40*083a11a3SMarcus Overhagen #define TRACE(a...) 41*083a11a3SMarcus Overhagen #endif 42*083a11a3SMarcus Overhagen 43*083a11a3SMarcus Overhagen static inline status_t user_memcpy(void *d, const void *s, size_t z) { memcpy(d, s, z); return B_OK; } 44*083a11a3SMarcus Overhagen #define B_BAD_ADDRESS B_ERROR 45*083a11a3SMarcus Overhagen 46*083a11a3SMarcus Overhagen static void 47*083a11a3SMarcus Overhagen dump_eeprom(cx23882_device *device) 48*083a11a3SMarcus Overhagen { 49*083a11a3SMarcus Overhagen uint8 d[256+8]; 50*083a11a3SMarcus Overhagen uint8 adr; 51*083a11a3SMarcus Overhagen uint8 *p; 52*083a11a3SMarcus Overhagen int i; 53*083a11a3SMarcus Overhagen status_t res; 54*083a11a3SMarcus Overhagen 55*083a11a3SMarcus Overhagen adr = 0; 56*083a11a3SMarcus Overhagen res = i2c_xfer(device->i2c_bus, I2C_ADDR_EEPROM, &adr, 1, d, sizeof(d)); 57*083a11a3SMarcus Overhagen if (res != B_OK) { 58*083a11a3SMarcus Overhagen TRACE("i2c_read failed: %08lx\n", res); 59*083a11a3SMarcus Overhagen return; 60*083a11a3SMarcus Overhagen } 61*083a11a3SMarcus Overhagen for (p = d, i = 0; i < ((int)sizeof(d) / 8); i++, p+= 8) 62*083a11a3SMarcus Overhagen 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*083a11a3SMarcus Overhagen 64*083a11a3SMarcus Overhagen } 65*083a11a3SMarcus Overhagen 66*083a11a3SMarcus Overhagen 67*083a11a3SMarcus Overhagen status_t 68*083a11a3SMarcus Overhagen interface_attach(void **cookie, const pci_info *info) 69*083a11a3SMarcus Overhagen { 70*083a11a3SMarcus Overhagen cx23882_device *device; 71*083a11a3SMarcus Overhagen uint32 val; 72*083a11a3SMarcus Overhagen int i; 73*083a11a3SMarcus Overhagen 74*083a11a3SMarcus Overhagen TRACE("interface_attach\n"); 75*083a11a3SMarcus Overhagen 76*083a11a3SMarcus Overhagen device = malloc(sizeof(cx23882_device)); 77*083a11a3SMarcus Overhagen if (!device) 78*083a11a3SMarcus Overhagen return B_NO_MEMORY; 79*083a11a3SMarcus Overhagen *cookie = device; 80*083a11a3SMarcus Overhagen 81*083a11a3SMarcus Overhagen // initialize cookie 82*083a11a3SMarcus Overhagen memset(device, 0, sizeof(*device)); 83*083a11a3SMarcus Overhagen device->regs_area = -1; 84*083a11a3SMarcus Overhagen device->dma_buf1_area = -1; 85*083a11a3SMarcus Overhagen device->dma_buf2_area = -1; 86*083a11a3SMarcus Overhagen device->capture_sem = -1; 87*083a11a3SMarcus Overhagen 88*083a11a3SMarcus Overhagen device->pci_info = info; 89*083a11a3SMarcus Overhagen 90*083a11a3SMarcus Overhagen // enable busmaster and memory mapped access, disable io port access 91*083a11a3SMarcus Overhagen val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2); 92*083a11a3SMarcus Overhagen val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS); 93*083a11a3SMarcus Overhagen gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2, val); 94*083a11a3SMarcus Overhagen 95*083a11a3SMarcus Overhagen // adjust PCI latency timer 96*083a11a3SMarcus Overhagen val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1); 97*083a11a3SMarcus Overhagen TRACE("PCI latency is %02lx, changing to %02x\n", val, PCI_LATENCY); 98*083a11a3SMarcus Overhagen gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1, PCI_LATENCY); 99*083a11a3SMarcus Overhagen 100*083a11a3SMarcus Overhagen // get IRQ 101*083a11a3SMarcus Overhagen device->irq = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_interrupt_line, 1); 102*083a11a3SMarcus Overhagen if (device->irq == 0 || device->irq == 0xff) { 103*083a11a3SMarcus Overhagen dprintf("cx23882: Error, no IRQ assigned\n"); 104*083a11a3SMarcus Overhagen goto err; 105*083a11a3SMarcus Overhagen } 106*083a11a3SMarcus Overhagen TRACE("IRQ %d\n", device->irq); 107*083a11a3SMarcus Overhagen 108*083a11a3SMarcus Overhagen // map registers into memory 109*083a11a3SMarcus Overhagen val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, 0x10, 4); 110*083a11a3SMarcus Overhagen val &= PCI_address_memory_32_mask; 111*083a11a3SMarcus Overhagen if (val == 0) { 112*083a11a3SMarcus Overhagen dprintf("cx23882: Error, no memory space assigned\n"); 113*083a11a3SMarcus Overhagen goto err; 114*083a11a3SMarcus Overhagen } 115*083a11a3SMarcus Overhagen TRACE("hardware register address %p\n", (void *) val); 116*083a11a3SMarcus Overhagen device->regs_area = map_mem(&device->regs, (void *)val, 16777216 /* 16 MB */, 0, "cx23882 registers"); 117*083a11a3SMarcus Overhagen if (device->regs_area < B_OK) { 118*083a11a3SMarcus Overhagen dprintf("cx23882: Error, can't map hardware registers\n"); 119*083a11a3SMarcus Overhagen goto err; 120*083a11a3SMarcus Overhagen } 121*083a11a3SMarcus Overhagen TRACE("mapped registers to %p\n", device->regs); 122*083a11a3SMarcus Overhagen 123*083a11a3SMarcus Overhagen device->capture_sem = create_sem(0, "cx23882 capture"); 124*083a11a3SMarcus Overhagen 125*083a11a3SMarcus Overhagen cx23882_reset(device); 126*083a11a3SMarcus Overhagen 127*083a11a3SMarcus Overhagen if (i2c_init(device) < B_OK) { 128*083a11a3SMarcus Overhagen dprintf("cx23882: Error, can't init I2C\n"); 129*083a11a3SMarcus Overhagen } 130*083a11a3SMarcus Overhagen 131*083a11a3SMarcus Overhagen 132*083a11a3SMarcus Overhagen if (cx23882_init(device) < B_OK) { 133*083a11a3SMarcus Overhagen dprintf("cx23882: Error, can't init hardware\n"); 134*083a11a3SMarcus Overhagen } 135*083a11a3SMarcus Overhagen 136*083a11a3SMarcus Overhagen 137*083a11a3SMarcus Overhagen for (i = 0; i < 20; i++) 138*083a11a3SMarcus Overhagen if (cx22702_init(device->i2c_bus) == B_OK) 139*083a11a3SMarcus Overhagen break; 140*083a11a3SMarcus Overhagen if (i == 20) { 141*083a11a3SMarcus Overhagen TRACE("cx22702_init failed\n"); 142*083a11a3SMarcus Overhagen goto err; 143*083a11a3SMarcus Overhagen } 144*083a11a3SMarcus Overhagen 145*083a11a3SMarcus Overhagen // setup interrupt handler 146*083a11a3SMarcus Overhagen if (install_io_interrupt_handler(device->irq, cx23882_int, device, 0) < B_OK) { 147*083a11a3SMarcus Overhagen dprintf("cx23882: Error, can't install interrupt handler\n"); 148*083a11a3SMarcus Overhagen goto err; 149*083a11a3SMarcus Overhagen } 150*083a11a3SMarcus Overhagen 151*083a11a3SMarcus Overhagen // dump_eeprom(device); 152*083a11a3SMarcus Overhagen // dtt7582_test(device->i2c_bus); 153*083a11a3SMarcus Overhagen 154*083a11a3SMarcus Overhagen return B_OK; 155*083a11a3SMarcus Overhagen err: 156*083a11a3SMarcus Overhagen free(cookie); 157*083a11a3SMarcus Overhagen return B_ERROR; 158*083a11a3SMarcus Overhagen } 159*083a11a3SMarcus Overhagen 160*083a11a3SMarcus Overhagen 161*083a11a3SMarcus Overhagen void 162*083a11a3SMarcus Overhagen interface_detach(void *cookie) 163*083a11a3SMarcus Overhagen { 164*083a11a3SMarcus Overhagen cx23882_device *device = cookie; 165*083a11a3SMarcus Overhagen 166*083a11a3SMarcus Overhagen i2c_terminate(device); 167*083a11a3SMarcus Overhagen 168*083a11a3SMarcus Overhagen if (cx23882_terminate(device) < B_OK) { 169*083a11a3SMarcus Overhagen } 170*083a11a3SMarcus Overhagen 171*083a11a3SMarcus Overhagen remove_io_interrupt_handler(device->irq, cx23882_int, device); 172*083a11a3SMarcus Overhagen 173*083a11a3SMarcus Overhagen delete_area(device->regs_area); 174*083a11a3SMarcus Overhagen 175*083a11a3SMarcus Overhagen delete_sem(device->capture_sem); 176*083a11a3SMarcus Overhagen 177*083a11a3SMarcus Overhagen TRACE("interface_detach\n"); 178*083a11a3SMarcus Overhagen } 179*083a11a3SMarcus Overhagen 180*083a11a3SMarcus Overhagen 181*083a11a3SMarcus Overhagen static void 182*083a11a3SMarcus Overhagen interface_get_interface_info(dvb_interface_info_t *info) 183*083a11a3SMarcus Overhagen { 184*083a11a3SMarcus Overhagen memset(info, 0, sizeof(*info)); 185*083a11a3SMarcus Overhagen info->version = 1; 186*083a11a3SMarcus Overhagen info->flags = 0; 187*083a11a3SMarcus Overhagen info->type = DVB_TYPE_DVB_T; 188*083a11a3SMarcus Overhagen strcpy(info->name, "CX23882"); 189*083a11a3SMarcus Overhagen strcpy(info->info, "Hauppauge WinTV-NOVA-T model 928 driver, Copyright (c) 2005 Marcus Overhagen"); 190*083a11a3SMarcus Overhagen } 191*083a11a3SMarcus Overhagen 192*083a11a3SMarcus Overhagen 193*083a11a3SMarcus Overhagen status_t 194*083a11a3SMarcus Overhagen interface_ioctl(void *cookie, uint32 op, void *arg, size_t len) 195*083a11a3SMarcus Overhagen { 196*083a11a3SMarcus Overhagen cx23882_device *device = cookie; 197*083a11a3SMarcus Overhagen status_t res; 198*083a11a3SMarcus Overhagen 199*083a11a3SMarcus Overhagen switch (op) { 200*083a11a3SMarcus Overhagen case DVB_GET_INTERFACE_INFO: 201*083a11a3SMarcus Overhagen { 202*083a11a3SMarcus Overhagen dvb_interface_info_t info; 203*083a11a3SMarcus Overhagen interface_get_interface_info(&info); 204*083a11a3SMarcus Overhagen if (user_memcpy(arg, &info, sizeof(info)) < B_OK) 205*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 206*083a11a3SMarcus Overhagen break; 207*083a11a3SMarcus Overhagen } 208*083a11a3SMarcus Overhagen 209*083a11a3SMarcus Overhagen case DVB_GET_FREQUENCY_INFO: 210*083a11a3SMarcus Overhagen { 211*083a11a3SMarcus Overhagen dvb_frequency_info_t info; 212*083a11a3SMarcus Overhagen if ((res = cx22702_get_frequency_info(device->i2c_bus, &info)) < B_OK) 213*083a11a3SMarcus Overhagen return res; 214*083a11a3SMarcus Overhagen if (user_memcpy(arg, &info, sizeof(info)) < B_OK) 215*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 216*083a11a3SMarcus Overhagen break; 217*083a11a3SMarcus Overhagen } 218*083a11a3SMarcus Overhagen 219*083a11a3SMarcus Overhagen case DVB_START_CAPTURE: 220*083a11a3SMarcus Overhagen { 221*083a11a3SMarcus Overhagen return cx23882_start_capture(device); 222*083a11a3SMarcus Overhagen } 223*083a11a3SMarcus Overhagen 224*083a11a3SMarcus Overhagen case DVB_STOP_CAPTURE: 225*083a11a3SMarcus Overhagen { 226*083a11a3SMarcus Overhagen return cx23882_stop_capture(device); 227*083a11a3SMarcus Overhagen } 228*083a11a3SMarcus Overhagen 229*083a11a3SMarcus Overhagen case DVB_SET_TUNING_PARAMETERS: 230*083a11a3SMarcus Overhagen { 231*083a11a3SMarcus Overhagen dvb_tuning_parameters_t params; 232*083a11a3SMarcus Overhagen if (user_memcpy(¶ms, arg, sizeof(params)) < B_OK) 233*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 234*083a11a3SMarcus Overhagen if ((res = cx22702_set_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) 235*083a11a3SMarcus Overhagen return res; 236*083a11a3SMarcus Overhagen break; 237*083a11a3SMarcus Overhagen } 238*083a11a3SMarcus Overhagen 239*083a11a3SMarcus Overhagen case DVB_GET_TUNING_PARAMETERS: 240*083a11a3SMarcus Overhagen { 241*083a11a3SMarcus Overhagen dvb_tuning_parameters_t params; 242*083a11a3SMarcus Overhagen if ((res = cx22702_get_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) 243*083a11a3SMarcus Overhagen return res; 244*083a11a3SMarcus Overhagen if (user_memcpy(arg, ¶ms, sizeof(params)) < B_OK) 245*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 246*083a11a3SMarcus Overhagen break; 247*083a11a3SMarcus Overhagen } 248*083a11a3SMarcus Overhagen 249*083a11a3SMarcus Overhagen case DVB_GET_STATUS: 250*083a11a3SMarcus Overhagen { 251*083a11a3SMarcus Overhagen dvb_status_t status; 252*083a11a3SMarcus Overhagen if ((res = cx22702_get_status(device->i2c_bus, &status)) < B_OK) 253*083a11a3SMarcus Overhagen return res; 254*083a11a3SMarcus Overhagen if (user_memcpy(arg, &status, sizeof(status)) < B_OK) 255*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 256*083a11a3SMarcus Overhagen break; 257*083a11a3SMarcus Overhagen } 258*083a11a3SMarcus Overhagen 259*083a11a3SMarcus Overhagen case DVB_GET_SS: 260*083a11a3SMarcus Overhagen { 261*083a11a3SMarcus Overhagen uint32 value; 262*083a11a3SMarcus Overhagen if ((res = cx22702_get_ss(device->i2c_bus, &value)) < B_OK) 263*083a11a3SMarcus Overhagen return res; 264*083a11a3SMarcus Overhagen if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 265*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 266*083a11a3SMarcus Overhagen break; 267*083a11a3SMarcus Overhagen } 268*083a11a3SMarcus Overhagen 269*083a11a3SMarcus Overhagen case DVB_GET_BER: 270*083a11a3SMarcus Overhagen { 271*083a11a3SMarcus Overhagen uint32 value; 272*083a11a3SMarcus Overhagen if ((res = cx22702_get_ber(device->i2c_bus, &value)) < B_OK) 273*083a11a3SMarcus Overhagen return res; 274*083a11a3SMarcus Overhagen if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 275*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 276*083a11a3SMarcus Overhagen break; 277*083a11a3SMarcus Overhagen } 278*083a11a3SMarcus Overhagen 279*083a11a3SMarcus Overhagen case DVB_GET_SNR: 280*083a11a3SMarcus Overhagen { 281*083a11a3SMarcus Overhagen uint32 value; 282*083a11a3SMarcus Overhagen if ((res = cx22702_get_snr(device->i2c_bus, &value)) < B_OK) 283*083a11a3SMarcus Overhagen return res; 284*083a11a3SMarcus Overhagen if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 285*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 286*083a11a3SMarcus Overhagen break; 287*083a11a3SMarcus Overhagen } 288*083a11a3SMarcus Overhagen 289*083a11a3SMarcus Overhagen case DVB_GET_UPC: 290*083a11a3SMarcus Overhagen { 291*083a11a3SMarcus Overhagen uint32 value; 292*083a11a3SMarcus Overhagen if ((res = cx22702_get_upc(device->i2c_bus, &value)) < B_OK) 293*083a11a3SMarcus Overhagen return res; 294*083a11a3SMarcus Overhagen if (user_memcpy(arg, &value, sizeof(value)) < B_OK) 295*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 296*083a11a3SMarcus Overhagen break; 297*083a11a3SMarcus Overhagen } 298*083a11a3SMarcus Overhagen 299*083a11a3SMarcus Overhagen case DVB_CAPTURE: 300*083a11a3SMarcus Overhagen { 301*083a11a3SMarcus Overhagen dvb_capture_t cap_data; 302*083a11a3SMarcus Overhagen // wait for data ready interrupt, with 100 ms timeout (in case tuning failed, bad reception, etc) 303*083a11a3SMarcus Overhagen if ((res = acquire_sem_etc(device->capture_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 100000)) < B_OK) 304*083a11a3SMarcus Overhagen return res; 305*083a11a3SMarcus Overhagen cap_data.data = device->capture_data; 306*083a11a3SMarcus Overhagen cap_data.size = device->capture_size; 307*083a11a3SMarcus Overhagen cap_data.end_time = device->capture_end_time; 308*083a11a3SMarcus Overhagen if (user_memcpy(arg, &cap_data, sizeof(cap_data)) < B_OK) 309*083a11a3SMarcus Overhagen return B_BAD_ADDRESS; 310*083a11a3SMarcus Overhagen break; 311*083a11a3SMarcus Overhagen } 312*083a11a3SMarcus Overhagen 313*083a11a3SMarcus Overhagen default: 314*083a11a3SMarcus Overhagen { 315*083a11a3SMarcus Overhagen TRACE("interface_ioctl\n"); 316*083a11a3SMarcus Overhagen return B_BAD_VALUE; 317*083a11a3SMarcus Overhagen } 318*083a11a3SMarcus Overhagen } 319*083a11a3SMarcus Overhagen 320*083a11a3SMarcus Overhagen return B_OK; 321*083a11a3SMarcus Overhagen } 322