The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

4.4 Пример драйвера MTD для NOR Flash

4.4 Пример драйвера MTD для NOR Flash

Предыдущая  Содержание  Следующая V*D*V

Погрузимся в подробности драйвера памяти NOR флеш для Linux. Файл mtd.c содержит код для простой NOR Flash, основанный на следующих предположениях:

 

Устройство флеш-памяти имеет один регион стирания, так что все секторы имеют одинаковый размер. (Регион стирания определяется как площадь микросхемы, которая содержит секторы одного и того же размера.)

Обращение к микросхеме флеш-памяти происходит с помощью 4-х байтовой шины.

Функциональность блокировки, разблокировки, приостановления и возобновления работы не поддерживается.

 

Для простоты будем считать, что у нас в виде макросов или функций имеется следующая информация:

 

DUMMY_FLASH_ERASE_SIZE: размер сектора стирания флеш-памяти

DUMMY_FLASH_SIZE: размер флеш-памяти

PROBE_FLASH(): функция, которая проверяет, присутствует ли NOR Flash по указанному адресу

WRITE_FLASH_ONE_WORD: функция/макрос для записи слова по указанному адресу

ERASE_FLASH_SECTOR: функция для стирания заданного сектора

DUMMY_FLASH_ERASE_TIME: время стирания одного сектора в тиках (jiffies)

 

Сначала составим список всех заголовочных файлов, которые потребуются для нашего драйвера флеш-памяти.

 

/* mtd.c */

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/types.h>

#include <linux/sched.h>

#include <linux/errno.h>

#include <linux/interrupt.h>

#include <linux/mtd/map.h>

#include <linux/mtd/mtd.h>

#include <linux/mtd/cfi.h>

#include <linux/delay.h>

 

Теперь определим все API/макросы, которые, как мы ожидаем, определит пользователь.

 

#define DUMMY_FLASH_ERASE_SIZE

#define PROBE_FLASH(map)

#define WRITE_FLASH_ONE_WORD(map, start, addr, data)

#define ERASE_FLASH_SECTOR(map, start, addr)

#define DUMMY_FLASH_ERASE_TIME

#define DUMMY_FLASH_SIZE

 

Краткое описание аргументов, которые передаются вышеописанному API:

 

map: это указатель на структуру map_info, объявленную в заголовочном файле include/linux/mtd/map.h. Эта структура более подробно объясняется в Разделе 4.5.

start: это начальный адрес микросхемы NOR флеш. Этот адрес обычно используется для программирования флеш-памяти с помощью команды стирания или записи данных.

addr: это смещение от начального адреса микросхемы, куда должны быть записаны данные или где должен быть стёрт сектор.

data: этот аргумент для API записи представляет собой 32-х разрядное слово, которое определяет, что должно быть записано по указанному адресу.

 

Далее мы определяем структуру, которая содержит информацию, относящуюся именно к этой флеш-памяти.

 

struct dummy_private_info_struct

{

  int number_of_chips; /* Количество микросхем флеш-памяти */

  int chipshift; /* Размер каждой флеш-памяти */

  struct flchip *chips;

} ;

 

Краткое описание каждого из полей этой структуры:

 

number_of_chips: как следует из названия, оно указывает, сколько всего микросхем можно найти по адресу probe. Это число коду драйвера должен вернуть API PROBE_FLASH().

chipshift: это общее количество разрядов адреса для устройства, которое используется для вычисления адреса смещения, и общего числа байтов, которое вмещает устройство.

chips: struct flchip можно найти в include/linux/mtd/flashchip.h. Дополнительное объяснение находится в функции dummy_probe().

 

Далее идёт список статических функций, которые должны быть объявлены.

 

static struct mtd_info * dummy_probe(struct map_info *);

static void dummy_destroy(struct mtd_info *);

static int dummy_flash_read(struct mtd_info *, loff_t , size_t ,

                            size_t *, u_char *);

static int dummy_flash_erase(struct mtd_info *,

                             struct erase_info *);

static int dummy_flash_write(struct mtd_info *, loff_t ,

                             size_t , size_t *, const u_char *);

static void dummy_flash_sync(struct mtd_info *);

 

Структура mtd_chip_driver используется процедурой инициализации dummy_flash_init() и функцией выхода dummy_flash_exit(). Наиболее важным полем является .probe, которое вызывается, чтобы определить, присутствует ли на плате по указанному адресу флеш-память указанного типа. Уровень MTD хранит список таких структур. Обращение к процедурам probe происходит, когда драйвер связи с флеш-памятью вызывает процедуру do_map_probe().

 

