中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

建設(shè)銀行網(wǎng)站供應(yīng)鏈線(xiàn)上職業(yè)技能培訓(xùn)平臺(tái)

建設(shè)銀行網(wǎng)站供應(yīng)鏈,線(xiàn)上職業(yè)技能培訓(xùn)平臺(tái),網(wǎng)站欄目頁(yè)如何做,如何做網(wǎng)站上抓視頻文章目錄一、配置連接說(shuō)明二、更新設(shè)備樹(shù)(1)將led燈引腳添加到pinctrl子系統(tǒng)(2)設(shè)備樹(shù)中添加LDE燈的設(shè)備樹(shù)節(jié)點(diǎn)(3)編譯更新設(shè)備樹(shù)三、驅(qū)動(dòng)開(kāi)發(fā)與測(cè)試(1)編寫(xiě)設(shè)備驅(qū)動(dòng)代碼&#xff08…

文章目錄

    • 一、配置連接說(shuō)明
    • 二、更新設(shè)備樹(shù)
      • (1)將led燈引腳添加到pinctrl子系統(tǒng)
      • (2)設(shè)備樹(shù)中添加LDE燈的設(shè)備樹(shù)節(jié)點(diǎn)
      • (3)編譯更新設(shè)備樹(shù)
    • 三、驅(qū)動(dòng)開(kāi)發(fā)與測(cè)試
      • (1)編寫(xiě)設(shè)備驅(qū)動(dòng)代碼
      • (2)編寫(xiě)驅(qū)動(dòng)測(cè)試代碼
      • (3)Makefile
    • 四、結(jié)果展示
    • 五、ioctl接口講解


前面我們介紹了Linux設(shè)備模型、平臺(tái)設(shè)備驅(qū)動(dòng)、設(shè)備樹(shù)(device tree)、GPIO子系統(tǒng)以及pinctrl子系統(tǒng)等,大家看這篇文章之前需要提前知道的基礎(chǔ)都在這篇文章中:

Linux設(shè)備模型、平臺(tái)設(shè)備驅(qū)動(dòng)、設(shè)備樹(shù)(device tree)、GPIO子系統(tǒng)以及pinctrl子系統(tǒng)介紹

有部分函數(shù)沒(méi)有涉及到的最后會(huì)講解。


一、配置連接說(shuō)明

我們做控制led燈的時(shí)候用的是下面三個(gè)管腳:
在這里插入圖片描述

控制LED燈連接實(shí)圖:
在這里插入圖片描述


二、更新設(shè)備樹(shù)

(1)將led燈引腳添加到pinctrl子系統(tǒng)

將我們的引腳添加到 igkboard.dts 下的 &iomuxc 節(jié)點(diǎn)下:

pinctrl_my_gpio_leds: my-gpio-leds {fsl,pins = <   MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x17059 /* led run */MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x17059MX6UL_PAD_JTAG_MOD__GPIO1_IO10     0x17059>;};

引腳定義都是在文件::~/imx6ull/imx6ull/bsp/kernel/linux-imx/arch/arm/boot/dts下可以查看:

wangdengtao@wangdengtao-virtual-machine:~/imx6ull/imx6ull/bsp/kernel/linux-imx/arch/arm/boot/dts$ cat imx6ul-pinfunc.h 
/* SPDX-License-Identifier: GPL-2.0-only */
/** Copyright 2014 - 2015 Freescale Semiconductor, Inc.*/#ifndef __DTS_IMX6UL_PINFUNC_H
#define __DTS_IMX6UL_PINFUNC_H/** The pin function ID is a tuple of* <mux_reg conf_reg input_reg mux_mode input_val>*/
#define MX6UL_PAD_BOOT_MODE0__GPIO5_IO10		0x0014 0x02a0 0x0000 5 0
#define MX6UL_PAD_BOOT_MODE1__GPIO5_IO11		0x0018 0x02a4 0x0000 5 0#define MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01      0x0020 0x02ac 0x0000 5 0
#define MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x003c 0x02c8 0x0000 5 0
#define MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00		0x001c 0x02a8 0x0000 5 0
#define MX6UL_PAD_JTAG_MOD__GPIO1_IO10          0x0044 0x02d0 0x0000 5 0

(2)設(shè)備樹(shù)中添加LDE燈的設(shè)備樹(shù)節(jié)點(diǎn)

