Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2297449
  • 博文数量: 395
  • 博客积分: 10994
  • 博客等级: 上将
  • 技术积分: 5586
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-17 19:49
文章存档

2014年(1)

2013年(10)

2012年(74)

2011年(303)

2010年(7)

分类: LINUX

2011-04-26 20:31:32

最近学习《linxu设备驱动开发详解》中的关于字符设备驱动第六章的内容,记录如下,


一.globalmem.c文件如下

/*
 * A globalmem driver as an example of char device drivers
 *
 * The initial developer of the original code is Barry Song
 * . All Rights Reserved.
 */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define GLOBALMEM_SIZE    0x1000    /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define GLOBALMEM_MAJOR 250    /*预设的globalmem的主设备号*/

static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
struct globalmem_dev {
    struct cdev cdev; /*cdev结构体*/
    unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
};

struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
/*文件打开函数*/
int globalmem_open(struct inode *inode, struct file *filp)
{
    /*将设备结构体指针赋值给文件私有数据指针*/
    filp->private_data = globalmem_devp;
    return 0;
}
/*文件释放函数*/
int globalmem_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/* ioctl设备控制函数 */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
    int cmd, unsigned long arg)
{
    struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/

    switch (cmd) {
    case MEM_CLEAR:
        memset(dev->mem, 0, GLOBALMEM_SIZE);
        printk(KERN_INFO "globalmem is set to zero\n");
        break;

    default:
        return  - EINVAL;
    }

    return 0;
}

/*读函数*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
    loff_t *ppos)
{
    unsigned long p =  *ppos;
    unsigned int count = size;
    int ret = 0;
    struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/

    /*分析和获取有效的写长度*/
    if (p >= GLOBALMEM_SIZE)
        return 0;
    if (count > GLOBALMEM_SIZE - p)
        count = GLOBALMEM_SIZE - p;

    /*内核空间->用户空间*/
    if (copy_to_user(buf, (void *)(dev->mem + p), count)) {
        ret =  - EFAULT;
    } else {
        *ppos += count;
        ret = count;

        printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
    }

    return ret;
}

/*写函数*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
    size_t size, loff_t *ppos)
{
    unsigned long p =  *ppos;
    unsigned int count = size;
    int ret = 0;
    struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/

    /*分析和获取有效的写长度*/
    if (p >= GLOBALMEM_SIZE)
        return 0;
    if (count > GLOBALMEM_SIZE - p)
        count = GLOBALMEM_SIZE - p;

    /*用户空间->内核空间*/
    if (copy_from_user(dev->mem + p, buf, count))
        ret =  - EFAULT;
    else {
        *ppos += count;
        ret = count;

        printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
    }

    return ret;
}

/* seek文件定位函数 */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
    loff_t ret = 0;
    switch (orig) {
    case 0:   /*相对文件开始位置偏移*/
        if (offset < 0)    {
            ret =  - EINVAL;
            break;
        }
        if ((unsigned int)offset > GLOBALMEM_SIZE) {
            ret =  - EINVAL;
            break;
        }
        filp->f_pos = (unsigned int)offset;
        ret = filp->f_pos;
        break;
    case 1:   /*相对文件当前位置偏移*/
        if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
            ret =  - EINVAL;
            break;
        }
        if ((filp->f_pos + offset) < 0) {
            ret =  - EINVAL;
            break;
        }
        filp->f_pos += offset;
        ret = filp->f_pos;
        break;
    default:
        ret =  - EINVAL;
        break;
    }
    return ret;
}

/*文件操作结构体*/
static const struct file_operations globalmem_fops = {
    .owner = THIS_MODULE,
    .llseek = globalmem_llseek,
    .read = globalmem_read,
    .write = globalmem_write,
    .ioctl = globalmem_ioctl,
    .open = globalmem_open,
    .release = globalmem_release,
};

/*初始化并注册cdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
    int err, devno = MKDEV(globalmem_major, index);

    cdev_init(&dev->cdev, &globalmem_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev, devno, 1);
    if (err)
        printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

/*设备驱动模块加载函数*/
int globalmem_init(void)
{
    int result;
    dev_t devno = MKDEV(globalmem_major, 0);

    /* 申请设备号*/
    if (globalmem_major)
        result = register_chrdev_region(devno, 1, "globalmem");
    else { /* 动态申请设备号 */
        result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
        globalmem_major = MAJOR(devno);
    }
    if (result < 0)
        return result;

    /* 动态申请设备结构体的内存*/
    globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
    if (!globalmem_devp) {    /*申请失败*/
        result =  - ENOMEM;
        goto fail_malloc;
    }

    memset(globalmem_devp, 0, sizeof(struct globalmem_dev));

    globalmem_setup_cdev(globalmem_devp, 0);
    return 0;

fail_malloc:
    unregister_chrdev_region(devno, 1);
    return result;
}

/*模块卸载函数*/
void globalmem_exit(void)
{
    cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
    kfree(globalmem_devp);     /*释放设备结构体内存*/
    unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
}

MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");

module_param(globalmem_major, int, S_IRUGO);

module_init(globalmem_init);
module_exit(globalmem_exit);

二.makefile文件如下(因为是在主机上运行的,由于ubuntu系统自带的有内核,所以也可以放在那个内核代码中使用 make moduls来产生.ko文件,这样的话,就不需要自制Makfile了,不过这个事先要你会才行


KVERS = $(shell uname -r)

# Kernel modules
obj-m += globalmem.o

# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0

build: kernel_modules

kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules

clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

三,make一下,生成.ko文件
四.最好切换用户到root模式,su
五.下面的操作,如果你学过内核移植的话,很好操作的,代码如下

root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# insmod globalmem.ko
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# lsmod
Module                  Size  Used by
globalmem              11140  0
binfmt_misc            16776  1
vboxvideo              10368  1
drm                    96296  2 vboxvideo
agpgart                42696  1 drm
vboxvfs                41800  0
bridge                 56340  0
stp                    10500  1 bridge
bnep                   20224  2
nfsd                  227756  13
lockd                  74156  1 nfsd
nfs_acl                11136  1 nfsd
auth_rpcgss            42144  1 nfsd
sunrpc                195424  13 nfsd,lockd,nfs_acl,auth_rpcgss
exportfs               12544  1 nfsd
input_polldev          11912  0
video                  25360  0
output                 11008  1 video
lp                     17156  0
ppdev                  15620  0
psmouse                61972  0
snd_intel8x0           37532  3
pcspkr                 10496  0
serio_raw              13316  0
snd_ac97_codec        112292  1 snd_intel8x0
ac97_bus                9856  1 snd_ac97_codec
snd_pcm_oss            46336  0
snd_mixer_oss          22656  1 snd_pcm_oss
snd_pcm                82948  3 snd_intel8x0,snd_ac97_codec,snd_pcm_oss
snd_seq_dummy          10756  0
snd_seq_oss            37760  0
snd_seq_midi           14336  0
snd_rawmidi            29696  1 snd_seq_midi
snd_seq_midi_event     15104  2 snd_seq_oss,snd_seq_midi
i2c_piix4              18448  0
snd_seq                56880  6 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_seq_midi_event
joydev                 18368  0
snd_timer              29704  2 snd_pcm,snd_seq
snd_seq_device         14988  5 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_rawmidi,snd_seq
snd                    62628  16 snd_intel8x0,snd_ac97_codec,snd_pcm_oss,snd_mixer_oss,snd_pcm,snd_seq_oss,snd_rawmidi,snd_seq,snd_timer,snd_seq_device
soundcore              15200  1 snd
snd_page_alloc         16904  2 snd_intel8x0,snd_pcm
vboxguest             160776  7 vboxvfs
parport_pc             40100  0
parport                42220  3 lp,ppdev,parport_pc
usbhid                 42336  0
e1000                 130500  0
fbcon                  46112  0
tileblit               10752  1 fbcon
font                   16384  1 fbcon
bitblit                13824  1 fbcon
softcursor              9984  1 bitblit
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6#
可以看到系统中已经globalmem 驱动模块,

六。建立节点:
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# mknod /dev/globalmem c 250 0
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# ls -l /dev/
total 0
crw-rw----+ 1 root    audio    14,  12 2011-04-26 18:58 adsp
crw-rw----+ 1 root    audio    14,   4 2011-04-26 18:58 audio
drwxr-xr-x  2 root    root         620 2011-04-26 18:58 block
drwxr-xr-x  3 root    root          60 2011-04-26 18:58 bus
lrwxrwxrwx  1 root    root           3 2011-04-26 18:58 cdrom -> sr0
drwxr-xr-x  2 root    root        3080 2011-04-26 18:58 char
crw-------  1 root    root      5,   1 2011-04-26 18:58 console
lrwxrwxrwx  1 root    root          11 2011-04-26 18:58 core -> /proc/kcore
crw-rw----  1 root    root     10,  60 2011-04-26 18:58 cpu_dma_latency
drwxr-xr-x  5 root    root         100 2011-04-26 18:58 disk
drwxr-xr-x  2 root    root          60 2011-04-26 18:58 dri
crw-rw----+ 1 root    audio    14,   3 2011-04-26 18:58 dsp
lrwxrwxrwx  1 root    root           3 2011-04-26 18:58 dvd -> sr0
crw-rw----  1 root    root     10,  63 2011-04-26 18:58 ecryptfs
lrwxrwxrwx  1 root    root          13 2011-04-26 18:58 fd -> /proc/self/fd
crw-rw-rw-  1 root    root      1,   7 2011-04-26 18:58 full
crw-rw-rw-+ 1 root    fuse     10, 229 2011-04-26 18:58 fuse
crw-r--r--  1 root    root    250,   0 2011-04-26 20:45 globalmem
crw-rw----  1 root    root    251,   0 2011-04-26 18:58 hidraw0
crw-rw----  1 root    root     10, 228 2011-04-26 18:58 hpet
prw-------  1 root    root           0 2011-04-26 18:58 initctl
........

7.查看读写是否成功
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# echo "hello world" >/dev/globalmem
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# cat /dev/globalmem
hello world
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6#

可以看到,可以写入和读出全局内存中的数据,证明还是成功的。。。。




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