Friday, September 30, 2011

SPI Flash應用

http://www.eettaiwan.com/STATIC/PDF/200808/EETOL_2008IIC_Spansion_AN_26.pdf?SOURCES=DOWNLOAD

I2C 串列匯流排

轉: http://chrisbalcom.wordpress.com/2010/02/19/i2c-%E4%B8%B2%E5%88%97%E5%8C%AF%E6%B5%81%E6%8E%92/

當初接這份工作時,剛到公司沒多久,就得用C實作出軟體的SPI介面。說實話,用軟體實做SPI和I2C通訊介面不難,只要照著spec的 timing圖動作,就不會錯了,用硬體來做更是簡單。比較常出問題的地方,反而是硬體周邊設計不良(如I2C pull high電阻阻值不恰當),layout不遵照spec建議,或寫軟體的人未完全遵照spec定義的protocol作動。有時候也會遇到IC本身的硬體 介面有bug(例如PIC16F877A的早期版本,詳細內容可google “PIC16F MSSP errata”),不過和前述的錯誤比起來,IC本身錯誤的出現機率低很多。

有關I2C的詳細介紹請參照 http://en.wikipedia.org/wiki/I²C 
這裡就不多廢話,直接舉例
以寫入I2C的EEPROM(24LC02B)為例,這裡取datasheet 中 figure 7-2 和邏輯分析儀的波形圖做比對:


從EEPROM的datasheet得知,command 0xA0可以為write commmad,0xA1可以為read command,故假設系統需要對memory address 0×10的位置做寫入,可遵循以下步驟:
  1. 檢查bus上是否為idle狀態,Yes則執行步驟2,No則跳出
  2. 啟始固定為傳送start bit
  3. 傳送write command 0xA0,並偵測EEPROM是否回應ACK bit(若無回應,視為傳輸失敗)
  4. 傳輸指定的memory address 0×10,並偵測EEPROM是否回應ACK bit(若無回應,視為傳輸失敗)
  5. 傳送要儲存的memory data(這裡是儲存數值0x1A),並偵測EEPROM是否回應ACK bit(若無回應,視為傳輸失敗)
  6. 結尾固定為傳送stop bit,完成後SDA與SCL皆為high狀態
如此便完成了EEPROM的寫入指令傳輸,待EEPROM將資料寫完(約3~5ms),整個動作才算是結束。

再來是讀取的對照圖,我就不多說讓讀者自己思考看看



如果對於I2C的timing還是不夠瞭解,可以參考Microchip網站的PIC24FJ Reference Manual – Sec24 Inter Integrated Circuit,裡面提供的timing圖有把master和slave的訊號分開來解說,非常淺顯易懂。

Thursday, September 29, 2011

[Flash]NOR FLASH應用-- Jedec V.S CFI

轉: http://tw.myblog.yahoo.com/chimei-015/article?mid=857&next=851&l=f&fid=33 
 
