embedded linux ,android

顯示具有 Linux Driver 標籤的文章。 顯示所有文章
顯示具有 Linux Driver 標籤的文章。 顯示所有文章

2010年11月28日 星期日

procfs sysfs devfs 的意義

/dev 是 user 利用application與硬體裝置溝通的介面
/sys  是OS post 出來的device相關的information
/proc 是Process與OS的整體資訊
所以三者是不互相取代的

2010年11月11日 星期四

[轉]linux 下视频设备设置的几个参数 v4l video4linux v4l2 ioctl

用一系列的ioctl发命令控制设备。v4l支持的ioctl命令大概有二十几个,为了尽快的编出一个
简单的图象捕捉程序,让我们先来看看几个主要的命令:



1. ioctl(fd,VIDIOCGCAP,&cap);
   该命令主要是为了获取电视卡的功能信息。例如电视卡的名称,类型,channel等。参数cap是一个结构,当ioctl命令返回时,结构的各成员就被赋值了,结构体的定义为:
struct video_capability
{
        char name[32];
        int type;
        int channels;        /* Num channels */
        int audios;        /* Num audio devices */
        int maxwidth;        /* Supported width */
        int maxheight;        /* And height */
        int minwidth;        /* Supported width */
        int minheight;        /* And height */
};
channel 指的是有几个信号输入源,例如television,composite,s-video等。

2.ioctl(fd,VIDIOCGCHAN,&vc)
3.ioctl(fd,VIDIOCSCHAN.&vc)
这两个命令用来取得和设置电视卡的channel信息,例如使用那个输入源,制式等。
vc 是一个video_channel结构,其定义为:
struct video_capability
{
        char name[32];
        int type;
        int channels;        /* Num channels */
        int audios;        /* Num audio devices */
        int maxwidth;        /* Supported width */
        int maxheight;        /* And height */
        int minwidth;        /* Supported width */
        int minheight;        /* And height */
};


struct video_channel
{
        int channel;
        char name[32];
        int tuners;//number of tuners for this input
        __u32  flags;
        __u16  type;        
        __u16 norm;                
};
成员channel代表输入源,通常,0: television 1:composite1 2:s-video
name 表示该输入源的名称。
norm 表示制式,通常,0:pal 1:ntsc 2:secam 3:auto

4. ioctl(fd,VIDIOCGMBUF,*mbuf)
获得电视卡缓存的信息,参数mbuf是video_mbuf结构。其定义如下:
struct video_mbuf
{
        int        size;                /* Total memory to map */
        int        frames;                /* Frames */
        int        offsets[VIDEO_MAX_FRAME];
};
size是缓存的大小,frames表明该电视卡的缓存可以容纳的帧数,数组offsets则表明
对应一帧的起始位置,0帧对应offsets[0],1帧对应offsets[1]....
执行完该命令后,就可以用mmap函数将缓存映射到内存中了。大致用法可以参考以下的代
码
struct video_mbuf mbuf;
unsigned char *buf1,*buf2;

if(ioctl(fd,VIDIOCGMBUF,&mbuf)<0)
{
        perror("VIDIOCGMBUF");
        return -1;
}

printf("the frame number is %d\n",mbuf.frames);

buf1 = (unsigned char*)mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd.0);

buf1 = buf1 + mbuf.offset[0];
buf2 = buf1 + mbuf.offset[1];//当然,如果mbuf.frames=1,就不需要下面的了。
......

5. ioctl(fd.VIDIOCMCAPTURE,&mm)
   启动硬件去捕捉图象,mm 是video_mmap 结构,设置捕捉图象需要设置的信息。结构体
如下定义:

struct video_mmap
{
        unsigned        int frame;                /* Frame (0 - n) for double buffer */
        int                height,width;
        unsigned        int format;                /* should be VIDEO_PALETTE_* */
};
frame :设置当前是第几帧
height,width:设置图象的高和宽。
format :颜色模式

要注意的是,该命令是非阻塞的,也就是说,它仅仅设置了硬件,而不负责是否捕捉到图象。
要确定是否捕捉到图象,要用到下一个命令。

