sceletonfb.c |
Содержание Следующая |
/* * 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");
|
Содержание Следующая |