Flash做為一種非易失性存儲器,在原理、技術和結構上,與ROMPROMEPROMEEPROM存儲器有顯著的不同。它是一種可快速擦除可現場編程的快擦寫存儲器。這種特性決定了Flash做為BIOS、在線擦寫、掉電保護數據以及分區保護數據等場合有著廣泛的應用。
Flash存儲器特點
由於其內部結構的特殊性,Flash存儲器最主要的特點在於其內部狀態機(Internal State Machine)及指令序列(Command Sequences)的操作模式,因此Flash需要較復雜的軟件支持。
除了讀取數據(Read Array Data)以外的其它所有操作,如生產商IDManufacture ID)及器件IDDevice ID)識別,分區寫保護(Sector Protection/去寫保護(Sector Unprotection),擦除(chip erase/sector erase),寫數據/校驗,復位等操作都需要通過器件內部的指令寄存器(Command Register)啟動內嵌算法(embeded algorithms)來完成。
BCS / SCS
Intel從早期的8位閃存芯片28F008開始,就為閃存芯片的操作定義了操作規程和一套相應的命令,一般就稱為“ 28F 008” 或者“ 008” 。后來正式命名為閃存操作基本命令集,即BCS,其要點如下:
閃存芯片平時處於隨機讀出狀態,此時的閃存芯片就像普通的ROM芯片,訪問地址決定了具體的存儲單元;
除非芯片處於寫入狀態,往芯片任意一個單元寫都意味著向芯片發命令,因此是對其控制器的訪問,而不是對其存儲單元的訪問;
根據命令代碼的不同,閃存芯片內部的狀態機進入不同的狀態,從而可以進行不同的操作。
BCS中有以下幾條命令:
隨機讀出(Read Array)。向芯片的任意地址寫0xff,使芯片復位進入讀存儲陣列狀態,在此狀態下CPU可以想訪問普通內存那樣從閃存芯片隨機讀出。閃存芯片加電后的初始狀態就是隨機讀出狀態。
讀狀態寄存器(Read Status Register)。 向芯片的任意地址寫0x70,表示要求從芯片讀出其狀態寄存器,此后可以從芯片的任意地址讀出狀態寄存器的內容。
寫入(Program,要求寫入芯片的若干存儲單元。往目標塊起始地址寫0x40,表示要求進入寫模式,或者稱為編程模式。進入寫模式后,就可以對目標塊進行隨機寫入,就像寫靜態RAM一樣。對每個單元只能寫一次(要再次對某單元寫入,需要先對該單元所在的塊進行擦除操作后,才能再進行)。
清除狀態寄存器(Clear Status Register)。向芯片的任意地址寫0x50,表示要求清除狀態寄存器。
單字節或者字寫入。先向需要寫入的單元寫入0x400x10,然后寫入具體數據。
成塊擦除(Block Erase)。向目標塊內任意地址寫0x20(或者0x28),表示要求擦除芯片內一個塊的所有內容。
暫停擦除(Erase Suspends)。向目標塊內任意地址寫0xb0,表示要求暫停擦除操作。需要時,可以通過往目標塊內的任意地址寫0xd0來恢復擦除。
成塊擦除確認,或者繼續擦除。往目標塊內的任意地址寫0xd0,表示確認要求擦除芯片內一個塊的所有內容,或者在暫停擦除后恢復擦除操作。
每當向芯片發出命令時,狀態寄存器的最高位(bit 7)就會變成0,當操作完成后,該bit會被硬件置為1
隨著閃存技術的發展,Intel后來對BCS進行了擴展,稱為SCSScaleable Command Set),即可擴充命令集。其中增加了芯片加鎖(Set/Clear Lock Bit)、緩沖寫入。芯片配置、整片擦除操作等命令功能。
上面BCSSCS描述的操作只適用於Intel的閃存芯片,或者使用Intel BCS/SCS規範的芯片。
Jedec ID
在閃存技術發展的初期,只有Intel一家生產閃存芯片,產品單一。后來慢慢多起來,新投入閃存芯片生產的廠商往往使自己的產品與Intel兼容,所以IntelBCS就成為了事實上的標準。但是,隨著閃存芯片生產廠商的增加,閃存芯片種類和規格也越來越多,一方面導致BCS不夠用了,另一方面就是有的廠商使用了不同於BCS的規程。例如,同樣是讀取芯片ID,由AMD生產的芯片則需要向片上地址0寫入0xAA5。實際上,INTELAMD就是最主要的閃存芯片廠商。在這種情況下,特別是對於通用計算機系統,在對閃存芯片進行操作之前,首先要搞清這是由哪個廠商生產的什麼芯片。為此,就需要有一個中立、受所有閃存芯片廠商支持的手段,使得計算機軟件可以從芯片中讀取這些信息。於是,便有了所謂的“Jedec ID”以及相應當命令:
讀芯片IDRead ID)。往芯片任何地址寫0x90,表示要求從芯片讀出固化在芯片內的身份信息,如由誰生產,什麼型號等等,稱為“Jedec ID”。這些信息並不占用閃存芯片在內存空間的地址。此后,CPU可以從片上地址0開始逐個字節讀出這些信息。
CFI
Jedec ID所提供的信息實在是太少了。因此,公共閃存接口Common Flash Interface,CFI,便應運而生。這是由存儲芯片工業界定義的一種獲取閃存芯片物理會和結構參數的操作規程和標準。
CFI規定,各廠商可以使用自己的操作規程和命令集,但是必須有統一的編號,並且在軟件到查詢下提供這個編號。而且,閃存芯片可以同時支持兩套操作規程和命令集,讓軟件選擇使用。同時,又規定閃存芯片必須提供更多的信息,包括:芯片的電源電壓是多少,擦除/寫入操作是否需要額外的電源,如果需要是多少,芯片的容量有多大,分成幾個擦除塊,各種操作所需時間的典型值和最大值,等等。為此,還定義了一個用來提供詳細信息的標準數據結構,凡是支持CFI的閃存芯片在收到查詢時都應該能夠按照這個數據結構的格式提供信息,即CFI信息塊。此外,還可以與所支持的操作規程和命令集配套提供附加的參數和信息。
CFI 查詢的規程和命令如下:
向芯片地址0x55寫入0x98,然后從片上地址0x10開始讀出數據。如果讀出的內容依次為:“Q”“R”“Y”,則該芯片支持CFI
然后從芯片上連續的地址0x13 0x30讀出CFI信息塊的固定部分。
除了固定部分以外,后面還有一個無符號整數數組,其大小取決於芯片上的存儲區間划分成幾個擦除區間,數組中的每一個無符號整數都描述一個擦除區間。一個擦除區間中可以有若干個大小相同的擦除塊。
如果從地址0x150x16讀出的16位無符號短整數P0,則在片上地址P處還有一個主算法擴充表。這就是與主算法(即芯片中主要的操作規程和命令集)配套的參數和其他信息。
如果從地址0x190x20讀出的16位無符號短整數T0,則在片上地址T處還有一個次算法擴充表。這就是與次算法(即芯片所支持的另外一套操作規程和命令集)配套的參數和其他信息。

