драйвер , обновление информации

Вопросы программного кода и архитектуры Linux

Модератор: Olej

Kurenya
Интересующийся
Сообщения: 8
Зарегистрирован: 17 фев 2017, 20:20
Контактная информация:

драйвер , обновление информации

Непрочитанное сообщение Kurenya » 17 фев 2017, 21:14

Добрый вечер .
Мною был написан драйвер для ISA устройства .
Драйвер работает , но есть одна проблема .
Простенькая программа читает данные из драйвера , но обновляются данные только если разкомментировать freopen();

Код: Выделить всё

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char name[]="/proc/ISA_TIME";
char str[]="day 000 run 00 hour 00 min 00 sec 00 msec 0000 irq 0 \n      ";
FILE * dfd;
unsigned int uistrlen;

int main(void){
uistrlen=strlen(str);
dfd=fopen(name,"r");
if(dfd==NULL){
  printf("open device error\n");
  exit(0);
  };
while(1){
  sprintf(str,"day 000 run 00 hour 00 min 00 sec 00 msec 0000 irq 0 ");
  fgets(str,uistrlen,dfd);
  //freopen(name,"r",dfd);
  fseek(dfd,0,SEEK_SET);
  printf("%s\n",str);
  usleep(100000);
  };
fclose(dfd);
return(0);
}
cat /proc/ISA_TIME работает .
строка обновляется по прерыванию от устройства .

Код: Выделить всё

static irqreturn_t ISATIME_irq_handler(int irq,void *dev_id){
set3=inw(0x326);
irqgen=set3>>12;
if(irqgen>0){
  set0=inw(0x320);
  set1=inw(0x322);
  set2=inw(0x324);
  den=((set0>>14)&0x3)*100+((set0>>10)&0xf)*10+((set0>>6)&0xf);
  tmp=((set0&0x3)<<2)|((set1>>14)&0x3);
  chas=tmp+((set0>>2)&0x3)*10;
  min=((set1>>10)&0x7)*10+((set1>>6)&0xf);
  tmp=((set1&0x3)<<2)|((set2>>14)&0x3);
  sec=((set1>>2)&0x7)*10+tmp;
  msec=((set2>>10)&0xf)*100+((set2>>6)&0xf)*10+((set2>>2)&0xf);
  mksec=set3&0xf;
  run=chas*4;
  if(min<15)             run=run+1;
  if((min>=15)&(min< 30))run=run+2;
  if((min>=30)&(min< 45))run=run+3;
  if((min>=45)&(min<=59))run=run+4;
  inw(0x328);
  sprintf(str,"day %03d run %02d hour %02d min %02d sec %02d msec %04d irq %1x\n",den,run,chas,min,sec,msec,irqgen);
  return IRQ_HANDLED;
  }else{
  return IRQ_NONE;
  };
}
код обработки чтения :

Код: Выделить всё

static ssize_t proc_node_read(char *buffer,char **start,off_t off,int count,int *eof,void *data){
  static int offset=0,i;
  //printk( KERN_INFO "read: %d\n", count );
  for(i=0;(offset<=len)&&('\0'!=str[offset]);offset++,i++)
    *(buffer+i)=str[offset];
  *(buffer+i)='\n';
  i++;
  if((offset>=len)||('\0'==str[offset])){
    offset=0;
    *eof=1;
  }else{
    *eof=0;
  };
  //printk( KERN_INFO "return bytes: %d\n", i );
  //if(*eof!=0)printk(KERN_INFO "EOF\n");
  return i;
};
хотя пробовал и такой :
[code]
static ssize_t device_read(struct file * file,char * buf,size_t count,loff_t *ppos){
if(count<len)return -EINVAL;
if(*ppos!=0){return 0;};
if(copy_to_user((void*)buf,str,len))return -EINVAL;
//printk("ISA module : copy to user Ok\n");
*ppos=len+1;
//*ppos=0;
returned=count;
return returned;
}
результат одинаковый .
[/code]

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 17 фев 2017, 21:23

Вы полный архив .tgz прикрепите к сообщению, чтобы предметно обсуждать, конкретно (там достаточно много вопросов).

1. По 1-му впечатлению, ваше устройство после 1-го чтения устанавливает признак EOF.

2. Зачем это вы придумали "устройство" создать по такому дикому пути?

Код: Выделить всё

"/proc/ISA_TIME"
Мною был написан драйвер для ISA устройства .
3. ISA устройства не должны разделять IRQ-линию.
cat /proc/ISA_TIME работает .
строка обновляется по прерыванию от устройства .
4. Скопируйте с терминала как это выглядит - вот с этого и нужно начинать.