將我們的 my_leds 設(shè)備節(jié)點(diǎn)添加在 igkbosrd.dts 的根節(jié)點(diǎn)下:

       my_leds {compatible = "my-gpio-leds"; /*設(shè)置“compatible”屬性值,與led的平臺(tái)驅(qū)動(dòng)做匹配*/pinctrl-names = "default"; /*定義引腳狀態(tài)*/pinctrl-0 = <&pinctrl_my_gpio_leds>; /*指定LED燈的引腳pinctrl信息*/status = "okay";led-gpios  = <&gpio5 8 GPIO_ACTIVE_HIGH>,/*指定引腳使用的哪個(gè)GPIO 引腳名字= <&GPIO組 GPIO編號(hào) 有效電平>*/<&gpio5 1 GPIO_ACTIVE_HIGH>,<&gpio1 10 GPIO_ACTIVE_HIGH>;default-state = "off";};

(3)編譯更新設(shè)備樹(shù)

添加完成之后我們需要去 linux-imx 文件夾下執(zhí)行 make dtbs 編譯一下我們的設(shè)備樹(shù),然后將開(kāi)發(fā)板上如下的文件路徑下的 igkboard.dtb 以及 zImage(linux下的zImage文件再/bootl路徑下) 修改。

wangdengtao@wangdengtao-virtual-machine:~/imx6ull/imx6ull/bsp/kernel/linux-imx$ make dtbs
root@igkboard:~# find / -name zImage
/run/media/mmcblk1p1/zImage
root@igkboard:~# find / -name igkboard.dtb
/run/media/mmcblk1p1/igkboard.dtb

替換之后執(zhí)行 sudo reboot 即可。

使用新的設(shè)備樹(shù)重新啟動(dòng)之后正常情況下會(huì)在開(kāi)發(fā)板的 “/proc/device-tree” 目錄下生成 “my_leds” 設(shè)備樹(shù)節(jié)點(diǎn)。如下所示。

root@igkboard:~# cd /proc/device-tree/
root@igkboard:/proc/device-tree# ls
'#address-cells'   3p3v          backlight-lcd   clock-di0   compatible   leds              mqs       panel        pxp_v4l2             regulator@0       soc         w1
'#size-cells'      __symbols__   chosen          clock-di1   cpus         memory@80000000   my_leds   pmu          regulator-peri-3v3   reserved-memory   sound-mqs1p8v              aliases       clock-cli       clock-osc   keys         model             name      pwm-buzzer   regulator-sd1-vmmc   serial-number     timer

進(jìn)入節(jié)點(diǎn)文件我們可以看到我們?cè)O(shè)置的gpio子系統(tǒng)的屬性:

root@igkboard:/proc/device-tree# cd my_leds/
root@igkboard:/proc/device-tree/my_leds# ls
compatible  default-state  led-gpios  name  pinctrl-0  pinctrl-names  status

三、驅(qū)動(dòng)開(kāi)發(fā)與測(cè)試

(1)編寫(xiě)設(shè)備驅(qū)動(dòng)代碼

代碼中涉及到的字符設(shè)備驅(qū)動(dòng)不了解的可以參考這篇文章:Linux下字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)以及流程介紹

/*************************************************************************> File Name: led_gpio.c> Author: WangDengtao> Mail: 1799055460@qq.com > Created Time: 2023年03月21日 星期二 13時(shí)55分02秒************************************************************************/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>/*如果沒(méi)有定義DEV_MAJOR就設(shè)置設(shè)備號(hào)為0,采用動(dòng)態(tài)申請(qǐng),如果有則使用宏定義的設(shè)備號(hào)*/
//#define DEV_MAJOR 88
#ifndef DEV_MAJOR
#define DEV_MAJOR 0
#endif#define PLATDRV_MAGIC 0x60 //魔術(shù)字
#define LED_OFF _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON  _IO (PLATDRV_MAGIC, 0x19)
#define DEV_NAME  "my_led"       /*宏定義設(shè)備的名字*/int dev_major = DEV_MAJOR;/*led設(shè)備初始化*/ 
struct led_device {    dev_t              devid;      /* 設(shè)備號(hào) */struct cdev        *cdev;      /*cdev結(jié)構(gòu)體*/struct class       *class;     /*定義一個(gè)class用于創(chuàng)建類(lèi) */struct device      *device;    /*設(shè)備 */struct device_node *node;      /* led設(shè)備節(jié)點(diǎn) */struct gpio_desc   *led_gpio1,*led_gpio2,*led_gpio3;  /*led燈GPIO描述符 */
}led_dev;/*字符設(shè)備操作函數(shù)集,open函數(shù)*/
static int led_open(struct inode *inode, struct file *file)
{file->private_data = &led_dev; //設(shè)置私有數(shù)據(jù)printk(KERN_DEBUG "/dev/led%d opened.\n", led_dev.devid);return 0;
}/*字符設(shè)備操作函數(shù)集,close函數(shù)*/
static int led_release(struct inode *inode, struct file *file)
{printk(KERN_DEBUG "/dev/led%d opened.\n", led_dev.devid);return 0;
}static void print_led_help(void)
{printk("Follow is the ioctl() command for LED driver:\n");printk("Turn LED on command : %u\n", LED_ON);printk("Turn LED off command : %u\n", LED_OFF);
}/*字符設(shè)備操作函數(shù)集,ioctl函數(shù)*/
static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{if(cmd == LED_OFF)/* variable case */{if(arg == 1){gpiod_set_value(led_dev.led_gpio1, 0);}else if(arg == 2){gpiod_set_value(led_dev.led_gpio2, 0);}else if(arg == 3){gpiod_set_value(led_dev.led_gpio3, 0);}else{printk("arg argument 1 2 3\n");return -EINVAL;}}else if(cmd == LED_ON){if(arg == 1){gpiod_set_value(led_dev.led_gpio1, 1);}else if(arg == 2){gpiod_set_value(led_dev.led_gpio2, 1);}else if(arg == 3){gpiod_set_value(led_dev.led_gpio3, 1);}else{printk("arg argument 1 2 3\n");return -EINVAL;}}else{printk("%s driver don't support ioctl command=%d\n", DEV_NAME, cmd);print_led_help();return -EINVAL;}return 0;
}/*字符設(shè)備操作函數(shù)集*/
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.release = led_release,.unlocked_ioctl = led_ioctl,
};  
/*驅(qū)動(dòng)安裝函數(shù)*/
static int led_probe(struct platform_device * pdev)
{int result= 0;/*獲取led的設(shè)備樹(shù)節(jié)點(diǎn),該函數(shù)適用于只有一個(gè)gpio,index為0*///led_dev.led_gpio = gpiod_get(&pdev -> dev, "led", 0);led_dev.led_gpio1 = gpiod_get_index(&pdev -> dev, "led", 0, GPIOD_OUT_HIGH);led_dev.led_gpio2 = gpiod_get_index(&pdev -> dev, "led", 1, GPIOD_OUT_HIGH);led_dev.led_gpio3 = gpiod_get_index(&pdev -> dev, "led", 2, GPIOD_OUT_HIGH);if(IS_ERR(led_dev.led_gpio1)){printk("gpiod request failure\n");return -1;}/*設(shè)置GPIO的方向?yàn)檩敵鰻顟B(tài),默認(rèn)為低電平*/result = gpiod_direction_output(led_dev.led_gpio1, 0);gpiod_direction_output(led_dev.led_gpio2, 0);gpiod_direction_output(led_dev.led_gpio3, 0);if(0 != result ){printk("gpiod direction output set failure\n");return result;}/*字符設(shè)備驅(qū)動(dòng)注冊(cè)的流程一:分配主次設(shè)備號(hào),這里不僅支持靜態(tài)指定,也支持動(dòng)態(tài)申請(qǐng)*//*靜態(tài)申請(qǐng)主次設(shè)備號(hào)*/if(0 != dev_major){led_dev.devid = MKDEV(dev_major, 0);//將主設(shè)備號(hào)dev_major和從設(shè)備號(hào)0分配給devno變量result = register_chrdev_region(led_dev.devid, 1, DEV_NAME);//請(qǐng)求分配一個(gè)設(shè)備號(hào),名字為DEV_NAME(chardev),設(shè)備號(hào)是:88 0}/*動(dòng)態(tài)申請(qǐng)*/else{result = alloc_chrdev_region(&led_dev.devid, 0, 1, DEV_NAME);//求分配一個(gè)名字為wangdengtao_dev的設(shè)備號(hào),從設(shè)備號(hào)為0,保存到devid變量中dev_major = MAJOR(led_dev.devid);//獲取設(shè)備號(hào)}/*失敗后的處理結(jié)果,總規(guī)上面只執(zhí)行一次,所以直接在外面判斷就可*/if(result < 0){printk(KERN_ERR " %s chardev can't use major %d\n", DEV_NAME, dev_major);return -result;}printk("%s driver use major %d\n", DEV_NAME, dev_major);/*字符串設(shè)備驅(qū)動(dòng)流程三:分配cdev結(jié)構(gòu)體,使用動(dòng)態(tài)申請(qǐng)的方式*//*內(nèi)核在內(nèi)部使用類(lèi)型struct cdev的結(jié)構(gòu)體來(lái)代表字符設(shè)備。在內(nèi)核調(diào)用你的設(shè)備操作之前,你必須分配一個(gè)這樣的結(jié)構(gòu)體并注冊(cè)給linux內(nèi)核,在這個(gè)結(jié)構(gòu)體里有對(duì)于這個(gè)設(shè)備進(jìn)行操作的函數(shù),具體定義在file_operation結(jié)構(gòu)體中。*/if(NULL == (led_dev.cdev = cdev_alloc())){printk(KERN_ERR "%s driver can't alloc for the cdev\n", DEV_NAME);unregister_chrdev_region(led_dev.devid, 1);//釋放掉設(shè)備號(hào)return -ENOMEM;}/*字符設(shè)備驅(qū)動(dòng)流程三:分配cdev結(jié)構(gòu)體,綁定主次設(shè)備號(hào),fops到cdev結(jié)構(gòu)體中,并且注冊(cè)到linux內(nèi)核*/led_dev.cdev -> owner = THIS_MODULE; /*.owner這表示誰(shuí)擁有這個(gè)驅(qū)動(dòng)程序*/cdev_init(led_dev.cdev, &led_fops);/*初始化設(shè)備*/result = cdev_add(led_dev.cdev, led_dev.devid, 1); /*將字符設(shè)備注冊(cè)進(jìn)內(nèi)核*/if(0 != result){printk(KERN_INFO "%s driver can't register cdev:result = %d\n", DEV_NAME, result);goto ERROR;}printk(KERN_INFO "%s driver can register cdev:result = %d\n", DEV_NAME, result);/*自動(dòng)創(chuàng)建設(shè)備類(lèi)型、/dev設(shè)備節(jié)點(diǎn)*/led_dev.class = class_create(THIS_MODULE, DEV_NAME); /*創(chuàng)建設(shè)備類(lèi)型sys/class/chrdev*/if (IS_ERR(led_dev.class)) {printk("%s driver create class failure\n", DEV_NAME);result = -ENOMEM;goto ERROR;}/*/dev/chrdev 注冊(cè)這個(gè)設(shè)備節(jié)點(diǎn)*/led_dev.device = device_create(led_dev.class, NULL, led_dev.devid, NULL, DEV_NAME); if(IS_ERR(led_dev.device)){result = -ENOMEM;//返回錯(cuò)誤碼,應(yīng)用空間strerror查看goto ERROR;}return 0;ERROR:printk(KERN_ERR" %s driver installed failure.\n", DEV_NAME);cdev_del(led_dev.cdev);unregister_chrdev_region(led_dev.devid, 1);return result;
}static int led_remove(struct platform_device *pdev)
{gpiod_set_value(led_dev.led_gpio1, 0); //低電平關(guān)閉燈gpiod_set_value(led_dev.led_gpio2, 0); //低電平關(guān)閉燈gpiod_set_value(led_dev.led_gpio3, 0); //低電平關(guān)閉燈gpiod_put(led_dev.led_gpio1); //釋放gpiogpiod_put(led_dev.led_gpio2); //釋放gpiogpiod_put(led_dev.led_gpio3); //釋放gpiocdev_del(led_dev.cdev); //刪除cdevunregister_chrdev_region(led_dev.devid, 1);//釋放設(shè)備號(hào)device_destroy(led_dev.class, led_dev.devid);//注銷(xiāo)設(shè)備class_destroy(led_dev.class); //注銷(xiāo)類(lèi)return 0;
}static const struct of_device_id leds_match_table[] = {{.compatible = "my-gpio-leds"},{/* sentinel */},
};
MODULE_DEVICE_TABLE(of, leds_match_table);/*內(nèi)核中使用platform_driver結(jié)構(gòu)體來(lái)描述平臺(tái)驅(qū)動(dòng)*/
static struct platform_driver gpio_led_driver =
{.probe  = led_probe,                           //安裝驅(qū)動(dòng)的時(shí)候會(huì)執(zhí)行的函數(shù).remove = led_remove,                          //驅(qū)動(dòng)卸載的時(shí)候會(huì)執(zhí)行的函數(shù).driver = {                                    //描述驅(qū)動(dòng)的屬性.name  = "my_led",                         //name域.owner = THIS_MODULE,                      //使用者,一般都是THIS_MODULE.of_match_table = leds_match_table,        //驅(qū)動(dòng)能夠兼容的設(shè)備類(lèi)型                                                                                    },
};/*入口函數(shù)*/
static int __init platdrv_led_init(void)
{int rv;/*當(dāng)我們初始化了platform_driver之后,通過(guò)platform_driver_register()函數(shù)來(lái)注冊(cè)我們的平臺(tái)驅(qū)動(dòng);成功注冊(cè)了一個(gè)平臺(tái)驅(qū)動(dòng)后,就會(huì)在/sys/bus/platform/driver目錄下生成一個(gè)新的目錄項(xiàng).成功: 0失敗: 負(fù)數(shù)*/rv = platform_driver_register(&gpio_led_driver);if(rv < 0){printk(KERN_ERR "%s:%d: Can't register platform driver %d \n", __FUNCTION__, __LINE__, rv);return rv;}printk("Regist LED Platform Driver successfully!\n ");return 0;
}/*出口函數(shù)*/
static void __exit platdrv_led_exit(void)
{printk("%s: %d remove LED platform driver\n", __FUNCTION__, __LINE__);/*卸載的驅(qū)動(dòng)模塊時(shí),需要注銷(xiāo)掉已注冊(cè)的平臺(tái)驅(qū)動(dòng)*/platform_driver_unregister(&gpio_led_driver);
}/*調(diào)用函數(shù) module_init 來(lái)聲明 xxx_init 為驅(qū)動(dòng)入口函數(shù),當(dāng)加載驅(qū)動(dòng)的時(shí)候 xxx_init函數(shù)就會(huì)被調(diào)用.*/
module_init(platdrv_led_init);
/*調(diào)用函數(shù)module_exit來(lái)聲明xxx_exit為驅(qū)動(dòng)出口函數(shù),當(dāng)卸載驅(qū)動(dòng)的時(shí)候xxx_exit函數(shù)就會(huì)被調(diào)用.*/
module_exit(platdrv_led_exit);/*添加LICENSE和作者信息,是來(lái)告訴內(nèi)核,該模塊帶有一個(gè)自由許可證;沒(méi)有這樣的說(shuō)明,在加載模塊的時(shí)內(nèi)核會(huì)“抱怨”.*/
MODULE_LICENSE("Dual BSD/GPL");//許可 GPL、GPL v2、Dual MPL/GPL、Proprietary(專(zhuān)有)等,沒(méi)有內(nèi)核會(huì)提示.
MODULE_AUTHOR("WangDengtao");//作者
MODULE_VERSION("V1.0");//版本

