AKever

导航

Linux TQ2440驱动HelloWorld

Linux TQ2440驱动HelloWorld

PS: 原理跳过, 程序贴上

======================================

环境

天嵌TQ2440(ARM 9)

Linux 2.6.30.4(TQ2440开发板系统)

Ubuntu 12.04.5 LTS  32bit (VMWare虚拟机系统)

gcc version 4.6.3(虚拟机 ubuntu gcc 版本)

==========================================

代码结构

----first_drvc(文件夹)

----| ---first_drvc.c

----| ---Makefile

----| ---first_drvc_test.c

=========================================

Ps: 代码根据环境做相应的调整 ...

  nfs搭建参考: http://www.cnblogs.com/TS-qrt/articles/linux_nfs.html

  驱动设备命令参考: http://www.cnblogs.com/TS-qrt/articles/linux_ko.html

 

挂载&卸载驱动

=========================================

 

insmod xxx.ko
rmmod xxx

 

 

==========================================

1.first_drvc.c(驱动程序)

 ps: 创建设备(device)的时候,由于linux版本的不同,创建设备的方法不一样,具体常看 linux2.6.xx.x/include/linux/device.h文件

         Linux 2.6.22.6版本是class_device_create, Linux 2.6.30.4版本是device_create(本版本)

/* first driver test chan*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>

//for create device after init driver
static struct class *firstdrvc_class;
static struct class_device *firstdrvc_class_dev;

static int first_drvc_open(struct inode * inode, struct file *file)
{
    printk("first_drvc_open\n");
    return 0;
}

static ssize_t first_drvc_write(struct file *file, const char __user *buffer,
                  size_t count, loff_t *ppos)
{
    printk("first_drvc_wirte\n");
    return 0;
}

static struct file_operations first_drvc_fops = {
    .owner        = THIS_MODULE,
    .open        = first_drvc_open,
    .write        = first_drvc_write,
};

int major;
static int first_drvc_init(void)
{
    major = register_chrdev(0, "first_drvc", &first_drvc_fops); // talk to kernel
    //create dev after init driver
    firstdrvc_class = class_create(THIS_MODULE, "first_drvc");
    firstdrvc_class_dev = device_create(firstdrvc_class, NULL, MKDEV(major, 0), NULL, "xyz");

    return 0;
}

static void first_drvc_exit(void)
{
    unregister_chrdev(major, "first_drvc"); // set down

    // rm dev
    device_unregister(firstdrvc_class_dev);
    class_destroy(firstdrvc_class);
    return 0;
}

module_init(first_drvc_init);
module_exit(first_drvc_exit);

MODULE_LICENSE("GPL");

 

2.Makefile(编译驱动程序)

obj-m:=first_drvc.o

CC=arm-linux-gcc
KERNELDIR=/opt/EmbedSky/linux-2.6.30.4
PWD:=$(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

3.first_drvc_test.c (测试驱动的程序)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    int fd;
    int val = 1;
    fd = open("/dev/xxx", O_RDWR); // "/dev/xyz"
    if(fd < 0)
        printf("can't open!\n");
    write(fd, &val, 4);
    return 0;
}

ps:编译

arm-linux-gcc -o first_drvc_test first_drvc_test.c

 

 驱动模板:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>

#include <asm/uaccess.h> // copy_from_user
#include <asm/io.h>    // ioremap

static struct class *keydrvc_class;
static struct class_device *keydrvc_class_dev;

volatile unsigned long *gpbcon = NULL;
volatile unsigned long *gpbdat = NULL;

static int key_drvc_open(struct inode * inode, struct file *file)
{
    /*
    *gpfcon &= ~((0x3<<(1*2)) | (0x3<<(4*2)) | (0x3<<(2*2)) | (0x3<<(0*2)));
    printk("first_drvc_open\n");
    */
    return 0;
}

static ssize_t key_drvc_write(struct file *file, const char __user *buffer,
                  size_t count, loff_t *ppos)
{
    /*
    int val;
    copy_from_user(&val, buf, count); //    copy_to_user();
    *gpfdat &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
    */
    return 0;
}

ssize_t key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    /* 
    unsigned char key_vals[4];
    int regval;
    if (size != sizeof(key_vals))
        return -EINVAL;
    regval = *gpfdat;
    key_vals[0] = (regval & (1<<1)) ? 1 : 0;
    key_vals[1] = (regval & (1<<4)) ? 1 : 0;
    key_vals[2] = (regval & (1<<2)) ? 1 : 0;
    key_vals[3] = (regval & (1<<0)) ? 1 : 0;
    copy_to_user(buf, key_vals, sizeof(key_vals));
    return sizeof(key_vals);
    */
    return 0;
}

static struct file_operations key_drvc_fops = {
    .owner        = THIS_MODULE,
    .open        = key_drvc_open,
    .write        = key_drvc_write,
    .read        = key_drvc_read,
};


int major;
static int key_drvc_init(void)
{
    major = register_chrdev(0, "key_drvc", &key_drvc_fops);
    // class and device
    keydrvc_class = class_create(THIS_MODULE, "key_drvc");
    keydrvc_class_dev = device_create(keydrvc_class, NULL, MKDEV(major, 0), NULL, "keys");

    //gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);
    //gpbdat = gpbcon + 1;

    return 0;
}

static void key_drvc_exit(void)
{
    unregister_chrdev(major, "key_drvc");
    class_device_unregister(keydrvc_class_dev);
    class_destroy(keydrvc_class);
    
    //iounmap(gpbcon);
}

module_init(key_drvc_init);
module_exit(key_drvc_exit);

MODULE_LICENSE("GPL")

 

 

-------------- THE END ------------------------------

 

posted on 2016-09-16 21:26  AKever  阅读(259)  评论(0)    收藏  举报