linux驅動程序和應用程序交互實現_基於2440

在學習安卓時候對驅動還是有疑惑 ,用jz2440重寫驅動

板子:jz2440
系統:ubutu16
最後所有代碼在底部

先配置板子uboot能與主機互相聯通

如果配置是
開發版 192.168.31.10
電腦 192.168.31.5
2440_ubuntu 192.168.31.51
4412 192.168.31.200

配置uboot的ip和服務器ip

set ipaddr 192.168.31.10
set serverip 192.168.31.51
setenv netmask 255.255.255.0
setenv gatewayip 192.168.31.1
save

在這裏插入圖片描述
ping 的到虛擬機

可以使用nfs掛載根目錄 板子啓動根文件系統在主機上方便傳輸,也可以不弄,在windos傳輸

進入uboot 輸入print
在這裏插入圖片描述
bootarg root(根文件系統)在nandflash上 改爲在虛擬機上
bootcmd 啓動內核的命令

進入板子的linux 用nfs傳輸文件


mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 192.168.31.51:/work/nfs_root /mnt

在這裏插入圖片描述
根據button_test.c 編譯出可執行驅動的文件 button_test

執行make命令生成驅動文件
在這裏插入圖片描述
裝載驅動文件

insmod buttons.ko

用 lsmod 查看裝載了沒有
在這裏插入圖片描述

cat /proc/devices

在這裏插入圖片描述
分配給我的設備號是252
在main函數中 要打開dev/buttons
在這裏插入圖片描述
查看是否有這個設備節點
在這裏插入圖片描述
現在已經有了如果沒有手工創建設備節點

mknod /dev/buttons c 252 0

代碼裏有自動創建設備節點
在這裏插入圖片描述
register_chrdev 分配主設備號,給內核知道,把驅動註冊進內核數組
class_create 創建一個/sys/class/sixth_dev的類,類下面生成buttons設備
class_device_create 創建/dev/buttons 文件,給 app 的 fb = open() 使用

在這裏插入圖片描述
在這裏插入圖片描述
裏面有主設備號信息次設備號信息
在這裏插入圖片描述

mdev根據這些設備信息生成設備節點

系統自帶的熱拔插程序 當有了設備信息後 自動生成設備節點 應用程序只要名字對了,打開裏面的設備節點就能使用
在這裏插入圖片描述
在這裏插入圖片描述

驅動和應用程序交換數據

在驅動程序裏裏有 copy_to_usr copy_from_usr 對應着應用程序裏的read write

copy_to_usr( to, &from, sizeof(from))

To:用戶空間函數 (可以是數組)

From:內核空間函數(可以是數組)

sizeof(from):內核空間要傳遞的數組的長度
在這裏插入圖片描述
驅動代碼
在這裏插入圖片描述
應用代碼
在這裏插入圖片描述

copy_from_usr(&from , to , sizeof(to) )

To:用戶空間函數 (可以是數組)

From:內核空間函數(可以是數組)

sizeof(from):內核空間要傳遞的數組的長度
驅動代碼
在這裏插入圖片描述
應用代碼
在這裏插入圖片描述

button_test.c


 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>


/* sixthdrvtest 
  */
int fd;

void my_signal_fun(int signum)
{
	unsigned char key_val;
	read(fd, &key_val, 1);
	printf("key_val: 0x%x\n", key_val);
}

int main(int argc, char **argv)
{
	unsigned char key_val;
	int ret;
	int Oflags;

	//signal(SIGIO, my_signal_fun);
	
	fd = open("/dev/buttons", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
		return -1;
	}

	//fcntl(fd, F_SETOWN, getpid());
	
	//Oflags = fcntl(fd, F_GETFL); 
	
	//fcntl(fd, F_SETFL, Oflags | FASYNC);


	while (1)
	{
		ret = read(fd, &key_val, 1);
		printf("key_val: 0x%x, ret = %d\n", key_val, ret);
		//sleep(5);
	}
	
	return 0;
}


button.c(驅動文件,用makefile編譯)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>


static struct class *sixthdrv_class;
static struct class_device	*sixthdrv_class_dev;

volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;

volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;

static struct timer_list buttons_timer;


static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中斷事件標誌, 中斷服務程序將它置1,sixth_drv_read將它清0 */
static volatile int ev_press = 0;

static struct fasync_struct *button_async;


struct pin_desc{
	unsigned int pin;
	unsigned int key_val;
};