(2)編寫(xiě)驅(qū)動(dòng)測(cè)試代碼

/*************************************************************************> File Name: led_gpio_test.c> Author: WangDengtao> Mail: 1799055460@qq.com > Created Time: 2023年03月23日 星期四 10時(shí)46分40秒************************************************************************/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>#define LED_CNT 1
#define DEVNAME_LEN 30
#define PLATDRV_MAGIC 0x60#define LED_OFF _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON _IO (PLATDRV_MAGIC, 0x19)static void msleep(unsigned long ms)
{struct timeval tv;tv.tv_sec = ms/1000;tv.tv_usec = (ms%1000)*1000;select(0, NULL, NULL, NULL, &tv);
}int main(int argc, char **argv)
{int fd[LED_CNT];char dev_name[DEVNAME_LEN];memset(dev_name, 0, sizeof(dev_name));snprintf(dev_name, sizeof(dev_name), "/dev/my_led");fd[LED_CNT] = open(dev_name, O_RDWR, 0755);if(fd[LED_CNT] < 0){printf("file %s open failure!\n", dev_name);goto err;}printf("open fd[%d] successfully.\n", fd[LED_CNT]);while(1){ioctl(fd[LED_CNT], LED_ON, 1);msleep(500);ioctl(fd[LED_CNT], LED_OFF, 1);ioctl(fd[LED_CNT], LED_ON, 2);msleep(500);ioctl(fd[LED_CNT], LED_OFF, 2);ioctl(fd[LED_CNT], LED_ON, 3);msleep(500);ioctl(fd[LED_CNT], LED_OFF, 3);msleep(500);}close(fd[LED_CNT]);return 0;
err:close(fd[LED_CNT]);return -1;
}

