1. 程式人生 > >Linux驅動子系統之I2C(一)

Linux驅動子系統之I2C(一)

1 硬體特性
1.1 概述

I2C匯流排是由Philips公司開發的兩線式序列匯流排,這兩根線為時鐘線(SCL)和雙向資料線(SDA)。由於I2C匯流排僅需要兩根線,因此在電路板上佔用的空間更少,帶來的問題是頻寬較窄。I2C在標準模式下傳輸速率最高100Kb/s,在快速模式下最高可達400kb/s。屬於半雙工。在嵌入式系統中,I2C應用非常廣泛,大多數微控制器中集成了I2C匯流排,一般用於和RTC,EEPROM,智慧電池電路,感測器,LCD以及其他類似裝置之間的通訊。I2C匯流排時鐘都是由I2C主控器提供
1.2 I2C匯流排傳輸時序


1.3 I2C匯流排的訊號狀態
1、  空閒狀態:SDA和SCL都是高電平;
2、  開始條件(S):SCL為高電平時,SDA由高電平向低電平跳變,開始傳輸資料;
3、  結束條件(P):SCL為高電平時,SDA由低電平向高電平跳變,結束傳輸資料;
4、  資料有效:在SCL的高電平期間,SDA保持穩定,資料有效。SDA的改變只能發生在SCL的低電平期間;
5、  ACK訊號:資料傳輸的過程中,接收器件每接收一個位元組資料要產生一個ACK訊號,向傳送器件發出特定的低電平脈衝,表示已經收到資料。
讀暫存器的標準流程為:


1.    Master傳送I2C addr(7bit)和w操作1(1bit),等待ACK
2.    Slave傳送ACK
3.    Master傳送reg addr(8bit),等待ACK
4.    Slave傳送ACK
5.    Master發起START
6.    Master傳送I2C addr(7bit)和r操作1(1bit),等待ACK
7.    Slave傳送ACK
8.    Slave傳送data(8bit),即暫存器裡的值
9.    Master傳送ACK
10.  第8步和第9步可以重複多次,即順序讀多個暫存器
10bit地址
10bit的定址擴充套件可能定址的數目.有7bit地址和10bit地址的裝置可以連線到相同的I2C總線上,而且7bit定址和10bit定址都可以用在所有的匯流排速度模式下.不過,10bit定址用的不多.
10bit的從機地址由開始條件(S)或重複開始條件(Sr)後的兩個位元組組成.第一個位元組的前7位是1111 0XX,XX是10bit地址的最高有效位的前兩位.第一個位元組的第8bit是讀寫位,決定傳輸方向.
儘管1111 XXX有8種可能的組合,然後只有1111 0XX這四種可以用於10bit定址.剩下的1111 1XX這四種是為將來I2C擴充套件用的.

1.4 從裝置地址


從datasheet發現,有三個IO口確定I2C從裝置地址後三位,I2C匯流排從裝置使用7位地址,最後一個為讀寫控制位。下圖是TVP5158的原理圖,我們可以計算出它的地址,在讀取SII9135A的時候,手冊上寫得是0X60、0X68,這是8位,前7位有效,所以真實的I2C地址為0x30、0x34,第八位代表讀寫。


1.5 I2C讀寫方式

下面I2C寫操作的步驟:


多位元組寫的時序

 下面是I2C讀操作的步驟:


多位元組讀的時序


具體可參考datasheet

2  I2C子系統
2.1 LinuxI2C子系統架構

在核心中已經提供I2C子系統,所以在做I2C驅動之前,就必須要熟悉該子系統。


2.2 三大組成部分
1、I2C核心(i2c-core)
I2C核心提供了I2C匯流排驅動和裝置驅動的註冊、登出方法,I2C通訊方法(algorithm)上層的、與具體介面卡無關的程式碼以及探測裝置、檢測裝置地址的上層程式碼等。
2、I2C匯流排驅動(I2Cadapter/Algo driver)
I2C匯流排驅動是I2C介面卡的軟體實現,提供I2C介面卡與從裝置間完成資料通訊的能力。
I2C匯流排驅動由i2c_adapter和i2c_algorithm來描述
3、I2C客戶驅動程式(I2Cclient driver)
I2C客戶驅動是對I2C從裝置的軟體實現,一個具體的I2C客戶驅動包括兩個部分:一部分是i2c_driver,用於將裝置掛接於i2c匯流排;另一部分是裝置本身的驅動。
I2C客戶驅動程式由i2c_driver和i2c_client來描述
2.3 所有的I2C驅動程式碼位於drivers/i2c目錄下
I2c-core.c    實現I2C核心的功能
I2c-dev.c     通用的從裝置驅動
Chips       特定的I2C裝置驅動
Busses      I2C介面卡的驅動
Algos       實現了一些I2C匯流排介面卡的algorithm
2.4 I2C驅動編寫的兩種方法
從上面的圖我們可以看到兩種編寫驅動方法,一種是利用系統提供的i2c-dev.c來實現一個i2c介面卡的裝置檔案,然後通過在應用層操作I2C介面卡來控制I2C裝置;另一種是為I2C從裝置獨立編寫一個裝置驅動,不需要i2c-dev.c檔案。
2.5 重要的資料結構
每次分析子系統免不了分析它的資料結構,OK我們先來分析一下。
I2c_adapter結構體代表I2C匯流排控制器

