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("