⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tuner.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",		buffer[0],buffer[1],buffer[2],buffer[3]);        if (4 != (rc = i2c_master_send(c,buffer,4)))                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);	if (t->type == TUNER_MICROTUNE_4042FI5) {		// FIXME - this may also work for other tuners		unsigned long timeout = jiffies + msecs_to_jiffies(1);		u8 status_byte = 0;		/* Wait until the PLL locks */		for (;;) {			if (time_after(jiffies,timeout))				return;			if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {				dprintk("tuner: i2c i/o read error: rc == %d (should be 1)\n",rc);				break;			}			/* bit 6 is PLL locked indicator */			if (status_byte & 0x40)				break;			udelay(10);		}		/* Set the charge pump for optimized phase noise figure */		tun->config &= ~0x40;		buffer[0] = (div>>8) & 0x7f;		buffer[1] = div      & 0xff;		buffer[2] = tun->config;		buffer[3] = config;		dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",			buffer[0],buffer[1],buffer[2],buffer[3]);		if (4 != (rc = i2c_master_send(c,buffer,4)))			dprintk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);	}}static void default_set_radio_freq(struct i2c_client *c, unsigned int freq){	struct tunertype *tun;	struct tuner *t = i2c_get_clientdata(c);        unsigned char buffer[4];	unsigned div;	int rc;	tun=&tuners[t->type];	div = freq + (int)(16*10.7);	buffer[2] = tun->config;	switch (t->type) {	case TUNER_PHILIPS_FM1216ME_MK3:	case TUNER_PHILIPS_FM1236_MK3:		buffer[3] = 0x19;		break;	case TUNER_PHILIPS_FM1256_IH3:		div = (20 * freq)/16 + 333 * 2;	        buffer[2] = 0x80;		buffer[3] = 0x19;		break;	case TUNER_LG_PAL_FM:		buffer[3] = 0xa5;		break;	default:		buffer[3] = 0xa4;		break;	}        buffer[0] = (div>>8) & 0x7f;        buffer[1] = div      & 0xff;	dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n",		buffer[0],buffer[1],buffer[2],buffer[3]);        if (4 != (rc = i2c_master_send(c,buffer,4)))                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);}/* ---------------------------------------------------------------------- */// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHzstatic void set_tv_freq(struct i2c_client *c, unsigned int freq){	struct tuner *t = i2c_get_clientdata(c);	if (t->type == UNSET) {		printk("tuner: tuner type not set\n");		return;	}	if (NULL == t->tv_freq) {		printk("tuner: Huh? tv_set is NULL?\n");		return;	}	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {		/* FIXME: better do that chip-specific, but		   right now we don't have that in the config		   struct and this way is still better than no		   check at all */		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);		return;	}	t->tv_freq(c,freq);}static void set_radio_freq(struct i2c_client *c, unsigned int freq){	struct tuner *t = i2c_get_clientdata(c);	if (t->type == UNSET) {		printk("tuner: tuner type not set\n");		return;	}	if (NULL == t->radio_freq) {		printk("tuner: no radio tuning for this one, sorry.\n");		return;	}	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",		       freq/16,freq%16*100/16,		       radio_range[0],radio_range[1]);		return;	}	t->radio_freq(c,freq);}static void set_freq(struct i2c_client *c, unsigned long freq){	struct tuner *t = i2c_get_clientdata(c);	switch (t->mode) {	case V4L2_TUNER_RADIO:		dprintk("tuner: radio freq set to %lu.%02lu\n",			freq/16,freq%16*100/16);		set_radio_freq(c,freq);		break;	case V4L2_TUNER_ANALOG_TV:	case V4L2_TUNER_DIGITAL_TV:		dprintk("tuner: tv freq set to %lu.%02lu\n",			freq/16,freq%16*100/16);		set_tv_freq(c, freq);		break;	}	t->freq = freq;}static void set_type(struct i2c_client *c, unsigned int type, char *source){	struct tuner *t = i2c_get_clientdata(c);	if (t->type != UNSET && t->type != TUNER_ABSENT) {		if (t->type != type)			printk("tuner: type already set to %d, "			       "ignoring request for %d\n", t->type, type);		return;	}	if (type >= TUNERS)		return;	t->type = type;	printk("tuner: type set to %d (%s) by %s\n",	       t->type,tuners[t->type].name, source);	strlcpy(c->name, tuners[t->type].name, sizeof(c->name));	switch (t->type) {	case TUNER_MT2032:		microtune_init(c);		break;	default:		t->tv_freq    = default_set_tv_freq;		t->radio_freq = default_set_radio_freq;		break;	}}static char pal[] = "-";module_param_string(pal, pal, 0644, sizeof(pal));static int tuner_fixup_std(struct tuner *t){	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {		/* get more precise norm info from insmod option */		switch (pal[0]) {		case 'b':		case 'B':		case 'g':		case 'G':			dprintk("insmod fixup: PAL => PAL-BG\n");			t->std = V4L2_STD_PAL_BG;			break;		case 'i':		case 'I':			dprintk("insmod fixup: PAL => PAL-I\n");			t->std = V4L2_STD_PAL_I;			break;		case 'd':		case 'D':		case 'k':		case 'K':			dprintk("insmod fixup: PAL => PAL-DK\n");			t->std = V4L2_STD_PAL_DK;			break;		}	}	return 0;}/* ---------------------------------------------------------------------- */static int tuner_attach(struct i2c_adapter *adap, int addr, int kind){	struct tuner *t;	struct i2c_client *client;	if (this_adap > 0)		return -1;	this_adap++;        client_template.adapter = adap;        client_template.addr = addr;        printk("tuner: chip found at addr 0x%x i2c-bus %s\n",	       addr<<1, adap->name);        if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))                return -ENOMEM;        memcpy(client,&client_template,sizeof(struct i2c_client));        t = kmalloc(sizeof(struct tuner),GFP_KERNEL);        if (NULL == t) {                kfree(client);                return -ENOMEM;        }        memset(t,0,sizeof(struct tuner));	i2c_set_clientdata(client, t);	t->type       = UNSET;	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio        i2c_attach_client(client);	if (type < TUNERS) {		set_type(client, type, "insmod option");		printk("tuner: The type=<n> insmod option will go away soon.\n");		printk("tuner: Please use the tuner=<n> option provided by\n");		printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n");	}	return 0;}static int tuner_probe(struct i2c_adapter *adap){	if (0 != addr) {		normal_i2c_range[0] = addr;		normal_i2c_range[1] = addr;	}	this_adap = 0;#ifdef I2C_CLASS_TV_ANALOG	if (adap->class & I2C_CLASS_TV_ANALOG)		return i2c_probe(adap, &addr_data, tuner_attach);#else	switch (adap->id) {	case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:	case I2C_ALGO_BIT | I2C_HW_B_BT848:	case I2C_ALGO_BIT | I2C_HW_B_RIVA:	case I2C_ALGO_SAA7134:	case I2C_ALGO_SAA7146:		return i2c_probe(adap, &addr_data, tuner_attach);		break;	}#endif	return 0;}static int tuner_detach(struct i2c_client *client){	struct tuner *t = i2c_get_clientdata(client);	i2c_detach_client(client);	kfree(t);	kfree(client);	return 0;}#define SWITCH_V4L2	if (!t->using_v4l2 && debug) \		          printk("tuner: switching to v4l2\n"); \	                  t->using_v4l2 = 1;#define CHECK_V4L2	if (t->using_v4l2) { if (debug) \			  printk("tuner: ignore v4l1 call\n"); \		          return 0; }static inttuner_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct tuner *t = i2c_get_clientdata(client);        unsigned int *iarg = (int*)arg;        switch (cmd) {	/* --- configuration --- */	case TUNER_SET_TYPE:		set_type(client,*iarg,client->adapter->name);		break;	case AUDC_SET_RADIO:		if (V4L2_TUNER_RADIO != t->mode) {			set_tv_freq(client,400 * 16);			t->mode = V4L2_TUNER_RADIO;		}		break;	case AUDC_CONFIG_PINNACLE:		switch (*iarg) {		case 2:			dprintk("tuner: pinnacle pal\n");			t->radio_if2 = 33300 * 1000;			break;		case 3:			dprintk("tuner: pinnacle ntsc\n");			t->radio_if2 = 41300 * 1000;			break;		}                break;	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOCSCHAN:	{		static const v4l2_std_id map[] = {			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,		};		struct video_channel *vc = arg;		CHECK_V4L2;		t->mode = V4L2_TUNER_ANALOG_TV;		if (vc->norm < ARRAY_SIZE(map))			t->std = map[vc->norm];		tuner_fixup_std(t);		if (t->freq)			set_tv_freq(client,t->freq);		return 0;	}	case VIDIOCSFREQ:	{		unsigned long *v = arg;		CHECK_V4L2;		set_freq(client,*v);		return 0;	}	case VIDIOCGTUNER:	{		struct video_tuner *vt = arg;		CHECK_V4L2;		if (V4L2_TUNER_RADIO == t->mode)			vt->signal = tuner_signal(client);		return 0;	}	case VIDIOCGAUDIO:	{		struct video_audio *va = arg;		CHECK_V4L2;		if (V4L2_TUNER_RADIO == t->mode)			va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);		return 0;	}	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		SWITCH_V4L2;		t->mode = V4L2_TUNER_ANALOG_TV;		t->std = *id;		tuner_fixup_std(t);		if (t->freq)			set_freq(client,t->freq);		break;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *f = arg;		SWITCH_V4L2;		if (V4L2_TUNER_RADIO == f->type &&		    V4L2_TUNER_RADIO != t->mode)			set_tv_freq(client,400*16);		t->mode  = f->type;		t->freq  = f->frequency;		set_freq(client,t->freq);		break;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *tuner = arg;		SWITCH_V4L2;		if (V4L2_TUNER_RADIO == t->mode)			tuner->signal = tuner_signal(client);		break;	}	default:		/* nothing */		break;	}	return 0;}static int tuner_suspend(struct device * dev, u32 state, u32 level){	dprintk("tuner: suspend\n");	/* FIXME: power down ??? */	return 0;}static int tuner_resume(struct device * dev, u32 level){	struct i2c_client *c = container_of(dev, struct i2c_client, dev);	struct tuner *t = i2c_get_clientdata(c);	dprintk("tuner: resume\n");	if (t->freq)		set_freq(c,t->freq);	return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver driver = {	.owner          = THIS_MODULE,        .name           = "i2c TV tuner driver",        .id             = I2C_DRIVERID_TUNER,        .flags          = I2C_DF_NOTIFY,        .attach_adapter = tuner_probe,        .detach_client  = tuner_detach,        .command        = tuner_command,	.driver = {		.suspend = tuner_suspend,		.resume  = tuner_resume,	},};static struct i2c_client client_template ={	I2C_DEVNAME("(tuner unset)"),	.flags      = I2C_CLIENT_ALLOW_USE,        .driver     = &driver,};static int __init tuner_init_module(void){	return i2c_add_driver(&driver);}static void __exit tuner_cleanup_module(void){	i2c_del_driver(&driver);}module_init(tuner_init_module);module_exit(tuner_cleanup_module);/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -