字元裝置驅動程式
#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);