(3)Makefile

同時(shí)編譯驅(qū)動(dòng)文件以及測(cè)試文件,編譯運(yùn)行之后我們可以看見(jiàn)可執(zhí)行文件以及.ko文件。

KERNAL_DIR ?= /home/wangdengtao/imx6ull/imx6ull/bsp/kernel/linux-imx
PWD :=$(shell pwd)
obj-m := led_gpio.oCC=arm-linux-gnueabihf-gcc
APP_NAME=led_gpio_testall:$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules@${CC} ${APP_NAME}.c -o ${APP_NAME}@make clearclear:@rm -f *.o *.cmd *.mod *.mod.c@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f@rm -f .*ko.cmd .*.o.cmd .*.o.d@rm -f *.unsignedclean:@rm -f *.ko@rm -f ${APP_NAME}
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/arm$ make
make -C /home/wangdengtao/imx6ull/imx6ull/bsp/kernel/linux-imx M=/home/wangdengtao/wangdengtao/driver/arm modules
make[1]: 進(jìn)入目錄“/home/wangdengtao/imx6ull/imx6ull/bsp/kernel/linux-imx”CC [M]  /home/wangdengtao/wangdengtao/driver/arm/led_gpio.oMODPOST /home/wangdengtao/wangdengtao/driver/arm/Module.symversCC [M]  /home/wangdengtao/wangdengtao/driver/arm/led_gpio.mod.oLD [M]  /home/wangdengtao/wangdengtao/driver/arm/led_gpio.ko
make[1]: 離開(kāi)目錄“/home/wangdengtao/imx6ull/imx6ull/bsp/kernel/linux-imx”
make[1]: 進(jìn)入目錄“/home/wangdengtao/wangdengtao/driver/arm”
make[1]: 離開(kāi)目錄“/home/wangdengtao/wangdengtao/driver/arm”
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/arm$ ls
led_gpio.c  led_gpio.ko  led_gpio_test  led_gpio_test.c  Makefile

