Chinaunix首页 | 论坛 | 博客
  • 博客访问: 453148
  • 博文数量: 40
  • 博客积分: 1410
  • 博客等级: 军士长
  • 技术积分: 1396
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-22 19:26
个人简介

嵌入式系统工程师,从事视频、图像、网络、虚拟化等方面的底层软件开发与优化。

文章存档

2014年(4)

2013年(10)

2012年(14)

2011年(12)

分类: LINUX

2011-08-05 10:04:39

1.驱动程序
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/cdev.h>
  7. #include <linux/types.h>
  8. #include <linux/device.h>
  9. #include <linux/mm.h>
  10. #include <linux/slab.h>
  11. #include <linux/sched.h>
  12. #include <linux/poll.h>
  13. #include <asm/uaccess.h>
  14. #include <asm/irq.h>
  15. #include <asm/io.h>
  16. #include <mach/map.h>
  17. #include <mach/regs-clock.h>
  18. #include <mach/regs-gpio.h>
  19. #include <mach/gpio-bank-k.h>
  20. #include <plat/gpio-cfg.h>

  21. #define DRIVER_DEBUG
  22. #define DEVICE_NAME        "mydriver"
  23. //#define DEVICE_MAJOR    252

  24. /* parameters */
  25. static int major;
  26. static int minor = 0;
  27. static int nr_devs = 1;            /* number of devices */

  28. struct class *my_class;
  29. struct mydriver_dev {
  30.     struct cdev cdev;        /* char device structure */
  31. }*mydriver_devp;            /* device structure pointer */

  32. /*
  33. * The open function of device driver.
  34. */
  35. static int mydriver_open(struct inode *inode, struct file *file)
  36. {
  37.     unsigned int led_tmp;

  38. #ifdef DRIVER_DEBUG
  39.     printk("\nIn the open function of driver!");
  40. #endif

  41.     //turn off all lights
  42.     led_tmp = readl(S3C64XX_GPKDAT);
  43.     led_tmp = (led_tmp | 0x000000f0);
  44.     writel(led_tmp, S3C64XX_GPKDAT);

  45.     return 0;
  46. }

  47.  static int mydriver_release(struct inode *inode, struct file *filp)
  48.  {
  49.     unsigned int led_tmp;

  50. #ifdef DRIVER_DEBUG
  51.     printk("In the release function of driver!\n");
  52. #endif
  53.     
  54.     //turn off all lights
  55.     led_tmp = readl(S3C64XX_GPKDAT);
  56.     led_tmp = (led_tmp | 0x000000f0);
  57.     writel(led_tmp, S3C64XX_GPKDAT);

  58.     return 0;
  59.  }

  60. /*
  61. * The read function of device driver. 
  62. */
  63. static int mydriver_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
  64. {
  65.     char led_state_read;

  66. #ifdef DRIVER_DEBUG    
  67.     printk("\nIn the read function of driver!");
  68. #endif

  69.     led_state_read = readl(S3C64XX_GPKDAT);
  70.     copy_to_user(buff, &led_state_read, 1);

  71.     return 1;
  72. }

  73. /*
  74. * The write function of device driver. 
  75. */
  76. static ssize_t mydriver_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
  77. {
  78.     unsigned int led_tmp;    
  79.     char led_state_write;

  80. #ifdef DRIVER_DEBUG
  81.     printk("\nIn the write function of driver!");
  82. #endif

  83.     copy_from_user(&led_state_write, buf, 1);
  84.     if (led_state_write <= 0x0f) {
  85.         led_tmp = readl(S3C64XX_GPKDAT);
  86.         led_tmp &= (led_state_write << 4);    //GPK[7:4] is connected to LEDs
  87.         led_tmp |= (led_state_write << 4);
  88.         writel(led_tmp, S3C64XX_GPKDAT);
  89.     } else {
  90.         printk("ERR: Illegal Input!\n");
  91.         printk("Please input the data that not over 16.\n");
  92.     }

  93.     return 1;
  94. }

  95. /*
  96.  * The file operations for the device
  97.  */
  98. static struct file_operations mydriver_fops = {
  99. .owner = THIS_MODULE,
  100. .open = mydriver_open,
  101. .release = mydriver_release,
  102. .read = mydriver_read,     
  103. .write = mydriver_write
  104. };

  105. /*
  106.  * Set up a cdev entry.
  107.  */
  108. static void mydriver_setup_cdev(struct mydriver_dev *dev, int index)
  109. {
  110.     int err, devno;

  111.     devno= MKDEV(major, minor + index);

  112.     cdev_init(&dev->cdev, &mydriver_fops);
  113.     dev->cdev.owner = THIS_MODULE;
  114.     err = cdev_add (&dev->cdev, devno, 1);
  115.     if (err)
  116.         printk(KERN_NOTICE "Error %d adding mydriver%d", err, index);
  117. }

  118. /*
  119.  * Initialize the pipe devs; return how many we did.
  120.  */
  121. static int __init mydriver_init_module(void)
  122. {
  123.     int ret;
  124.     dev_t devno = MKDEV(major, minor);

      /* 注册设备 */
  1.     if (major) /* 静态申请主设备号 */
  2.         ret = register_chrdev_region(devno, nr_devs, DEVICE_NAME);
  3.     else { /* 动态分配主设备号 */
  4.         ret = alloc_chrdev_region(&devno, minor, nr_devs, DEVICE_NAME);
  5.         major = MAJOR(devno);
  6.     }
  7.     if (ret < 0) {
  8.         printk(KERN_WARNING "%s: can't get major %d\n", DEVICE_NAME, major);
  9.         return ret;
  10.     }
      
     /* 动态申请设备结构体的内存并清零 */
  1.     mydriver_devp = kzalloc(sizeof(struct mydriver_dev), GFP_KERNEL);
  2.     if (!mydriver_devp) {
  3.         ret = - ENOMEM;
  4.         goto fail_malloc;

  5.     }

     /* 初始化字符设备结构体 */
  1.     /* The following step must after kmalloc() and memset() */
  2.     mydriver_setup_cdev(mydriver_devp, 0);

     /* 自动创建设备文件 */
  1.     /* 1. create your own class under /sys
  2.     *  2. register your own device in sys
  3.     *     this will cause udev to create corresponding device node
  4.     */
  5.     my_class = class_create(THIS_MODULE, "my_class");
  6.     if (IS_ERR(my_class)) {
  7.         printk(DEVICE_NAME " failed in creating class./n");
  8.         return -1; 
  9.     }
  10.     device_create(my_class, NULL, MKDEV(major, minor), NULL, "mydriver""%d", 0);

  11.     printk(DEVICE_NAME "\tinitialized, major = %d, minor = %d.\n", major, minor);

  12.     return 0;

  13. fail_malloc:
  14.     unregister_chrdev_region(devno, 1);

  15.     return ret;
  16. }

  17. /*
  18.  * This is called by cleanup_module or on failure.
  19.  */
  20. static void __exit mydriver_exit_module(void)
  21. {
  22.     device_destroy(my_class, MKDEV(major, minor));
  23.     class_destroy(my_class);
  24.     cdev_del(&mydriver_devp->cdev);
  25.     kfree(mydriver_devp);
  26.     unregister_chrdev_region(MKDEV(major, minor), 1);    
  27.     printk(DEVICE_NAME "\texited!\n");
  28. }

  29. module_init(mydriver_init_module);
  30. module_exit(mydriver_exit_module);

  31. MODULE_AUTHOR("Jason Lu");
  32. MODULE_VERSION("0.1.0");
  33. MODULE_DESCRIPTION("Jason's blog: http://blog.chinaunix.net/space.php?uid=20746260");
  34. MODULE_LICENSE("Dual MPL/GPL");
2.应用程序
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include

  7. int main()
  8. {
  9. int fd, i = 0;
  10. char led_read_buf = 0, led_write_buf = 0;
  11. printf("--------------------------------------------------------------\n");
  12. printf("--- This is the begining of the test program of my driver! ---\n");
  13. printf("--------------------------------------------------------------\n");
  14. sleep(1); //加入延时是为了打印信息和程序执行过程同步输出,下同
  15. /* 1. open the device driver */
  16. printf("1. open device driver:\n");
  17. fd = open("/dev/mydriver0", O_RDWR);
  18. if (fd < 0) {
  19. printf("Device open error!\n");
  20. exit(1);
  21. }
  22. sleep(1);

  23. /* 2. Read LED status */
  24. printf("2. Read LED status:\n");
  25. if (read(fd, &led_read_buf, 1) < 0) {
  26. printf("Read data error!\n");
  27. exit(1);
  28. }
  29. /* GPK[7:4] is connected to LEDs */
  30. printf("The status of GPK[7:0] is 0x%x.\n", led_read_buf);
  31. sleep(1);
  32. /* 3. Control LED lights */
  33. printf("3. Control LED lights:\n");
  34. while (i < 128) {
  35. led_write_buf = i % 16;
  36. write(fd, &led_write_buf, 1);
  37. sleep(1);
  38. i++;
  39. }

  40. /* 4. close device driver */
  41. close(fd);
  42. printf("---------------------------------------------------------\n");
  43. printf("--- This is the end of the test program of my driver! ---\n");
  44. printf("---------------------------------------------------------\n");

  45. return 0;
  46. }
