1. 程式人生 > >字元裝置驅動程式

字元裝置驅動程式

#include <linux/init.h>           // 用於標記函式的巨集,如_init、__exit

#include <linux/module.h>         // 將核心模組載入到核心中的核心標頭檔案

#include <linux/device.h>         // 支援核心驅動模型的標頭檔案

#include <linux/kernel.h>         // 包含核心中的型別、巨集和函式

#include <linux/fs.h>             // 支援Linux檔案系統的標頭檔案

#include <asm/uaccess.h>          // 複製到使用者使用者空間函式需要的標頭檔案

#include <linux/gpio.h>           // GPIO

#define  DEVICE_NAME "matrix"     ///< 使用此值,裝置將會展示在/dev/matrix

#define  CLASS_NAME  "mat"        ///< 裝置類名,這是一個字元裝置驅動

MODULE_LICENSE("GPL");            ///< 許可型別,這回影響到可用功能

MODULE_VERSION("0.1");            ///< 告知使用者的版本號

static int    majorNumber;                  ///< 儲存主裝置號,這裡自動確定

static char   message[256] = {0};           ///< 用於儲存從使用者空間傳輸過來字串的記憶體

static short  size_of_message;              ///< 用於記錄儲存的字串長度

static int    numberOpens = 0;              ///< 用於儲存裝置開啟次數的計數器

static struct class*  matClass  = NULL; ///< 裝置驅動類結構體指標

static struct device* matDevice = NULL; ///< 裝置驅動裝置結構體指標

// 字元裝置操作的函式原型,必須在結構體定義前定義

static int     dev_open(struct inode *, struct file *);

static int     dev_release(struct inode *, struct file *);

static ssize_t dev_read(struct file *, char *, size_t, loff_t *);

static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);

/** @brief 裝置在核心中被表示為檔案結構。 /linux/fs.h中定義的file_operations結構體,

 * 它使用C99語法的結構體,列舉了檔案操作關聯的回撥函式。

 * 字元裝置通常需要實現open、read、write和release函式。

 */

static struct file_operations fops =

{

   .open = dev_open,

   .read = dev_read,

   .write = dev_write,

   .release = dev_release,

};

/** @brief 可載入核心模組初始化函式

 *  static關鍵字限制該函式的可見性在該C檔案之內。 The __init

 *  __init巨集對於內建驅動(非可載入核心模組)來說,只在初始化時呼叫,在此之後,該函式將被廢棄,記憶體將被回收。

 *  @return 如果成功返回0

 */

static int __init matrix_init(void){

   printk(KERN_INFO "Initializing matrix.\n");

   // 嘗試為這個裝置動態生成一個主裝置號,雖然麻煩一點,但這是值得的

   majorNumber = register_chrdev(0, DEVICE_NAME, &fops);

   if (majorNumber<0){

      printk(KERN_ALERT "Failed to register a major number.\n");

      return majorNumber;

   }

   // printk(KERN_INFO "EBBChar: registered correctly with major number %d\n", majorNumber);

   // 註冊裝置類

   matClass = class_create(THIS_MODULE, CLASS_NAME);

   if (IS_ERR(matClass)){                // 如果有錯誤,清理環境

      unregister_chrdev(majorNumber, DEVICE_NAME);

      printk(KERN_ALERT "Failed to register device class.\n");

      return PTR_ERR(matClass);          // 對於指標型別返回錯誤訊息正確的方式

   }

   // printk(KERN_INFO "EBBChar: device class registered correctly\n");

   // 註冊裝置驅動

   matDevice = device_create(matClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);

   if (IS_ERR(matDevice)){               // 如果有錯誤,清理環境

      class_destroy(matClass);           // 重複的程式碼,可選方式是使用goto語句

      unregister_chrdev(majorNumber, DEVICE_NAME);

      printk(KERN_ALERT "Failed to create the device.\n");

      return PTR_ERR(matDevice);

   }

   // printk(KERN_INFO "EBBChar: device class created correctly\n"); // 搞定,裝置已經初始化

   return 0;

}

/** @brief 可載入核心模組清理函式

 *  和初始化函式類似,該函式是靜態的。__exit巨集標識如果這個程式碼是使用在內建驅動(非可載入核心模組)中,該函式不需要。

 */