將我們的可執(zhí)行文件以及.ko文件上傳到開(kāi)發(fā)板:

root@igkboard:~# tftp -gr led_gpio.ko 192.168.137.8
root@igkboard:~# tftp -gr led_gpio_test 192.168.137.8
root@igkboard:~# ls
led_gpio.ko  led_gpio_test

四、結(jié)果展示

安裝我們的驅(qū)動(dòng),可以看見(jiàn)在 /dev 路徑下生成的設(shè)備樹(shù)文件 my_led。

root@igkboard:~# insmod led_gpio.ko 
root@igkboard:~# lsmod
Module                  Size  Used by
led_gpio               16384  0
rtl8188fu             999424  0
imx_rngc               16384  0
rng_core               20480  1 imx_rngc
secvio                 16384  0
error                  20480  1 secvio
root@igkboard:~# ls -l /dev/my_led 
crw------- 1 root root 243, 0 Mar 25 08:49 /dev/my_led

執(zhí)行我們的測(cè)試代碼,我們可以看見(jiàn)我們的led燈隔5毫秒閃爍了:

root@igkboard:~# ./led_gpio_test 
open fd[3] successfully.

最后卸載我們的驅(qū)動(dòng):

root@igkboard:~# rmmod led_gpio
root@igkboard:~# lsmod
Module                  Size  Used by
rtl8188fu             999424  0
imx_rngc               16384  0
rng_core               20480  1 imx_rngc
secvio                 16384  0
error                  20480  1 secvio

在這里插入圖片描述


五、ioctl接口講解

大部分驅(qū)動(dòng)需要除了讀寫(xiě)設(shè)備的能力,還需要有通過(guò)設(shè)備驅(qū)動(dòng)進(jìn)行各種硬件控制的能力。

ioctl 驅(qū)動(dòng)函數(shù):

int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
  • inode:和 filp 指針是對(duì)應(yīng)應(yīng)用程序傳遞的文件描述符 fd 的值, 和傳遞給 open 方法的相同參數(shù)。
  • cmd:參數(shù)從用戶(hù)那里不改變地傳下來(lái),并且可選的參數(shù)。
  • arg:參數(shù)以一個(gè) unsigned long 的形式傳遞, 不管它是否由用戶(hù)給定為一個(gè)整數(shù)或一個(gè)指針。

為了保證 cmd 命令的唯一性(類(lèi)似于現(xiàn)實(shí)中的身份證)。

wangdengtao@wangdengtao-virtual-machine:~$ cat /opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/sysroot/usr/include/asm-generic/ioctl.h
#ifndef _ASM_GENERIC_IOCTL_H
#define _ASM_GENERIC_IOCTL_H/* ioctl command encoding: 32 bits total, command in lower 16 bits,* size of the parameter structure in the lower 14 bits of the* upper 16 bits.* Encoding the size of the parameter structure in the ioctl request* is useful for catching programs compiled with old versions* and to avoid overwriting user space outside the user buffer area.* The highest 2 bits are reserved for indicating the ``access mode''.* NOTE: This limits the max parameter size to 16kB -1 !*//** The following is for compatibility across the various Linux* platforms.  The generic ioctl numbering scheme doesn't really enforce* a type field.  De facto, however, the top 8 bits of the lower 16* bits are indeed used as a type field, so we might just as well make* this explicit here.  Please be sure to use the decoding macros* below from now on.*/
#define _IOC_NRBITS	8
#define _IOC_TYPEBITS	8/** Let any architecture override either of the following before* including this file.*/#ifndef _IOC_SIZEBITS
# define _IOC_SIZEBITS	14
#endif#ifndef _IOC_DIRBITS
# define _IOC_DIRBITS	2
#endif#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)#define _IOC_NRSHIFT	0
#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)/** Direction bits, which any architecture can choose to override* before including this file.*/#ifndef _IOC_NONE
# define _IOC_NONE	0U
#endif#ifndef _IOC_WRITE
# define _IOC_WRITE	1U
#endif#ifndef _IOC_READ
# define _IOC_READ	2U
#endif#define _IOC(dir,type,nr,size) \(((dir)  << _IOC_DIRSHIFT) | \((type) << _IOC_TYPESHIFT) | \((nr)   << _IOC_NRSHIFT) | \((size) << _IOC_SIZESHIFT))#define _IOC_TYPECHECK(t) (sizeof(t))/* used to create numbers */
#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOR_BAD(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)			(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)/* ...and for the drivers/sound files... */#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)#endif /* _ASM_GENERIC_IOCTL_H */

