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

📄 saa6752hs.c

📁 电脑主机的PCI电视卡的源代码
💻 C
字号:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/i2c.h>#include <linux/types.h>#include <linux/videodev.h>#include <linux/init.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#include "i2c-compat.h"#include "id.h"#include "saa6752hs.h"#else#include <media/id.h>#include <media/saa6752hs.h>#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)#endif/* Addresses to scan */static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};I2C_CLIENT_INSMOD;MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");MODULE_AUTHOR("Andrew de Quincey");MODULE_LICENSE("GPL");static struct i2c_driver driver;static struct i2c_client client_template;enum saa6752hs_command {	SAA6752HS_COMMAND_RESET = 0,    	SAA6752HS_COMMAND_STOP = 1,    	SAA6752HS_COMMAND_START = 2,    	SAA6752HS_COMMAND_PAUSE = 3,    	SAA6752HS_COMMAND_RECONFIGURE = 4,    	SAA6752HS_COMMAND_SLEEP = 5,	SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,    	SAA6752HS_COMMAND_MAX};/* ---------------------------------------------------------------------- */static u8 PAT[] = {	0xc2, // i2c register	0x00, // table number for encoder  	0x47, // sync	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)     	0x00, // PSI pointer to start of table    	0x00, // tid(0)	0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)    	0x00, 0x01, // transport_stream_id(1)    	0xc1, // version_number(0), current_next_indicator(1)    	0x00, 0x00, // section_number(0), last_section_number(0)	0x00, 0x01, // program_number(1)		0xe0, 0x10, // PMT PID(0x10)	0x76, 0xf1, 0x44, 0xd1 // CRC32};static u8 PMT[] = {	0xc2, // i2c register	0x01, // table number for encoder  	0x47, // sync	0x40, 0x10, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0x10)	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)     	0x00, // PSI pointer to start of table    	0x02, // tid(2)	0xb0, 0x17, // section_syntax_indicator(1), section_length(23)	0x00, 0x01, // program_number(1)    	0xc1, // version_number(0), current_next_indicator(1)    	0x00, 0x00, // section_number(0), last_section_number(0)    	0xe1, 0x04, // PCR_PID (0x104)   	0xf0, 0x00, // program_info_length(0)    	0x02, 0xe1, 0x00, 0xf0, 0x00, // video stream type(2), pid(0x100)	0x04, 0xe1, 0x03, 0xf0, 0x00, // audio stream type(4), pid(0x103)    	0xa1, 0xca, 0x0f, 0x82 // CRC32};static struct mpeg_params mpeg_params_template ={	.bitrate_mode = MPEG_BITRATE_MODE_CBR,	.video_target_bitrate = 5000,	.audio_bitrate = MPEG_AUDIO_BITRATE_256,	.total_bitrate = 6000,};  /* ---------------------------------------------------------------------- */static int saa6752hs_chip_command(struct i2c_client* client,				  enum saa6752hs_command command){	unsigned char buf[3];	unsigned long timeout;	int status = 0;	// execute the command	switch(command) {  	case SAA6752HS_COMMAND_RESET:  		buf[0] = 0x00;		break;	  	case SAA6752HS_COMMAND_STOP:		  	buf[0] = 0x03;		break;	  	case SAA6752HS_COMMAND_START:  		buf[0] = 0x02;		break;	case SAA6752HS_COMMAND_PAUSE:  		buf[0] = 0x04;		break;	  	case SAA6752HS_COMMAND_RECONFIGURE:		buf[0] = 0x05;		break;	    	case SAA6752HS_COMMAND_SLEEP:  		buf[0] = 0x06;		break;  	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:		buf[0] = 0x07;		break;		default:		return -EINVAL;  	}	  	// set it and wait for it to be so	i2c_master_send(client, buf, 1);	timeout = jiffies + HZ * 3;	for (;;) {		// get the current status		buf[0] = 0x10;	  	i2c_master_send(client, buf, 1);		i2c_master_recv(client, buf, 1);		if (!(buf[0] & 0x20))			break;		if (time_after(jiffies,timeout)) {			status = -ETIMEDOUT;			break;		}			// wait a bit		set_current_state(TASK_INTERRUPTIBLE);		schedule_timeout(HZ/100);	}	// delay a bit to let encoder settle	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(HZ/20);		// done  	return status;}static int saa6752hs_set_bitrate(struct i2c_client* client,				 struct mpeg_params* params){  	u8 buf[3];  	// set the bitrate mode	buf[0] = 0x71;	buf[1] = params->bitrate_mode;	i2c_master_send(client, buf, 2);	  	// set the video bitrate	if (params->bitrate_mode == MPEG_BITRATE_MODE_VBR) {		// set the target bitrate		buf[0] = 0x80;	    	buf[1] = params->video_target_bitrate >> 8;	  	buf[2] = params->video_target_bitrate & 0xff;		i2c_master_send(client, buf, 3);		// set the max bitrate		buf[0] = 0x81;	    	buf[1] = params->video_max_bitrate >> 8;	  	buf[2] = params->video_max_bitrate & 0xff;		i2c_master_send(client, buf, 3);	} else {		// set the target bitrate (no max bitrate for CBR)  		buf[0] = 0x81;	    	buf[1] = params->video_target_bitrate >> 8;	  	buf[2] = params->video_target_bitrate & 0xff;		i2c_master_send(client, buf, 3);	}	  	// set the audio bitrate 	buf[0] = 0x94;  	buf[1] = params->audio_bitrate;	i2c_master_send(client, buf, 2);		// set the total bitrate	buf[0] = 0xb1;  	buf[1] = params->total_bitrate >> 8;  	buf[2] = params->total_bitrate & 0xff;	i2c_master_send(client, buf, 3);  	return 0;}static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params){  	unsigned char buf[3];	void *data;	// check the bitrate parameters first	if (params != NULL) {		if (params->bitrate_mode >= MPEG_BITRATE_MODE_MAX)			return -EINVAL;		if (params->video_target_bitrate >= MPEG_VIDEO_TARGET_BITRATE_MAX)			return -EINVAL;  		if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX)			return -EINVAL;		if (params->audio_bitrate >= MPEG_AUDIO_BITRATE_MAX)			return -EINVAL;		if (params->total_bitrate >= MPEG_TOTAL_BITRATE_MAX)        		return -EINVAL;		if (params->bitrate_mode         == MPEG_BITRATE_MODE_MAX &&		    params->video_target_bitrate <= params->video_max_bitrate)			return -EINVAL; 	}      	// Set GOP structure {3, 13}	buf[0] = 0x72;	buf[1] = 0x03;	buf[2] = 0x0D;	i2c_master_send(client,buf,3);      	// Set minimum Q-scale {4}	buf[0] = 0x82;	buf[1] = 0x04;	i2c_master_send(client,buf,2);      	// Set maximum Q-scale {12}	buf[0] = 0x83;	buf[1] = 0x0C;	i2c_master_send(client,buf,2);      	// Set Output Protocol	buf[0] = 0xD0;	buf[1] = 0x01;	i2c_master_send(client,buf,2);      	// Set video output stream format {TS}	buf[0] = 0xB0;	buf[1] = 0x05;	i2c_master_send(client,buf,2);      	// Set Audio PID {0x103}	buf[0] = 0xC1;	buf[1] = 0x01;	buf[2] = 0x03;	i2c_master_send(client,buf,3);          // setup bitrate settings	data = i2c_get_clientdata(client);	if (params) {		saa6752hs_set_bitrate(client, params);		memcpy(data, params, sizeof(struct mpeg_params));	} else {		// parameters were not supplied. use the previous set   		saa6752hs_set_bitrate(client, (struct mpeg_params*) data);	}	  	// Send SI tables  	i2c_master_send(client,PAT,sizeof(PAT));  	i2c_master_send(client,PMT,sizeof(PMT));	  	// mute then unmute audio. This removes buzzing artefacts	buf[0] = 0xa4;	buf[1] = 1;	i2c_master_send(client, buf, 2);  	buf[1] = 0;	i2c_master_send(client, buf, 2);	  	// start it going	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);	return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)#elsestatic int saa6752hs_attach(struct i2c_adapter *adap, int addr,			    unsigned short flags, int kind)#endif{	struct i2c_client *client;	struct mpeg_params* params;        client_template.adapter = adap;        client_template.addr = addr;        printk("saa6752hs: chip found @ 0x%x\n", addr<<1);        if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))                return -ENOMEM;        memcpy(client,&client_template,sizeof(struct i2c_client));	strlcpy(client->name, "saa6752hs", sizeof(client->name));   	if (NULL == (params = kmalloc(sizeof(struct mpeg_params), GFP_KERNEL)))		return -ENOMEM;	memcpy(params,&mpeg_params_template,sizeof(struct mpeg_params));	i2c_set_clientdata(client, params);        i2c_attach_client(client);  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_INC_USE_COUNT;#endif	return 0;}static int saa6752hs_probe(struct i2c_adapter *adap){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)		return i2c_probe(adap, &addr_data, saa6752hs_attach);#else	switch (adap->id) {	case I2C_ALGO_SAA7134:		return i2c_probe(adap, &addr_data, saa6752hs_attach);		break;	}#endif	return 0;}static int saa6752hs_detach(struct i2c_client *client){	void *data;	data = i2c_get_clientdata(client);	i2c_detach_client(client);	kfree(data);	kfree(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_DEC_USE_COUNT;#endif	return 0;}static intsaa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct mpeg_params* init_arg = arg;        switch (cmd) {	case MPEG_SETPARAMS:   		return saa6752hs_init(client, init_arg);	default:		/* nothing */		break;	}		return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver driver = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,54)	.owner          = THIS_MODULE,#endif        .name           = "i2c saa6752hs MPEG encoder",        .id             = I2C_DRIVERID_SAA6752HS,        .flags          = I2C_DF_NOTIFY,        .attach_adapter = saa6752hs_probe,        .detach_client  = saa6752hs_detach,        .command        = saa6752hs_command,};static struct i2c_client client_template ={	I2C_DEVNAME("(saa6752hs unset)"),	.flags      = I2C_CLIENT_ALLOW_USE,        .driver     = &driver,};static int saa6752hs_init_module(void){	i2c_add_driver(&driver);	return 0;}static void saa6752hs_cleanup_module(void){	i2c_del_driver(&driver);}module_init(saa6752hs_init_module);module_exit(saa6752hs_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 + -