NFC驅動調試

来源:https://www.cnblogs.com/linhaostudy/archive/2018/04/04/8716333.html
-Advertisement-
Play Games

1.NFC基本概念: NFC 又稱為近場通信,是一種新興技術,可以在彼此靠近的情況下進行數據交換,是由非接觸式射頻識別(RFID)及互連互通技術整合演變而來,通過單一晶元集成感應式讀卡器; NFC有效通訊距離一般不超過10釐米,其傳輸速度有106 Kbit/秒、212 Kbit/秒或者424 Kbi ...


1.NFC基本概念:

NFC 又稱為近場通信,是一種新興技術,可以在彼此靠近的情況下進行數據交換,是由非接觸式射頻識別(RFID)及互連互通技術整合演變而來,通過單一晶元集成感應式讀卡器;
NFC有效通訊距離一般不超過10釐米,其傳輸速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三種。

2.NFC的工作模式:

  • 讀卡器模式(Reader / Writer Mode)
  • 模擬卡模式(Card Emulation Mode)
  • 點對點模式(P2P Mode)

讀卡器模式:
讀卡器模式本質上就是通過NFC設備(比如支持NFC的Android手機)從帶有NFC晶元的標簽,貼紙,明信片,報紙,名片等媒介讀取信息,或者將數據寫到這些媒介中。貼有NFC貼紙的產品在市面上很常見。

模擬卡模式:
模擬卡模式就是將支持NFC的手機或者其他電子設備當成借記卡、信用卡、公交卡、門禁卡等IC卡使用。基本原理就是將相應IC卡中的信息(支付憑證)封裝成數據包存儲在支持NFC的手機中。在使用時,還需要一個NFC射頻器(相當於刷傳統IC卡使用的刷卡器)。將手機靠近NFC射頻器,手機就會接收到NFC射頻器發過來的信號,在通過一些列驗證後,將IC卡的相應信息傳入NFC射頻器,最後這些IC卡數據會傳入NFC射頻器連接的電腦,併進行相應的處理。

點對點(P2P)模式:
該模式與藍牙、紅外線差不多,可以用於不同NFC設備之間進行數據交換,只是NFC的點對點模式有效距離更短(不能超過10釐米),而且傳輸建立速度要比紅外線和藍牙技術快很多。
點對點模式的典型應用是兩部支持NFC的手機或平板電腦實現數據的點對點傳輸,例如,下載音樂、交換圖片、同步設備地址薄。因此,通過NFC,多個設備如數字相機,PDA,電腦,手機之間,都可以快速鏈接並交換資料或者服務。

3.NFC與其他模塊的比較

對比項 NFC 藍牙 紅外
網路類型 點對點 單點對多點 點對點
使用距離 ≤0.1m ≤10m ≤1m
傳輸速度 106、212、424、868、721、115Kbps 2.1 Mbps ~1.0 Mbps
建立時間 < 0.1s 6s 0.5s
安全性 主動-主動/被動 主動-主動 主動-主動
成本

4.NFC的物理組成

讀寫器(Reader/Interrogator)、標簽(Tag/Transponder)、天線(Antenna)
1.讀寫器將要發送的信息,編碼並載入到高頻載波信號上再經天線向外發送。
2.進入讀寫器工作區域的電子標簽接收到信號,其卡內晶元的有關電路就會進行倍壓整流、調製、解密,然後對命令請求、密碼、許可權進行判斷。

5.NFC手機的幾種實現方式

根據SE(安全模塊的Security Element為用用戶賬號,身份認證等敏感信息提供安全載體,為加強手機支付的安全性)所在位置不同;

5.1 NFC-SD卡方案

5.2 NFC-SWP模式

5.3 NFC的全終端模式

6.NFC kernel分析

6.1 從module_init函數開始:

/*
 * module load/unload record keeping
 */
static int __init nqx_dev_init(void)
{
    return i2c_add_driver(&nqx);
}
module_init(nqx_dev_init);

