• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      ARM-Linux-IIC設(shè)備的添加與驅(qū)動(dòng)實(shí)現(xiàn)

      2012-02-15 03:29:46怯肇乾吳志亮
      電子設(shè)計(jì)工程 2012年10期
      關(guān)鍵詞:適配器內(nèi)核字節(jié)

      怯肇乾,吳志亮

      (鄭州精益達(dá)汽車(chē)零部件有限公司,河南 鄭州 100044)

      廣泛應(yīng)用的ARM-Linux及其Android的嵌入式軟硬件系統(tǒng)中,常常涉及到內(nèi)部整合電路IIC (Inter-Integrated Circuit)總線的操作及其設(shè)備的添加與驅(qū)動(dòng)的實(shí)現(xiàn)?;贏RM內(nèi)核的各類(lèi)微處理器芯片中,通常都會(huì)集成一到幾個(gè)IIC總線控制器,用以連接存儲(chǔ)器、傳感器、人機(jī)界面等IIC設(shè)備。沒(méi)有操作系統(tǒng)的常規(guī)應(yīng)用中,根據(jù)IIC控制器和所選IIC設(shè)備的特點(diǎn),按照IIC通信協(xié)議,通過(guò)直接明了的編程設(shè)計(jì),很容易在系統(tǒng)中實(shí)現(xiàn)IIC設(shè)備的添加與驅(qū)動(dòng)。而ARM-Linux嵌入式操作系統(tǒng),對(duì)IIC采用分層分散的總線架構(gòu),雖然做到了穩(wěn)定、高效、模塊化,卻使向其中添加需要的IIC設(shè)備及其驅(qū)動(dòng)實(shí)現(xiàn)困難了很多,常規(guī)的驅(qū)動(dòng)設(shè)計(jì)方法不能用了。ARMLinux下,IIC總線的體系框架是怎樣的?如何因地制宜向其中添加IIC設(shè)備并順利實(shí)現(xiàn)其驅(qū)動(dòng)程序設(shè)計(jì)呢?本文以下將展開(kāi)詳細(xì)闡述。

      1 IIC總線設(shè)備驅(qū)動(dòng)及其實(shí)現(xiàn)分析

      ARM-Linux下,IIC分為3個(gè)層次:IIC內(nèi)核、IIC總線驅(qū)動(dòng)和IIC設(shè)備驅(qū)動(dòng)。IIC內(nèi)核提供核心數(shù)據(jù)結(jié)構(gòu)的定義和相關(guān)接口函數(shù),實(shí)現(xiàn)驅(qū)動(dòng)的注冊(cè)、注銷(xiāo)管理,設(shè)備的探測(cè)、檢查,以及無(wú)關(guān)具體適配器的讀寫(xiě)通信代碼。IIC總線驅(qū)動(dòng)定義具體的適配器結(jié)構(gòu)i2c_adapter及其算法結(jié)構(gòu)i2c_algorithm,控制適配器以主控方式產(chǎn)生IIC通信時(shí)序。IIC內(nèi)核和IIC總線驅(qū)動(dòng)共同完成硬件上的主機(jī)總線控制器驅(qū)動(dòng)。IIC設(shè)備驅(qū)動(dòng)定義描述具體設(shè)備的i2c_client,以具體的i2c_driver實(shí)現(xiàn)從機(jī)設(shè)備驅(qū)動(dòng),包括read、write以及ioctl等用戶層接口。ARMLinux-IIC總線驅(qū)動(dòng)的框架結(jié)構(gòu)及其所在的軟/硬件體系如圖1所示。

      圖1 ARM-Linux-IIC總線驅(qū)動(dòng)的框架結(jié)構(gòu)圖Fig.1 A framework drawing of ARM-Linux-IICbus driving

      從圖1可以看出,在ARM-Linux中添加IIC設(shè)備,首先是編寫(xiě)針對(duì)該設(shè)備的具體i2c_driver驅(qū)動(dòng)程序。然后是構(gòu)造描述該IIC設(shè)備的i2c_client,并向系統(tǒng)注冊(cè)。構(gòu)造的i2c_client是“橋梁”,完成指定i2c_adapter主機(jī)適配控制器與特定i2c_driver設(shè)備驅(qū)動(dòng)的有機(jī)聯(lián)結(jié),從而實(shí)現(xiàn)需要的IIC主從串行通信。

      一般地,ARM-Linux操作系統(tǒng)提供有實(shí)現(xiàn)了IIC內(nèi)核框架的i2c/i2c-core.c文件及其包括GPIO模擬IIC在內(nèi)的常用IIC各類(lèi)通信算法(在目錄i2c/algos/下),還有適用于大多數(shù)IIC從設(shè)備的i2c/i2c-dev.c文件。針對(duì)具體的ARM內(nèi)核微處理器體系, 如 Samsung-CortexA8 的 S5PV110/S5PV210、TICortexA8 的 AM3515/AM3715、Freescale -CortexA8 的 i.MX515/i.MX535等,半導(dǎo)體廠家通常都為自己具體的IIC總線控制器提供有適配器驅(qū)動(dòng) (在目錄i2c/algos/下,如i2cs3c2410.c)。

      綜上所述,在ARM-Linux中增加IIC新設(shè)備,可以借用IIC通用驅(qū)動(dòng)i2c-dev.c快速實(shí)現(xiàn),可以為其編寫(xiě)特定的IIC驅(qū)動(dòng)。ARM-Linux設(shè)備驅(qū)動(dòng)通常采用靜態(tài)加載操作,它有兩種方式:適配 (adapter)和探測(cè) (probe),適配是傳統(tǒng)方式(Legacy),探測(cè)是新類(lèi)型(New Style),大多數(shù)設(shè)備驅(qū)動(dòng)越來(lái)越趨向采用probe方式。也可以采用驅(qū)動(dòng)設(shè)計(jì)人員習(xí)慣的動(dòng)態(tài)加載方式編寫(xiě)簡(jiǎn)易的IIC“客服-驅(qū)動(dòng)”。IIC總線,可以采用系統(tǒng)硬件實(shí)現(xiàn)的IIC總線控制器,也可以選用通用輸入-輸出端口GPIO模擬產(chǎn)生。如果理解不了ARM-Linux的IIC總線層次框架,也可以拋掉這種機(jī)制采用傳統(tǒng)方式編寫(xiě)IIC字符型設(shè)備驅(qū)動(dòng)程序。下面就上述幾種方法,分別說(shuō)明ARM-Linux-IIC設(shè)備的具體添加與驅(qū)動(dòng)實(shí)現(xiàn)過(guò)程。

      需要注意的是,ARM-Linux中,由于IIC總線及其控制器使用的普遍,默認(rèn)系統(tǒng)是加載IIC總線適配器的。如果選用的平臺(tái)沒(méi)有采用己有的IIC總線及其控制器,使用ARMLinux-IIC總線驅(qū)動(dòng)框架,首先要在編譯形成系統(tǒng)映像文件前,通過(guò)menuconfig配置選擇IIC及其相應(yīng)的適配器驅(qū)動(dòng),還有通用或特定的IIC設(shè)備驅(qū)動(dòng)。

      2 借用通用i2c-dev.c驅(qū)動(dòng)新設(shè)備

      采用i2c-dev.c直接驅(qū)動(dòng)新添加的IIC設(shè)備是最簡(jiǎn)便的方法,它實(shí)際上是通過(guò)在應(yīng)用層操作IIC適配器來(lái)控制i2c設(shè)備的。i2c-dev.c是通用的IIC設(shè)備驅(qū)動(dòng),它提供有通用的read()、write()和 ioctl()等設(shè)備文件操作接口,應(yīng)用層可以借用這些接口訪問(wèn)掛接在適配器上的IIC設(shè)備的存儲(chǔ)空間或寄存器,并控制IIC設(shè)備的工作方式。需要注意的是,i2c-dev.c對(duì)應(yīng)的read()和write()是分別調(diào)用IIC內(nèi)核心的i2c_master_recv()和 i2c_master_send()函數(shù),通過(guò)構(gòu)造一條 IIC 消息并引發(fā)適配器algorithm通信函數(shù)的調(diào)用來(lái)完成消息傳輸?shù)?,而大多?shù)稍微復(fù)雜一點(diǎn)IIC設(shè)備的讀寫(xiě)流程并不對(duì)應(yīng)于一條消息,往往需要兩條甚至更多的消息來(lái)進(jìn)行一次讀寫(xiě)周期,即具有IIC重復(fù)開(kāi)始位RepStart的情況,此時(shí)將不能正確地讀寫(xiě)。對(duì)于兩條以上消息組成的讀寫(xiě)即IIC總線RepStart的情況,需要采用ioctl(),組織i2c_msg消息數(shù)組并調(diào)用I2C_RDWR IOCTL命令來(lái)完成。下面以IIC接口無(wú)線射頻RFID卡讀寫(xiě)模塊的標(biāo)識(shí)字節(jié)設(shè)置操作為例,簡(jiǎn)單加以說(shuō)明。

      采用read()和write()操作的主要程序代碼如下:

      int main(void)

      { unsigned int fd; unsigned char buf[10];

      fd=open("/dev/i2c-1", O_RDWR);

      if(!fd) return 0;

      ioctl(fd, I2C_SLAVE, 0x58); //設(shè)置從機(jī)設(shè)備地址

      ioctl(fd, I2C_TIMEOUT, 1); //設(shè)置超時(shí)值

      ioctl(fd, I2C_RETRIES, 1); //設(shè)置重試次數(shù)

      buf[0]=0x03; buf[1]=0x13;buf[2]=0x13;buf[3]=0x03;

      write(fd, buf, 4); //RFID 卡標(biāo)識(shí)字節(jié)設(shè)置

      read(fd, buf, 3); //回讀,以判斷設(shè)置是否成功

      close(fd); return 0;

      }

      采用ioctl()操作的主要程序代碼如下,這里實(shí)現(xiàn)面向3個(gè)連續(xù)的IIC從機(jī)進(jìn)行寫(xiě)入:

      int main(void)

      { struct i2c_rdwr_ioctl_data work_queue;

      unsigned int i, fd, buf[4]= {0x03, 0x13, 0x13,0x03};

      fd=open("/dev/i2c-1", O_RDWR);

      if(!fd) return 0;

      work_queue.nmsgs=3; //消息數(shù)量

      work_queue.msgs= (struct i2c_msg*)

      malloc (work_queue.nmsgs*sizeof (struct i2c_msg));

      for(i=0; i< work_queue.nmsgs; ++i)

      { work_queue.msgs[i].len=4; //數(shù)據(jù)長(zhǎng)度

      work_queue.msgs[i].addr=0x58+i;//IIC 從機(jī)地址

      work_queue.msgs[i].buf=buf; //數(shù)據(jù)指針

      work_queue.msgs[i].flags=I2C_M_WR;//寫(xiě)命令

      }

      ioctl(fd, I2C_TIMEOUT, 2); //設(shè)置超時(shí)

      ioctl(fd, I2C_RETRIES, 1); //設(shè)置重試次數(shù)

      ioctl(fd,I2C_RDWR,(unsigned long)&work_queue);

      close(fd); return 0;

      }

      3 為新設(shè)備編寫(xiě)probe方式驅(qū)動(dòng)

      probe方式的驅(qū)動(dòng),供ARM-Linux-IIC驅(qū)動(dòng)體系,在系統(tǒng)啟動(dòng)后進(jìn)行IIC基本功能性探測(cè)并加載,在系統(tǒng)關(guān)閉時(shí)進(jìn)行“去除”缷載。這種類(lèi)型的驅(qū)動(dòng)基本上分為3部分:面向用戶的設(shè)備文件操作、面向IIC體系的驅(qū)動(dòng)探測(cè)與去除、設(shè)備模塊的加載初始化與缷載去除,設(shè)計(jì)的關(guān)鍵在于具體i2c_client的構(gòu)造和ic2_driver的實(shí)例化。上述IIC接口RFID卡讀寫(xiě)模塊probe方式的主要驅(qū)動(dòng)程序代碼編寫(xiě)如下:

      static struct i2c_client*rfid_client; //IIC客戶

      static const struct i2c_device_id rfid_i2c_id[]={{"rfid_iic",0}};//IIC設(shè)備標(biāo)識(shí)

      static int rfid_open(struct inode*inode, struct file*filp )

      //設(shè)備文件打開(kāi)

      { filp->private_data=NULL;

      try_module_get(THIS_MODULE); return 0;

      }

      static int rfid_release(struct inode*inode,struct file*filp)

      //設(shè)備文件關(guān)閉

      { filp->private_data=NULL;

      module_put(THIS_MODULE); return 0;

      }

      static int rfid_write (struct file*filp, const char*buffer,size_t count, loff_t*offset) //設(shè)備寫(xiě)操作

      { char*tmp; int ret;

      tmp=kzalloc(count, GFP_KERNEL);

      //內(nèi)核數(shù)據(jù)空間分配

      if(tmp==NULL) return -ENOMEM;

      if(copy_from_user(tmp, buffer, count))

      //數(shù)據(jù)拷貝:用戶空間-->內(nèi)核空間

      {kfree(tmp); return -EFAULT; }

      ret=i2c_master_send(rfid_client, tmp, count);

      //調(diào)用系統(tǒng)函數(shù),完成數(shù)據(jù)發(fā)送

      kfree(tmp); return ret;

      }

      static int rfid_read (struct file*filp, char*buffer, size_t count,loff_t*offset) //設(shè)備讀操作

      { char *tmp; int ret;

      tmp=kzalloc(count, GFP_KERNEL);

      //內(nèi)核數(shù)據(jù)空間分配

      if(tmp==NULL)return -ENOMEM;

      ret=i2c_master_recv(rfid_client, tmp, count);

      //調(diào)用系統(tǒng)函數(shù),執(zhí)行數(shù)據(jù)接收

      if(copy_to_user(buffer, tmp, count))

      //數(shù)據(jù)拷貝:內(nèi)核空間-->用戶空間

      {kfree(tmp); return -EFAULT; }

      kfree(tmp); return ret;

      }

      static structfile_operationsrfid_fops=//設(shè)備文件系統(tǒng)實(shí)例化

      { owner:THIS_MODULE,

      read: rfid_read,

      write:rfid_write,

      open:rfid_open,

      release: rfid_release,

      };

      static int__devinit rfid_probe (struct i2c_client*client,const struct i2c_device_id*id)//IIC設(shè)備探測(cè)

      { if (!i2c_check_functionality (client->adapter,I2C_FUNC_I2C)) return -ENODEV;

      return 0;

      }

      static int rfid_remove(struct i2c_client*client)

      //IIC設(shè)備去除

      { kfree(rfid_client);

      i2c_set_clientdata(client, NULL); return 0;

      }

      static struct i2c_driver rfid_i2c_driver=

      //IIC設(shè)備驅(qū)動(dòng)實(shí)例化

      { .driver={.name="rfidDriver",}, //驅(qū)動(dòng)命名

      .probe=rfid_probe, //設(shè)備探測(cè)

      .remove=__devexit_p(rfid_remove), //設(shè)備去除

      .id_table=rfid_i2c_id, //設(shè)備信息標(biāo)識(shí)

      };

      static int__init rfid_drv_init(void) //IIC 設(shè)備初始化

      { int ret;

      struct i2c_board_info info;

      struct i2c_adapter *adapter;

      adapter=i2c_get_adapter(1);

      //選擇 IIC 適配器號(hào)(0~2)

      memset(&info,0,sizeof(struct i2c_board_info)); // 構(gòu)造IIC設(shè)備(板信息-->IIC客戶)

      strlcpy(info.type, "rfidClient", I2C_NAME_SIZE);

      //設(shè)備名字

      info.addr=0x58; //從機(jī)地址

      rfid_client=i2c_new_device(adapter, &info);

      //注冊(cè)特定的i2c_client

      if(!rfid_client) return -ENODEV;

      ret=register_chrdev(250, "rfidIIC", &rfid_fops);

      //注冊(cè)字符設(shè)備

      if(ret==0)

      { ret=i2c_add_driver(&rfid_i2c_driver);

      //指定特定IIC設(shè)備驅(qū)動(dòng)

      if(ret==0) printk("Rfid(0x058)_Creation success! ");

      }

      else unregister_chrdev(250, "rfidIIC");

      return ret;

      }

      static void__exit rfid_drv_exit(void) //IIC設(shè)備缷載

      { i2c_del_driver(&rfid_i2c_driver);//注銷(xiāo) IIC 驅(qū)動(dòng)

      unregister_chrdev(250, "rfidIIC");

      //注銷(xiāo)字符設(shè)備

      }

      MODULE_LICENSE("GPL");

      module_init(rfid_drv_init); //Linux 模塊初始化

      module_exit(rfid_drv_exit); //Linux 模塊去除

      4 簡(jiǎn)易“客服-驅(qū)動(dòng)”型設(shè)備驅(qū)動(dòng)設(shè)計(jì)

      動(dòng)態(tài)加載形式的設(shè)備驅(qū)動(dòng),便于調(diào)試,用時(shí)掛載,不用時(shí)隨時(shí)缷載,既使運(yùn)行時(shí),因而廣泛采用。將probe方式IIC設(shè)備驅(qū)動(dòng)的xxx_probe()和xxx_remove()函數(shù)分別合并到xxx_init()和xxx_exit()函數(shù),就可以得到動(dòng)態(tài)加載形式的IIC設(shè)備驅(qū)動(dòng)。i2c_client的構(gòu)造仍是IIC設(shè)備驅(qū)動(dòng)具體化的關(guān)鍵,因此特別稱這種類(lèi)型的驅(qū)動(dòng)為簡(jiǎn)易“客服-驅(qū)動(dòng)”型設(shè)備驅(qū)動(dòng)。對(duì)上述IIC接口RFID卡讀寫(xiě)模塊probe方式的驅(qū)動(dòng)作簡(jiǎn)易“客服-驅(qū)動(dòng)”型設(shè)備驅(qū)動(dòng)改造,變化部分的主要程序代碼如下:

      static int__init rfid_drv_init(void) //IIC 設(shè)備初始化

      { int ret;

      struct i2c_board_info info;

      struct i2c_adapter *adapter;

      if(!i2c_check_functionality(client->adapter,

      //IIC設(shè)備基本功能性探測(cè)

      I2C_FUNC_I2C))return-ENODEV;

      adapter=i2c_get_adapter(1);

      //選擇 IIC 適配器號(hào)(0~2)

      memset(&info,0,sizeof(struct i2c_board_info));

      //構(gòu)造IIC設(shè)備(板信息-->IIC客戶)

      strlcpy(info.type, "rfidClient", I2C_NAME_SIZE);

      //設(shè)備名字

      info.addr=0x58; //從機(jī)地址

      rfid_client=i2c_new_device(adapter, &info);

      //注冊(cè)特定的i2c_client

      if(!rfid_client) return -ENODEV;

      ret=register_chrdev(250, "rfidIIC", &rfid_fops);

      //注冊(cè)字符設(shè)備

      if(ret<0) unregister_chrdev(250, "rfidIIC");

      return ret;

      }

      static void__exit rfid_drv_exit(void) //IIC 設(shè)備缷載

      { kfree(rfid_client); //i2c_client描述釋放

      unregister_chrdev(250, "rfidIIC"); //注銷(xiāo)字符設(shè)備

      }

      MODULE_LICENSE("GPL");

      module_init(rfid_drv_init); //Linux 模塊初始化

      module_exit(rfid_drv_exit); //Linux 模塊去除

      可以看到,相對(duì)probe方式的IIC設(shè)備驅(qū),簡(jiǎn)易“客服-驅(qū)動(dòng)”型IIC設(shè)備驅(qū)動(dòng),沒(méi)有了xxx_i2c_driver及其相關(guān)函數(shù)的實(shí)例化設(shè)計(jì),整個(gè)程序框架結(jié)構(gòu)簡(jiǎn)便多了,可設(shè)計(jì)性與可讀性增加了。

      5 GPIO模擬IIC設(shè)備驅(qū)動(dòng)快速實(shí)現(xiàn)

      選擇GPIO端口模擬IIC總線驅(qū)動(dòng)IIC設(shè)備,雖然對(duì)于系統(tǒng)整體效率不高,但是直截了當(dāng),易于操作實(shí)現(xiàn)。可以采用ARM-Linux已有的GPIO模擬程序,也可以選擇GPIO自行獨(dú)立設(shè)計(jì)。這里仍以上述IIC接口RFID卡讀寫(xiě)模塊為例,自選GPIO模擬IIC時(shí)序,以動(dòng)態(tài)加載形式的字符型IIC簡(jiǎn)易“客服-驅(qū)動(dòng)”設(shè)計(jì),加以說(shuō)明。主要程序代碼如下:

      #define ByteDelayTimeout 0x0700; //字節(jié)傳輸超時(shí)值

      #define BitDelayTimeout 0x1000; //位傳輸超時(shí)值

      #define SCL_H{gpio_set_value (S5PV210_GPG3(5), 1);} //IIC串行時(shí)鐘線模擬

      #define SCL_L{gpio_set_value (S5PV210_GPG3(5),0); }

      #define SDA_H {gpio_set_value (S5PV210_GPG3(6),1);} //IIC串行數(shù)據(jù)線模擬

      #define SDA_L{gpio_set_value(S5PV210_GPG3(6),0);}

      #define SDA_IN {gpio_direction_input(S5PV210_GPG3(6));} //IIC 串行數(shù)據(jù)位輸入輸出

      #define SDA_OUT {gpio_direction_output(S5PV210_GPG3(6),1); }

      #define WHILE_SDA_HIGH (gpio_get_value (S5PV210_GPG3(6)))

      static void ByteDelay(void) //字節(jié)傳輸延時(shí)

      { volatile unsigned int dwTimeout;

      dwTimeout=ByteDelayTimeout;

      while (--dwTimeout) {asm ("nop") ;}

      }

      static void BitDelay(void) //位傳輸延時(shí)

      { volatile unsigned int dwTimeout;

      dwTimeout=BitDelayTimeout;

      while ( --dwTimeout) {asm("nop"); }

      }

      static void I2C_Start(void) //IIC 傳輸啟動(dòng)位模擬

      { SDA_OUT; SDA_H; BitDelay();

      SCL_H; BitDelay(); SDA_L; BitDelay();

      }

      static void I2C_Stop(void) //IIC傳輸停止位模擬

      { SDA_OUT; SDA_L; BitDelay();

      SCL_H; BitDelay(); SDA_H; BitDelay();

      }

      static void I2C_Ack(void) //IIC 傳輸響應(yīng)位

      { SDA_OUT; SDA_L; BitDelay();

      SCL_H; BitDelay(); SCL_L;

      BitDelay(); SDA_IN; BitDelay();

      }

      static void I2C_Ack1(void) //IIC傳輸響應(yīng)位(帶延時(shí))

      { int i=0;

      SCL_H; BitDelay(); SDA_IN;

      while((WHILE_SDA_HIGH)&&(i<255)) i++; //無(wú)

      應(yīng)答延時(shí)一段時(shí)間后默認(rèn)已經(jīng)收到

      SCL_L; BitDelay(); SDA_OUT; BitDelay();

      }

      static void I2C_Nack(void) //IIC傳輸非響應(yīng)位

      { SDA_OUT; SDA_H; BitDelay();

      SCL_H; BitDelay(); SCL_L;

      BitDelay(); SCL_H;

      }

      static char Write_I2C_Byte(char byte)

      //IIC總線字節(jié)寫(xiě)操作

      { char i;

      SCL_L; BitDelay ();

      for(i=0 ; i<8; i++)

      {if((byte&0x80)==0x80) SDA_H;

      else SDA_L;

      BitDelay(); SCL_H; BitDelay();

      SCL_L; BitDelay(); byte <<=1;

      }

      return 1;

      }

      static char Read_I2C_Byte(void) //IIC總線字節(jié)讀操作

      { char i, buff=0;

      SCL_L; BitDelay();

      for(i=0; i< 8; i++)

      {SDA_OUT;SDA_H;BitDelay();

      SCL_H; SDA_IN; BitDelay();

      if(WHILE_SDA_HIGH) buff|=0x01;

      else buff&=~0x01;

      if(i<7) buff<<=1 ;

      SCL_L; BitDelay();

      }

      return buff;

      }

      static void InterfaceInit(void) //IIC接口的GPIO定義

      { gpio_direction_output(S5PV210_GPG3(5), 1);

      //SCL OUT

      gpio_direction_output(S5PV210_GPG3(6), 1);

      //SDA OUT

      gpio_set_value (S5PV210_GPG3(5), 1);

      //初始高電平

      gpio_set_value (S5PV210_GPG3(6), 1);

      ByteDelay(); ByteDelay(); ByteDelay();

      }

      static int dvcIIC_open (struct inode*inode_ptr, struct file

      *fptr) //設(shè)備文件打開(kāi)

      { fptr->f_op=&dvcIIC_fops;

      fptr->private_data=NULL;

      try_module_get(THIS_MODULE); return 0;

      }

      static int dvcIIC_release (struct inode*inode_ptr, struct file*fptr)//設(shè)備文件關(guān)閉

      { //fptr->private_data=NULL;

      module_put(THIS_MODULE); return 0 ;

      }

      static int dvcIIC_read(struct file*fptr, char*buffer, size_t count,loff_t*fp) //設(shè)備文件讀

      { int i;char data[100];

      I2C_Start(); //啟動(dòng)IIC傳輸,發(fā)送從機(jī)設(shè)備地址

      Write_I2C_Byte((0x58<<1)+1);

      I2C_Ack1();

      for(i=0;i<count;i++) //按字節(jié)讀入數(shù)據(jù)

      {data[i]=Read_I2C_Byte();I2C_Ack();}

      I2C_Nack();I2C_Stop();

      //發(fā)送非響應(yīng)位/停止位,結(jié)束操作

      if(copy_to_user(buffer,data,count))return-1;

      //向用戶空間回傳數(shù)據(jù)

      else return 0;

      }

      static int dvcIIC_write(struct file*fptr,const char*buffer,size_t size,loff_t*fp)//設(shè)備文件寫(xiě)

      { int i;char data[100];

      if(copy_from_user(data,buffer,size))return-1;

      //從用戶空間接收數(shù)據(jù)

      I2C_Start(); //啟動(dòng)IIC傳輸,發(fā)送從機(jī)設(shè)備地址

      Write_I2C_Byte((0x58<<1));I2C_Ack1();

      for(i=0;i<size;i++) //按字節(jié)寫(xiě)入數(shù)據(jù)

      {Write_I2C_Byte(data[i]);I2C_Ack1();}

      I2C_Stop();I2C_Nack(); //發(fā)送非響應(yīng)位/停止位,結(jié)束操作

      I2C_Stop();return 0;

      }

      static struct file_operations dvcIIC_fops=//設(shè)備文件操作接口

      { .owner=THIS_MODULE,

      .open=dvcIIC_open,

      .read=dvcIIC_read,

      .write=dvcIIC_write,

      .release=dvcIIC_release,

      };

      static int dvcIIC_init(void)//IIC設(shè)備初始化:字符設(shè)備注冊(cè)

      { int status;

      InterfaceInit();

      status=register_chrdev(239,"dvcIIC",&dvcIIC_fops);

      if(status<0)return status;

      return 0;

      }

      static void dvcIIC_exit(void) //IIC設(shè)備注銷(xiāo)

      { unregister_chrdev(239,"dvcIIC");}

      MODULE_LICENSE("GPL");

      module_init(dvcIIC_init); //驅(qū)動(dòng)模塊初始化

      module_exit(dvcIIC_exit); //驅(qū)動(dòng)模塊去除

      6 結(jié)束語(yǔ)

      ARM-Linux-IIC設(shè)備的添加與驅(qū)動(dòng),可以根據(jù)主機(jī)控制器與從機(jī)設(shè)備的特點(diǎn)采用傳統(tǒng)字符型設(shè)備驅(qū)動(dòng)的方式實(shí)現(xiàn);也可以根據(jù)ARM-Linux-IIC總線設(shè)備層次驅(qū)動(dòng)的軟件特點(diǎn),對(duì)常規(guī)IIC設(shè)備采用通用i2c-dev.c快速驅(qū)動(dòng),對(duì)特定IIC設(shè)備設(shè)計(jì)probe流行方式的驅(qū)動(dòng)或動(dòng)態(tài)加載的簡(jiǎn)易IIC“客服-驅(qū)動(dòng)”;還可以選用GPIO模擬IIC總線快速驅(qū)動(dòng)設(shè)備。其中,根據(jù)ARM-Linux-IIC層次驅(qū)動(dòng)的總線架構(gòu)設(shè)計(jì)IIC設(shè)備驅(qū)動(dòng),稍顯繁瑣,不易理解,但更符合ARM-Linux總線驅(qū)動(dòng)模塊化的規(guī)范,能夠有效地融入ARM-Linux體系,充分利用Linux內(nèi)核資源,實(shí)現(xiàn)Linux系統(tǒng)的穩(wěn)定、高效,是應(yīng)該主動(dòng)選擇與推薦使用的。

      [1]怯肇乾.基于底層硬體的軟件設(shè)計(jì)[M].北京:航空航天大學(xué)出版社,2008.

      [2]宋寶華.Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)詳解[M].北京:人民郵電出版社,2008.

      [3]劉紅波.實(shí)例解析Linux內(nèi)核I2C體系結(jié)構(gòu) [EB/OL](2009-12).http://www.dzsc.com/data/html/2009-12-22/81040.html.

      [4]杜博,方向忠.嵌入式Linux系統(tǒng)下I2C設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)[J].微計(jì)算機(jī)信息,2006,22(11):21-23.DU Bo,F(xiàn)ANG Xiang-zhong.I2Cdevice driver development in embedded Linux OS[J].Microcomputer Information,2006,22(11):21-23.

      [5]李力,厲謹(jǐn).利用GPIO模擬I2C總線協(xié)議 [J].科技風(fēng),2009(12):33-36.LI Li,LI Jin.Simulating I2C bus communication with GPIO[J].Science-Technology Wind,2009(12):33-36.

      [6]楊文鉑,刑鵬康.Linux下I2C設(shè)備驅(qū)動(dòng)的一種適配器層直接實(shí)現(xiàn)方法[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2011,11(6):16-19.YANGWen-bo,XING Peng-kang.A I2Cdevice driver method about adapter layer in linux OS[J].Single Chip Microcomputer and Embedded System Application,2011,11(6):16-19.

      [7]蘇纓墩,鐘漢如.嵌入式Linux中的Nand Flash驅(qū)動(dòng)詳解[J].工業(yè)儀表與自動(dòng)化裝置,2011(4):56-60.SU Ying-dun,ZHONG Han-ru.A detail explication on Nand Flash drive in embedded Linux[J].Industrial Instrumentation&Automation,2011(4):56-60.

      猜你喜歡
      適配器內(nèi)核字節(jié)
      萬(wàn)物皆可IP的時(shí)代,我們當(dāng)夯實(shí)的IP內(nèi)核是什么?
      No.8 字節(jié)跳動(dòng)將推出獨(dú)立出口電商APP
      強(qiáng)化『高新』內(nèi)核 打造農(nóng)業(yè)『硅谷』
      No.10 “字節(jié)跳動(dòng)手機(jī)”要來(lái)了?
      基于嵌入式Linux內(nèi)核的自恢復(fù)設(shè)計(jì)
      Linux內(nèi)核mmap保護(hù)機(jī)制研究
      適配器模式及其應(yīng)用
      簡(jiǎn)談MC7字節(jié)碼
      新型水文測(cè)驗(yàn)GPS適配器設(shè)計(jì)與應(yīng)用
      基于藍(lán)牙串口適配器的GPS接收機(jī)與AutoCAD的實(shí)時(shí)無(wú)線通信
      饶平县| 西贡区| 东平县| 林州市| 乐安县| 宝丰县| 剑川县| 铜梁县| 浪卡子县| 密山市| 龙游县| 许昌县| 逊克县| 清苑县| 内江市| 开阳县| 高淳县| 临猗县| 佛教| 泸定县| 阳新县| 庐江县| 大邑县| 遂川县| 宿迁市| 福海县| 福安市| 昆明市| 桓仁| 兴化市| 松江区| 深圳市| 新丰县| 墨玉县| 汨罗市| 临汾市| 年辖:市辖区| 洛浦县| 额敏县| 姜堰市| 乐山市|