sceletonfb.c

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

/*

 * linux/drivers/video/skeletonfb.c -- скелет для устройства с кадровым буфером

 *

 *  Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com)

 *

 *  Created 28 Dec 1997 by Geert Uytterhoeven

 *

 *

 *  Я начал переписывать этот драйвер в качестве примера развития нового API.

 *  Основной целью является удалить код консоли из fbdev и поместить его

 *  в fbcon.c. Это сокращает код и делает написание нового драйвера fbdev

 *  простым, так как автору не нужно беспокоиться о внутренностях консоли. Это

 *  также позволяет запускать fbdev без системы консоли/терминала поверх

 *  него.

 *

 *  Первоначальные роли структур fb_info и display изменились. Структура display

 *  исчезнет. Способ, которым будет работать код новой консоли с кадровым буфером,

 *  заключается в том, что он будет воздействовать на передачу данных от терминала/

 *  консоли в структуре vc_data в аппаратно-независимые данные в структуре fb_info.

 *  Затем для сохранения устройство-зависимого состояния в аналогичном поле

 *  в структуре fb_info и изменения состояния оборудования для соответствия этому

 *  состоянию будут вызываться разные функции в структуре fb_ops. Это позволяет

 *  очень точно отделить слой fbdev от слоя консоли. Это также позволяет

 *  использовать fbdev отдельно, что является бонусом для встраиваемых устройств.

 *  Причиной, по которой такой подход работает, является то, что для каждого

 *  устройства с кадровым буфером при использовании в качестве терминального/

 *  консольного устройства к нему выделяется набор виртуальных терминалов. Для

 *  каждого устройства с кадровым буфером может быть активен только один

 *  виртуальный терминал. У нас уже есть все данные, необходимые нам, в структуре

 *  vc_data, так зачем в каждом виртуальном терминале хранить кучу цветовых схем

 *  и других специфичных данных для fbdev.

 *

 *  Как можно увидеть, это делает параметр con, в значительный степени бесполезный

 *  для структуры функций fb_ops, как это и должно быть. Кроме того, наличие в

 *  fb_info структуры fb_var_screeninfo и других данных почти исключает

 *  необходимость в get_fix и get_var. После того, как все драйверы начнут

 *  использовать fix, var и cmap, fbcon можно написать с использованием этих полей.

 *  Это также избавит от необходимости восстанавливать структуры fb_var_screeninfo,

 *  fb_fix_screeninfo и fb_cmap каждый раз при вызове функций get_var, get_fix,

 *  get_cmap, как это делают сейчас многие драйверы.

 *

 *  Этот файл подчиняется условиям использования GNU General Public License.

 *  Для подробностей смотрите файл COPYING в основном каталоге этого архива.

 */

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/errno.h>

#include <linux/string.h>

#include <linux/mm.h>

#include <linux/slab.h>

#include <linux/delay.h>

#include <linux/fb.h>

#include <linux/init.h>

#include <linux/pci.h>

 

    /*

     *  Это всего лишь простой пример кода.

     *

     *  Нет гарантии, что он скомпилируется.

     *  Ещё меньше гарантий, что он заработает :-)

     */

 

/*

 * Данные драйвера

 */

static char *mode_option __devinitdata;

 

/*

 *  Если ваш драйвер поддерживает несколько плат, вы должны сделать ниже

 *  массивы с необходимыми типами данных, или создать их динамически

 *  (используя kmalloc()).

 */ 

 

/* 

 * Эта структура определяет состояние оборудования графической видеокарты.

 * Обычно это размещается в файле заголовка в linux/include/video. Этот файл

 * обычно также включает информацию о регистрах. Это позволяет другим

 * драйверным подсистемам и приложениям пользовательского пространства

 * использовать один и тот же заголовочный файл, чтобы избежать двойной

 * работы и упростить переносимость программного обеспечения.

 */

struct xxx_par;

 

/*

 * Здесь определяется значение по умолчанию для структур fb_fix_screeninfo и

 * fb_var_screeninfo, если не используется modedb. Если modedb действительно

 * используется, как использовать его, чтобы получить fb_var_screeninfo,

 * смотрите xxxfb_init. В противном случае определите переменную по умолчанию

 * также.

 */

static struct fb_fix_screeninfo xxxfb_fix __devinitdata = {

    .id =        "FB's name", 

    .type =      FB_TYPE_PACKED_PIXELS,

    .visual =    FB_VISUAL_PSEUDOCOLOR,

    .xpanstep =  1,

    .ypanstep =  1,

    .ywrapstep = 1, 