6. ioctl(fd,VIDIOCSYNC,&frame)
等待捕捉到这一帧图象。frame 是要等待的图象,它的值应和上一个命令中设置的frame相对应。

好了,说了这么多,读者大概也对视频捕捉有了一个了解,是不是想亲自动手试一下,那就让我们
开始实际程序的编写吧。
下面我们会编一个程序,将捕捉到的图象存为jpeg文件。为此,还要向大家介绍一个函数,

int write_jpeg(char *filename,unsigned char *buf,int quality,int width, int height, int gray)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE *fp;
    int i;
    unsigned char *line;
    int line_length;
    
    if (NULL == (fp = fopen(filename,"w"))) 
    {
                fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));
                return -1;
    }
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fp);
    cinfo.image_width  = width;
    cinfo.image_height = height;
    cinfo.input_components = gray ? 1: 3;
    cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);

    line_length = gray ? width : width * 3;
    for (i = 0, line = buf; i < height; i++, line += line_length)
        jpeg_write_scanlines(&cinfo, &line, 1);
    
    jpeg_finish_compress(&(cinfo));
    jpeg_destroy_compress(&(cinfo));
    fclose(fp);

    return 0;
}

这个函数很通用,它的作用是把buf中的数据压缩成jpeg格式。

/*         下面是一个完整的程序 test.c
*           gcc test.c -o test -ljpeg
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
         
#include <jpeglib.h>

#define WIDTH  320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"

main()
{

   unsigned char* buf;
   int i,j;
   int fd;
   int re;

   struct video_capability vcap;
   struct video_channel    vc;
   struct video_mbuf       mbuf;
   struct video_mmap       mm;

   fd = open(V4L_DEVICE, O_RDWR);
   if(fd<=0)
   {
           perror("open");
             exit(1);
   }

   if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
   {
             perror("VIDIOCGCAP");
             exit(1);
   }

   fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);

   for(i=0;i<vcap.channels;i++)
   {
             vc.channel = i;
             if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
             {
                       perror("VIDIOCGCHAN");
                       exit(1);
             }

             fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
   }

   vc.channel =1;
   vc.norm=1;

   if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
   {
             perror("VIDIOCSCHAN");
             exit(1);
   }

  if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
  {
        perror("VIDIOCGMBUF");
        exit(1);
  }
   fprintf(stderr,"the frames number is %d\n",mbuf.frames); 

  buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
   if((int)buf < 0)
   {
             perror("mmap");
             exit(1);
   }
   mm.frame  = 0;
   mm.height = HEIGHT;
   mm.width  = WIDTH;
   mm.format = VIDEO_PALETTE_RGB24;

   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {
             perror("VIDIOCMCAPTURE");
            exit(1);
   }

   if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {
             perror("VIDIOCSYNC");
             exit(1);
   }

if(-1 == (write_jpeg("./pic001.jpeg",buf,75,WIDTH,HEIGHT,0)))
{
        printf("write_jpeg error\n");
        exit(1);
}

   munmap(buf,mbuf.size);
   close(fd);
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lanmanck/archive/2009/04/13/4069534.aspx

Porting CMOS Sensor OV9650 form 2.6.24 to android kernel 2.6.29 on dma6410xp

由於dma6410xp的camera還不能動,
所以要了一份 kernel 2.6.24的OV9650 driver,
參考s5k4ba修改ov9650

基本上ov9650 透過 I2C 連到 s3c6410 camera control上
























ov9650.c
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/delay.h>

//#define CAMIF_DEBUG

#include "s3c_camif.h"
#include "ov9650.h"

static const char *sensor_version = "ov9650.c 2010/11/6";

static void delay(int i)
{
 int j;
 for(j=0;j<i*10;j++);
}

static struct i2c_driver ov9650_driver;

/* This is SXGA(1280x1024) camera but start from VGA(640x480) mode */
static camif_cis_t ov9650_data = 
{
        itu_fmt:       CAMIF_ITU601,
        order422:      CAMIF_YCBYCR,  //YCRYCB
        camclk:        24000000, /* No effect */
        source_x:      640,
        source_y:      480,
        win_hor_ofst:  0,
        win_ver_ofst:  0,
        win_hor_ofst2: 0,
        win_ver_ofst2: 0,
        polarity_pclk: 1,
        polarity_vsync:1,
        polarity_href: 0,        
        reset_type:CAMIF_EX_RESET_AL, /* Active Low */
        reset_udelay: 20000,
};

