#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <machine/clock.h>
#include <dev/video/cxm/cxm.h>
#include <bus/iicbus/iiconf.h>
#include <bus/iicbus/iicbus.h>
#include "iicbb_if.h"
static int
cxm_eeprom_read(device_t iicbus, int i2c_addr,
char *buf, int len, unsigned int offset)
{
char msg[1];
int received;
int sent;
msg[0] = (unsigned char)offset;
if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
return -1;
if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
|| sent != sizeof(msg))
goto fail;
if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
goto fail;
if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
goto fail;
iicbus_stop(iicbus);
return received;
fail:
iicbus_stop(iicbus);
return -1;
}
int
cxm_eeprom_init(struct cxm_softc *sc)
{
unsigned char eeprom[1];
if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
return -1;
return 0;
}
int
cxm_eeprom_tuner_type(struct cxm_softc *sc)
{
unsigned char eeprom[256];
unsigned int i;
unsigned int len;
unsigned int subsystem_vendor_id;
unsigned int tuner_code;
int tuner_type;
if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
return -1;
subsystem_vendor_id = (unsigned int)eeprom[254] << 8 | eeprom[255];
tuner_type = -1;
switch (subsystem_vendor_id) {
case PCI_VENDOR_HAUPPAUGE:
if (eeprom[0] != 0x84) {
device_printf(sc->dev,
"unknown Hauppauge eeprom format %#x\n",
(unsigned int)eeprom[0]);
break;
}
tuner_code = -1;
for (i = 0; i < sizeof(eeprom); i += len) {
len = 0;
if (eeprom[i] == 0x84) {
len = (unsigned int)eeprom[i + 2] << 8
| eeprom[i + 1];
i += 3;
} else if ((eeprom[i] & 0xf0) == 0x70) {
if (eeprom[i] & 0x08)
break;
len = eeprom[i] & 0x07;
i++;
} else {
device_printf(sc->dev,
"unknown Hauppauge eeprom packet %#x\n",
(unsigned int)eeprom[i]);
return -1;
}
if (i >= sizeof(eeprom)
|| (i + len) > sizeof(eeprom)) {
device_printf(sc->dev,
"corrupt Hauppauge eeprom packet\n");
return -1;
}
switch (eeprom[i]) {
case 0x00:
tuner_code = eeprom[i + 6];
break;
case 0x0a:
tuner_code = eeprom[i + 2];
break;
default:
break;
}
}
switch (tuner_code) {
case 0x03:
case 0x08:
tuner_type = CXM_TUNER_PHILIPS_FI1216_MK2;
break;
case 0x22:
tuner_type = CXM_TUNER_PHILIPS_FQ1216ME;
break;
case 0x37:
tuner_type = CXM_TUNER_PHILIPS_FQ1216ME_MK3;
break;
case 0x1d:
tuner_type = CXM_TUNER_TEMIC_4006_FH5;
break;
case 0x30:
tuner_type = CXM_TUNER_LG_TPI8PSB11D;
break;
case 0x34:
tuner_type = CXM_TUNER_MICROTUNE_4049_FM5;
break;
case 0x05:
case 0x0a:
tuner_type = CXM_TUNER_PHILIPS_FI1236_MK2;
break;
case 0x1a:
tuner_type = CXM_TUNER_TEMIC_4036_FY5;
break;
case 0x52:
tuner_type = CXM_TUNER_LG_TAPC_H701F;
break;
case 0x55:
tuner_type = CXM_TUNER_TCL_2002N_6A;
break;
case 0x06:
case 0x0b:
tuner_type = CXM_TUNER_PHILIPS_FI1246_MK2;
break;
case 0x23:
tuner_type = CXM_TUNER_TEMIC_4066_FY5;
break;
case 0x10:
case 0x15:
tuner_type = CXM_TUNER_PHILIPS_FM1216;
break;
case 0x39:
tuner_type = CXM_TUNER_PHILIPS_FM1216ME_MK3;
break;
case 0x2a:
tuner_type = CXM_TUNER_TEMIC_4009_FR5;
break;
case 0x2f:
tuner_type = CXM_TUNER_LG_TPI8PSB01N;
break;
case 0x12:
case 0x17:
tuner_type = CXM_TUNER_PHILIPS_FM1236;
break;
case 0x21:
tuner_type = CXM_TUNER_TEMIC_4039_FR5;
break;
case 0x44:
tuner_type = CXM_TUNER_LG_TAPE_H001F;
break;
case 0x13:
case 0x18:
tuner_type = CXM_TUNER_PHILIPS_FM1246;
break;
default:
device_printf(sc->dev, "unknown tuner code %#x\n",
tuner_code);
break;
}
break;
default:
device_printf(sc->dev, "unknown subsystem vendor id %#x\n",
subsystem_vendor_id);
break;
}
return tuner_type;
}