複製程式碼
struct i2c_adapter {
   struct module *owner;
   unsigned int class;       /*classes to allow probing for */
    const struct i2c_algorithm*algo; /* 總線上資料傳輸的演算法*/
   void *algo_data;              /* algorithm 資料 */
 
   int timeout;            /* injiffies */
   int retries;             /* 重試次數 */
    struct device dev;      /* the adapter device */
 
   int nr;
   char name[48];                 /* 介面卡名字 */
   struct completion dev_released;   /* 用於同步 */
};
複製程式碼

I2c_algorithm對應一套通訊方法

複製程式碼
struct i2c_algorithm {
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum);
    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
               unsigned short flags, charread_write,
               u8 command, int size, unioni2c_smbus_data *data);
    u32 (*functionality) (structi2c_adapter *);
};
複製程式碼

Functionality 函式用於返回algorithm所支援的通訊協議,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等。
smbus_xfer   函式SMBus傳輸函式指標,SMBus大部分基於I2C匯流排規範,SMBus不需增加額外引腳。與I2C匯流排相比,SMBus增加了一些新的功能特性,在訪問時序也有一定的差異。
Master_xfer  函式實現總線上資料傳輸,與具體的介面卡有關
Master_xfer  函式實現模板:

複製程式碼
static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)
{
   ......
   for (i = 0; i < num; i++) {
       i2c_adapter_xxx_start();         /*產生起始位*/
       if (msgs[i]->flags & I2C_M_RD) {    /*讀取*/
           i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);  /*傳送從裝置地址*/
           i2c_adapter_xxx_wait_ack();   /*獲得從裝置的ACK*/
i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len);  /*讀取len長度的資料到buf中*/
       } else {
           i2c_adapter_xxx_setaddr(msg->addr << 1);
           i2c_adapter_xxx_wait_ack();
           i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);
       }
    }
   i2c_adapter_xxx_stop(); /*產生停止位*/
}
複製程式碼

上面呼叫的函式用於完成介面卡的底層硬體操作,與I2C介面卡和CPU的具體硬體直接相關,需要由工程師根據晶片的資料手冊來實現。在核心原始碼中,針對不同的I2C介面卡都有master_xfer的實現,風格與模板不盡相同,但是可以用該模板作為參考來看原始碼,受益匪淺。
I2c_driver代表I2C從裝置驅動

複製程式碼
struct i2c_driver {
         unsignedint class;
 
         int(*attach_adapter)(struct i2c_adapter *) __deprecated; /*依附i2c介面卡函式指標*/
         int(*detach_adapter)(struct i2c_adapter *) __deprecated;/*脫離i2c介面卡函式指標*/
 
         int (*probe)(struct i2c_client*, const struct i2c_device_id *);
         int (*remove)(struct i2c_client*);
 
         int(*suspend)(struct i2c_client *, pm_message_t mesg);
         int(*resume)(struct i2c_client *);
         void(*alert)(struct i2c_client *, unsigned int data);
         int(*command)(struct i2c_client *client, unsigned int cmd, void *arg);
 
         struct device_driver driver;
         const struct i2c_device_id*id_table;  /* 該驅動所支援的裝置ID表 */
 
         /*Device detection callback for automatic device creation */
         int(*detect)(struct i2c_client *, struct i2c_board_info *);
         constunsigned short *address_list;
         structlist_head clients;
};
複製程式碼

在新核心中,attach_adapter和detach_adapter已經被probe和remove取代
Id_table用於i2c_driver和i2c_client的匹配
I2c_client代表I2C從裝置

