歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> 簡單的LINUX字符設備驅動及編譯進Linux內核

簡單的LINUX字符設備驅動及編譯進Linux內核

日期:2017/3/3 12:16:56   编辑:Linux內核


簡單的LINUX字符設備驅動及編譯進Linux內核…

2010-07-06 11:23:00| 分類: 嵌入式linux|舉報|字號 訂閱


下載LOFTER我的照片書 |
驅動代碼:
#include <linux/init.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#ifndef MODULE
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#define MAJOR_NUM 253
MODULE_LICENSE("GPL");
int dev_test_open(struct inode *, struct file *);
ssize_t dev_test_read(struct file *, char *, size_t, loff_t *);
ssize_t dev_test_write(struct file *, const char *, size_t, loff_t *);
int dev_test_release(struct inode *, struct file *);
struct file_operations hello_fops =
{
open:dev_test_open,
read:dev_test_read,
write:dev_test_write,
release:dev_test_release,
};
char *pBuff;
static int __init dev_test_init(void)
{
printk("<1>hello dev test\r\n");
if (register_chrdev(MAJOR_NUM, "dev_test", &hello_fops))
printk("<1>register failed\r\n");
return 0;
}
static void __exit dev_test_exit(void)
{
printk("<1>bye dev_test\r\n");
if (unregister_chrdev(MAJOR_NUM, "dev_test"))
printk("<1>unregiter failed\r\n");
}
int dev_test_open(struct inode *pInode, struct file *pFile)
{
pBuff = (char*)kmalloc(128, GFP_KERNEL);
if (pBuff == NULL)
printk("<1>kmalloc memory failed\r\n");
return 0;
}
int dev_test_release(struct inode *pInode, struct file *pFile)
{
kfree(pBuff);
return 0;
}
ssize_t dev_test_read(struct file *pFile, char *buff, size_t len, loff_t *pOff)
{
if (copy_to_user(buff, pBuff, len))
{
printk("<1>copy_from_user failed\r\n");
return -EFAULT;
}
return len;
}
ssize_t dev_test_write(struct file *pFile, const char *buff, size_t len, loff_t *pOff)
{
int i = 0;
if (copy_from_user(pBuff, buff, len))
{
printk("<1>copy_to_user failed\r\n");
return -EFAULT;
}
while (pBuff[i] != '\0')
{
if (pBuff[i] > 0x40 && pBuff[i] < 0x60)
pBuff[i] += 0x20;
else if (pBuff[i] > 0x60 && pBuff[i] < 0x80)
pBuff[i] -= 0x20;
i++;
}
return len;
}
module_init(dev_test_init);
module_exit(dev_test_exit);
=========================================================
把該代碼保存為/usr/local/src/linux-2.x.x/driver/char/dev_test.c
(假設內核代碼的目錄為/usr/local/src/linux-2.x.x)
=========================================================
下面就是編譯模塊,按動態加載和靜態加載進內核分為兩種編譯模式.
(1) 動態加載到內核模式,這個比較簡單, 但是uClinux不支持這種方式, 所以以linux為例.
A. 用 gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux-2.x.x/include -c -o dev_test.o dev_test.c
B. 在/usr/local/src/linux-2.x.x/driver/char/上用shell 輸入 insmod dev_test.o
C. 在shell上使用 mknod /dev/dev_test c 253 0 創建設備文件
到這裡就搞定了, 用戶就可以在用戶層使用open read write 等函數對"/dev/dev_test"這個文件進行操作, 內核就會調用相應的函數處理用戶層的請求.
當用戶不需要使用這個驅動模塊時,可以用rmmod dev_test進行卸載.
--------------------------------------------------------------------------------------------------------
(2) 靜態編入內核,通過 這種方法編譯的,只要內核一啟動,模塊就會自動加載到內核
A. 在/usr/local/src/linux-2.x.x/driver/char/下的Makefile文件中加入以下代碼
ifeq ($(CONFIG_DEV_TEST),y)
obj-y += dev_test.o
endif
B. 在/usr/local/src/linux-2.x.x/driver/char/下的Makefile文件中加入以下代碼
bool 'support for dev_test' CONFIG_DEV_TEST y
如果沒有該文件, 就在/usr/local/src/linux-2.x.x/arch/xxxnommu/目錄下的config.in文件中的字符驅動部分加入.
C. 在shell上使用mknod /dev/dev_test c 253 0 創建設備文件
(如果是uClinux, 則使用mknod /xxx/romdist/dev/dev_test c 253 0, /xxx/romdist為嵌入式文件系統的目錄)
D. 編譯固件和文件系統鏡像後燒到目標版上就可以了.
===========================================================
下面是用戶層的應用程序代碼, 它使用open, read, write等函數來調用內核實現的驅動代碼.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
char buff[128];
fd = open("/dev/dev_test", O_RDWR);
while(1)
{
printf("enter the string:");
scanf("%s", buff);
write(fd, buff, 128);
memset(buff, 0, 128);
read(fd, buff, 128);
printf("%s\r\n", buff);
}
return 0;
}
Copyright © Linux教程網 All Rights Reserved