Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
werter Гость
|
Добавлено: Ср Июн 25 2003 14:38 Заголовок сообщения: Программеры АААААА!!!!! |
|
|
Народ подскажите участок кода для отображения памяти. В драйвере устройства есть буфер. В пользовательско задаче тоже есть подобный буфер. Нужно чтобы пользовательский буфер по указателю работал бы с данными в буфере драйвера. Мне нужен код или перечень функций (или просто хорошая идея) как бы такое сделать как на строне драйвера, так и на стороне пользователя (ядро 2.3.?)
HELP! |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Ср Июн 25 2003 16:53 Заголовок сообщения: А исходники драйвера есть? (-) |
|
|
- |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Чт Июн 26 2003 10:46 Заголовок сообщения: Re: А исходники драйвера есть? (-) ЕСТЬ |
|
|
Пока это не совсем драйвер реального устройства, но тестовый код такой
//Фрагмент кода драйвера:
short driverbuf[256];//буфер данных драйвера ... /* далее функция mmap которая должна отобразить буфер driverbuf на указатель пользовательской программы, чтобы та имела доступ к driverbuf через операции с указателями */ static int drv_mmap(struct file *filp, struct vma_area_struct *vma) { /* Вот здесь и нужно что то сделать чтобы отобразить driverbuf на пользовательскую программу */ return 0; } ...
//Фрагмент кода пользовательской программы void main() { ... fd= open(/dev/mydriver", O_RDWR); ... /* буфер куда планируется отобразить данные драйвера */ short userbuf[256]; //указатель на отображенную область short *pbuf; ... pbuf=(short*) mmap((short*) userbuf, sizeof(userbuf), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd,0); /* Ну и далее типа таких операций pbuf[2]= 0x1234; short datafromdriverbuf= pbuf[2]; */ ... }
В общем все это работает не так как надо. То сигналы всякие вылетают по типу не та область памяти, то параметры mmap задаются неверно (если последний параметр сделать не равным 0), а в коде драйвера размер запрашиваемого прикладной задачей блока всегда равен 4096 байт (ну возможно это условие гранулярности страниц памяти Linux) |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Чт Июн 26 2003 12:55 Заголовок сообщения: Вопрос стал неясным, но попробую. |
|
|
Строки:
>>> static int drv_mmap(struct file *filp, struct vma_area_struct *vma)... >>> pbuf=(short*) mmap((short*) userbuf, sizeof(userbuf), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd,0);
предполагают, что адрес пользовательского буфера попадает в одно из полей переменной *filp (а именно, в первое поле). Кроме того, вероятно, в твоём драйвере есть функции, которые совместно используют буфер
>>> short driverbuf[256];//буфер данных драйвера
иначе зачем он нужен? Если сказанное верно, то твой вопрос звучит так: как сделать, чтобы работа с буфером driverbuf в действительности была работой с переданным из пользовательской функции адресом? Ответ, например, такой: вместо
short driverbuf[256];
написать
short* driverbuf;
а внутри функции
static int drv_mmap(struct file *filp, struct vma_area_struct *vma)...
написать присвоение переменной driverbuf значения из первого поля *filp:
driverbuf = filp->имя_поля;
Тогда все другие функции драйвера будут работать с буфером, который передан из пользовательской функции.
Думаю, идея понятна. |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Чт Июн 26 2003 13:51 Заголовок сообщения: Re: Вопрос стал неясным, но попробую. |
|
|
Я понял, что ты предлагаешь. Спасибо. Действительно с driverbuf[256] в моем драйвере работают еще и read() и write() и ioctl(). Но в драйвере реального устройства driverbuf будет не софтовым буфером, а указателем на физический адрес регистров устройства. Этот адрес определит сам драйвер (устройство PCIное) и нужно чтобы по этому адресу можно было обмениваться данными в пользовательской программе. Т.е. нужно каким то образом отобразить физический адрес устройства через мой драйвер на область памяти пользовательского процесса. Я прикидывал вариант с отображением памяти через драйвер /dev/mem, но нехотелось бы для работы с одним устройством использовать два разных драйвера. хотелось бы узнать название сишного файла, который реализует драйвер /dev/mem, возможно там в исходниках будет что то полезное. А то у меня Linux без исходников, а ставить их неоткуда (ядро кемто перелопачено, а исходники не поставляются) |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Чт Июн 26 2003 15:54 Заголовок сообщения: Теперь прояснилось. |
|
|
То есть driverbuf[256] у тебя не сдвинуть, так как аппаратные операции работают конкретно с этими адресами, но нужно чтобы содержимое этих адресов отображалось в поставляемый пользовательской функцией буфер. Тогда можно ввести вспомогательный указатель по тому же принципу, что в предыдущем сообщении, и во всех функциях до или после требуемых действий синхронизировать содержимое этих двух буферов. Кстати, здесь удобнее использовать C++ с его переопределением операторов и функций вместо C, чтобы не заботиться о синхронизации.
Но в любом случае при наличии двух буферов (аппаратного и программного) возникает вопрос актуальности информации для прикладных процессов. Это Вас не беспокоит? |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Пт Июн 27 2003 09:50 Заголовок сообщения: Re: Идею я понял но это, по моему, не совсем то. |
|
|
Ситуация такая:
Драйвер: /* в драйвере указатель настраивается на область памяти устройства (DEVICE_MEM - виртуальный адрес для физических адресов устройства) */ short *p_device= DEVICE_MEM;
/* далее в драйвере следующая операция приводит к передачи данных device_data в регистры устройсва с заданным смещением */ *(p_device + (offset>>1))= device_data;
ПРОГРАММА: В программе нужно работать с регистрами устройства так же как и в драйвере, т.e. по указателю.
short *p_proga= null; /* следующая операция должна для устройства (fd -дескриптор устройства) в программе создать указатель, по которому прикладная программа как и в коде драйвера моглабы работать напрямую с памятью устройства */ p_proga= mmap(p_proga,..., fd, 0); *(p_proga+(offset>>1))= device_data;
Т.е. идея с двумя разными буферами, которые синхронизируются между собой, здесь не совсем то что нужно. Скорее нужно просто создать два указателя (один в драйвере, другой в программе), настроенных на один и тот же физический адрес памяти. В драйвере это не проблема, а вот в прикладной программе - это проблема. Причем хотелось бы чтобы прикладная программа получала указатель на физический адрес от моего драйвера, а не от какого то друго, например, /dev/mem. Для /dev/mem операция mmap в пользовательской программе как раз и создает указатель на заданный физический адрес (сам не проверял, но в internet источниках приводится подобный пример). Посмотреть бы как mmap реализован в драйвере /dev/mem. Но какой у этого драйвера файл с исходником (drivers/char/mem.c не уверен)? |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Пт Июн 27 2003 16:48 Заголовок сообщения: Re: Идею я понял но это, по моему, не совсем то. |
|
|
Так что тебе мешает возвратить из драйверной функции drv_mmap() не ноль, а адрес буфера, то есть p_device? |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Вт Июл 01 2003 15:20 Заголовок сообщения: Что и все? |
|
|
Т.е. если я в драйвере где-то (например в open) создаю указатель на нужные мне физические адреса типа p_device= __ioremap(PHYS_ADDR, LEN, 0); , то достаточно в drv_mmap сделать так?
int drv_mmap(...) { return p_device; //или так? remap_page_range(vma->vm_start, __io_phys(p_device), size, prot); /* Вот здесь предположительно возникает ошибка -ядро не хочет ремапить память на пользовательскую область (vm_start) потому как эта область уже отремаплина на область драйвера (p_device). */ return 0; }
И это должно сработать? Но, по моему, нужно возвращать 0, чтобы пользовательский mmap не завершился с ошибкой и как в этом случае соотносятся адресное пространство ядра (драйвера) и пользовательское. Но чувствую, я уже достаточно близко подобрался к разгдке сей Linux тайны. Уже могу создать общий для драйвера и пользовательской программы буфер, чтобы работать с ним указательными операциями. Правда беда в том, что буфер етот расположен не знамо где, а мне нужно там где знамо. |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Ср Июл 02 2003 12:59 Заголовок сообщения: Re: Что и все? |
|
|
С точки зрения C/C++ должен работать такой твой вариант (p_device, естественно, должен быть видим для всех функций драйвера):
... p_device= __ioremap(PHYS_ADDR, LEN, 0); ...
int drv_mmap(...) { return p_device; }
Но ты совершенно верно беспокоишься по поводу прав драйверного и пользовательского процессов.
>>> по моему, нужно возвращать 0, чтобы пользовательский mmap не завершился с ошибкой и как в этом случае соотносятся адресное пространство ядра (драйвера) и пользовательское.
Я, к сожалению, вплотную этим не занимался, поэтому только предположу, что в драйверной функции drv_mmap() нужно понизить права и только потом возвратить указатель. (В этом и состоит концепция "процесс в ядре в режиме пользователя".) Еще, конечно, перед понижением прав не забыть установить специальный флаг, сигнализирующий о захвате устройства прикладным процессом. Но еще раз напоминаю, что это только общие соображения, и очень вероятно, что ты тут знаешь больше меня. |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Чт Июл 03 2003 12:50 Заголовок сообщения: Re: Программеры АААААА!!!!! |
|
|
Уфф, Вроде разобрался
Не понимаю почему заработало, но факт - работает. Просто убрал из кода драйвера то, что было явно ненужно.
И протестировал это дело на видеопамяти не из-под VMWare, а из просто Linux. Хочется надеяться, что и для других устройств ето будет работать.
Спасибосибочки огромное. Будем искать новые заморочки... |
|
Вернуться к началу |
|
 |
Борис Гость
|
Добавлено: Чт Июл 03 2003 15:59 Заголовок сообщения: Рассказал бы, что ли, что было, как решил. Думаю, многим (мне точно) будет интересно. (-) |
|
|
- |
|
Вернуться к началу |
|
 |
werter Гость
|
Добавлено: Пт Июл 04 2003 12:40 Заголовок сообщения: Re: Рассказал бы, что ли, что было, как решил. Думаю, многим (мне точно) будет интересно. (-) |
|
|
Идея следующая: создать два указателя на один и тот же физический адрес некоторого устройства. Причем один указатель должен быть в драйвере, а второй в пользовательской программе. В качестве тестового устройства я взял память видеоадаптера. Физическия адрес начала этой памяти можно посмотреть где угодно, а в частности в /proc/pci или самому программно определить етот адрес. Да не стоит проверять из под VMWare (у меня Linux запускался из под WinXP). И возможны проблемы из-за собственно видеокарты. У меня на рабочей машине все работает, а на домашней попытка напрямую писать в видеопамять приводит к перезагрузки машины (возможно потому, что Linux находится в консольном текстовом режиме, может какие то аппаратные глюки именно из-за этого). Если все правильно сработает, то запись в видеопамять каких то байтов приведет к появлению на экрае разных (бессмысленных) символов определенного цвета, соответствующих передаваемым байтам.
Вот собственно что было сделано, что касается отображения памяти.
-------------------------------------- Драйвер:
#defien LEN (64*1024);//размер выделяемой памяти должен быть кратен 64кБ, но возможно это не обязательно (хотя скорее всего обязательно)
u_long phys_addr= 0xabcdefg1;//к примеру
char *device_buf;//указатель на память устройства
device_buf= __ioremap(phys_addr, LEN); //так можно создать указатель на память устройства в драйвере.
iounmap(device_buf);// так выделенная ранее в драйвере память освобождается.
//через следующую функцию пользовательская программа настраивает свой указатель на заданный физический адрес. int my_mmap(struct file *file, struct vm_area_struct *vma) { u_long user_buf; u_long addr, leng; user_buf= vma->vm_start;//получить виртуальный пользовательский адрес, через который пользовательская програ должна получить доступ к физическому адресу
addr= phys_addr; или addr= vma->vm_offset;//если пользовательская программа сама хочет указать к какому физическому адресу ей нужен доступ
leng= vma->vm_end - vma->vm_start; //размер запрашиваемой памяти (Linux автоматически делает кратным 64кБ)
//далее происходит собственно отображение памяти if(remap_page_range(user_buf, addr, leng, vma->vm_page_prot)) return ERROR;
/* указатель драйвера еще можно настроить таким образом device_buf= (char*) user_buf; но это имеет смысл делать только после успешного отображения пользовательского буфера, например в ioctl или гдето еще. Но в этом случае виртуальный адрес пользовательского и драйверного указателя будет один и тот же (пользовательский), но проблем с доступом к нему из драйвера не будет (если наоборот, то были бы проблемы с правами доступа, а как их менять я неразбирался и думаю это не просто(какой нибудь массив структур, в котором надо кучу параметров изменить)). */
return 0; }
------------------------------- Пользовательская программа:
#defien LEN (64*1024) char *buf; int fd; u_long phys_addr=0; fd= open("/dev/xxx", IO_RDWR); buf= mmap(0, LEN, ... |
|
Вернуться к началу |
|
 |
|