static struct mtd_chip_driver dummy_chipdrv =

{

  .probe   = dummy_probe,

  .destroy = dummy_destroy,

  .name    = "dummy_probe",

  .module  = THIS_MODULE

};

 

Теперь определим процедуру probe. Эта функция проверяет, может ли флеш-память быть найдена по адресу map->virt, который заполняется драйвером связи с флеш-памятью. Если он в состоянии обнаружить флеш-память, то он выделяет память для структуры mtd и структуры dummy_private_info. Структура mtd заполнена различными процедурами драйвера, такими как read, write, erase и так далее. Структура dummy_private_info заполнена информации о данной флеш-памяти. Реализацию процедуры probe можно посмотреть в Распечатке 4.1.

 

Наиболее интересными структурами данных, которые инициализируются в функции probe, являются очередь ожидания и мьютекс. Они используются для предотвращения одновременного доступа к флеш-памяти, что является необходимым условием почти для всех устройств флеш-памяти. Таким образом, когда должны быть выполнены такие операции, как чтение или запись, драйвер должен проверить, не используется ли флеш-память. Это выполняется с помощью поля state, которое установлено во время инициализации в FL_READY. Если флеш-память используется, то процесс должен заблокироваться на очереди ожидания и ждать пробуждения. Мьютекс (спин-блокировка) используется для предотвращения проблем с состояниями гонок на машинах с SMP (симметричной многопроцессорной обработкой) или в случае, если разрешено вытеснение.

 

Перейдём к процедуре read. Процедурой чтения, зарегистрированной в ядре MTD, является dummy_flash_read(), которая вызывается, чтобы прочитать len байтов из флеш-памяти со смещения from. Поскольку процедуры записи могут охватывать несколько микросхем, для чтения данных из одной микросхемы внутри вызывается функция dummy_flash_read_one_chip(). Реализацию можно посмотреть в Распечатке 4.2.

 

Теперь перейдём к процедуре записи. Процедурой, зарегистрированной в ядре MTD, является dummy_flash_write(). Поскольку запись может начинаться с невыровненного адреса, данная функция гарантирует, что она забуферирует данные в таких случаях и, в свою очередь, вызовет функцию dummy_flash_write_oneword() для записи 32-х разрядных данных по выровненным 32-х разрядным адресам. Реализацию можно посмотреть в Распечатке 4.3.

 

Функцией стирания, зарегистрированной в ядре MTD, является dummy_flash_erase(). Эта функция должна убедиться, что указанный адрес стирания является выровненным по сектору и количество байт, которое будет стираться, кратно размеру сектора. Внутри вызывается функция dummy_flash_erase_one_block(); она стирает один сектор по указанному адресу. Поскольку стирание сектора занимает много времени, эта функция вытесняет вызывающую задачу, отправляя её в сон на DUMMY_FLASH_ERASE_TIME тиков. По окончании стирания ядро MTD сигнализирует, что стирание завершено, устанавливая  состояние стирания в MTD_ERASE_DONE, а затем перед возвращением выполняются все зарегистрированные обратные вызовы. Реализацию можно посмотреть в Распечатке 4.4.

 

Когда устройство флеш-памяти закрывается, вызывается функция sync. Эта функция должна убедиться, что ни одна из микросхем флеш-памяти не используется на момент закрытия; если же они используются, функция заставляет вызывающий процесс ждать, пока все микросхемы не перейдут в неиспользуемое состояние. Реализацию имитации функции sync можно посмотреть в Распечатке 4.5.

 

В случае, если драйвер флеш-памяти загружен как модуль, вызывается функция dummy_destroy. Функции dummy_destroy()  выполняет все очистку при выгрузке модуля.

 

static void dummy_destroy(struct mtd_info *mtd)

{

  struct dummy_private_info_struct *priv =

                   ((struct map_info *)mtd->priv)->fldrv_priv;

  kfree(priv->chips);

}

 

Следующими являются функции инициализации и выхода.

 

int __init dummy_flash_init(void)

{

  register_mtd_chip_driver(&dummy_chipdrv);

  return 0;

}

void __exit dummy_flash_exit(void)

{

  unregister_mtd_chip_driver(&dummy_chipdrv);

}

 

module_init(dummy_flash_init);

module_exit(dummy_flash_exit);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Embedded Linux book");

MODULE_DESCRIPTION("Sample MTD driver");

 

Предыдущая  Содержание  Следующая