一、杂项设备驱动
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#define DEV_NAME "led"
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;
static void init_led(void)
{
// 配置GPB5引脚功能为输出
*gpbcon &= ~(3 << 10);
*gpbcon |= (1 << 10);
// 将GPB5引脚电平置高
*gpbdat |= (1 << 5);
}
static void led_on(void)
{
// 将GPB5引脚电平置低
*gpbdat &= ~(1 << 5);
}
static void led_off(void)
{
// 将GPB5引脚电平置高
*gpbdat |= (1 << 5);
}
static int open (struct inode *inode, struct file *file)
{
init_led();
printk("open..\n");
return 0;
}
static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
printk("read..\n");
return 0;
}
static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t *offset)
{
unsigned char data[12] = {0};
size_t len_cp = sizeof(data) < len ? sizeof(data) : len;
copy_from_user(data, buf, len_cp);
if (!strcmp(data,"ledon"))
{
led_on();
}
else if (!strcmp(data,"ledoff"))
{
led_off();
}
else
return -EINVAL;
printk("write..\n");
return len_cp;
}
static int close (struct inode * inode, struct file * file)
{
printk("close..\n");
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = open,
.read = read,
.write = write,
.release = close
};
//struct class *class;
//struct device *device;
static struct miscdevice misc_device_node =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEV_NAME,
.fops = &fops
};
static int __init led_init(void)
{
int ret = 0;
// class = class_create(THIS_MODULE,"led");
ret = misc_register(&misc_device_node);
if (ret < 0)
goto err_misc_register;
gpbcon = ioremap(GPBCON,sizeof(*gpbcon));//映射一个地址
gpbdat = ioremap(GPBDAT,sizeof(*gpbdat));
// device = device_create(class,NULL,dev,NULL,"led");
printk("led_init ------------------------\n");
return ret;
err_misc_register:
misc_deregister(&misc_device_node);
printk("led misc_register failed\n");
return ret;
}
static void __exit led_exit(void)
{
// device_destroy(class,dev);
iounmap(gpbcon);//解除一个地址
iounmap(gpbdat);
// class_destroy(class);
misc_deregister(&misc_device_node);
printk("led_exit ----------------------------\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
- 新建一个led_misc.c 代码修改内容如上
- 修改Makefile
- make menuconfig,新选项LED_MISC选中<M>
- make modules
- cp drivers/char/led_misc.ko /home/linux/nfs/rootfs
- 开发板 insmod led_misc.ko
- 开发板 ls /dev -l 查看led设备是否生成
- 开发板 ./led_app 运行程序
二、自动创建设备节点
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#define MAJOR_NUM 253
#define MINOR_NUM 0
#define DEV_NAME "led"
#define DEV_NUM 1
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;
static void init_led(void)
{
// 配置GPB5引脚功能为输出
*gpbcon &= ~(0xff << 10);
*gpbcon |= (0x55 << 10);
// 将GPB5引脚电平置高
*gpbdat |= (0xf << 5);
}
static void led_on(void)
{
// 将GPB5引脚电平置低
*gpbdat &= ~(0xf << 5);
}
static void led_off(void)
{
// 将GPB5引脚电平置高
*gpbdat |= (0xf << 5);
}
static int open (struct inode * inode, struct file * file)
{
init_led();
printk("led open ...\n");
return 0;
}
static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
//copy_to_user(buf, data, len);
printk("led read ...\n");
return 0;
}
static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
unsigned char data[12] = {0};
size_t len_cp = sizeof(data) < len ? sizeof(data) : len;
copy_from_user(data, buf, len_cp);
if(!strcmp(data, "ledon"))
led_on();
else if(!strcmp(data, "ledoff"))
led_off();
else
return -1;
printk("led write ...\n");
return len_cp;
}
static int close (struct inode * inode, struct file * file)
{
printk("led close ...\n");
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = open,
.read = read,
.write = write,
.release = close
};
static struct cdev cdev;
static dev_t dev;
struct class * pclass;
struct device * pdev;
static int __init led_init(void)
{
int ret = 0;
dev = MKDEV(MAJOR_NUM, MINOR_NUM);
cdev_init(&cdev, &fops);
ret = cdev_add(&cdev, dev, DEV_NUM);
if(ret < 0)
goto err_cdev_add;
ret = register_chrdev_region(dev, DEV_NUM, DEV_NAME);
if(ret < 0)
goto err_register_chrdev_region;
pclass = class_create(THIS_MODULE, "led_class");
if(pclass == NULL)
goto err_class_create;
pdev = device_create(pclass, NULL, dev, NULL, DEV_NAME);
if(pdev == NULL)
goto err_device_create;
gpbcon = ioremap(GPBCON, sizeof(*gpbcon));
gpbdat = ioremap(GPBDAT, sizeof(*gpbdat));
printk("led_init ...\n");
return ret;
err_cdev_add:
cdev_del(&cdev);
printk("led cdev_add failed\n");
return ret;
err_register_chrdev_region:
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led register_chrdev_region failed\n");
return ret;
err_class_create:
class_destroy(pclass);
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led class_create failed\n");
return -1;
err_device_create:
device_destroy(pclass, dev);
class_destroy(pclass);
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led device_create failed\n");
return -1;
}
static void __exit led_exit(void)
{
iounmap(gpbcon);
iounmap(gpbdat);
device_destroy(pclass, dev);
class_destroy(pclass);
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led_exit ###############################\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
三、GPIO子系统