2011年6月9日 星期四

gpio driver 筆記整理

簡單的說, 是 CPU register 的 access driver, 像 freescale 那種 EIM bus access 應該不能這樣寫. 這是用很老式的 file_operations 寫法, 要用到 /dev/??? 的 character 檔案去做媒界, 所以僅參考用:

static int libGPIO_open(struct inode *inode, struct file *file)
{ return 0; }

static int libGPIO_release(struct inode *inode, struct file *file)
{ return 0; }

static ssize_t libGPIO_read(struct file *filp, char *buffer, size_t count, loff_t *f_pos)
{
// ...
}

static ssize_t libGPIO_write(struct file *filp, const char *buffer, size_t count, loff_t *f_pos)
{
unsigned long lADDR = 0x73f8400L;
unsigned long lDATA = *(unsigned long *)buffer;
void *pvPTR = 0;
struct resource *ptRES = 0;

//在有 OS 保護下, 要存取實際位址的東西前, 要做一些動作
//尋問這段記憶體有沒有其它程式佔用
ptRES = request_mem_region(lADDR, 8, "GPIOmem");
if(!ptRES)
{
printk("mem_rgn_req_fail\n");
return -1;
}

//把這段記憶體位址映射到一塊可存取的空間上, 使用 8byte 大小的空間.
pvPTR = ioremap(lADDR, 8);
if(!pvPTR)
{
printk("ioremap_fail\n");
return -1;
}

//對這段記憶體做存取動作
iowrite32(lDATA, pvPTR);
iounmap(pvPTR); //釋放映射位址.
release_mem_region(lADDR, 8); //解除使用鎖定.
}

static int libGPIO_ioctl(struct inode *inode, struct file *file, unsigned int ctl_code, unsigned long param)
{
// ...
}

static struct file_operations tMODULE =
{
.open = libGPIO_open,
.release = libGPIO_release,
.read = libGPIO_read,
.write = libGPIO_write,
.ioctl = libGPIO_ioctl,
};

static int __init ____init(void)
{
return register_chrdev(240, "gpio_acs", &tMODULE);
}

static void __exit ____exit(void)
{
unregister_chrdev(240, "gpio_acs");
}

module_init(____init);
module_exit(____exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("spam ");
MODULE_DESCRIPTION("GPIO read/write module");

其中 iowrite32 跟以前 writel 一樣, 但兩個參數剛好顛倒.
其它還有 ioread8/16/32 (做用和 readb/w/l一樣), iowrite8/16/32 (做用和 writeb/w/l一樣)可用.

然後 AP 這邊就要應用 open/close/read/write/ioctl 這些動作去觸發 driver 裡的對應動作:

int GPIOopen(void)
{
return open(_LIB_NOD_FILENAME_, O_RDWR);
}

int GPIOclose(unsigned int nHeader)
{
return close(nHeader);
}

int GPIOopt(unsigned int nHeader, unsigned long lADDR, unsigned long *plValue)
{
int ret = -1;

if(!plValue || !nHeader) return -1;

ret = ioctl(nHeader, 1, lADDR);
ret = read(nHeader, plValue, 4);
// ret = write(nHeader, &lValue, 4);
return ret;
}

這樣的動作. 只是 ioctl 第二個 parameter 要非 0, 否則無法觸發. read/write 原本的 count 定義是 ssize_t, 在 -m32 下最大就到 2G, 2G 以上的數字會被直接擋掉, 不會進到 module 裡面運作..

btw, 這是實驗用的東西才這樣寫, 真正商業的東西已經不能這樣搞了...

沒有留言: