JZ2440笔记:字符设备驱动程序之LED驱动程序_测试改进2

(4) vi first_drv.c(自动分配主设备号)

int major;
static int first_drv_init(void)
{
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        printk("first_drv_init\n");
        return 0;
}

static void first_drv_exit(void)
{
        unregister_chrdev(major,"first_drv");
        printk("first_drv_exit\n");
}

make编译通过。insmod后查看自动分配的设备号:

# insmod first_drv.ko
first_drv_init
/mnt/3 # cat /proc/devices
Character devices:
248 first_drv

测试驱动:# ./firstdrvtest
can't open /dev/xxx !

当然通不过了,主设备号不是111了。

# ls -l /dev/xxx
crw-r--r--    1 0        0         111,   0 Jan  3 05:35 /dev/xxx

 重新新建设备文件,测试成功。

# rm /dev/xxx
/mnt/3 # mknod /dev/xxx c 248 0
/mnt/3 # ./firstdrvtest
first_drv_open
 

(5) vi first_drv.c(mdev子系统自动创建设备文件)

int major;
static struct class *firstdrv_class;
static struct class_device *firstdrv_device;
static int first_drv_init(void)
{
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        firstdrv_class = class_create(THIS_MODULE,"firstdrv");
        firstdrv_device = class_device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"xxx");
        printk("first_drv_init\n");
        return 0;
}

static void first_drv_exit(void)
{
        unregister_chrdev(major,"first_drv");
        class_device_unregister(firstdrv_device);
        class_destroy(firstdrv_class);
        printk("first_drv_exit\n");
}

make出现错误:

error: implicit declaration of function 'class_create' [-Werror=implicit-function-declaration]

error: implicit declaration of function 'class_device_create' [-Werror=implicit-function-declaration]

增加头文件#include <linux/device.h> 后,依然报错:

error: implicit declaration of function 'class_device_create' [-Werror=implicit-function-declaration]

要使用:

static struct device *firstdrv_device;

firstdrv_device = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"xxx");

device_destroy(firstdrv_class,MKDEV(major,0));

编译通过。

测试驱动:# cat /dev/xxx
cat: can't open '/dev/xxx': No such file or directory
# insmod first_drv.ko
first_drv_init

# cat /sys/class/firstdrv/xxx/dev
248:0

# cat /dev/xxx
first_drv_open

最后代码:

#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>

static int first_drv_open(struct inode *inode,struct file *file)
{
        printk("first_drv_open\n");
        return 0;
}

static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
        printk("first_drv_write\n");
        return 0;
}


static struct file_operations first_drv_fops = {
        .owner = THIS_MODULE,
        .open = first_drv_open,
        .write = first_drv_write,
};

int major;
static struct class *firstdrv_class;
static struct device *firstdrv_device;
static int first_drv_init(void)
{
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        firstdrv_class = class_create(THIS_MODULE,"firstdrv");
        firstdrv_device = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"xxx");
        printk("first_drv_init\n");
        return 0;
}

static void first_drv_exit(void)
{
        unregister_chrdev(major,"first_drv");
        device_destroy(firstdrv_class,MKDEV(major,0));
        class_destroy(firstdrv_class);
        printk("first_drv_exit\n");
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");

(6) vi first_drv.c(点灭全部灯)

#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;


static int first_drv_open(struct inode *inode,struct file *file)
{
        gpfcon &= ~(0x3<<(4*2)|(0x3<<(5*2))|(0x3<<(6*2)));
        gpfcon |=  (0x1<<(4*2)|(0x1<<(5*2))|(0x1<<(6*2)));
        return 0;
}

static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
        int val;
        copy_from_user(&val,buf,len);
        if(val==1)
                gpfdat &= ~((1<<4)|(1<<5)|(1<<6));
        else
                gpfdat |= ((1<<4)|(1<<5)|(1<<6));
        return 0;
}


static struct file_operations first_drv_fops = {
        .owner = THIS_MODULE,
        .open = first_drv_open,
        .write = first_drv_write,
};

int major;
static struct class *firstdrv_class;
static struct device *firstdrv_device;
static int first_drv_init(void)
{
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        firstdrv_class = class_create(THIS_MODULE,"firstdrv");
        firstdrv_device = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"xxx");

        gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
        gpfdat = gpfcon + 1;

        printk("first_drv_init\n");
        return 0;
}

static void first_drv_exit(void)
{
        iounmap(gpfcon);

        unregister_chrdev(major,"first_drv");
        device_destroy(firstdrv_class,MKDEV(major,0));
        class_destroy(firstdrv_class);
        printk("first_drv_exit\n");
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");

make出现invalid operands to binary & (have 'volatile long unsigned int *' and 'int')

原来是指针操作错误,加解引用符号后为:*gpfcon &= ~(0x3<<(4*2)|(0x3<<(5*2))|(0x3<<(6*2)));
        *gpfcon |=  (0x1<<(4*2)|(0x1<<(5*2))|(0x1<<(6*2)));*gpfdat &= ~((1<<4)|(1<<5)|(1<<6));
        *gpfdat |= ((1<<4)|(1<<5)|(1<<6));

make出现error: implicit declaration of function 'copy_from_user' [-Werror=implicit-function-declaration],则加头文件#include <linux/uaccess.h>。

make出现error: implicit declaration of function 'ioremap' [-Werror=implicit-function-declaration],则加头文件#include <asm/mach/map.h>,编译成功。

vi firstdrvtest.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
        int fd;
        int val;
        fd = open("/dev/xxx",O_RDWR);
        if(fd<0)
                printf("can't open /dev/xxx !\n");
        if(argc!=2)
        {
                printf("Usage: \n");
                printf("%s <on|off>\n",argv[0]);
                return 0;
        }
        if(strcmp(argv[1],"on")==0)
                val = 1;
        else
                val = 0;
        write(fd,&val,4);
        return 0;
}

编译出现warning: implicit declaration of function 'strcmp' [-Wimplicit-function-declaration],则man 3 strcmp,得到并加头文件 #include <string.h>

编译出现warning: implicit declaration of function 'write' [-Wimplicit-function-declaration],则man 2 write,得到并加头文件#include <unistd.h>,编译通过。

加载测试驱动:insmod first_drv.ko
first_drv_init
# ./firstdrvtest
Usage:
./firstdrvtest <on|off>
# ./firstdrvtest on       //3盏灯同时点亮
# ./firstdrvtest off       //3盏灯同时熄灭

(7) vi first_drv.c(点灭一灯)

static struct device firstdrv_device[4];
static int first_drv_init(void)
{
        int i;
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        firstdrv_class = class_create(THIS_MODULE,"firstdrv");
        firstdrv_device[0] = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"leds");
        for(i=1;i<4;i++)
        {
                firstdrv_device[i] = device_create(firstdrv_class,NULL,MKDEV(major,i),NULL,"led%d",i);
        }

        gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
        gpfdat = gpfcon + 1;

        printk("first_drv_init\n");
        return 0;
}



static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
        char val;
        int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        copy_from_user(&val,buf,len);
        switch(minor)
        {
                case 0:
                        if(val==1)
                                *gpfdat &= ~((1<<4)|(1<<5)|(1<<6));
                         else
                                 *gpfdat |= ((1<<4)|(1<<5)|(1<<6));
                         break;
                case 1:
                        if(val==1)
                                *gpfdat &= ~((1<<4));
                         else
                                 *gpfdat |= ((1<<4));
                         break;
                case 2:
                        if(val==1)
                                *gpfdat &= ~((1<<5));
                         else
                                 *gpfdat |= ((1<<5));
                         break;
                case 3:
                        if(val==1)
                                *gpfdat &= ~((1<<6));
                         else
                                 *gpfdat |= ((1<<6));
                         break;


        }
        return 0;
}

make出现 error: 'struct file' has no member named 'f_dentry',原来是代码太老了,参考编译驱动时error: ‘struct file’ has no member named ‘f_dentry’-CSDN博客 ​​​​​​将MINOR(file->f_dentry->d_inode->i_rdev)改成MINOR(file_inode(file)->i_rdev)。

再次make出现error: incompatible types when assigning to type 'struct device' from type 'struct device *',疏忽了,应该是指针数组static struct device *firstdrv_device[4]; 改完编译通过。

vi firstdrvtest.c

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
        int fd;
        char val;
        char *filename;

        if(argc!=3)
        {
                printf("Usage: \n");
                printf("%s </dev/led?> <on|off>\n",argv[0]);
                return 0;
        }

        filename = argv[1];
        fd = open(filename,O_RDWR);
        if(fd<0)
        {
                printf("can't open %s !\n",filename);
                return 0;
        }

        if(strcmp(argv[2],"on")==0)
                val = 1;
        else if(strcmp(argv[2],"off")==0)
                val = 0;
        else
        {
                printf("Usage: \n");
                printf("%s </dev/led?> <on|off>\n",argv[0]);
                return 0;
        }

        write(fd,&val,4);
        return 0;
}

加载测试驱动:# insmod first_drv.ko
first_drv_init

# ls /dev/led* -l
crw-rw----    1 0        0         248,   1 Jan  4 00:07 /dev/led1
crw-rw----    1 0        0         248,   2 Jan  4 00:07 /dev/led2
crw-rw----    1 0        0         248,   3 Jan  4 00:07 /dev/led3
crw-rw----    1 0        0         248,   0 Jan  4 00:07 /dev/leds

