platform是一条虚拟的总线。设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device driver机制(通过driver_register进行注册)相比,一个明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动中使用这些资源时通过platform device提供的标准结构进行申请并使用。这样提高了驱动和资源的独立性,并且具有较好的可移植性和安全性(这些标准接口是安全的)。

pltform机制本身使用并不复杂,由两部分组成:platform_device和platform_driver。通过platform机制开发底层驱动的大致流程为:定义platform_deive->注册platform_device->定义platform_driver->注册platform_driver。

platform driver的probe函数是平台总线实现匹配以后首先被调用的函数,因此在其中实现字符设备、块设备、网络设备驱动的初始化是有意义的,这样的设备驱动就是基于平台总线的设备驱动,便于维护。如果添加实际的设备到该平台总线设备驱动模型中,则可以在该函数中实现具体的设备驱动函数的初始化操作,包括设备号的申请,设备的初始化,添加。自动设备文件创建函数的添加等操作。或者是混杂字符设备的相关初始化操作。在remove函数中实现具体的设备的释放,包括设备的删除,设备号的注销等操作。

基于misc device实现一个简单的platform driver(仿照driver/char/sonypi.c).

fellowplat.h

#ifndef _FELLOW_MISC_H_
#define _FELLOW_MISC_H_
#include <linux/ioctl.h>
//#define FELLOW_MISC_MAJOR 199
//#define FELLOW_MISC_NR 2
struct miscdata {
int val;
char *str;
unsigned int size;
};
#define FELLOW_MISC_IOC_MAGIC 'f'
#define FELLOW_MISC_IOC_PRINT _IO(FELLOW_MISC_IOC_MAGIC, 1)
#define FELLOW_MISC_IOC_GET _IOR(FELLOW_MISC_IOC_MAGIC, 2, struct miscdata)
#define FELLOW_MISC_IOC_SET _IOW(FELLOW_MISC_IOC_MAGIC, 3, struct miscdata)
#define FELLOW_MISC_IOC_MAXNR 3
#endif

fellowplat.c

#include <linux/module.h>
#include <linux/init.h>
//#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "fellowplat.h"
struct fellowmisc_dev{
struct miscdevice misc;
struct miscdata data;
};
struct fellowmisc_dev *fellowmisc_devp;
int fellowmisc_open(struct inode *inode, struct file *filep)
{
  filep->private_data = fellowmisc_devp;
  return 0;
}
int fellowmisc_release(struct inode *inode, struct file *filep)
{
  return 0;
}

long fellowmisc_ioctl(struct file *filep,unsigned int cmd,unsigned long arg)

{

  int ret = 0;
  struct fellowmisc_dev *devp = (struct fellowmisc_dev *)(filep->private_data);
  if (_IOC_TYPE(cmd) != FELLOW_MISC_IOC_MAGIC)
    return -EINVAL;
  if (_IOC_NR(cmd) > FELLOW_MISC_IOC_MAXNR)
    return -EINVAL;
  switch(cmd)
  {
    case FELLOW_MISC_IOC_PRINT:
      printk("FELLOW_MISC_IOC_PRINT\n");
      printk("val:%d, size: %d, str: %s\n", devp->data.val, devp->data.size, devp->data.str);
    break;
    case FELLOW_MISC_IOC_SET:
      printk("FELLOW_MISC_IOC_SET\n");
      ret = copy_from_user((unsigned char*)&(devp->data), (unsigned char *)arg, sizeof(struct miscdata));
      printk("set val:%d, size: %d, str: %s\n", devp->data.val, devp->data.size, devp->data.str);
    break;
    case FELLOW_MISC_IOC_GET:
      printk("FELLOW_MISC_IOC_GET\n");
      ret = copy_to_user((unsigned char*)arg,(unsigned char*)&(devp->data), sizeof(struct miscdata));
    break;
    default:
      return -EINVAL;

  }
  return ret;
}
static const struct file_operations fellowmisc_fops ={
.owner = THIS_MODULE,
.open = fellowmisc_open,
.release = fellowmisc_release,
.unlocked_ioctl = fellowmisc_ioctl,
};
static struct miscdevice fellow_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "fellowplat",
.fops = &fellowmisc_fops,
};
static struct platform_device *fellow_platform_device;
static int fellow_plat_drv_probe(struct platform_device *dev)
{
  int error;
  printk("fellow_plat_drv_probe\n");
  fellowmisc_devp = kmalloc(sizeof(struct fellowmisc_dev), GFP_KERNEL);
  if (!fellowmisc_devp)
  {
    error = -ENOMEM;
    return error;
  }
  memset(&(fellowmisc_devp->data), 0, sizeof(fellowmisc_devp->data));
  fellowmisc_devp->misc = fellow_misc;
  error = misc_register(&fellow_misc);
  return error;
}
static int fellow_plat_drv_remove(struct platform_device *dev)
{
  int error;
  if (fellowmisc_devp)
    kfree(fellowmisc_devp);
  error = misc_deregister(&fellow_misc);
  return error;
}
static struct platform_driver fellow_platform_driver = {
.driver = {
.name = "fellow",
},
.probe = fellow_plat_drv_probe,
.remove = fellow_plat_drv_remove,
};

static int fellowplat_init(void)
{
  int error;
  printk("fellowplat_init\n");
  printk("fellow register driver\n");
  error = platform_driver_register(&fellow_platform_driver);//注册platform driver
  if (error)
    return error;

  fellow_platform_device = platform_device_alloc("fellow", -1);//名字与platform driver相同。
  if (!fellow_platform_device) {
    error = -ENOMEM;
    goto err_driver_unregister;
  }

  printk("fellow register device\n");
  error = platform_device_add(fellow_platform_device);//添加platform device
  if (error)
    goto err_free_device;

  return 0;

err_free_device:
  platform_device_put(fellow_platform_device);
err_driver_unregister:
  platform_driver_unregister(&fellow_platform_driver);
  return error;
}

