1. 程式人生 > >linux驅動支援多個裝置

linux驅動支援多個裝置

1.註冊裝置

insmod driverName.ko

//主要是呼叫xxx_init()函式向chrdev中註冊裝置號(代表一類裝置),和將要使用的裝置數量

// xxx_init()中利用函式結構體,file_operations初始化cdev,然後把cdev和註冊的裝置號關聯。

// 利用 cat /proc/devices 可以看到主裝置號,和裝置號。

2.建立裝置檔案

mknod /dev/xxxdevice c 260 1
mknod /dev/xxxdevice c 260 2
//主要是建立多個裝置檔案,制定檔名稱,裝置型別,主裝置好,次裝置號

3.TODO:

// 區分裝置

4. code 例項(一)

static mem_major = MEMDEV_MAJOR;

module_param(mem_major, int, S_IRUGO);

struct mem_dev *mem_devp; /*裝置結構體指標*/

struct cdev cdev; 

/*檔案開啟函式*/
int mem_open(struct inode *inode, struct file *filp)
{
    struct mem_dev *dev;
    
    /*獲取次裝置號*/
    int num = MINOR(inode->i_rdev);

    if (num >= MEMDEV_NR_DEVS) 
            return -ENODEV;
    dev = &mem_devp[num];
    
    /*將裝置描述結構指標賦值給檔案私有資料指標*/
    filp->private_data = dev;
    
    return 0; 
}

/*檔案釋放函式*/
int mem_release(struct inode *inode, struct file *filp)
{
  return 0;
}

/*讀函式*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;        /*記錄檔案指標偏移位置*/  
  unsigned int count = size;    /*記錄需要讀取的位元組數*/ 
  int ret = 0;    /*返回值*/  
  struct mem_dev *dev = filp->private_data; /*獲得裝置結構體指標*/

  /*判斷讀位置是否有效*/
  if (p >= MEMDEV_SIZE)    /*要讀取的偏移大於裝置的記憶體空間*/  
    return 0;
  if (count > MEMDEV_SIZE - p)     /*要讀取的位元組大於裝置的記憶體空間*/ 
    count = MEMDEV_SIZE - p;

  /*讀資料到使用者空間:核心空間->使用者空間交換資料*/  
  if (copy_to_user(buf, (void*)(dev->data + p), count))
  {
    ret =  - EFAULT;
  }
  else
  {
    *ppos += count;
    ret = count;
    
    printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  }

  return ret;
}

/*寫函式*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct mem_dev *dev = filp->private_data; /*獲得裝置結構體指標*/
  
  /*分析和獲取有效的寫長度*/
  if (p >= MEMDEV_SIZE)
    return 0;
  if (count > MEMDEV_SIZE - p)    /*要寫入的位元組大於裝置的記憶體空間*/
    count = MEMDEV_SIZE - p;
    
  /*從使用者空間寫入資料*/
  if (copy_from_user(dev->data + p, buf, count))
    ret =  - EFAULT;
  else
  {
    *ppos += count;      /*增加偏移位置*/  
    ret = count;      /*返回實際的寫入位元組數*/ 
    
    printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  }

  return ret;
}

/* seek檔案定位函式 */
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
{ 
    loff_t newpos;      

    switch(whence) {
      case 0: /* SEEK_SET */       /*相對檔案開始位置偏移*/ 
        newpos = offset;           /*更新檔案指標位置*/
        break;

      case 1: /* SEEK_CUR */
        newpos = filp->f_pos + offset;    
        break;

      case 2: /* SEEK_END */
        newpos = MEMDEV_SIZE -1 + offset;
        break;

      default: /* can't happen */
        return -EINVAL;
    }
    if ((newpos<0) || (newpos>MEMDEV_SIZE))
        return -EINVAL;
        
    filp->f_pos = newpos;
    return newpos;

}

/*檔案操作結構體*/
static const struct file_operations mem_fops =
{
  .owner = THIS_MODULE,
  .llseek = mem_llseek,
  .read = mem_read,
  .write = mem_write,
  .open = mem_open,
  .release = mem_release,
};

