1 /* 2 * Copyright (c) 2003, 2004, 2005 3 * John Wehle <john@feith.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Wehle. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * EEPROM routines for the Conexant MPEG-2 Codec driver. 34 * 35 * Ideally these routines should be implemented as a separate 36 * driver which has a generic EEPROM interface so that it's 37 * not necessary for each multimedia driver to re-invent the 38 * wheel. 39 */ 40 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/conf.h> 45 #include <sys/uio.h> 46 #include <sys/kernel.h> 47 #include <sys/poll.h> 48 #include <sys/select.h> 49 #include <sys/resource.h> 50 #include <sys/bus.h> 51 #include <sys/rman.h> 52 53 54 #include <machine/clock.h> 55 56 #include <dev/video/cxm/cxm.h> 57 58 #include <bus/iicbus/iiconf.h> 59 #include <bus/iicbus/iicbus.h> 60 61 #include "iicbb_if.h" 62 63 64 static int 65 cxm_eeprom_read(device_t iicbus, int i2c_addr, 66 char *buf, int len, unsigned int offset) 67 { 68 char msg[1]; 69 int received; 70 int sent; 71 72 msg[0] = (unsigned char)offset; 73 74 if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) 75 return -1; 76 77 if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 78 || sent != sizeof(msg)) 79 goto fail; 80 81 if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) 82 goto fail; 83 84 if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) 85 goto fail; 86 87 iicbus_stop(iicbus); 88 89 return received; 90 91 fail: 92 iicbus_stop(iicbus); 93 return -1; 94 } 95 96 97 int 98 cxm_eeprom_init(struct cxm_softc *sc) 99 { 100 unsigned char eeprom[1]; 101 102 if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM, 103 eeprom, sizeof(eeprom), 0) != sizeof(eeprom)) 104 return -1; 105 106 return 0; 107 } 108 109 110 int 111 cxm_eeprom_tuner_type(struct cxm_softc *sc) 112 { 113 unsigned char eeprom[256]; 114 unsigned int i; 115 unsigned int len; 116 unsigned int subsystem_vendor_id; 117 unsigned int tuner_code; 118 int tuner_type; 119 120 if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM, 121 eeprom, sizeof(eeprom), 0) != sizeof(eeprom)) 122 return -1; 123 124 subsystem_vendor_id = (unsigned int)eeprom[254] << 8 | eeprom[255]; 125 tuner_type = -1; 126 127 switch (subsystem_vendor_id) { 128 case PCI_VENDOR_HAUPPAUGE: 129 130 /* 131 * The Hauppauge eeprom format is tagged. 132 */ 133 134 if (eeprom[0] != 0x84) { 135 device_printf(sc->dev, 136 "unknown Hauppauge eeprom format %#x\n", 137 (unsigned int)eeprom[0]); 138 break; 139 } 140 141 tuner_code = -1; 142 143 for (i = 0; i < sizeof(eeprom); i += len) { 144 len = 0; 145 if (eeprom[i] == 0x84) { 146 len = (unsigned int)eeprom[i + 2] << 8 147 | eeprom[i + 1]; 148 i += 3; 149 } else if ((eeprom[i] & 0xf0) == 0x70) { 150 if (eeprom[i] & 0x08) 151 break; 152 len = eeprom[i] & 0x07; 153 i++; 154 } else { 155 device_printf(sc->dev, 156 "unknown Hauppauge eeprom packet %#x\n", 157 (unsigned int)eeprom[i]); 158 return -1; 159 } 160 161 if (i >= sizeof(eeprom) 162 || (i + len) > sizeof(eeprom)) { 163 device_printf(sc->dev, 164 "corrupt Hauppauge eeprom packet\n"); 165 return -1; 166 } 167 168 switch (eeprom[i]) { 169 case 0x00: 170 tuner_code = eeprom[i + 6]; 171 break; 172 173 case 0x0a: 174 tuner_code = eeprom[i + 2]; 175 break; 176 177 default: 178 break; 179 } 180 } 181 182 switch (tuner_code) { 183 case 0x03: /* Philips FI1216 */ 184 case 0x08: /* Philips FI1216 MK2 */ 185 tuner_type = CXM_TUNER_PHILIPS_FI1216_MK2; 186 break; 187 188 case 0x22: /* Philips FQ1216ME */ 189 tuner_type = CXM_TUNER_PHILIPS_FQ1216ME; 190 break; 191 192 case 0x37: /* Philips FQ1216ME MK3 */ 193 tuner_type = CXM_TUNER_PHILIPS_FQ1216ME_MK3; 194 break; 195 196 case 0x1d: /* Temic 4006FH5 */ 197 tuner_type = CXM_TUNER_TEMIC_4006_FH5; 198 break; 199 200 case 0x30: /* LG Innotek TPI8PSB11D */ 201 tuner_type = CXM_TUNER_LG_TPI8PSB11D; 202 break; 203 204 case 0x34: /* Microtune 4049FM5 */ 205 tuner_type = CXM_TUNER_MICROTUNE_4049_FM5; 206 break; 207 208 case 0x05: /* Philips FI1236 */ 209 case 0x0a: /* Philips FI1236 MK2 */ 210 tuner_type = CXM_TUNER_PHILIPS_FI1236_MK2; 211 break; 212 213 case 0x1a: /* Temic 4036FY5 */ 214 tuner_type = CXM_TUNER_TEMIC_4036_FY5; 215 break; 216 217 case 0x52: /* LG Innotek TAPC-H701F */ 218 tuner_type = CXM_TUNER_LG_TAPC_H701F; 219 break; 220 221 case 0x55: /* TCL 2002N-6A */ 222 tuner_type = CXM_TUNER_TCL_2002N_6A; 223 break; 224 225 case 0x06: /* Philips FI1246 */ 226 case 0x0b: /* Philips FI1246 MK2 */ 227 tuner_type = CXM_TUNER_PHILIPS_FI1246_MK2; 228 break; 229 230 case 0x23: /* Temic 4066FY5 */ 231 tuner_type = CXM_TUNER_TEMIC_4066_FY5; 232 break; 233 234 case 0x10: /* Philips FR1216 MK2 */ 235 case 0x15: /* Philips FM1216 */ 236 tuner_type = CXM_TUNER_PHILIPS_FM1216; 237 break; 238 239 case 0x39: /* Philips FM1216ME MK3 */ 240 tuner_type = CXM_TUNER_PHILIPS_FM1216ME_MK3; 241 break; 242 243 case 0x2a: /* Temic 4009FR5 */ 244 tuner_type = CXM_TUNER_TEMIC_4009_FR5; 245 break; 246 247 case 0x2f: /* LG Innotek TPI8PSB01N */ 248 tuner_type = CXM_TUNER_LG_TPI8PSB01N; 249 break; 250 251 case 0x12: /* Philips FR1236 MK2 */ 252 case 0x17: /* Philips FM1236 */ 253 tuner_type = CXM_TUNER_PHILIPS_FM1236; 254 break; 255 256 case 0x21: /* Temic 4039FR5 */ 257 tuner_type = CXM_TUNER_TEMIC_4039_FR5; 258 break; 259 260 case 0x44: /* LG Innotek TAPE-H001F */ 261 tuner_type = CXM_TUNER_LG_TAPE_H001F; 262 break; 263 264 case 0x13: /* Philips FR1246 MK2 */ 265 case 0x18: /* Philips FM1246 */ 266 tuner_type = CXM_TUNER_PHILIPS_FM1246; 267 break; 268 269 default: 270 device_printf(sc->dev, "unknown tuner code %#x\n", 271 tuner_code); 272 break; 273 } 274 break; 275 276 default: 277 device_printf(sc->dev, "unknown subsystem vendor id %#x\n", 278 subsystem_vendor_id); 279 break; 280 } 281 282 return tuner_type; 283 } 284