static void __exit nqx_dev_exit(void)
{
    unregister_reboot_notifier(&nfcc_notifier);
    i2c_del_driver(&nqx);
}
module_exit(nqx_dev_exit);

通過i2c_add_driver(&nqx)和i2c_del_driver(&nqx)註冊相應的i2c設備驅動,通過i2c傳輸相應數據。

static struct i2c_driver nqx = {
    .id_table = nqx_id,
    .probe = nqx_probe,
    .remove = nqx_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "nq-nci",
        .of_match_table = msm_match_table,
        .pm = &nfc_pm_ops,
    },
};

通過of_match_table匹配上:

static struct of_device_id msm_match_table[] = {
    {.compatible = "qcom,nq-nci"},
    {}
};

6.2 probe函數

probe函數如下:

static int nqx_probe(struct i2c_client *client,
            const struct i2c_device_id *id)
{
    int r = 0;
    int irqn = 0;
    struct nqx_platform_data *platform_data;
    struct nqx_dev *nqx_dev;

    dev_dbg(&client->dev, "%s: enter\n", __func__);
    if (client->dev.of_node) {
        platform_data = devm_kzalloc(&client->dev,
            sizeof(struct nqx_platform_data), GFP_KERNEL);
        if (!platform_data) {
            r = -ENOMEM;
            goto err_platform_data;
        }
        //解析設備樹
        r = nfc_parse_dt(&client->dev, platform_data);
        if (r)
            goto err_free_data;
    } else
        platform_data = client->dev.platform_data;

    dev_dbg(&client->dev,
        "%s, inside nfc-nci flags = %x\n",
        __func__, client->flags);

    if (platform_data == NULL) {
        dev_err(&client->dev, "%s: failed\n", __func__);
        r = -ENODEV;
        goto err_platform_data;
    }
    //判斷適配器能力,這裡檢測適配器具有I2C功能
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        dev_err(&client->dev, "%s: need I2C_FUNC_I2C\n", __func__);
        r = -ENODEV;
        goto err_free_data;
    }
    //分配記憶體空間
    nqx_dev = kzalloc(sizeof(*nqx_dev), GFP_KERNEL);
    if (nqx_dev == NULL) {
        r = -ENOMEM;
        goto err_free_data;
    }
    nqx_dev->client = client;
    nqx_dev->kbuflen = MAX_BUFFER_SIZE;
    nqx_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL);
    if (!nqx_dev->kbuf) {
        dev_err(&client->dev,
            "failed to allocate memory for nqx_dev->kbuf\n");
        r = -ENOMEM;
        goto err_free_dev;
    }

    if (gpio_is_valid(platform_data->en_gpio)) {
        r = gpio_request(platform_data->en_gpio, "nfc_reset_gpio");
        if (r) {
            dev_err(&client->dev,
            "%s: unable to request nfc reset gpio [%d]\n",
                __func__,
                platform_data->en_gpio);
            goto err_mem;
        }
        r = gpio_direction_output(platform_data->en_gpio, 0);
        if (r) {
            dev_err(&client->dev,
                "%s: unable to set direction for nfc reset gpio [%d]\n",
                    __func__,
                    platform_data->en_gpio);
            goto err_en_gpio;
        }
    } else {
        dev_err(&client->dev,
        "%s: nfc reset gpio not provided\n", __func__);
        goto err_mem;
    }

    if (gpio_is_valid(platform_data->irq_gpio)) {
        r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
        if (r) {
            dev_err(&client->dev, "%s: unable to request nfc irq gpio [%d]\n",
                __func__, platform_data->irq_gpio);
            goto err_en_gpio;
        }
        r = gpio_direction_input(platform_data->irq_gpio);
        if (r) {
            dev_err(&client->dev,
            "%s: unable to set direction for nfc irq gpio [%d]\n",
                __func__,
                platform_data->irq_gpio);
            goto err_irq_gpio;
        }
        irqn = gpio_to_irq(platform_data->irq_gpio);
        if (irqn < 0) {
            r = irqn;
            goto err_irq_gpio;
        }
        client->irq = irqn;
    } else {
        dev_err(&client->dev, "%s: irq gpio not provided\n", __func__);
        goto err_en_gpio;
    }
    if (gpio_is_valid(platform_data->firm_gpio)) {
        r = gpio_request(platform_data->firm_gpio,
            "nfc_firm_gpio");
        if (r) {
            dev_err(&client->dev,
                "%s: unable to request nfc firmware gpio [%d]\n",
                __func__, platform_data->firm_gpio);
            goto err_irq_gpio;
        }
        r = gpio_direction_output(platform_data->firm_gpio, 0);
        if (r) {
            dev_err(&client->dev,
            "%s: cannot set direction for nfc firmware gpio [%d]\n",
            __func__, platform_data->firm_gpio);
            goto err_firm_gpio;
        }
    } else {
        dev_err(&client->dev,
            "%s: firm gpio not provided\n", __func__);
        goto err_irq_gpio;
    }
    if (gpio_is_valid(platform_data->ese_gpio)) {
        //申請中斷
        r = gpio_request(platform_data->ese_gpio,
                "nfc-ese_pwr");
        if (r) {
            nqx_dev->ese_gpio = -EINVAL;
            dev_err(&client->dev,
                "%s: unable to request nfc ese gpio [%d]\n",
                    __func__, platform_data->ese_gpio);
            /* ese gpio optional so we should continue */
        } else {
            nqx_dev->ese_gpio = platform_data->ese_gpio;
            r = gpio_direction_output(platform_data->ese_gpio, 0);
            if (r) {
                /* free ese gpio and set invalid
                   to avoid further use
                */
                gpio_free(platform_data->ese_gpio);
                nqx_dev->ese_gpio = -EINVAL;
                dev_err(&client->dev,
                "%s: cannot set direction for nfc ese gpio [%d]\n",
                __func__, platform_data->ese_gpio);
                /* ese gpio optional so we should continue */
            }
        }
    } else {
        nqx_dev->ese_gpio = -EINVAL;
        dev_err(&client->dev,
            "%s: ese gpio not provided\n", __func__);
        /* ese gpio optional so we should continue */
    }
    if (gpio_is_valid(platform_data->clkreq_gpio)) {
        r = gpio_request(platform_data->clkreq_gpio,
            "nfc_clkreq_gpio");
        if (r) {
            dev_err(&client->dev,
                "%s: unable to request nfc clkreq gpio [%d]\n",
                __func__, platform_data->clkreq_gpio);
            goto err_ese_gpio;
        }
        r = gpio_direction_input(platform_data->clkreq_gpio);
        if (r) {
            dev_err(&client->dev,
            "%s: cannot set direction for nfc clkreq gpio [%d]\n",
            __func__, platform_data->clkreq_gpio);
            goto err_clkreq_gpio;
        }
    } else {
        dev_err(&client->dev,
            "%s: clkreq gpio not provided\n", __func__);
        goto err_ese_gpio;
    }

    nqx_dev->en_gpio = platform_data->en_gpio;
    nqx_dev->irq_gpio = platform_data->irq_gpio;
    nqx_dev->firm_gpio  = platform_data->firm_gpio;
    nqx_dev->clkreq_gpio = platform_data->clkreq_gpio;
    nqx_dev->pdata = platform_data;

    /* init mutex and queues */
    init_waitqueue_head(&nqx_dev->read_wq);
    mutex_init(&nqx_dev->read_mutex);
    spin_lock_init(&nqx_dev->irq_enabled_lock);

    nqx_dev->nqx_device.minor = MISC_DYNAMIC_MINOR;
    nqx_dev->nqx_device.name = "nq-nci";
     //在此處與 nfc_dev_fops 操作列表進行連接
    nqx_dev->nqx_device.fops = &nfc_dev_fops;
    //註冊混雜設備驅動
    r = misc_register(&nqx_dev->nqx_device);
    if (r) {
        dev_err(&client->dev, "%s: misc_register failed\n", __func__);
        goto err_misc_register;
    }

    /* NFC_INT IRQ */
    nqx_dev->irq_enabled = true;
    r = request_irq(client->irq, nqx_dev_irq_handler,
              IRQF_TRIGGER_HIGH, client->name, nqx_dev);
    if (r) {
        dev_err(&client->dev, "%s: request_irq failed\n", __func__);
        goto err_request_irq_failed;
    }
    nqx_disable_irq(nqx_dev);

    /*
     * To be efficient we need to test whether nfcc hardware is physically
     * present before attempting further hardware initialisation.
     *
     */
    r = nfcc_hw_check(client , platform_data->en_gpio);
    if (r) {
        /* make sure NFCC is not enabled */
        gpio_set_value(platform_data->en_gpio, 0);
        /* We don't think there is hardware switch NFC OFF */
        goto err_request_hw_check_failed;
    }

    /* Register reboot notifier here */
    r = register_reboot_notifier(&nfcc_notifier);
    if (r) {
        dev_err(&client->dev,
            "%s: cannot register reboot notifier(err = %d)\n",
            __func__, r);
        /* nfcc_hw_check function not doing memory
           allocation so using same goto target here
        */
        goto err_request_hw_check_failed;
    }