    .accel =     FB_ACCEL_NONE,

};

 

    /*

     *  Современные графические аппаратные средства не только поддерживают

     *  конвейеры, некоторые также поддерживают несколько мониторов, где

     *  у каждого дисплея могут быть собственные уникальные данные. В этом

     *  случае каждый дисплей мог бы быть представлен отдельным устройством

     *  с кадровым буфером, то есть с отдельной структурой fb_info.

     *  Сейчас структура xxx_par представляет состояние графического

     *  оборудования таким образом, что на каждую карту существует только

     *  одна. В данном случае структура xxx_par для каждой видеокарты была

     *  бы общей для всех структур fb_info, которые представляют кадровый

     *  буфер такой платы. Когда один дисплей изменяет свои параметры

     *  разрешения (info->var), это позволяет другим дисплеям узнать об этом

     *  немедленно. Каждый дисплей может всегда узнать о состоянии всего

     *  оборудования, которое его затрагивает, потому что они совместно

     *  используют одну и ту же структуру xxx_par. Другая сторона монеты

     *  - несколько видеокарт, которые раздают данные, пока они наконец

     *  не отображены на одном мониторе. Примерами этого являются карты

     *  Voodoo 1 и мощные серверы графики с NUMA. Для этого случая у нас

     *  есть куча структур par, каждая из которых представляет состояние

     *  графики, которая принадлежит одной структуре fb_info. В этом случае

     *  Вы бы захотели иметь *par, указывающий на массив состояний

     *  устройств и иметь отдельную структуру функций fb_ops, чтобы иметь

     *  дело со всеми этими состояниями. Я надеюсь, что это покрывает все

     *  возможные варианты дизайна оборудоания. Если нет, посылайте не

     *  стесняясь ваши идеи на jsimmons@users.sf.net

     */

 

    /*

     *  Если ваш драйвер поддерживает несколько плат, или поддерживает

     *  несколько кадровых буферов, вы должны создать эти массивы или

     *  получить их динамически используя framebuffer_alloc() и освободить

     *  их с помощью framebuffer_release().

     */ 

static struct fb_info info;

 

    /* 

     * Каждая представляет собой состояние оборудования. У большинства

     * оборудования есть только одно состояние. Здесь представлено

     * заданное по умолчанию состояние(я).

     */

static struct xxx_par __initdata current_par;

 

int xxxfb_init(void);

 

/**

 *    xxxfb_open - Необязательная функция. Вызывается при первом обращении

 *                 к кадровому буферу.

 *    @info: структура кадрового буфера, которая представляет собой один 

 *            кадровый буфер.

 *    @user: сообщает, кто обращается к буферу, пользовательское

 *            пространство (значение=1), или консоль.

 *

 *    Эта функция является первой функцией, вызываемой в api кадрового

 *    буфера. Обеспечивать эту функцию обычно нет необходимости. Случаем,

 *    когда она используется, является смена тестового режима оборудования

 *    на графический режим. 

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_open(struct fb_info *info, int user)

{

    return 0;

}

 

/**

 *    xxxfb_release - Необязательная функция. Вызывается при закрытии

 *                устройства с кадровым буфером. 

 *    @info: структура кадрового буфера, которая представляет собой один 

 *            кадровый буфер.

 *    @user: сообщает, кто обращается к буферу, пользовательское

 *            пространство (значение=1), или консоль.

 *

 *    Эта функция вызывается при закрытии /dev/fb или при отключении

 *    консольной системы с кадровым буфером. Обычно в этой функции нет

 *    необходимости. Случаем, когда она обычно используется, является

 *    переход из графического в текстовый режим.

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_release(struct fb_info *info, int user)

{

    return 0;

}

 

/**

 *    xxxfb_check_var - Необязательная функция. Проверяет переданную в

 *                    неё var. 

 *    @var: переменная кадрового буфера экранной структуры

 *    @info: структура кадрового буфера, представляющая один кадровый буфер 

 *

 *    Выясняет, поддерживает ли оборудование состояние, которое затребовано

 *    переданной в неё переменной var. Эта функция не изменяет состояние

 *    оборудования!!! Это означает, что данные, хранящиеся в структурах

 *    fb_info и xxx_par, не изменяются. Это включает и переменную var в

 *    структуре fb_info. НЕ изменяйте их. Эта функция может быть вызвана

 *    самостоятельно, если мы намерены только проверить режим, а не

 *    фактически установить его. Материал в modedb.c - пример этого. Если

 *    переданная переменная var немного за пределами того, что может

 *    поддержать оборудование, мы изменяем эту ПЕРЕДАВАЕМУЮ переменную var,

 *    на то, что может быть выполнено.

 *

 *    Для значений, которые вне пределов, эта функция должен округлить их

 *    _вверх_ до следующего значения, поддерживаемого оборудованием. Если

 *    значение больше, чем самое высокое значение, поддерживаемое

 *    оборудованием, эта функция должна возвратить -EINVAL.

 *

 *    Исключение к вышеупомянутому правилу: некоторые драйверы имеют

 *    фиксированный режим, то есть оборудование уже проинициализировано при

 *    загрузке и он не может быть изменён. В этом случае более приемлемо,

 *    чтобы эта функция только возвращала копию используемой в настоящее

 *    время рабочей переменной var (info->var). Лучше не реализовывать эту

 *    функцию, поскольку верхний уровень сделает копирование текущей

 *    переменной var за вас.

 *

 *    Замечание: это единственная функция, где содержание var может быть

 *    свободно откорректировано после того, как драйвер был зарегистрирован.

 *    Если вы находите, что у вас есть код за пределами этой функции,

 *    который изменяет содержание var, то вы делаете что-то не так.

 *    Обратите внимание также, что содержание info->var должно оставаться

 *    нетронутым всё время после регистрации драйвера.

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)

{

    /* ... */

    return 0;                   

}

 