Kurenya
Интересующийся
Сообщения: 8
Зарегистрирован: 17 фев 2017, 20:20
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Kurenya » 17 фев 2017, 22:17

Olej писал(а):Вы полный архив .tgz прикрепите к сообщению, чтобы предметно обсуждать, конкретно (там достаточно много вопросов).
1. По 1-му впечатлению, ваше устройство после 1-го чтения устанавливает признак EOF.
2. Зачем это вы придумали "устройство" создать по такому дикому пути?

Код: Выделить всё

"/proc/ISA_TIME"
туда его закидывает :

Код: Выделить всё

#define DEV_NAME "ISA_TIME"
...
create_proc_read_entry(DEV_NAME,0,NULL,proc_node_read,NULL)
как объяснить системе место в иерархии я ещё не разбирался .
3. ISA устройства не должны разделять IRQ-линию.
оно не разделяет . промышленный компьютер . линия прерывания зарезервирована для шины isa в биосе .
4. Скопируйте с терминала как это выглядит - вот с этого и нужно начинать.
работа cat-а :
Изображение
программа без freopen() :
Изображение
программа с freopen() :
Изображение
irq - эти тип прерывания внутри устройства , не обращайте внимания .
Вложения
drv009.zip
последняя версия
(3.5 КБ) 121 скачивание

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 18 фев 2017, 09:49

Kurenya писал(а): Драйвер работает , но есть одна проблема .
Простенькая программа читает данные из драйвера , но обновляются данные только если разкомментировать freopen();
Я так предполагаю, что вы просто ловите EOF при всех чтениях после 1-го, а не изменяющийся "результат" str[] - это просто мусор, застрявший там после 1-го чтения.

Код: Выделить всё

[olej@dell Linux.books.own]$ man fgets
...
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.   Read‐
       ing  stops  after an EOF or a newline.
- поменяйте (временно) fgets() на fread(), то же самое, но нагляднее:

Код: Выделить всё

fread()  does  not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which
       occurred.
- анализируйте EOF после каждого чтения ...
- очистите str[] после каждого чтения...

И наблюдайте ;-)

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 18 фев 2017, 10:12

Не делайте (и не показывайте) эти вот не нужные телодвижения:

Код: Выделить всё

# ./test

Куда понятнее и нагляднее нормальная команда, которая и есть ваш test:

Код: Выделить всё

# cat /proc/ISA_TIME
(и скриншоты вкопировать не есть хорошая практика - куда проще и нагляднее 1-2 строчки скопировать с терминала и вставить под тэгом code).

Но сама идея (архитектурно) отображение быстро меняющихся данных, и вообще передачу пользовательских данных сделать через /proc - неудачная.
Куда лучше это сделать через драйвер символьного (байтового) устройства в /dev.
Или, на худой конец, это временами делают через /sys.

Кроме того, может быть много мелких замечаний по вашему драйверу:

1. Не нужно при open() (функция device_open()) делать:

Код: Выделить всё

try_module_get()
И соответственно, при close():

Код: Выделить всё

module_put()
Дефаултные реализации операций open()/close() сделают это по умолчанию.

2. И, как следствие, вашему драйверу вообще не нужны реализации open()/close() - пусть используются дефаултные.

3.
ISA устройства не должны разделять IRQ-линию.
оно не разделяет . промышленный компьютер . линия прерывания зарезервирована для шины isa в биосе .
Я написал "не может разделять" к тому, что ваш обработчик прерываний не может возвращать разные значения кода возврата:

Код: Выделить всё

...
  return IRQ_HANDLED;
  }else{
  return IRQ_NONE;
  };
Он должен обрабатывать прерывание безусловно и всегда (IRQ_HANDLED). Он никогда не может передавать обработку (IRQ_NONE) другому обработчику того же IRQ (как это и сделано для PCI устройств).

Ну и конечно ... стиль написания кода :-o - отступы от уровней структурной вложенности :cry:
Это, может, и "мелочь", но разобраться в такой мелочи и не понаделать лишних ошибок - невозможно, при чуть более-менее сложном коде.

Kurenya
Интересующийся
Сообщения: 8
Зарегистрирован: 17 фев 2017, 20:20
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Kurenya » 19 фев 2017, 04:12

Olej писал(а): Но сама идея (архитектурно) отображение быстро меняющихся данных, и вообще передачу пользовательских данных сделать через /proc - неудачная.
Куда лучше это сделать через драйвер символьного (байтового) устройства в /dev.
Или, на худой конец, это временами делают через /sys.
первая версия драйвера была через /dev .
из /dev инфа читается только если программа запущена с root правами .

