以下都是我刚开始看驱动视频的个人强行解读,如果有误请指出,共同进步。
https://blog.csdn.net/ZZRsr/article/details/80599489
https://blog.csdn.net/fxjqzs/article/details/47356039
https://www.cnblogs.com/xiansheng/p/5531462.html
仅上代码,此处以后再写。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("MrYang");
#define DEV_MAJOR 0 /* 默认主设备号(为0则linux自动分配可用号码) */
#define DEV_MINOR 0 /* 默认次设备号(为0则linux自动分配可用号码) */
#define DEV_MINOR_NUM 2 /* 要注册的次设备的数量 */
#define DEV_NAME "mryang_ascdev" /* 设备名 */
// 初始化主次设备号
int device_major = DEV_MAJOR;
int device_minor = DEV_MINOR;
static int led_gpios[] = {
EXYNOS4_GPL2(0),EXYNOS4_GPK1(1),
};
/*打开操作*/
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){
printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %u,arg is %lu!\n",cmd,arg);
switch(cmd)
{
case 0:
case 1:
gpio_set_value(led_gpios[arg], cmd);
break;
default:
break;
}
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;
}
// cdev结构体
struct cdev *my_cdev_ptr;
// 文件操作结构体
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,
};
struct class *myclass;
static int led_init(void)
{
int i = 0;
int flag = -1;
printk(KERN_EMERG "led init!\n");
for(i=0;i<2;i++)
{
gpio_free(led_gpios[i]);
// 申请GPIO
flag = gpio_request(led_gpios[i],"LEDS");
if(flag < 0){
printk(KERN_EMERG "gpio_request LED%d failed!\n", i);
return flag;
}
printk(KERN_EMERG "gpio_request LED%d success!\n", i);
// 配置GPIO为输出
s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
// 设置默认输出为0
gpio_set_value(led_gpios[i],0);
}
return 0;
}
static int mryang_init(void)
{
int ret, i;
dev_t mryang_dev;
printk(KERN_EMERG "HELLO MrYang\n");
// 动态申请设备号
ret = alloc_chrdev_region(&mryang_dev, device_minor, DEV_MINOR_NUM, DEV_NAME);
if(ret < 0)
printk(KERN_EMERG "failed!\n");
else
printk(KERN_EMERG "success!\n");
// 提取主、次设备号
device_major = MAJOR(mryang_dev);
device_minor = MINOR(mryang_dev);
printk(KERN_EMERG "major: %d, minor: %d\n", device_major, device_minor);
// 注册设备类
myclass = class_create(THIS_MODULE, DEV_NAME);
// 静态申请内存大小(设备数*结构体就是大小)
my_cdev_ptr = kmalloc( DEV_MINOR_NUM * sizeof(struct cdev), GFP_KERNEL);
if(my_cdev_ptr==NULL)
{
printk(KERN_EMERG "kmalloc failed!\n");
return -1;
}
memset(my_cdev_ptr, 0, DEV_MINOR_NUM * sizeof( struct cdev ) ); // 可省略,init会自动memset,看源码
for(i=0;i<DEV_MINOR_NUM;i++)
{
// 初始化cdev,并绑定文件操作函数
cdev_init(&my_cdev_ptr[i], &my_fops);
// 赋值
my_cdev_ptr[i].owner = THIS_MODULE;
my_cdev_ptr[i].ops = &my_fops;
// 注册到系统
ret = cdev_add(&my_cdev_ptr[i], MKDEV(device_major, device_minor+i), 1);
if( ret < 0 )
printk(KERN_EMERG "cdev_add %d failed!\n", i);
else
printk(KERN_EMERG "cdev_add %d success!\n", i);
/* 创建设备节点 */
device_create(myclass,NULL, MKDEV(device_major, device_minor+i), NULL, DEV_NAME"%d",i);
}
led_init();
return 0;
}
static void mryang_exit(void)
{
int i;
dev_t mryang_dev;
// 设备号
mryang_dev = MKDEV(device_major, device_minor);
for(i=0;i<DEV_MINOR_NUM;i++)
{ // 注销字符设备
cdev_del(&my_cdev_ptr[i]);
device_destroy(myclass,MKDEV(device_major, device_minor+i));
}
// 注销内存
kfree(my_cdev_ptr);
// 注销设备号
unregister_chrdev_region(mryang_dev, DEV_MINOR_NUM);
printk(KERN_EMERG "Bye MrYang\n");
}
module_init(mryang_init);
module_exit(mryang_exit);
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd;
char *mryang_node0 = "/dev/mryang_ascdev0";
char *mryang_node1 = "/dev/mryang_ascdev1";
int cmd = atoi(argv[1]);
int arg = atoi(argv[2]);
switch( arg )
{
case 0:
// 次设备 0
fd = open(mryang_node0, O_RDWR|O_NDELAY);
if(fd < 0)
{
printf("open %s failed!\n", mryang_node0);
}
else
{
printf("open %s success! fd=%d\n", mryang_node0, fd);
ioctl(fd, cmd, arg);
}
close(fd);
break;
case 1:
// 次设备 1
fd = open(mryang_node1, O_RDWR|O_NDELAY);
if(fd < 0)
{
printf("open %s failed!\n", mryang_node1);
}
else
{
printf("open %s success! fd=%d\n", mryang_node1, fd);
ioctl(fd, cmd, arg);
}
close(fd);
break;
default:
break;
}
return 0;
}