/**

 *    xxxfb_set_par - Необязательная функция. Изменяет состояние оборудования.

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *

 *    Используя fb_var_screeninfo в fb_info мы устанавливаем разрешение этого

 *    конкретного кадрового буфера. Эта функция изменяет par И fb_fix_screeninfo,

 *    сохранённый в fb_info. Это не изменяет var в fb_info, так как мы

 *    используем эти данные. Это означает, что мы зависим от данных в var

 *    внутри fb_info, чтобы быть поддержанными оборудованием.

 *

 *    Эта функция также используется, чтобы возвратить/восстановить оборудование

 *    в известное рабочее состояние.

 *

 *    Перед xxxfb_set_par всегда вызывается xxxfb_check_var, для уверенности,

 *    что содержимое var всегда корректно.

 *

 *    И снова, если изменить разрешение нельзя, в этой функции нет необходимости.

 *

 *    Однако, даже если ваше оборудование не поддерживает изменение режима,

 *    set_par мог бы быть необходим, чтобы по крайней мере проинициализировать

 *    оборудование в известное рабочее состояние, особенно, если бы это

 *    происходило при возвращении из другого процесса, который также изменяет это

 *    же самое оборудование, такого, как X.

 *

 *    Если дело обстоит таким образом, должна работать следующая комбинация:

 *

 *    static int xxxfb_check_var(struct fb_var_screeninfo *var,

 *                               struct fb_info *info)

 *    {

 *        *var = info->var;

 *        return 0;

 *    }

 *

 *    static int xxxfb_set_par(struct fb_info *info)

 *    {

 *        инициализируйте здесь ваше оборудование

 *    }

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_set_par(struct fb_info *info)

{

    struct xxx_par *par = info->par;

    /* ... */

    return 0;        

}

 

/**

 *    xxxfb_setcolreg - Необязательная функция. Устанавливает регистр цвета.

 *    @regno: Какой регистр в CLUT (таблица цветов) программируется.

 *    @red: Значение красного, которое может быть до 16 бит.

 *    @green: Значение зелёного, которое может быть до 16 бит.

 *    @blue: Значение синего, которое может быть до 16 бит.

 *    @transp: Значение альфа-канала, если поддерживается, может быть до 16 бит.

 *    @info: структура с информацией о кадровом буфере.

 *

 *    Устанавливает единственный регистр цвета. Поддерживаемые значения

 *    имеют размерность в 16 бит, которую необходимо отмасштабировать в этой

 *    функции для данного оборудования. Необходимо учесть, сколько регистров

 *    цвета, если таковые вообще имеются, поддерживаются текущей визуализацией

 *    цвета. В режиме truecolor никакие цветовые палитры не поддерживаются.

 *    Здесь создаётся псевдо палитра, для которой мы сохраняем значение в

 *    pseudo_palette в структуре fb_info. Для режима pseudocolor у нас

 *    есть ограниченная цветовая палитра. Чтобы иметь дело с этим, мы можем

 *    запрограммировать, какой цвет отображается для специфического значения

 *    пикселя. DirectColor аналогичен тому, в котором мы можем программировать

 *    каждое цветовое поле. Если у нас есть статическая цветовая таблица,

 *    реализовывать эту функцию нет необходимости.

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,

                           unsigned blue, unsigned transp,

                           struct fb_info *info)

{

    if (regno >= 256)    /* номера аппаратных регистров */

        return -EINVAL;

    /*

     * Программируем оборудование... делаем всё, что хотим

     */

 

    /* в directcolor оттенки серого работают лишь частично */

    if (info->var.grayscale) {

       /* grayscale = 0.30*R + 0.59*G + 0.11*B */

       red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;

    }

 

    /* Directcolor:

     *    var->{color}.offset содержит начало битового поля

     *    var->{color}.length содержит длину битового поля

     *    {зависит от обрудования} содержит разрядность ЦАП

     *    pseudo_palette[X] программируется в (X << red.offset) |

     *                                      (X << green.offset) |

     *                                      (X << blue.offset)

     *    RAMDAC[X] программируется в (red, green, blue)

     *    глубина цвета = SUM(var->{color}.length)

     *

     * Pseudocolor:

     *    var->{color}.offset 0, если индекс палитры занимает меньше,

     *                        чем bits_per_pixel бит и хранится в старших

     *                        битах значения пикселя

     *    var->{color}.length устанавливается так, что 1 << length является

     *                        числом доступных в палитре записей

     *    pseudo_palette не используется

     *    RAMDAC[X] программируется в (red, green, blue)

     *    глубина цвета = var->{color}.length

     *

     * Static pseudocolor:

     *    так же как Pseudocolor, но RAMDAC не программируется (только читается)

     *

     * Mono01/Mono10:

     *    Имеет только 2 значения, чёрный на белом или белый на чёрном (fg на bg),

     *    var->{color}.offset равен 0

     *    white = (1 << var->{color}.length) - 1, black = 0

     *    pseudo_palette не используется

     *    RAMDAC не существует

     *    глубина цвета всегда 2

     *

     * Truecolor:

     *    does not use RAMDAC (usually has 3 of them).

     *    var->{color}.offset contains start of bitfield

     *    var->{color}.length contains length of bitfield

     *    pseudo_palette программируется в (red << red.offset) |

     *                                    (green << green.offset) |

     *                                    (blue << blue.offset) |

     *                                    (transp << transp.offset)

     *    RAMDAC не существует

     *    глубина цвета = SUM(var->{color}.length)

     *

     *  Глубина цвета используется fbcon для выбора логотипа, а также

     *  для преобразования цветовой палитры, если глубина цвета < 4.

     *

     *  Как видно из сказанного выше, поле bits_per_pixel _НЕ_ является

     *  критерием для описания видимого цвета.

     *

     *  Распространённой ошибкой является предположение, что

     *  bits_per_pixel <= 8 представляет собой pseudocolor, а выше, чем это,

     *  true/directcolor. Это неправильно, надо смотреть на fix->visual.

     *

     *  Другой распространённой ошибкой является использование bits_per_pixel

     *  для расчёта глубины цвета. Поле bits_per_pixel не перевести

     *  непосредственно в глубину цвета. Необходимы вычисления для глубины

     *  цвета (с помощью цветовых битовых полей) и fix->visual, как показано

     *  выше.

     */

 

    /*

     * Это та точка, где цвет превращается во что-то, понятное оборудованию.

     */