NAND Flash (基本概念)

NAND Flash

轉:  http://realchecko.blogspot.com/2006/11/nand-flash.html
轉:  http://www.icmade.com/Sheet/79227.html
轉:  http://esslab.tw/wiki/index.php/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues


NAND Flash 使用類似HD一樣的操作方式來動作,他和MCU 的interface是 8(some use 16) 條 command/Data/Address 控制線(稱為IO),配上CLE/ALE/CE/RE/WE 控制線來辨別目前IO 傳遞的內容。

NAND Flash 內存放資料的方式,也和HD類似,是以塊狀的方式存放,但是和HD不一樣的是,NAND Flash 保有Nor Flash 的特性,只能一塊一塊的erase。

NAND Flash 內的儲存單位有一些名稱:

Block : 最大的單位,也是erase的單位。
Pages: 內部buffer讀取的單位,一個Block有64 個Pages。

一個Page 內含 2k Bytes 的一般data,和額外64 bytes 的輔助資料空間。
雖然有這樣的區分,但是實際上2k和64 bytes之間並沒有區動作,64 byte的功能是讓programmer自行運用的。一般用來存放ECC,或是wearing 資料..
NAND Flash 內部和HD一樣 有一個buffer,buffer大小剛好是一個pages,buffer作為NAND Flash 內部儲存元件與外界溝通的空間,所有 data I/O 動作都要藉由buffer完成:
  • 讀取動作:下command要求buffer將某一pages的內容讀入buffer,MCU再一一將buffer的資料讀出。
  • 寫入動作:先告訴buffer要作write動作,接著輸入1個page的資料,完成後,請buffer將資料寫入(某一)page。
和NOR Flash 一樣,寫入的動作需要先作erase,Erase將所有data bit社為1,program是把bit 清為0。
programming guid 有說明:也可以不做erase 動作,只要你知道你要寫入的區域都是1111..也就是未曾使用過的區域。
同樣的,寫入資料時,"1"應視為"don't change",也就是不改變該bit內容的意思。
MCU Interface Protocol

如前所述,靠著CLE/ALE/RE/WE 來決定IOx8 的內容
  • CLE : Command Latch Enable - 目前IOx8的內容是command
  • ALE:Address Latch Enable - 目前IOx8的內容是Address
  • RE : Read Enable - 目前IOx8 作read 動作
  • WE: Write Enable - 目前IOx8 作write動作
RE/WE除了指示IOx8 的"方向"外,同時作 latch 的signal。
Protocol 區分為以下幾段:
  1. Command : 送出Command Code,表示目前的操作
  2. Address : 該Command 操作的 Address
  3. Data : 資料
  4. Command : 第二個command,通常代表command確認,結束。
不是所有的動作都需要有這四段,有些動作不需要Address,有些不需要Data。

Address

