/*
  Bu belgenin telif haklar� Necati Ersen ���EC�'ye aittir.
  K�k: http://acikkod.org
  �lk bask�: 2004-04-22
  Son de�i�iklik: 2004-04-22
  Bu d�k�man A��kkod.ORG Belge Yaz�m ve Da��t�m Lisans� ile da��t�lmaktad�r.
*/

/dev/null Ayg�t� ve S�r�c� Programlama

Bu bolumde, /dev/null ayg�t�n�n s�r�c�s�n�n nas�l yaz�ld���n� inceleyece�iz.

Linux �ekirde�inde her ayg�t i�in yap�lmas� gereken belli ba�l� i�lemler vard�r.
 Okuma (read), yazma(write), a�ma (open) gibi.

Linux'de bir sistem �a�r�s� olu�tu�u zaman (�rne�in open), hangi ayg�t i�in
olu�turtu ise, o ayg�t�n ilgili fonksiyonu �al��t�r�l�r.

Bu i�lemler, Linux �ekirde�inde karakter ayg�tlar� i�in file_operations isimli
bir yap�da tutulur. linux/fs.h ta tan�mlanan file_operations yap�s� a�a��daki
gibidir.

struct file_operations {
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
    int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, struct dentry *);
    int (*fasync) (int, struct file *, int);
    int (*check_media_change) (kdev_t dev);
    int (*revalidate) (kdev_t dev);
    int (*lock) (struct file *, int, struct file_lock *);
} ;

Biz bunlardan sadece gerekenleri kullanaca��z.

Bu yap�n�n amac�, sistem bu ayg�t ile ilgili olu�an sistem �a�r�lar�n� yerine
getirirken hangi fonksiyonlar� kullanaca��n� belirtmektir.

Hangi fonksiyonlar� kullanaca��m�z� belirledikten sonra kullanaca��m�z ayg�t�
se�meliyiz. Bu ayg�t�n bir major ve minor numaras� olmas� gerekti�ini biliyoruz.
Yapmam�z gerek �ey, sisteme bu ayg�t i�in yap�lan sistem �a�r�lar�nda kullan�lacak
fonksiyonlar�n tutuldu�u, tan�mlad���m�z file_operations yap�s�n� kullanmas�
gerekti�ini belirtmek. Bu i�lemi init_module() fonksiyonu i�inde yapmam�z gerekiyor.

Sisteme bir karakter ayg�t eklemek istedi�imizde;

int register_chrdev(unsigned int, const char *, struct file_operations *)

�eklinde tan�mlanan register_chrdev() fonksiyonunu kullan�yoruz. Burada birinci
parametre, ayg�t�n major numaras�, ikinci parametre ayg�t�n ismi, ���nc�s� ise
tan�mlad���m�z file_operations yap�s�na pointerdir.

 i = register_chrdev (201, "bdevice", &fops);

register_chrdev() fonksiyonunu major numaras� olarak 0 verirsek, sistem otomatik
olarak ayg�ta bir major numaras� verecek ve fonksiyonun geri d�n�� de�eri ayg�t
i�in kullan�lacak olan major numaras� olacakt�r.

register_chrdev() fonksiyonu ikinci parametre ile belirtti�imiz ayg�t olup olmad���n�
kontrol etmez. Bu y�zden i�lem ba�ar�l� ise verdi�imiz parametreye g�re 0 yada major
numaras� ile geri d�necektir.

int init_module (void)
{
    int i = 0;
    i = register_chrdev (device_major_number, DEVICE_NAME , &fops);
    if (i < 0) return i;
    if (device_major_number == 0) device_major_number = i;
    return 0;
}

��lerimiz bitti ve mod�l� bellekten ataca��z. Bu durumda yap�lmas� gereken �ey
cleanup_module() fonksiyonu ile kulland���m�z ayg�t� unregister etmek.

int unregister_chrdev(unsigned int major, const char * name);

unregister_chrdev() fonksiyonundaki ilk parametre ayg�t�n major numaras�, ikincisi
ise ayg�t�n ismidir.

void cleanup_module (void)
{
    unregister_chrdev (201, "bdevice");
}


/dev/null ayg�t� ad�ndan da anla��ld��� gibi hi� bir �ey yapmayan, herhangi bir
bellek blogu kullanmayan okuma ve yazma i�lemleri yap�labilen bir ayg�tt�r. Yazmak
istedi�imizde yazmak istedi�imiz t�m data n�n yaz�ld���n�, okumak istedi�imizde
ise 0 dondurur.