複製程式碼
struct i2c_client {
unsigned short flags;                 /*I2C_CLIENT_TEN:使用10位從地址,I2C_CLIENT_PEC:使用SMBus包錯誤檢測*/
         unsignedshort addr;                 /* chipaddress - NOTE: 7bit    */
         charname[I2C_NAME_SIZE];
         struct i2c_adapter *adapter; /* 依附的i2c_adapter   */
         struct i2c_driver *driver;         /* 依附的i2c_driver*/
         structdevice dev;             /* the devicestructure             */
         intirq;                         /* irq issuedby device               */
         structlist_head detected;
};
複製程式碼

2.6 核心層提供的介面函式
1、  增加/刪除I2C介面卡
int i2c_add_adapter(struct i2c_adapter *adapter)->static int i2c_register_adapter(struct i2c_adapter *adap)
int i2c_del_adapter(struct i2c_adapter *adap)

複製程式碼
static int i2c_register_adapter(struct i2c_adapter *adap)
{
    int res = 0;

    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p))) {
        res = -EAGAIN;
        goto out_list;
    }

    /* Sanity checks */
    if (unlikely(adap->name[0] == '\0')) {
        pr_err("i2c-core: Attempt to register an adapter with "
               "no name!\n");
        return -EINVAL;
    }
    if (unlikely(!adap->algo)) {
        pr_err("i2c-core: Attempt to register adapter '%s' with "
               "no algo!\n", adap->name);
        return -EINVAL;
    }

    rt_mutex_init(&adap->bus_lock);
    mutex_init(&adap->userspace_clients_lock);
    INIT_LIST_HEAD(&adap->userspace_clients);

    /* Set default timeout to 1 second if not already set */
    if (adap->timeout == 0)
        adap->timeout = HZ;

    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    adap->dev.bus = &i2c_bus_type;
    adap->dev.type = &i2c_adapter_type;
    res = device_register(&adap->dev);
    if (res)
        goto out_list;

    dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

#ifdef CONFIG_I2C_COMPAT
    res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
                       adap->dev.parent);
    if (res)
        dev_warn(&adap->dev,
             "Failed to create compatibility class link\n");
#endif

    /* create pre-declared device nodes */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);

    /* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);

    return 0;

out_list:
    mutex_lock(&core_lock);
    idr_remove(&i2c_adapter_idr, adap->nr);
    mutex_unlock(&core_lock);
    return res;
}
複製程式碼

Device_register(&adap->dev)  向I2C匯流排註冊一個adapter裝置
i2c_scan_static_board_info(adap)   註冊所有已知的i2c_client
2、  增加/刪除I2C從裝置驅動  
int i2c_add_driver(struct i2c_driver *driver)->int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
void i2c_del_driver(struct i2c_driver *driver)  

複製程式碼
/*
 * An i2c_driver is used with one or more i2c_client (device) nodes to access
 * i2c slave chips, on a bus instance associated with some i2c_adapter.
 */
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
    int res;

    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p)))
        return -EAGAIN;

    /* add the driver to the list of i2c drivers in the driver core */
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;

    /* When registration returns, the driver core
     * will have called probe() for all matching-but-unbound devices.
     */
    res = driver_register(&driver->driver);
    if (res)
        return res;

    pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

    INIT_LIST_HEAD(&driver->clients);
    /* Walk the adapters that are already present */
    mutex_lock(&core_lock);
    bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
    mutex_unlock(&core_lock);

    return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
複製程式碼

向I2C匯流排註冊一個i2c_driver
3、  i2c傳輸,傳送和接收
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg*msgs, int num)  
int i2c_master_send(const struct i2c_client *client, constchar *buf, int count)  
int i2c_master_recv(const struct i2c_client *client, char*buf, int count) 