Address 的指定方式和內部構造一樣,分為 Block Index (address), Pages Index (address) 和 Byte Address。 分別指定:第幾個Block,該Block中的第幾個Pages,和該Page中的第幾個Byte。
由於IO只有8條,所以address要分成多次輸入:
  1. Byte Address 0-7
  2. Byte Address 8-11
  3. Page Address 0-5 + Block Address 0 -1
  4. Block Address 2-9
  5. Block Address 10
這5個Address不是每一個command都需要,有些需要1, 2,有些需要4,5,有些command不需要Address資料。

以下針對各動作的protocol說明

Read
  1. 送出Command 00h
  2. 送出要讀取的Address ,如:的3個block,的100個pages的第34 bytes開始。-
  3. 送出Command 30h - Read Confirm
  4. 等NAND buffer將該page的資料讀進buffer中
  5. 每一個RE依序輸出一個byte的資料,從Address指定的位置開始,可以讀任意個,但是只能在同一個page中,當讀取超出該page時,會讀到錯的資料。
Random Read

在剛剛的Read 過程中,RE輸出data的階段,如果想跳到同一個pages的其他位置去讀取,可以在用 Command 05 插入RE的讀取動作中,修改讀取的address:
  1. RE.....
  2. Command 05h
  3. Address - 2 cycles就可以,因為限定在同一個page中,所以不用送pages 和block address。
  4. Command E0h - Confirm
  5. RE...從新的位置開始讀取...
Write (Program)

和Read 類似,對整個page動作:
  1. Command 80h
  2. Address - 5 cycles, 指定從block-pages-start address開始..
  3. Data - 開始輸入要write的資料, WE clock..依次輸入...
  4. Command 10h - Confirm
Command 80h 會將NAND Flash 內部的buffer 清為FFh,接下來的Address,代表你要對從哪一個Block的哪一個page的哪一個位址開始"修改資料",然後data cycle 就開始從那個位置開始將buffer的data update成你輸入的data。
Random input

和Random Read一樣,在輸入資料的階段 WR...,可以用Command 85 + 2 Address cycle 改變要輸入的位址,接著繼續輸入資料。


以上可以看出 NAND Flash 內部buffer有一個pointer,代表buffer R/W的位址,每次R/W後會自動+1, 85h command就是更動該pointer資料的command。

Monday, September 5, 2011

How to Read/Write in Kernel Module

  模块中对文件的读写操作 (2009-05-19 11:21)
轉:http://blog.csdn.net/billowszpt/article/details/6661333

 2.6.20以後,,,要使用filp_open()的方式~而之前版本的話,則使用sys_open()
最近在忙实验室项目,有阵子没写blog了。这期间遇到个问题,就是需要在内核模块中对文件进行读写操作。由于设备在linux中也是以文件表示的,所以 操作应该都一样。平时网络部分的东西碰的多些,这块一开始还真不知道怎么写,因为肯定和在用户空间下是不同的。google过后,得到以下答案。一般可以 用两种方法:第一种是用系统调用。第二种方法是filp->open()等函数。下面分别来说下这两种方法。

1,利用系统调用:
sys_open,sys_write,sys_read等。
其实分析过sys_open可以知道,最后调用的也是filp->open。
sys_open ==> do_sys_open ==> filp->open
在linuxsir上的一个帖子,上面一个版主说:sys_open和进程紧密相关,往往不在内核中使用。
而其实sys_open最后也是调用了filp->open。所以就后者进行详细的介绍。

2,filp->open等函数。
在模块中,用户空间的open,read,write,llseek等函数都是不可以使用的。应该使用其在内核中对应的函数。可以使用filp->open配合struct file里的read/write来进行对文件的读写操作。
自己写了一个程序:
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>

#include<linux/types.h>

#include<linux/fs.h>
#include<linux/string.h>
#include<asm-x86/uaccess.h> /* get_fs(),set_fs(),get_ds() */

#define FILE_DIR "/home/hmily/workstation/program/test.txt"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("hmily8023");

char *buff = "gaozhenbo";
char tmp[100];

static struct file *filp = NULL;

static int __init wr_test_init(void)
{
    mm_segment_t old_fs;
    
    filp = filp_open(FILE_DIR, O_RDWR | O_CREAT, 0644);
    
    //    if(!filp)

    if(IS_ERR(filp))
        printk("open error...\n");
    
    old_fs = get_fs();
    set_fs(get_ds());
    
    filp->f_op->write(filp, buff, strlen(buff), &filp->f_pos);

    ssize_t ret;
    
    filp->f_op->llseek(filp,0,0);
    ret = filp->f_op->read(filp, tmp, strlen(buff), &filp->f_pos);
    
    set_fs(old_fs);
    
    if(ret > 0)
        printk("%s\n",tmp);
    else if(ret == 0)
        printk("read nothing.............\n");
    else 
        {
            printk("read error\n");
            return -1;
        }

    return 0;
}

static void __exit wr_test_exit(void)
{
    if(filp)
        filp_close(filp,NULL);
}

module_init(wr_test_init);
module_exit(wr_test_exit);

Kernel Symbols: What's Available to Your Module, What Isn't.

Kernel Symbols: What's Available to Your Module, What Isn't

This week, let's talk about what, out of all the symbols in kernel space, you're allowed to access, and what you're not. And while we're at it, what symbols you can make available to other loadable modules from your code.
(The archive of all previous "Kernel Newbie Corner" articles can be found here.)
This is ongoing content from the Linux Foundation training program. If you want more content please, consider signing up for one of these classes.

Back to Basics

Let's once again consider a fairly basic loadable module, which prints to /var/log/messages that it's been loaded, and also prints the current value of the kernel space symbol jiffies, which is the number of kernel clock ticks in HZ since the kernel was booted (sort of). Here's the sample module source file m1.c:
#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>   [for "jiffies" variable]

  static int __init hi(void)
 {
     printk(KERN_INFO "module m1 being loaded.\n");
     printk("Current jiffies: %lu.\n", jiffies);
     return 0;
 }

   static void __exit bye(void)
 {
     printk(KERN_INFO "module m1 being unloaded.\n");
 }

  module_init(hi);
  module_exit(bye);

  MODULE_AUTHOR("Robert P. J. Day");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Symbols, exported and otherwise.");

Run That Baby!

Given that the tick rate for my current kernel is 1000, if I load and unload that module once per second, I should expect to see the value of jiffies increasing by about 1000 each time. So let's let the shell keep track of that by running the following at the command line until we tell it to stop:
# while true ; do
 > insmod m1.ko
 > rmmod m1
 > sleep 1
 > done
at which point we see in /var/log/messages:
...
 Jul 29 11:04:17 localhost kernel: module m1 being loaded.
 Jul 29 11:04:17 localhost kernel: Current jiffies: 4297191451.
 Jul 29 11:04:17 localhost kernel: module m1 being unloaded.
 Jul 29 11:04:18 localhost kernel: module m1 being loaded.
 Jul 29 11:04:18 localhost kernel: Current jiffies: 4297192470.
 Jul 29 11:04:18 localhost kernel: module m1 being unloaded.
 Jul 29 11:04:19 localhost kernel: module m1 being loaded.
 Jul 29 11:04:19 localhost kernel: Current jiffies: 4297193488.
 Jul 29 11:04:19 localhost kernel: module m1 being unloaded.
 Jul 29 11:04:20 localhost kernel: module m1 being loaded.
 Jul 29 11:04:20 localhost kernel: Current jiffies: 4297194508.
 Jul 29 11:04:20 localhost kernel: module m1 being unloaded.
 ...
That looks good--the value of jiffies seems to be increasing about 1000 each time. Which brings us to our main point.

What Exactly Can Your Module Access After It's Loaded?

As you can see, your module needed to be able to access a couple different symbols from kernel space: the routine printk(), and the variable jiffies. And why were those symbols available to your module? Because they were "exported".
You can think of kernel symbols (either functions or data objects) as visible at three different levels in the kernel source code:
  • "static", and therefore visible only within their own source file (just like standard user space programming),
  • "external", and therefore potentially visible to any other code built into the kernel itself, and
  • "exported", and therefore visible and available to any loadable module.
Exporting symbols for modules is typically done with one of:
  • EXPORT_SYMBOL(), which exports to any loadable module, or
  • EXPORT_SYMBOL_GPL(), which exports only to GPL-licensed modules.
Not surprisingly, then, since we could access those two symbols, we expect to find them exported somewhere in the source tree and, sure enough:
kernel/printk.c:EXPORT_SYMBOL(printk);
 kernel/time.c:EXPORT_SYMBOL(jiffies);
