diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/config.h b/src/add-ons/kernel/drivers/dvb/cx23882/config.h new file mode 100644 index 0000000000..493df85bb1 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/config.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define VERSION "1.0" +#define BUILD __DATE__ " "__TIME__ +#define INFO1 "cx23882: DVB-T Driver. Version " VERSION ", Revision " REVISION ", Build " BUILD +#define INFO2 "cx23882: Copyright (c) 2004-2006 Marcus Overhagen. All rights reserved.\n" + +#define MAX_CARDS 8 + +#define PCI_LATENCY 0x20 + +#define I2C_ADDR_DEMOD 0x43 +#define I2C_ADDR_EEPROM 0x50 +#define I2C_ADDR_PLL 0x61 + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.c b/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.c new file mode 100644 index 0000000000..874c7fb270 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "cx22702.h" +#include "dtt7592.h" +#include "config.h" +#include "dvb.h" + +#define TRACE_CX22702 +#ifdef TRACE_CX22702 + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + + +static void +cx22702_reg_dump(i2c_bus *bus) +{ + int i; + for (i = 0; i < 256; i++) { + uint8 data; + if (cx22702_reg_read(bus, i, &data) != B_OK) + dprintf("cx22702_reg 0x%02x error\n", i); + else + dprintf("cx22702_reg 0x%02x value 0x%02x\n", i, data); + } +} + + +status_t +cx22702_reg_write(i2c_bus *bus, uint8 reg, uint8 data) +{ + status_t res; + uint8 buf[2] = {reg, data}; + res = i2c_write(bus, I2C_ADDR_DEMOD, buf, 2); + if (res != B_OK) + TRACE("cx22702_reg_write error, reg 0x%02x, value 0x%02x\n", reg, data); + return res; +} + + +status_t +cx22702_reg_read(i2c_bus *bus, uint8 reg, uint8 *data) +{ + status_t res; + res = i2c_xfer(bus, I2C_ADDR_DEMOD, ®, 1, data, 1); + if (res != B_OK) + TRACE("cx22702_reg_read error, reg 0x%02x\n", reg); + return res; +} + + +status_t +cx22702_init(i2c_bus *bus) +{ + if (cx22702_reg_write(bus, 0x00, 0x02) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK) return B_ERROR; + snooze(10000); + if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x09, 0x01) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x0B, 0x04) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x0C, 0x00) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x0D, 0x80) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x26, 0x80) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x2D, 0xff) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0xDC, 0x00) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0xE4, 0x00) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0xF8, 0x02) != B_OK) return B_ERROR; + if (cx22702_reg_write(bus, 0x00, 0x01) != B_OK) return B_ERROR; + return B_OK; +} + + +status_t +cx22702_get_frequency_info(i2c_bus *bus, dvb_frequency_info_t *info) +{ + memset(info, 0, sizeof(*info)); + info->frequency_min = 149000000; + info->frequency_max = 860000000; + info->frequency_step = 166667; + return B_OK; +} + + +status_t +cx22702_set_tuning_parameters(i2c_bus *bus, const dvb_t_tuning_parameters_t *params) +{ + uint8 data; + status_t res; + + if (cx22702_reg_write(bus, 0x00, 0x00) != B_OK) + return B_ERROR; + + res = dtt7592_set_frequency(bus, params->frequency, params->bandwidth); + if (res != B_OK) + return res; + + if (cx22702_reg_read(bus, 0x0c, &data) != B_OK) + return B_ERROR; + switch (params->inversion) { + case DVB_INVERSION_ON: data |= 0x01; break; + case DVB_INVERSION_OFF: data &= ~0x01; break; + default: return B_ERROR; + } + switch (params->bandwidth) { + case DVB_BANDWIDTH_6_MHZ: data = (data & ~0x10) | 0x20; break; + case DVB_BANDWIDTH_7_MHZ: data = (data & ~0x20) | 0x10; break; + case DVB_BANDWIDTH_8_MHZ: data &= ~0x30; break; + default: return B_ERROR; + } + if (cx22702_reg_write(bus, 0x0c, data) != B_OK) + return B_ERROR; + + switch (params->modulation) { + case DVB_MODULATION_QPSK: data = 0x00; break; + case DVB_MODULATION_16_QAM: data = 0x08; break; + case DVB_MODULATION_64_QAM: data = 0x10; break; + default: return B_ERROR; + } + switch (params->hierarchy) { + case DVB_HIERARCHY_NONE: break; + case DVB_HIERARCHY_1: data |= 0x01; break; + case DVB_HIERARCHY_2: data |= 0x02; break; + case DVB_HIERARCHY_4: data |= 0x03; break; + default: return B_ERROR; + } + if (cx22702_reg_write(bus, 0x06, data) != B_OK) + return B_ERROR; + + switch (params->code_rate_hp) { + case DVB_FEC_NONE: data = 0x00; break; + case DVB_FEC_1_2: data = 0x00; break; + case DVB_FEC_2_3: data = 0x08; break; + case DVB_FEC_3_4: data = 0x10; break; + case DVB_FEC_5_6: data = 0x18; break; + case DVB_FEC_6_7: data = 0x20; break; + default: return B_ERROR; + } + switch (params->code_rate_lp) { + case DVB_FEC_NONE: break; + case DVB_FEC_1_2: break; + case DVB_FEC_2_3: data |= 0x01; break; + case DVB_FEC_3_4: data |= 0x02; break; + case DVB_FEC_5_6: data |= 0x03; break; + case DVB_FEC_6_7: data |= 0x04; break; + default: return B_ERROR; + } + if (cx22702_reg_write(bus, 0x07, data) != B_OK) + return B_ERROR; + + switch (params->transmission_mode) { + case DVB_TRANSMISSION_MODE_2K: data = 0x00; break; + case DVB_TRANSMISSION_MODE_8K: data = 0x01; break; + default: return B_ERROR; + } + switch (params->guard_interval) { + case DVB_GUARD_INTERVAL_1_4: data |= 0x0c; break; + case DVB_GUARD_INTERVAL_1_8: data |= 0x08; break; + case DVB_GUARD_INTERVAL_1_16: data |= 0x04; break; + case DVB_GUARD_INTERVAL_1_32: break; + default: return B_ERROR; + } + if (cx22702_reg_write(bus, 0x08, data) != B_OK) + return B_ERROR; + + if (cx22702_reg_read(bus, 0x0b, &data) != B_OK) + return B_ERROR; + if (cx22702_reg_write(bus, 0x0b, data | 0x02) != B_OK) + return B_ERROR; + + if (cx22702_reg_write(bus, 0x00, 0x01) != B_OK) + return B_ERROR; + +// cx22702_reg_dump(bus); + + return B_OK; +} + + +status_t +cx22702_get_tuning_parameters(i2c_bus *bus, dvb_t_tuning_parameters_t *params) +{ + uint8 reg01, reg02, reg03, reg0A, reg0C; + + if (cx22702_reg_read(bus, 0x01, ®01) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0x02, ®02) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0x03, ®03) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0x0a, ®0A) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0x0c, ®0C) != B_OK) + return B_ERROR; + + memset(params, 0, sizeof(*params)); + params->inversion = (reg0C & 0x01) ? DVB_INVERSION_ON : DVB_INVERSION_OFF; + + // XXX TODO... + + return B_OK; +} + + +status_t +cx22702_get_status(i2c_bus *bus, dvb_status_t *status) +{ + uint8 reg0A, reg23; + + if (cx22702_reg_read(bus, 0x0a, ®0A) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0x23, ®23) != B_OK) + return B_ERROR; + + *status = 0; + if (reg0A & 0x10) + *status |= DVB_STATUS_LOCK | DVB_STATUS_VITERBI | DVB_STATUS_SYNC; + if (reg0A & 0x20) + *status |= DVB_STATUS_CARRIER; + if (reg23 < 0xf0) + *status |= DVB_STATUS_SIGNAL; + + return B_OK; +} + + +status_t +cx22702_get_ss(i2c_bus *bus, uint32 *ss) +{ + uint8 reg23; + if (cx22702_reg_read(bus, 0x23, ®23) != B_OK) + return B_ERROR; + *ss = reg23; + return B_OK; +} + + +status_t +cx22702_get_ber(i2c_bus *bus, uint32 *ber) +{ + uint8 regDE_1, regDE_2, regDF; + int trys; + + trys = 50; + do { + if (cx22702_reg_read(bus, 0xDE, ®DE_1) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0xDF, ®DF) != B_OK) + return B_ERROR; + if (cx22702_reg_read(bus, 0xDE, ®DE_2) != B_OK) + return B_ERROR; + } while (regDE_1 != regDE_2 && --trys > 0); + if (trys == 0) + return B_ERROR; + + *ber = (regDE_1 & 0x7f) << 7 | (regDF & 0x7f); + + return B_OK; +} + + +status_t +cx22702_get_snr(i2c_bus *bus, uint32 *snr) +{ + uint32 ber; + status_t stat = cx22702_get_ber(bus, &ber); + *snr = 16384 - ber; + return stat; +} + + +status_t +cx22702_get_upc(i2c_bus *bus, uint32 *upc) +{ + uint8 regE3; + + if (cx22702_reg_read(bus, 0xE3, ®E3) != B_OK) + return B_ERROR; + if (cx22702_reg_write(bus, 0xE3, 0) != B_OK) + return B_ERROR; + *upc = regE3; + return B_OK; +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.h b/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.h new file mode 100644 index 0000000000..f92e20ac17 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx22702.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CX22702_H +#define __CX22702_H + +#include "i2c-core.h" +#include "dvb.h" + +status_t cx22702_reg_write(i2c_bus *bus, uint8 reg, uint8 data); +status_t cx22702_reg_read(i2c_bus *bus, uint8 reg, uint8 *data); + +status_t cx22702_init(i2c_bus *bus); + +status_t cx22702_get_frequency_info(i2c_bus *bus, dvb_frequency_info_t *info); + +status_t cx22702_set_tuning_parameters(i2c_bus *bus, const dvb_t_tuning_parameters_t *params); +status_t cx22702_get_tuning_parameters(i2c_bus *bus, dvb_t_tuning_parameters_t *params); + +status_t cx22702_get_status(i2c_bus *bus, dvb_status_t *status); +status_t cx22702_get_ss(i2c_bus *bus, uint32 *ss); +status_t cx22702_get_ber(i2c_bus *bus, uint32 *ber); +status_t cx22702_get_snr(i2c_bus *bus, uint32 *snr); +status_t cx22702_get_upc(i2c_bus *bus, uint32 *upc); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.c b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.c new file mode 100644 index 0000000000..dcba84cc35 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "cx23882.h" +#include "util.h" +#include +#include +#include + + +#define TRACE_CX23882 +#ifdef TRACE_CX23882 + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + +// settings for hardware stream sync +#define MPEG2_SYNC_BYTE 0x47 +#define MPEG2_PACKET_SIZE 188 +#define SYNC_PACKET_COUNT 7 // 0 and 5 don't seem to work + +// Line size is also used as FIFO size! +// BYTES_PER_LINE must be a multiple of 8 and <= 4096 bytes +#define PACKETS_PER_LINE 20 +#define BYTES_PER_LINE (PACKETS_PER_LINE * MPEG2_PACKET_SIZE) + +#define SRAM_START_ADDRESS 0x180000 +#define SRAM_BASE_CMDS_TS 0x200 +#define SRAM_BASE_RISC_PROG 0x400 +#define SRAM_BASE_RISC_QUEUE 0x800 +#define SRAM_BASE_CDT 0x900 +#define SRAM_BASE_FIFO_0 0x1000 +#define SRAM_BASE_FIFO_1 0x2000 + +// About 64 kByte DMA buffer size +#define LINES_PER_BUFFER 16 +#define DMA_BUFFER_SIZE (LINES_PER_BUFFER * BYTES_PER_LINE) + + +static status_t cx23882_buffers_alloc(cx23882_device *device); +static void cx23882_buffers_free(cx23882_device *device); +static void cx23882_risc_ram_setup(cx23882_device *device); +static void cx23882_sram_setup(cx23882_device *device); +static void cx23882_via_sis_fixup(cx23882_device *device); + + +void +cx23882_reset(cx23882_device *device) +{ + // software reset (XXX Test) + reg_write32(0x38c06c, 1); + snooze(200000); + + // disable RISC controller + reg_write32(REG_DEV_CNTRL2, 0); + + // disable TS interface DMA + reg_write32(REG_TS_DMA_CNTRL, 0x0); + + // disable VIP interface up- & downstram DMA + reg_write32(REG_VIP_STREAM_EN, 0x0); + + // disable host interface up- & downstram DMA + reg_write32(REG_HST_STREAM_EN, 0x0); + + // stop all interrupts + reg_write32(REG_PCI_INT_MSK, 0x0); + reg_write32(REG_VID_INT_MSK, 0x0); + reg_write32(REG_AUD_INT_MSK, 0x0); + reg_write32(REG_TS_INT_MSK, 0x0); + reg_write32(REG_VIP_INT_MSK, 0x0); + reg_write32(REG_HST_INT_MSK, 0x0); + reg_write32(REG_DMA_RISC_INT_MSK, 0x0); + + // clear all pending interrupts + reg_write32(REG_PCI_INT_STAT, 0xffffffff); + reg_write32(REG_VID_INT_STAT, 0xffffffff); + reg_write32(REG_AUD_INT_STAT, 0xffffffff); + reg_write32(REG_TS_INT_STAT, 0xffffffff); + reg_write32(REG_VIP_INT_STAT, 0xffffffff); + reg_write32(REG_HST_INT_STAT, 0xffffffff); + reg_write32(REG_DMA_RISC_INT_MSK, 0xffffffff); +} + + +status_t +cx23882_init(cx23882_device *device) +{ + // assumes that cx23882_reset() has already been called + + status_t err; + + if ((err = cx23882_buffers_alloc(device)) < B_OK) { + dprintf("cx23882: Error, buffer alloc failed\n"); + return err; + } + + device->capture_size = DMA_BUFFER_SIZE; + + cx23882_via_sis_fixup(device); + + // Set FIFO thresholds, should be 0 < x <= 7 + reg_write32(REG_PDMA_STHRSH, PDMA_ISBTHRSH_6 | PDMA_PCITHRSH_6); + reg_write32(REG_PDMA_DTHRSH, PDMA_ISBTHRSH_6 | PDMA_PCITHRSH_6); + + // init risc programm + cx23882_risc_ram_setup(device); + + // init sram + cx23882_sram_setup(device); + + // Reset counter to 0 + reg_write32(REG_TS_GP_CNT_CNTRL, 0x3); + + // Line length for RISC DMA + reg_write32(REG_TS_LNGTH, BYTES_PER_LINE); + + // Set serial interface mode + reg_write32(REG_TS_GEN_CONTROL, reg_read32(REG_TS_GEN_CONTROL) | TS_GEN_CONTROL_IPB_SMODE); + + // Setup hardware MPEG2 fec interface + reg_write32(REG_HW_SOP_CONTROL, (MPEG2_SYNC_BYTE << 16) | (MPEG2_PACKET_SIZE << 4) | SYNC_PACKET_COUNT); + + // Setup TSSTOP status, active low, rising and falling edge, single bit width + reg_write32(REG_TS_SOP_STATUS, reg_read32(REG_TS_SOP_STATUS) | 0x18000); + reg_write32(REG_TS_SOP_STATUS, reg_read32(REG_TS_SOP_STATUS) & ~0x06000); + + // Enable interrupts for MPEG TS and all errors + reg_write32(REG_PCI_INT_MSK, reg_read32(REG_PCI_INT_MSK) | PCI_INT_STAT_TS_INT | 0x00fc00); + reg_write32(REG_TS_INT_MSK, reg_read32(REG_TS_INT_MSK) | TS_INT_STAT_TS_RISC1 | TS_INT_STAT_TS_RISC2 | 0x1f1100); + + TRACE("cx23882_init done\n"); + return B_OK; +} + + +status_t +cx23882_terminate(cx23882_device *device) +{ + cx23882_reset(device); + + cx23882_buffers_free(device); + return B_OK; +} + + +status_t +cx23882_start_capture(cx23882_device *device) +{ + TRACE("cx23882_start_capture\n"); + + // start RISC processor and DMA + reg_write32(REG_DEV_CNTRL2, reg_read32(REG_DEV_CNTRL2) | DEV_CNTRL2_RUN_RISC); + reg_write32(REG_TS_DMA_CNTRL, reg_read32(REG_TS_DMA_CNTRL) | TS_DMA_CNTRL_TS_FIFO_EN | TS_DMA_CNTRL_TS_RISC_EN); + return B_OK; +} + + +status_t +cx23882_stop_capture(cx23882_device *device) +{ + TRACE("cx23882_stop_capture\n"); + + // stop RISC processor and DMA + reg_write32(REG_TS_DMA_CNTRL, reg_read32(REG_TS_DMA_CNTRL) & ~(TS_DMA_CNTRL_TS_FIFO_EN | TS_DMA_CNTRL_TS_RISC_EN)); + reg_write32(REG_DEV_CNTRL2, reg_read32(REG_DEV_CNTRL2) & ~DEV_CNTRL2_RUN_RISC); + return B_OK; +} + + +static inline void +cx23882_mpegts_int(cx23882_device *device) +{ + uint32 mstat = reg_read32(REG_TS_INT_MSTAT); + reg_write32(REG_TS_INT_STAT, mstat); + +// dprintf("cx23882_mpegts_int got 0x%08lx\n", mstat); + + if (mstat & TS_INT_STAT_OPC_ERR) { + dprintf("cx23882_mpegts_int RISC opcode error\n"); + reg_write32(REG_PCI_INT_MSK, 0); + return; + } + + if ((mstat & (TS_INT_STAT_TS_RISC1 | TS_INT_STAT_TS_RISC2)) == (TS_INT_STAT_TS_RISC1 | TS_INT_STAT_TS_RISC2)) { + dprintf("cx23882_mpegts_int both buffers ready\n"); + mstat = TS_INT_STAT_TS_RISC1; + } + + if (mstat & TS_INT_STAT_TS_RISC1) { + int32 count; +// dprintf("cx23882_mpegts_int buffer 1 at %Ld\n", system_time()); + device->capture_data = device->dma_buf1_virt; + device->capture_end_time = system_time(); + get_sem_count(device->capture_sem, &count); + if (count <= 0) + release_sem_etc(device->capture_sem, 1, B_DO_NOT_RESCHEDULE); + } + + if (mstat & TS_INT_STAT_TS_RISC2) { + int32 count; +// dprintf("cx23882_mpegts_int buffer 2 at %Ld\n", system_time()); + device->capture_data = device->dma_buf2_virt; + device->capture_end_time = system_time(); + get_sem_count(device->capture_sem, &count); + if (count <= 0) + release_sem_etc(device->capture_sem, 1, B_DO_NOT_RESCHEDULE); + } +} + + +int32 +cx23882_int(void *data) +{ + cx23882_device *device = data; + uint32 mstat; + uint32 wmstat; + + mstat = reg_read32(REG_PCI_INT_MSTAT); + if (!mstat) + return B_UNHANDLED_INTERRUPT; + + if (mstat & (PCI_INT_STAT_HST_INT | PCI_INT_STAT_VIP_INT | PCI_INT_STAT_AUD_INT | PCI_INT_STAT_VID_INT)) { + // serious error, these bits should not be set + dprintf("cx23882_int error: msk 0x%08lx, stat 0x%08lx, mstat 0x%08lx\n", reg_read32(REG_PCI_INT_MSK), reg_read32(REG_PCI_INT_STAT), mstat); + reg_write32(REG_PCI_INT_MSK, 0); + return B_HANDLED_INTERRUPT; + } + + wmstat = mstat & ~(PCI_INT_STAT_HST_INT | PCI_INT_STAT_VIP_INT | PCI_INT_STAT_TS_INT | PCI_INT_STAT_AUD_INT | PCI_INT_STAT_VID_INT); + if (wmstat) + reg_write32(REG_PCI_INT_STAT, wmstat); + + if (wmstat) + dprintf("cx23882_int got 0x%08lx\n", wmstat); + + if (mstat & PCI_INT_STAT_TS_INT) { + cx23882_mpegts_int(device); + return B_INVOKE_SCHEDULER; + } else { + return B_HANDLED_INTERRUPT; + } +} + + +static status_t +cx23882_buffers_alloc(cx23882_device *device) +{ + device->dma_buf1_area = alloc_mem(&device->dma_buf1_virt, &device->dma_buf1_phys, DMA_BUFFER_SIZE, B_READ_AREA, "cx23882 dma buf 1"); + device->dma_buf2_area = alloc_mem(&device->dma_buf2_virt, &device->dma_buf2_phys, DMA_BUFFER_SIZE, B_READ_AREA, "cx23882 dma buf 2"); + if (device->dma_buf1_area < B_OK || device->dma_buf2_area < B_OK) { + cx23882_buffers_free(device); + return B_NO_MEMORY; + } + return B_OK; +} + + +static void +cx23882_buffers_free(cx23882_device *device) +{ + if (device->dma_buf1_area >= 0) + delete_area(device->dma_buf1_area); + if (device->dma_buf2_area >= 0) + delete_area(device->dma_buf2_area); + device->dma_buf1_area = -1; + device->dma_buf2_area = -1; +} + + +static void +cx23882_sram_setup(cx23882_device *device) +{ + dprintf("cx23882_sram_setup enter\n"); + + // setup CDT entries for both FIFOs + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CDT, SRAM_START_ADDRESS + SRAM_BASE_FIFO_0); + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CDT + 16, SRAM_START_ADDRESS + SRAM_BASE_FIFO_1); + + // setup CDMS + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CMDS_TS + 0x00, SRAM_START_ADDRESS + SRAM_BASE_RISC_PROG); + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CMDS_TS + 0x04, SRAM_START_ADDRESS + SRAM_BASE_CDT); + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CMDS_TS + 0x08, (2 * 16) / 8); // FIFO count = 2 + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CMDS_TS + 0x0c, SRAM_START_ADDRESS + SRAM_BASE_RISC_QUEUE); + reg_write32(SRAM_START_ADDRESS + SRAM_BASE_CMDS_TS + 0x10, 0x80000000 | (0x100 / 4)); + + // setup DMA registers + reg_write32(REG_DMA28_PTR1, SRAM_START_ADDRESS + SRAM_BASE_FIFO_0); + reg_write32(REG_DMA28_PTR2, SRAM_START_ADDRESS + SRAM_BASE_CDT); + reg_write32(REG_DMA28_CNT1, BYTES_PER_LINE / 8); + reg_write32(REG_DMA28_CNT2, (2 * 16) / 8); // FIFO count = 2 + + dprintf("cx23882_sram_setup leave\n"); +} + + +static void +cx23882_risc_ram_setup(cx23882_device *device) +{ + char *start = (char *)(device->regs) + SRAM_START_ADDRESS + SRAM_BASE_RISC_PROG; + volatile uint32 *rp = (volatile uint32 *)start; + int i; + + #define set_opcode(a) (*rp++) = B_HOST_TO_LENDIAN_INT32((a)) + + dprintf("cx23882_risc_ram_setup enter\n"); + + // sync + set_opcode(RISC_RESYNC | 0); + + // copy buffer 1 + for (i = 0; i < LINES_PER_BUFFER; i++) { + set_opcode(RISC_WRITE | RISC_SOL | RISC_EOL | BYTES_PER_LINE); + set_opcode((unsigned long)device->dma_buf1_phys + i * BYTES_PER_LINE); + } + + // execute IRQ 1 + set_opcode(RISC_SKIP | RISC_IRQ1 | RISC_SOL | 0); + + // copy buffer 2 + for (i = 0; i < LINES_PER_BUFFER; i++) { + set_opcode(RISC_WRITE | RISC_SOL | RISC_EOL | BYTES_PER_LINE); + set_opcode((unsigned long)device->dma_buf2_phys + i * BYTES_PER_LINE); + } + + // execute IRQ 2 + set_opcode(RISC_SKIP | RISC_IRQ2 | RISC_SOL | 0); + + // jmp to start, but skip sync instruction + set_opcode(RISC_JUMP | RISC_SRP); + set_opcode(SRAM_START_ADDRESS + SRAM_BASE_RISC_PROG + 4); + + #undef set_opcode + + dprintf("cx23882_risc_ram_setup leave\n"); +} + + +static void +cx23882_via_sis_fixup(cx23882_device *device) +{ + uint16 host_vendor; + uint32 dev_cntrl1; + + host_vendor = gPci->read_pci_config(0, 0, 0, PCI_vendor_id, 2); + dev_cntrl1 = reg_read32(REG_F2_DEV_CNTRL1); + + if (host_vendor == PCI_VENDOR_VIA || host_vendor == PCI_VENDOR_SIS) { + dprintf("cx23882: enabling VIA/SIS compatibility mode\n"); + reg_write32(REG_F2_DEV_CNTRL1, dev_cntrl1 | F2_DEV_CNTRL1_EN_VSFX); + } else { + dprintf("cx23882: disabling VIA/SIS compatibility mode\n"); + reg_write32(REG_F2_DEV_CNTRL1, dev_cntrl1 & ~F2_DEV_CNTRL1_EN_VSFX); + } +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.h b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.h new file mode 100644 index 0000000000..8dd852a749 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CX23882_H +#define __CX23882_H + +#include +#include "driver.h" +#include "cx23882_regs.h" +#include "i2c-core.h" + +typedef struct { + const pci_info * pci_info; + int irq; + void * regs; + area_id regs_area; + uint32 i2c_reg; + i2c_bus * i2c_bus; + + area_id dma_buf1_area; + void * dma_buf1_virt; + void * dma_buf1_phys; + area_id dma_buf2_area; + void * dma_buf2_virt; + void * dma_buf2_phys; + + sem_id capture_sem; + void * capture_data; + size_t capture_size; + bigtime_t capture_end_time; +} cx23882_device; + + +#define reg_read8(offset) (*(volatile uint8 *) ((char *)(device->regs) + (offset))) +#define reg_read16(offset) (*(volatile uint16 *)((char *)(device->regs) + (offset))) +#define reg_read32(offset) (*(volatile uint32 *)((char *)(device->regs) + (offset))) +#define reg_write8(offset, value) (*(volatile uint8 *) ((char *)(device->regs) + (offset)) = value) +#define reg_write16(offset, value) (*(volatile uint16 *)((char *)(device->regs) + (offset)) = value) +#define reg_write32(offset, value) (*(volatile uint32 *)((char *)(device->regs) + (offset)) = value) + + +void cx23882_reset(cx23882_device *device); +status_t cx23882_init(cx23882_device *device); +status_t cx23882_terminate(cx23882_device *device); + +status_t cx23882_start_capture(cx23882_device *device); +status_t cx23882_stop_capture(cx23882_device *device); + +int32 cx23882_int(void *data); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.c b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.c new file mode 100644 index 0000000000..20216f4ea5 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "i2c.h" +#include "i2c-core.h" + + +static void +set_scl(void *cookie, int state) +{ + cx23882_device * device = cookie; + if (state) + device->i2c_reg |= I2C_SCL; + else + device->i2c_reg &= ~I2C_SCL; + reg_write32(REG_I2C_CONTROL, device->i2c_reg); + reg_read32(REG_I2C_CONTROL); // PCI bridge flush +} + + +static void +set_sda(void *cookie, int state) +{ + cx23882_device * device = cookie; + if (state) + device->i2c_reg |= I2C_SDA; + else + device->i2c_reg &= ~I2C_SDA; + reg_write32(REG_I2C_CONTROL, device->i2c_reg); + reg_read32(REG_I2C_CONTROL); // PCI bridge flush +} + + +static int +get_scl(void *cookie) +{ + cx23882_device * device = cookie; + return (reg_read32(REG_I2C_CONTROL) & I2C_SCL) >> 1; // I2C_SCL is 0x02 +} + + +static int +get_sda(void *cookie) +{ + cx23882_device * device = cookie; + return reg_read32(REG_I2C_CONTROL) & I2C_SDA; // I2C_SDA is 0x01 +} + + +status_t +i2c_init(cx23882_device *device) +{ + device->i2c_bus = i2c_create_bus(device, 80000, 2000000, set_scl, set_sda, get_scl, get_sda); + device->i2c_reg = reg_read32(REG_I2C_CONTROL); + device->i2c_reg &= ~I2C_HW_MODE; + device->i2c_reg |= I2C_SCL | I2C_SDA; + reg_write32(REG_I2C_CONTROL, device->i2c_reg); + reg_read32(REG_I2C_CONTROL); // PCI bridge flush + return device->i2c_bus ? B_OK : B_ERROR; +} + + +void +i2c_terminate(cx23882_device *device) +{ + i2c_delete_bus(device->i2c_bus); +} + + diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.h b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.h new file mode 100644 index 0000000000..5c41b6366c --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_i2c.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __I2C_H +#define __I2C_H + +#include "cx23882.h" + +status_t i2c_init(cx23882_device *device); +void i2c_terminate(cx23882_device *device); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_regs.h b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_regs.h new file mode 100644 index 0000000000..f699b21775 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/cx23882_regs.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CX23882_REGS_H +#define __CX23882_REGS_H + +#define PCI_PCICMD_IOS 0x01 +#define PCI_PCICMD_MSE 0x02 +#define PCI_PCICMD_BME 0x04 + +#define PCI_VENDOR_SIS 0x1039 +#define PCI_VENDOR_VIA 0x1106 + +#define REG_PDMA_STHRSH 0x200000 +#define REG_PDMA_DTHRSH 0x200010 + +#define PDMA_ISBTHRSH_1 0x0100 +#define PDMA_ISBTHRSH_2 0x0200 +#define PDMA_ISBTHRSH_3 0x0300 +#define PDMA_ISBTHRSH_4 0x0400 +#define PDMA_ISBTHRSH_5 0x0500 +#define PDMA_ISBTHRSH_6 0x0600 +#define PDMA_ISBTHRSH_7 0x0700 + +#define PDMA_PCITHRSH_1 0x0001 +#define PDMA_PCITHRSH_2 0x0002 +#define PDMA_PCITHRSH_3 0x0003 +#define PDMA_PCITHRSH_4 0x0004 +#define PDMA_PCITHRSH_5 0x0005 +#define PDMA_PCITHRSH_6 0x0006 +#define PDMA_PCITHRSH_7 0x0007 + +#define REG_DEV_CNTRL2 0x200034 + +#define DEV_CNTRL2_RUN_RISC 0x20 + +#define REG_PCI_INT_MSK 0x200040 +#define REG_PCI_INT_STAT 0x200044 +#define REG_PCI_INT_MSTAT 0x200048 + +#define PCI_INT_STAT_VID_INT 0x01 +#define PCI_INT_STAT_AUD_INT 0x02 +#define PCI_INT_STAT_TS_INT 0x04 +#define PCI_INT_STAT_VIP_INT 0x08 +#define PCI_INT_STAT_HST_INT 0x10 + +#define REG_VID_INT_MSK 0x200050 +#define REG_VID_INT_STAT 0x200054 +#define REG_VID_INT_MSTAT 0x200058 + +#define REG_AUD_INT_MSK 0x200060 +#define REG_AUD_INT_STAT 0x200064 +#define REG_AUD_INT_MSTAT 0x200068 + +#define REG_TS_INT_MSK 0x200070 +#define REG_TS_INT_STAT 0x200074 +#define REG_TS_INT_MSTAT 0x200078 + +#define TS_INT_STAT_TS_RISC1 0x000001 +#define TS_INT_STAT_TS_RISC2 0x000010 +#define TS_INT_STAT_OPC_ERR 0x010000 + +#define REG_VIP_INT_MSK 0x200080 +#define REG_VIP_INT_STAT 0x200084 +#define REG_VIP_INT_MSTAT 0x200088 + +#define REG_HST_INT_MSK 0x200090 +#define REG_HST_INT_STAT 0x200094 +#define REG_HST_INT_MSTAT 0x200098 + +#define REG_F2_DEV_CNTRL1 0x2f0240 +#define F2_DEV_CNTRL1_EN_VSFX 0x8 + +#define REG_DMA28_PTR1 0x30009c +#define REG_DMA28_PTR2 0x3000dc +#define REG_DMA28_CNT1 0x30011c +#define REG_DMA28_CNT2 0x30015c + +#define REG_TS_GP_CNT_CNTRL 0x33c030 +#define REG_TS_DMA_CNTRL 0x33c040 + +#define TS_DMA_CNTRL_TS_FIFO_EN 0x01 +#define TS_DMA_CNTRL_TS_RISC_EN 0x10 + +#define REG_TS_LNGTH 0x33c048 +#define REG_HW_SOP_CONTROL 0x33c04c +#define REG_TS_GEN_CONTROL 0x33c050 + +#define TS_GEN_CONTROL_IPB_SMODE 0x08 + +#define REG_TS_BD_PKT_STATUS 0x33c054 +#define REG_TS_SOP_STATUS 0x33c058 + +#define REG_VIP_STREAM_EN 0x34c040 + +// these 3 are not in my spec, taken form Linux +#define REG_DMA_RISC_INT_MSK 0x35C060 +#define REG_DMA_RISC_INT_STAT 0x35C064 +#define REG_DMA_RISC_INT_MSTAT 0x35C068 + +#define REG_I2C_CONTROL 0x368000 +#define I2C_SDA 0x01 +#define I2C_SCL 0x02 +#define I2C_HW_MODE 0x80 + +#define REG_HST_STREAM_EN 0x38c040 + + +// RISC instructions +#define RISC_RESYNC 0x80008000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_WRITECR 0xd0000000 + +#define RISC_IMM 0x00000001 +#define RISC_SOL 0x08000000 +#define RISC_EOL 0x04000000 +#define RISC_IRQ2 0x02000000 +#define RISC_IRQ1 0x01000000 +#define RISC_SRP 0x00000001 + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/driver.c b/src/add-ons/kernel/drivers/dvb/cx23882/driver.c new file mode 100644 index 0000000000..683aed0333 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/driver.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "version.h" +#include "config.h" +#include "driver.h" +#include "mktime.h" + +#define TRACE_DRIVER +#ifdef TRACE_DRIVER + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + +typedef struct +{ + int vendor; + int device; + int subvendor; + int subdevice; + const char *name; +} card_info; + +int32 api_version = B_CUR_DRIVER_API_VERSION; +pci_module_info * gPci; +static char * sDevNameList[MAX_CARDS + 1]; +static pci_info * sDevList[MAX_CARDS]; +static int32 sOpenMask; + +static card_info sCardTable[] = +{ + { 0x14f1, 0x8802, 0x0070, 0x9002, "Hauppauge WinTV-NOVA-T model 928" }, + { /* end */ } +}; + + +typedef struct +{ + void * cookie; + int dev_id; +} interface_cookie; + + +static const char * +identify_device(const card_info *cards, const pci_info *info) +{ + for (; cards->name; cards++) { + if (cards->vendor >= 0 && cards->vendor != info->vendor_id) + continue; + if (cards->device >= 0 && cards->device != info->device_id) + continue; + if ((info->header_type & PCI_header_type_mask) != PCI_header_type_generic) + continue; + if (cards->subvendor >= 0 && cards->subvendor != info->u.h0.subsystem_vendor_id) + continue; + if (cards->subdevice >= 0 && cards->subdevice != info->u.h0.subsystem_id) + continue; + return cards->name; + } + return NULL; +} + + +status_t +init_hardware(void) +{ + pci_info info; + status_t res; + int i; + + TRACE("cx23882: init_hardware()\n"); + + if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) + return B_ERROR; + for (res = B_ERROR, i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { + if (identify_device(sCardTable, &info)) { + res = B_OK; + break; + } + } + put_module(B_PCI_MODULE_NAME); + gPci = NULL; + + return res; +} + + +status_t +init_driver(void) +{ + struct pci_info *item; + int index; + int cards; + +#ifdef DEBUG + set_dprintf_enabled(true); + load_driver_symbols("cx23882"); +#endif + + dprintf(gBanner); + + item = (pci_info *)malloc(sizeof(pci_info)); + if (!item) + return B_NO_MEMORY; + + if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) { + free(item); + return B_ERROR; + } + + for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) { + const char *info = identify_device(sCardTable, item); + if (info) { + char name[64]; + sprintf(name, "dvb/cx23882/%d", cards + 1); + dprintf("cx23882: /dev/%s is a %s\n", name, info); + sDevList[cards] = item; + sDevNameList[cards] = strdup(name); + sDevNameList[cards + 1] = NULL; + cards++; + item = (pci_info *)malloc(sizeof(pci_info)); + if (!item) + goto err_outofmem; + if (cards == MAX_CARDS) + break; + } + } + + free(item); + + if (!cards) + goto err_cards; + + return B_OK; + +err_outofmem: + TRACE("cx23882: err_outofmem\n"); + for (index = 0; index < cards; index++) { + free(sDevList[index]); + free(sDevNameList[index]); + } +err_cards: + put_module(B_PCI_MODULE_NAME); + return B_ERROR; +} + + +void +uninit_driver(void) +{ + int32 i; + + TRACE("cx23882: uninit_driver\n"); + + for (i = 0; sDevNameList[i] != NULL; i++) { + free(sDevList[i]); + free(sDevNameList[i]); + } + + put_module(B_PCI_MODULE_NAME); +} + + +static status_t +driver_open(const char *name, uint32 flags, void** _cookie) +{ + interface_cookie *cookie; + char *deviceName; + status_t status; + int dev_id; + int mask; + + TRACE("cx23882: driver open\n"); + + for (dev_id = 0; (deviceName = sDevNameList[dev_id]) != NULL; dev_id++) { + if (!strcmp(name, deviceName)) + break; + } + if (deviceName == NULL) { + TRACE("cx23882: invalid device name\n"); + return B_ERROR; + } + + // allow only one concurrent access + mask = 1 << dev_id; + if (atomic_or(&sOpenMask, mask) & mask) + return B_BUSY; + + cookie = (interface_cookie *)malloc(sizeof(interface_cookie)); + if (!cookie) + return B_NO_MEMORY; + + cookie->dev_id = dev_id; + status = interface_attach(&cookie->cookie, sDevList[dev_id]); + if (status != B_OK) { + free(cookie); + atomic_and(&sOpenMask, ~(1 << dev_id)); + return status; + } + + *_cookie = cookie; + return B_OK; +} + + +static status_t +driver_close(void* cookie) +{ + TRACE("cx23882: driver close\n"); + interface_detach(((interface_cookie *)cookie)->cookie); + return B_OK; +} + + +static status_t +driver_free(void* cookie) +{ + TRACE("cx23882: driver free\n"); + atomic_and(&sOpenMask, ~(1 << ((interface_cookie *)cookie)->dev_id)); + return B_OK; +} + + +static status_t +driver_read(void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + TRACE("cx23882: driver read\n"); + *num_bytes = 0; // required by design for read hook! + return B_ERROR; +} + + +static status_t +driver_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ + TRACE("cx23882: driver write\n"); + *num_bytes = 0; // not sure if required for write hook + return B_ERROR; +} + + +static status_t +driver_control(void *cookie, uint32 op, void *arg, size_t len) +{ +// TRACE("cx23882: driver control\n"); + return interface_ioctl(((interface_cookie *)cookie)->cookie, op, arg, len); +} + + +static device_hooks +sDeviceHooks = { + driver_open, + driver_close, + driver_free, + driver_control, + driver_read, + driver_write, +}; + + +const char** +publish_devices(void) +{ + return (const char**)sDevNameList; +} + + +device_hooks* +find_device(const char* name) +{ + return &sDeviceHooks; +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/driver.h b/src/add-ons/kernel/drivers/dvb/cx23882/driver.h new file mode 100644 index 0000000000..b480030428 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/driver.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DRIVER_H +#define __DRIVER_H + +#include + +extern pci_module_info *gPci; + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.c b/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.c new file mode 100644 index 0000000000..660cbbfdd5 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "dtt7592.h" +#include "config.h" + +#define TRACE_DTT7592 +#ifdef TRACE_DTT7592 + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + + +status_t +dtt7592_write(i2c_bus *bus, const uint8 data[4]) +{ + status_t res; + TRACE("dtt7592_write values 0x%02x 0x%02x 0x%02x 0x%02x\n", data[0], data[1], data[2], data[3]); + res = i2c_write(bus, I2C_ADDR_PLL, data, 4); + if (res != B_OK) + TRACE("dtt7592_write error, values 0x%02x 0x%02x 0x%02x 0x%02x\n", data[0], data[1], data[2], data[3]); + return res; +} + + +status_t +dtt7592_read(i2c_bus *bus, uint8 *data) +{ + status_t res; + res = i2c_read(bus, I2C_ADDR_PLL, data, 1); + if (res != B_OK) + TRACE("dtt7592_read error\n"); + return res; +} + + +status_t +dtt7592_set_frequency(i2c_bus *bus, uint32 frequency, dvb_bandwidth_t bandwidth) +{ + status_t res; + uint32 divider; + uint8 data[4]; + + divider = (frequency + 36083333) / 166666; + if (divider > 0x7fff) + divider = 0x7fff; + + TRACE("dtt7592_set_frequency frequency %ld, divider 0x%lx (%ld)\n", frequency, divider, divider); + + data[0] = divider >> 8; + data[1] = (uint8)divider; + + if (frequency > 835000000) + data[2] = 0xfc; + else if (frequency > 735000000) + data[2] = 0xf4; + else if (frequency > 465000000) + data[2] = 0xbc; + else if (frequency > 445000000) + data[2] = 0xfc; + else if (frequency > 405000000) + data[2] = 0xf4; + else if (frequency > 305000000) + data[2] = 0xbc; + else + data[2] = 0xb4; + + if (frequency > 429000000) + data[3] = 0x08; // select UHF IV/V + else + data[3] = 0x02; // select VHF III + + // only used in Germany right now, where VHF channels + // are 7 MHz wide, while UHF are 8 MHz. + if (bandwidth == DVB_BANDWIDTH_5_MHZ + || bandwidth == DVB_BANDWIDTH_6_MHZ + || bandwidth == DVB_BANDWIDTH_7_MHZ) { + data[3] |= 0x10; // activate 7 Mhz filter + } + + res = dtt7592_write(bus, data); + if (res != B_OK) { + dprintf("dtt7592_set_frequency step 1 failed\n"); + return res; + } + + // enable AGC + data[2] = (data[2] & 0x40) | 0x9c; + data[3] = 0xa0; + res = dtt7592_write(bus, data); + if (res != B_OK) { + dprintf("dtt7592_set_frequency step 2 failed\n"); + return res; + } + + // wait 100 ms + snooze(100000); + + // disable AGC + data[3] = 0x20; + res = dtt7592_write(bus, data); + if (res != B_OK) { + dprintf("dtt7592_set_frequency step 3 failed\n"); + return res; + } + + return B_OK; +} + + +void +dtt7582_dump(i2c_bus *bus) +{ + uint8 data; + if (B_OK != dtt7592_read(bus, &data)) { + TRACE("dtt7582_dump failed\n"); + } + TRACE("dtt7582_dump: 0x%02x, PLL %s, AGC %s\n", data, (data & 0x40) ? "locked" : "open", (data & 0x08) ? "active" : "off"); +} + + +void +dtt7582_test(i2c_bus *bus) +{ + TRACE("dtt7582_test start\n"); + dtt7582_dump(bus); + TRACE("dtt7582_test freq 1\n"); + dtt7592_set_frequency(bus, 150000000, DVB_BANDWIDTH_7_MHZ); + dtt7582_dump(bus); + TRACE("dtt7582_test freq 2\n"); + dtt7592_set_frequency(bus, 746000000, DVB_BANDWIDTH_8_MHZ); // Kabel 1 + dtt7582_dump(bus); + TRACE("dtt7582_test freq 3\n"); + dtt7592_set_frequency(bus, 538000000, DVB_BANDWIDTH_7_MHZ); // VOX + dtt7582_dump(bus); + TRACE("dtt7582_test freq 4\n"); + dtt7592_set_frequency(bus, 896000000, DVB_BANDWIDTH_8_MHZ); + dtt7582_dump(bus); + TRACE("dtt7582_test freq 5\n"); + dtt7592_set_frequency(bus, 333000000, DVB_BANDWIDTH_7_MHZ); + dtt7582_dump(bus); +} + + + diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.h b/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.h new file mode 100644 index 0000000000..63ce7faa8f --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/dtt7592.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DTT7592_H +#define __DTT7592_H + +#include "i2c-core.h" +#include "dvb.h" + +status_t dtt7592_write(i2c_bus *bus, const uint8 data[4]); +status_t dtt7592_read(i2c_bus *bus, uint8 *data); + +status_t dtt7592_set_frequency(i2c_bus *bus, uint32 frequency, dvb_bandwidth_t bandwidth); + +void dtt7582_test(i2c_bus *bus); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.c b/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.c new file mode 100644 index 0000000000..8791f4bb04 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "interface.h" +#include "cx23882.h" +#include "cx22702.h" +#include "dtt7592.h" +#include "driver.h" +#include "config.h" +#include "util.h" +#include "i2c.h" + +#define TRACE_INTERFACE +#ifdef TRACE_INTERFACE + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + +static inline status_t user_memcpy(void *d, const void *s, size_t z) { memcpy(d, s, z); return B_OK; } +#define B_BAD_ADDRESS B_ERROR + +static void +dump_eeprom(cx23882_device *device) +{ + uint8 d[256+8]; + uint8 adr; + uint8 *p; + int i; + status_t res; + + adr = 0; + res = i2c_xfer(device->i2c_bus, I2C_ADDR_EEPROM, &adr, 1, d, sizeof(d)); + if (res != B_OK) { + TRACE("i2c_read failed: %08lx\n", res); + return; + } + for (p = d, i = 0; i < ((int)sizeof(d) / 8); i++, p+= 8) + 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]); + +} + + +status_t +interface_attach(void **cookie, const pci_info *info) +{ + cx23882_device *device; + uint32 val; + int i; + + TRACE("interface_attach\n"); + + device = malloc(sizeof(cx23882_device)); + if (!device) + return B_NO_MEMORY; + *cookie = device; + + // initialize cookie + memset(device, 0, sizeof(*device)); + device->regs_area = -1; + device->dma_buf1_area = -1; + device->dma_buf2_area = -1; + device->capture_sem = -1; + + device->pci_info = info; + + // enable busmaster and memory mapped access, disable io port access + val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2); + val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS); + gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2, val); + + // adjust PCI latency timer + val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1); + TRACE("PCI latency is %02lx, changing to %02x\n", val, PCI_LATENCY); + gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1, PCI_LATENCY); + + // get IRQ + device->irq = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_interrupt_line, 1); + if (device->irq == 0 || device->irq == 0xff) { + dprintf("cx23882: Error, no IRQ assigned\n"); + goto err; + } + TRACE("IRQ %d\n", device->irq); + + // map registers into memory + val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, 0x10, 4); + val &= PCI_address_memory_32_mask; + if (val == 0) { + dprintf("cx23882: Error, no memory space assigned\n"); + goto err; + } + TRACE("hardware register address %p\n", (void *) val); + device->regs_area = map_mem(&device->regs, (void *)val, 16777216 /* 16 MB */, 0, "cx23882 registers"); + if (device->regs_area < B_OK) { + dprintf("cx23882: Error, can't map hardware registers\n"); + goto err; + } + TRACE("mapped registers to %p\n", device->regs); + + device->capture_sem = create_sem(0, "cx23882 capture"); + + cx23882_reset(device); + + if (i2c_init(device) < B_OK) { + dprintf("cx23882: Error, can't init I2C\n"); + } + + + if (cx23882_init(device) < B_OK) { + dprintf("cx23882: Error, can't init hardware\n"); + } + + + for (i = 0; i < 20; i++) + if (cx22702_init(device->i2c_bus) == B_OK) + break; + if (i == 20) { + TRACE("cx22702_init failed\n"); + goto err; + } + + // setup interrupt handler + if (install_io_interrupt_handler(device->irq, cx23882_int, device, 0) < B_OK) { + dprintf("cx23882: Error, can't install interrupt handler\n"); + goto err; + } + +// dump_eeprom(device); +// dtt7582_test(device->i2c_bus); + + return B_OK; +err: + free(cookie); + return B_ERROR; +} + + +void +interface_detach(void *cookie) +{ + cx23882_device *device = cookie; + + i2c_terminate(device); + + if (cx23882_terminate(device) < B_OK) { + } + + remove_io_interrupt_handler(device->irq, cx23882_int, device); + + delete_area(device->regs_area); + + delete_sem(device->capture_sem); + + TRACE("interface_detach\n"); +} + + +static void +interface_get_interface_info(dvb_interface_info_t *info) +{ + memset(info, 0, sizeof(*info)); + info->version = 1; + info->flags = 0; + info->type = DVB_TYPE_DVB_T; + strcpy(info->name, "CX23882"); + strcpy(info->info, "Hauppauge WinTV-NOVA-T model 928 driver, Copyright (c) 2005 Marcus Overhagen"); +} + + +status_t +interface_ioctl(void *cookie, uint32 op, void *arg, size_t len) +{ + cx23882_device *device = cookie; + status_t res; + + switch (op) { + case DVB_GET_INTERFACE_INFO: + { + dvb_interface_info_t info; + interface_get_interface_info(&info); + if (user_memcpy(arg, &info, sizeof(info)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_FREQUENCY_INFO: + { + dvb_frequency_info_t info; + if ((res = cx22702_get_frequency_info(device->i2c_bus, &info)) < B_OK) + return res; + if (user_memcpy(arg, &info, sizeof(info)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_START_CAPTURE: + { + return cx23882_start_capture(device); + } + + case DVB_STOP_CAPTURE: + { + return cx23882_stop_capture(device); + } + + case DVB_SET_TUNING_PARAMETERS: + { + dvb_tuning_parameters_t params; + if (user_memcpy(¶ms, arg, sizeof(params)) < B_OK) + return B_BAD_ADDRESS; + if ((res = cx22702_set_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) + return res; + break; + } + + case DVB_GET_TUNING_PARAMETERS: + { + dvb_tuning_parameters_t params; + if ((res = cx22702_get_tuning_parameters(device->i2c_bus, ¶ms.u.dvb_t)) < B_OK) + return res; + if (user_memcpy(arg, ¶ms, sizeof(params)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_STATUS: + { + dvb_status_t status; + if ((res = cx22702_get_status(device->i2c_bus, &status)) < B_OK) + return res; + if (user_memcpy(arg, &status, sizeof(status)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_SS: + { + uint32 value; + if ((res = cx22702_get_ss(device->i2c_bus, &value)) < B_OK) + return res; + if (user_memcpy(arg, &value, sizeof(value)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_BER: + { + uint32 value; + if ((res = cx22702_get_ber(device->i2c_bus, &value)) < B_OK) + return res; + if (user_memcpy(arg, &value, sizeof(value)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_SNR: + { + uint32 value; + if ((res = cx22702_get_snr(device->i2c_bus, &value)) < B_OK) + return res; + if (user_memcpy(arg, &value, sizeof(value)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_GET_UPC: + { + uint32 value; + if ((res = cx22702_get_upc(device->i2c_bus, &value)) < B_OK) + return res; + if (user_memcpy(arg, &value, sizeof(value)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + case DVB_CAPTURE: + { + dvb_capture_t cap_data; + // wait for data ready interrupt, with 100 ms timeout (in case tuning failed, bad reception, etc) + if ((res = acquire_sem_etc(device->capture_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 100000)) < B_OK) + return res; + cap_data.data = device->capture_data; + cap_data.size = device->capture_size; + cap_data.end_time = device->capture_end_time; + if (user_memcpy(arg, &cap_data, sizeof(cap_data)) < B_OK) + return B_BAD_ADDRESS; + break; + } + + default: + { + TRACE("interface_ioctl\n"); + return B_BAD_VALUE; + } + } + + return B_OK; +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.h b/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.h new file mode 100644 index 0000000000..6e9454bd0c --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/dvb_interface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DVB_INTERFACE_H +#define __DVB_INTERFACE_H + +status_t interface_attach(void **cookie, const pci_info *info); +void interface_detach(void *cookie); +status_t interface_ioctl(void *cookie, uint32 op, void *arg, size_t len); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.c b/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.c new file mode 100644 index 0000000000..1293827fb0 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "i2c-core.h" + +#define TRACE_I2C +#ifdef TRACE_I2C + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + +static status_t i2c_writebyte(i2c_bus *bus, uint8 byte, int *ack); +static status_t i2c_readbyte(i2c_bus *bus, uint8 *pbyte); +static status_t i2c_read_unlocked(i2c_bus *bus, int address, void *data, int size); +static status_t i2c_write_unlocked(i2c_bus *bus, int address, const void *data, int size); + + +struct _i2c_bus +{ + void *cookie; + bigtime_t delay; + bigtime_t timeout; + i2c_set_scl set_scl; + i2c_set_sda set_sda; + i2c_get_scl get_scl; + i2c_get_sda get_sda; + sem_id sem; +}; + + +i2c_bus * +i2c_create_bus(void *cookie, + int frequency, + bigtime_t timeout, + i2c_set_scl set_scl, + i2c_set_sda set_sda, + i2c_get_scl get_scl, + i2c_get_sda get_sda) +{ + i2c_bus *bus = malloc(sizeof(i2c_bus)); + if (!bus) + return NULL; + + bus->sem = create_sem(1, "i2c bus access"); + if (bus->sem < 0) { + free(bus); + return NULL; + } + + bus->cookie = cookie; + bus->delay = 1000000 / frequency; + if (bus->delay == 0) + bus->delay = 1; + bus->timeout = timeout; + bus->set_scl = set_scl; + bus->set_sda = set_sda; + bus->get_scl = get_scl; + bus->get_sda = get_sda; + + set_scl(cookie, 1); + set_sda(cookie, 1); + + return bus; +} + + +void +i2c_delete_bus(i2c_bus *bus) +{ + if (!bus) + return; + delete_sem(bus->sem); + free(bus); +} + + +static inline void +set_sda_low(i2c_bus *bus) +{ + bus->set_sda(bus->cookie, 0); + snooze(bus->delay); +} + + +static inline void +set_sda_high(i2c_bus *bus) +{ + bus->set_sda(bus->cookie, 1); + snooze(bus->delay); +} + + +static inline void +set_scl_low(i2c_bus *bus) +{ + bus->set_scl(bus->cookie, 0); + snooze(bus->delay); +} + + +static inline status_t +set_scl_high(i2c_bus *bus) +{ + bigtime_t end = system_time() + bus->timeout; + bus->set_scl(bus->cookie, 1); + while (0 == bus->get_scl(bus->cookie)) { + if (system_time() > end) + return B_TIMED_OUT; + snooze(5); + } + snooze(bus->delay); + return B_OK; +} + + +static inline void +i2c_start(i2c_bus *bus) +{ + set_sda_low(bus); + set_scl_low(bus); +} + + +static inline void +i2c_stop(i2c_bus *bus) +{ + set_sda_low(bus); + set_scl_high(bus); + set_sda_high(bus); +} + + +static inline status_t +i2c_start_address(i2c_bus *bus, int address, int read /* 1 = read, 0 = write */) +{ + status_t res; + uint8 addr; + int ack; + int i; + +// TRACE("i2c_start_address: enter\n"); + + addr = (address << 1) | (read & 1); + for (i = 0; i < 5; i++) { + i2c_start(bus); + res = i2c_writebyte(bus, addr, &ack); + if (res == B_OK) { + if (ack) + break; + res = B_ERROR; + } + if (res == B_TIMED_OUT) + break; + i2c_stop(bus); + snooze(50); + } + +// TRACE("i2c_start_address: %s, ack %d, i %d\n", strerror(res), ack, i); + return res; +} + + +/* write one byte and the ack/nack + * return values: + * B_OK => byte transmitted + * B_ERROR => arbitration lost + * B_TIMED_OUT => time out + */ +status_t +i2c_writebyte(i2c_bus *bus, uint8 byte, int *ack) +{ + int has_arbitration; + + int i; + has_arbitration = 1; + for (i = 7; i >= 0; i--) { + int bit = (byte >> i) & 1; + if (has_arbitration) { + if (bit) + set_sda_high(bus); + else + set_sda_low(bus); + } + if (set_scl_high(bus) != B_OK) { + set_sda_high(bus); // avoid blocking the bus + TRACE("i2c_writebyte timeout at bit %d\n", i); + return B_TIMED_OUT; + } + if (has_arbitration) { + if (bit == 1 && 0 == bus->get_sda(bus->cookie)) { + has_arbitration = 0; +// TRACE("i2c_writebyte lost arbitration at bit %d\n", i); + } + } + set_scl_low(bus); + } + set_sda_high(bus); + if (set_scl_high(bus) != B_OK) { + TRACE("i2c_writebyte timeout at ack\n"); + return B_TIMED_OUT; + } + *ack = 0 == bus->get_sda(bus->cookie); + set_scl_low(bus); + + return has_arbitration ? B_OK : B_ERROR; +} + + +/* read one byte, don't generate ack + */ +status_t +i2c_readbyte(i2c_bus *bus, uint8 *pbyte) +{ + int i; + uint8 byte; + + set_sda_high(bus); + byte = 0; + for (i = 7; i >= 0; i--) { + if (set_scl_high(bus) != B_OK) { + TRACE("i2c_readbyte timeout at bit %d\n", i); + return B_TIMED_OUT; + } + byte = (byte << 1) | bus->get_sda(bus->cookie); + set_scl_low(bus); + } + *pbyte = byte; + return B_OK; +} + + +status_t +i2c_read_unlocked(i2c_bus *bus, int address, void *data, int size) +{ + status_t status; + uint8 *bytes; + + if (size <= 0) + return B_BAD_VALUE; + + status = i2c_start_address(bus, address, 1 /* 1 = read, 0 = write */); + if (status != B_OK) { + TRACE("i2c_read: error on i2c_start_address: %s\n", strerror(status)); + return status; + } + + bytes = data; + while (size > 0) { + if (i2c_readbyte(bus, bytes) != B_OK) { // timeout + TRACE("i2c_read: timeout error on byte %ld\n", bytes - (uint8 *)data); + return B_TIMED_OUT; + } + if (size > 0) + set_sda_low(bus); // ack + else + set_sda_high(bus); // nack + + if (set_scl_high(bus) != B_OK) { + set_sda_high(bus); // avoid blocking the bus + TRACE("i2c_read: timeout at ack\n"); + return B_TIMED_OUT; + } + set_scl_low(bus); + set_sda_high(bus); + + size--; + bytes++; + } + + i2c_stop(bus); + + return B_OK; +} + + +status_t +i2c_write_unlocked(i2c_bus *bus, int address, const void *data, int size) +{ + const uint8 *bytes; + status_t status; + int ack; + + if (size <= 0) + return B_BAD_VALUE; + + status = i2c_start_address(bus, address, 0 /* 1 = read, 0 = write */); + if (status != B_OK) { + TRACE("i2c_write: error on i2c_start_address: %s\n", strerror(status)); + return status; + } + + bytes = data; + while (size > 0) { + status = i2c_writebyte(bus, *bytes, &ack); + if (status == B_TIMED_OUT) { + TRACE("i2c_write: timeout error on byte %ld\n", bytes - (uint8 *)data); + return B_TIMED_OUT; + } + if (status != B_OK) { + TRACE("i2c_write: arbitration lost on byte %ld\n", bytes - (uint8 *)data); + break; + } + if (!ack) { + TRACE("i2c_write: error, got NACK on byte %ld\n", bytes - (uint8 *)data); + break; + } + bytes++; + size--; + } + i2c_stop(bus); + + if (status != B_OK) + return status; + + return ack ? B_OK : B_ERROR; +} + + +status_t +i2c_read(i2c_bus *bus, int address, void *data, int size) +{ + status_t res; + acquire_sem(bus->sem); + res = i2c_read_unlocked(bus, address, data, size); + release_sem(bus->sem); + return res; +} + + +status_t +i2c_write(i2c_bus *bus, int address, const void *data, int size) +{ + status_t res; + acquire_sem(bus->sem); + res = i2c_write_unlocked(bus, address, data, size); + release_sem(bus->sem); + return res; +} + + +status_t +i2c_xfer(i2c_bus *bus, int address, + const void *write_data, int write_size, + void *read_data, int read_size) +{ + status_t res; + + acquire_sem(bus->sem); + + if (write_data != 0 && write_size != 0) { + res = i2c_write_unlocked(bus, address, write_data, write_size); + if (res != B_OK) { + release_sem(bus->sem); + return res; + } + } + + if (read_data != 0 && read_size != 0) { + res = i2c_read_unlocked(bus, address, read_data, read_size); + if (res != B_OK) { + release_sem(bus->sem); + return res; + } + } + + release_sem(bus->sem); + + return B_OK; +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.h b/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.h new file mode 100644 index 0000000000..1189fb0940 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/i2c_core.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __I2C_CORE_H +#define __I2C_CORE_H + +#include + +typedef void (*i2c_set_scl)(void *cookie, int state); +typedef void (*i2c_set_sda)(void *cookie, int state); +typedef int (*i2c_get_scl)(void *cookie); +typedef int (*i2c_get_sda)(void *cookie); + +struct _i2c_bus; +typedef struct _i2c_bus i2c_bus; + +i2c_bus *i2c_create_bus(void *cookie, + int freqency, + bigtime_t timeout, + i2c_set_scl set_scl, + i2c_set_sda set_sda, + i2c_get_scl get_scl, + i2c_get_sda get_sda); + +void i2c_delete_bus(i2c_bus *bus); + +status_t i2c_read(i2c_bus *bus, int address, void *data, int size); +status_t i2c_write(i2c_bus *bus, int address, const void *data, int size); + +status_t i2c_xfer(i2c_bus *bus, int address, + const void *write_data, int write_size, + void *read_data, int read_size); + +#endif diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/util.c b/src/add-ons/kernel/drivers/dvb/cx23882/util.c new file mode 100644 index 0000000000..4b7ad1b9b4 --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/util.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "util.h" + +#define TRACE_UTIL +#ifdef TRACE_UTIL + #define TRACE dprintf +#else + #define TRACE(a...) +#endif + + +area_id +map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name) +{ + uint32 offset; + void *phyadr; + void *mapadr; + area_id area; + + TRACE("mapping physical address %p with %ld bytes for %s\n", phy, size, name); + + offset = (uint32)phy & (B_PAGE_SIZE - 1); + phyadr = (char *)phy - offset; + size = ROUNDUP(size + offset, B_PAGE_SIZE); + area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, protection, &mapadr); + if (area < B_OK) { + TRACE("mapping '%s' failed, error 0x%lx (%s)\n", name, area, strerror(area)); + return area; + } + + *virt = (char *)mapadr + offset; + + TRACE("physical = %p, virtual = %p, offset = %ld, phyadr = %p, mapadr = %p, size = %ld, area = 0x%08lx\n", + phy, *virt, offset, phyadr, mapadr, size, area); + + return area; +} + + +area_id +alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name) +{ + physical_entry pe; + void * virtadr; + area_id areaid; + status_t rv; + + TRACE("allocating %ld bytes for %s\n", size, name); + + size = ROUNDUP(size, B_PAGE_SIZE); + areaid = create_area(name, &virtadr, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK | B_CONTIGUOUS, protection); + if (areaid < B_OK) { + TRACE("couldn't allocate area %s\n", name); + return B_ERROR; + } + rv = get_memory_map(virtadr, size, &pe, 1); + if (rv < B_OK) { + delete_area(areaid); + TRACE("couldn't map %s\n", name); + return B_ERROR; + } + if (virt) + *virt = virtadr; + if (phy) + *phy = pe.address; + TRACE("area = %ld, size = %ld, virt = %p, phy = %p\n", areaid, size, virtadr, pe.address); + return areaid; +} diff --git a/src/add-ons/kernel/drivers/dvb/cx23882/util.h b/src/add-ons/kernel/drivers/dvb/cx23882/util.h new file mode 100644 index 0000000000..8df060ed7c --- /dev/null +++ b/src/add-ons/kernel/drivers/dvb/cx23882/util.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2007 Marcus Overhagen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __UTIL_H +#define __UTIL_H + +#include + +area_id map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name); +area_id alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name); + +// generic macro for rounding, can only be used for power of 2 blocksize +#define ROUNDUP(size, blocksize) (((size) + (blocksize) - 1) & ~((blocksize) - 1)) + +#define atomic_read(a) atomic_or(a, 0) + +#endif