複製程式碼
/**
 * i2c_transfer - execute a single or combined I2C message
 * @adap: Handle to I2C bus
 * @msgs: One or more messages to execute before STOP is issued to
 *    terminate the operation; each message begins with a START.
 * @num: Number of messages to be executed.
 *
 * Returns negative errno, else the number of messages executed.
 *
 * Note that there is no requirement that each message be sent to
 * the same slave address, although that is the most common model.
 */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    unsigned long orig_jiffies;
    int ret, try;

    /* REVISIT the fault reporting model here is weak:
     *
     *  - When we get an error after receiving N bytes from a slave,
     *    there is no way to report "N".
     *
     *  - When we get a NAK after transmitting N bytes to a slave,
     *    there is no way to report "N" ... or to let the master
     *    continue executing the rest of this combined message, if
     *    that's the appropriate response.
     *
     *  - When for example "num" is two and we successfully complete
     *    the first message but get an error part way through the
     *    second, it's unclear whether that should be reported as
     *    one (discarding status on the second message) or errno
     *    (discarding status on the first one).
     */

    if (adap->algo->master_xfer) {
#ifdef DEBUG
        for (ret = 0; ret < num; ret++) {
            dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
                "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
                ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
        }
#endif

        if (in_atomic() || irqs_disabled()) {
            ret = i2c_trylock_adapter(adap);
            if (!ret)
                /* I2C activity is ongoing. */
                return -EAGAIN;
        } else {
            i2c_lock_adapter(adap);
        }

        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
            ret = adap->algo->master_xfer(adap, msgs, num);
            if (ret != -EAGAIN)
                break;
            if (time_after(jiffies, orig_jiffies + adap->timeout))
                break;
        }
        i2c_unlock_adapter(adap);

        return ret;
    } else {
        dev_dbg(&adap->dev, "I2C level transfers not supported\n");
        return -EOPNOTSUPP;
    }
}
EXPORT_SYMBOL(i2c_transfer);
複製程式碼

最終會呼叫到介面卡實現的master_xfer函式來完成資料傳輸工作

2.6 I2C子系統初始化

複製程式碼
struct bus_type i2c_bus_type = {
    .name        = "i2c",
    .match        = i2c_device_match,
    .probe        = i2c_device_probe,
    .remove        = i2c_device_remove,
    .shutdown    = i2c_device_shutdown,
    .pm        = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
//////////////////////////////
static int __init i2c_init(void)
{
    int retval;

    retval = bus_register(&i2c_bus_type);
    if (retval)
        return retval;
#ifdef CONFIG_I2C_COMPAT
    i2c_adapter_compat_class = class_compat_register("i2c-adapter");
    if (!i2c_adapter_compat_class) {
        retval = -ENOMEM;
        goto bus_err;
    }
#endif
    retval = i2c_add_driver(&dummy_driver);
    if (retval)
        goto class_err;
    return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
    class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
    bus_unregister(&i2c_bus_type);
    return retval;
}

static void __exit i2c_exit(void)
{
    i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
    class_compat_unregister(i2c_adapter_compat_class);
#endif
    bus_unregister(&i2c_bus_type);
}

/* We must initialize early, because some subsystems register i2c drivers
 * in subsys_initcall() code, but are linked (and initialized) before i2c.
 */
postcore_initcall(i2c_init);
module_exit(i2c_exit);
複製程式碼

3  i2c-dev
3.1 概述

之前在介紹I2C子系統時,提到過使用i2c-dev.c檔案在應用程式中實現我們的I2C從裝置驅動。不過,它實現的是一個虛擬,臨時的i2c_client,隨著裝置檔案的開啟而產生,並隨著裝置檔案的關閉而撤銷。I2c-dev.c針對每個I2C介面卡生成一個主裝置號為89的裝置檔案,實現了i2c_driver的成員函式以及檔案操作介面,所以i2c-dev.c的主題是”i2c_driver成員函式+字元裝置驅動”。
3.2 i2c-dev.c原始碼分析
初始化模組

複製程式碼
static int __init i2c_dev_init(void)
{
         res= register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
 
         i2c_dev_class= class_create(THIS_MODULE, "i2c-dev");
 
         /*Keep track of adapters which will be added or removed later */
         res= bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
 
         /*繫結已經存在的介面卡 */
         i2c_for_each_dev(NULL,i2cdev_attach_adapter);
}
複製程式碼

I2c-dev初始化函式主要做了註冊名為”i2c”的字元裝置檔案和”i2c-dev”的類
i2cdev_read和i2cdev_write
I2c-dev.c中實現的i2cdev_read和i2cdev_write函式不具有太強的通用性,只適合下面這種單開始訊號情況:


而不適合多開始訊號的情況:


所以我們經常會使用i2cdev_ioctl函式的I2C_RDWR,在分析i2cdev_ioctl函式之前,我們需要了解一個結構體:

/* This is the structure as used in theI2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
         structi2c_msg __user *msgs;         /* pointersto i2c_msgs */
         __u32nmsgs;                    /* number ofi2c_msgs */
};

Msgs     表示單個開始訊號傳遞的資料;
Nmsgs     表示有多少個msgs,比如上圖,單開始訊號時,nmsgs等於1;多開始訊號時,nmsgs等於2