само физическое устройство может работать в нескольких режимах .
из них только работа прерыванием на каждую миллисекунду можно считать частым .
Olej писал(а): Кроме того, может быть много мелких замечаний по вашему драйверу:

1. Не нужно при open() (функция device_open()) делать:

Код: Выделить всё

try_module_get()
И соответственно, при close():

Код: Выделить всё

module_put()
Дефаултные реализации операций open()/close() сделают это по умолчанию.

2. И, как следствие, вашему драйверу вообще не нужны реализации open()/close() - пусть используются дефаултные.

3.
ISA устройства не должны разделять IRQ-линию.
оно не разделяет . промышленный компьютер . линия прерывания зарезервирована для шины isa в биосе .
Я написал "не может разделять" к тому, что ваш обработчик прерываний не может возвращать разные значения кода возврата:

Код: Выделить всё

...
  return IRQ_HANDLED;
  }else{
  return IRQ_NONE;
  };
Он должен обрабатывать прерывание безусловно и всегда (IRQ_HANDLED). Он никогда не может передавать обработку (IRQ_NONE) другому обработчику того же IRQ (как это и сделано для PCI устройств).

Ну и конечно ... стиль написания кода :-o - отступы от уровней структурной вложенности :cry:
Это, может, и "мелочь", но разобраться в такой мелочи и не понаделать лишних ошибок - невозможно, при чуть более-менее сложном коде.
1.2.знаю уже . это остаток от /dev варианта .
3.это я проверял версию того , что кроме устройства кто-то ещё дёргает прерывание .

вот как раз с таким стилем ещё ни разу не было путаницы . :)
вы не поверите с каким чужим кодом приходится работать - "go to" в коде , без отступов и форматирования вообще .

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 19 фев 2017, 07:58

Kurenya писал(а): первая версия драйвера была через /dev .
из /dev инфа читается только если программа запущена с root правами .
Этому делу легко помочь ;-) : написать правила udev для этого устройства в /etc/udev/rules.d
Но это более "цивильный" подход: устройство, создающее поток байт, отображается в /dev
Kurenya писал(а): само физическое устройство может работать в нескольких режимах .
из них только работа прерыванием на каждую миллисекунду можно считать частым .
Я неточно выразился, вопрос не в том, насколько часто, а в том что периодически ... или даже точнее - асинхронно: если даже устройство генерирует данные, то это - устройство, а /proc - это инструмент для диагностики (и иногда управления) некоторыми переменными состояниями ядра (и модулей в частном случае).
Может быть, конечно, и так ... но это несколько нарушает логику, для того, кто будет работать с этим "со стороны".

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 19 фев 2017, 08:06

Kurenya писал(а): вот как раз с таким стилем ещё ни разу не было путаницы . :)
вы не поверите с каким чужим кодом приходится работать - "go to" в коде , без отступов и форматирования вообще .
Вот как-раз с go to в коде ядра/модулей как-раз всё в порядке - там их миллион, и там это хороший стиль - вся обработка ошибочных ситуаций.

Но я не имел в виду вообще "кодестайл" и "говнокод", по которым сопли льют юные дарования на интернет-ресурсах.
Пишите как хотите и как удобно.
Но структурные отступы уровней не соблюдать на структурном языке C не соблюдать? ... это не комильфо.
Смотреть такой чужой код невозможно.
Пишите тогда в одну строчку, без переносов строк - ещё круче станет смотреться. :lol:
(кстати, в последнем развитии линии C/C++ языков Go как раз пошли, наконец, в этом направлении, что потребовали соблюдать синтаксически некоторую структурность текста + придали смысл переносам строк ... не Python, конечно, но подвижки в этом направлении)

Kurenya
Интересующийся
Сообщения: 8
Зарегистрирован: 17 фев 2017, 20:20
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Kurenya » 20 фев 2017, 11:51

получилось с обновлением так :

Код: Выделить всё

...
char str[]="day 000 run 00 hour 00 min 00 sec 00 msec 0000  ";
len=strlen(str);
...
while(){
  ...
  fread(str,len,1,dfd);
  fseek(dfd,0,SEEK_SET);
  ...
  };
размер буфера должен быть чуть больше принимаемой строки .
если сделать большим считывается хлам какой-то .
осталось понять почему так происходит и чем провинился fgets() .

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: драйвер , обновление информации

Непрочитанное сообщение Olej » 20 фев 2017, 12:40

Kurenya писал(а):осталось понять почему так происходит и чем провинился fgets() .
Потому, что ваша операция в модуле возвращает строку без завершающего '\0'.

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 3 гостя