ov9650_t ov9650_regs_mirror[OV9650_REGS];

extern camif_cis_t* get_initialized_cis(void);
camif_cis_t* get_initialized_cis() 
{
        printk(KERN_CRIT"[CAM DRV]+get_initialized_cis\n");
        if(ov9650_data.init_sensor == 0) return NULL;
        printk(KERN_CRIT"[CAM DRV]-get_initialized_cis\n");
        return &ov9650_data;
}

//the device slave address are 60 for read 61 for write
#define CAM_ID 0x60

static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { (CAM_ID >> 1), I2C_CLIENT_END };

static struct i2c_client_address_data addr_data = 
{
      normal_i2c:normal_addr,
      probe:ignore,
      ignore:ignore,
};


unsigned char sensor_read(struct i2c_client *client, unsigned char subaddr)
{
        int ret;
        unsigned char buf[1];
        struct i2c_msg msg = { client->addr, 0, 1, buf };
        buf[0] = subaddr;

        printk(KERN_CRIT"[CAM DRV]+sensor_read\n");
        ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
        if (ret == -EIO) {
            printk(" I2C write Error \n");
            return -EIO;
        }

        msg.flags = I2C_M_RD;
        ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;

        printk(KERN_CRIT"[CAM DRV]-sensor_read\n");
        return buf[0];
}


static int sensor_write(struct i2c_client *client,
             unsigned char subaddr, unsigned char val)
{
        unsigned char buf[2];
        struct i2c_msg msg = { client->addr, 0, 2, buf };

        printk(KERN_CRIT"[CAM DRV]+sensor_write\n");
        buf[0] = subaddr;
        buf[1] = val;

        printk(KERN_CRIT"[CAM DRV]-sensor_write\n");
        return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
}

void inline sensor_testreg(struct i2c_client *sam_client)
{
 ov9650_t testreg[OV9650_INIT_REGS];
 int i;
        printk(KERN_CRIT"[CAM DRV]+sensor_testreg\n");
 for (i = 0; i < OV9650_INIT_REGS; i++) {
  testreg[i].value = sensor_read(sam_client,ov9650_reg[i].subaddr);
  printk(KERN_CRIT"ov9650reg value:[0x%02x][0x%02x]\r\n",ov9650_reg[i].subaddr,testreg[i].value);
 }
 while(1)
  {
        sensor_write(sam_client, 0x35,0x78);
     delay(20);
     testreg[1].value = sensor_read(sam_client,10);
   printk(KERN_CRIT"ov9650reg value:[0x%x]\r\n",testreg[1].value);
  }
        printk(KERN_CRIT"[CAM DRV]-sensor_testreg\n");
}

void inline sensor_init(struct i2c_client *sam_client)
{
 int i;
 //i = (sizeof(ov9650_reg)/sizeof(ov9650_reg[0]));

        printk(KERN_CRIT"[CAM DRV]+sensor_init\n");
 for (i = 0; i < OV9650_INIT_REGS; i++) {
  delay(50);
  sensor_write(sam_client,ov9650_reg[i].subaddr, ov9650_reg[i].value);
#if 0
   printk(KERN_ERR "Page:[%03d] Subaddr %02x = 0x%02x\n",i,
          ov9650_reg[i].subaddr,
          ov9650_reg[i].value);
#endif
 }

#ifdef YOU_WANT_TO_CHECK_IMG_SENSOR
 for (i = 0; i < OV9650_INIT_REGS; i++) {
  if (ov9650_reg[i].subaddr == PAGE_ADDRESS) {
   sensor_write(sam_client,
         ov9650_reg[i].subaddr,
         ov9650_reg[i].value);

   printk(KERN_ERR "Page: Subaddr %02x = 0x%02x\n",
          ov9650_reg[i].subaddr,
          ov9650_reg[i].value);


  } else {
   ov9650_regs_mirror[i].subaddr =
       ov9650_reg[i].subaddr;
   ov9650_regs_mirror[i].value =
       s5k3aa_read(sam_client, ov9650_reg[i].subaddr);
   printk(KERN_ERR "Subaddr %02x = 0x%02x\n",
          ov9650_reg[i].subaddr,
          ov9650_regs_mirror[i].value);
  }
 }
#endif
        printk(KERN_CRIT"[CAM DRV]-sensor_init\n");
}


