Linux下编写模块驱动,注册设备,编译,并使用QT调用方法

1.驱动编写

/************************************************
LED的驱动,在TX2440A开发板上做测试

维护记录:  2009-10-18  V1.0    

linux内核:2.6.31

硬件接法:
        LED1 --> GPF0
        LED2 --> GPF1
        LED3 --> GPF2
        LED4 --> GPF3
        低电平点亮
驱动用法:
        设备名称:TX2440-led
        点亮一个灯:LED_ON
        熄灭一个灯:LED_OFF
        点亮所有灯:ALL_LED_ON
        熄灭所有灯:ALL_LED_OFF
说明:
        内核源码里已经有LED的驱动,将它们注释掉
        在arch/arm/plat-s3c24xx/common-smdk.c中
        将GPF0-GPF3设为输出,全部输出低电平
*************************************************/
#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 <asm/arch/regs-gpio.h>
//#include <mach/regs-gpio.h>
//#include <asm/hardware.h>
//#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h>

#define DEVICE_NAME    "zhou-led"    /* 设备名称 */        
static int LED_Major = 0;            /* 主设备号 */

#define LED_OFF             0
#define LED_ON             1
#define ALL_LED_OFF      3
#define ALL_LED_ON       4

//用来指定LED所用的GPIO引脚 
static unsigned long led_table [] =
{
    1,//S3C2410_GPF(0),
    2,//S3C2410_GPF(1),
    3,//S3C2410_GPF(2),
    4,//S3C2410_GPF(3),
};

static int TX2440_led_open(struct inode *inode, struct file *file)
{
//    MOD_INC_USE_COUNT;
    printk("TX2440-LED Driver Open Called!\n");
    return 0;
}

static int TX2440_led_release(struct inode *inode, struct file *file)
{
//    MOD_DEC_USE_COUNT;
    printk("TX2440-LED Driver Release Called!\n");
    return 0;
}

static int TX2440_led_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{

    int i;
    printk("TX2440_led_ioctl\n");
    if (arg > 4)
    {
        return -EINVAL;
    }
    switch(cmd)
    {
        case LED_ON:  //set the pin
            //s3c2410_gpio_setpin(led_table[arg], 0);
            break;

        case LED_OFF:  //clr the pin
            //s3c2410_gpio_setpin(led_table[arg], 1);
            break;
            
        case ALL_LED_ON:  //set all pin
            for (i = 0; i < 4; i++)
                //s3c2410_gpio_setpin(led_table[i], 0);
            break;
            
        case ALL_LED_OFF:  //clr all pin
            for (i = 0; i < 4; i++)
                //s3c2410_gpio_setpin(led_table[i], 1);
            break;

        default:
            return -EINVAL;
    }
}

static struct file_operations TX2440_led_fops =
{
    .owner  =   THIS_MODULE,
    .open   =   TX2440_led_open, 
    .release =  TX2440_led_release,
    .unlocked_ioctl  =   TX2440_led_ioctl,

};

static struct class *led_class;

static int __init TX2440_led_init(void)
{

    printk("TX2440 LED DRIVER MODULE INIT\n");

    LED_Major = register_chrdev(0, DEVICE_NAME, &TX2440_led_fops);
    if (LED_Major < 0)
    {
        printk(DEVICE_NAME " can't register major number\n");
        return LED_Major;
    }
    printk("register TX2440-LED Driver OK! Major = %d\n", LED_Major);

    led_class = class_create(THIS_MODULE, DEVICE_NAME);
    if(IS_ERR(led_class))
    {
        printk("Err: failed in TX2440-LED class. \n");
        return -1;
    }

    device_create(led_class, NULL, MKDEV(LED_Major, 0), NULL, DEVICE_NAME);

    printk(DEVICE_NAME " initialized\n");
    return 0;
}

static void __exit TX2440_led_exit(void)
{
    printk("TX2440 LED DRIVER MODULE EXIT\n");
    unregister_chrdev(LED_Major, DEVICE_NAME);
    device_destroy(led_class, MKDEV(LED_Major, 0));
    class_destroy(led_class);
}

module_init(TX2440_led_init);
module_exit(TX2440_led_exit);

MODULE_AUTHOR("www.xxxx.com");        
MODULE_DESCRIPTION("XXXX LED Driver");    
MODULE_LICENSE("GPL");


2.编写makefile文件

obj-m := led.o
#modules-objs:= TX2440_led.o

KDIR := /lib/modules/`uname -r`/build
PWD := $(shell pwd)

default:
    make -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions *.order *.symvers

3.编译:输入,make命令,生成 *.ko 模块文件

4.安装模块,输入命令:insmod led.ko ,此时模块安装成功,在输入命令:ls /dev/ ,即可看到模块创建的设备名:zhou-led,此后使用标准的linux的open和ioctl便可操作。

 

5.新建工程,编写QT代码

led.h

#ifndef LED_H
#define LED_H
#ifdef __cplusplus
extern "C"{
    #endif
    extern int led_open(const char *devname);
    int led_ioctl(unsigned int cmd, unsigned long led_num);
    extern int led_close();
    extern int led_fd;
    #ifdef __cplusplus
}
#endif
#endif  //LED_H

led.c

#include "led.h"
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define IOCTL_LED_ON  0
#define IOCTL_LED_OFF 1

