十七、字符类 GPIOS
生活随笔
收集整理的這篇文章主要介紹了
十七、字符类 GPIOS
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、驅動代碼(char_driver_leds.c)
/*包含初始化宏定義的頭文件,代碼中的module_init和module_exit在此文件中*/ #include <linux/init.h> /*包含初始化加載模塊的頭文件,代碼中的MODULE_LICENSE在此頭文件中*/ #include <linux/module.h> /*定義module_param module_param_array的頭文件*/ #include <linux/moduleparam.h> /*定義module_param module_param_array中perm的頭文件*/ #include <linux/stat.h> /*三個字符設備函數*/ #include <linux/fs.h> /*MKDEV轉換設備號數據類型的宏定義*/ #include <linux/kdev_t.h> /*定義字符設備的結構體*/ #include <linux/cdev.h> /*分配內存空間函數頭文件*/ #include <linux/slab.h> /*包含函數device_create 結構體class等頭文件*/ #include <linux/device.h>/*自定義頭文件*/ #include "char_driver_leds.h"/*Linux中申請GPIO的頭文件*/ #include <linux/gpio.h> /*三星平臺的GPIO配置函數頭文件*/ /*三星平臺EXYNOS系列平臺,GPIO配置參數宏定義頭文件*/ #include <plat/gpio-cfg.h> /*三星平臺4412平臺,GPIO宏定義頭文件*/ #include <mach/gpio-exynos4.h>MODULE_LICENSE("Dual BSD/GPL"); /*聲明是開源的,沒有內核版本限制*/ MODULE_AUTHOR("iTOPEET_dz"); /*聲明作者*/static int led_gpios[] = {EXYNOS4_GPL2(0),EXYNOS4_GPK1(1), }; #define LED_NUM ARRAY_SIZE(led_gpios)int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/*輸入主設備號*/ module_param(numdev_major,int,S_IRUSR); /*輸入次設備號*/ module_param(numdev_minor,int,S_IRUSR);static struct class *myclass; struct reg_dev *my_devices;/*打開操作*/ static int chardevnode_open(struct inode *inode, struct file *file){printk(KERN_EMERG "chardevnode_open is success!\n");return 0; } /*關閉操作*/ static int chardevnode_release(struct inode *inode, struct file *file){printk(KERN_EMERG "chardevnode_release is success!\n");return 0; } /*IO操作*/ static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg){switch(cmd){case 0:case 1:if (arg > LED_NUM) {return -EINVAL;}gpio_set_value(led_gpios[arg], cmd);break;default:return -EINVAL;}printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);return 0; }ssize_t chardevnode_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops){return 0; }ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t count, loff_t *f_ops){return 0; }loff_t chardevnode_llseek(struct file *file, loff_t offset, int ence){return 0; } struct file_operations my_fops = {.owner = THIS_MODULE,.open = chardevnode_open,.release = chardevnode_release,.unlocked_ioctl = chardevnode_ioctl,.read = chardevnode_read,.write = chardevnode_write,.llseek = chardevnode_llseek, };/*設備注冊到系統*/ static void reg_init_cdev(struct reg_dev *dev,int index){int err;int devno = MKDEV(numdev_major,numdev_minor+index);/*數據初始化*/cdev_init(&dev->cdev,&my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;/*注冊到系統*/err = cdev_add(&dev->cdev,devno,1);if(err){printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,err);}else{printk(KERN_EMERG "cdev_add %d is success!\n",numdev_minor+index);} }static int gpio_init(void){int i=0,ret;for(i=0;i<LED_NUM;i++){ret = gpio_request(led_gpios[i], "LED");if (ret) {printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,i,ret);return -1;}else{s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);gpio_set_value(led_gpios[i], 1); }}return 0; }static int scdev_init(void) {int ret = 0,i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);if(numdev_major){num_dev = MKDEV(numdev_major,numdev_minor);ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);}else{/*動態注冊設備號*/ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);/*獲得主設備號*/numdev_major = MAJOR(num_dev);printk(KERN_EMERG "adev_region req %d !\n",numdev_major);}if(ret<0){printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major); }myclass = class_create(THIS_MODULE,DEVICE_NAME);my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL);if(!my_devices){ret = -ENOMEM;goto fail;}memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));/*設備初始化*/for(i=0;i<DEVICE_MINOR_NUM;i++){my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);memset(my_devices[i].data,0,REGDEV_SIZE);/*設備注冊到系統*/reg_init_cdev(&my_devices[i],i);/*創建設備節點*/device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL,DEVICE_NAME"%d",i);}ret = gpio_init();if(ret){printk(KERN_EMERG "gpio_init failed!\n");} printk(KERN_EMERG "scdev_init!\n");/*打印信息,KERN_EMERG表示緊急信息*/return 0;fail:/*注銷設備號*/unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);printk(KERN_EMERG "kmalloc is fail!\n");return ret; }static void scdev_exit(void) {int i;printk(KERN_EMERG "scdev_exit!\n");/*除去字符設備*/for(i=0;i<DEVICE_MINOR_NUM;i++){cdev_del(&(my_devices[i].cdev));/*摧毀設備節點函數d*/device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));}/*釋放設備class*/class_destroy(myclass);/*釋放內存*/kfree(my_devices);/*釋放GPIO*/for(i=0;i<LED_NUM;i++){gpio_free(led_gpios[i]);}unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); }module_init(scdev_init); /*初始化函數*/ module_exit(scdev_exit); /*卸載函數*/?char_driver_leds.h
#ifndef _CHAR_DRIVER_LEDS_H_ #define _CHAR_DRIVER_LEDS_H_#ifndef DEVICE_NAME #define DEVICE_NAME "chardevnode" #endif#ifndef DEVICE_MINOR_NUM #define DEVICE_MINOR_NUM 2 #endif#ifndef DEV_MAJOR #define DEV_MAJOR 0 #endif#ifndef DEV_MINOR #define DEV_MINOR 0 #endif#ifndef REGDEV_SIZE #define REGDEV_SIZE 3000 #endifstruct reg_dev {char *data;unsigned long size;struct cdev cdev; }; #endif?
二、Makefile
#!/bin/bash #通知編譯器我們要編譯模塊的哪些源碼 #這里是編譯itop4412_hello.c這個文件編譯成中間文件mini_linux_module.o obj-m += char_driver_leds.o #源碼目錄變量,這里用戶需要根據實際情況選擇路徑 #作者是將Linux的源碼拷貝到目錄/home/topeet/android4.0下并解壓的 KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0#當前目錄變量 PWD ?= $(shell pwd)#make命名默認尋找第一個目標 #make -C就是指調用執行的路徑 #$(KDIR)Linux源碼目錄,作者這里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0 #$(PWD)當前目錄變量 #modules要執行的操作 all:make -C $(KDIR) M=$(PWD) modules#make clean執行的操作是刪除后綴為o的文件 clean:rm -rf *.mod.c *.o *.order *.ko *.mod.o *.symvers三、應用程序(invoke_char_gpios.c)
編譯:arm-none-linux-gnueabi-gcc -o invoke_char_gpios invoke_char_gpios.c - static
#include <stdio.h>#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h>/*argv[1] is cmd , argv[2] is io_arg*/ int main(int argc , char **argv){int fd;char *lednode = "/dev/chardevnode0";/*O_RDWR只讀打開,O_NDELAY非阻塞方式*/ if((fd = open(lednode,O_RDWR|O_NDELAY))<0){printf("APP open %s failed!\n",lednode);}else{printf("APP open %s success!\n",lednode);ioctl(fd,atoi(argv[1]),atoi(argv[2]));printf("APP ioctl %s ,cmd is %s! io_arg is %s!\n",lednode,argv[1],argv[2]);}close(fd); }四、運行效果
?
?
?
總結
以上是生活随笔為你收集整理的十七、字符类 GPIOS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十六、字符驱动及应用
- 下一篇: 十八、中断之独立按键