#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)

    red = CNVT_TOHW(red, info->var.red.length);

    green = CNVT_TOHW(green, info->var.green.length);

    blue = CNVT_TOHW(blue, info->var.blue.length);

    transp = CNVT_TOHW(transp, info->var.transp.length);

#undef CNVT_TOHW

    /*

     * Это та точка, где эта функция загружает цвет в палитру оборудования

     * после преобразования цветов к чему-то понятному оборудованию.

     * Обратите внимание, только в режимах FB_VISUAL_DIRECTCOLOR и

     * FB_VISUAL_PSEUDOCOLOR необходимо писать в аппаратную палитру.

     * Если у вас есть код, который пишет в аппаратную CLUT (таблицу цветов),

     * и это не один из вышеприведённых режимов, вы делаете что-то неправильно.

     */

    if (info->fix.visual == FB_VISUAL_DIRECTCOLOR ||

        info->fix.visual == FB_VISUAL_TRUECOLOR)

        write_{red|green|blue|transp}_to_clut();

 

    /*

     * Именно на этом этапе было необходимо заполнить содержание

     * info->pseudo_palette. Эта структура используется _только_ в fbcon,

     * так что она содержит только 16 записей в соответствии с числом цветов,

     * поддерживаемых консолью. pseudo_palette используется только тогда,

     * когда визуализация происходит в режиме directcolor или truecolor.

     * В других режимах визуализации pseudo_palette не используется.

     * (Это может измениться в будущем.)

     *

     * Содержание pseudo_palette представляет собой необработанный формат

     * пиксела. То есть каждая запись может быть записана непосредственно в

     * кадровый буфер без какого-либо преобразования. pseudo_palette является

     * (void *). Тем не менее, при использовании общих функций рисования

     * (cfb_imageblit, cfb_fillrect), pseudo_palette должна быть приведена к

     * (u32 *) _независимо_ от числа битов на пиксель. Если драйвер использует

     * свои собственные функции рисования, то он может использовать любую

     * размерность, какую хочет.

     */

    if (info->fix.visual == FB_VISUAL_TRUECOLOR ||

        info->fix.visual == FB_VISUAL_DIRECTCOLOR) {

        u32 v;

 

        if (regno >= 16)

            return -EINVAL;

 

        v = (red << info->var.red.offset) |

            (green << info->var.green.offset) |

            (blue << info->var.blue.offset) |

            (transp << info->var.transp.offset);

 

        ((u32*)(info->pseudo_palette))[regno] = v;

    }

 

    /* ... */

    return 0;

}

 

/**

 *    xxxfb_pan_display - НЕ обязательная функция. Панорамирует дисплей.

 *    @var: переменная кадрового буфера экранной структуры

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *

 *    Панорамирование (или прокрутка, зависит от поля `vmode') дисплея,

 *    используя поля `xoffset' и `yoffset' в структуре `var'.

 *    Если значения не соответствующие, возвращает -EINVAL.

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

static int xxxfb_pan_display(struct fb_var_screeninfo *var,

                             struct fb_info *info)

{

    /*

     * Если ваше оборудование не поддерживает панорамирование, _не_

     * реализуйте эту функцию. Создание пустой функции только запутает

     * пользовательские приложения.

     */

 

    /*

     * Заметим, что даже если эта функция является полнофункциональной,

     * значение 0 в обоих xpanstep и ypanstep означает, что эта функция

     * никогда не будет вызвана.

     */

 

    /* ... */

    return 0;

}

 

/**

 *    xxxfb_blank - НЕ обязательная функция. Гашение дисплея.

 *    @blank_mode: желаемый режим гашения. 

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *

 *    Экран гасится, если blank_mode != FB_BLANK_UNBLANK, иначе не гасится.

 *    Возвращает 0, если гашение успешно, != 0, если не/гашение неудачно,

 *    так как видеорежим не поддерживается.

 *

 *    Реализует режимы VESA для приостановки и выключения питания

 *    оборудования, поддерживающем отключение вертикальной и горизонтальной

 *    синхронизации:

 *

 *    FB_BLANK_NORMAL = дисплей погашен, синхронизация работает.

 *    FB_BLANK_HSYNC_SUSPEND = выключена горизонтальная синхронизация.

 *    FB_BLANK_VSYNC_SUSPEND = выключена вертикальная синхронизация.

 *    FB_BLANK_POWERDOWN = горизонтальная и вертикальная синхронизация выключена.

 *

 *    Если эта функция реализуется, по крайней мере поддержите FB_BLANK_UNBLANK.

 *    Верните !0 для всех режимов, которые не реализованы.

 *

 */

static int xxxfb_blank(int blank_mode, struct fb_info *info)

{

    /* ... */

    return 0;

}

 

/* ----------------- Функции ускорения --------------------- */

 

