Recently, we are working on a board of Ruixin micro platform , model :rk3399
, Just started these days , I've been working on the environment a few days ago , Be familiar with this board , This board runs Android7.1 System of . There are not a lot of things that open to this on the Internet , I also want to make a record . then , Let's go :

I have been familiar with the directory structure of this board , Where is the device tree file , And compiling scripts , About compiling source code ,firefly The forum also talked about , I won't say much about this one , Let's talk about what I did first : Wrote one led drive , It's simple , The purpose, of course, is to light the lights , Let's experience how the driver of this platform is different from what I have been exposed to before , So test it first , Here are some of the ways I use them :

* Compile into kernel , This way Power on System 1 , The module will be loaded automatically at a certain time , Enter the driver's probe, This is the only difference between the two approaches
* difference : module_platform_driver(led_driver); module_exit(led_exit);
MODULE_LICENSE("GPL");
 

     3. Does not compile into the kernel

Driver writing mode :1. Character device registration 2. Register as miscellaneous device

Direct code :
#include <linux/kernel.h> #include <linux/gpio.h> #include <linux/init.h>
#include <linux/module.h>  #include <linux/delay.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_platform.h> #include
<linux/version.h> #include <linux/init.h> #include <linux/fs.h> #include
<linux/sched.h> #include <linux/pm.h> #include <linux/sysctl.h> #include
<linux/proc_fs.h> //#include <linux/platform_device.h> #include <asm/uaccess.h>
#include <asm/io.h> #define GPIO_LOW 0 #define GPIO_HIGH 1 int gpio; int major;
static struct class *cls; static int led_open(struct inode *inode, struct file
*file) {     printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);        
 return 0;     } static ssize_t led_write(struct file *file, const char __user
*buf, size_t count, loff_t * ppos) {     int val;     int ret;   
 printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);     ret =
copy_from_user(&val, buf, count); //    copy_to_user();     if (val == 1)     {
        gpio_set_value(gpio,GPIO_LOW);     }     else     {       
 gpio_set_value(gpio,GPIO_HIGH);     }          return 0; } static struct
file_operations led_fops = {     .owner  =   THIS_MODULE,        .open   =  
led_open,          .write    =    led_write,        }; static int
led_probe(struct platform_device *pdev) {     int ret ;     int i;     enum
of_gpio_flags flag;     struct device_node *led_node = pdev->dev.of_node;     
         printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);     gpio =
of_get_named_gpio_flags(led_node,"led-gpio", 0,&flag);     if
(!gpio_is_valid(gpio)){         printk(KERN_INFO "hello: invalid gpio :
%d\n",gpio);         return -1;     }      ret = gpio_request(gpio, "led");   
 if (ret) {         gpio_free(gpio);         return -EIO;     }   
 gpio_direction_output(gpio, GPIO_HIGH);     for(i=0; i < 10; i++)     {       
 gpio_set_value(gpio,GPIO_LOW);         mdelay(500);       
 gpio_set_value(gpio,GPIO_HIGH);         mdelay(500);     }               major
= register_chrdev(0, "myled", &led_fops);     cls = class_create(THIS_MODULE,
"myled");     device_create(cls, NULL, MKDEV(major, 0), NULL, "led");         
      gpio_set_value(gpio,GPIO_LOW);              printk(KERN_INFO "%s-%d:
exit\n",__FUNCTION__,__LINE__);                    return 0;  //return Ok }
static int led_remove(struct platform_device *pdev) {      printk(KERN_INFO
"Enter %s\n", __FUNCTION__);     gpio_free(gpio);     device_destroy(cls,
MKDEV(major, 0));     class_destroy(cls);     unregister_chrdev(major,
"myled");     return 0; } static const struct of_device_id of_led_match[] = {
    { .compatible = "led_test" },     { /* Sentinel */ } }; static struct
platform_driver led_driver = {     .probe        = led_probe,     .remove      
 = led_remove,     .driver        = {         .name    = "led",       
 .owner    = THIS_MODULE,         .of_match_table    = of_led_match,     }, };
static int __init led_init(void) {     printk(KERN_INFO "Enter %s\n",
__FUNCTION__);     return platform_driver_register(&led_driver);     return 0;
} static void __exit led_exit(void) {   
 platform_driver_unregister(&led_driver);     printk(KERN_INFO "Exit Hello
world\n"); } module_init(led_init); module_exit(led_exit);
MODULE_LICENSE("GPL");
 

Another one
​ ​ #include <linux/kernel.h> #include <linux/gpio.h> #include
<linux/miscdevice.h> #include <linux/init.h> #include <linux/module.h> #include
<linux/delay.h> #include <linux/of.h> #include <linux/of_gpio.h> #include
<linux/of_platform.h> #include <linux/version.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/sched.h> #include <linux/pm.h> #include
<linux/sysctl.h> #include <linux/proc_fs.h> //#include
<linux/platform_device.h> #include <asm/uaccess.h> #include <asm/io.h> #define
GPIO_LOW 0 #define GPIO_HIGH 1 int gpio; int major; static long hello_ioctl(
struct file *files, unsigned int cmd, unsigned long arg){ //printk("cmd is
%d,arg is %d\n",cmd,arg); if(cmd > 1){ printk(KERN_EMERG "cmd is 0 or 1\n"); }
if(arg > 1){ printk(KERN_EMERG "arg is only 1\n"); } gpio_set_value(gpio,cmd);
return 0; } static int hello_release(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello release\n"); return 0; } static int hello_open(struct
inode *inode, struct file *file){ printk(KERN_EMERG "hello open\n"); return 0;
} static struct file_operations hello_ops = { .owner = THIS_MODULE, .open =
hello_open, .release = hello_release, .unlocked_ioctl = hello_ioctl, }; static
struct miscdevice hello_dev = { .minor = MISC_DYNAMIC_MINOR, .name =
"hello-ctl", .fops = &hello_ops, }; static int led_probe(struct platform_device
*pdev) { int ret ; int i; enum of_gpio_flags flag; struct device_node *led_node
= pdev->dev.of_node; printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);
gpio = of_get_named_gpio_flags(led_node,"led-gpio", 0,&flag); if
(!gpio_is_valid(gpio)){ printk(KERN_INFO "hello: invalid gpio : %d\n",gpio);
return -1; } ret = gpio_request(gpio, "led"); if (ret) { gpio_free(gpio);
return -EIO; } gpio_direction_output(gpio, GPIO_HIGH); for(i=0; i < 10; i++) {
gpio_set_value(gpio,GPIO_LOW); mdelay(500); gpio_set_value(gpio,GPIO_HIGH);
mdelay(500); } misc_register(&hello_dev); gpio_set_value(gpio,GPIO_LOW);
printk(KERN_INFO "%s-%d: exit\n",__FUNCTION__,__LINE__); return 0; //return Ok
} static int led_remove(struct platform_device *pdev) { printk(KERN_EMERG
"\tremove\n"); gpio_free(gpio); misc_deregister(&hello_dev); return 0; } static
const struct of_device_id of_led_match[] = { { .compatible = "led_test" }, { /*
Sentinel */ } }; static struct platform_driver led_driver = { .probe =
led_probe, .remove = led_remove, .driver = { .name = "led", .owner =
THIS_MODULE, .of_match_table = of_led_match, }, };
module_platform_driver(led_driver); module_exit(led_exit);
MODULE_LICENSE("GPL"); ​ ​
in addition , The driver under the platform , Something needs to be changed in the kernel , This board involves the device tree , The device tree file needs to be modified :

My device tree file path :/rk3399/source/g3399-v7-1-2-20180529/kernel/arch/arm64/boot/dts/rockchip

Maybe different boards will be slightly different , Device tree file :g3399-baseboard.dtsi( It depends on you ), The device tree is not described , Self study

Add content :( At random )
hello-led{                 compatible = "led_test";                 led-gpio =
<&gpio0 8 GPIO_ACTIVE_LOW>;                 status = "okay";         };
The next step is to increase Kconfig and Makefile Create a new directory Put it in Directory location /path/xxxxxxx/kernel/driver/

In this directory Makefile newly added :obj-y             += test/

Kconfig newly added :
source "drivers/test/Kconfig"
above test For folder name

Next, enter test Folder Add own Makefile and Kconfig

The details are as follows :Makefile:
obj-$(CONFIG_HELLO)     += hello.o
 

hello It's the driver .c Name of the document  CONFIG_HELLO This general naming format is CONFIG_xxx

Kconfig:
config HELLO         tristate "led test"         help           Hello for test
Pay attention to this place there HELLO and Makefile inside CONFIG_xxx Medium xxx agreement ,tristate "led test"
The contents in double quotation marks can be modified by yourself ,help It's help information , Modify by yourself .

About procedure , There are some in the forum demo, It can be referred to , But it's up to you

About driver run results :
g3399:/storage/0000-0000 # insmod test test.ko         test_char.ko
g3399:/storage/0000-0000 # insmod test.ko                                      
[  355.467922] Exit Hello world [ 3372.497665] Enter led_init [ 3372.498181]
led_probe-77: enter [ 3382.500052] led_probe-104: exit g3399:/storage/0000-0000
# rmmod test [ 3385.692121]  remove g3399:/storage/0000-0000 # 
So far, a test program has been written , 1. Implementation , The result is very helpless ( This is the test program , Not a driver )
g3399:/storage/0000-0000 # ./cmd_test                                        
  /system/bin/sh: ./cmd_test: can't execute: Permission denied
About its authority :-rwxrwx--x 1 root sdcard_rw   8502 2018-11-05 00:01 cmd_test

I feel it's OK , I can't even access it , in addition : Discover the file system usage of development board cp On command , The following problems arise :
g3399:/storage/0000-0000 # cp -rf test.ko ../../                             
cp: ../..//test.ko: Read-only file system

The above reasons have been solved , The reason is that when the file system is compiled, the corresponding permissions of the file directory are not given , terms of settlement , Copy file to /data/....../...../ I can't remember the specific catalogue ,ls
-l Command to see the permissions of each directory

Note: All the orders above are in root Run under permission

Last but not least ; The device node created by the driver can be used ls /dev see

 

Technology