3. 把驱动程序加入内核(One)
a.把上述驱动程序添加到/driver/char目录下;
b.把/driver/char目录下的Kconfig文件里,添加如下几行:
  1. config MY_DRIVER
  2. tristate "My driver for FriendlyARM Tiny6410 development boards"
  3. depends on MACH_MINI6410
  4. default m if MACH_MINI6410 //默认是内核模块
  5. help
  6. this is My driver for FriendlyARM Tiny6410 development boards
c.把/driver/char目录下的Makefile文件里,添加如下一行:
  1. obj-$(CONFIG_MY_DRIVER) += my_driver.o
d.cp config_mini6410_n43 .config
e.make menuconfig
f.在出现的配置界面里,输入D,找到Device Drivers,按Enter键进入子界面
g.在子配置界面里,两次输入C,找到Character devices,按Enter键进入子界面
h.查看是否有一行是 My driver for FriendlyARM Tiny6410 development boards
i.退出,make uImage
j.待生成uImage后,在内核工程主目录下输入:
  1. mkimage -A arm -O linux -T kernel -C none -a 0x50018000 -e 0x50018040 -n "Jason Linux" -d arch/arm/boot/zImage ./uImage
k.把内核通过SD卡烧入开发板
l.make modules  驱动程序如果没有错误的话,就会生成my_driver.ko
m.通过串口终端rz命令,传入my_driver.ko以及应用程序的可执行文件drivertest,把前者放到lib/modules/2.6.38-FriendlyARM/kernel/drivers/char/目录下
n.然后如下图操作:


4. 把驱动程序加入内核(Two)
   注:modules:下一行必须以TAB键开始,下同,不解释。
  1. DRIVER_NAME =my_led
  2. KERNELDIR =/home/source/friendlyarm/linux-2.6.38-jason/
  3. PWD :=$(shell pwd)
  4. INSTALLDIR =$(KERNELDIR)/drivers/char/

  5. CROSS_COMPILE =/home/source/friendlyarm/toolschain/4.5.1/bin/arm-linux-
  6. CC =$(CROSS_COMPILE)gcc

  7. obj-m :=$(DRIVER_NAME).o 

  8. modules:
  9. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

  10. modules_install:
  11. cp $(DRIVER_NAME).ko $(INSTALLDIR)

  12. clean:
  13. rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.symvers *.order

  14. clean_all:
  15. rm -rf *.ko *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.symvers *.order

  16. .PHONY: modules modules_install clean

阅读(3013) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~