/*裝置驅動模組載入函式*/
static int memdev_init(void)
{
  int result;
  int i;

  dev_t devno = MKDEV(mem_major, 0);

   /* 申請裝置號,當xxx_major不為0時,表示靜態指定;當為0時,表示動態申請*/ 
  /* 靜態申請裝置號*/
  if (mem_major)
    result = register_chrdev_region(devno, 2, "memdev");
  else  /* 動態分配裝置號 */
  {
    result = alloc_chrdev_region(&devno, 0, 2, "memdev");
    mem_major = MAJOR(devno);    /*獲得申請的主裝置號*/
  }  
  
  if (result < 0)
    return result;

 /*初始化cdev結構,並傳遞file_operations結構指標*/ 
  cdev_init(&cdev, &mem_fops);    
  cdev.owner = THIS_MODULE;    /*指定所屬模組*/
  cdev.ops = &mem_fops;
  
  /* 註冊字元裝置 */
  cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
   
  /* 為裝置描述結構分配記憶體,此處是重點(1)*/
  mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
  if (!mem_devp)    /*申請失敗*/
  {
    result =  - ENOMEM;
    goto fail_malloc;
  }
  memset(mem_devp, 0, sizeof(struct mem_dev));
  
  /*為裝置分配記憶體*/
  for (i=0; i < MEMDEV_NR_DEVS; i++) 
  {
        mem_devp[i].size = MEMDEV_SIZE;
        mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
        memset(mem_devp[i].data, 0, MEMDEV_SIZE);
  }
    
  return 0;

  fail_malloc: 
  unregister_chrdev_region(devno, 1);
  
  return result;
}

/*模組解除安裝函式*/
static void memdev_exit(void)
{
  cdev_del(&cdev);   /*登出裝置*/
  kfree(mem_devp);     /*釋放裝置結構體記憶體*/
  unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*釋放裝置號*/
}

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("GPL");

module_init(memdev_init);
module_exit(memdev_exit);


#include <stdio.h>

int main()
{
    FILE *fp0 = NULL;
    char Buf[4096];
    
    /*初始化Buf*/
    strcpy(Buf,"Mem is char dev!");
    printf("BUF: %s\n",Buf);
    
    /*開啟裝置檔案*/
    fp0 = fopen("/dev/memdev0","r+");
    if (fp0 == NULL)
    {
        printf("Open Memdev0 Error!\n");
        return -1;
    }
    
    /*寫入裝置*/
    fwrite(Buf, sizeof(Buf), 1, fp0);
    
    /*重新定位檔案位置(思考沒有該指令,會有何後果)*/
    fseek(fp0,0,SEEK_SET);
    
    /*清除Buf*/
    strcpy(Buf,"Buf is NULL!");
    printf("BUF: %s\n",Buf);
    
    
    /*讀出裝置*/
    fread(Buf, sizeof(Buf), 1, fp0);
    
    /*檢測結果*/
    printf("BUF: %s\n",Buf);
    
    return 0;    

}


相關推薦

linux驅動支援裝置

1.註冊裝置 insmod driverName.ko //主要是呼叫xxx_init()函式向chrdev中註冊裝置號(代表一類裝置),和將要使用的裝置數量 // xxx_init()中利用函式結構體,file_operations初始化cdev,然後把cdev和註冊的

linux 驅動建立裝置

linux 驅動中建立一個裝置的例子很多,以下例子是建立多個字元裝置的例子,包括驅動部分和測試部分 驅動部分包括 globalmem.c  Makefile兩個檔案: globalmem.c file: #include <linux/module.h>

一個驅動支援裝置再usb子系統、input子系統、platform、iic子系統 中的實現

platform 你寫的驅動你應該知道它適用與哪些裝置吧,如果你想支援一個裝置,那麼你就構造一個 usb_device_id (USB)、i2c_device_id (IIC)、platform_device_id(Platform)放到對應驅動的id_

ZYNQ Linux驅動開發——第一字元裝置驅動

硬體平臺:XCZ7020 CLG484-1 完全適配Zedboard 開發環境:Widows下Vivado 2016.2 、 SDK2016.2 、 Linux機器:debin 目的:操作板載的LED燈LD9,受PS部分的MIO7控制 linux裝置驅

一個驅動程式對應裝置

#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #in

程式碼:編寫一個簡單的字元裝置驅動——建立同類型裝置

編寫同類型多個裝置字元驅動應注意一下幾個問題: 1、申請裝置號alloc_chrdev_region時須指定次裝置號範圍; 2、動態分配裝置空間時同時分配NUM個裝置的空間; 3、根據次裝置號和統一的主裝置號生成針對單個裝置的devno,然後完成cdev_add註冊; 4、

linux——alsa中音效卡裝置時開啟某一指定音效卡的PCM裝置

