blob: 48b2d46048ab36ace21716c141e2aa817daf6bbb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * i2c tv tuner chip device driver
4 * core core, i.e. kernel interfaces, registering and so on
5 */
6
7#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/string.h>
10#include <linux/timer.h>
11#include <linux/delay.h>
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/poll.h>
15#include <linux/i2c.h>
16#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/init.h>
Michael Krufkyffbb8072007-08-21 01:14:12 -030018#include <linux/videodev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <media/tuner.h>
Michael Krufky4adad282007-08-27 21:59:08 -030020#include <media/tuner-types.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020021#include <media/v4l2-common.h>
Michael Krufky8218b0b2007-06-26 13:12:08 -030022#include "tuner-driver.h"
Michael Krufky96c0b7c2007-08-27 21:23:08 -030023#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030024#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030025#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030026#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030027#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030028#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030029#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#define UNSET (-1U)
32
Michael Krufky241020d2007-10-30 09:46:10 -030033#define PREFIX "tuner "
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* standard i2c insmod options */
36static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030037#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030038 0x10,
39#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080040 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070041 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
42 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 I2C_CLIENT_END
44};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046I2C_CLIENT_INSMOD;
47
48/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070049static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070050static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070051static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070052
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/* insmod options used at runtime => read/write */
Hans Verkuilf9195de2006-01-11 19:01:01 -020054int tuner_debug = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070056static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static unsigned int radio_range[2] = { 65, 108 };
58
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020059static char pal[] = "--";
60static char secam[] = "--";
61static char ntsc[] = "-";
62
Hans Verkuilf9195de2006-01-11 19:01:01 -020063
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020064module_param(addr, int, 0444);
65module_param(no_autodetect, int, 0444);
66module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020067module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020068module_param_string(pal, pal, sizeof(pal), 0644);
69module_param_string(secam, secam, sizeof(secam), 0644);
70module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070071module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072module_param_array(radio_range, int, NULL, 0644);
73
74MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
75MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
76MODULE_LICENSE("GPL");
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static struct i2c_driver driver;
79static struct i2c_client client_template;
80
81/* ---------------------------------------------------------------------- */
82
Michael Krufky4e9154b2007-10-21 19:39:50 -030083static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq)
Michael Krufkye18f9442007-08-21 01:25:48 -030084{
Michael Krufky4e9154b2007-10-21 19:39:50 -030085 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
86 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -030087
88 struct analog_parameters params = {
89 .frequency = freq,
90 .mode = t->mode,
91 .audmode = t->audmode,
92 .std = t->std
93 };
94
95 if (NULL == fe_tuner_ops->set_analog_params) {
96 tuner_warn("Tuner frontend module has no way to set freq\n");
97 return;
98 }
Michael Krufky4e9154b2007-10-21 19:39:50 -030099 fe_tuner_ops->set_analog_params(fe, &params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300100}
101
Michael Krufky4e9154b2007-10-21 19:39:50 -0300102static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300103{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300104 if (fe->ops.tuner_ops.release)
105 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300106
Michael Krufky4e9154b2007-10-21 19:39:50 -0300107 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300108
109 /* DO NOT kfree(fe->analog_demod_priv)
110 *
111 * If we are in this function, analog_demod_priv contains a pointer
112 * to struct tuner *t. This will be kfree'd in tuner_detach().
113 *
114 * Otherwise, fe->ops.analog_demod_ops->release will
115 * handle the cleanup for analog demodulator modules.
116 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300117 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300118}
119
Michael Krufky4e9154b2007-10-21 19:39:50 -0300120static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300121{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300122 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300123
124 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300125 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300126}
127
Michael Krufky4e9154b2007-10-21 19:39:50 -0300128static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300129{
Michael Krufky14196832007-10-14 18:11:53 -0300130 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300131
Michael Krufky4e9154b2007-10-21 19:39:50 -0300132 if (fe->ops.tuner_ops.get_rf_strength)
133 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300134
135 return strength;
136}
137
Michael Krufky4e9154b2007-10-21 19:39:50 -0300138static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300139
140static struct analog_tuner_ops tuner_core_ops = {
141 .set_tv_freq = fe_set_freq,
142 .set_radio_freq = fe_set_freq,
143 .standby = fe_standby,
144 .release = fe_release,
145 .has_signal = fe_has_signal,
146 .tuner_status = tuner_status
147};
148
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700149/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void set_tv_freq(struct i2c_client *c, unsigned int freq)
151{
152 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300153 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700156 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 return;
158 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300159 if ((NULL == ops) || (NULL == ops->set_tv_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700160 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return;
162 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700163 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
164 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
165 freq / 16, freq % 16 * 100 / 16, tv_range[0],
166 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200167 /* V4L2 spec: if the freq is not possible then the closest
168 possible value should be selected */
169 if (freq < tv_range[0] * 16)
170 freq = tv_range[0] * 16;
171 else
172 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Michael Krufky4e9154b2007-10-21 19:39:50 -0300174 ops->set_tv_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177static void set_radio_freq(struct i2c_client *c, unsigned int freq)
178{
179 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300180 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700183 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 return;
185 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300186 if ((NULL == ops) || (NULL == ops->set_radio_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700187 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return;
189 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200190 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700191 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
192 freq / 16000, freq % 16000 * 100 / 16000,
193 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200194 /* V4L2 spec: if the freq is not possible then the closest
195 possible value should be selected */
196 if (freq < radio_range[0] * 16000)
197 freq = radio_range[0] * 16000;
198 else
199 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700201
Michael Krufky4e9154b2007-10-21 19:39:50 -0300202 ops->set_radio_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205static void set_freq(struct i2c_client *c, unsigned long freq)
206{
207 struct tuner *t = i2c_get_clientdata(c);
208
209 switch (t->mode) {
210 case V4L2_TUNER_RADIO:
211 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700212 freq / 16000, freq % 16000 * 100 / 16000);
213 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200214 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 break;
216 case V4L2_TUNER_ANALOG_TV:
217 case V4L2_TUNER_DIGITAL_TV:
218 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700219 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200221 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300223 default:
224 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Michael Krufky293197c2007-08-28 17:20:42 -0300228static void tuner_i2c_address_check(struct tuner *t)
229{
230 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300231 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300232 return;
233
234 tuner_warn("====================== WARNING! ======================\n");
235 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
236 tuner_warn("will soon be dropped. This message indicates that your\n");
237 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300238 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300239 tuner_warn("To ensure continued support for your device, please\n");
240 tuner_warn("send a copy of this message, along with full dmesg\n");
241 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
242 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
243 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300244 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300245 tuners[t->type].name);
246 tuner_warn("====================== WARNING! ======================\n");
247}
248
Michael Krufky4adad282007-08-27 21:59:08 -0300249static void attach_simple_tuner(struct tuner *t)
250{
251 struct simple_tuner_config cfg = {
252 .type = t->type,
253 .tun = &tuners[t->type]
254 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300255 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300256}
257
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700258static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300259 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300260 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
262 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300263 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300264 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700265 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700267 if (type == UNSET || type == TUNER_ABSENT) {
268 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700272 if (type >= tuner_count) {
273 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
274 return;
275 }
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300278 t->config = new_config;
279 if (tuner_callback != NULL) {
280 tuner_dbg("defining GPIO callback\n");
281 t->tuner_callback = tuner_callback;
282 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300283
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300284 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300285 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
286
287 return;
288 }
289
Michael Krufkyb2083192007-05-29 22:54:06 -0300290 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300291 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300292 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 switch (t->type) {
295 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300296 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 break;
298 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300299 {
Michael Krufky8c125f2c2007-10-27 02:00:57 -0300300 tda829x_attach(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300301 break;
302 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700303 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300304 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700305 t->type = TUNER_ABSENT;
306 t->mode_mask = T_UNINITIALIZED;
307 return;
308 }
309 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700310 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300311 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300312 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300313 t->type = TUNER_ABSENT;
314 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300315 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300316 }
317 t->mode_mask = T_RADIO;
318 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700319 case TUNER_PHILIPS_FMD1216ME_MK3:
320 buffer[0] = 0x0b;
321 buffer[1] = 0xdc;
322 buffer[2] = 0x9c;
323 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700324 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700325 mdelay(1);
326 buffer[2] = 0x86;
327 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700328 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300329 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700330 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800331 case TUNER_PHILIPS_TD1316:
332 buffer[0] = 0x0b;
333 buffer[1] = 0xdc;
334 buffer[2] = 0x86;
335 buffer[3] = 0xa4;
336 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300337 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200338 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300339 case TUNER_XC2028:
340 {
341 int rc=xc2028_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
342 &c->dev, c->adapter->algo_data,
343 t->tuner_callback);
344 if (rc<0) {
345 t->type = TUNER_ABSENT;
346 t->mode_mask = T_UNINITIALIZED;
347 return;
348 }
349 break;
350 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300351 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300352 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300355 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 break;
357 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700358
Michael Krufkye2be32a2007-10-21 14:35:21 -0300359 ops = t->fe.ops.analog_demod_ops;
360
Michael Krufky1dde7a42007-10-21 13:40:56 -0300361 if (((NULL == ops) ||
362 ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) &&
363 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300364 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
365 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300366
Michael Krufky1dde7a42007-10-21 13:40:56 -0300367 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300368 t->fe.analog_demod_priv = t;
Michael Krufkye18f9442007-08-21 01:25:48 -0300369 }
370
Michael Krufky49427442007-10-30 09:44:12 -0300371 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300372
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700373 if (t->mode_mask == T_UNINITIALIZED)
374 t->mode_mask = new_mode_mask;
375
Hans Verkuil27487d42006-01-15 15:04:52 -0200376 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700377 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100378 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700379 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300380 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700383/*
384 * This function apply tuner config to tuner specified
385 * by tun_setup structure. I addr is unset, then admin status
386 * and tun addr status is more precise then current status,
387 * it's applied. Otherwise status and type are applied only to
388 * tuner with exactly the same addr.
389*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700390
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700391static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700392{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700393 struct tuner *t = i2c_get_clientdata(c);
394
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300395 tuner_dbg("set addr for type %i\n", t->type);
396
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300397 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
398 (t->mode_mask & tun_setup->mode_mask))) ||
399 (tun_setup->addr == c->addr)) {
400 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300401 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700402 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700403}
404
405static inline int check_mode(struct tuner *t, char *cmd)
406{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700407 if ((1 << t->mode & t->mode_mask) == 0) {
408 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700409 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700410
411 switch (t->mode) {
412 case V4L2_TUNER_RADIO:
413 tuner_dbg("Cmd %s accepted for radio\n", cmd);
414 break;
415 case V4L2_TUNER_ANALOG_TV:
416 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
417 break;
418 case V4L2_TUNER_DIGITAL_TV:
419 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
420 break;
421 }
422 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700423}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700424
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700425/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426static int tuner_fixup_std(struct tuner *t)
427{
428 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300430 case '6':
431 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
432 t->std = V4L2_STD_PAL_60;
433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 case 'b':
435 case 'B':
436 case 'g':
437 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700438 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 t->std = V4L2_STD_PAL_BG;
440 break;
441 case 'i':
442 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700443 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 t->std = V4L2_STD_PAL_I;
445 break;
446 case 'd':
447 case 'D':
448 case 'k':
449 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700450 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 t->std = V4L2_STD_PAL_DK;
452 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700453 case 'M':
454 case 'm':
455 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
456 t->std = V4L2_STD_PAL_M;
457 break;
458 case 'N':
459 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200460 if (pal[1] == 'c' || pal[1] == 'C') {
461 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
462 t->std = V4L2_STD_PAL_Nc;
463 } else {
464 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
465 t->std = V4L2_STD_PAL_N;
466 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700467 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700468 case '-':
469 /* default parameter, do nothing */
470 break;
471 default:
472 tuner_warn ("pal= argument not recognised\n");
473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
475 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700476 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
477 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200478 case 'b':
479 case 'B':
480 case 'g':
481 case 'G':
482 case 'h':
483 case 'H':
484 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
485 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
486 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700487 case 'd':
488 case 'D':
489 case 'k':
490 case 'K':
491 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
492 t->std = V4L2_STD_SECAM_DK;
493 break;
494 case 'l':
495 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800496 if ((secam[1]=='C')||(secam[1]=='c')) {
497 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
498 t->std = V4L2_STD_SECAM_LC;
499 } else {
500 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
501 t->std = V4L2_STD_SECAM_L;
502 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700503 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700504 case '-':
505 /* default parameter, do nothing */
506 break;
507 default:
508 tuner_warn ("secam= argument not recognised\n");
509 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700510 }
511 }
512
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200513 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
514 switch (ntsc[0]) {
515 case 'm':
516 case 'M':
517 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
518 t->std = V4L2_STD_NTSC_M;
519 break;
520 case 'j':
521 case 'J':
522 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
523 t->std = V4L2_STD_NTSC_M_JP;
524 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200525 case 'k':
526 case 'K':
527 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
528 t->std = V4L2_STD_NTSC_M_KR;
529 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200530 case '-':
531 /* default parameter, do nothing */
532 break;
533 default:
534 tuner_info("ntsc= argument not recognised\n");
535 break;
536 }
537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return 0;
539}
540
Michael Krufky4e9154b2007-10-21 19:39:50 -0300541static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200542{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300543 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200544 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300545 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300546 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200547 const char *p;
548
549 switch (t->mode) {
550 case V4L2_TUNER_RADIO: p = "radio"; break;
551 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
552 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
553 default: p = "undefined"; break;
554 }
555 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200556 freq = t->radio_freq / 16000;
557 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200558 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200559 freq = t->tv_freq / 16;
560 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200561 }
562 tuner_info("Tuner mode: %s\n", p);
563 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300564 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200565 if (t->mode != V4L2_TUNER_RADIO)
566 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300567 if (fe_tuner_ops->get_status) {
568 u32 tuner_status;
569
570 fe_tuner_ops->get_status(&t->fe, &tuner_status);
571 if (tuner_status & TUNER_STATUS_LOCKED)
572 tuner_info("Tuner is locked.\n");
573 if (tuner_status & TUNER_STATUS_STEREO)
574 tuner_info("Stereo: yes\n");
575 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300576 if (ops) {
577 if (ops->has_signal)
578 tuner_info("Signal strength: %d\n",
579 ops->has_signal(fe));
580 if (ops->is_stereo)
581 tuner_info("Stereo: %s\n",
582 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200583 }
584}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586/* ---------------------------------------------------------------------- */
587
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700588/*
589 * Switch tuner to other mode. If tuner support both tv and radio,
590 * set another frequency to some value (This is needed for some pal
591 * tuners to avoid locking). Otherwise, just put second tuner in
592 * standby mode.
593 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700595static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
596{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300597 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
598
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800599 if (mode == t->mode)
600 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700601
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800602 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700603
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800604 if (check_mode(t, cmd) == EINVAL) {
605 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300606 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300607 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800608 return EINVAL;
609 }
610 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700611}
612
613#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800614 tuner_dbg("switching to v4l2\n"); \
615 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700616
617static inline int check_v4l2(struct tuner *t)
618{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300619 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
620 TV, v4l1 for radio), until that is fixed this code is disabled.
621 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
622 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700623 return 0;
624}
625
626static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300629 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300630 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Hans Verkuilf9195de2006-01-11 19:01:01 -0200632 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300633 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200634
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700635 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700637 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300638 tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700639 ((struct tuner_setup *)arg)->type,
640 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300641 ((struct tuner_setup *)arg)->mode_mask,
642 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700643
644 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700645 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200647 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
648 == EINVAL)
649 return 0;
650 if (t->radio_freq)
651 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700653 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200654 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
655 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300656 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300657 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300658 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200659 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300660#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700661 case VIDIOCSAUDIO:
662 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
663 return 0;
664 if (check_v4l2(t) == EINVAL)
665 return 0;
666
667 /* Should be implemented, since bttv calls it */
668 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700671 {
672 static const v4l2_std_id map[] = {
673 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
674 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
675 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
676 [4 /* bttv */ ] = V4L2_STD_PAL_M,
677 [5 /* bttv */ ] = V4L2_STD_PAL_N,
678 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
679 };
680 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700682 if (check_v4l2(t) == EINVAL)
683 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700684
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700685 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700688 if (vc->norm < ARRAY_SIZE(map))
689 t->std = map[vc->norm];
690 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200691 if (t->tv_freq)
692 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700693 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700694 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700695 case VIDIOCSFREQ:
696 {
697 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700698
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700699 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
700 return 0;
701 if (check_v4l2(t) == EINVAL)
702 return 0;
703
704 set_freq(client, *v);
705 return 0;
706 }
707 case VIDIOCGTUNER:
708 {
709 struct video_tuner *vt = arg;
710
711 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
712 return 0;
713 if (check_v4l2(t) == EINVAL)
714 return 0;
715
716 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300717 if (fe_tuner_ops->get_status) {
718 u32 tuner_status;
719
720 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300721 if (tuner_status & TUNER_STATUS_STEREO)
722 vt->flags |= VIDEO_TUNER_STEREO_ON;
723 else
724 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300725 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300726 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300727 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300728 vt->flags |=
729 VIDEO_TUNER_STEREO_ON;
730 else
731 vt->flags &=
732 ~VIDEO_TUNER_STEREO_ON;
733 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700734 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300735 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300736 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300737
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700738 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
739
740 vt->rangelow = radio_range[0] * 16000;
741 vt->rangehigh = radio_range[1] * 16000;
742
743 } else {
744 vt->rangelow = tv_range[0] * 16;
745 vt->rangehigh = tv_range[1] * 16;
746 }
747
748 return 0;
749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700751 {
752 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700754 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
755 return 0;
756 if (check_v4l2(t) == EINVAL)
757 return 0;
758
Michael Krufkye18f9442007-08-21 01:25:48 -0300759 if (V4L2_TUNER_RADIO == t->mode) {
760 if (fe_tuner_ops->get_status) {
761 u32 tuner_status;
762
763 fe_tuner_ops->get_status(&t->fe, &tuner_status);
764 va->mode = (tuner_status & TUNER_STATUS_STEREO)
765 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300766 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300767 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300768 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
769 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700770 return 0;
771 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300772#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300773 case TUNER_SET_CONFIG:
774 {
775 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
776 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300778 if (t->type != cfg->tuner)
779 break;
780
781 if (t->type == TUNER_TDA9887) {
782 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300783 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300784 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300785 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300786
787 if (NULL == fe_tuner_ops->set_config) {
788 tuner_warn("Tuner frontend module has no way to "
789 "set config\n");
790 break;
791 }
792 fe_tuner_ops->set_config(&t->fe, cfg->priv);
793
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300794 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300795 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300796 /* --- v4l ioctls --- */
797 /* take care: bttv does userspace copying, we'll get a
798 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700800 {
801 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700803 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
804 == EINVAL)
805 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700806
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700807 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700809 t->std = *id;
810 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200811 if (t->tv_freq)
812 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700813 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700814 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700815 case VIDIOC_S_FREQUENCY:
816 {
817 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700818
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300819 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
820 == EINVAL)
821 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700822 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200823 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700824
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700825 break;
826 }
827 case VIDIOC_G_FREQUENCY:
828 {
829 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700830
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700831 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
832 return 0;
833 switch_v4l2();
834 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300835 if (fe_tuner_ops->get_frequency) {
836 u32 abs_freq;
837
838 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
839 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
840 (abs_freq * 2 + 125/2) / 125 :
841 (abs_freq + 62500/2) / 62500;
842 break;
843 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200844 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
845 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700846 break;
847 }
848 case VIDIOC_G_TUNER:
849 {
850 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700851
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700852 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
853 return 0;
854 switch_v4l2();
855
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200856 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300857 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300858 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300859 if (t->mode == V4L2_TUNER_ANALOG_TV)
860 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200861 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700862 tuner->rangelow = tv_range[0] * 16;
863 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200864 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700865 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200866
867 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200868 tuner->rxsubchans =
869 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300870 if (fe_tuner_ops->get_status) {
871 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200872
Michael Krufkye18f9442007-08-21 01:25:48 -0300873 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300874 tuner->rxsubchans =
875 (tuner_status & TUNER_STATUS_STEREO) ?
876 V4L2_TUNER_SUB_STEREO :
877 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300878 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300879 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300880 tuner->rxsubchans =
881 ops->is_stereo(&t->fe) ?
882 V4L2_TUNER_SUB_STEREO :
883 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300884 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300885 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300886 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300887 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200888 tuner->capability |=
889 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
890 tuner->audmode = t->audmode;
891 tuner->rangelow = radio_range[0] * 16000;
892 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700893 break;
894 }
895 case VIDIOC_S_TUNER:
896 {
897 struct v4l2_tuner *tuner = arg;
898
899 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
900 return 0;
901
902 switch_v4l2();
903
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200904 /* do nothing unless we're a radio tuner */
905 if (t->mode != V4L2_TUNER_RADIO)
906 break;
907 t->audmode = tuner->audmode;
908 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700909 break;
910 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200911 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300912 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300913 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200914 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916
917 return 0;
918}
919
Jean Delvare21b48a72007-03-12 19:20:15 -0300920static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700922 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700924 tuner_dbg ("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 /* FIXME: power down ??? */
926 return 0;
927}
928
Jean Delvare21b48a72007-03-12 19:20:15 -0300929static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700931 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700933 tuner_dbg ("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -0200934 if (V4L2_TUNER_RADIO == t->mode) {
935 if (t->radio_freq)
936 set_freq(c, t->radio_freq);
937 } else {
938 if (t->tv_freq)
939 set_freq(c, t->tv_freq);
940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 return 0;
942}
943
Hans Verkuil92de1f12007-11-04 10:53:09 -0300944/* ---------------------------------------------------------------------- */
945
946LIST_HEAD(tuner_list);
947
948/* Search for existing radio and/or TV tuners on the given I2C adapter.
949 Note that when this function is called from tuner_attach you can be
950 certain no other devices will be added/deleted at the same time, I2C
951 core protects against that. */
952static void tuner_lookup(struct i2c_adapter *adap,
953 struct tuner **radio, struct tuner **tv)
954{
955 struct tuner *pos;
956
957 *radio = NULL;
958 *tv = NULL;
959
960 list_for_each_entry(pos, &tuner_list, list) {
961 int mode_mask;
962
963 if (pos->i2c->adapter != adap ||
964 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
965 continue;
966
967 mode_mask = pos->mode_mask & ~T_STANDBY;
968 if (*radio == NULL && mode_mask == T_RADIO)
969 *radio = pos;
970 /* Note: currently TDA9887 is the only demod-only
971 device. If other devices appear then we need to
972 make this test more general. */
973 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
974 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
975 *tv = pos;
976 }
977}
978
979/* During client attach, set_type is called by adapter's attach_inform callback.
980 set_type must then be completed by tuner_attach.
981 */
982static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
983{
984 struct i2c_client *client;
985 struct tuner *t;
986 struct tuner *radio;
987 struct tuner *tv;
988
989 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
990 if (NULL == client)
991 return -ENOMEM;
992
993 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
994 if (NULL == t) {
995 kfree(client);
996 return -ENOMEM;
997 }
998 t->i2c = client;
999 client_template.adapter = adap;
1000 client_template.addr = addr;
1001 memcpy(client, &client_template, sizeof(struct i2c_client));
1002 i2c_set_clientdata(client, t);
1003 t->type = UNSET;
1004 t->audmode = V4L2_TUNER_MODE_STEREO;
1005 t->mode_mask = T_UNINITIALIZED;
1006
1007 if (show_i2c) {
1008 unsigned char buffer[16];
1009 int i, rc;
1010
1011 memset(buffer, 0, sizeof(buffer));
1012 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1013 tuner_info("I2C RECV = ");
1014 for (i = 0; i < rc; i++)
1015 printk(KERN_CONT "%02x ", buffer[i]);
1016 printk("\n");
1017 }
1018 /* HACK: This test were added to avoid tuner to probe tda9840 and
1019 tea6415c on the MXB card */
1020 if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
1021 return -ENODEV;
1022
1023 /* autodetection code based on the i2c addr */
1024 if (!no_autodetect) {
1025 switch (addr) {
1026 case 0x10:
1027 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1028 != EINVAL) {
1029 t->type = TUNER_TEA5761;
1030 t->mode_mask = T_RADIO;
1031 t->mode = T_STANDBY;
1032 /* Sets freq to FM range */
1033 t->radio_freq = 87.5 * 16000;
1034 tuner_lookup(t->i2c->adapter, &radio, &tv);
1035 if (tv)
1036 tv->mode_mask &= ~T_RADIO;
1037
1038 goto register_client;
1039 }
1040 break;
1041 case 0x42:
1042 case 0x43:
1043 case 0x4a:
1044 case 0x4b:
1045 /* If chip is not tda8290, don't register.
1046 since it can be tda9887*/
1047 if (tda829x_probe(t) == 0) {
1048 tuner_dbg("tda829x detected\n");
1049 } else {
1050 /* Default is being tda9887 */
1051 t->type = TUNER_TDA9887;
1052 t->mode_mask = T_RADIO | T_ANALOG_TV |
1053 T_DIGITAL_TV;
1054 t->mode = T_STANDBY;
1055 goto register_client;
1056 }
1057 break;
1058 case 0x60:
1059 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1060 != EINVAL) {
1061 t->type = TUNER_TEA5767;
1062 t->mode_mask = T_RADIO;
1063 t->mode = T_STANDBY;
1064 /* Sets freq to FM range */
1065 t->radio_freq = 87.5 * 16000;
1066 tuner_lookup(t->i2c->adapter, &radio, &tv);
1067 if (tv)
1068 tv->mode_mask &= ~T_RADIO;
1069
1070 goto register_client;
1071 }
1072 break;
1073 }
1074 }
1075
1076 /* Initializes only the first TV tuner on this adapter. Why only the
1077 first? Because there are some devices (notably the ones with TI
1078 tuners) that have more than one i2c address for the *same* device.
1079 Experience shows that, except for just one case, the first
1080 address is the right one. The exception is a Russian tuner
1081 (ACORP_Y878F). So, the desired behavior is just to enable the
1082 first found TV tuner. */
1083 tuner_lookup(t->i2c->adapter, &radio, &tv);
1084 if (tv == NULL) {
1085 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1086 if (radio == NULL)
1087 t->mode_mask |= T_RADIO;
1088 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1089 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1090 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1091 }
1092
1093 /* Should be just before return */
1094register_client:
1095 tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
1096
1097 /* Sets a default mode */
1098 if (t->mode_mask & T_ANALOG_TV) {
1099 t->mode = T_ANALOG_TV;
1100 } else if (t->mode_mask & T_RADIO) {
1101 t->mode = T_RADIO;
1102 } else {
1103 t->mode = T_DIGITAL_TV;
1104 }
1105
1106 i2c_attach_client(client);
1107 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
1108 return 0;
1109}
1110
1111static int tuner_probe(struct i2c_adapter *adap)
1112{
1113 if (0 != addr) {
1114 normal_i2c[0] = addr;
1115 normal_i2c[1] = I2C_CLIENT_END;
1116 }
1117
1118 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1119 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1120 * and an RTC at 0x6f which can get corrupted if probed.
1121 */
1122 if ((adap->id == I2C_HW_B_CX2388x) ||
1123 (adap->id == I2C_HW_B_CX23885)) {
1124 unsigned int i = 0;
1125
1126 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1127 i += 2;
1128 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1129 ignore[i+0] = adap->nr;
1130 ignore[i+1] = 0x6b;
1131 ignore[i+2] = adap->nr;
1132 ignore[i+3] = 0x6f;
1133 ignore[i+4] = I2C_CLIENT_END;
1134 } else
1135 printk(KERN_WARNING "tuner: "
1136 "too many options specified "
1137 "in i2c probe ignore list!\n");
1138 }
1139
1140 if (adap->class & I2C_CLASS_TV_ANALOG)
1141 return i2c_probe(adap, &addr_data, tuner_attach);
1142 return 0;
1143}
1144
1145static int tuner_detach(struct i2c_client *client)
1146{
1147 struct tuner *t = i2c_get_clientdata(client);
1148 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
1149 int err;
1150
1151 err = i2c_detach_client(t->i2c);
1152 if (err) {
1153 tuner_warn
1154 ("Client deregistration failed, client not detached.\n");
1155 return err;
1156 }
1157
1158 if (ops && ops->release)
1159 ops->release(&t->fe);
1160
1161 list_del(&t->list);
1162 kfree(t);
1163 kfree(client);
1164 return 0;
1165}
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167/* ----------------------------------------------------------------------- */
1168
1169static struct i2c_driver driver = {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001170 .id = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001171 .attach_adapter = tuner_probe,
1172 .detach_client = tuner_detach,
1173 .command = tuner_command,
Jean Delvare21b48a72007-03-12 19:20:15 -03001174 .suspend = tuner_suspend,
1175 .resume = tuner_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 .driver = {
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001177 .name = "tuner",
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001178 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001180static struct i2c_client client_template = {
Jean Delvarefae91e72005-08-15 19:57:04 +02001181 .name = "(tuner unset)",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001182 .driver = &driver,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183};
1184
1185static int __init tuner_init_module(void)
1186{
1187 return i2c_add_driver(&driver);
1188}
1189
1190static void __exit tuner_cleanup_module(void)
1191{
1192 i2c_del_driver(&driver);
1193}
1194
1195module_init(tuner_init_module);
1196module_exit(tuner_cleanup_module);
1197
1198/*
1199 * Overrides for Emacs so that we follow Linus's tabbing style.
1200 * ---------------------------------------------------------------------------
1201 * Local variables:
1202 * c-basic-offset: 8
1203 * End:
1204 */