本系列准備分為3-4篇來講,因為說的太多會比較亂
v4l2視頻驅動主要涉及幾個知識點:
攝像頭方面的知識(攝像頭廠家提供的芯片手冊可以查看)
要了解選用的攝像頭的特性,包括訪問控制方法、各種參數的配置方法、信號輸出類型等。
Camera解碼器、控制器(主控芯片的芯片手冊里面有攝像頭相關的寄存器設置,比如2410里,里面主要是設置相關控制功能使能,芯片內部自己的架構)
如果攝像頭是模擬量輸出的,要熟悉解碼器的配置。最后數字視頻信號進入camera控制器后,還要熟悉camera控制器的操作。
V4L2的API和數據結構控制(主要是用戶空間需要的一些v4l2的操作,然后針對這些操作必須在底層實現相應的驅動)
編寫驅動前要熟悉應用程序訪問V4L2的方法及設計到的數據結構。
V4L2的驅動架構(這個是在底層寫驅動,為用戶空間提供相應的訪問接口,可以參照內核里面的/drivers/media/video//zc301/zc301_core.c 中的ZC301視頻驅動代碼
它是內核提供的非常完善的v4l2架構的例子,基本上都可以在它的基礎上進行修改!)
最后編寫出符合V4L2規范的視頻驅動。
NO.1 攝像頭方面的知識
ov9650攝像頭,暫時先不說,先了解一下camera解碼器、控制器,不同的主控芯片的camera控制器都差不多
static struct ov9650_reg { unsigned char subaddr; unsigned char value; }regs[] = { /* OV9650 intialization parameter table for VGA application */ {0x12, 0x40},// Camera Soft reset. Self cleared after reset. {CHIP_DELAY, 10}, {0x11,0x81},{0x6a,0x3e},{0x3b,0x09},{0x13,0xe0},{0x01,0x80},{0x02,0x80},{0x00,0x00},{0x10,0x00}, {0x13,0xe5},{0x39,0x43},{0x38,0x12},{0x37,0x91},{0x35,0x91},{0x0e,0xa0},{0x1e,0x04},{0xA8,0x80}, {0x14,0x40},{0x04,0x00},{0x0c,0x04},{0x0d,0x80},{0x18,0xc6},{0x17,0x26},{0x32,0xad},{0x03,0x00}, {0x1a,0x3d},{0x19,0x01},{0x3f,0xa6},{0x14,0x2e},{0x15,0x10},{0x41,0x02},{0x42,0x08},{0x1b,0x00}, {0x16,0x06},{0x33,0xe2},{0x34,0xbf},{0x96,0x04},{0x3a,0x00},{0x8e,0x00},{0x3c,0x77},{0x8B,0x06}, {0x94,0x88},{0x95,0x88},{0x40,0xc1},{0x29,0x3f},{0x0f,0x42},{0x3d,0x92},{0x69,0x40},{0x5C,0xb9}, {0x5D,0x96},{0x5E,0x10},{0x59,0xc0},{0x5A,0xaf},{0x5B,0x55},{0x43,0xf0},{0x44,0x10},{0x45,0x68}, {0x46,0x96},{0x47,0x60},{0x48,0x80},{0x5F,0xe0},{0x60,0x8c},{0x61,0x20},{0xa5,0xd9},{0xa4,0x74}, {0x8d,0x02},{0x13,0xe7},{0x4f,0x3a},{0x50,0x3d},{0x51,0x03},{0x52,0x12},{0x53,0x26},{0x54,0x38}, {0x55,0x40},{0x56,0x40},{0x57,0x40},{0x58,0x0d},{0x8C,0x23},{0x3E,0x02},{0xa9,0xb8},{0xaa,0x92}, {0xab,0x0a},{0x8f,0xdf},{0x90,0x00},{0x91,0x00},{0x9f,0x00},{0xa0,0x00},{0x3A,0x01},{0x24,0x70}, {0x25,0x64},{0x26,0xc3},{0x2a,0x00},{0x2b,0x00},{0x6c,0x40},{0x6d,0x30},{0x6e,0x4b},{0x6f,0x60}, {0x70,0x70},{0x71,0x70},{0x72,0x70},{0x73,0x70},{0x74,0x60},{0x75,0x60},{0x76,0x50},{0x77,0x48}, {0x78,0x3a},{0x79,0x2e},{0x7a,0x28},{0x7b,0x22},{0x7c,0x04},{0x7d,0x07},{0x7e,0x10},{0x7f,0x28}, {0x80,0x36},{0x81,0x44},{0x82,0x52},{0x83,0x60},{0x84,0x6c},{0x85,0x78},{0x86,0x8c},{0x87,0x9e}, {0x88,0xbb},{0x89,0xd2},{0x8a,0xe6}, };
上面是需要順序寫ov9650的寄存器的地址和寫入的數值(采用I2C子系統傳輸)
I2C子系統傳輸已經分析過,平台設備的資源可以在板文件中初始化:
1.修改vi drivers/i2c/busses/Kconfig
修改
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
depends on ARCH_S3C2410 || ARCH_S3C64XX
help
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
為:
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100
help
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
2.內核配置並重新編譯內核
$ make menuconfig
Device Drivers --->
<*> I2C support --->
<*> I2C device interface
I2C Hardware Bus support --->
<*> S3C2410 I2C Driver
3.修改vi arch/arm/mach-s5pc100/mach-smdkc100.c
查看原理圖可以知道攝像頭是接在I2C-0或1上,假設在1上,根據原理圖修改i2c_devs1添加ov9650的內容,主要是ov9650的地址,這個在芯片手冊上可以查到是0x60
而下面為什么是0x30呢?在我的另外一篇I2C子系統分析里面講過。給個鏈接解釋
修改:
static struct i2c_board_info i2c_devs1[] __initdata = {
};
為:
static struct i2c_board_info i2c_devs1[] __initdata = {
{
I2C_BOARD_INFO("ov9650", 0x30),
},
};
添加s5pc100 攝像頭控制器平台設備相關內容,這些內容我們可以通過查看S5PC100的芯片手冊查到
static struct resource s3c_camif_resource[] = {
[0] = {
.start = 0xEE200000,
.end = 0xEE200000 + SZ_1M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_FIMC0,
.end = IRQ_FIMC0,
.flags = IORESOURCE_IRQ,
}
};
static u64 s3c_device_camif_dmamask = 0xffffffffUL;
struct platform_device s3c_device_camif = {
.name = "s5pc100-camif",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_camif_resource),
.resource = s3c_camif_resource,
.dev = {
.dma_mask = &s3c_device_camif_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_camif);
注冊攝像頭控制平台設備:
在smdkc100_devices中添加s3c_device_camif
static struct platform_device *smdkc100_devices[] __initdata = {
&s3c_device_camif, //添加內容
};
4. 添加驅動(video)
Make menuconfig
Device Drivers --->
<*> Multimedia support --->
<*> Video For Linux
[*] Enable Video For Linux API 1 (DEPRECATED) (NEW)
[*] Video capture adapters (NEW) --->
[*] V4L USB devices (NEW) --->
<*> USB Video Class (UVC)
[*] UVC input events device support (NEW)
<*> USB ZC0301[P] webcam support (DEPRECATED)
這樣device已經注冊好了!
/* write a register */
static int ov9650_reg_write(struct i2c_client *client, u8 reg, u8 val)
{
int ret;
u8 _val;
unsigned char data[2] = { reg, val };
struct i2c_msg msg = {
.addr= client->addr,
.flags= 0,
.len= 2,
.buf= data,
};
//構建i2c_msg
ret = i2c_transfer(client->adapter, &msg, 1); //I2C適配器和I2C設備之間的一組消息的交換
return 0;
}
static void ov9650_init_regs(void)
{
int i;
for (i=0; i<ARRAY_SIZE(regs); i++)
{
if (regs[i].subaddr == 0xff)
{
mdelay(regs[i].value);
continue;
}
ov9650_reg_write(ov9650_client, regs[i].subaddr, regs[i].value);
}
}
至此,通過I2C總線已經將攝像頭的寄存器初始化好了。
下一部分將講解Camera解碼器、控制器。