static void fellowplat_exit(void)
{
  platform_device_unregister(fellow_platform_device);
  platform_driver_unregister(&fellow_platform_driver);
}

MODULE_AUTHOR("fellow");
MODULE_LICENSE("GPL");
module_init(fellowplat_init);
module_exit(fellowplat_exit);

app.c

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "fellowplat.h"
int main(void)
{
  int fd = open("/dev/fellowplat", O_RDWR);
  if (fd < 0)
  {
    printf("open fail:%s\n", strerror(errno));
    return -1;
  }
  int ret = 0;
  struct miscdata data;
  data.val = 18;
  data.str = "fellow platform device";
  data.size = sizeof("fellow platform device");
  if ((ret = ioctl(fd, FELLOW_MISC_IOC_SET, &data)) < 0)
  {
    printf("ioctl set fail:%s\n", strerror(errno));
  }
  struct miscdata getdata;
  if ((ret = ioctl(fd, FELLOW_MISC_IOC_GET, &getdata)) < 0)
  {
    printf("ioctl get fail:%s\n", strerror(errno));
  }
  printf("get val:%d, str:%s, size: %d\n", getdata.val, getdata.str, getdata.size);
  if ((ret = ioctl(fd, FELLOW_MISC_IOC_PRINT, NULL)) < 0)
  {
    printf("ioctl print fail:%s\n", strerror(errno));
  }
  close(fd);
  return ret;
}

运行结果如下

设备驱动基础学习--platform driver简单实现的更多相关文章

  1. 设备驱动基础学习--misc device简单实现

    在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述).miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同. 所有的miscde ...

  2. 设备驱动基础学习--poll

    使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行,所以我们的问题就集中到了如何编 ...

  3. 设备驱动基础学习--/proc下增加节点

    在需要创建一个由一系列数据顺序组合而成的/proc虚拟文件或一个较大的/proc虚拟文件时,推荐使用seq_file接口. 数据结构struct seq_fille定义在include/linux/s ...

  4. Hasen的linux设备驱动开发学习之旅--时钟

    /** * Author:hasen * 參考 :<linux设备驱动开发具体解释> * 简单介绍:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date ...

  5. Linux设备驱动模型之platform(平台)总线详解

    /********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...

  6. Introduction the naive“scull” 《linux设备驱动》 学习笔记

    Introduction the naive "scull" 首先.什么是scull? scull (Simple Character Utility for Loading Lo ...

  7. 【驱动】Flash设备驱动基础·NOR·NAND

    Flash存储器 ——>Flash存储器是近几年来发展最快的存储设备,通常也称作闪存.Flash属于EEPROM(电可擦除可编程只读存储器),是一类存取速度很高的存储器. ——>它既有RO ...

  8. 探究linux设备驱动模型之——platform虚拟总线(一)

    说在前面的话 :      设备驱动模型系列的文章主要依据的内核版本是2.6.32的,因为我装的Linux系统差不多就是这个版本的(实际上我用的fedora 14的内核版本是2.6.35.13的.) ...

  9. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

随机推荐

  1. Python标准库之sys模块

    获取Python解释器的版本信息 import sys print(sys.version) #输出 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) ...

  2. 从零DIY机械键盘/主控方案

    自从有了第一套机械键盘,先后修改了接口方案,安装了LED灯等,但是始终无法满足自己的DIY欲望. 于是想到最简单的方法就是用现成的主控,而主控来源于废弃的键盘,如下图: 这种主控也是矩阵方式,只需要测 ...

  3. JavaScript DOM–节点操作

    节点 节点至少拥有nodeType(节点类型).nodeName(节点名称)和nodeValue(节点值)这三个基本属性. 元素节点 nodeType  为1 属性节点 nodeType  为2 文本 ...

  4. python3函数的参数

    函数的定义能简化代码的逻辑,对于函数的调用者来说,只需要知道如何正确的传递参数,以及知道函数将返回什么值就可以了,而函数内部的复杂逻辑被封装起来,调用者不必了解. 位置参数 调用函数时,传入实参的值按 ...

  5. hashlib加密模块_python

    一.hashlib模块 1.功能 主要用于字符串加密 2.常用方法 md5()/sha1():创建一个md5或者sha1加密模式的hash对象update(arg):用字符串参数来更新hash对象,如 ...

  6. JAVA 注解教程(三)注解的属性

    简介 注解的属性也叫做成员变量,注解只有成员变量,没有方法.注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型 实例 @Targe ...

  7. java 集合与数组的互转方法,与源码分析

    前言 java数组与集合需要互相转换的场景非常多,但是运用不好还是容易抛出UnSupportedOperationException.下面讲解一下互转的方法,以及结合源码分异常产生的原因 集合转数组 ...

  8. ASP.NET + MVC5 入门完整教程七 -—-- MVC基本工具(下)

    https://blog.csdn.net/qq_21419015/article/details/80493633 Visual Stdio 的单元测试

  9. L2-1 分而治之

    思路 这题的意思是,如果把这些点打掉,其他的点是否能够完全不连通. 用并查集,或者打上标记之后,判断每个点是否还能到达其他点,如果一个点可以到达其他任何点,都应该输出否. 代码 #include &l ...

  10. bzoj3626: [LNOI2014]LCA (树链剖分)

    很神奇的方法 感觉是有生之年都想不到正解的这种 考虑对i 到根的节点权值 + 1,则从根到z的路径和就是lca(i,z)的深度 所以依次把0 ~ n - 1的点权值 + 1 对于询问[l, r] 这个 ...