驱动第一天 之 第一个驱动.LED

lcled_drv.c
 1 #include <linux/module.h>
 2 #include <linux/kernel.h>
 3 #include <linux/fs.h>
 4 #include <linux/init.h>
 5 #include <linux/delay.h>
 6 #include <asm/uaccess.h>
 7 #include <asm/irq.h>
 8 #include <asm/io.h>
 9 #include <asm/arch/regs-gpio.h>
10 #include <asm/hardware.h>
11 
12 int major;
13 volatile unsigned long *gpbcon = NULL;
14 volatile unsigned long *gpbdat = NULL;
15 
16 static int lcled_drv_open(struct inode *inode, struct file *file)
17 {
18     *gpbcon &= ~((0x3<<(5*2)) | (0x3<<(6*2)) | (0x3<<(7*2)) | (0x3<<(8*2)));
19     *gpbcon |= ((0x1<<(5*2)) | (0x1<<(6*2)) | (0x1<<(7*2)) | (0x1<<(8*2)));
20     return 0;
21 }
22 
23 static ssize_t lcled_drv_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
24 {
25     int val;
26     copy_from_user(&val, buf, count);
27     if(val == 1){
28         *gpbdat &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
29     }else{
30         *gpbdat |= (1<<5) | (1<<6) | (1<<7) | (1<<8);
31     }
32     
33 }
34 
35 static struct file_operations lcled_drv_fops = {
36     .owner = THIS_MODULE,
37     .open  = lcled_drv_open,
38     .write = lcled_drv_write,
39 };
40 
41 static int lcled_drv_init(void)
42 {
43     major = register_chrdev(0, "lcled_drv", &lcled_drv_fops);
44     gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);
45     gpbdat = gpbcon + 1;
46 
47     return 0;
48 }
49 
50 static void lcled_drv_exit(void)
51 {
52     unregister_chrdev(major, "lcled_drv");
53     iounmap(gpbcon);
54 }
55 
56 
57 
58 module_init(lcled_drv_init);
59 module_exit(lcled_drv_exit);
60 
61 MODULE_LICENSE("GPL");
Makefile
 1 KERN_DIR = /home/book/linux-2.6.25.8
 2 
 3 all:
 4     make -C $(KERN_DIR) M=`pwd` modules 
 5 
 6 clean:
 7     make -C $(KERN_DIR) M=`pwd` modules clean
 8     rm -rf modules.order
 9 
10 obj-m    += lcled_drv.o
test
 1 #include <stdio.h>
 2 #include <fcntl.h>
 3 
 4 int main(int argc, char **argv)
 5 {
 6     int fd;
 7     int val = 1;
 8     fd = open("/dev/lcled", O_RDWR);
 9     if (fd < 0)
10     {
11         printf("can't open!\n");
12     }
13     if (argc != 2)
14     {
15         printf("Usage :\n");
16         printf("%s <on|off>\n", argv[0]);
17         return 0;
18     }
19 
20     if (strcmp(argv[1], "on") == 0)
21     {
22         val  = 1;
23     }
24     else
25     {
26         val = 0;
27     }
28     
29     write(fd, &val, 4);
30     return 0;
31 }

函数原型:
  int (*open)(struct inode *inode, struct file *filp);

  ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

module_init(lcled_drv_init);
module_exit(lcled_drv_exit);是用于注册和删除驱动程序

  这个比较简单,网上有很多分析的文章,这里只是作为自己简单的记录,这个驱动是韦东山《嵌入式linux应用开发完全手册》配套光盘里的first_drv精简的。但是未精简之前的代码在编译的时候会有这个问题:用2.6.22.6内核编译可以顺利通过,但用TQ光盘提供的2.6.25.8内核却会报错,要添加一个头文件:

#include <linux/device.h>,这样就能编译成功了。(就这个昨天倒腾到今天,主要还是方法欠佳,经验教训!!- -!)再续!!!

posted @ 2012-12-22 17:27  永不指步  阅读(225)  评论(0编辑  收藏  举报