led_cdev.c:
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/delay.h>
-
#include <asm/uaccess.h>
-
#include <asm/irq.h>
-
#include <asm/io.h>
-
#include <linux/device.h>//classcreate的定义
-
#include <linux/gpio.h>//gpio结构体的定义
-
#include <mach/regs-gpio.h>
-
//linux 3.10内核的regs-gpio.h位置不再是<asm/arch/regs-gpio.h>
-
#include <mach/hardware.h>
-
#include <linux/cdev.h>
-
-
volatile unsigned long *gpc0con = NULL;
-
volatile unsigned long *gpc0pud = NULL;
-
volatile unsigned long *gpc0dat = NULL;
-
-
#define LED_MAJOR 0
-
-
static struct gpio leds_gpios[] = {
-
{ S5PV210_GPC0(3), GPIOF_OUT_INIT_LOW, "LED1" }, /* 默认为输出 */
-
{ S5PV210_GPC0(4),GPIOF_OUT_INIT_LOW, "LED2" } /* 默认为输出 */
-
};
-
-
static struct class *firstdrv_class;
-
static struct device *firstdrv_class_dev;
-
-
static int first_led_open(struct inode *inode, struct file *file)
-
{
-
printk("first_drv_open\n");
-
return 0;
-
}
-
-
static ssize_t first_led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
-
{
-
int val;
-
int ret;
-
printk("first_drv_write\n");
-
ret = copy_from_user(&val, buf, count); // copy_to_user();
-
if(ret)
-
{
-
printk("copy_from_user error\n");
-
return -EFAULT;
-
}
-
if (val == 1)
-
{
-
gpio_set_value( S5PV210_GPC0(3), 1);
-
gpio_set_value( S5PV210_GPC0(4), 1);
-
}
-
else
-
{
-
gpio_set_value( S5PV210_GPC0(3), 0);
-
gpio_set_value( S5PV210_GPC0(4), 0);
-
}
-
return 0;
-
}
-
-
static struct file_operations first_led_fops = {
-
.owner = THIS_MODULE,
-
.open = first_led_open,
-
.write = first_led_write,
-
};
-
-
int major = 0;
-
dev_t devid;
-
struct cdev led_dev;
-
static int __init first_led_init(void)
-
{
-
int err;
-
#if 0
-
major = register_chrdev(0, "led_cdev", &first_led_fops);
-
#else
-
/* 1. 分配设备号 */
-
if(major){
-
devid = MKDEV(major,0);
-
major = MAJOR(devid);
-
err = register_chrdev_region(devid,0,"led_cdev");//向系统注册一个已知的设备编号
-
}
-
else{
-
printk("-> alloc_chrdev_region\n");
-
err = alloc_chrdev_region(&devid,0,1,"led_cdev");//申请编号,主设备动态分配,次设备号为0,范围1,申请到的主设备号存放在devid中
-
}
-
-
if(err){
-
printk(KERN_WARNING "led:can't get major %d\n",LED_MAJOR);
-
return err;
-
}
-
/* 2. 根据设备号注册设备 */
-
led_dev.owner = THIS_MODULE;
-
cdev_init(&led_dev, &first_led_fops);//构造字符设备结构体cdev led_dev
-
err = cdev_add(&led_dev,devid,1); //cdev_add(&led_dev,dev_t,count),注册字符设备
-
if(err){
-
printk("cdev_add error !");
-
return err;
-
}
-
#endif
-
/* 3. 建立设备节点,用deice_create自动创建 */
-
//MKDEV将主设备号和次设备号转为dev_t类型
-
//device_create创建设备信息,udev会自动根据设备信息创建设备节点/dev/xyz,应用程序根据设备节点(路径)访问设备
-
//linux 3.10中,class_device_create替换为device_create
-
//major = MAJOR(devid);//提取申请到的主设备号
-
firstdrv_class = class_create(THIS_MODULE,"class_led_cdev");
-
firstdrv_class_dev = device_create(firstdrv_class, NULL,devid, NULL, "xyz");
-
-
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));//申请GPIO
-
if (err){
-
printk("gpio_request_array error\n");
-
return -EFAULT;
-
}
-
printk("led initialize\n");
-
return 0;
-
}
-
-
static void __exit first_led_exit(void)
-
{
-
printk("first_led_exit\n");
-
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));//释放GPIO
-
#if 0
-
unregister_chrdev(major, "led_cdev");
-
#else
-
unregister_chrdev_region(devid, 1);//释放设备编号unregister_chrdev_region(dev_t from, unsigned count)
-
cdev_del(&led_dev); //删除字符设备
-
#endif
-
device_unregister(firstdrv_class_dev);//linux 3.10中,class_device_unregister替换为device_unregister
-
class_destroy(firstdrv_class);
-
}
-
-
module_init(first_led_init);
-
module_exit(first_led_exit);
-
-
MODULE_LICENSE("GPL");
ledtest.c:
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
-
/* firstdrvtest on
-
* firstdrvtest off
-
*/
-
int main(int argc, char **argv)
-
{
-
int fd;
-
int val = 1;
-
fd = open("/dev/xyz", O_RDWR);
-
if (fd < 0)
-
{
-
printf("can't open!\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;
-
}
Makefile:
-
KERN_DIR = /home/richard/work/kernel/linux-3.10.80
-
obj-m += led_cdev.o
-
-
all:
-
make -C $(KERN_DIR) M=`pwd` modules
-
clean:
-
rm -rf *.ko *.mod.c *.mod.o *.o *.order *.symvers *.cmd .*.o.* .*.ko.*
具体代码分析可参考LDD3或者宋宝华老师书籍或者韦东山的视频
阅读(1933) | 评论(0) | 转发(0) |