內(nèi)存: 1GB 存儲(chǔ): 4GB
詳細(xì)參數(shù) https://m.tb.cn/h.3wMaSKm
開發(fā)板交流群 641395230
目前創(chuàng)新互聯(lián)已為千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、石鼓網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
全志A64設(shè)備樹結(jié)構(gòu)體
#include <linux/of.h>
//設(shè)備樹里的每個(gè)設(shè)備及每個(gè)設(shè)備子節(jié)點(diǎn)都用此結(jié)構(gòu)體描述
struct device_node
{
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct property *properties; //屬性
struct property *deadprops; /* removed properties */
struct device_node *parent; //在設(shè)備子節(jié)點(diǎn)對(duì)象,指向?qū)儆诘脑O(shè)備對(duì)象
struct device_node *child; //在設(shè)備對(duì)象,指向子節(jié)點(diǎn)
struct device_node *sibling; //指向同級(jí)的下一個(gè)對(duì)象.
struct device_node *next; /* next device of same type */ //應(yīng)是指向device_type是同樣的對(duì)象
struct device_node *allnext; /* next in list of all nodes */ ...
};
//下面函數(shù)用于獲取設(shè)備樹里的設(shè)備節(jié)點(diǎn)及設(shè)備子節(jié)點(diǎn)extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
//通過名字查找相應(yīng)的設(shè)備節(jié)點(diǎn)static inline int of_get_child_count(const struct device_node *np);
//獲取指定設(shè)備的子節(jié)點(diǎn)個(gè)數(shù)extern struct device_node *of_find_node_by_path(const char *path);
//通過路徑來獲取設(shè)備節(jié)點(diǎn),可用于獲取設(shè)備子節(jié)點(diǎn)extern struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
//通過指定的device_type來獲取設(shè)備節(jié)點(diǎn)
//下面函數(shù)用于獲取設(shè)備節(jié)點(diǎn)或設(shè)備子節(jié)點(diǎn)的屬性
static inline int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
extern int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value);
extern int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz);
extern int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);
extern int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);
extern int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);
extern int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
首先增加節(jié)點(diǎn),修改dtsi文件。vim /lichee/linux-3.10/arch/arm64/boot/dts/sun50iw1p1-pinctrl.dtsi
驅(qū)動(dòng)代碼:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MY_DEVICE_NAME "my_led_device"
// 獲取到設(shè)備樹中到節(jié)點(diǎn)
static int gpio = -1;
int get_irqno_from_node(void)
{
struct gpio_config config;
struct device_node *np = of_find_node_by_path("/leds");
if(np){
printk("find node ok\n");
}
else{
printk("find node failed\n");
}
gpio = of_get_named_gpio_flags(nd, "gpios", i, (enum of_gpio_flags *)&config);// 從設(shè)備樹中讀取gpios的GPIO配置編號(hào)和標(biāo)志
if(!gpio_is_valid(gpio)){
//判斷該 GPIO 編號(hào)是否有效,有效gpio_request 則申請(qǐng)占用該 GPIO。如果初始化過程出錯(cuò),需要調(diào)用 gpio_free 來釋放之前申請(qǐng)過且成功的 GPIO
printk("gpio isn't valid\n");
return -1;
}
if(gpio_request(gpio, "leds") < 0)
printk("gpio request failed %d\n", gpio);
gpio_direction_output(gpio, 1); //關(guān)燈
return 0;
}
static int my_open (struct inode *node, struct file *filp)
{
if(gpio)
{
printk("open ok\n");
}
else
{
return -EINVAL;
}
return 0;
}
static ssize_t my_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
unsigned char val;
copy_from_user(&val, buf, 1);
printk(" gpl_dat address 0x%x\n",gpl_dat);
if (val)
{
gpio_direction_output(gpio, 0); //關(guān)燈
printk("led on\n");
}
else
{
gpio_direction_output(gpio, 1); //關(guān)燈
printk("led off\n");
}
return 1;
}
static const struct file_operations my_led_fops = {
//step 1 :定義file_operations結(jié)構(gòu)體
.open = my_open,
.write = my_write,
};
//step 1 :
static struct class *led_class;
static struct cdev *pcdev; //定義一個(gè)cdev指針
static dev_t n_dev; //第一個(gè)設(shè)備號(hào)(包含了主和次)
static int __init led_device_init(void)
{//step 2 :注冊(cè)
int ret = -1;
pcdev = cdev_alloc();//分配cdev結(jié)構(gòu)空間
if(pcdev == NULL) {
printk(KERN_EMERG" cdev_alloc error\n");
ret = -ENOMEM; /* 分配失敗 */
return ret;
}
//2. 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)
ret = alloc_chrdev_region(&n_dev, 0 , 2, MY_DEVICE_NAME);
if(ret < 0 ) {
//釋放前面成功的資源
kfree(pcdev); /*釋放cdev結(jié)構(gòu)空間 */
printk(KERN_EMERG"alloc_chrdev_region error\n");
return ret;
}
cdev_init(pcdev, &my_led_fops); //初始化cdev結(jié)構(gòu) /* 建立cdev和file_operations之間的連接 */
/*
或這樣初始化cdev結(jié)構(gòu)
pcdev->owner = THIS_MODULE;
pcdev->ops = &my_led_fops;
*/
ret = cdev_add(pcdev, n_dev, 2) ;// 向內(nèi)核里面添加一個(gè)驅(qū)動(dòng),注冊(cè)驅(qū)動(dòng)
if(ret < 0 ) {
//釋放前面成功的資源
unregister_chrdev_region(n_dev, 2); /* 釋放前面申請(qǐng)的調(diào)和號(hào)*/
kfree(pcdev); /* 釋放cdev結(jié)構(gòu)空間 */
printk(KERN_EMERG"alloc_chrdev_region error\n");
return ret;
}
/*自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)/dev/SinlinxA64_LED*/
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, n_dev, NULL, "SinlinxA64_LED");
get_irqno_from_node();
printk(KERN_EMERG"cdev ok\n");
return 0;
}
static void __exit led_device_exit(void)
{ //step 2 :注銷
//注銷cdev結(jié)構(gòu)
cdev_del(pcdev);
//釋放設(shè)備號(hào)
unregister_chrdev_region(n_dev, 2); /*起始設(shè)備號(hào)(主、次) 連續(xù)的次設(shè)備號(hào)數(shù)量*/
//釋放cdev結(jié)構(gòu)空間
kfree(pcdev);
device_destroy(led_class, n_dev);
class_destroy(led_class);
gpio_free(gpio);
printk(KERN_EMERG"cdev_del ok\n");
}
module_init(led_device_init);
module_exit(led_device_exit);
MODULE_LICENSE("GPL");
參考文章:https://blog.csdn.net/jklinux/article/details/82382066