您的位置:首页 > 运维架构 > Linux

linux驱动说开去(一)--模块示例

2018-02-22 12:41 471 查看
本系列将以一个简单的驱动开发例子扩展讲述驱动开发各要点

一、基础知识
Linux 设备打开依次跨越层次:应用程序->系统调用接口->VFS层->当前设备文件系统(如字符设备)->驱动->硬件



Linux设备驱动分为:字符设备、块设备和网络设备。原理图如下:



  二、代码实现
2.1.1驱动层代码实现

创建目录/home/workplace/sc2410_android/kernel/drivers/leon_test
将下述hello.c hello.h Makefie放于上述目录

hello.c
/*
*  * =====================================================================================
*   *
*       Filename:  hello.c
*
*    Description:  hello_mod
*
*        Version:  1.0
*        Created:  02/22/2018 10:07:55 AM
*       Revision:  none
*       Compiler:  gcc
*
*         Author:  Leon, pengliang2851035@163.com
*        Company:  None
*
* =====================================================================================
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
#include "hello.h"

#define MAJOR_NUM 260
#define MINOR_NUM 0
#define IN_BUF_LEN 256
#define OUT_BUF_LEN 512

MODULE_AUTHOR("Leon");
MODULE_DESCRIPTION("Hello_mod driver by Leon");

static struct class * hello_class;
static struct cdev hello_cdev;
static dev_t devnum = 0;
static char * modname = "hello_mod";
static char * devicename = "hello";
static char * classname = "hello_class";

static int open_count = 0;
static struct semaphore sem;
static DEFINE_SPINLOCK(spin);
static char * inbuffer = NULL;
static char * outbuffer = NULL;
static lang_t langtype;

static int hello_mod_open(struct inode *, struct file *);
static int hello_mod_release(struct inode *, struct file *);
static ssize_t hello_mod_read(struct file *, char *, size_t, loff_t *);
static ssize_t hello_mod_write(struct file *, const char *, size_t, loff_t *);
static long hello_mod_ioctl(struct file *, unsigned int, unsigned long);

struct file_operations hello_mod_fops =
{
.owner = THIS_MODULE,
.open = hello_mod_open,
.read = hello_mod_read,
.write = hello_mod_write,
.unlocked_ioctl = hello_mod_ioctl,
.release = hello_mod_release,
};

static int hello_mod_open(struct inode *inode, struct file *pfile)
{
printk("+hello_mod_open()!\n");
spin_lock(&spin);
if(open_count)
{
spin_unlock(&spin);
return -EBUSY;
}
open_count++;
spin_unlock(&spin);
printk("-hello_mod_open()!\n");
return 0;
}
static int hello_mod_release(struct inode *inode, struct file *pfile)
{
printk("+hello_mod_release()!\n");
open_count--;
printk("-hello_mod_release()!\n");
return 0;
}
static ssize_t hello_mod_read(struct file *pfile, char *user_buf, size_t len, loff_t *off)
{
printk("+hello_mod_read()!\n");

if(down_interruptible(&sem))
{
return -ERESTARTSYS;
}
memset(outbuffer, 0, OUT_BUF_LEN);
printk("    +switch()\n");
switch(langtype)
{
case english:
printk("        >in case: english\n");
sprintf(outbuffer, "Hello! %s.", inbuffer);
break;
case chinese:
printk("        >in case: chinese\n");
sprintf(outbuffer, "Ni hao %s.", inbuffer);
break;
case pinyin:
printk("        >in case: pinyin\n");
sprintf(outbuffer, "ni hao! %s.", inbuffer);
break;
default:
printk("        >in case: default\n");
break;
}
printk("    -switch()\n");
if(copy_to_user(user_buf, outbuffer, len))
{
up(&sem);
return -EFAULT;
}
up(&sem);
printk("-hello_mod_read()!\n");
return 0;
}
static ssize_t hello_mod_write(struct file *pfile, const char *user_buf, size_t len, loff_t *off)
{
printk("+hello_mod_write()!,user_buf: %s, len: %d\n",user_buf,len);
if(down_interruptible(&sem))
{
return -ERESTARTSYS;
}
if(len > IN_BUF_LEN)
{
printk("Out of input buffer\n");
return -ERESTARTSYS;
}
if(copy_from_user(inbuffer, user_buf, len))
{
up(&sem);
return -EFAULT;
}
up(&sem);
printk("-hello_mod_write()!, inbuffer: %s\n",inbuffer);
return 0;
}
static long hello_mod_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{
int err = 0;
printk("+hello_mod_ioctl()!, cmd: %d\n",cmd);
printk("    +switch()\n");
switch(cmd)
{
case HELLO_IOCTL_RESETLANG:
printk("        >in case: HELLO_IOCTL_RESETLANG\n");
langtype = english;
break;
case HELLO_IOCTL_GETLANG:
printk("        >in case: HELLO_IOCTL_GETLANG\n");
err = copy_to_user((int *)arg, &langtype, sizeof(int));
break;
case HELLO_IOCTL_SETLANG:
printk("        >in case: HELLO_IOCTL_SETLANG\n");
err = copy_from_user(&langtype,(int *)arg, sizeof(int));
break;
default:
printk("        >in case: default\n");
err = ENOTSUPP;
break;
}
printk("    -switch()\n");
printk("-hello_mod_ioctl()!\n");
return err;
}
static int __init hello_mod_init(void)
{
int result;
printk("+hello_mod_init()!\n");
devnum = MKDEV(MAJOR_NUM, MINOR_NUM);
result = register_chrdev_region(devnum, 1, modname);

if(result < 0)
{
printk("hello_mod : can't get major number!\n");
return result;
}

cdev_init(&hello_cdev, &hello_mod_fops);
hello_cdev.owner = THIS_MODULE;
hello_cdev.ops = &hello_mod_fops;
result = cdev_add(&hello_cdev, devnum, 1);
if(result)
printk("Failed at cdev_add()\n");
hello_class = class_create(THIS_MODULE, classname);
if(IS_ERR(hello_class))
{
printk("Failed at class_create().Please exec [mknod] before operate the device\n");
}
else
{
device_create(hello_class, NULL, devnum,NULL, devicename);
}

open_count = 0;
langtype = english;
inbuffer = (char *)kmalloc(IN_BUF_LEN, GFP_KERNEL);
outbuffer = (char *)kmalloc(OUT_BUF_LEN, GFP_KERNEL);
sema_init(&sem, 1);
printk("-hello_mod_init()!\n");
return 0;
}

static void __exit hello_mod_exit(void)
{
printk(KERN_ALERT"+hello_mod_exit!\n");
kfree(inbuffer);
kfree(outbuffer);
cdev_del(&hello_cdev);
device_destroy(hello_class, devnum);
class_destroy(hello_class);
unregister_chrdev_region(devnum, 1);
printk(KERN_ALERT"-hello_mod_exit!\n");

return ;
}

module_init(hello_mod_init);
module_exit(hello_mod_exit);
MODULE_LICENSE("GPL");
hello.h/*
* =====================================================================================
*
* Filename: hello.h
*
* Description: define the cmd supported by hello_mod
*
* Version: 1.0
* Created: 02/22/2018 10:24:20 AM
* Revision: none
* Compiler: gcc
*
* Author: Leon, pengliang2851035@163.com
* Company: None
*
* =====================================================================================
*/