siseci:~/kernel# cat /dev/null
siseci:~/kernel# cat /etc/passwd > /dev/null
siseci:~/kernel# cat /dev/null
siseci:~/kernel#

Ayg�t�m�z bir karakter ayg�t oldu�u i�in open ve close sistem �a�r�lar�n� yan�tlayacak
fonksiyonlara ihtiyac�m�z olmayacak.

read ve write i�lemleri i�in iki fonksiyon yazmam�z gerekecek.

Sistemde �al��an null ayg�t� var oldu�u i�in ayg�t�n ad�n� null2 olarak kullanal�m.

/dev/null2 ayg�t�m�z i�in read system ca�r�s� olu�tu�unda bu �a�r�y�
null2_read() fonksiyonu ile cevaplayal�m. read i�lemi sonucunda kullan�c�ya
dosya sonunda gelindi yada okunacak bilgi yok anlam�na gelen 0 d�ndermemiz
gerekiyor.

read() fonksiyonunun nas�l kullan�ld���n� zaten file_operations yap�s�ndan biliyoruz.

static ssize_t
null2_read (struct file * file, char * buf, size_t count, loff_t *ppos)
{
    return 0;
}

write i�lemi i�in ise, kullan�c� ka� bayt yazmak istediyse, o kadar bilginin yaz�ld���n�
do�rulamak i�in, kullan�c�n�n bize parametre olarak verdi�i uzunlu�u, kullan�c�ya geri
d�ndermemiz yeterli olacakt�r. Fonksiyonumuz null2_write() olsun.

static ssize_t
null2_write (struct file * file, const char * buf, size_t size, loff_t * ppos)
{
    return size;
}

file_operations yap�m�za bakt���m�zda,

static struct file_operations null2_fops = {
    NULL,                /* lseek   */
    null2_read,          /* read    */
    null2_write,         /* write   */
    NULL,                /* readdir */
    NULL,                /* select  */
    NULL,                /* ioctl   */
    NULL,                /* mmap    */
    NULL,                /* open    */
    NULL,                /* release */
    NULL,                /* fsync   */
} ;

�eklinde olacakt�r.
T�m koda bakacak olursak;

#ifndef __KERNEL__
  #define __KERNEL__
  #define MODULE
  #define LINUX
#endif

#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h>

static ssize_t null2_read  (struct file *, char *      , size_t, loff_t *);
static ssize_t null2_write (struct file *, const char *, size_t, loff_t *);

static struct file_operations null2_fops = {
    read:       null2_read,
    write:      null2_write,
};

static ssize_t
null2_read (struct file * file, char * buf, size_t count, loff_t *ppos)
{
    return 0;
}

static ssize_t
null2_write (struct file * file, const char * buf, size_t size, loff_t * ppos)
{
    return size;
}

int init_module (void)
{
    int i = 0;
    i = register_chrdev (222, "null2", & null2_fops);
    if (i < 0) return i;
    return 0;
}

void cleanup_module (void)
{
    unregister_chrdev (222, "null2");
}


Derleyip sisteme y�kleyelim.

siseci:~/kernel# mknod /dev/null2 c 222 0
siseci:~/kernel# gcc -Wall -c null2.c
siseci:~/kernel# ls -al null2.o
-rw-------   1 root     root         1468 Jan  1 03:07 null2.o
siseci:~/kernel# insmod null2
siseci:~/kernel# echo Deneme > /dev/null2
siseci:~/kernel# cat /dev/null2
siseci:~/kernel# ls -al /dev/null2
crw-------   1 root     root     222,   0 Jan  1  1998 /dev/null2
siseci:~/kernel# rmmod null2

B�ylece sisteme y�klemi� ve testini de yapm�� olduk. Yukardaki testlerden de anla��ld���
�zere null2 ayg�t�, sistemdeki null ayg�t� gibi davranmaktad�r.

Linux �ekirdek kodlar�na bakt���m�zda null (linux/drivers/char/mem.c ) ayg�t�n�n,
lseek() sistem �a�r�s� i�in de bir fonksiyon yaz�lm��. Bu dosyaya g�z atman�z� tavsiye
ederim.


Necati Ersen ���EC�

25 �ubat 2004