Let's let kernel wizard Robert Love summarize this in his book, Linux Kernel Development (2nd ed.), p. 288:
When modules are loaded, they are dynamically linked into the kernel. As with userspace, dynamically linked binaries can call only into external functions that are explicitly exported for use. In the kernel, this is handled via special directives EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL().
Functions that are exported are available for use by modules. Functions that are not exported cannot be invoked by modules. The linking and invoking rules are much more stringent for modules than code in the core kernel image. Core code can call any non-static interface in the kernel because all core source files are linked into a single base image. Exported symbols, of course, must be non-static, too.
The set of kernel symbols that are exported are known as the exported kernel interfaces or even (gasp) the kernel API.
But wait--there's more.

Exporting Symbols of Your Own

Not surprisingly, you can use the above to export symbols from your loadable modules to make them available to other modules. Consider module source file m2.c:
#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>

  static int rday_1 = 1;
  int rday_2 = 2;
  int rday_3 = 3;

  EXPORT_SYMBOL(rday_3);

   static int __init hi(void)
 {
     printk(KERN_INFO "module m2 being loaded.\n");
     return 0;
 }

  static void __exit bye(void)
 {
     printk(KERN_INFO "module m2 being unloaded.\n");
 }

  module_init(hi);
  module_exit(bye);

  MODULE_AUTHOR("Robert P. J. Day");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Let's try some exporting.");
As you can see, there are three integer variables defined, only one of which should be visible to other modules after this one is loaded. To confirm that, once you compile that module, but before you load it, you can examine its symbol table thusly:
$ nm m2.ko
 0000000000000000 r __kstrtab_rday_3
 0000000000000000 r __ksymtab_rday_3
 0000000000000040 r __mod_author25
 0000000000000000 r __mod_description27
 0000000000000028 r __mod_license26
 0000000000000060 r __mod_srcversion23
 00000000000000a0 r __mod_vermagic5
 0000000000000088 r __module_depends
 0000000000000000 D __this_module
 0000000000000000 t bye
 0000000000000000 T cleanup_module
 0000000000000000 t hi
 0000000000000000 T init_module
                  U mcount
                  U printk
 0000000000000000 D rday_2
 0000000000000004 D rday_3
If you're familiar with the nm utility, you'll see that the variable rday_1 doesn't show up in the symbol table at all (having been declared as "static"), while both rday_2 and rday_3 are flagged as global data objects but, additionally, you can see that rday_3 has an entry in the module string table and symbol table, meaning that when this module is loaded, thatsymbol will be made available to other loadable modules. And it's easy enough to verify that by loading that module, then checking the contents of the dynamic kernel symbol table available in the file /proc/kallsyms:
$ grep rday /proc/kallsyms
 ffffffffa00f6080 r __ksymtab_rday_3     [m2]
 ffffffffa00f6090 r __kstrtab_rday_3     [m2]
 ffffffffa00f6570 D rday_3       [m2]
 ffffffffa00f656c d rday_2       [m2]
What the above excerpt from /proc/kallsyms represents should be obvious:
  • The variable rday_1 shouldn't show up anywhere in kernel space since it was declared as static.
  • The variable rday_2 exists in kernel space, but is considered "local" in that context.
  • The variable rday_3 exists in kernel space, and is considered "global" and available to other modules since it was exported.
In other words, you should now be able to write another module that tries to read rday_3--obviously an exercise for the reader.

A Couple More Details Regarding Exporting

Besides the standard export macros defined in the kernel header file linux/module.h, there are a couple more specialized ones:
  • EXPORT_UNUSED_SYMBOL() and EXPORT_UNUSED_SYMBOL_GPL(), which are used to identify symbols that arecurrently being exported but which are destined for unexporting some day, so you should try to avoid using them. The phrase "UNUSED" in this context is unfortunate, as it would have made much more sense to have used the phrase "DEPRECATED".
  • EXPORT_SYMBOL_GPL_FUTURE(), which denotes a symbol that is currently available to all modules, but is planned for restriction to GPL-only modules in the future
It's left as an exercise for the reader to see if these macros are currently being used anywhere in the current kernel source tree, and perhaps to figure out why.
Robert P. J. Day is a Linux consultant and long-time corporate trainer who lives in Waterloo, Ontario. He provides assistance to the Linux Foundation's Training Program. Robert can be reached at rpjday@crashcourse.ca, and can be followed at http://twitter.com/rpjday