#ifdef NFC_KERNEL_BU
    r = nqx_clock_select(nqx_dev);
    if (r < 0) {
        dev_err(&client->dev,
            "%s: nqx_clock_select failed\n", __func__);
        goto err_clock_en_failed;
    }
    gpio_set_value(platform_data->en_gpio, 1);
#endif
    device_init_wakeup(&client->dev, true);
    device_set_wakeup_capable(&client->dev, true);
    i2c_set_clientdata(client, nqx_dev);
    nqx_dev->irq_wake_up = false;

    dev_err(&client->dev,
    "%s: probing NFCC NQxxx exited successfully\n",
         __func__);
    return 0;

#ifdef NFC_KERNEL_BU
err_clock_en_failed:
    unregister_reboot_notifier(&nfcc_notifier);
#endif
err_request_hw_check_failed:
    free_irq(client->irq, nqx_dev);
err_request_irq_failed:
    misc_deregister(&nqx_dev->nqx_device);
err_misc_register:
    mutex_destroy(&nqx_dev->read_mutex);
err_clkreq_gpio:
    gpio_free(platform_data->clkreq_gpio);
err_ese_gpio:
    /* optional gpio, not sure was configured in probe */
    if (nqx_dev->ese_gpio > 0)
        gpio_free(platform_data->ese_gpio);
err_firm_gpio:
    gpio_free(platform_data->firm_gpio);
err_irq_gpio:
    gpio_free(platform_data->irq_gpio);
err_en_gpio:
    gpio_free(platform_data->en_gpio);
err_mem:
    kfree(nqx_dev->kbuf);
err_free_dev:
    kfree(nqx_dev);
err_free_data:
    if (client->dev.of_node)
        devm_kfree(&client->dev, platform_data);
err_platform_data:
    dev_err(&client->dev,
    "%s: probing nqxx failed, check hardware\n",
         __func__);
    return r;
}

6.3 file_operations

fops 中包含了 ioctl 的操作方式,cmd 為 1 關閉 nfc , 2 為開啟ese功能,3 為獲取ese功能。

static const struct file_operations nfc_dev_fops = {
    .owner = THIS_MODULE,
    .llseek = no_llseek,
    .read  = nfc_read,
    .write = nfc_write,
    .open = nfc_open,
    .unlocked_ioctl = nfc_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = nfc_compat_ioctl
#endif
};
static long nfc_ioctl(struct file *pfile, unsigned int cmd,
            unsigned long arg)
{
    int r = 0;

    switch (cmd) {
    case NFC_SET_PWR:
        r = nfc_ioctl_power_states(pfile, arg);
        break;
    case ESE_SET_PWR:
        r = nqx_ese_pwr(pfile->private_data, arg);
        break;
    case ESE_GET_PWR:
        r = nqx_ese_pwr(pfile->private_data, 3);
        break;
    case SET_RX_BLOCK:
        break;
    case SET_EMULATOR_TEST_POINT:
        break;
    case NFCC_INITIAL_CORE_RESET_NTF:
        r = nfc_ioctl_core_reset_ntf(pfile);
        break;
    default:
        r = -ENOIOCTLCMD;
    }
    return r;
}

因為NQ210的eSE功能被閹割,所以,只需要調通I2C即可;上層只需調用相應的ioctl功能;高通的中NQ220有eSE功能就是在trustzone的QSEE環境下運行的;如果有調試到,再分析分析;
第一次使用markdown功能寫博客,挺好用的;


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我們都知道 Ubuntu 是一款 Linux 系統,是開源的系統,隨時都在更新,所以人們都說 Linux 系統要比 Windows 系統安全。那麼為了我們的電腦安全,我們如何利用 Ubuntu 命令來進行更新系統呢? 一、運行sudo apt-get update命令 回車之後提示輸入管理員密碼 二 ...
  • |版權聲明:本文為博主原創文章,未經博主允許不得轉載。 AN4069應用筆記中提到MMA8451的三個軸重力校準有兩種方法, 第一種方法是簡易校準,將貼有MMA8451的設備整體,Z軸正面朝上放在校準平面上。此時X軸,Y軸,Z軸的重力加速度理論值分別為0,0,1g。 第二種方法是精確校準,校準MMA ...
  • 以前裝Nginx都是直接百度一下,裝完了事,結果用的時候又有很多不明白的地方,所有今天打算把安裝過程記錄一下。 首先是安裝環境的準備,我的系統環境是Centos 7,用的是虛擬機。因為打算自己編譯安裝,所以先看一下編譯安裝所需要的工具是否都安裝好了。 編譯安裝Nginx需要GCC,PCRE,zlib ...
  • 依賴環境,沒有安裝的需要安裝一下 編寫啟動腳本 腳本內容如下 # !/bin/bash # chkconfig: - 30 21 # description: http service. # Source Function Library ./etc/init.d/functions # Nginx ...
  • 這是我在學習Linux0.11內核時做的筆記,以作為以後複習使用。本文解釋為什麼fork()函數會調用一次,返回兩次。以及為什麼返回給父進程的是子進程的pid,而返回給子進程的是0。 大致過程 用戶程式調用fork()函數(標準庫)->中斷處理程式(system_call.s)->sys_fork( ...
  • 歡迎來到CSRF漏洞章節,在此,請允許作為#靈魂畫師!!#的我圖文並茂的為大家簡單介紹一下CSRF漏洞: CSRF跨站點請求偽造(Cross—Site Request Forgery) 你可以這樣來理解: 攻擊者盜用了你的身份,以你的名義發送惡意請求,對伺服器來說這個請求是完全合法的, 但是卻完成了 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是 ARM Cortex M學習資源 。 概念科普類 資源 版本 短評 Cortex M ARM官方主頁 / 最權威的Cortex M資源來源,最新的Cortex M技術應該從這裡去找 ARM_Cortex M維基百科 / 對於技術名詞的 ...
  • Linux管理磁碟 查看當前磁碟使用情況: (查看所有的硬碟) 伺服器添加硬碟:在系統設置添加 分區: (sdb, sdc, sde) 指令: (幫助信息), (新加分區) 第二步: 指令 第三步:寫入磁碟 使用:掛載: 掛載到/data目錄下,掛載成功如下 可以掛載到多個設備 Vi命令 所有的指令 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...