saa711x驱动分析.doc_第1页
saa711x驱动分析.doc_第2页
saa711x驱动分析.doc_第3页
saa711x驱动分析.doc_第4页
saa711x驱动分析.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Saa7115的驱动支持saa7111, saa7111a, saa7113, saa7114,saa7115 and saa7118.这里分析的代码是来自linux-2.6.19内核。具体路径为/driver/media/video/saa7115.c。1. 模块的加载与卸载module_init(saa711x_init_module);module_exit(saa711x_cleanup_module);static int _init saa711x_init_module(void) return i2c_add_driver(&i2c_driver_saa711x);static void _exit saa711x_cleanup_module(void) i2c_del_driver(&i2c_driver_saa711x);i2c_add_driver()用于注册设备驱动程序的i2c_driver数据结构。i2c_del_driver()则相反,用于注销设备驱动程序的i2c_driver树结构。由此加载i2c_driver的结构体i2c_driver_saa711xstatic struct i2c_driver i2c_driver_saa711x = .driver = .name = saa7115, , .id = I2C_DRIVERID_SAA711X, .attach_adapter = saa711x_probe, .detach_client = saa711x_detach, .command = saa711x_command,;其中driver为驱动名。id为驱动号。attach_adapter依附i2c_adapter函数指针。detach_client为脱离i2c_client函数指针。command为实现针对设备的控制命令指针,类似ioctl。下面分别对saa711x_probe(),saa711x_detach(),saa711x_command()作分析。2. saa711x_probe()函数saa711x_probe()是实现attach_adapter的函数。可以简单的通过调用i2c_probe()函数来实现。static int saa711x_probe(struct i2c_adapter *adapter) if (adapter-class & I2C_CLASS_TV_ANALOG | adapter-class & I2C_CLASS_TV_DIGITAL) return i2c_probe(adapter, &addr_data, &saa711x_attach); return 0;adapter:内核指针数组adapters的一个元素,代表当前被扫描的i2c 总线。addr_data:在ltc3445.h中由I2C_CLIENT_INSMOD宏创建的静态二维数组,表示使用该驱动程序的所有设备的所有可能地址的集合。saa711x_attach:为一个在地址成功检测时被调用的回调函数,用于创建描述该设备的i2c_client数据结构并初始化。i2c_probe 函数用于认领adapter所指适配器上的所有合适的设备。设备可能使用的地址的“线索”由addr_data二元数组指出,如果检测到存在实际设备,则调用saa711x_attach回调函数分配、初始化设备的i2c_client等数据结构。由此引出了函数saa7111x_attach():static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind);adapter:i2c_adapter类型的适配器 address:chip address。下面分析该函数的代码:struct i2c_client *client; /具体设备名struct saa711x_state *state; /saa711x_state结构体/*saa711x_state的结构体如下:struct saa711x_state v4l2_std_id std; int input; int output; int enable; int radio; int bright; int contrast; int hue; int sat; int width; int height; u32 ident; u32 audclk_freq; u32 crystal_freq; u8 ucgc; u8 cgcdiv; u8 apll;*/if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) return 0;这里调用了函数i2c_check_functionality()判断指定适配器是否支持相应的方法。I2C_FUNC_SMBUS_BYTE_DATA: Handles the SMBUS read_byte_data and write_byte_data commands.接着是对i2c_client初始化,初始化的过程中用到了saa711x_write和saa711x_read两个函数。l saa711x_write():static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value);这个函数的功能是把value的值写到client设备的reg寄存器中。它通过调用i2c_smbus_write_byte_data来实现。s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) union i2c_smbus_data data; data.byte = value; return i2c_smbus_xfer(client-adapter,client-addr,client-flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data);EXPORT_SYMBOL(i2c_smbus_write_byte_data);可以看出实际上是调用i2c_smbus_xfer()来实现。这个函数通过适配器驱动提供的总线访问方法(i2c_algorithm的smbus_xfer方法)尝试访问处于addr地址上的设备。s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter-algo-smbus_xfer) mutex_lock(&adapter-bus_lock); res = adapter-algo-smbus_xfer(adapter,addr,flags,read_write, command,size,data); mutex_unlock(&adapter-bus_lock); else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); return res;而目前i2c中没有实现smbus_xfer方法而只实现了master_xfer方法,所以相关的操作就由i2c_smbus_xfer_emulated函数来模拟。这个函数比较长,所以只分析它的参数。其中size为I2C_SMBUS_QUICK的一段。第二个参数为需要检测的设备地址,第四个参数read_write为0,表示进行写入操作。如果使用这个总线地址和设备通信成功,则说明设备使用的正是这个地址。l saa711x_read():static inline int saa711x_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg);这个函数的功能是把client设备的reg寄存器中的值读出并返回。它通过调用i2c_smbus_read_byte_data来实现。s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) union i2c_smbus_data data; if (i2c_smbus_xfer(client-adapter,client-addr,client-flags, I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data) return -1; else return data.byte;EXPORT_SYMBOL(i2c_smbus_read_byte_data);可以看出,它也是调用i2c_smbus_xfer函数来实现的,因此和saa711x_write()的过程基本一样。再回头看i2c_client的初始化:分配i2c_client的内存空间 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client = 0) return -ENOMEM;初始化client的addr,adapter和driver。没什么可说的。 client-addr = address; client-adapter = adapter; client-driver = &i2c_driver_saa711x;初始化client的name。 snprintf(client-name, sizeof(client-name) - 1, saa7115); for (i = 0; i 9) namei += a - 9 - 1; namei = 0;查看芯片号是否为saa711x。 saa711x_write(client, 0, 5); chip_id = saa711x_read(client, 0) & 0x0f; /* Check whether this chip is part of the saa711x series */ if (memcmp(name, 1f711, 5) v4l_dbg(1, debug, client, chip found 0x%x (ID %s) does not match a known saa711x chip.n, address name, sizeof(client-name) - 1, saa711%d,chip_id); v4l_info(client, saa711%d found (%s) 0x%x (%s)n, chip_id, name, address name);到此,i2c_client结构体client初始化完毕。下面开始对saa711x_state结构体state进行初始化。 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state);/将state存到client-dev中 if (state = NULL) kfree(client); return -ENOMEM; state-input = -1; state-output = SAA7115_IPORT_ON; state-enable = 1; state-radio = 0; state-bright = 128; state-contrast = 64; state-hue = 0; state-sat = 64;然后根据芯片号确认是哪款芯片。并选择不同的初始化函数。 switch (chip_id) case 1: state-ident = V4L2_IDENT_SAA7111; break; case 3: state-ident = V4L2_IDENT_SAA7113; break; case 4: state-ident = V4L2_IDENT_SAA7114; break; case 5: state-ident = V4L2_IDENT_SAA7115; break; case 8: state-ident = V4L2_IDENT_SAA7118; break; default: state-ident = V4L2_IDENT_SAA7111; v4l_info(client, WARNING: Chip is not known - Falling back to saa7111n); state-audclk_freq = 48000; v4l_dbg(1, debug, client, writing init valuesn); /* init to 60hz/48khz */ state-crystal_freq = SAA7115_FREQ_24_576_MHZ; switch (state-ident) case V4L2_IDENT_SAA7111: saa711x_writeregs(client, saa7111_init); break; case V4L2_IDENT_SAA7113: saa711x_writeregs(client, saa7113_init); break; default: state-crystal_freq = SAA7115_FREQ_32_11_MHZ; saa711x_writeregs(client, saa7115_init_auto_input); 以7111的初始化函数saa7111_init()为例分析芯片的初始化。这里用到了saa711x_writeregs()函数。在saa711x_writeregs()中又调用了i2c_get_clientdata(),saa711x_has_reg()以及saa711x_write()。saa711x_write()在前面已经分析过了,这里重点分析i2c_getclientdata()和saa711x_has_reg()。l i2c_get_clientdata()是i2c的一个API。static inline void *i2c_get_clientdata (struct i2c_client *dev) return dev_get_drvdata (&dev-dev);static inline void *dev_get_drvdata (struct device *dev) return dev-driver_data;很明显,是将一个i2c_client结构体中的dev-driver_data返回。l saa711x_has_reg()函数/* Sanity routine to check if a register is present */static int saa711x_has_reg(const int id, const u8 reg) if (id = V4L2_IDENT_SAA7111) return reg 0x20 & reg != 0x01 & reg != 0x0f & (reg 0x19) & reg != 0x1d & reg != 0x1e; /* common for saa7113/4/5/8 */ if (unlikely(reg = 0x3b & reg = 0xb5 & reg = 0xe5 & reg = 0x89 & reg = 0x8e) return 0; switch (id) case V4L2_IDENT_SAA7113: return reg != 0x14 & (reg 0x1e) & (reg 0x3f) & reg != 0x5d & reg 0x63; case V4L2_IDENT_SAA7114: return (reg 0x1e) & (reg 0x2f) & (reg 0x7f) & reg != 0x33 & reg != 0x37 & reg != 0x81 & reg 0xf0; case V4L2_IDENT_SAA7115: return (reg 0x2f) & reg != 0x65 & (reg 0xfe); case V4L2_IDENT_SAA7118: return (reg 0x1d) & (reg 0x22) & (reg 0x28) & reg != 0x33 & reg != 0x37 & (reg 0x7f) & reg != 0x81 & reg ident,reg) if (saa711x_write(client, reg, data) std) return; state-std = std; / This works for NTSC-M, SECAM-L and the 50Hz PAL variants. if (std & V4L2_STD_525_60) v4l_dbg(1, debug, client, decoder set standard 60 Hzn); saa711x_writeregs(client, saa7115_cfg_60hz_video); saa711x_set_size(client, 720, 480); else v4l_dbg(1, debug, client, decoder set standard 50 Hzn); saa711x_writeregs(client, saa7115_cfg_50hz_video); saa711x_set_size(client, 720, 576); /* Register 0E - Bits D6-D4 on NO-AUTO mode (SAA7111 and SAA7113 doesnt have auto mode) 50 Hz / 625 lines 60 Hz / 525 lines 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz) 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz) 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz) 011 NTSC N (3.58MHz) PAL M (3.58MHz) 100 reserved NTSC-Japan (3.58MHz) */ if (state-ident = V4L2_IDENT_SAA7111 | state-ident = V4L2_IDENT_SAA7113) u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f; if (std = V4L2_STD_PAL_M) reg |= 0x30; else if (std = V4L2_STD_PAL_N) reg |= 0x20; else if (std = V4L2_STD_PAL_60) reg |= 0x10; else if (std = V4L2_STD_NTSC_M_JP) reg |= 0x40; else if (std & V4L2_STD_SECAM) reg |= 0x50; saa711x_write(client, R_0E_CHROMA_CNTL_1, reg); e

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论