複製程式碼
struct i2c_msg {
         __u16addr;     /* slave address                         */
         __u16flags;  /* 預設為寫入 */
#define I2C_M_TEN                  0x0010     /*this is a ten bit chip address */
#define I2C_M_RD           0x0001     /* read data,from slave to master */
#define I2C_M_NOSTART                  0x4000     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR     0x2000     /*if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK          0x1000     /*if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK           0x0800     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN               0x0400     /* length will be first received byte */
         __u16len;                  /* msg length                              */
         __u8*buf;                 /* pointer to msgdata                       */
};
複製程式碼

使用i2cdev_ioctl函式的I2C_RDWR指令會呼叫到i2cdev_ioctl_rdrw函式:

複製程式碼
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
                   unsignedlong arg)
{
         structi2c_rdwr_ioctl_data rdwr_arg;
         structi2c_msg *rdwr_pa;
         u8__user **data_ptrs;
         inti, res;
 
         if(copy_from_user(&rdwr_arg,
                               (struct i2c_rdwr_ioctl_data __user *)arg,
                               sizeof(rdwr_arg)))
                   return-EFAULT;
 
         if(rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
                   return-EINVAL;
 
         rdwr_pa= kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
 
         if(copy_from_user(rdwr_pa, rdwr_arg.msgs,
                               rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
                   kfree(rdwr_pa);
                   return-EFAULT;
         }
 
         res= i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
         while(i-- > 0) {
                   if(res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
                            if(copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
                                                rdwr_pa[i].len))
                                     res= -EFAULT;
                   }
                   kfree(rdwr_pa[i].buf);
         }
}
複製程式碼

咋一看,還挺複雜,其實主要做了一件事情:把使用者空間傳遞過來的i2c_rdwr_ioctl_data資料進行錯誤檢查,然後呼叫i2c_transfer函式與介面卡進行通訊,如果是接收資料,程式碼會將訪問到的資料傳回i2c_rdwr_ioctl_data的buf中。I2c_transfer最終會呼叫到I2C介面卡具體實現的master_xfer函式來與硬體進行通訊。
3.3 使用者空間驅動模板

複製程式碼
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define OSA_SOK      0  ///< Status : OK
#define OSA_EFAIL   -1  ///< Status : Generic error

#define I2C_DEFAULT_INST_ID  (2)

            
           

相關推薦

Linux驅動子系統I2C

1 硬體特性 1.1 概述 I2C匯流排是由Philips公司開發的兩線式序列匯流排,這兩根線為時鐘線(SCL)和雙向資料線(SDA)。由於I2C匯流排僅需要兩根線,因此在電路板上佔用的空間更少,帶來的問題是頻寬較窄。I2C在標準模式下傳輸速率最高100Kb/s,在快速模式下最高可達400kb/s。屬於半

linux程序管理概念

一、程序和執行緒的概念 1.程序和執行緒的定義   程序並不只是一段可以執行的程式碼,也包含了執行程式碼所需要的資源。   在作業系統來看,程序是資源管理的最小單元,而我們又知道,執行緒是程式執行的最小單元。   話說回來,Linux系統至少有一個程序,一個程式可以對應多個程序,一個程序只能對應一個程

Linux進階:部署

經過長期的開發工作,在專案中經常會需要將打包好的專案部署到Linux伺服器上,不過,在此之前需要掌握一些Linux常用命令比如ls、ll、ps -ef|grep java 、cp、tail 等等,詳細的可以百度查一下,還是很多的。接下來,就說一下關於專案的部署。 首先需要一個遠端訪問Linu

linux驅動開發蜂鳴器驅動源碼分析

linux 蜂鳴器 驅動 蜂鳴器的驅動源碼在/driver/char/buzzer/x210-buzzer.c文件中,源碼如下#include <linux/module.h> #include <linux/kernel.h> #include <linux

Linux I2C常用的幾種實例化(i2c_client ) 【轉】

掃描 sent near 通過 完成 check 根據 pup views 轉自:http://blog.csdn.net/lugandong/article/details/48092397 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 目錄(?)

Linux I2C常用的幾種例項化(i2c_client )

前言: 因為工作是音訊驅動,所以經常涉及到I2C、I2S等常用的匯流排,想將I2C相關的東西總結一下,讓自己更加了解I2C。 基於:Linux3.10 方式一: 使用arch/arm/mach-s3c24xx/mach-mini2440.c舉例:

linux下源代碼搭建php環境mysql

運行程序 google chcon 系統環境 ncurses con 軟件 func ets 如今已經大半夜了,五一勞動節挺無聊的。 折騰一下吧。實在是睡不著。於是乎在電腦上安裝個虛擬機,然後呢,在虛擬機上搭建一個php環境。 首先我得安裝MYSQL吧。發現遇到

小白的linux學習

探索linux一、進入系統*)普通用戶登陸student 普通用戶,密碼student*)超級用戶登陸 —〉not listed 點擊未列出 username 提示輸入用戶名稱 —〉root root 為系統超級用戶 passw

