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