制御用のFON2405E(LEDE・Openwrt)向けドライバ作成
1. SPI仕様
[0x01][コントラスト] ※コントラストは0x00〜0x06
[0x02][コマンド] ※ RS=0 でLCDに出力
[0x03][データ] ※ RS=1 でLCDに出力
http://akizukidenshi.com/download/ds/sunlike/SD1602HULB-XA-G-G.PDF
http://219.117.208.26/~saka/ham/LCD2/
2. ドライバ仕様
基本的には、MCP23S09の時と同じ。
キャラクタデバイスとして[/dev/ PicClcdDriver0]が作成される。
これに表示したい内容を流しこめばOK
一方で、各種制御は[/sys/bus/spi/drivers/PicClcdDriver/spi0.1/]に
lcd_clear:Clear Display(全表示クリア)
lcd_set_cgram:Set CGRAM address
lcd_set_ddram:Set DDRAM address
が作成される
3. 動作
insmod pic_clcd.ko
echo > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_clear
echo -n HelloWorld! > /dev/ PicClcdDriver0
英数字以外 例えば 「イ」とか
echo -ne "\xB2" > /dev/ PicClcdDriver0
外字CGRAM
0番目に「晴?」アイコン
echo 00411040E04110400 > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_set_cgram
ドライバソースコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* pic_cled.c | |
* | |
* Created on: 2018/07/08 | |
* Author: adeno | |
*/ | |
#include <linux/module.h> | |
#include <linux/moduleparam.h> | |
#include <linux/kernel.h> | |
#include <linux/cdev.h> | |
#include <linux/delay.h> | |
#include <linux/uaccess.h> //copy_from_user | |
#include <linux/gpio.h> | |
#include <linux/spi/spi.h> | |
MODULE_AUTHOR("Adeno"); | |
MODULE_LICENSE("GPL v2"); | |
//======================================================================================= | |
/* ドライバ */ | |
#define DRV_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */ | |
#define DRV_DEVNAME "PicClcdDriver" /* このデバイスドライバの名称 */ | |
#define DRV_MAJOR 0 /* メジャー番号だが自動設定なので0 */ | |
#define DRV_MINOR 0 /* マイナー番号のベース番号 */ | |
#define DRV_GPIO_MAPNAME "pcd_gpio_map" | |
/* SPI PIC設定 */ | |
#define SPCD_PACKET_SIZE 1 | |
const uint8_t SPCD_LCD_PWM = 0x01; | |
const uint8_t SPCD_LCD_CMD = 0x02; | |
const uint8_t SPCD_LCD_DATA = 0x03; | |
const uint8_t SPCD_LCD_CMD_CLEARDISPLAY = 0b00000001; | |
const uint8_t SPCD_LCD_CMD_RETURNHOME = 0b00000010; | |
const uint8_t SPCD_LCD_CMD_SETCGRAM = 0b01000000; | |
const uint8_t SPCD_LCD_CMD_SETDDRAM = 0b10000000; | |
//======================================================================================= | |
/* ドライバ */ | |
static int _spcd_major = DRV_MAJOR; | |
static int _spcd_minor = DRV_MINOR; | |
/* SPI */ | |
struct drvdata { | |
struct spi_device *spi; | |
struct mutex lock; | |
unsigned char tx[SPCD_PACKET_SIZE]; | |
unsigned char rx[SPCD_PACKET_SIZE]; | |
struct spi_transfer xfer; | |
struct spi_message msg; | |
dev_t md_dev; | |
struct class *drv_class; | |
struct cdev *drv_cdev_array; | |
} ____cacheline_aligned; | |
static struct drvdata spcd; | |
static struct spi_board_info spcd_info = { | |
.modalias = "spcd", | |
.max_speed_hz = 1000000, | |
.bus_num = 0, | |
.chip_select = 0, | |
.mode = SPI_MODE_3, | |
}; | |
static struct spi_device_id spcd_id[] = { | |
{ "spcd", 0 }, | |
{ }, | |
}; | |
MODULE_DEVICE_TABLE(spi, spcd_id); | |
/* Parameters Setting */ | |
static int gpiono = 9; | |
static int show_debug = 0; | |
//static int hexmode = 0; | |
//======================================================================================= | |
/* プロトタイプ宣言 */ | |
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v); | |
static void spi_remove_device(struct spi_master *master, unsigned int cs); | |
static int spcd_probe(struct spi_device *spi); | |
static int spcd_remove(struct spi_device *spi); | |
static int spcd_open(struct inode *inode, struct file *filep); | |
static int spcd_release(struct inode *inode, struct file *filep); | |
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos); | |
static int spcd_register_dev(void); | |
static int spcd_init(void); | |
static void spcd_exit(void); | |
//======================================================================================= | |
/* SPIデバイス */ | |
static struct spi_driver spcd_driver = { | |
.driver = { | |
.name = DRV_DEVNAME, | |
.owner = THIS_MODULE, | |
}, | |
.id_table = spcd_id, | |
.probe = spcd_probe, | |
.remove = spcd_remove, | |
}; | |
/* キャラクタデバイス */ | |
struct file_operations spcd_fops = { | |
.open = spcd_open, | |
.release = spcd_release, | |
.write = spcd_write, | |
}; | |
//======================================================================================= | |
static int lcd_clear_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
{ | |
int size = strlen( buf ); | |
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev); | |
spcd_set_value(drd,SPCD_LCD_CMD); | |
spcd_set_value(drd,SPCD_LCD_CMD_CLEARDISPLAY); | |
// spcd_set_value(drd,SPCD_LCD_FIN); | |
return size; | |
} | |
static DEVICE_ATTR(lcd_clear, S_IWUSR|S_IWGRP, NULL, lcd_clear_store ); | |
static int lcd_set_cgram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
{ | |
//CharNo Line(0-7) | |
//[1] [2]x8 | |
int b[9],i; | |
int size = strlen( buf ); | |
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev); | |
if(size >= 17){ | |
if(buf[0] >='0' && buf[0] <= '9') b[0] = buf[0]-'0'; | |
b[0] = SPCD_LCD_CMD_SETCGRAM | (((b[0] & 0b111) << 3) & 0b111000); | |
if(show_debug) printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d\n",size,b[0]); | |
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr output=%d\n",b[0]); | |
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b[0]); | |
for(i=0; i<8; i++){ | |
if(buf[i*2+1] >='0' && buf[i*2+1] <= '9') b[i] = (buf[i*2+1]-'0') * 0x10; | |
else if(buf[i*2+1] >='A' && buf[i*2+1] <= 'F') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10; | |
else if(buf[i*2+1] >='a' && buf[i*2+1] <= 'f') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10; | |
if(buf[i*2+2] >='0' && buf[i*2+2] <= '9') b[i] += (buf[i*2+2]-'0'); | |
else if(buf[i*2+2] >='A' && buf[i*2+2] <= 'F') b[i] += (buf[i*2+2]-'A'+0xA); | |
else if(buf[i*2+2] >='a' && buf[i*2+2] <= 'f') b[i] += (buf[i*2+2]-'A'+0xA); | |
spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,b[i]); | |
} | |
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,0b10); //ホームに | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,buf[0]-'0'); | |
// | |
// | |
// | |
// if((buf[0] >='0' && buf[0] <= '9') && (buf[1] >='0' && buf[1] <= '9')){ | |
// int cno = buf[0]-'0'; | |
// int lno = buf[1]-'0'; | |
// int b = 0x40 | (((cno & 0b111) << 3) | (lno & 0b111)); | |
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d,L=%d,output=%d\n",size,cno,lno,b); | |
// | |
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b); | |
//// spcd_set_value(drd,SPCD_LCD_FIN); | |
// | |
// //debug | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101); | |
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b00000); | |
//// spcd_set_value(drd,SPCD_LCD_FIN); | |
// } | |
} | |
return size; | |
} | |
static DEVICE_ATTR(lcd_set_cgram, S_IWUSR|S_IWGRP, NULL, lcd_set_cgram_store ); | |
static int lcd_set_ddram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
{ | |
//Adr | |
//[2] | |
int b; | |
int size = strlen( buf ); | |
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev); | |
if(size >= 1){ | |
if(buf[0] >='0' && buf[0] <= '9') b = (buf[0]-'0') * 0x10; | |
else if(buf[0] >='A' && buf[0] <= 'F') b += (buf[0]-'A'+0xA) * 0x10; | |
else if(buf[0] >='a' && buf[0] <= 'f') b += (buf[0]-'A'+0xA) * 0x10; | |
if(buf[1] >='0' && buf[1] <= '9') b += (buf[1]-'0'); | |
else if(buf[1] >='A' && buf[1] <= 'F') b += (buf[1]-'A'+0xA); | |
else if(buf[1] >='a' && buf[1] <= 'f') b += (buf[1]-'A'+0xA); | |
/*if(show_debug)*/ printk(KERN_INFO "LCD SET DD Adr size=%d,C=%d\n",size,(b | SPCD_LCD_CMD_SETDDRAM)); | |
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,(b | SPCD_LCD_CMD_SETDDRAM)); | |
} | |
return size; | |
} | |
static DEVICE_ATTR(lcd_set_ddram, S_IWUSR|S_IWGRP, NULL, lcd_set_ddram_store ); | |
static int lcd_contrast_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
{ | |
int size = strlen( buf ); | |
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev); | |
if(size > 0){ | |
if(show_debug) printk(KERN_INFO "Change LCD Contrast %d,%c\n", size,buf[0]); | |
spcd_set_value(drd,SPCD_LCD_PWM); | |
switch(buf[0]){ | |
case '0': | |
spcd_set_value(drd,0x00); | |
break; | |
case '1': | |
spcd_set_value(drd,0x01); | |
break; | |
case '2': | |
spcd_set_value(drd,0x02); | |
break; | |
case '3': | |
spcd_set_value(drd,0x03); | |
break; | |
case '4': | |
spcd_set_value(drd,0x04); | |
break; | |
case '5': | |
spcd_set_value(drd,0x05); | |
break; | |
case '6': | |
spcd_set_value(drd,0x06); | |
break; | |
default: | |
spcd_set_value(drd,0x03); | |
break; | |
} | |
} | |
return size; | |
} | |
static DEVICE_ATTR(lcd_contrast, S_IWUSR|S_IWGRP, NULL, lcd_contrast_store ); | |
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v) | |
{ | |
unsigned int r = 0; | |
mutex_lock( &data->lock ); | |
data->tx[0] = v; | |
if( spi_sync( data->spi, &data->msg) ) { | |
if(show_debug) printk(KERN_INFO "spi_sync_transfer returned non zero\n" ); | |
} | |
usleep_range(1000,2000); | |
mutex_unlock(&data->lock); | |
return r; | |
} | |
/** | |
* SPIデバイスの削除 | |
*/ | |
static void spi_remove_device(struct spi_master *master, unsigned int cs) | |
{ | |
struct device *dev; | |
char str[128]; | |
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs); | |
if(show_debug) printk(KERN_INFO "[spi_remove_device] %s\n",str); | |
// SPIデバイスを探す | |
dev = bus_find_device_by_name(&spi_bus_type, NULL, str); | |
// あったら削除 | |
if( dev ){ | |
if(show_debug) printk(KERN_INFO "Delete %s\n", str); | |
device_del(dev); | |
} | |
} | |
/** | |
* SPI通信初期化 | |
*/ | |
static int spcd_probe(struct spi_device *spi) | |
{ | |
// struct mcp_drvdata *data; | |
int retval; | |
if(show_debug) printk(KERN_INFO "spcd spi probe\n"); | |
/* SPIを設定する */ | |
spi->max_speed_hz = spcd_info.max_speed_hz; | |
spi->mode = spcd_info.mode; | |
spi->bits_per_word = 8; | |
if( spi_setup( spi ) ) { | |
printk(KERN_ERR "spi_setup returned error\n"); | |
return -ENODEV; | |
} | |
spcd.spi = spi; | |
mutex_init( &spcd.lock ); | |
spcd.xfer.tx_buf = spcd.tx; | |
spcd.xfer.rx_buf = 0;//data->rx; | |
spcd.xfer.bits_per_word = 8; | |
spcd.xfer.len = SPCD_PACKET_SIZE; | |
spcd.xfer.cs_change = 0; | |
spcd.xfer.delay_usecs = 0; | |
spcd.xfer.speed_hz = 1000000; | |
spi_message_init_with_transfers( &spcd.msg, &spcd.xfer, 1 ); | |
spi_set_drvdata( spi, &spcd ); | |
mutex_lock( &spcd.lock ); | |
spcd.tx[0] = 0x00; | |
if( spi_sync( spcd.spi, &spcd.msg) ) { | |
printk(KERN_INFO "spi_sync_transfer returned non zero\n" ); | |
} | |
mutex_unlock(&spcd.lock); | |
retval = device_create_file( &spi->dev, &dev_attr_lcd_clear ); | |
if(retval) { | |
printk(KERN_ERR "failed to add lcd_clear attribute\n" ); | |
} | |
retval = device_create_file( &spi->dev, &dev_attr_lcd_contrast ); | |
if(retval) { | |
printk(KERN_ERR "failed to add lcd_contrast attribute\n" ); | |
} | |
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_cgram ); | |
if(retval) { | |
printk(KERN_ERR "failed to add lcd_set_cgram attribute\n" ); | |
} | |
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_ddram ); | |
if(retval) { | |
printk(KERN_ERR "failed to add lcd_set_ddram attribute\n" ); | |
} | |
return 0; | |
} | |
/** | |
* SPI通信終了 | |
*/ | |
static int spcd_remove(struct spi_device *spi) | |
{ | |
if(show_debug) printk(KERN_INFO "[spcd spi_remove]\n"); | |
struct drvdata *drd = spi_get_drvdata(spi); | |
mutex_lock( &drd->lock ); | |
drd->tx[0] = 0x00; | |
if( spi_sync( drd->spi, &drd->msg) ) { | |
printk(KERN_INFO "spi_sync_transfer returned non zero\n" ); | |
} | |
mutex_unlock(&drd->lock); | |
device_remove_file( &spi->dev, &dev_attr_lcd_clear); | |
device_remove_file( &spi->dev, &dev_attr_lcd_contrast); | |
device_remove_file( &spi->dev, &dev_attr_lcd_set_cgram); | |
device_remove_file( &spi->dev, &dev_attr_lcd_set_ddram); | |
spi_set_drvdata(drd->spi, NULL); | |
drd->spi = NULL; | |
mutex_destroy(&spcd.lock); | |
if(gpiono != 0) gpio_free(gpiono); | |
return 0; | |
} | |
/** | |
* デバイスオープン時の処理 | |
*/ | |
static int spcd_open(struct inode *inode, struct file *filep) | |
{ | |
if(show_debug) printk(KERN_INFO "[spcd_open]\n"); | |
filep->private_data = &spcd; | |
return 0; | |
} | |
/** | |
* デバイスクローズ時の処理 | |
*/ | |
static int spcd_release(struct inode *inode, struct file *filep) | |
{ | |
if(show_debug) printk(KERN_INFO "[spcd_release]\n"); | |
struct drvdata *drd = filep->private_data; | |
if ((drd == NULL) || (drd->spi == NULL)) | |
return -ENODEV; | |
filep->private_data = NULL; | |
return 0; | |
} | |
/** | |
* デバイス書き込み処理 | |
*/ | |
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos) | |
{ | |
char cvalue; | |
// int i; | |
struct drvdata *drd = filep->private_data; | |
if ((drd == NULL) || (drd->spi == NULL)) | |
return -ENODEV; | |
// struct mcp_drvdata *data = (struct mcp_drvdata *)dev_get_drvdata(filep->private_data); | |
if(count > 0) { | |
if(gpiono != 0) gpio_set_value(gpiono,1); | |
if(copy_from_user( &cvalue, buf, sizeof(char) )) { | |
return -EFAULT; | |
} | |
spcd_set_value(drd,SPCD_LCD_DATA); | |
spcd_set_value(drd,cvalue); | |
// spcd_set_value(drd,SPCD_LCD_FIN); | |
// if((cvalue >=0) && (cvalue <= 9)) spcd_set_value(drd,cvalue); | |
// else if(('0' <= cvalue) && (cvalue <= '9')) { | |
// spcd_set_value(drd,0x03); | |
// spcd_set_value(drd,cvalue); | |
// spcd_set_value(drd,0x00); | |
// } | |
// else{ | |
// if(hexmode){ | |
// if(('A' <= cvalue) && (cvalue <= 'F')) spcd_set_value(drd,cvalue - 'A' + 10); | |
// else if(('a' <= cvalue) && (cvalue <= 'f')) spcd_set_value(drd,cvalue - 'a' + 10); | |
// } | |
// else if(show_debug) printk(KERN_ALERT "Can not display %d\n", cvalue ); | |
// } | |
if(gpiono != 0) gpio_set_value(gpiono,0); | |
return sizeof(char); | |
} | |
return 0; | |
} | |
/** | |
* デバイスドライバをカーネルに登録 | |
*/ | |
static int spcd_register_dev(void) | |
{ | |
int retval; | |
// dev_t dev; | |
size_t size; | |
int i; | |
/* 空いているメジャー番号を使ってメジャー& | |
マイナー番号をカーネルに登録する */ | |
retval = alloc_chrdev_region( | |
&spcd.md_dev, /* 結果を格納するdev_t構造体 */ | |
DRV_MINOR, /* ベースマイナー番号 */ | |
DRV_NUM_DEVS, /* デバイスの数 */ | |
DRV_DEVNAME /* デバイスドライバの名前 */ | |
); | |
if( retval < 0 ) { | |
printk(KERN_ERR "alloc_chrdev_region failed.\n" ); | |
return retval; | |
} | |
_spcd_major = MAJOR(spcd.md_dev); | |
/* デバイスクラスを作成する */ | |
spcd.drv_class = class_create(THIS_MODULE,DRV_DEVNAME); | |
if(IS_ERR(spcd.drv_class)) | |
return PTR_ERR(spcd.drv_class); | |
/* cdev構造体の用意 */ | |
size = sizeof(struct cdev) * DRV_NUM_DEVS; | |
spcd.drv_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL); | |
/* デバイスの数だけキャラクタデバイスを登録する */ | |
/* ただし7セグLEDは1個しかない */ | |
for( i = 0; i < DRV_NUM_DEVS; i++ ) { | |
dev_t devno = MKDEV(_spcd_major, _spcd_minor+i); | |
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */ | |
cdev_init(&(spcd.drv_cdev_array[i]), &spcd_fops); | |
spcd.drv_cdev_array[i].owner = THIS_MODULE; | |
if( cdev_add( &(spcd.drv_cdev_array[i]), devno, 1) < 0 ) { | |
/* 登録に失敗した */ | |
printk(KERN_ERR "cdev_add failed minor = %d\n", _spcd_minor+i ); | |
} | |
else { | |
/* デバイスノードの作成 */ | |
device_create( | |
spcd.drv_class, | |
NULL, | |
devno, | |
NULL, | |
DRV_DEVNAME"%u",_spcd_minor+i | |
); | |
} | |
} | |
return 0; | |
} | |
/** | |
* モジュールの初期化処理 | |
*/ | |
static int spcd_init(void) | |
{ | |
int retval; | |
int i; | |
/* 開始のメッセージ */ | |
printk(KERN_INFO "%s loading...\n", DRV_DEVNAME ); | |
if(gpiono != 0){ | |
/* GPIOレジスタがマップ可能か調べる */ | |
retval = gpio_request_one(gpiono, GPIOF_OUT_INIT_LOW, DRV_GPIO_MAPNAME); | |
if (retval) { | |
printk(KERN_ERR "Unable to request GPIOs: %d\n", retval); | |
return retval; | |
} | |
for( i=0; i<10; i++ ) { | |
gpio_set_value(gpiono,1); | |
msleep(10); | |
gpio_set_value(gpiono,0); | |
msleep(10); | |
} | |
} | |
/* デバイスドライバをカーネルに登録 */ | |
retval = spcd_register_dev(); | |
if( retval != 0 ) { | |
printk( KERN_ALERT "mcp7d driver register failed.\n"); | |
return retval; | |
} | |
if(show_debug) | |
printk( KERN_INFO "mcp7d driver register sccessed.\n"); | |
struct spi_master *master; | |
struct spi_device *spi_device; | |
spi_register_driver(&spcd_driver); | |
spcd_info.bus_num = 0; | |
spcd_info.chip_select = 1; | |
master = spi_busnum_to_master(spcd_info.bus_num); | |
if( ! master ) { | |
printk( KERN_ERR "spi_busnum_to_master returned NULL\n"); | |
spi_unregister_driver(&spcd_driver); | |
return -ENODEV; | |
} | |
spi_remove_device(master, spcd_info.chip_select); | |
spi_device = spi_new_device( master, &spcd_info ); | |
if( !spi_device ) { | |
printk(KERN_ERR "spi_new_device returned NULL\n" ); | |
spi_unregister_driver(&spcd_driver); | |
return -ENODEV; | |
} | |
return 0; | |
} | |
/** | |
* モジュールの終了処理 | |
*/ | |
static void spcd_exit(void) | |
{ | |
int i; | |
dev_t devno; | |
if(show_debug) printk(KERN_INFO "[spcd_exit]\n"); | |
if(show_debug) printk(KERN_INFO "[cdev_del]\n"); | |
/* キャラクタデバイスの登録解除 */ | |
for( i = 0; i < DRV_NUM_DEVS; i++ ) { | |
cdev_del(&(spcd.drv_cdev_array[i])); | |
devno = MKDEV(_spcd_major, _spcd_minor+i); | |
device_destroy(spcd.drv_class, devno); | |
} | |
/* メジャー番号/マイナー番号を取り除く */ | |
devno = MKDEV(_spcd_major,_spcd_minor); | |
unregister_chrdev_region(devno, DRV_NUM_DEVS); | |
/* デバイスノードを取り除く */ | |
class_destroy( spcd.drv_class ); | |
kfree(spcd.drv_cdev_array); | |
if(show_debug) printk(KERN_INFO "[spcd_del]\n"); | |
spi_unregister_driver(&spcd_driver); | |
} | |
module_init(spcd_init); | |
module_exit(spcd_exit); | |
module_param( show_debug, int, S_IRUSR | S_IRGRP | S_IROTH ); | |
module_param( gpiono, int, S_IRUSR | S_IRGRP | S_IROTH ); | |
//module_param( hexmode, int, S_IRUSR | S_IRGRP | S_IROTH ); | |
0 件のコメント:
コメントを投稿