#ifndef __HELLO_H__
#define __HELLO_H__

#define HELLO_MAGIC 12
#define HELLO_IOCTL_RESETLANG _IO(HELLO_MAGIC,0) //set langtype = english
#define HELLO_IOCTL_GETLANG _IOR(HELLO_MAGIC,1,int) //get langtype
#define HELLO_IOCTL_SETLANG _IOW(HELLO_MAGIC,2,int) //set langtype

typedef enum _lang_t
{
english, chinese, pinyin
}lang_t;

#endif Makefile#Makefile 2.6

obj-m :=hello.o
KERNEL :=/home/workplace/sc2410_android/kernel
PWD :=$(shell pwd)
$(warinning $(MAKE))
modules :
$(MAKE) -C $(KERNEL) M=$(PWD) modules

.PHONEY:clean
clean :
rm -f *.o *.ko2.1.2 编译
cd /home/workplace/sc2410_android/kernel/drivers/leon_test
root@leon:    /home/workplace/sc2410_android/kernel/drivers/leon_test# ls
Makefile  hello.c  hello.h
root@leon:    /home/workplace/sc2410_android/kernel/drivers/leon_test# make
make -C /home/workplace/sc2410_android/kernel M=/home/workplace/sc2410_android/kernel/drivers/leon_test   modules  
make[1]: 正在进入目录 `/home/workplace/sc2410_android/kernel'
  CC [M]  /home/workplace/sc2410_android/kernel/drivers/leon_test/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/workplace/sc2410_android/kernel/drivers/leon_test/hello.mod.o
  LD [M]  /home/workplace/sc2410_android/kernel/drivers/leon_test/hello.ko
make[1]:正在离开目录 `/home/workplace/sc2410_android/kernel'

root@leon:    /home/workplace/sc2410_android/kernel/drivers/leon_test# ls
Makefile  modules.order  Module.symvers  hello.c  hello.h  hello.ko  hello.mod.c  hello.mod.o  hello.o