# ./firstdrvtest
Usage:
./firstdrvtest </dev/led?> <on|off>
# ./firstdrvtest /dev/led1 on
------------[ cut here ]------------
WARNING: CPU: 0 PID: 1057 at ./include/linux/thread_info.h:134 first_drv_write+0x15c/0x190 [first_drv]
Buffer overflow detected (1 < 4)!
Modules linked in: first_drv(O) [last unloaded: first_drv]
CPU: 0 PID: 1057 Comm: firstdrvtest Tainted: G           O      4.19.0-rc3 #6
Hardware name: SMDK2440
[<c0010698>] (unwind_backtrace) from [<c000dccc>] (show_stack+0x10/0x18)
[<c000dccc>] (show_stack) from [<c04e8f2c>] (dump_stack+0x18/0x24)
[<c04e8f2c>] (dump_stack) from [<c0019a8c>] (__warn+0xe8/0x110)
[<c0019a8c>] (__warn) from [<c0019af8>] (warn_slowpath_fmt+0x44/0x6c)
[<c0019af8>] (warn_slowpath_fmt) from [<bf03818c>] (first_drv_write+0x15c/0x190 [first_drv])
[<bf03818c>] (first_drv_write [first_drv]) from [<c00c34c8>] (__vfs_write+0x2c/0x174)
[<c00c34c8>] (__vfs_write) from [<c00c37b4>] (vfs_write+0xa0/0x188)
[<c00c37b4>] (vfs_write) from [<c00c3a04>] (ksys_write+0x4c/0xb8)
[<c00c3a04>] (ksys_write) from [<c0009000>] (ret_fast_syscall+0x0/0x50)
Exception stack(0xc3187fa8 to 0xc3187ff0)
7fa0:                   00010654 00000000 00000003 beebfc47 00000004 00000000
7fc0: 00010654 00000000 000103e8 00000004 00000000 00000000 b6f81000 beebfc54
7fe0: 00000070 beebfc20 0001062c b6ec8848
---[ end trace 8864fd30a4029042 ]---


?????????????????吓我一跳,原来是write(fd,&val,4);忘了改成write(fd,&val,1);

修改后再试,成功点亮点灭: # ./firstdrvtest /dev/led1 on
 # ./firstdrvtest /dev/led1 off

最后驱动代码:

#include <asm/mach/map.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;


static int first_drv_open(struct inode *inode,struct file *file)
{
        *gpfcon &= ~(0x3<<(4*2)|(0x3<<(5*2))|(0x3<<(6*2)));
        *gpfcon |=  (0x1<<(4*2)|(0x1<<(5*2))|(0x1<<(6*2)));
        return 0;
}

static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
        char val;
        int minor = MINOR(file_inode(file)->i_rdev);
        copy_from_user(&val,buf,len);
        switch(minor)
        {
                case 0:
                        if(val==1)
                                *gpfdat &= ~((1<<4)|(1<<5)|(1<<6));
                         else
                                 *gpfdat |= ((1<<4)|(1<<5)|(1<<6));
                         break;
                case 1:
                        if(val==1)
                                *gpfdat &= ~((1<<4));
                         else
                                 *gpfdat |= ((1<<4));
                         break;
                case 2:
                        if(val==1)
                                *gpfdat &= ~((1<<5));
                         else
                                 *gpfdat |= ((1<<5));
                         break;
                case 3:
                        if(val==1)
                                *gpfdat &= ~((1<<6));
                         else
                                 *gpfdat |= ((1<<6));
                         break;
        }
        return 0;
}


static struct file_operations first_drv_fops = {
        .owner = THIS_MODULE,
        .open = first_drv_open,
        .write = first_drv_write,
};

int major;
static struct class *firstdrv_class;
static struct device *firstdrv_device[4];
static int first_drv_init(void)
{
        int i;
        major = register_chrdev(0,"first_drv",&first_drv_fops);
        firstdrv_class = class_create(THIS_MODULE,"firstdrv");
        firstdrv_device[0] = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"leds");
        for(i=1;i<4;i++)
        {
                firstdrv_device[i] = device_create(firstdrv_class,NULL,MKDEV(major,i),NULL,"led%d",i);
        }

        gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
        gpfdat = gpfcon + 1;

        printk("first_drv_init\n");
        return 0;
}

static void first_drv_exit(void)
{
        iounmap(gpfcon);

        unregister_chrdev(major,"first_drv");
        device_destroy(firstdrv_class,MKDEV(major,0));
        class_destroy(firstdrv_class);
        printk("first_drv_exit\n");
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");

测试代码:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
        int fd;
        char val;
        char *filename;

        if(argc!=3)
        {
                printf("Usage: \n");
                printf("%s </dev/led?> <on|off>\n",argv[0]);
                return 0;
        }

        filename = argv[1];
        fd = open(filename,O_RDWR);
        if(fd<0)
        {
                printf("can't open %s !\n",filename);
                return 0;
        }

        if(strcmp(argv[2],"on")==0)
                val = 1;
        else if(strcmp(argv[2],"off")==0)
                val = 0;
        else
        {
                printf("Usage: \n");
                printf("%s </dev/led?> <on|off>\n",argv[0]);
                return 0;
        }

        write(fd,&val,1);
        return 0;
}

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值