大体上可分为以下几个部分:
1.注册设备驱动 spi_register_driver
2.分配 mtd_info 结构体
3.配置 mtd_info 结构体
4.注册 mtd_info 结构体
构建 spi_driver 并注册
static struct spi_driver spi_flash_drv = {
.driver = {
.name = "spi_flash",
.owner = THIS_MODULE,
},
.probe = spi_flash_probe,
.remove = __devexit_p(spi_flash_remove),
};
static int spi_flash_init(void)
{
return spi_register_driver(&spi_flash_drv);
}
当内核中注册了同名的设备,会调用该驱动的 probe 程序
/* 分配 mtd_info 结构体 */
static struct mtd_info spi_flash_dev;
static int __devinit spi_flash_probe(struct spi_device *spi)
{
int mid, did;
spi_flash = spi;
s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
SPIFlashInit();
SPIFlashReadID(&mid, &did);
printk("SPI Flash ID: %02x %02x
", mid, did);
memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));
/* 构造并注册这个 mtd_info
* mtd_device_register(master, parts, nr_parts)
*/
/* Setup the MTD structure */
spi_flash_dev.name = "spi_flash";
spi_flash_dev.type = MTD_NORFLASH;
spi_flash_dev.flags = MTD_CAP_NORFLASH;
spi_flash_dev.size = 0x200000; /* 2M */
spi_flash_dev.writesize = 1;
spi_flash_dev.writebufsize = 4096; /* 没有用到 */
spi_flash_dev.erasesize = 4096; /* 擦除的最小单位 */
spi_flash_dev.owner = THIS_MODULE;
spi_flash_dev._erase = spi_flash_erase;
spi_flash_dev._read = spi_flash_read;
spi_flash_dev._write = spi_flash_write;
mtd_device_register(&spi_flash_dev, NULL, 0);
return 0;
}
spi_flash_dev._erase = spi_flash_erase;
spi_flash_dev._read = spi_flash_read;
spi_flash_dev._write = spi_flash_write;
这三个函数与前面一篇文章所调用的函数基本相同,只是 SPI 的发送我们需要调用内核中的函数来完成,程序如下(linux/spi.h):
static inline int
spi_write(struct spi_device *spi, const void *buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
忙等待函数我们也要加以修改,避免浪费 CPU 资源,程序如下:
static void SPIFlashWaitWhenBusy(void)
{
while (SPIFlashReadStatusReg1() & 1)
{
/* 休眠一段时间 */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/100); /* 休眠10MS后再次判断 */
}
}
将进程设置为可中断的等待状态 TASK_INTERRUPTIBLE 。
状态解释:进程被挂起(睡眠),直到某个条件变为真。产生一个硬件中断,释放进程正在等待的系统资源,或传递一个信号都是可以唤醒进程的条件 (把进程的状态放回到 TASK_RUNNING)。
使用 schedule_timeout 函数,该方法会让需要延迟的任务睡眠到指定的延时时间后在重新运行。