在驅(qū)動(dòng)程序里, ioctl() 函數(shù)上傳送的變量 cmd 是應(yīng)用程序用于區(qū)別設(shè)備驅(qū)動(dòng)程序請(qǐng)求處理內(nèi)容的值。cmd除了可區(qū)別數(shù)字外,還包含有助于處理的幾種相應(yīng)信息。 cmd的大小為 32位,共分 4 個(gè)域:

bit31~bit30 2位為 “區(qū)別讀寫(xiě)” 區(qū),作用是區(qū)分是讀取命令還是寫(xiě)入命令。

bit29~bit15 14位為 “數(shù)據(jù)大小” 區(qū),表示 ioctl() 中的 arg 變量傳送的內(nèi)存大小。

bit20~bit08 8位為 “魔數(shù)"(也稱(chēng)為"幻數(shù)")區(qū),這個(gè)值用以與其它設(shè)備驅(qū)動(dòng)程序的 ioctl 命令進(jìn)行區(qū)別。

bit07~bit00 8位為 “區(qū)別序號(hào)” 區(qū),是區(qū)分命令的命令順序序號(hào)。

內(nèi)核定義了 _IO() , _IOR() , IOW() 和 _IOWR() 這 4 個(gè)宏來(lái)輔助生成上面的 cmd 。下面分析 _IO() 的實(shí)現(xiàn)。

上面的代碼中可以看見(jiàn)_IO的定義以及_IOC的定義:

#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
#define _IOC(dir,type,nr,size) \(((dir)  << _IOC_DIRSHIFT) 	| \((type) << _IOC_TYPESHIFT) | \((nr)   << _IOC_NRSHIFT) 	| \((size) << _IOC_SIZESHIFT))
#ifndef _IOC_NONE
# define _IOC_NONE	0U
#endif#define _IOC_TYPESHIFT    (_IOC_NRSHIFT+_IOC_NRBITS)      //8
#define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)  //16
#define _IOC_DIRSHIFT     (_IOC_SIZESHIFT+_IOC_SIZEBITS)  //30
#define _IOC_NRSHIFT    0
#define _IOC_NRBITS     8
#define _IOC_TYPEBITS   8
(dir)  << _IOC_DIRSHIFT)    dir 往左移 30 位,即移到 bit31~bit30 兩位上,得到方向(讀寫(xiě))的屬性
(size) << _IOC_SIZESHIFT)   位左移 16 位得到“數(shù)據(jù)大小”區(qū)
(type) << _IOC_TYPESHIFT)   左移 8位得到"魔數(shù)區(qū)" 
(nr)   << _IOC_NRSHIFT)     左移 0( bit7~bit0) 

前面代碼中我們使用的宏定義解釋:

#define PLATDRV_MAGIC 0x60#define LED_OFF _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON _IO (PLATDRV_MAGIC, 0x19)

_IO (魔數(shù), 基數(shù)):

魔數(shù) (magic number)

魔數(shù)范圍為 0~255 。通常,用英文字符 “A” ~ “Z” 或者 “a” ~ “z” 來(lái)表示。設(shè)備驅(qū)動(dòng)程序從傳遞進(jìn)來(lái)的命令獲取魔數(shù),然后與自身處理的魔數(shù)想比較,如果相同則處理,不同則不處理。魔數(shù)是拒絕誤使用的初步輔助狀態(tài)。設(shè)備驅(qū)動(dòng) 程序可以通過(guò) _IOC_TYPE (cmd) 來(lái)獲取魔數(shù)。不同的設(shè)備驅(qū)動(dòng)程序最好設(shè)置不同的魔數(shù),但并不是要求絕對(duì),也是可以使用其他設(shè)備驅(qū)動(dòng)程序已用過(guò)的魔數(shù)。

