драйвер символьного устройства - PullRequest
1 голос
/ 13 февраля 2010

Функции обратного вызова 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"); 

Ответы [ 2 ]

2 голосов
/ 13 февраля 2010

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

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

0 голосов
/ 13 февраля 2010

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

Прежде всего, вам нужно copy_from_user buf в буфер на стороне ядра. Вы не знаете размер буфера заблаговременно, поэтому вы должны k / vmalloc его (РЕДАКТИРОВАТЬ: вы можете пропустить выделение памяти, так как ваши данные <= 128 байт, может иметь локальный буфер в стек) </p>

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;

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

Удачи и веселья!

...