static int
ov9650_attach(struct i2c_adapter *adap, int addr,  int  flags )
{
 struct i2c_client *c;
 int ret = 0;
 //unsigned char a = 0xff;

        printk(KERN_CRIT"[CAM DRV]+ov9650_attach\n");
 c = kmalloc(sizeof(*c), GFP_KERNEL);
 if (!c)
  return -ENOMEM;

 memset(c, 0, sizeof(struct i2c_client));     

 strcpy(c->name, "ov9650");
 c->addr = addr;
 c->adapter = adap;
 c->driver = &ov9650_driver;
 ov9650_data.sensor = c;

 ret = i2c_attach_client(c);
 
 //a = sensor_read(c,10);
 //printk("0V9650.C:CAMERA ID: 0x%x\r\n",a);
 
        printk(KERN_CRIT"[CAM DRV]-ov9650_attach\n");
 return ret;
}

static int sensor_probe(struct i2c_adapter *adap)
{
        printk(KERN_CRIT"[CAM DRV]+sensor_probe\n");
        printk(KERN_CRIT"[CAM DRV]-sensor_probe\n");
 
        return i2c_probe(adap, &addr_data, ov9650_attach);
}

static int sensor_detach(struct i2c_client *client)
{
        printk(KERN_CRIT"[CAM DRV]+sensor_detach\n");
        i2c_detach_client(client);
        printk(KERN_CRIT"[CAM DRV]-sensor_detach\n");
        return 0;
}

static int change_sensor_size(struct i2c_client *client, int size)
{
 int i;

        printk(KERN_CRIT"[CAM DRV]+change_sensor_size\n");
 switch (size) {

 case SENSOR_VGA:
  for (i = 0; i < OV9650_VGA_REGS; i++) {
   delay(50);
   sensor_write(client, ov9650_reg_vga[i].subaddr,
         ov9650_reg_vga[i].value);
  }
  break;
 case SENSOR_SXGA:
  for (i = 0; i < OV9650_SXGA_REGS; i++) {
   delay(50);
   sensor_write(client, ov9650_reg_sxga[i].subaddr,
         ov9650_reg_sxga[i].value);
  }
  break;
  

 case SENSOR_SVGA:
  for (i = 0; i < OV9650_INIT_REGS; i++) {
   delay(50);
   sensor_write(client, ov9650_reg[i].subaddr,
         ov9650_reg[i].value);
  }
  break;

 default:
  panic("ov9650.c: unexpect value \n");
 }

        printk(KERN_CRIT"[CAM DRV]-change_sensor_size\n");
 return 0;
}

static int change_sensor_wb(struct i2c_client *client, int type)
{
        printk(KERN_CRIT"[CAM DRV]+change_sensor_wb\n");
       printk("[ *** Page 0, OV9650 Sensor White Balance Mode ***]\n");
       
       sensor_write(client, 0xFC, 0x0);
       sensor_write(client, 0x30, type);

       switch(type){
           case 0:
           default:
                printk(" -> AWB auto mode ]\n");
                break;
           case 1:
                printk(" -> Indoor 3100 mode ]\n");
                break;
           case 2:
                printk(" -> Outdoor 5100 mode ]\n");
                break;
           case 3:
                printk(" -> Indoor 2000 mode ]\n");
                break;
           case 4:
                printk(" -> AE/AWB halt ]\n");
                break;
           case 5:
                printk(" -> Cloudy(6000) mode ]\n");
                break;
           case 6:
                printk(" -> Sunny(8000) mode ]\n");
                break;
       }

        printk(KERN_CRIT"[CAM DRV]-change_sensor_wb\n");
       return 0;
}