Linux文件系統學習相關概念???

正是 range 不同的 struct pan 根據 inode 存在 opera “一切皆是文件”是 Unix/Linux 的基本哲學之一。不僅普通的文件,目錄、字符設備、塊設備、套接字等在 Unix/Linux 中都是以文件被對待;它們雖然類型不同,但是對其提供的卻是同

Linux內核設計基礎中斷處理

family ng- 內存 irq strong 睡眠 sign 技術 struct 假設讓內核定期對設備進行輪詢。以便處理設備,那會做非常多無用功,假設能讓設備在

學習淺談:基礎命令及linux工作原理

linux命令 看了視頻,它系統的講解了linux從硬件到操作系統的工作過程,以及常用的基礎命令的詳細參數及用法。 我也在這裏整理之後加強記憶一次基本概念,及linux文件樹目錄的基本知識結構。 硬件——>操作系統OS——>l

linuxmount

tex 我們 fuse exe rem nosuid nag 格式 proc Linux中的根目錄以外的文件要想被訪問,需要將其“關聯”到根目錄下的某個目錄來實現,這種關聯操作就是“掛載”,這個目錄就是“掛載點”,解除次關聯關系的過程稱之為“卸載”。這就是linux中的mo

Linux文本處理三劍客awk

awk變量 信息 tro 不同 當前 block 文件中 是否 定義變量   AWK是一個優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一。其名稱得自於它的創始人阿爾佛雷德·艾侯、彼得·溫伯格和布萊恩·柯林漢姓氏的首個字母

Linux 學習

01|03 kernel space 記憶體碎片 GUI:圖形使用者介面 CLI:命令列使用者介面 核心功能: 程序管理 記憶體管理 檔案系統 網路功能 硬體驅動 安全機制 批處理系統 jobs1$$$$$$jobs2

Linux進階:自動化運維ANSIBLE

運維自動化發展歷程 1、本地部署(On-Premiss) 部署硬體+軟體+作業系統+環境+服務 2、基礎設施即服務(Iaas) 相當於只准備硬體 3、平臺即服務(Paas) 相當於只准備服務 4、軟體即服務(SaaS) 直接使用 企業實際應用場景分析 1、Dev開發環境 使用者:程式

Linux使用者

一、使用者存在的意義 Linux系統其實是一個多使用者、多工的分時作業系統,任何一個要使用系統資源的使用者,都必須首先向系統管理員申請一個賬號,然後以這個賬號的身份進入系統。比如:你想長期使用某大學的某某宿舍的某某床,你必須先考上大學,有了“某大學某專業某班級的學生誰誰誰”這個身份,你才能長

Linux驅動開發除錯技術

驅動程式開發的一個重大難點就是不易除錯。本文目的就是介紹驅動開發中常用的幾種直接和間接的除錯手段,它們是:     使用printk     檢視OOP訊息     使用strace     使用核心內建的hacking選項     使用ioctl方法     使用/proc 檔案系統     使用

Linux驅動設計硬體基礎介面與匯流排乙太網介面

2.3.5 乙太網介面    乙太網介面由MAC(乙太網媒體接入控制器)和PHY(物理介面收發器)組成。乙太網MAC由IEEE802.3乙太網標準定義,實現了資料鏈路層。常用的MAC支援10Mbit/s或100Mbit/s兩種速率。千兆位乙太網是快速乙太網的下一代技術,將網速

Linux驅動設計硬體基礎介面與匯流排USB

2.3.4 USB    USB(通用序列匯流排)是Intel、Microsoft等廠商為解決計算機外設種類的日益增加與有限的主機板插槽和埠之間的矛盾於1995年提出的,它具有資料傳輸率高、易擴充套件、支援即插即用和熱插拔的優點。    USB 1.1包含全速和低速兩種模式,

伺服器開發linux網路程式設計---學習章節

前言:    近期學習了伺服器相關的開發,平常主要擼c的程式,所以就下定決心研究了c的伺服器開發,目的也在與鞏固c的基本知識。詳細分享如下,若有錯誤請指正,希望與大家探討,共同學習進步。