Chinaunix首页 | 论坛 | 博客
  • 博客访问: 41223
  • 博文数量: 27
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 35
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-07 12:17
文章分类
文章存档

2014年(14)

2013年(13)

我的朋友

分类: LINUX

2013-04-18 16:35:29

     本例主要是实现一个三星ARM9处理器S3C2440上面的数码管的驱动程序。并随附了相关makefile文件及测试程序。

驱动程序源代码如下,关键地方提供了注释,并且此驱动在开发板上面测试通过。

//首先是头文件部分,必须包含像cdev.hmodule.h等头文件

#include

#include

#include

#include

#include

#include /* for -EBUSY */

#include       /* for verify_area */

#include              /* for module_init */

#include       /* for get_user and put_user */

// 定义了驱动名字 主设备号 从设备号,设备号注意不要与系统已有的冲突

// 本例没有采用动态分配的方法!!

#define DEVICE_NAME       "s3c2440_seg"  

#define SEG_MAJOR     232

#define SEG_MINOR     0

// 数码管的位选和段选地址,不同开发板地址可能不一样

#define SEG_SELECT         0xfe007000

#define VALUE_SELECT     0xfe006000

#define LED_NUM 6

#define LED_VALUE_MAX 16

#define ALL_LIGHT 7

// 定义驱动的ioctl函数,其中第一个unsigned int表示数码管的位选,选择第几

// 个数码管亮,第二个是段选,选择亮的数值

int   device_ioctl(struct inode *,struct file *,unsigned int ,unsigned long );       

// 定义主设备号变量及从设备号变量,并初始化了

int major = SEG_MAJOR;

int minor = SEG_MINOR;

// 数码管显示对应数值的十六进制值,是共阳型的

 unsigned char seg7table[16] =

{

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e

};

// 位选值

unsigned char seg7select[6] =

{

       /*0          1            2           3         4         5*/

          0xfe,    0xfd,      0xfb,    0xf7,     0xef,    0xdf

};

// seg_ioctl具体实现

static int seg_ioctl(

       struct inode *inode,

          struct file *file,

       unsigned int cmd,

       unsigned long arg)

{

     printk("Device Ioctl\n");

       // choose wich ligth to be lighted

     unsigned int value;

       value = (unsigned int)arg;  // 强制转换,表示对应数码管应该显示的数值

       if (cmd < LED_NUM)

              (*(char *)SEG_SELECT) = seg7select[cmd - 1];

       else if (cmd == ALL_LIGHT)

              (*(char *)SEG_SELECT) = 0x0;

       else

              printk(KERN_EMERG"The light is not existed!!\n");

       // choose the value to light

       if (value < LED_VALUE_MAX)

              (*(char *)VALUE_SELECT) = seg7table[value];

       else

              printk(KERN_EMERG"The light value illegal!!\n");

     return 0;

}

// 初始化file_operations结构体,只有一个操作

static struct file_operations seg_fops = {

       .owner          = THIS_MODULE,

       .ioctl                    = seg_ioctl,

       };

// 定义一个字符设备结构体

static struct cdev seg_devs;

// 初始化字符设备

static void seg_setup_cdev(struct cdev *seg_dev,  struct file_operations *fops)

{

       int err;

       dev_t devno = MKDEV(major, minor);

       cdev_init(seg_dev, fops);

       seg_dev->owner = THIS_MODULE;

       seg_dev->ops = fops;

       err = cdev_add(seg_dev, devno, 1);

       if (err)

       {

              printk(KERN_EMERG"cdev initial failed\n");

       }

}

// 注册设备并调用初始设备函数

static int __init seg_init( void )

{

       int ret = 0;

       dev_t dev = MKDEV(major, minor);

       if (major)

       {

              ret = register_chrdev_region(dev, 1, DEVICE_NAME);

       }

       else

       {

              printk(KERN_EMERG"device number allocated failed!!\n");

              return ret;

       }

      

       seg_setup_cdev(&seg_devs, &seg_fops);   

       printk (DEVICE_NAME" initialized\n");

     return ret;

};

// 驱动卸载时调用

static void __exit seg_exit(void)

{

       cdev_del(&seg_devs);         // log out the device

       unregister_chrdev_region(MKDEV(major, minor), 1);

       printk("The light device is uninstalled\n");

}

module_init(seg_init);

module_exit(seg_exit);

// 辅助信息

MODULE_AUTHOR("GetleHacker");

MODULE_DESCRIPTION("S3C2440 Led Device Driver");

MODULE_LICENSE("GPL");

在完成上述简单的驱动代码编写之后,可以使用下列makefile文件中的内容进行编译生成驱动安装文件s3c2440_seg.ko

ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /opt/linux-2.6.30.4

PWD :=$(shell pwd)

modules:

      $(MAKE) -C $(KERNELDIR) M=$(PWD)      modules

modules_install:

      $(MAKE) -C $(KERNELDIR) M=$(PWD)      modules_install

clean:

      rm -rf *.o *~ core .depend  .*.cmd *.mod.c *.markers *.order *.symvers .tmp_versions

.PHONY: modules modules_install clean

else

      obj-m:=s3c2440_seg.o

endif

注意第二行中的KERNELDIR非常关键,此内核目录是你ARM板系统同一内核必须。

完成上述工作之后,启动ARM板,通过nfs服务器,将LINUX系统根目录下的文件夹shareARM板中/mnt/nfs连接共享。此时可以直接在ARM板上的LINUX系统访问PC机端的share目录中的内容(具体请参考上一篇博文ARM开发板中LINUX系统访问PC端的共享文件目录)。将生成的s3c2440_seg.ko文件放在共享目录share中。

ARM开发板上进入/mnt/nfs目录下,执行如下命令:

# insmod s3c2440_seg.ko

# mknod /dev/s3c2440_seg c 232 0

注意这里的主设备号和从设备号与驱动程序中的相一致。

    完成上面的工作之后,驱动就安装上去了,接着可以测试驱动工作是否正常了。

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