error = wait_event_interruptible(mylog_wait,!is_mylog_empty());
/* If copy_to_user is correct, the string is obtained successfully*/
while( !error && (mylog_getc(&c)) && i < count ){
error = __put_user(c, buf); //Equivalent to copy_to_user
buf++;
i++;
}
if(!error)
error = i;
return error;
}
When the application uses cat to read /proc/mymsg, if the program is started in a non-blocking manner and buff is empty, it returns directly, otherwise it puts the program into an interruptible sleep.
The condition for waking up is that buff is not empty. When the program is awakened, the copy_to_user function is called to copy the data to the user process for printing.
8. Modify the test driver err_led.c.
First, import the myprintk function externally, and then modify all the printk functions of the test driver to myprintk function.
1 extern int myprintk(const char *fmt, ...); //Introduce external declaration
2
3 static int key_open(struct inode *inode, struct file *file)
4 {
5 myprintk("<0>function open!nn"); //Change printk to myprintk
6 return 0;
7 }
9. Compile and test:
Pay attention to the order in which you load the drivers.
① Load the mymsg.ko driver
② Load the test/err_led.ko driver: Found that the err_led light on the board is flashing, wait for the led to finish flashing
③ Read cat /proc/mymsg: It is found that the message that our err_led wants to print is successfully printed, as shown below
④ Uninstall test/err_led.ko: Found that err_led on the board is flashing, wait until the flashing is finished
⑤ Read cat /proc/mymsg: There is an additional goodbye message at the end of the message, success
⑥Uninstall mymsg.ko driver
Attach the driver mymsg_4.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10
11
12 #define MYLOG_BUF_LEN 1024
13
14 //Define the entry structure of proc
15 static struct proc_dir_entry *myentry;
16 static char mylog_buf[MYLOG_BUF_LEN]; //data buffer
17 static char tmp_buf[MYLOG_BUF_LEN]; //data buffer
18 static int mylog_r = 0;
19 static int mylog_w = 0;
20
21 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);
twenty two
23 //Judge whether it is empty
24 static int is_mylog_empty(void)
25 {
26 return (mylog_r == mylog_w);
27 }
28 //Judge whether it is full
29 static int is_mylog_full(void)
30 {
31 return (((mylog_w + 1) % MYLOG_BUF_LEN) == mylog_r);
32 }
33 //Write characters
34 static void mylog_putc(char c)
35 {
36 if(is_mylog_full)
37 {
38 //Discard a data
39 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
40 }
41 mylog_buf[mylog_w] = c;
42 mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;
43
44 /* Wake up the process waiting for data */
45 wake_up_interruptible(&mylog_wait);
46 }
47 //Read characters
48 static int mylog_getc(char *p)
49 {
50 if(is_mylog_empty())
51 return 0;
52 *p = mylog_buf[mylog_r];
53 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
54 return 1;
55 }
56
57 //Print output Refer to sprintf in vsprintf.c
58 int myprintk(const char *fmt, ...)
59 {
60 va_list args;
61 int i,j;
62
63 va_start(args, fmt);
64 i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
65 va_end(args);
66 for(j = 0; j
67 {
68 mylog_putc(tmp_buf[j]);
69 }
70 return 1;
71 }
72 EXPORT_SYMBOL(myprintk);
73
74 //Realize the read function, refer to kmsg.c
75 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
76 {
77 int error;
78 int i = 0; //The number of data read
79 char c;
80
81 //Open with non-blocking mode and the data queue is empty
82 if ((file->f_flags & O_NONBLOCK) && is_mylog_empty())
83 return -EAGAIN;
84
85 //Wait until the queue is not empty
86 error = wait_event_interruptible(mylog_wait,!is_mylog_empty());
87
88 /* If copy_to_user is correct, the string is obtained successfully*/
89 while( !error && (mylog_getc(&c)) && i < count ){
90 error = __put_user(c, buf); //Equivalent to copy_to_user
91 buf++;
92 i++;
93 }
94 if(!error)
95 error = i;
96 return error;
97 }
98
99 //Define file_operation structure
100 static struct file_operations proc_mymsg_operations = {
101 .read = mymsg_read,
102 };
103 //Entry function
104 static int mymsg_init(void)
105 {
106 //sprintf(mylog_buf, "%s", "abcdefghijklmnn"); //Simulate the data of forged buf
107 //Create proc entry
108 myentry = create_proc_entry("mymsg",S_IRUSR,NULL); //S_IRUSR:400 read only
109
110 if(myentry)
111 myentry->proc_fops = &proc_mymsg_operations;
112
113
114 return 0;
115 }
116 //Export function
117 static void mymsg_exit(void)
118 {
119 remove_proc_entry("mymsg", NULL);
120 }
121
122 module_init(mymsg_init);
123 module_exit(mymsg_exit);
124
125 MODULE_LICENSE("GPL");
126 MODULE_AUTHOR("Lover Cher");
127
128
129 /*
130 1. Ring Buffer
131 Empty: R == W
132 write: buf[W] = val;
133 W = (W+1) % 10;
134 Read: val = buf[R]
135 R = (R+1) % 10
136
137
138
139 */
Attached is the test driver err_led.c:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14
15 #define Driver_NAME "err_led_dev"
16 #define DEVICE_NAME "err_led_dev"
17
18 static int major = 0;
19
20 //auto to create device node
21 static struct class *drv_class = NULL;
22 static struct class_device *drv_class_dev = NULL;
twenty three
24 //Register base address;
25 static unsigned long base_iomux; //iomux base address 0X 43FA C000 - 0X 43FA FFFF
26 static unsigned long base_gpio3; //gpio3 0X 53FA 4000 - 0X 53FA 7FFF
27 //MUX_CTL mode selection configuration register
28 #define MUX_CTL (*(volatile unsigned long *)(base_iomux + 0x0060))
29 //PAD_CTL GPIO common function settings
30 #define PAD_CTL (*(volatile unsigned long *)(base_iomux + 0x0270))
31 //GPIO DR data register DR
32 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000))
33 // GPIO GDIR direction control register GDIR
34 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004))
35
36
37 extern int myprintk(const char *fmt, ...);
38
39 static int key_open(struct inode *inode, struct file *file)
40 {
41 myprintk("<0>function open!nn");
42 return 0;
43 }
44
45 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
46 {
47 return 0;
48 }
49
50 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
51 {
52 myprintk("<0>function write!nn");
53 return 1;
54 }
55
56 static int key_release(struct inode *inode, struct file *filp)
57 {
58 myprintk("<0>function write!nn");
59 return 0;
60 }
61
62 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
63 {
64 myprintk("<0>function ioctl!nn");
65 return 0;
66 }
67 static struct file_operations key_fops = {
68 .owner = THIS_MODULE, /* This is a macro that pushes to the __this_module variable that is automatically created when compiling the module*/
69 .open = key_open,
70 .read = key_read,
71 .write = key_write,
72.release= key_release,
73 .ioctl = key_ioctl,
74 };
75
76 void gpio_addr(void){
77 myprintk("<0>addr base_iomux : %x n",base_iomux);
78 myprintk("<0>addr base_gpio3 : %x n",base_gpio3);
79 myprintk("<0>addr MUX_CTL : %x n",&MUX_CTL);
80 myprintk("<0>addr PAD_CTL : %x n",&PAD_CTL);
81 myprintk("<0>addr GDIR_GPIO3 : %x n",&GDIR_GPIO3);
82 myprintk("<0>addr DR_GPIO3 : %x n",&DR_GPIO3);
83 }
84
85 void led_on_off(void){
86 ssleep(1);
87 DR_GPIO3 |= (0x01 << 23); //Set GPIO2_23 to 1
88 ssleep(1);
89 DR_GPIO3 &= ~(0x01 << 23); // Clear GPIO2_23
90 ssleep(1);
91 DR_GPIO3 |= (0x01 << 23); //Set GPIO2_23 to 1
92 ssleep(1);
93 DR_GPIO3 &= ~(0x01 << 23); // Clear GPIO2_23
94 ssleep(1);
95 DR_GPIO3 |= (0x01 << 23); //Set GPIO2_23 to 1
96 ssleep(1);
97 DR_GPIO3 &= ~(0x01 << 23); // Clear GPIO2_23
98 ssleep(1);
99 DR_GPIO3 |= (0x01 << 23); //Set GPIO2_23 to 1
100 ssleep(1);
101 DR_GPIO3 &= ~(0x01 << 23); //Clear GPIO2_23
102 ssleep(1);
103 DR_GPIO3 |= (0x01 << 23); //Set GPIO2_23 to 1
104 }
105
106 static int __init key_irq_init(void)
107 {
108 myprintk("<0>nHello,this is %s module!nn",Driver_NAME);
109 //register and mknod
110 major = register_chrdev(0,Driver_NAME,&key_fops);
111 drv_class = class_create(THIS_MODULE,Driver_NAME);
112 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/
113
114 //IO port application ioremap can directly access these addresses through pointers
115 base_iomux = ioremap(0x43FAC000,0xFFF);
116 base_gpio3 = ioremap(0x53FA4000,0xFFF);
Previous article:Debug analysis: PC pointer analysis error based on kernel error information
Next article:iMX257 pin configuration function/memory read and write function
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- TI C2000 MCU DesignDRIVE Solutions for Industrial Motor Drives
- Application of reflective memory network in long-distance distributed system
- Based on AM335X development board (ARM Cortex-A8)——Linux system user manual (Part 2)
- DFRobot Motor Drive Evaluation Summary
- [GD32E231 DIY Contest] 02. Why can’t the PWM duty cycle be changed in the external interrupt service function?
- 【MicroPython】STM32 branch allows selection of USB FS or USB HS
- REF3133 Issues
- Look at other people’s USB soldering irons, do I still need mine?
- How to Choose the Right Circuit Protection
- Live Review: RSL15 - ON Semiconductor's More Efficient, Smarter and Safer BLE 5.2 Bluetooth Chip