作为初学者,笔者尝试了“hello world”——点灯。然而鉴于william hill官网
和百度中许多大神用了杂项设备的方法,笔者自己尝试了下字符型设备,编译方法就略过了,以下是源码:
char_driver_leds.h
- #ifndef _CHAR_DRIVER_LEDS_H_
- #define _CHAR_DRIVER_LEDS_H_
- #ifndef DEVICE_NAME
- #define DEVICE_NAME "charGPIO"
- #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
- #endif
- struct reg_dev
- {
- char *data;
- struct cdev cdev;
- };
- #endif
char_driver_leds.c
- /*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
- #include
- /*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
- #include
- /*定义module_param module_param_array的头文件*/
- #include
- /*定义module_param module_param_array中perm的头文件*/
- #include
- /*三个字符设备函数*/
- #include
- /*MKDEV转换设备号数据类型的宏定义*/
- #include
- /*定义字符设备的结构体*/
- #include
- /*分配内存空间函数头文件*/
- #include
- /*包含函数device_create 结构体class等头文件*/
- #include
- #include
- #include //包含prink等函数
- #include //与c++相关的东西
- #include //Linux中申请GPIO的头文件
- /*自定义头文件*/
- #include "char_driver_leds.h"
- #include //不同平台使用的文件
- #include
- MODULE_LICENSE("Dual BSD/GPL");
- /*声明是开源的,没有内核版本限制*/
- MODULE_AUTHOR("XIE_dz");
- /*声明作者*/
- static int led_gpios[] = {
- PAD_GPIO_C + 11,PAD_GPIO_C + 10,
- };
- #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;
-
-
- /*注册到系统*/
- err = cdev_add(&dev->cdev,devno,1);
- if(err){
- printk(KERN_EMERG "cdev_add %d is fail! %dn",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
- ret = gpio_request(led_gpios[i], "LED");
- if (ret) {
- printk("%s: request GPIO %d for LED failed, ret = %dn", DEVICE_NAME,i,ret);
- return -1;
- }
- else{
- gpio_direction_output(led_gpios[i], 1);
- //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));//将s中前n个字节用 ch 替换并返回 s 。
-
- /*设备初始化*/
- for(i=0;i
- my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);//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
- cdev_del(&(my_devices[i].cdev));//这个函数会干掉cdev_map 散列表及dev本身
- /*摧毁设备节点函数d*/
- device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));
- }
- /*释放设备class*/
- class_destroy(myclass);
- /*释放内存*/
- kfree(my_devices);
-
- /*释放GPIO*/
- for(i=0;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);
- /*卸载函数*/
还有调用该驱动的文件invoke_char_gpios.c
- #include
- //#include //根据环境变化的长度,各种_t
- //#include //获取文件属性函数,各种_t
- #include
- #include //各种系统api如read,write
- #include
- /*argv[1] is cmd , argv[2] is io_arg*/
- int main()
- {
- int fd,i;
- char *lednode = "/dev/charGPIO0";
- /*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]);
- for(i=0;i<10;i++){
- ioctl(fd, 1, 0);
- ioctl(fd, 1, 1);
- sleep(1);
- ioctl(fd, 0, 0);
- ioctl(fd, 0, 1);
- sleep(1);
- }
- }
-
- close(fd);
- return 0;
- }
以上就是全部的源码了,望各位大神指教咯。