Linux online debugging camera driver __linux

Source: Internet
Author: User
Tags goto message queue usleep

In the use of embedded Linux devices to do point-to-point image transmission, such as the Linux platform to collect camera data, and then through WiFi or Bluetooth and other devices to send image data to the phone, and finally use the phone to display the image. Image processing and image transfer are done in the application layer, and it is easy to write code and debug code in the application layer. However, if you need to debug some of the camera-driven parameters, it involves the driver layer of things will be more trouble. In my use of this platform, if I want to debug the camera driver gc0308 register, it needs to change the register value every time and then reproduce as a firmware, and finally look at the image effect, such a debugging method is to let people crash.

In fact, in the Linux driver, it has provided a debugging V4L2 device interface. In the Linux source code, we can see the following definition:

struct V4l2_subdev_core_ops {int (*g_chip_ident) (struct V4l2_subdev *sd, struct v4l2_dbg_chip_ident);
	Int (*log_status) (struct V4l2_subdev *sd);
	Int (*s_io_pin_config) (struct V4l2_subdev *sd, size_t N, struct v4l2_subdev_io_pin_config);
	Int (*init) (struct V4l2_subdev *sd, u32 val);
	Int (*LOAD_FW) (struct V4l2_subdev *sd);
	Int (*reset) (struct V4l2_subdev *sd, u32 val);
	Int (*s_gpio) (struct V4l2_subdev *sd, u32 val);
	Int (*queryctrl) (struct V4l2_subdev *sd, struct V4l2_queryctrl);
	Int (*g_ctrl) (struct V4l2_subdev *sd, struct v4l2_control);
	Int (*s_ctrl) (struct V4l2_subdev *sd, struct v4l2_control);
	Int (*g_ext_ctrls) (struct V4l2_subdev *sd, struct v4l2_ext_controls);
	Int (*s_ext_ctrls) (struct V4l2_subdev *sd, struct v4l2_ext_controls);
	Int (*try_ext_ctrls) (struct V4l2_subdev *sd, struct v4l2_ext_controls);
	Int (*querymenu) (struct V4l2_subdev *sd, struct v4l2_querymenu); Int (*G_STD) (struct V4l2_subdev *sd, v4l2_std_id *norm);
	Int (*S_STD) (struct V4l2_subdev *sd, v4l2_std_id norm);
Long (*ioctl) (struct V4l2_subdev *sd, unsigned int cmd, void *arg);
	#ifdef Config_video_adv_debug Int (*g_register) (struct V4l2_subdev *sd, struct v4l2_dbg_register);
Int (*s_register) (struct V4l2_subdev *sd, const struct v4l2_dbg_register);
	#endif Int (*s_power) (struct V4l2_subdev *sd, int on);
	Int (*interrupt_service_routine) (struct V4l2_subdev *sd, u32 status, BOOL *handled);
	Int (*subscribe_event) (struct V4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription);
Int (*unsubscribe_event) (struct V4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription); };
In the V4l2_subdev_core_ops has provided us with the direct Operation V4L2 device registers the interface, only needs us to define the macro config_video_adv_debug to be possible. Here is a direct description of how to configure and design online debugging.

(1) Open the Config_video_adv_debug macro, the macro directly in the Linux configuration file can be configured, into the following figure:


Make the debug option available.

(2) Driver device Add Operation interface

When initializing the struct v4l2_subdev_core_ops structure, add a direct read register and a write register interface, as follows:

static const struct V4l2_subdev_core_ops sensor_core_ops = {
	. g_chip_ident = Sensor_g_chip_ident,
	. G_ctrl = Sensor_g_ctrl,
	. S_ctrl = Sensor_s_ctrl,
	. Queryctrl = Sensor_queryctrl,
	. reset = Sensor_reset,
	. init = Sensor_init,
	. S_power = Sensor_power,
	. IOCTL = sensor_ioctl,
#ifdef config_video_adv_debug
	. g_ Register = sensor_g_register,
	. S_register = Sensor_s_register,
#endif
};
The Sensor_g_register is the value of the read register, Sensor_s_register is the value of the write register, which is defined as the following two functions:

#ifdef config_video_adv_debug
static int sensor_g_register (struct V4l2_subdev *sd, struct v4l2_dbg_register  * Para)
{
	int ret;
	unsigned short reg_addr  = 0;
	unsigned short reg_value = 0;
	
	Reg_addr  = para->size;
	ret = Sensor_read (sd,reg_addr,&reg_value);

	if (Ret < 0)
	{
		printk ("Sensor_g_register ret=%d; reg_addr=%d; Reg_value=%d\n ", ret, reg_addr, reg_value);
		return ret;
	}

	return reg_value;
}

static int sensor_s_register (struct v4l2_subdev *sd, const struct V4l2_dbg_register *para)
{
	int ret;
	unsigned short reg_addr;
	unsigned short reg_val;
	__u32 size;
	__U64 reg;
	 
	Size = para->size;
	Reg  = para->reg; 

	Reg_addr = (unsigned short) size;
	Reg_val  = (unsigned short) reg;
	
	ret = sensor_write (SD, REG_ADDR, reg_val);
	if (Ret < 0)
	{
		printk ("sensor_s_register ret =%d, reg_addr=%d, reg_val=%d\n", ret,reg_addr,reg_val);
	return
	ret;
}
#endif
The above code needs to note that in the data type struct V4l2_dbg_register In addition to the device pairing, it defines three variables, size,reg,val. The value of Val on my platform is not transmitted here, there is also a problem is that the kernel parameters can not be returned to the application layer, the specific reasons for not to do more in-depth analysis. Here, in order to achieve the ability to debug, I used an opportunistic way to achieve. I use the size parameter to pass the address, use the Reg parameter to pass the value of the register that needs to be set, and finally use the return value of the function to implement the Read register value back to the application tier.

(3) Application Layer Direct Operation register

The following is a test applet that directly accesses the interface implemented in the driver above via IOCTL

/*============================================================================= # filename:test.c # DESC:IOC TL to set/get vedio driver Register # author:licaibiao # Version: =========================================== ==================================*/#include <stdio.h> #include <fcntl.h> #include <stdlib.h> # Include <sys/types.h> #include <sys/ioctl.h> #include <linux/types.h> #include <linux/
	videodev2.h> #define FILE_VIDEO "/dev/video0" int Open_camera (void) {int fd;

	struct V4l2_input inp; FD = open (File_video, O_RDWR |
	o_nonblock,0);
		if (FD < 0) {fprintf (stderr, "%s open err \ n", File_video);
	Exit (Exit_failure);

	};
	Inp.index = 0;
	if ( -1 = = IOCTL (FD, Vidioc_s_input, &AMP;INP)) {fprintf (stderr, "Vidioc_s_input \ n");
} return FD;
}//dbg.match.type = V4l2_chip_match_i2c_driver;
strcpy (Dbg.match.name, "gc0308");
Dbg.match.type = v4l2_chip_match_i2c_addr;

DBG.MATCH.ADDR = 0x21; Void v4l2_write_reg (int fd, int reg_addr, int reg_val) {int ret;
	
	struct V4l2_dbg_register dbg;
	Dbg.match.type = 4;
	DBG.MATCH.ADDR = 1;
	Dbg.size = (__u32) reg_addr;
	Dbg.reg = (__u64) reg_val;

	Dbg.val = 0;
	RET = IOCTL (FD, Vidioc_dbg_s_register, &dbg);
	if (Ret < 0) {printf ("Sensor IOCTL data ERR ret =%d\n", ret);
	an int v4l2_read_reg (int fd, int reg_addr) {int ret;
	
	struct V4l2_dbg_register dbg;
	Dbg.match.type = 4;
	DBG.MATCH.ADDR = 1;
	Dbg.size = (__u32) reg_addr;
	Dbg.reg = 0;
	Dbg.val = 0;
	RET = IOCTL (FD, Vidioc_dbg_g_register, &dbg);
	if (Ret < 0) {printf ("Sensor IOCTL data ERR reg_addr=%x =%d\n", Reg_addr,ret);
return ret;
	} void Main (void) {int fd;
	int reg_addr= 0;

	int reg_val = 0;
	FD = Open_camera ();
	printf ("FD =%d\n", FD);
	REG_ADDR = 0x00;
	Reg_val = V4l2_read_reg (FD,REG_ADDR);


	printf ("V4l2 Read reg%x value =%x\n", reg_addr,reg_val);
	REG_ADDR = 0x0f;
	Reg_val = V4l2_read_reg (FD,REG_ADDR); printf ("V4l2 Read reg%X value =%x\n ", reg_addr,reg_val);
	REG_ADDR = 0x0f;
	Reg_val = 0x00;
	
	V4l2_write_reg (FD, REG_ADDR, reg_val);
	Usleep (10000);
	REG_ADDR = 0x0f;
	Reg_val = V4l2_read_reg (FD,REG_ADDR);
	
	printf ("V4l2 Read reg%x value =%x\n", reg_addr,reg_val);

Close (FD);

 }
The code above needs to be aware of the initialization of the struct v4l2_dbg_register. Mine is the linux3.10.65 version, which is defined in the Videodev2.h as follows:

/* vidioc_dbg_g_register and Vidioc_dbg_s_register * * #define V4L2_CHIP_MATCH_BRIDGE 0/* MATCH a Gainst chip ID on the "bridge" (0 for the bridge) * * * * #define V4L2_CHIP_MATCH_HOST V4l2_chip_match_bridge #define V4l2_chip_m Atch_i2c_driver 1/* match against I2C DRIVER name */#define V4L2_CHIP_MATCH_I2C_ADDR 2/* match against I2C 7-bit      Address */#define V4L2_CHIP_MATCH_AC97 3/* MATCH against Anciliary AC97 CHIP/#define V4l2_chip_match_subdev 4/* match against Subdev index/struct V4l2_dbg_match {__u32 type;/* Match type */union {/* match this
		Chip, meaning determined by type */__U32 addr;
	Char name[32];
};

} __attribute__ ((packed));
	struct V4l2_dbg_register {struct V4l2_dbg_match match;	__U32 size;
	/* Register Size in bytes * * __u64 reg;
__u64 Val; } __attribute__ ((packed)); 
It needs to do equipment matching, in my platform, I have used CHIP ID,I2C driver name,i2c address to match, have failed to achieve the matching device matching, can only use V4l2_chip_match_subdev to match, But in my cross-compilation tool chain, the first three methods are defined, but V4l2_chip_match_subdev is not defined, so in the above test program I will directly dbg.match.type = 4;

The results of the test applet are as follows:

/tmp #./test 
 V4l2 Read reg 0 value = 9b
 v4l2 Read reg f value =
 V4l2 Read reg F value = 0
/tmp # 
/ TMP # 
(4) porting the test program to the image transmission project

The idea is that, in the process of image transfer, create a thread that creates a message queue in the thread to receive the operation instructions. In addition, write a small program, send the operation instructions to the message queue, so that you can see the effect of the image in real time. The program code for the receiving end is as follows:

 /********************************************************************* * Licaibiao Add interface to debug V4L2 camera * /void V4l2_write_reg (int fd, int reg_addr, int
    Reg_val) {int ret;
    
    struct V4l2_dbg_register dbg;
    Dbg.match.type = 4;
    DBG.MATCH.ADDR = 1;
    Dbg.size = (__u32) reg_addr;
    Dbg.reg = (__u64) reg_val;
 
     Dbg.val = 0;
     RET = IOCTL (FD, Vidioc_dbg_s_register, &dbg); if (Ret < 0) {printf ("!!!!! SENSOR WRITE DATA ERR!!!!!
     ret =%d\n ", ret);
     else {printf ("write register 0x%x value = 0x%x \ n", reg_addr, Reg_val);
     } void V4l2_read_reg (int fd, int reg_addr) {int ret;
     
     struct V4l2_dbg_register dbg;
     Dbg.match.type = 4;
     DBG.MATCH.ADDR = 1;
     Dbg.size = (__u32) reg_addr;
     Dbg.reg = 0;
     Dbg.val = 0;
     RET = IOCTL (FD, Vidioc_dbg_g_register, &dbg); 
  if (Ret < 0) {       printf ("Sensor IOCTL data ERR reg_addr=%x =%d\n", Reg_addr,ret);
     else {printf ("read Register 0x%x value = 0x%x \ n", reg_addr, ret);
     } struct Msg_st {long int msg_type;
 Char Text[bufsiz];
 
 };
     void *main_v4l2_debug_camera (void* arg) {int running = 1;
     int msgid =-1;
     int reg_addr = 0;
     int reg_val = 0;
     int len = 0;
     int i = 0;
     int FD;
     struct MSG_ST data; 
     
     long int msgtype = 0;
     
     FD = * (int*) arg;
     
     printf ("\n\n\n Enter Main_v4l2_debug_camera thread \n\n\n"); MsgId = Msgget (key_t) 1234, 0666 |
     Ipc_creat);
         if (MsgId = = 1) {fprintf (stderr, "Msgget failed with Error:%d\n", errno);
     Exit (Exit_failure);
         while (running) {len = MSGRCV (MsgId, (void*) &data, Bufsiz, Msgtype, 0);
             if (Len < 0) {fprintf (stderr, "MSGRCV failed with errno:%d\n", errno); if (MSGctl (MsgId, Ipc_rmid, 0)) {printf ("Remove msg ERR \ n");
             } pthread_exit (0);
         Exit (Exit_failure);  }else {if (strncmp (Data.text, "End", 3) = = 0) {running =
                 0;
                 if (Msgctl (MsgId, Ipc_rmid, 0)) {printf ("Remove msg ERR \ n");
             } pthread_exit (0); For (I=1 i<len-1; i++) {if ((data.text[i) >= ' 0 ') &AMP;&A MP; (Data.text[i] <= ' 9 ") | | ((Data.text[i] >= ' A ') && (data.text[i] <= ' F ') | | ((Data.text[i] >= ' a ') && (Data.text[i] <= ' f ') | |
                 (Data.text[i] = = ") {}else {printf ("1plase enter:read/write:reg_addr:reg_value e.g \ n ");
                 Goto err; } if ((data.text[0]== ' W ') | |
             (data.text[0]== ' W ')) {if ((data.text[1]!= ') | | |
                 (Data.text[4]!= ")
                     {printf ("2plase enter:read/write:reg_addr:reg_value e.g");
                 Goto err; 
                 } sscanf (&data.text[2], "%x", &reg_addr);  
                 SSCANF (&data.text[5], "%x", &reg_val);
                 printf ("write:addr =%x val =%x\n", reg_addr, Reg_val);
             V4l2_write_reg (FD, Reg_addr,reg_val); if (data.text[0]== ' R ') | |
             (data.text[0]== ' R ')) {if (data.text[1]!= ') {printf ("3plase Enter:rea
                     D/write:reg_addr:reg_value e.g);
    Goto err;             } sscanf (&data.text[2], "%x", &reg_addr);
                 printf ("read:addr =%x \ n", reg_addr);
             V4l2_read_reg (FD, REG_ADDR);
     } err:i = i;
 }

 }
 
 /********************************************************************/
To add a thread:

if (Pthread_create (&v4l2_contect->msg_id, NULL, Main_v4l2_debug_camera, &V4L2_CONTECT->MCAMFD))
{
    printf ("V4L2 pthread create ERR!!!! \ n ");

The code that sends the message queue side is implemented as follows:

/*============================================================================= # filename:msg_test.c # Desc:      Send message to camera process to ioctl V4L2 # Author:licaibiao # Version: # lastchange:2017-01-20 # History: =============================================================================*/#include <unistd.h > #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/msg.h> #include &
	lt;errno.h> #define Max_text struct Msg_st {long int msg_type;
Char Text[max_text];

};
	int main () {int running = 1;
	struct MSG_ST data;
	Char Buffer[bufsiz];
	int msgid =-1;

	int Len; MsgId = Msgget (key_t) 1234, 0666 |
	Ipc_creat);
		if (MsgId = = 1) {fprintf (stderr, "Msgget failed with Error:%d\n", errno);
	Exit (Exit_failure);
	printf ("Enter cmd format,r/w,addr,val:r/w");
		while (running) {printf ("Enter cmd:");
		Fgets (buffer, bufsiz, stdin);    
		Data.msg_type = 1; StrcpY (data.text, buffer);	
		Len = strlen (Data.text);
			if (Msgsnd (MsgId, (void*) &data, len, 0) = = 1) {fprintf (stderr, "msgsnd failed\n");
		Exit (Exit_failure);
		} if (strncmp (buffer, "End", 3) = = 0) running = 0;
	Usleep (100000);
} exit (exit_success); }

The results of the operation are as follows:

/tmp #./send 
Enter cmd format,r/w,addr,val:  r/w 
Enter cmd:r
Read Register 0x14 value = 0x10
  enter cmd:w
Write register 0x14 value = 0x13 Enter cmd:end MSGRCV failed with
errno:43
From the results above, you can see that the register read and settings are normal, but in my platform to execute: Msgctl (msgid, Ipc_rmid, 0) when the message queue to delete the problem, resulting in the failure of normal exit, the problem followed by time to reposition.


On the other, we can realize the on-line debugging of V4L2 point-to-point transmission image, and also leave some problems to be followed.

(i) The Val variable value in struct V4l2_dbg_register cannot be transferred from the application layer to the drive layer.

(b) Variable values in struct V4l2_dbg_register cannot be fed back to the application layer from the driver layer.

(iii) Error deleting Message Queuing at application layer end of application.


This is the recent debugging interface, recorded to facilitate the reference, at the same time, for the remaining problems, if any friends have a solution, welcome to discuss.

                                                                    &NB Sp                                   &NB Sp                                   &NB Sp                                   &NB Sp                        

2017.01.20













Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.