- 论坛徽章:
- 0
|
首先编写驱动程序,在驱动程序中主要实现read,poll,interrupt,其中read主要针对非阻塞方法进行处理,实现poll方法,以满足应用程序对select,FD_SET……一套函数的调用。定义等待队列static DECLARE_WAIT_QUEUE_HEAD(queue);在中断中调用wake_up_interruptible(&queue);唤醒等待队列,在poll中调用poll_wait(filp, &queue, wait);等待中断的唤醒。
注意事项,编译驱动的交叉编译器要和编译内核的交叉编译器一致。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SKB_NAME "/dev/skbdriver"
int __init skb_init(void);
void __exit skb_exit(void);
void gpio_init(void);
static unsigned int skb_poll(struct file *filp, poll_table *wait);
static void skb_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static ssize_t skb_read(struct file *filp, char *buf, size_t count, loff_t *l);
static int skb_open(struct inode *inode, struct file *filp);
static int skb_release(struct inode *inode, struct file *filp);
//static wait_queue_head_t queue;
static DECLARE_WAIT_QUEUE_HEAD(queue);
static unsigned char portdata[2];
void gpio_init(void){
unsigned long temp;
//disable interrupt
// temp = readl(VIC1INTENABLE)&0xf7ffffff;
// writel(temp,VIC1INTENABLE);
disable_irq(IRQ_GPIO);
//select irq mode
temp = readl(VIC1INTSELECT)&0xf7ffffff;
writel(temp,VIC1INTSELECT);
//setup EGPIO(A(3-7),B(0,2))
//direction register
temp = readl(GPIO_PADDR)&0x07;
writel(temp,GPIO_PADDR);
temp = readl(GPIO_PBDDR)&0xfa;
writel(temp,GPIO_PBDDR);
//interrupt enable register
temp = readl(GPIO_AINTEN)|~0x07;
writel(temp,GPIO_AINTEN);
temp = readl(GPIO_BINTEN)|~0xfa;
writel(temp,GPIO_BINTEN);
//inttype1 register
temp = readl(GPIO_AINTTYPE1)|~0x07;
writel(temp,GPIO_AINTTYPE1);
temp = readl(GPIO_AINTTYPE2)|~0xfa;
writel(temp,GPIO_AINTTYPE2);
temp = readl(GPIO_BINTTYPE1)&0x07;
writel(temp,GPIO_BINTTYPE1);
temp = readl(GPIO_BINTTYPE2)&0xfa;
writel(temp,GPIO_BINTTYPE2);
//EOI register
temp = readl(GPIO_AEOI)|~0x07;
writel(temp,GPIO_AEOI);
temp = readl(GPIO_BEOI)|~0xfa;
writel(temp,GPIO_BEOI);
//debounce register
temp = readl(GPIO_ADB)|~0x07;
writel(temp,GPIO_ADB);
temp = readl(GPIO_BDB)|~0xfa;
writel(temp,GPIO_BDB);
//enable interrupt
// temp = readl(VIC1INTENABLE)|~0xf7ffffff;
// writel(temp,VIC1INTENABLE);
// init_waitqueue_head(&queue);
portdata[0]=0xf8;
portdata[1]=0x05;
enable_irq(IRQ_GPIO);
}
static unsigned int skb_poll(struct file *filp, poll_table *wait)
{
// printk("before poll_wait\n");
poll_wait(filp, &queue, wait);
// printk("in skb_poll\n");
if (((portdata[0]&0xf8)!=0xf8)||((portdata[1]&0x05)!=0x05))
{
// printk("faint\n");
return POLLIN | POLLRDNORM;
}
return 0;
}
static void skb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long temp;
disable_irq(IRQ_GPIO);
temp = readl(GPIO_AEOI)|~0x07;
writel(temp,GPIO_AEOI);
temp = readl(GPIO_BEOI)|~0xfa;
writel(temp,GPIO_BEOI);
portdata[0]=readl(GPIO_PADR);
portdata[1]=readl(GPIO_PBDR);
// printk("%x\t%x\n",portdata[0],portdata[1]);
wake_up_interruptible(&queue);
enable_irq(IRQ_GPIO);
}
static ssize_t skb_read(struct file *filp, char *buf, size_t count, loff_t *l)
{
unsigned char data[2];
ssize_t retval;
data[0]=portdata[0];
data[1]=portdata[1];
if(((data[0]&0xf8)==0xf8)&&((data[1]&0x05)==0x05))
{
if (filp->f_flags & O_NONBLOCK)
{
retval = -EAGAIN;
}
}
if(copy_to_user(buf, &data, sizeof(data)))
return -EFAULT;
// printk("in skb_read\n");
portdata[0]=0xf8;
portdata[1]=0x05;
return (sizeof(data));
}
static int skb_open(struct inode *inode, struct file *filp)
{
// printk("in open\n");
MOD_INC_USE_COUNT;
return 0;
}
static int skb_release(struct inode *inode, struct file *filp)
{
// printk("in release\n");
MOD_DEC_USE_COUNT;
return 0;
}
struct file_operations skb_fops = {
read: skb_read,
poll: skb_poll,
open: skb_open,
release: skb_release,
};
int __init skb_init(void){
int rc;
int ret;
rc = register_chrdev(144,SKB_NAME, &skb_fops);
if(rc
printk(KERN_INFO"LINBUS: Can't get Major \n");
return rc;
}
printk("*****************rc is %d\n",rc) ;
if ((ret = request_irq(IRQ_GPIO,skb_interrupt,SA_INTERRUPT, SKB_NAME, NULL)))
{
printk("skb_init: failed to register IRQ\n");
free_irq(IRQ_GPIO, NULL);
return ret;
}
gpio_init();
return 0;
}
void __exit skb_exit(void)
{
free_irq(IRQ_GPIO, NULL);
// devfs_unregister_chrdev(TS_MAJOR, TS_NAME);
// printk("ads7843 touch screen driver removed\n");
}
module_init(skb_init);
module_exit(skb_exit);
然后修改/root/Qt_arm/qt-2.3.7-emb/src/kernel/qkeyboard_qws.cpp程序,主要参考QWSTtyKeyboardHandler的实现方法,其中QSocketNotifier的实现类似于FD_SET,也可能就是对FD_SET的封装。最后在QWSKeyboardHandler *QWSServer::newKeyboardHandler( const QString &spec )函数中将所实现的类实例化else if ( type == "SKB" ) {
handler = new QWSSKBKeyboardHandler(device);
//modified by bugqiao begin
class QWSSKBKeyboardHandler : public QWSPC101KeyboardHandler
{
Q_OBJECT
public:
QWSSKBKeyboardHandler(const QString& device); virtual ~QWSSKBKeyboardHandler();
private slots:
void readKeyboardData();
private:
int fd;
};
//modified by bugqiao end
/* SKB driver */
//modified by bugqiao begin
QWSSKBKeyboardHandler::QWSSKBKeyboardHandler(const QString& device)
{
fd = open(device.isEmpty()?"/dev/skbdriver":device.latin1(),O_RDONLY|O_NONBLOCK, 0);
qDebug("fd = %d\n",fd);
if ( fd >= 0 ) {
QSocketNotifier *notifier;
notifier = new QSocketNotifier( fd, QSocketNotifier::Read, this );
connect( notifier, SIGNAL(activated(int)),this,
SLOT(readKeyboardData()) );
}
}
QWSSKBKeyboardHandler::~QWSSKBKeyboardHandler()
{
close(fd);
}
void QWSSKBKeyboardHandler::readKeyboardData()
{
unsigned char portdata[2];
int n = read(fd, &portdata, sizeof(portdata) );
int tmp;
qDebug("n=%d\tportdata[0]=%x\tportdata[1]=%x\n",n,portdata[0],portdata[1]);
if ( n != 2 )
return;
if((tmp=portdata[0]&0x08)==0) {
qDebug("up\n");
processKeyEvent( 0, Qt::Key_Up, 0, 1, false );
} else if((tmp=portdata[0]&0x10)==0) {
qDebug("right\n");
processKeyEvent( 0, Qt::Key_Right, 0, 1, false );
} else if((tmp=portdata[0]&0x20)==0) {
qDebug("down\n");
processKeyEvent( 0, Qt::Key_Down, 0, 1, false );
} else if((tmp=portdata[0]&0x40)==0) {
qDebug("left\n");
processKeyEvent( 0, Qt::Key_Left, 0, 1, false );
} else if((tmp=portdata[0]&0x80)==0) {
qDebug("esc\n");
processKeyEvent( 0, Qt::Key_Escape, 0, 1, false );
} else if((tmp=portdata[1]&0x01)==0) {
qDebug("return\n");
processKeyEvent( 0, Qt::Key_Return, 0, 1, false );
}
}
//modified by bugqiao end
最后在编写的脚本文件中增加export QWS_KEYBOARD=SKB:/dev/skbdriver
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/8800/showart_96230.html |
|