int led_fd=0;
int led_open(const char *devname)
{
    led_fd=open(devname, O_RDWR);//调用驱动函数,打开设备文件
    printf("LED driver is ok\n");
    if(led_fd<0) //如果打开失败
    {
        printf("open device %s failed.\n",devname);
        return -1;
    }
    return 0;
}

int led_ioctl(unsigned int cmd, unsigned long led_num)
{
    
    printf("on/off is ok\t");
    printf("cmd=%d\n",cmd);
    ioctl(led_fd, cmd, led_num-1); //调用驱动函数,设置对应io口的状态
    return 0;
}

int led_close(void)
{
    if(led_fd)
        close(led_fd);//调用驱动函数,关闭设备文件
}

wedget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QCheckBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <QDirectPainter>

class Widget : public QWidget
{
    Q_OBJECT
    
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:

    QPushButton *ledbutton_on;
    QPushButton *ledbutton_off;

    QPushButton *led1button;
    QPushButton *led2button;
    QPushButton *led3button;
    QPushButton *led4button;

    QVBoxLayout *vlayout;
public slots:

    void led1_clicked();
    void led2_clicked();
    void led3_clicked();
    void led4_clicked();

    void led_on();
    void led_off();


};

#endif // WIDGET_H

wedget.app

#include "widget.h"
#include "led.h"

//LEDx=0表示点亮,LEDx=1表示熄灭
static unsigned int LED1=1,LED2=1,LED3=1,LED4=1;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //新建窗口控件并设置控件的布局以及对应的槽函数。
    ledbutton_on = new  QPushButton(tr("ALL_ON"));
    ledbutton_off = new QPushButton(tr("ALL_OFF"));
    connect(ledbutton_on, SIGNAL(clicked()), this, SLOT(led_on()));
    connect(ledbutton_off, SIGNAL(clicked()), this, SLOT(led_off()));
 
    led1button = new QPushButton(tr("LED1"));
    led2button = new QPushButton(tr("LED2"));
    led3button = new QPushButton(tr("LED3"));
    led4button = new QPushButton(tr("LED4"));
    connect(led1button, SIGNAL(clicked()), this, SLOT(led1_clicked()));
    connect(led2button, SIGNAL(clicked()), this, SLOT(led2_clicked()));
    connect(led3button, SIGNAL(clicked()), this, SLOT(led3_clicked()));
    connect(led4button, SIGNAL(clicked()), this, SLOT(led4_clicked()));

    vlayout = new QVBoxLayout;
    vlayout->addWidget(ledbutton_on);
    vlayout->addWidget(ledbutton_off);

    vlayout->addWidget(led1button);
    vlayout->addWidget(led2button);
    vlayout->addWidget(led3button);
    vlayout->addWidget(led4button);

    led_open("dev/TX2440-led");//选择打开的设备节点,找到要控制的设备驱动
    printf("C++ /dev/TX2440-led \n");

    this->setLayout(vlayout);//添加主布局到窗口中
/*    int screenWidth = QDirectPainter::screenWidth();
    int screenHeight = QDirectPainter::screenHeight();
    this->resize(screenWidth, screenHeight);
*/
    this->resize(320, 240);//设置窗口界面大小
}

Widget::~Widget()
{

}
/*****************各个槽函数的具体实现****************/

//led_ioctl()的第一个参数为cmd,第二个参数为arg,分别代表switch的判断执行语句和控制的第几个led。
void Widget::led_on()
{    

    led_ioctl(4, 1);//第二个参数在这里并不起作用,但必须>=1(因为后面有led_num-1)
    printf("led_on clicked\n");
    LED1=1;LED2=1;LED3=1;LED4=1;
}

void Widget::led_off()
{    
    led_ioctl(3, 1);//第二个参数在这里并不起作用,但必须设置为1
    printf("led_off clicked\n");
    LED1=0;LED2=0;LED3=0;LED4=0;
}

void Widget::led1_clicked()
{
    
    if(LED1==1)
    {
        LED1=0;
        printf("LED1=%d\n",LED1);
        led_ioctl(LED1, 1);
        printf("\n");
    }
    else
    {
        LED1=1;
        printf("LED1=%d\n",LED1);
        led_ioctl(LED1, 1);
        printf("\n");
    }
    
}

void Widget::led2_clicked()
{

    if(LED2==1)
    {
        LED2=0;
        printf("LED2=%d\n",LED2);
        led_ioctl(LED2, 2);
        printf("\n");
    }
    else
    {
        LED2=1;
        printf("LED2=%d\n",LED2);
        led_ioctl(LED2, 2);
        printf("\n");
    }
}

void Widget::led3_clicked()
{

    if(LED3==1)
    {
        LED3=0;
        printf("LED3=%d\n",LED3);
        led_ioctl(LED3, 3);
        printf("\n");
    }
    else
    {
        LED3=1;
        printf("LED3=%d\n",LED3);
        led_ioctl(LED3, 3);
        printf("\n");
    }
}

void Widget::led4_clicked()
{

    if(LED4==1)
    {
        LED4=0;
        printf("LED4=%d\n",LED4);
        led_ioctl(LED4, 4);
        printf("\n");
    }
    else
    {
        LED4=1;
        printf("LED4=%d\n",LED4);
        led_ioctl(LED4, 4);
        printf("\n");
    }
}

 

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    
    return a.exec();
}

 

6.完成,手工

 

posted on 2017-10-30 21:40  酷卡宜  阅读(4454)  评论(0)    收藏  举报

导航