/*

 * Мы предоставляем свои функции, если у нас есть аппаратное ускорение

 * или схемы размещения пикселей в неупакованном формате. Если у нас

 * нет аппаратного ускорения, мы можем использовать общие функции

 * без акселерации. Если используется формат упакованных пикселей,

 * просто используйте функции в cfb_*.c. Каждый файл имеет одну из

 * трёх различных функций ускорения, которые мы поддерживаем.

 */

 

/**

 *    xxxfb_fillrect - ОБЯЗАТЕЛЬНАЯ функция. Если оборудование не

 *                    поддерживает ускорение и используются упакованные

 *                    пиксели, можно использовать стандартные подпрограммы.

 *                    Рисует на экране прямоугольник.

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *    @region: структура, представляющая прямоугольную область, которую мы

 *            желаем отрисовать.

 *

 *    Она выполняет операцию по отрисовке для размещения/удаления на экране

 *    прямоугольника в зависимости от операции растеризации со значением

 *    цвета в формате текущей глубины цвета.

 */

void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)

{

/*    Содержание структуры fb_fillrect

 *

 *    @dx: x и y координаты верхнего левого угла

 *    @dy: области, которую мы хотим отрисовать.

 *    @width: Ширина прямоугольника, который мы хотим нарисовать.

 *    @height: Высота прямоугольника, который мы хотим нарисовать.

 *    @color:        Цвет заполнения прямоугольника.

 *    @rop: Операция растеризации. Мы можем рисовать прямоугольник с помощью

 *            COPY или XOR, предоставляющий эффект стирания. 

 */

}

 

/**

 *    xxxfb_copyarea - ОБЯЗАТЕЛЬНАЯ функция. Если оборудование не

 *                    поддерживает ускорение и используются упакованные

 *                    пиксели, можно использовать стандартные подпрограммы.

 *                    Копирует одну область экрана в другую.

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *    @area: Структура, представляющая данные для копирования

 *            содержимого кадрового буфера из одной области в другую.

 *

 *    Этот операция отрисовки копирует прямоугольную область из одного места

 *    экрана в другое.

 */

void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 

{

/*

 *    @dx: x и y координаты верхнего левого угла

 *    @dy: области, которую мы хотим отрисовать.

 *    @width: Ширина прямоугольника, который мы хотим нарисовать.

 *    @height: Высота прямоугольника, который мы хотим нарисовать.

 *    @sx: x и y координаты верхнего левого угла

 *    @sy: области источника на экране.

 */

}

 

/**

 *    xxxfb_imageblit - ОБЯЗАТЕЛЬНАЯ функция. Если оборудование не

 *                    поддерживает ускорение и используются упакованные

 *                    пиксели, можно использовать стандартные подпрограммы.

 *                    Копирует изображение из системной памяти на экран. 

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *    @image: структура, описывающая изображение.

 *

 *    Эта операция отрисовки орисовывает на экране изображение. Это может быть

 *    моно-изображение (требуется для обработки шрифтов) или цветное изображение

 *    (требуется для пингвина).

 */

void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) 

{

/*

 *    @dx: x и y координаты верхнего левого угла области назначения

 *    @dy: для размещения картинки на экране.

 *    @width: Ширина изображения, которое мы хотим скопировать.

 *    @height: Высота изображения, которое мы хотим скопировать.

 *    @fg_color: Для двуцветных битовых изображений это данные о цвете для

 *    @bg_color: фона и изображения картинки для записи непосредственно в

 *                кадровый буфер.

 *    @depth: Сколько бит представляют один пиксель этого изображения.

 *    @data: Фактические данные, используемые для построения картинки на дисплее.

 *    @cmap: Цветовая таблица, используемая для цветных изображений.

 */

 

/*

 * Универсальная функция, cfb_imageblit, ожидает, что строки битовых полей

 * являются выровненными на следующем байте. Большинство аппаратных ускорителей

 * могут требовать выравнивания к следующему u16 или следующему u32. Если это

 * так, драйвер может указать это, установив info->pixmap.scan_align = 2 или 4.

 * Смотрите более подробное описание работы с растровым изображением ниже.

 */

}

 

/**

 *    xxxfb_cursor - НЕОБЯЗАТЕЛЬНА. Если ваше оборудование не имеет

 *                поддержки курсора, оставьте это поле NULL.

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *    @cursor: структура, описывающая курсор для отрисовки.

 *

 *    Эта операция используется для установки или изменения свойств курсора.

 *

 *    Возвращает отрицательное значение при ошибке или ноль при

 *    успешном завершении.

 */

int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)

{

/*

 *    @set: Какие поля мы изменяем в структуре fb_cursor 

 *    @enable: Отключаем или включаем курсор.

 *    @rop: Битовая операция, которую мы хотим выполнить.

 *    @mask: Это битовая маска курсора.

 *    @dest: Изображение области, где мы собираемся отобразить курсор.

 *            Используется драйвером для внутренних целей.

 *    @hot: Горячая точка (точка, куда показывает курсор). 

 *    @image: Фактические данные для изображения курсора.

 *

 *    ЗАМЕЧАНИЯ О ФЛАГАХ (cursor->set):

 *

 *    FB_CUR_SETIMAGE - изменилось изображение курсора (cursor->image.data)

 *    FB_CUR_SETPOS   - изменилась позиция курсора (cursor->image.dx|dy)

 *    FB_CUR_SETHOT   - изменилась точка указания курсора (cursor->hot.dx|dy)

 *    FB_CUR_SETCMAP  - изменились цвета курсора (cursor->fg_color|bg_color)

 *    FB_CUR_SETSHAPE - изменилось битовая маска курсора (cursor->mask)

 *    FB_CUR_SETSIZE  - изменился размер курсора (cursor->width|height)

 *    FB_CUR_SETALL   - изменилось всё

 *

 *    ЗАМЕЧАНИЯ О БИТОВЫХ ОПЕРАЦИЯХ (cursor->rop, Операция Растеризации)

 *

 *    ROP_XOR         - cursor->image.data XOR cursor->mask

 *    ROP_COPY        - curosr->image.data AND cursor->mask

 *

 *    ДРУГИЕ ЗАМЕЧАНИЯ:

 *

 *    - fbcon поддерживает только 2-х цветный курсор (cursor->image.depth = 1)

 *    - Структура fb_cursor, @cursor, _будет_ всегда содержать достоверные

 *        поля, независимо от того, установлены или нет любые битовые поля

 *        в cursor->set.

 */

}

 

/**

 *    xxxfb_rotate -  НЕ обязательная функция. Если ваше оборудование

 *                поддерживает поворот целого экрана, вам стоит предоставить

 *                метод для этого.

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *    @angle: Угол поворота экрана.   

 *

 *    Эта операция используется для установки или изменения свойств курсора.

 */

void xxxfb_rotate(struct fb_info *info, int angle)

{

    /* Будет исключена */

}

 

/**

 *    xxxfb_sync - НЕ обязательная функция. Обычно ускоритель видеокарты

 *                требует определённого количества времени. Часто необходимо

 *                ждать, чтобы ускоритель завершил свою работу, прежде чем

 *                мы сможем записать кадровый буфер, чтобы иметь

 *                последовательный вывод на дисплей.

 *

 *    @info: структура кадрового буфера, представляющая один кадровый буфер.

 *

 *    Если драйвер реализует собственную функцию отрисовки, базирующуюся на

 *    возможностях оборудования, реализация этой функции настоятельно

 *    рекомендуется.

 */

int xxxfb_sync(struct fb_info *info)

{

    return 0;

}

 

    /*

     *  Операции кадрового буфера

     */

 

static struct fb_ops xxxfb_ops = {

    .owner           = THIS_MODULE,

    .fb_open         = xxxfb_open,

    .fb_read         = xxxfb_read,

    .fb_write        = xxxfb_write,

    .fb_release      = xxxfb_release,

    .fb_check_var    = xxxfb_check_var,

    .fb_set_par      = xxxfb_set_par,

    .fb_setcolreg    = xxxfb_setcolreg,

    .fb_blank        = xxxfb_blank,

    .fb_pan_display  = xxxfb_pan_display,

    .fb_fillrect     = xxxfb_fillrect,    /* Необходимо !!! */

    .fb_copyarea     = xxxfb_copyarea,    /* Необходимо !!! */

    .fb_imageblit    = xxxfb_imageblit,   /* Необходимо !!! */

    .fb_cursor       = xxxfb_cursor,      /* Необязательно !!! */

    .fb_rotate       = xxxfb_rotate,

    .fb_sync         = xxxfb_sync,

    .fb_ioctl        = xxxfb_ioctl,

    .fb_mmap         = xxxfb_mmap,

};

 

/* ------------------------------------------------------------------------- */

 

    /*

     *  Инициализация

     */

 

/* static int __init xxfb_probe (struct platform_device *pdev) -- для разработчиков платформ */

static int __devinit xxxfb_probe(struct pci_dev *dev,

                                 const struct pci_device_id *ent)