基(序列號(hào))數(shù)

基數(shù)用于區(qū)別各種命令。通常,從 0開(kāi)始遞增,相同設(shè)備驅(qū)動(dòng)程序上可以重復(fù)使用該值。例如,讀取和寫(xiě)入命令中使用了相同的基數(shù),設(shè)備驅(qū)動(dòng)程序也能分辨出來(lái),原因在于設(shè)備驅(qū)動(dòng)程序區(qū)分命令時(shí) 使用 switch ,且直接使用命令變量 cmd值。創(chuàng)建命令的宏生成的值由多個(gè)域組合而成,所以即使是相同的基數(shù),也會(huì)判斷為不同的命令。設(shè)備驅(qū)動(dòng)程序想要從命令中獲取該基數(shù),就使用下面的宏:_IOC_NR (cmd)


http://m.risenshineclean.com/news/65104.html

相關(guān)文章:

  • 成都公司注冊(cè)網(wǎng)seo運(yùn)營(yíng)經(jīng)理
  • 做供應(yīng)鏈的網(wǎng)站創(chuàng)建網(wǎng)站教程
  • 網(wǎng)站制作中企動(dòng)力公司網(wǎng)絡(luò)優(yōu)化是做啥的
  • 滄州網(wǎng)站設(shè)計(jì)公司價(jià)格必應(yīng)搜索引擎網(wǎng)站
  • 新網(wǎng)站應(yīng)該怎么做seo太原百度快速排名提升
  • 做一個(gè)簡(jiǎn)單的網(wǎng)站贛州網(wǎng)站建設(shè)公司
  • 金堂做網(wǎng)站的公司快手流量推廣網(wǎng)站
  • 商標(biāo)查詢(xún)網(wǎng)入口鄭州seo
  • 寧波城鄉(xiāng)建設(shè)局管方網(wǎng)站濟(jì)南seo網(wǎng)絡(luò)優(yōu)化公司
  • h5網(wǎng)站后臺(tái)管理模板培訓(xùn)課程開(kāi)發(fā)
  • 豪華網(wǎng)站建設(shè)外貿(mào)網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣
  • 網(wǎng)站建設(shè)全視頻教程下載南寧seo計(jì)費(fèi)管理
  • 泰安定制網(wǎng)站建設(shè)公司項(xiàng)目推廣計(jì)劃書(shū)
  • 廣州網(wǎng)站建設(shè)培訓(xùn)學(xué)校網(wǎng)站alexa排名查詢(xún)
  • 深圳有哪些做網(wǎng)站的公司好企業(yè)如何做好網(wǎng)絡(luò)營(yíng)銷(xiāo)
  • 會(huì)員卡系統(tǒng)多少錢(qián)一套谷歌seo公司
  • 網(wǎng)站建設(shè)漢獅怎么樣seo研究協(xié)會(huì)網(wǎng)
  • 如何創(chuàng)建網(wǎng)站教程視頻微信朋友圈推廣
  • 重慶市建設(shè)工程信息網(wǎng)聯(lián)系電話(huà)自動(dòng)seo系統(tǒng)
  • 開(kāi)了網(wǎng)站建設(shè)公司 如何接業(yè)務(wù)競(jìng)價(jià)托管公司
  • 哪些網(wǎng)站是用python做的seo如何快速排名百度首頁(yè)
  • 如何在百度上做公司做網(wǎng)站百度上首頁(yè)
  • 通過(guò)做政府門(mén)戶(hù)網(wǎng)站的實(shí)驗(yàn)獲得什么發(fā)軟文是什么意思
  • 編制網(wǎng)站建設(shè)策劃書(shū)淘寶排名查詢(xún)工具
  • 長(zhǎng)沙有哪些網(wǎng)站建設(shè)公司經(jīng)典廣告語(yǔ)
  • 做網(wǎng)站地圖的步驟網(wǎng)絡(luò)推廣優(yōu)化seo
  • 動(dòng)態(tài)網(wǎng)站沒(méi)有數(shù)據(jù)庫(kù)怎么做巨量數(shù)據(jù)官網(wǎng)
  • 小程序開(kāi)發(fā) 網(wǎng)站建設(shè)網(wǎng)站做優(yōu)化好還是推廣好
  • 北京海淀區(qū)建設(shè)局網(wǎng)站萬(wàn)網(wǎng)
  • 做網(wǎng)站定制只要做好關(guān)鍵詞優(yōu)化