您的位置:首页 > 其它

字符设备驱动-----控制mini2440开发板的4个led灯

2013-03-16 20:50 387 查看
正在看韦东山的教程,他写了一个控制led灯的驱动。

我也写了一个。

总结:

         1)copy_from_user的用法          

//测试程序,即用户空间
char val;
...
write(fd, &val, sizeof(val));

//驱动程序,即内核空间
copy_from_user(&val, (char *)buf, sizeof(char));
注意:要明确val的类型,否则,可能取到的数值不正确。比如用户空间的val是int类型,而驱动部分却误写成了char类型的,就可能得不到正确数值了。(说可能,是因为不 知道目标机器是大端模式,还是小端模式);

         2)alloc_chrdev_region(&devno, 0, 4, DEVNAME); 此函数指明设备的个数。然后调用多次cdev_add创建多个字符设备。这些字符设备使用同一套函数,即struct file_operations变量中的函数:

for(i = 1; i <= 4; i++){//register char device
cdev_add(&firstcdev, MKDEV(MAJOR(devno), i - 1), 1);
}


3)为了自动创建字符设备文件,so.....(一个类,多个设备)

myclass = class_create(THIS_MODULE, "ctlled"); //create /sys/class/ctlled
for(i = 1; i <= 4; i++){//create for devices
device_create(myclass, NULL, MKDEV(MAJOR(devno), i - 1), NULL, "led%d", i); //auto create /dev/led1~4
}

源代码:





#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/device.h>

//device name
#define DEVNAME "ledctl"

//cdev
struct cdev firstcdev;
dev_t devno;

//for auto creata device file
struct class *myclass;

static int first_drv_open(struct inode *inode, struct file *file)
{
//printk("first_cdrv_open\n");
int i;
int ledno = 0;
//int minor = MINOR(file->f_dentry->d_inode->i_rdev);
int minor = MINOR(inode->i_rdev);

printk("open:minor is %d\n", minor);

s3c2410_gpio_cfgpin(S3C2410_GPB(5 + minor), S3C2410_GPIO_OUTPUT); //GPBx out mode
s3c2410_gpio_setpin(S3C2410_GPB(5 + minor), 1); //ledx off

return 0;
}

static int first_drv_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
{
//printk("first_cdrv_write\n");

char val;
int ledno = 0;
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
printk("write:minor is %d\n", minor);

copy_from_user(&val, (char *)buf, sizeof(char));
printk("val from user is %d\n", val);
ledno = minor + 5; //led1's pin number is 5
printk("write:ledno is %d\n", minor);
s3c2410_gpio_setpin(S3C2410_GPB(ledno), (val == 0 ? 1 : 0)); //val=1 led1 on

return 0;
}

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

static int first_drv_init(void)
{
int i;

cdev_init(&firstcdev, &first_drv_fops); //init cdev
alloc_chrdev_region(&devno, 0, 4, DEVNAME); //alloc char device number
printk("devno = %d\nmajor = %d\nminor = %d\n", devno, MAJOR(devno), MINOR(devno));//devno contains major and minor

for(i = 1; i <= 4; i++){//register char device cdev_add(&firstcdev, MKDEV(MAJOR(devno), i - 1), 1); }

myclass = class_create(THIS_MODULE, "ctlled"); //create /sys/class/ctlled
for(i = 1; i <= 4; i++){//create for devices
device_create(myclass, NULL, MKDEV(MAJOR(devno), i - 1), NULL, "led%d", i); //auto create /dev/led1~4
}

printk("firstdrvcdev initialized.\n");

return 0;
}

static void first_drv_exit(void)
{
int i;

unregister_chrdev_region(devno, 1); //release dev number
for(i = 0; i < 4; i++){
device_destroy(myclass, MKDEV(MAJOR(devno), i)); //del device
}
class_destroy(myclass); //del class
cdev_del(&firstcdev); //del char device
}

module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");


测试程序:(与韦老师提供的有点小小的改动)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/*
*  ledtest <dev> <on|off>
*/

void print_usage(char *file)
{
printf("Usage:\n");
printf("%s <dev> <on|off>\n",file);
printf("eg. \n");
printf("%s /dev/led1 on\n", file);
printf("%s /dev/led1 off\n", file);
printf("%s /dev/led2 on\n", file);
printf("%s /dev/led3 off\n", file);
printf("%s /dev/led4 off\n", file);
}

int main(int argc, char **argv)
{
int fd;
char* filename;
char val;

if (argc != 3)
{
print_usage(argv[0]);
return 0;
}

filename = argv[1];

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

if (0 == strcmp("on", argv[2]))
{
// ÁÁµÆ
val = 1;
write(fd, &val, sizeof(val));
}
else if (0 == strcmp("off", argv[2]))
{
// ÃðµÆ
val = 0;
write(fd, &val, sizeof(val));
}
else
{
print_usage(argv[0]);
return 0;
}

return 0;
}








                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: