xref: /dragonfly/sys/dev/video/cxm/cxm_eeprom.c (revision cf89a63b)
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