收藏 分享(赏)

saa711x驱动分析.doc

上传人:hskm5268 文档编号:7051010 上传时间:2019-05-04 格式:DOC 页数:17 大小:84KB
下载 相关 举报
saa711x驱动分析.doc_第1页
第1页 / 共17页
saa711x驱动分析.doc_第2页
第2页 / 共17页
saa711x驱动分析.doc_第3页
第3页 / 共17页
saa711x驱动分析.doc_第4页
第4页 / 共17页
saa711x驱动分析.doc_第5页
第5页 / 共17页
点击查看更多>>
资源描述

1、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(static void _exit saa71

2、1x_cleanup_module(void)i2c_del_driver(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

3、,.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

4、 的函数。可以简单的通过调用 i2c_probe()函数来实现。static int saa711x_probe(struct i2c_adapter *adapter)if (adapter-class return 0;adapter:内核指针数组 adapters的一个元素,代表当前被扫描的 i2c 总线。addr_data:在 ltc3445.h 中由 I2C_CLIENT_INSMOD 宏创建的静态二维数组,表示使用该驱动程序的所有设备的所有可能地址的集合。saa711x_attach:为一个在地址成功检测时被调用的回调函数,用于创建描述该设备的 i2c_client 数据结构并初始

5、化。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。下面分析该函数的代码

6、: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 cg

7、cdiv;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_

8、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 i2

9、c_smbus_data data;data.byte = value;return i2c_smbus_xfer(client-adapter,client-addr,client-flags,I2C_SMBUS_WRITE,command,I2C_SMBUS_BYTE_DATA,EXPORT_SYMBOL(i2c_smbus_write_byte_data);可以看出实际上是调用 i2c_smbus_xfer()来实现。这个函数通过适配器驱动提供的总线访问方法(i2c_algorithm 的 smbus_xfer 方法)尝试访问处于 addr 地址上的设备。s32 i2c_smbus_xf

10、er(struct i2c_adapter * adapter, u16 addr, unsigned short flags,char read_write, u8 command, int size,union i2c_smbus_data * data)s32 res;flags if (adapter-algo-smbus_xfer) mutex_lock(res = adapter-algo-smbus_xfer(adapter,addr,flags,read_write,command,size,data);mutex_unlock( elseres = i2c_smbus_xfe

11、r_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(

12、):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(clie

13、nt-adapter,client-addr,client-flags,I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,elsereturn 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

14、(client = 0)return -ENOMEM;初始化 client 的 addr,adapter 和 driver。没什么可说的。client-addr = address;client-adapter = adapter;client-driver = 初始化 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);ch

15、ip_id = saa711x_read(client, 0) /* 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 foun

16、d (%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;stat

17、e-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_SAA

18、7114;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“);/* ini

19、t 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

20、, 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 v

21、oid *i2c_get_clientdata (struct i2c_client *dev)return dev_get_drvdata (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(co

22、nst int id, const u8 reg)if (id = V4L2_IDENT_SAA7111)return reg 0x19) /* common for saa7113/4/5/8 */if (unlikely(reg = 0x3b case V4L2_IDENT_SAA7118:return (reg 0x1d) state-std = std;/ This works for NTSC-M, SECAM-L and the 50Hz PAL variants.if (std saa711x_writeregs(client, saa7115_cfg_60hz_video);s

23、aa711x_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 li

24、nes000 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(clien

25、t, R_0E_CHROMA_CNTL_1) 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 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg); else /* restart task B if needed */int t

26、askb = saa711x_read(client, R_80_GLOBAL_CNTL_1) if (taskb /* switch audio mode too! */saa711x_set_audio_clock_freq(client, state-audclk_freq);具体的设置就不仔细分析了。最后是i2c_attach_client(client);该函数向设备所在的总线注册设备数据结构。首先检查这个新设备所使用的地址不与总线上已有设备的地址冲突。否则返回-EBUSY。一条 I2C 总线上所有已注册设备的 i2c_client 数据结构被组织在 i2c_adapter 中的 c

27、lients指针数组中。所谓注册,其实也就是在 clients 数据中找到第一个未使用的元素,并将其指向新的 i2c_client 数据结构。最后,如果适配器驱动程序模块中提供了 client_register 方法则调用之,这个方法用于完成适配器端的额外的注册工作。到此 saa711x_attach()函数就结束了。3. saa711x_detech()函数:static int saa711x_detach(struct i2c_client *client)struct saa711x_state *state = i2c_get_clientdata(client);int err;err = i2c_detach_client(client);if (err) return err;kfree(state);kfree(client);return 0;这个函数相对比较简单。就是调用 i2c_detach_client()。4. saa711x_command()函数这个函数实现了针对设备的控制命令。具体的控制命令是设备相关的。这里主要是留出了V4L2 的 API。具体含义请参照 V4L2 的说明文档。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报