hello.ko即为我们所需要的驱动安装文件
安装步骤如下:
root@leon:    /home/workplace/sc2410_android/kernel/drivers/leon_test# adb push test1.ko /sdcard/
[100%] /sdcard/test1.ko
root@leon:    /home/workplace/rk3229_android/kernel/drivers/test1# adb shell
shell@sc2410_box:/ $ cd sdcard/
shell@sc2410_box:/sdcard $ su
shell@sc2410_box:/sdcard # lsmod                                               
vcodec_service 33766 0 - Live 0x00000000
shell@sc2410_box:/mnt/internal_sd # insmod hello.ko
shell@sc2410_box:/sdcard # lsmod                                               
test1 3685 0 - Live 0x00000000 (O)
vcodec_service 33766 0 - Live 0x00000000
上述黑体部分即表示安装成功

2.2.1应用层代码实现
创建目录/home/workplace/sc2410_android/leon_test
将下述hello.c hello.h Android.mk放于上述目录Android.mkLOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
hello.c \

LOCAL_MODULE:= hello

#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_EXECUTABLE)hello.c/*************************************************************************
> File Name: hello.c
> Author: leon
> Mail: pengliang2851035@163.com
> Created Time: 02/22/2018 10:24:20 AM
************************************************************************/

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/ioctl.h>
#include <string.h>
#include <errno.h>
#include "hello.h"

int main()
{
char outbuf[512];
char * myname = "leon";
lang_t langtype = english;
int fd = open("/dev/hello", O_RDWR, S_IRUSR|S_IWUSR);
if(fd != -1)
{
write(fd, myname, strlen(myname)+1);
langtype = chinese;
ioctl(fd, HELLO_IOCTL_SETLANG, &langtype);
read(fd, outbuf, 512);
printf("langtype=chinese:%s\n", outbuf);
memset(outbuf, 0, 512);
langtype = pinyin;
ioctl(fd, HELLO_IOCTL_SETLANG, &langtype);
read(fd, outbuf, 512);
printf("langtype=pinyin:%s\n", outbuf);
memset(outbuf, 0, 512);
ioctl(fd, HELLO_IOCTL_RESETLANG, &langtype);
read(fd, outbuf, 512);
printf("langtype=english:%s\n", outbuf);
}
else
{
perror("Failed at open():");
}
close(fd);
return 0;
}
hello.h/*
* =====================================================================================
*
* Filename: hello.h
*
* Description: define the cmd supported by hello_mod
*
* Version: 1.0
* Created: 02/22/2018 10:24:20 AM
* Revision: none
* Compiler: gcc
*
* Author: Leon, pengliang2851035@163.com
* Company: None
*
* =====================================================================================
*/

#ifndef __HELLO_H__
#define __HELLO_H__

#define HELLO_MAGIC 12
#define HELLO_IOCTL_RESETLANG _IO(HELLO_MAGIC,0) //set langtype = english
#define HELLO_IOCTL_GETLANG _IOR(HELLO_MAGIC,1,int) //get langtype
#define HELLO_IOCTL_SETLANG _IOW(HELLO_MAGIC,2,int) //set langtype

typedef enum _lang_t
{
english, chinese, pinyin
}lang_t;

#endif 2.2.2 编译运行
root@leon:    /home/workplace/sc2410_android/leon_test# mm
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1.1
TARGET_PRODUCT=sc2410_box
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=cortex-a7
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-100-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_BUILD_TYPE=release
BUILD_ID=OTCoA1_000_010
OUT_DIR=out
============================================
PRODUCT_COPY_FILES device/sc2410/common/ueventd.sc2410.rc:root/ueventd.rk30board.rc ignored.
PRODUCT_COPY_FILES device/sc2410/common/fstab.sc2410board.bootmode.unknown:root/fstab.sc2410board.bootmode.unknown ignored.
PRODUCT_COPY_FILES device/sc2410/common/fstab.sc2410board.bootmode.emmc:root/fstab.sc2410board.bootmode.emmc ignored.
PRODUCT_COPY_FILES device/sc2410/common/performance_info.xml:system/etc/performance_info.xml ignored.
make:进入目录'/home/workplace/sc2410_android'
target thumb C: hello <= leon_test/hello.c
target Executable: hello (out/target/product/sc2410_box/obj/EXECUTABLES/hello_intermediates/LINKED/hello)
target Symbolic: hello (out/target/product/sc2410_box/symbols/system/bin/hello)
target Strip: hello (out/target/product/sc2410_box/obj/EXECUTABLES/hello_intermediates/hello)
Install: out/target/product/sc2410_box/system/bin/hello
make:离开目录“/home/workplace/sc2410_android”

#### make completed successfully (2 seconds) ####

root@leon:    /home/workplace/sc2410_android/leon_test/# adb push ../out/target/product/rk322x_box/system/bin/hello /sdcard/
root@leon:    /home/workplace/sc2410_android/leon_test/# adb shell
shell@sc2410_box:# cp /sdcard/hello /system/bin
shell@sc2410_box:/system/bin # ./test1                                         
langtype=chinese:Ni hao tishion.
langtype=pinyin:ni hao! tishion.
langtype=english:Hello! tishion.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: