драйвер символьного устройства

Функции обратного вызова read() и write() в нашем драйвере устройства cmosram.c передают только один байт данных при каждом вызове, поэтому для чтения всех мест хранения RTC требуется 128 системных вызовов!

Можете ли вы повысить эффективность этого драйвера, изменив его функции read() и write(), чтобы они передавали столько действительных байтов, сколько может вместить предоставленный буфер?

код выглядит следующим образом

char modname[] = "cmosram"; // name of this kernel module
char devname[] = "cmos";    // name for the device's file
int my_major = 70;      // major ID-number for driver
int cmos_size = 128;    // total bytes of cmos memory
int write_max = 9;      // largest 'writable' address

ssize_t my_read( struct file *file, char *buf, size_t len, loff_t *pos )
{
    unsigned char   datum;

    if ( *pos >= cmos_size ) return 0;

    outb( *pos, 0x70 );  datum = inb( 0x71 );

    if ( put_user( datum, buf ) ) return -EFAULT;

    *pos += 1;
    return  1;
}

ssize_t my_write( struct file *file, const char *buf, size_t len, loff_t *pos )
{
    unsigned char   datum;

    if ( *pos >= cmos_size ) return 0;

    if ( *pos > write_max ) return -EPERM;

    if ( get_user( datum, buf ) ) return -EFAULT;

    outb( *pos, 0x70 );  outb( datum, 0x71 );

    *pos += 1;
    return  1;
}

loff_t my_llseek( struct file *file, loff_t pos, int whence )
{
    loff_t  newpos = -1;

    switch ( whence )
        {
        case 0: newpos = pos; break;            // SEEK_SET
        case 1: newpos = file->f_pos + pos; break;  // SEEK_CUR
        case 2: newpos = cmos_size + pos; break;    // SEEK_END
        }

    if (( newpos < 0 )||( newpos > cmos_size )) return -EINVAL;

    file->f_pos = newpos;
    return  newpos;
}


struct file_operations my_fops = {
                owner:  THIS_MODULE,
                llseek: my_llseek,
                write:  my_write,
                read:   my_read,
                };

static int __init my_init( void )
{
    printk( "<1>\nInstalling \'%s\' module ", devname );
    printk( "(major=%d) \n", my_major );
    return  register_chrdev( my_major, devname, &my_fops );
}

static void __exit my_exit(void )
{
    unregister_chrdev( my_major, devname );
    printk( "<1>Removing \'%s\' module\n", devname );
}

module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE("GPL"); 

person sandra    schedule 13.02.2010    source источник
comment
Это домашнее задание (см. здесь: cs.usfca.edu/~cruse/cs635 /lesson04.ppt), поэтому я пометил его соответствующим образом.   -  person caf    schedule 15.02.2010


Ответы (2)


Вы должны использовать параметр len и цикл inb/outb соответственно для чтения/записи максимального количества байтов, которое помещается в данный буфер. Тогда return len (количество прочитанных байт!) вместо return 1.

Я не буду приводить пример кода, так как вам лучше знать, как читать этот материал CMOS.

person AndiDog    schedule 13.02.2010

Вы можете сделать get_user в цикле, но 128 вызовов функции, вероятно, не очень эффективны. Вы можете сделать все это одним выстрелом, используя следующий подход.

Прежде всего, вам нужно copy_from_user бафнуть в буфер на стороне ядра. Вы не знаете размер буфера заранее, поэтому вы должны k/vmalloc его (EDIT: вы можете пропустить выделение памяти, так как ваши данные ‹ = 128 байт, возможно, в стеке есть локальный буфер)

u8 * kernel_buf;

kernel_buf = kmalloc(len, GFP_KERNEL);
if(!kernel_buf)
   return -ENOMEM;
.
.
kfree(kernel_buf); // no memory leaks please

Вам также необходимо убедиться, что вы можете читать/записывать len байта из буфера пространства пользователя, а затем копировать в/из буфера на стороне ядра, который вы только что выделили.

if(!access_ok(VERIFY_WRITE, buf, len))
{
   kfree(kernel_buf);
   return -EFAULT;
}

if(copy_from_user(kernel_buf, buf, len))
   return -EFAULT;

// now do your business in a for loop
for(i = 0; i < len; i++)
{
   outb(*pos + i, 0x70);
   outb(kernel_buf[i], 0x71),
}

// cleanup kernel buf
kfree(kernel_buf);

return len;

Очевидно, вам следует перепроверить мои предложения, поскольку я их не компилировал и не тестировал, но, надеюсь, это поможет.

Удачи и приятного времяпровождения!

person Sam Post    schedule 13.02.2010