- ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
- ssize_t write(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
Argumenty:
- struct file *filp - wskaźnik na plik, nie mylić z FILE który występuje w standardowej bibliotece C a nigdy w kodzie kernela
- char __user *buff - wskaźnik na bufor przechowujący dane, należy pamiętać, że jest to wskaźnik z poziomu user-space, z tego powodu nie możemy go zwyczajnie wyłuskać w naszym module, który wykonywany jest w kernel-space
- size_t count - rozmiar danych do transferu
- loff_t *f_pos - aktualna pozycja w pliku
Jak zostało wspomniane wyżej, wskaźnika buff nie możemy wyłuskać. Tutaj z pomocą przychodzą nam funkcje zdefinowane w nagłówku <linux/uaccess.h>
- unsigned long copy_to_user(void __user *to, const void *from, unsigned long count) - kopiuje dane z kernel-space do user-space
- unsigned long copy_from_user(void *to, const void __user *from, unsigned long count) - kopiuje dane z user-space do kernel-space
Argumenty:
- to - wskaźnik na adres docelowy
- from - wskaźnik na adres źródłowy
- count - rozmiar danych do transferu w bajtach
Obie funkcje zwracają ilość bajtów, których nie udało się skopiować. W przypadku pełnego powodzenia zwracana jest wartość 0. Zaimplementujmy więc mechanizm zapisu i odczytu.
static ssize_t char_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
{
static const ssize_t size = sizeof(device.array);
printk("char_read()\n");
if ((*f_pos) >= size)
return 0;
if (copy_to_user(buff,&device.array,size) != 0)
return -EFAULT;
(*f_pos) = size;
return size;
}
Zmienna ssize_t size będzie przechowywać rozmiar tablicy z naszego wirtualnego urządzenia. Na początku sprawdzamy czy pozycja w pliku nie wykroczyła poza zakres. Jeśli tak, to kończymy odczytywanie. Następnie kopiujemy zawartość naszej tablicy do bufora znajdującego się w user-space. Ustawiamy odpowiednią pozycję pliku i zwracamy ilość skopiowanych bajtów.
static ssize_t char_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos)
{
printk("char_write()\n");
if (copy_from_user(&device.array,buff,count) != 0)
return -EFAULT;
printk("Zapisano %s\n",device.array);
return count;
}
Podczas zapisu korzystamy z funkcji copy_from_user, ponieważ kopiujemy dane z przestrzeni użytkownika do kernela. Zwracamy ilość zapisanych bajtów.
Z tak zaimplementowanymi funkcjami polecam sprawdzać działanie za pomocą prostego skryptu, np.
Po uruchomieniu skryptu:
Jak przystosować funkcję read do dwóch lub wiecej urzadzeń? Dostać się jakoś przez file?
OdpowiedzUsuńok, to zwraca pointer do urzadzenia : file->private_data;
UsuńAle mimo wszystko laduje mi zawsze do jednego z urzadzen..