static int
sensor_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
        printk(KERN_CRIT"[CAM DRV]+sensor_command\n");
 switch (cmd) {
 case SENSOR_INIT:
  sensor_init(client);
  printk("External Camera initialized\n");
  break;
  
 case USER_ADD:
  //MOD_INC_USE_COUNT;
  break;
  
 case USER_EXIT:
  //MOD_DEC_USE_COUNT;
  //sensor_testreg(client);
  break;
  
 case SENSOR_VGA:
  printk("change_sensor_size:SENSOR_VGA\n");
  change_sensor_size(client, SENSOR_VGA);
  break;
  
 case SENSOR_SVGA:
  printk("change_sensor_size:SENSOR_SVGA\n");
  change_sensor_size(client, SENSOR_SVGA);
  break;
  
 case SENSOR_SXGA:
  printk("change_sensor_size:SENSOR_SXGA\n");
  change_sensor_size(client, SENSOR_SXGA);
  break;
  
 case SENSOR_UXGA:
  printk("change_sensor_size:SENSOR_UXGA\n");
  change_sensor_size(client, SENSOR_UXGA);
  break;
/* Todo
 case SENSOR_BRIGHTNESS:
  change_sensor();
  break;
*/
 case SENSOR_WB:
         printk("[ *** OV9650 Sensor White Balance , No mode ***]\n");
         change_sensor_wb(client, (int)arg);
         break;
 
 default:
  panic("ov9650.c : Unexpect Sensor Command \n");
  break;
 }
 
        printk(KERN_CRIT"[CAM DRV]-sensor_command\n");
 return 0;
}

static struct i2c_driver ov9650_driver = {
 .driver = {
  .name = "ov9650",
 },
      .id = I2C_DRIVERID_OVCAMCHIP,
      .attach_adapter = sensor_probe,
      .detach_client = sensor_detach,
      .command = sensor_command
};

static int ov9650_sensor_init(void)
{
 int ret;

        printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_init\n");
 s3c_camif_open_sensor(&ov9650_data);

 if (ov9650_data.sensor == NULL)
  if ((ret = i2c_add_driver(&ov9650_driver)))
   return ret;

 if (ov9650_data.sensor == NULL) {
  i2c_del_driver(&ov9650_driver); 
  return -ENODEV;
 }

 s3c_camif_register_sensor(&ov9650_data);

        printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_init\n");
 return 0;
}

static void ov9650_sensor_exit(void)
{
        printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
        if (ov9650_data.sensor != NULL)
            s3c_camif_unregister_sensor(&ov9650_data);
        printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
}

static struct v4l2_input ov9650_input = {
 //第幾個camera輸入
 .index  = 0,
 //cmos name 
 .name  = "Camera Input (OV9650)",
 //V4L2_INPUT_TYPE_TUNER 1 This input uses a tuner (RF demodulator).
        //V4L2_INPUT_TYPE_CAMERA 2 Analog baseband input, for example CVBS
        //Composite Video, S-Video, RGB.
 .type  = V4L2_INPUT_TYPE_CAMERA, 
        //Video inputs combine with zero or more audio inputs.
 .audioset = 0,
 //Capture devices can have zero or more tuners
 .tuner  = 0,
        //Every video input supports one or more different video standards 
 .std  = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
        //
 .status  = 0,
};

static struct v4l2_input_handler ov9650_input_handler = {
 ov9650_sensor_init,
 ov9650_sensor_exit
};

static __init int ov9650_sensor_add(void)
{
        printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n");
        printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_add\n");
        return s3c_camif_add_sensor(&ov9650_input, &ov9650_input_handler);
}

static __exit void ov9650_sensor_remove(void)
{
        printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_remove\n");
        if(ov9650_data.sensor != NULL)
        {
            i2c_del_driver(&ov9650_driver); 
        } 

        s3c_camif_remove_sensor(&ov9650_input, &ov9650_input_handler);
        printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_remove\n");
}

module_init(ov9650_sensor_add)
module_exit(ov9650_sensor_remove)