前言   最近除錯板子上的3個ADAU1761音訊介面,使用pocketsphinx語音庫呼叫alsa庫的API介面開啟指定的Mic進行錄入語音時出現異常,預設情況只能開啟第一個ADAU1761音訊介面,想開啟第二個或第三個ADAU1761音訊介面時卻出現錯誤

Windows驅動開發WDM (11)- 裝置物件(同一個驅動

通常在WDM驅動的AddDevice裡面只會呼叫一次IoCreateDevice建立一個裝置物件。其實我們也可以呼叫多次IoCreateDevice來建立多個裝置物件。當驅動呼叫IoCreateDevice成功後,驅動物件DriverObject的DeviceObject指

linux驅動開發之一真正的裝置驅動需要一些什麼元素(裝置號,操作方法)

1,需要一個裝置號(重點看下面的程式碼) 因為核心中有很多的裝置驅動,所以需要一個裝置號id來進行區分 裝置號分成兩個部分: 主裝置號:某一

Linux下nginx+Tomcat負載均衡的實現

java 負載 均衡 bootstra 火墻 瀏覽器 startup 顯示 tomcat的配置 由於項目需要,共創建了10個Tomcat端,由nginx負責轉發。9個Tomcat端口分別是8080,11000,12000,13000,14000,15000,16000,17

Linux下SVN+Tomcat自動部署

mod .html 部署 update語句 hooks 參考 eba bsp auth 項目中都是jsp開發,所以用到Tomcat。 在我文章中也寫過多個Tomcat 的部署,具體可以參考:http://www.cnblogs.com/magmell/p/7045193.h

如何將Linux系統的目錄及文件備份並壓縮到一個文件,以方面保持和傳遞?

如何將linux系統的多個目錄及文件備份並壓縮到一個文件 以方面保持和傳遞? 1.備份Linux系統  window系統在運行狀態下,我們是無法將文件拷貝出來的,那麽在Linux下呢?她的文件結構式一種樹型結構。而且在系統運行的時候我們可以進行打包所有系統文件。特別要說的在Linux的root賬戶具備

linux nginx配置網站

vhost host 編輯 dir OS nginx 文件夾 CA nginx配置 1.把網站配置在hom目錄下,需要建立wwwroot目錄 1.在nginx.conf 增加inlcude代碼,然後創建一個vhost,最後配置個xxx.com.conf //編輯n

Linux 下 svn 項目多用戶分配

usr osi 匿名 win 註意 () 禁止訪問 缺省值 管理 安裝步驟如下: 1、yum install subversion 2、輸入rpm -ql subversion查看安裝位置,如下圖: 輸入 svn –help可以查看svn的使用方法 需求 開發

Linux上配置tomcat的配置修改(修改tomcat配置)

1、修改環境變數      #vi  /etc/profile ####### 工程1 tomcat1####### export CATALINA_BASE=/data/server/tomcat export CATALINA_HOME=$CA

Spring環境下MyBatis支援Datasource參考實現

需求背景 最近接到一個專案,需要改造一個老的系統。該老系統以Oracle為儲存,巨量的PL/SQL程式碼實現業務程式碼,C實現Socket Server,作為Client和PL/SQL的橋樑。不出所料,該老系統最大的問題是PL/SQL程式碼量巨大(上萬的Procedure好幾個),且毫無

Appium自動化測試-同時執行裝置

在之前的文章中,學習了Appium的基本使用,可以參考Appium自動化測試-入門,我們接著學習一下在一臺電腦中同時執行多裝置的方法,這樣在測試多種裝置的時候,可以直接在本地完成。 一、啟動Appium 一個Appium伺服器只能連線一個測試裝置進行測試,如果要在一臺電腦上同時測

Ubuntu16.04配置Apache支援站點

怎樣在一個Ubuntu的機器上(虛擬機器)配置Apache支援多個網站呢? 比如你有一臺獨立的Ubuntu虛擬機器,配有一個外網的IP(45.46.47.48),並且註冊了兩個域名AAA.com和BBB.com,將這兩個域名DNS解析到你虛機的IP地址。假設你已經安裝好了Apache,一

Linux下部署Tomcat端

由於專案需要,共建立了10個Tomcat端,由nginx負責轉發。10個Tomcat埠分別是8080,11000,12000,13000,14000,15000,16000,17000,18000,19000. nginx配置:upstream Tomcat { server xxx.

iReport列印(支援模版交叉列印)

//根據實際情況從資料庫中獲取資料 List<User> userList = new ArrayList<>(); User printBean = null; JasperPrint jasperPrint = n