{

    struct fb_info *info;

    struct xxx_par *par;

    struct device *device = &dev->dev; /* или &pdev->dev */

    int cmap_len, retval;        

 

    /*

     * Динамическое выделение памяти для info и par

     */

    info = framebuffer_alloc(sizeof(struct xxx_par), device);

 

    if (!info) {

        /* идём по пути ошибок */

    }

 

    par = info->par;

 

    /* 

     * Здесь мы устанавливаем screen_base для кадрового буфера

     * на адрес в виртуальной памяти. Как правило, мы получаем

     * адрес ресурса от уровня шины, а затем переводим его в

     * пространство виртуальной памяти с помощью ioremap.

     * Примите во внимание ioport.h.

     */

    info->screen_base = framebuffer_virtual_memory;

    info->fbops = &xxxfb_ops;

    info->fix = xxxfb_fix; /* это будет единственным разом, когда

                    * будет использоваться xxxfb_fix, поэтому помечаем

                    * его как __devinitdata

                    */

    info->pseudo_palette = pseudo_palette; /* Псевдопалитра - это

                            * массив из 16-ти элементов

                            */

    /*

     * Установка флагов, чтобы указать, какие виды ускорения может

     * предоставить ваш драйвер (pan/wrap/copyarea/и так далее.) и

     * является ли он модулем -- смотрите FBINFO_* в include/linux/fb.h

     *

     * Если ваше оборудование может поддержать любую из функций с

     * аппаратным ускорением, производительность fbcon увеличится, если

     * соответствующим образом установить info->flags.

     *

     * FBINFO_HWACCEL_COPYAREA - оборудование двигает области

     * FBINFO_HWACCEL_FILLRECT - оборудование заливает прямоугольники

     * FBINFO_HWACCEL_IMAGEBLIT - аппаратное расширение mono->color

     * FBINFO_HWACCEL_YPAN - оборудование может панорамировать дисплей по оси y

     * FBINFO_HWACCEL_YWRAP - оборудование может прокручивать дисплей по оси y

     * FBINFO_HWACCEL_DISABLED - аппаратное ускорение поддерживается, но запрещено

     * FBINFO_READS_FAST - если установлен, предпочтение работы через расширение mono->color

     * FBINFO_MISC_TILEBLITTING - оборудование может делать копирование элементов

     *                            мозаичного изображения

     *

     * ПРИМЕЧАНИЕ: Это только для использования в fbcon.

     */

    info->flags = FBINFO_DEFAULT;

 

/********************* Этот этап является необязательным ***************************/

    /*

     * Структура pixmap - это рабочая область для функций отрисовки. Это

     * то, где высокими уровнями создаётся монохромное битовое изображение

     * и затем передаётся ускорителю. Если драйвер использует

     * cfb_imageblit, можно пропустить эту часть. Для тех, кто имеет более

     * строгие требования, этот этап необходим.

     */

 

    /* 

     * PIXMAP_SIZE должен быть достаточно небольшим, чтобы оптимизировать отрисовку,

     * но не слишком большой, чтобы впустую расходовать память. Безопасный размер

     * это (max_xres * max_font_height/8). max_xres зависит от драйвера,

     * max_font_height равно 32.

     */

    info->pixmap.addr = kmalloc(PIXMAP_SIZE, GFP_KERNEL);

    if (!info->pixmap.addr) {

        /* переход по ошибке */

    }

 

    info->pixmap.size = PIXMAP_SIZE;

 

    /*

     * FB_PIXMAP_SYSTEM - память в системном ОЗУ

     * FB_PIXMAP_IO     - память является отображённой на пространство ввода-вывода

     * FB_PIXMAP_SYNC   - если установлен, для доступа к pixmap будем вызывать

     *                    fb_sync(), обычно это происходит, если установлен FB_PIXMAP_IO.

     *

     * Сейчас FB_PIXMAP_IO не реализован.

     */

    info->pixmap.flags = FB_PIXMAP_SYSTEM;

 

    /*

     * scan_align это число для выравнивания каждой строки сканирования. Оно в байтах.

     * Таким образом для ускорителей, которым необходимо выравнивание к следующему,

     * установите здесь 4.

     */

    info->pixmap.scan_align = 4;

 

    /*

     * buf_align это число для выравнивания буфера. Например, для i810fb необходимо

     * scan_align равный 2, но ожидается работа с dwords, так что требуется

     * buf_align = 4.

     */

    info->pixmap.buf_align = 4;

 

    /* access_align - как много битов можно получить из кадрового буфера,

     * например, некоторые карты от epson разрешают только 16-ти битный доступ.

     * Большинство драйверов будут безопасно работать при параметре u32.

     *

     * ЗАМЕЧАНИЕ: Это поле в настоящее время не используется.

     */

    info->pixmap.access_align = 32;

/********************* Конец необязательного этапа ************************/

 

    /*

     * Должен быть задан разумный режим по умолчанию для видео. Это потребуется,

     * когда мы сможем установить режим видео. 

     */

    if (!mode_option)

        mode_option = "640x480@60";

 

    retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);

  

    if (!retval || retval == 4)

        return -EINVAL;

 

    /* Это должно быть сделано! */

    if (fb_alloc_cmap(&info->cmap, cmap_len, 0))

        return -ENOMEM;

 

    /* 

     * Это выполняется в случае, если имеется оборудование со статическим

     * режимом. Если мы устанавливаем режим самостоятельно, мы не вызываем это.

     */        

    info->var = xxxfb_var;

 

    /*

     * Для драйверов, которые могут это...

     */

    xxxfb_check_var(&info->var, info);

 

    /*

     * Необходим ли вызов fb_set_par() перед register_framebuffer? Это

     * будет зависеть от вас и оборудования. Если вы уверены, что ваш драйвер

     * является в системе только устройством, вызов fb_set_par() безопасен.

     *

     * Оборудование в x86 системах имеет ядро VGA. Вызов set_par() в этом

     * месте повредит VGA консоль, поэтому безопаснее пропустить здесь вызов

     * set_par и просто позволить fbcon сделать это за вас.

     */

    /* xxxfb_set_par(info); */

 

    if (register_framebuffer(info) < 0) {

        fb_dealloc_cmap(&info->cmap);

        return -EINVAL;

    }

    printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,

            info->fix.id);

    pci_set_drvdata(dev, info); /* или platform_set_drvdata(pdev, info) */

    return 0;

}

 

    /*

     *  Очистка

     */

/* static void __devexit xxxfb_remove(struct platform_device *pdev) */

static void __devexit xxxfb_remove(struct pci_dev *dev)

{

    struct fb_info *info = pci_get_drvdata(dev);

    /* или platform_get_drvdata(pdev); */

 

    if (info) {

        unregister_framebuffer(info);

        fb_dealloc_cmap(&info->cmap);

        /* ... */

        framebuffer_release(info);

    }

}

 

#ifdef CONFIG_PCI

#ifdef CONFIG_PM

/**

 *    xxxfb_suspend - Необязательная, но рекомендуемая функция.Приостановка

 *                    работы устройства.

 *    @dev: PCI устройство

 *    @msg: код события приобстановки.

 *

 *    Для большей информации смотрите Documentation/power/devices.txt

 */

static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)

{

    struct fb_info *info = pci_get_drvdata(dev);

    struct xxxfb_par *par = info->par;

 

    /* приостанавливаем работу устройства здесь */

    return 0;

}

 

/**

 *    xxxfb_resume - Необязательная, но рекомендуемая функция. Возобновление

 *                    работы устройства.

 *    @dev: PCI устройство

 *

 *    Для большей информации смотрите Documentation/power/devices.txt

 */

static int xxxfb_resume(struct pci_dev *dev)

{

    struct fb_info *info = pci_get_drvdata(dev);

    struct xxxfb_par *par = info->par;

 

    /* восстанавливаем работу устройства здесь */

    return 0;

}

#else

#define xxxfb_suspend NULL

#define xxxfb_resume NULL

#endif /* CONFIG_PM */

 

static struct pci_device_id xxxfb_id_table[] = {

    { PCI_VENDOR_ID_XXX, PCI_DEVICE_ID_XXX,

      PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,

      PCI_CLASS_MASK, 0 },

    { 0, }

};

 

/* Для драйверов PCI */

static struct pci_driver xxxfb_driver = {

    .name     = "xxxfb",

    .id_table = xxxfb_id_table,

    .probe    = xxxfb_probe,

    .remove   = __devexit_p(xxxfb_remove),

    .suspend  = xxxfb_suspend, /* необязательно, но рекомендуется */

    .resume   = xxxfb_resume,  /* необязательно, но рекомендуется */

};

 

MODULE_DEVICE_TABLE(pci, xxxfb_id_table);

 

int __init xxxfb_init(void)

{

    /*

     *  Для параметров загрузки ядра (в формате 'video=xxxfb:<options>')

     */

#ifndef MODULE

    char *option = NULL;

 

    if (fb_get_options("xxxfb", &option))

        return -ENODEV;

    xxxfb_setup(option);

#endif

 

    return pci_register_driver(&xxxfb_driver);

}

 

static void __exit xxxfb_exit(void)

{

    pci_unregister_driver(&xxxfb_driver);

}

#else /* не PCI, устройства платформы */

#include <linux/platform_device.h>

/* для устройств платформы */

 

#ifdef CONFIG_PM

/**

 *    xxxfb_suspend - Необязательная, но рекомендуемая функция. Приостановка

 *                    работы устройства.

 *    @dev: устройство платформы.

 *    @msg: код события приостановки.

 *

 *    Для большей информации смотрите Documentation/power/devices.txt

 */

static int xxxfb_suspend(struct platform_device *dev, pm_message_t msg)

{

    struct fb_info *info = platform_get_drvdata(dev);

    struct xxxfb_par *par = info->par;

 

    /* приостанавливаем работу устройства здесь */

    return 0;

}

 

/**

 *    xxxfb_resume - Необязательная, но рекомендуемая функция. Возобновление

 *                    работы устройства.

 *    @dev: устройство платформы.

 *

 *    Для большей информации смотрите Documentation/power/devices.txt

 */

static int xxxfb_resume(struct platform_dev *dev)

{

    struct fb_info *info = platform_get_drvdata(dev);

    struct xxxfb_par *par = info->par;

 

    /* восстанавливаем работу устройства здесь */

    return 0;

}

#else

#define xxxfb_suspend NULL

#define xxxfb_resume NULL

#endif /* CONFIG_PM */

 

static struct platform_device_driver xxxfb_driver = {

    .probe = xxxfb_probe,

    .remove = xxxfb_remove,

    .suspend = xxxfb_suspend, /* необязательно, но рекомендуется */

    .resume = xxxfb_resume,   /* необязательно, но рекомендуется */

    .driver = {

    .name = "xxxfb",

    },

};

 

static struct platform_device *xxxfb_device;

 

#ifndef MODULE

    /*

     *  Установка

     */

 

/*

 * Необходимо только если драйвер имеет специальные возможности,

 * в противном случае мы откатываемся к обычному fb_setup().

 */

int __init xxxfb_setup(char *options)

{

    /* Анализ заданных пользователем параметров (`video=xxxfb:') */

}

#endif /* MODULE */

 

static int __init xxxfb_init(void)

{

    int ret;

    /*

     *  Параметры для загрузки ядра (в формате 'video=xxxfb:<options>')

     */

#ifndef MODULE

    char *option = NULL;

 

    if (fb_get_options("xxxfb", &option))

        return -ENODEV;

    xxxfb_setup(option);

#endif

    ret = platform_driver_register(&xxxfb_driver);

 

    if (!ret) {

        xxxfb_device = platform_device_register_simple("xxxfb", 0,

                        NULL, 0);

 

        if (IS_ERR(xxxfb_device)) {

            platform_driver_unregister(&xxxfb_driver);

            ret = PTR_ERR(xxxfb_device);

        }

    }

 

    return ret;

}

 

static void __exit xxxfb_exit(void)

{

    platform_device_unregister(xxxfb_device);

    platform_driver_unregister(&xxxfb_driver);

}

#endif /* CONFIG_PCI */

 

/* ------------------------------------------------------------------------- */

 

 

    /*

     *  Модуляризация

     */

 

module_init(xxxfb_init);

module_exit(xxxfb_remove);

 

MODULE_LICENSE("GPL");

 

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