Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию
    главная     хостинг    
Поиск по сайту:  
Смотрите также

2.3.6.8. Функция init()

Эта функция не входит в file_operations но вам придется использовать ее, так как именно она регистрирует file_operations с содержащейся там VFS - - без нее запросы на драйвер будут находится в беспорядочном состоянии. Эта функция запускается во время загрузки и самоконфигурирования ядра. init() получает переменную с адресом конца используемой памяти. Затем она обнаруживает все устройства, выделяет память, исходя из их общего числа, сохраняет полезные адреса и возвращает новый адрес конца используемой памяти. Функцию init() вы должны вызывать из определенного места. Для символьных устройств это /kernel/cdr_dev/mem.c. В общем случае функции надо задавать лишь переменную memory_start.

Во время работы функции init(), она регистрирует ваш драйвер с помощью регистрирующих функций. Для символьных устройств это register_chrdev(). register_chrdev использует три аргумента :

  • int major - основной номер устройства.
  • srtring name - имя устройства.
  • адрес #DEVICE#_fops структуры file_operations.
  • После окончания работы функции, файлы становятся доступными для VFS, и она по надобности переключает устройство с одного вызова на другой.

    Функция init() обычно выводит сведения о найденном аппаратном обеспечении и информацию о драйвере.Это делается с использованием функции printk().

    2.4. Cимвольные устройства

    2.4.1. Инициализация

    Кроме функций описанных в file_operations, есть еще одна функция, кото- рую вам надо вписать в функцию foo_init(). Вам придется изменить функцию chr_dev_init() в chr_drv/mem.c для вызова вашей функции foo_init(). foo_init() вначале должна вызывать register_chrdev() для определения самой себя и установки номеров устройств. Аргументы register_chrdev() :

    • int major - основной номер драйвера.
    • char *name - имя драйвера оно может быть изменено, но не имеет практического применения.
    • struct file_operations *fops - адрес определенной вами file_operations.
    • Возвращаемые значения : 0 - в случае если указанным основным номером ни одно устройство более не обладает. не 0 в случае некорректного вызова.

    2.4.2. Прерывания или последовательный вызов?

    В драйверах, не использующих прерывания, легко пишутся функции foo_read() и foo_write() :

           static int foo_write(struct inode * inode, struct file * file,
                                char * buf, int count)
           {
               unsigned int minor = MINOR(inode-i_rdev);
               char ret;
               while (count  0) {
                   ret = foo_write_byte(minor);
           if (ret 
    
    
    
    
    
    
    
    

    foo_write_byte() и foo_handle_error() - функции, также определенные в foo.c или псевдокоде.

    WRITE - константа или определена #define.

    Из примера также видно как пишется функция foo_read(). Драйверы, управ- ляемые прерываниями, более сложны :

    Пример foo_write для драйвера, управляемого прерываниями :

            static int foo_write(struct inode * inode, struct file * file,
                                 char * but, int count)
            {
               unsigned int minor = MINOR(inode-i_rdev);
               unsigned long copy_size;
               unsigned long total_bytes_written = 0;
               unsigned long bytes_written;
               struct foo_struct *foo = &foo_table[minor];
    
               do {
                   copy_size = (count 
    foo_buffer, buf, copy_size);
    
                   while (copy_size) {
                          /* запуск прерывания */
    
                          if (some_error_has_occured) {
                              /* обработка ошибочного состояния */                       }
    
                          current-timeout = jiffies +FOO_INTERRUPT_TIMEOUT;
                              /* set timeout in case an interrupt has been missed */
                          interruptible_sleep_on(&foo-foo_wait_queue);
                          bytes_written = foo-bytes_xfered;
                          foo-bytes_written = 0;
                          if (current-signal & ~current-blocked) {
                              if (total_bytes_written + bytes_written)
                                   return total_bytes_written + bytes_written;
                              else
                                   return -EINTR; /* nothing was written, system
                                                call was interrupted, try again */
                          }
                   }
                   total_bytes_written += bytes_written;
                   buf += bytes_written;
                   count -= bytes-written;
    
               } while (count  0);
    
               return total_bytes_written;
            }
    
            static void foo_interrupt(int irq)
            {
                struct foo_struct *foo = &foo_table[foo_irq[irq]];
    
                /* Here, do whatever actions ought to be taken on an interrupt.
                   Look at a flag in foo_table to know whether you ought to be
                   reading or writing. */
    
                /* Increment foo-bytes_xfered by however many characters were
                   read or written */
                if (buffer too full/empty)
                    wake_up_ interruptible(&foo-foo_wait_queue);
             }
    

    Здесь функция foo_read также аналогична. foo_table[] - массив структур, каждая из которых имеет несколько элементов, в том числе foo_wait_queue и bytes_xfered, которые используются и для чтения, и для записи. foo_irq[] - - массив из 16 целых использующийся для контроля за приоритетами элементов foo_table[] засылаемыми в foo_interrupt().

    Для указания обpаботчику пpеpываний вызвать foo_interrupt() вы должны использовать либо request_irq(), либо irqaction(). Это делается либо пpи вызове foo_open(), либо для пpостоты в foo_init(). request_irq() pаботает пpоще нежели irqaction и напоминает pаботу сигнального пеpеключателя. У нее существует два аpгумента:

    • номеp irq, котоpым вы pасполагаете
    • указатель на пpоцедуpу упpавления пpеpываниями, имеющую аpгумент типа integer.

    request_irq() возвpащает -EINVAL, если irq 15, или в случае указателя на пpогpамму pавного NULL, EBUSY если пpеpывание уже используется или 0 в случае успеха.

    irqaction() pаботает также как функция sigaction() на пользовательском уpовне и фактически использует стpуктуpу sigaction. Поле sa_restorer() в стpуктуpе не используется, остальное - же осталось неизменным. См. pаздел "Функции поддеpжки" для более полной инфоpмации о irqaction().


    [ Назад | Оглавление | Далее ]









    helloworld.ru © 2001-2021
    Все права защищены