/* 鍵值: 按下時, 0x01, 0x02, 0x03, 0x04 */
/* 鍵值: 鬆開時, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;

struct pin_desc pins_desc[4] = {
	{S3C2410_GPF0, 0x01},
	{S3C2410_GPF2, 0x02},
	{S3C2410_GPG3, 0x03},
	{S3C2410_GPG11, 0x04},
};

static struct pin_desc *irq_pd;

//static atomic_t canopen = ATOMIC_INIT(1);     //定義原子變量並初始化爲1

static DECLARE_MUTEX(button_lock);     //定義互斥鎖

/*
  * 確定按鍵值
  */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	/* 10ms後啓動定時器 */
	irq_pd = (struct pin_desc *)dev_id;
	mod_timer(&buttons_timer, jiffies+HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
}

static int sixth_drv_open(struct inode *inode, struct file *file)
{
#if 0	
	if (!atomic_dec_and_test(&canopen))
	{
		atomic_inc(&canopen);
		return -EBUSY;
	}
#endif		

	if (file->f_flags & O_NONBLOCK)
	{
		if (down_trylock(&button_lock))
			return -EBUSY;
	}
	else
	{
		/* 獲取信號量 */
		down(&button_lock);
	}

	/* 配置GPF0,2爲輸入引腳 */
	/* 配置GPG3,11爲輸入引腳 */
	request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
	request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
	request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
	request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);	

	return 0;
}

ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	if (size != 1)
		return -EINVAL;

	if (file->f_flags & O_NONBLOCK)
	{
		if (!ev_press)
			return -EAGAIN;
	}
	else
	{
		/* 如果沒有按鍵動作, 休眠 */
		wait_event_interruptible(button_waitq, ev_press);
	}

	/* 如果有按鍵動作, 返回鍵值 */
	copy_to_user(buf, &key_val, 1);
	ev_press = 0;
	
	return 1;
}


int sixth_drv_close(struct inode *inode, struct file *file)
{
	//atomic_inc(&canopen);
	free_irq(IRQ_EINT0, &pins_desc[0]);
	free_irq(IRQ_EINT2, &pins_desc[1]);
	free_irq(IRQ_EINT11, &pins_desc[2]);
	free_irq(IRQ_EINT19, &pins_desc[3]);
	up(&button_lock);
	return 0;
}

static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
	poll_wait(file, &button_waitq, wait); // 不會立即休眠

	if (ev_press)
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

static int sixth_drv_fasync (int fd, struct file *filp, int on)
{
	printk("driver: sixth_drv_fasync\n");
	return fasync_helper (fd, filp, on, &button_async);
}


static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 這是一個宏,推向編譯模塊時自動創建的__this_module變量 */
    .open    =  sixth_drv_open,     
	.read	 =	sixth_drv_read,	   
	.release =  sixth_drv_close,
	.poll    =  sixth_drv_poll,
	.fasync	 =  sixth_drv_fasync,
};


int major;

static void buttons_timer_function(unsigned long data)
{
	struct pin_desc * pindesc = irq_pd;
	unsigned int pinval;

	if (!pindesc)
		return;
	
	pinval = s3c2410_gpio_getpin(pindesc->pin);

	if (pinval)
	{
		/* 鬆開 */
		key_val = 0x80 | pindesc->key_val;
	}
	else
	{
		/* 按下 */
		key_val = pindesc->key_val;
	}

    ev_press = 1;                  /* 表示中斷髮生了 */
    wake_up_interruptible(&button_waitq);   /* 喚醒休眠的進程 */
	
	kill_fasync (&button_async, SIGIO, POLL_IN);
}


static int sixth_drv_init(void)
{
	init_timer(&buttons_timer);
	buttons_timer.function = buttons_timer_function;
	//buttons_timer.expires  = 0;
	add_timer(&buttons_timer); 

	major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);//給內核知道

	sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");

	/* 爲了讓mdev根據這些信息來創建設備節點 */
	sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
	gpfdat = gpfcon + 1;

	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
	gpgdat = gpgcon + 1;

	return 0;
}

static void sixth_drv_exit(void)
{
	unregister_chrdev(major, "sixth_drv");
	class_device_unregister(sixthdrv_class_dev);
	class_destroy(sixthdrv_class);
	iounmap(gpfcon);
	iounmap(gpgcon);
	return 0;
}


module_init(sixth_drv_init);

module_exit(sixth_drv_exit);

MODULE_LICENSE("GPL");


makefile

KERN_DIR = /work/system/linux-2.6.22.6

all:
	make -C $(KERN_DIR) M=`pwd` modules 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

obj-m	+= buttons.o

KERM_DIR是驅動程序要根據所用內核才能編譯出 虛擬機裏要有這個內核

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章