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.完成,手工

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM