亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        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á)汽車零部件有限公司,河南 鄭州 100044)

        廣泛應(yīng)用的ARM-Linux及其Android的嵌入式軟硬件系統(tǒng)中,常常涉及到內(nèi)部整合電路IIC (Inter-Integrated Circuit)總線的操作及其設(shè)備的添加與驅(qū)動(dòng)的實(shí)現(xiàn)?;贏RM內(nè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è)、注銷管理,設(shè)備的探測(cè)、檢查,以及無(wú)關(guān)具體適配器的讀寫通信代碼。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è)備,首先是編寫針對(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各類通信算法(在目錄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),可以為其編寫特定的IIC驅(qū)動(dòng)。ARM-Linux設(shè)備驅(qū)動(dòng)通常采用靜態(tài)加載操作,它有兩種方式:適配 (adapter)和探測(cè) (probe),適配是傳統(tǒng)方式(Legacy),探測(cè)是新類型(New Style),大多數(shù)設(shè)備驅(qū)動(dòng)越來(lái)越趨向采用probe方式。也可以采用驅(qū)動(dòng)設(shè)計(jì)人員習(xí)慣的動(dòng)態(tài)加載方式編寫簡(jiǎn)易的IIC“客服-驅(qū)動(dòng)”。IIC總線,可以采用系統(tǒng)硬件實(shí)現(xiàn)的IIC總線控制器,也可以選用通用輸入-輸出端口GPIO模擬產(chǎn)生。如果理解不了ARM-Linux的IIC總線層次框架,也可以拋掉這種機(jī)制采用傳統(tǒng)方式編寫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è)備的讀寫流程并不對(duì)應(yīng)于一條消息,往往需要兩條甚至更多的消息來(lái)進(jìn)行一次讀寫周期,即具有IIC重復(fù)開(kāi)始位RepStart的情況,此時(shí)將不能正確地讀寫。對(duì)于兩條以上消息組成的讀寫即IIC總線RepStart的情況,需要采用ioctl(),組織i2c_msg消息數(shù)組并調(diào)用I2C_RDWR IOCTL命令來(lái)完成。下面以IIC接口無(wú)線射頻RFID卡讀寫模塊的標(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)行寫入:

        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;//寫命令

        }

        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è)備編寫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)行“去除”缷載。這種類型的驅(qū)動(dòng)基本上分為3部分:面向用戶的設(shè)備文件操作、面向IIC體系的驅(qū)動(dòng)探測(cè)與去除、設(shè)備模塊的加載初始化與缷載去除,設(shè)計(jì)的關(guān)鍵在于具體i2c_client的構(gòu)造和ic2_driver的實(shí)例化。上述IIC接口RFID卡讀寫模塊probe方式的主要驅(qū)動(dòng)程序代碼編寫如下:

        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è)備寫操作

        { 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);//注銷 IIC 驅(qū)動(dòng)

        unregister_chrdev(250, "rfidIIC");

        //注銷字符設(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)鍵,因此特別稱這種類型的驅(qū)動(dòng)為簡(jiǎn)易“客服-驅(qū)動(dòng)”型設(shè)備驅(qū)動(dòng)。對(duì)上述IIC接口RFID卡讀寫模塊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"); //注銷字符設(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)??梢圆捎肁RM-Linux已有的GPIO模擬程序,也可以選擇GPIO自行獨(dú)立設(shè)計(jì)。這里仍以上述IIC接口RFID卡讀寫模塊為例,自選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é)寫操作

        { 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è)備文件寫

        { 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é)寫入數(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è)備注銷

        { 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ú)線通信
        国产电影一区二区三区| 中国少妇×xxxx性裸交| 亚洲av无码一区东京热久久| 精品国内在视频线2019| 亚洲av无码不卡久久| 国产欧美日韩视频一区二区三区| 97中文字幕在线观看| 亚洲最大日夜无码中文字幕| 国产成人拍精品免费视频| 综合图区亚洲另类偷窥| 国产一区二区三区蜜桃| 激情文学婷婷六月开心久久| 亚洲精品一区二区国产精华液 | av一区二区三区综合网站| 久久久精品国产亚洲av网深田| 无码人妻精品一区二区三区9厂| √天堂中文官网8在线| 在线亚洲+欧美+日本专区| 日韩av一区二区三区精品| 亚洲av男人的天堂在线| 丰满人妻一区二区三区蜜桃| 玩弄丰满奶水的女邻居| 国产精品亚洲综合色区韩国| 中文人妻无码一区二区三区| 在线播放中文字幕一区二区三区| 亚洲中文字幕一区精品| 中文字幕一区二区三区四区五区| 在线成人一区二区| 天天躁人人躁人人躁狂躁| 亚洲日韩精品AⅤ片无码富二代| 日本韩国一区二区高清| 把女人弄爽特黄a大片| 国产成人精品一区二区三区免费 | 亚洲精品第一国产麻豆| 久九九久视频精品网站| 凹凸世界视频a一二三| 99久久99久久久精品齐齐| 日产精品久久久久久久性色| 美女一级毛片免费观看97| 国产精品一区二区三区三| 日韩人妻无码精品一专区二区三区 |