static void __exit matrix_exit(void){

   device_destroy(matClass, MKDEV(majorNumber, 0));     // 移除裝置

   class_unregister(matClass);                          // 登出裝置類

   class_destroy(matClass);                             // 移除裝置類

   unregister_chrdev(majorNumber, DEVICE_NAME);             // 登出主裝置號

   printk(KERN_INFO "Goodbye!\n");

}

static unsigned PIN_DIN = 23;

static unsigned PIN_CS = 24;

static unsigned PIN_CLK = 25;

static unsigned char disp1[256][8] = {

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x0

{ 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E }, //0x1

{ 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E }, //0x2

{ 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00 }, //0x3

{ 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00 }, //0x4

{ 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C }, //0x5

{ 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C }, //0x6

{ 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00 }, //0x7

{ 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF }, //0x8

{ 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00 }, //0x9

{ 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF }, //0xA

{ 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78 }, //0xB

{ 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18 }, //0xC

{ 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0 }, //0xD

{ 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0 }, //0xE

{ 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99 }, //0xF

{ 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00 }, //0x10

{ 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00 }, //0x11

{ 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18 }, //0x12

{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00 }, //0x13

{ 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00 }, //0x14

{ 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78 }, //0x15

{ 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00 }, //0x16

{ 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF }, //0x17

{ 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00 }, //0x18

{ 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00 }, //0x19

{ 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00 }, //0x1A

{ 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00 }, //0x1B

{ 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00 }, //0x1C

{ 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00 }, //0x1D

{ 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00 }, //0x1E

{ 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00 }, //0x1F

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x20

{ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00 }, //0x21

{ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x22

{ 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00 }, //0x23

{ 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00 }, //0x24

{ 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00 }, //0x25

{ 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00 }, //0x26

{ 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x27

{ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00 }, //0x28

{ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00 }, //0x29

{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00 }, //0x2A

{ 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00 }, //0x2B

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60 }, //0x2C

{ 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00 }, //0x2D

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00 }, //0x2E

{ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00 }, //0x2F

{ 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00 }, //0x30

{ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00 }, //0x31

{ 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00 }, //0x32

{ 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00 }, //0x33

{ 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00 }, //0x34

{ 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00 }, //0x35

{ 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00 }, //0x36

{ 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00 }, //0x37

{ 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00 }, //0x38

{ 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00 }, //0x39

{ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00 }, //0x3A

{ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60 }, //0x3B

{ 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00 }, //0x3C

{ 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00 }, //0x3D

{ 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00 }, //0x3E

{ 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00 }, //0x3F

{ 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00 }, //0x40

{ 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00 }, //0x41

{ 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00 }, //0x42

{ 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00 }, //0x43

{ 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00 }, //0x44

{ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00 }, //0x45

{ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00 }, //0x46

{ 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00 }, //0x47

{ 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00 }, //0x48

{ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x49

{ 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00 }, //0x4A

{ 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00 }, //0x4B

{ 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00 }, //0x4C

{ 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00 }, //0x4D

{ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00 }, //0x4E

{ 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00 }, //0x4F

{ 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00 }, //0x50

{ 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00 }, //0x51

{ 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00 }, //0x52

{ 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00 }, //0x53

{ 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x54

{ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00 }, //0x55

{ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00 }, //0x56

{ 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00 }, //0x57

{ 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00 }, //0x58

{ 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00 }, //0x59

{ 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00 }, //0x5A

{ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00 }, //0x5B

{ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00 }, //0x5C

{ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00 }, //0x5D

{ 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00 }, //0x5E

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, //0x5F

{ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x60

{ 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00 }, //0x61

{ 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00 }, //0x62

{ 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00 }, //0x63

{ 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00 }, //0x64

{ 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00 }, //0x65

{ 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00 }, //0x66

{ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8 }, //0x67

{ 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00 }, //0x68

{ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x69

{ 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78 }, //0x6A

{ 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00 }, //0x6B

{ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x6C

{ 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00 }, //0x6D

{ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00 }, //0x6E

{ 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00 }, //0x6F

{ 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0 }, //0x70

{ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E }, //0x71

{ 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00 }, //0x72

{ 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00 }, //0x73

{ 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00 }, //0x74

{ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00 }, //0x75

{ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00 }, //0x76

{ 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00 }, //0x77

{ 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00 }, //0x78

{ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8 }, //0x79

{ 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00 }, //0x7A

{ 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00 }, //0x7B

{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00 }, //0x7C

{ 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00 }, //0x7D

{ 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0x7E

{ 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00 }, //0x7F

{ 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78 }, //0x80

{ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00 }, //0x81

{ 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00 }, //0x82

{ 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00 }, //0x83

{ 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00 }, //0x84

{ 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00 }, //0x85

{ 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00 }, //0x86

{ 0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38 }, //0x87

{ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00 }, //0x88

{ 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00 }, //0x89

{ 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00 }, //0x8A

{ 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x8B

{ 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00 }, //0x8C

{ 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0x8D

{ 0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00 }, //0x8E

{ 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00 }, //0x8F

{ 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00 }, //0x90

{ 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00 }, //0x91

{ 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00 }, //0x92

{ 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00 }, //0x93

{ 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00 }, //0x94

{ 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00 }, //0x95

{ 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00 }, //0x96

{ 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00 }, //0x97

{ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8 }, //0x98

{ 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00 }, //0x99

{ 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00 }, //0x9A

{ 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18 }, //0x9B

{ 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00 }, //0x9C

{ 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30 }, //0x9D

{ 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7 }, //0x9E

{ 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70 }, //0x9F

{ 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00 }, //0xA0

{ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 }, //0xA1

{ 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00 }, //0xA2

{ 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00 }, //0xA3

{ 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00 }, //0xA4

{ 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00 }, //0xA5

{ 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00 }, //0xA6

{ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00 }, //0xA7

{ 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00 }, //0xA8

{ 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00 }, //0xA9

{ 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00 }, //0xAA

{ 0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F }, //0xAB

{ 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03 }, //0xAC

{ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00 }, //0xAD

{ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00 }, //0xAE

{ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00 }, //0xAF

{ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88 }, //0xB0

{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA }, //0xB1

{ 0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE }, //0xB2

{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }, //0xB3

{ 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18 }, //0xB4

{ 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18 }, //0xB5

{ 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36 }, //0xB6

{ 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36 }, //0xB7

{ 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18 }, //0xB8

{ 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36 }, //0xB9

{ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 }, //0xBA

{ 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36 }, //0xBB

{ 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00 }, //0xBC

{ 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00 }, //0xBD

{ 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00 }, //0xBE

{ 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18 }, //0xBF

{ 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00 }, //0xC0

{ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00 }, //0xC1

{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18 }, //0xC2

{ 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18 }, //0xC3

{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 }, //0xC4

{ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18 }, //0xC5

{ 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18 }, //0xC6

{ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36 }, //0xC7

{ 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00 }, //0xC8

{ 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36 }, //0xC9

{ 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00 }, //0xCA

{ 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36 }, //0xCB

{ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36 }, //0xCC

{ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00 }, //0xCD

{ 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36 }, //0xCE

{ 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00 }, //0xCF

{ 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00 }, //0xD0

{ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18 }, //0xD1

{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36 }, //0xD2

{ 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00 }, //0xD3

{ 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00 }, //0xD4

{ 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18 }, //0xD5

{ 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36 }, //0xD6

{ 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36 }, //0xD7

{ 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18 }, //0xD8

{ 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00 }, //0xD9

{ 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18 }, //0xDA

{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, //0xDB

{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }, //0xDC

{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 }, //0xDD

{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, //0xDE

{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }, //0xDF

{ 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00 }, //0xE0

{ 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0 }, //0xE1

{ 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00 }, //0xE2

{ 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00 }, //0xE3

{ 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00 }, //0xE4

{ 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00 }, //0xE5

{ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0 }, //0xE6

{ 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00 }, //0xE7

{ 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC }, //0xE8

{ 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00 }, //0xE9

{ 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00 }, //0xEA

{ 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00 }, //0xEB

{ 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00 }, //0xEC

{ 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0 }, //0xED

{ 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00 }, //0xEE

{ 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00 }, //0xEF

{ 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00 }, //0xF0

{ 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00 }, //0xF1

{ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00 }, //0xF2

{ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00 }, //0xF3

{ 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18 }, //0xF4

{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70 }, //0xF5

{ 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00 }, //0xF6

{ 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00 }, //0xF7

{ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00 }, //0xF8

{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00 }, //0xF9

{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 }, //0xFA

{ 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C }, //0xFB

{ 0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00 }, //0xFC

{ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00 }, //0xFD

{ 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00 }, //0xFE

{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0xFF

};

static void writeMatrix_byte(unsigned char data)

{

    unsigned char i;

    gpio_set_value(PIN_CS, 0);

    for(i=8; i>=1; i--)

    {

        gpio_set_value(PIN_CLK, 0);

        gpio_set_value(PIN_DIN, data&0x80);

        data = data<<1;

        gpio_set_value(PIN_CLK, 1);

    }

}

static void writeMatrix(unsigned char addr, unsigned char data)

{

    gpio_set_value(PIN_CS, 0);

    writeMatrix_byte(addr);

    writeMatrix_byte(data);

    gpio_set_value(PIN_CS, 1);

}

/** @brief 每次裝置被代開的時候呼叫的裝置開啟函式

 *  在本例中,該函式只是簡單的累加numberOpens計數器。

 *  @param inodep 指向inode物件的指標(定義在linux/fs.h標頭檔案中)

 *  @param filep 指向檔案物件指標(定義在linux/fs.h標頭檔案中)

 */

static int dev_open(struct inode *inodep, struct file *filep)

{

   int req_din = gpio_request(PIN_DIN, "PIN_DIN");

   int req_cs  = gpio_request(PIN_CS, "PIN_CS");

   int req_clk = gpio_request(PIN_CLK, "PIN_CLK");

   if (req_din || req_cs || req_clk) {

      return -1;

   }

   gpio_direction_output(PIN_DIN, 0);

   gpio_direction_output(PIN_CS, 0);

   gpio_direction_output(PIN_CLK, 0);

   numberOpens++;

   printk(KERN_INFO "Device has been opened %d time(s)\n", numberOpens);

   writeMatrix(0x09, 0x00);

   writeMatrix(0x0a, 0x03);

   writeMatrix(0x0b, 0x07);

   writeMatrix(0x0c, 0x01);

   writeMatrix(0x0f, 0x00);

   return 0;

}

/** @brief 該函式在裝置從使用者空間讀取的時候被呼叫,即資料從裝置向用戶空間傳輸。

 *  在本例中,通過copy_to_user()函式將緩衝區中的字串傳送給使用者,並且捕獲任何異常。

 *  @param filep 指向檔案物件的指標(定義在linux/fs.h標頭檔案中)

 *  @param buffer 指向本函式寫入資料的緩衝區指標

 *  @param len 緩衝區長度

 *  @param offset 此次讀取在核心緩衝區中的偏移量

 */

static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset)

{

   return 0;

}

/** @brief 該函式在裝置想使用者空間寫入的時候呼叫,即從資料從使用者發往裝置。

 *  在此核心模組中,資料通過sprintf()函式複製到message[]陣列中,同時字串長度被儲存到size_of_message變數中。

 *  @param filep 指向檔案物件的指標

 *  @param buffer 包含待寫入裝置字串的緩衝區

 *  @param len 傳遞到const char型別緩衝區的資料長度

 *  @param offset 檔案裝置當前偏移量

 */

static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset)

{

   //sprintf(message, "%s(%d letters)", buffer, len);   // 通過長度追加當前接受到的字串

   unsigned char i;

   for(i = 1; i < 9; i++)

      writeMatrix(i, disp1[(unsigned char)buffer[0]][i-1]);

   size_of_message = 1;

   printk(KERN_INFO "Received characters %c from the user\n", buffer[0]);

   return len;

}

/** @brief 當裝置被使用者空間程式關閉/釋放時呼叫的函式。

 *  @param inodep 指向inode物件的指標(定義在linux/fs.h標頭檔案中)

 *  @param filep 指向檔案物件的指標(定義在linux/fs.h標頭檔案中)

 */

static int dev_release(struct inode *inodep, struct file *filep)

{

   gpio_free(PIN_DIN);

   gpio_free(PIN_CS);

   gpio_free(PIN_CLK);

   printk(KERN_INFO "Device closed.\n");

   return 0;

}

/** @brief 核心模組必須使用linux/init.h標頭檔案中提供的module_init()、module_exit()巨集,

 *  在插入和清理的時候標識對應的函式(如上所列)

 */

module_init(matrix_init);

module_exit(matrix_exit);