Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / dev / video / cxm / cxm_eeprom.c
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 }