Linux Character Drivers Üzerinde Klavyenin Ledlerini Yakma


Linux Character Drivers Üzerinde  Klavyenin Ledlerini Yakma      

     Character special files veya character devices , donanım cihazına arabelleksiz, doğrudan erişim sağlar. Programların aynı anda tek bir karakter okumasına veya yazmasına izin vermezler. Örneğin bir sabit disk için kullanılan karakter aygıtı, normalde tüm okuma ve yazmaların sınırları engellemek için hizalanmasını ve kesinlikle tek bir baytın okunmasına izin vermeyeceğini gerektirir. Karakter aygıtları, bazen bir blok tabanlı donanım için bir karakter aygıtının hizalanmış blokları okumak ve yazmak için programlar gerektirdiği gerçeğini çevreleyen karışıklığı önlemek için ham aygıtlar olarak bilinir.
     Kullanıcı alanı programları, aygıt özel dosyaları olarak da adlandırılan aygıt düğümleri aracılığıyla karakterlere ve engelleme aygıtlarına erişir. Bir aygıt düğümü oluşturulduğunda, bir major ve minor numarayla ilişkilendirilir. Bu yapıyı görsellemek istersek;
      Klavye ledlerini yakmak için oluşturduğumuz   modülümüzde metholar ile /dev alt dosyalama yapısı oluşturabiliriz.

     Son iki yazımızda bulunan koda benzer şekilde, bir init () işlevi ve bir exit () işlevi vardır. Bununla birlikte, karakter aygıtı için gereken ek file_operations işlevleri vardır:


dev_open(): Cihaz kullanıcı alanından her açıldığında çağrılır.
dev_read(): Veriler cihazdan kullanıcı alanına gönderildiğinde çağrılır.
dev_write(): Veri kullanıcı alanından aygıta gönderildiğinde çağrılır.
dev_release (): Cihaz kullanıcı alanında kapatıldığında çağrılır
   1: Kernel Modülünün Oluşturulması

#cd  /home/demet/Downloads/LKernel
#mkdir  DriverModules
#cd DriverModules
#gedit Keyboard.c
   2: C Modulünün Yazılması
     
     Bu methodu ister /dev alt dosyasının Read methodunu çalışırken aktif edebiliriz ister Write methodu çalışırken aktif edebiliriz. İki yöntem arasında pek fark yoktur. Sürücülerin sınıf adı ve cihaz adı var.Sınıf adı olarak CoreClass  ve aygıt adı olarak NativeCore kullandık. Bu, dosya sisteminde /sys/class/CoreClass/NativeCore 'da görünen bir aygıt oluşturulmasına neden olur.

Kaynak Kodu indirmek için (Tıklayınız) (Source Code)

//Kütüphanelerin tanımlanması
#include <linux/module.h>
#include <linux/device.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/tty.h> #include <linux/kd.h> #include <linux/vt.h> #include <linux/console_struct.h> #include <linux/init.h>
//Modül bilgilerinin tanımlanması MODULE_LICENSE("GPL"); MODULE_AUTHOR("NativeCore");
//Char. Device bilgilerinin ve Keyboard LED lerinin adreslerinin tanımlanması #define DEVICE_NAME "NativeCore" #define CLASS_NAME "CoreClass" #define MAX_SIZE 3 #define ZERO 0x00 #define cc 0x04 #define ss 0x01 #define nn 0x02 //NumLock
//Char. Device Major Numarasının tanımlanması
static int majorNumber;
//Class ve Device struct yapılarının tanımlanması static struct class* coreClass = NULL; static struct device* coreDevice = NULL;
//Keyboard LED driverının tanımlanması static struct tty_driver *ttyDriver; extern int fg_console;
//File Operationsların tanımlanması static ssize_t DeviceRead(struct file *filep, char *buffer, size_t __user len, loff_t *offset); static ssize_t DeviceWrite(struct file *filep, const char __user *buffer, size_t len, loff_t *offset);
//Özel methodların tanımlanması
static void SetLEDs(char *);
static int Validate(char *,int);
//Değişkenlerin tanımlanması static char DeviceBuffer[MAX_SIZE]; static int BufferSize;
//File Operations struct yapısının tanımlanması static struct file_operations fo = { .owner = THIS_MODULE, .read = DeviceRead, .write = DeviceWrite };
//init methodu static int onStart(void) {
//Keyboard Driver ın oluşturulması int k = 0; printk(KERN_ALERT "NativeCore\n"); for (k = 0; k < MAX_NR_CONSOLES; k++) { if (!vc_cons[k].d) break; } ttyDriver = vc_cons[fg_console].d->port.tty->driver;
//Major numarsının kaydının alınması majorNumber = register_chrdev(0, DEVICE_NAME, &fo); if (majorNumber<0) { printk(KERN_ALERT "Device kayıt edilmedi.Major Numarası : %d\n",majorNumber); return majorNumber; }
//Class yapısının oluşturulması coreClass = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(coreClass)) { unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_ALERT "Device kayıt edilmedi.Major Numarası : %d\n",majorNumber); return PTR_ERR(coreClass); }
//Device yapısının oluşturulması coreDevice = device_create(coreClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(coreDevice)){ class_destroy(coreClass); unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_ALERT "Device oluşturulmadı\n"); return PTR_ERR(coreClass); } printk(KERN_ALERT "Device oluşturuldu %d : %s.\n",majorNumber,DEVICE_NAME); return 0; }
//exit methodu static void onExit(void){
//Çıkış sonrası gerekli methodların kapatılması device_destroy(coreClass, MKDEV(majorNumber, 0)); class_unregister(coreClass); class_destroy(coreClass); unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_ALERT "Device silindi %d : %s.\n",majorNumber,DEVICE_NAME); ((ttyDriver->ops)->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED,0xFF); }
//File Operations Read Methodu static ssize_t DeviceRead(struct file *filep, char *buffer, size_t __user len, loff_t *offset) { ssize_t sst = 1; return simple_read_from_buffer(buffer,len,offset,DeviceBuffer,sst); }
//File Operations Write Methodu static ssize_t DeviceWrite(struct file *filep, const char __user *buffer, size_t len, loff_t *offset){ printk(KERN_ALERT "DeviceWrite : çalıştırıldı.\n"); BufferSize = len; if (BufferSize > MAX_SIZE) { BufferSize = MAX_SIZE; } if (copy_from_user(DeviceBuffer, buffer, BufferSize)) { printk(KERN_ALERT "DeviceWrite : Device dosyası kopyalanmadı\n"); return -EFAULT; } if(BufferSize == MAX_SIZE) { if(Validate(DeviceBuffer,len) == 1) { SetLEDs(DeviceBuffer); } else { printk(KERN_ALERT "Geçersiz Karakter girildi.\n"); } } return BufferSize; }
//Girilen Karakter string in doğruluğunu kontrol edilmesi static int Validate(char *s,int l) { int i = 0; for(i=0;i<l-1;i++) { if(s[i] != '0' && s[i] != '1') { return 0; } } return 1; }
//Girilen 3 bitlik ([101] vb.) yapıya göre LED ışıklarının yanmasını sağlayan yapı static void SetLEDs(char *v) { //[***] //[0] CapsLock //[1] NumLock //[2] ScrollLock //int c = 0x04 * v[0]; //int n = 0x02 * v[1]; //int s = 0x01 * v[2]; printk(KERN_ALERT "----%d-%x----\n",((v[0] == '0') ? ZERO : cc )+((v[1] == '0') ? ZERO : nn)+((v[2] == '0') ? ZERO : ss),((v[0] == '0') ? ZERO : cc )+((v[1] == '0') ? ZERO : nn)+((v[2] == '0') ? ZERO : ss)); if(v[0] == '0' && v[1] == '0' && v[2] == '0') { ((ttyDriver->ops)->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED,0xFF); } else { ((ttyDriver->ops)->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED, ((v[0] == '0') ? ZERO : cc )+((v[1] == '0') ? ZERO : nn)+((v[2] == '0') ? ZERO : ss)); } } module_init(onStart); module_exit(onExit);
Klavye ledlerini yakmak için yazdığımız c kodunda LED durumu bir baytın 3 ilk bitinde aynı sırada saklanması yoluyla gerçekleştirdik.
  * Klavyedeki LED'ler şu şekildedir:
* Bit 0: CapsLock LED'i
  * Bit 1: NumLock LED'i
* Bit 2: ScrollLock LED'i
     
     3: Makefile Yazılması

obj-m = Keyboard.o
all:
 make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
   
     4: Modülün derlenmesi ve aktif olması


# make (derleme)
# insmod Keyboard.ko (aktif etme)
# rmmod Keyboard(inaktif etme)


     5: Dosyamıza veri yazılması ya da okunması
       
       Modül üzerinde ki Write methodu ile dosyaya veri yazmak için "echo"komutu kullanılır.

#### Dosyamıza veri yazmak için ####
# echo "ledleri yakmak içintercih ettiğiniz bit kombinasyonu" > /dev/DevName
# echo "111">/dev/NativeCore
# dmesg

    Örneğin echo “111”>/dev/NativeCore çalıştırdığımızda CapsLock LED'i
NumLock LED'i ve  ScrollLock LED'inin tümü yanacaktır.

   

   dmesg komutunu yazarak  çalışan DeviceWrite durumunu gözlemleyebiliriz;


     
     5: Dosyamıza veri yazılması ya da okunması


#rmmod Keyboard
Olası Hatalar ve Çözümleri

1: "Makefile:3: *** missing separator. Stop".
Makefile dosyanızda boşluk(Space) karakterleri olabilir,bu karakterler yerine TAB karakteri koymalısınız.
2: "make not found"
Bu hata Kernel Kaynak kodlarının bozulması sonucunda meydana gelir, güncel Kerneli indirip tekrar derlenip kurulması gerekir.
3"Bad Adrress" or "Is not proccess"
Bu hata genellikle Write Read methodları içinde veri okurken copy_to_user yada copy_from_user fonksiyonlarının karıştırılması sonucu oluşur 
4:"Could not save file"
Bu hata Kernel Dosyalarını değiştirmek için yönetici izninizin  olmadığını belirtir.

Yönetici şifrenizi oluşturmadıysanız 
# sudo passwd root
Yönetici olarak terminalde işlem yapmak için 
# su
C dosyasının derlerken alınan hatalar için komut satırı incelenmeli ve hataların ayıklanması gerekmektedir. En çok karşılaşan hatalar /proc dosyası için tanımlanan write/read methodlarının geri dönüş tipi yada parametlerin hatalı olmasından kaynaklamakdatır.

Olası hata kodlarının anlamları
/usr/include/asm-generic/errno-base.h
#ifndef _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_H

#define EPERM        1  /* Operation not permitted */
#define ENOENT       2  /* No such file or directory */
#define ESRCH        3  /* No such process */
#define EINTR        4  /* Interrupted system call */
#define EIO      5  /* I/O error */
#define ENXIO        6  /* No such device or address */
#define E2BIG        7  /* Argument list too long */
#define ENOEXEC      8  /* Exec format error */
#define EBADF        9  /* Bad file number */
#define ECHILD      10  /* No child processes */
#define EAGAIN      11  /* Try again */
#define ENOMEM      12  /* Out of memory */
#define EACCES      13  /* Permission denied */
#define EFAULT      14  /* Bad address */
#define ENOTBLK     15  /* Block device required */
#define EBUSY       16  /* Device or resource busy */
#define EEXIST      17  /* File exists */
#define EXDEV       18  /* Cross-device link */
#define ENODEV      19  /* No such device */
#define ENOTDIR     20  /* Not a directory */
#define EISDIR      21  /* Is a directory */
#define EINVAL      22  /* Invalid argument */
#define ENFILE      23  /* File table overflow */
#define EMFILE      24  /* Too many open files */
#define ENOTTY      25  /* Not a typewriter */
#define ETXTBSY     26  /* Text file busy */
#define EFBIG       27  /* File too large */
#define ENOSPC      28  /* No space left on device */
#define ESPIPE      29  /* Illegal seek */
#define EROFS       30  /* Read-only file system */
#define EMLINK      31  /* Too many links */
#define EPIPE       32  /* Broken pipe */
#define EDOM        33  /* Math argument out of domain of func */
#define ERANGE      34  /* Math result not representable */

#endif
/usr/include/asm-generic/errno.h
#ifndef _ASM_GENERIC_ERRNO_H
#define _ASM_GENERIC_ERRNO_H

#include <asm-generic/errno-base.h>

#define EDEADLK     35  /* Resource deadlock would occur */
#define ENAMETOOLONG    36  /* File name too long */
#define ENOLCK      37  /* No record locks available */
#define ENOSYS      38  /* Function not implemented */
#define ENOTEMPTY   39  /* Directory not empty */
#define ELOOP       40  /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN  /* Operation would block */
#define ENOMSG      42  /* No message of desired type */
#define EIDRM       43  /* Identifier removed */
#define ECHRNG      44  /* Channel number out of range */
#define EL2NSYNC    45  /* Level 2 not synchronized */
#define EL3HLT      46  /* Level 3 halted */
#define EL3RST      47  /* Level 3 reset */
#define ELNRNG      48  /* Link number out of range */
#define EUNATCH     49  /* Protocol driver not attached */
#define ENOCSI      50  /* No CSI structure available */
#define EL2HLT      51  /* Level 2 halted */
#define EBADE       52  /* Invalid exchange */
#define EBADR       53  /* Invalid request descriptor */
#define EXFULL      54  /* Exchange full */
#define ENOANO      55  /* No anode */
#define EBADRQC     56  /* Invalid request code */
#define EBADSLT     57  /* Invalid slot */

#define EDEADLOCK   EDEADLK

#define EBFONT      59  /* Bad font file format */
#define ENOSTR      60  /* Device not a stream */
#define ENODATA     61  /* No data available */
#define ETIME       62  /* Timer expired */
#define ENOSR       63  /* Out of streams resources */
#define ENONET      64  /* Machine is not on the network */
#define ENOPKG      65  /* Package not installed */
#define EREMOTE     66  /* Object is remote */
#define ENOLINK     67  /* Link has been severed */
#define EADV        68  /* Advertise error */
#define ESRMNT      69  /* Srmount error */
#define ECOMM       70  /* Communication error on send */
#define EPROTO      71  /* Protocol error */
#define EMULTIHOP   72  /* Multihop attempted */
#define EDOTDOT     73  /* RFS specific error */
#define EBADMSG     74  /* Not a data message */
#define EOVERFLOW   75  /* Value too large for defined data type */
#define ENOTUNIQ    76  /* Name not unique on network */
#define EBADFD      77  /* File descriptor in bad state */
#define EREMCHG     78  /* Remote address changed */
#define ELIBACC     79  /* Can not access a needed shared library */
#define ELIBBAD     80  /* Accessing a corrupted shared library */
#define ELIBSCN     81  /* .lib section in a.out corrupted */
#define ELIBMAX     82  /* Attempting to link in too many shared libraries */
#define ELIBEXEC    83  /* Cannot exec a shared library directly */
#define EILSEQ      84  /* Illegal byte sequence */
#define ERESTART    85  /* Interrupted system call should be restarted */
#define ESTRPIPE    86  /* Streams pipe error */
#define EUSERS      87  /* Too many users */
#define ENOTSOCK    88  /* Socket operation on non-socket */
#define EDESTADDRREQ    89  /* Destination address required */
#define EMSGSIZE    90  /* Message too long */
#define EPROTOTYPE  91  /* Protocol wrong type for socket */
#define ENOPROTOOPT 92  /* Protocol not available */
#define EPROTONOSUPPORT 93  /* Protocol not supported */
#define ESOCKTNOSUPPORT 94  /* Socket type not supported */
#define EOPNOTSUPP  95  /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT    96  /* Protocol family not supported */
#define EAFNOSUPPORT    97  /* Address family not supported by protocol */
#define EADDRINUSE  98  /* Address already in use */
#define EADDRNOTAVAIL   99  /* Cannot assign requested address */
#define ENETDOWN    100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET   102 /* Network dropped connection because of reset */
#define ECONNABORTED    103 /* Software caused connection abort */
#define ECONNRESET  104 /* Connection reset by peer */
#define ENOBUFS     105 /* No buffer space available */
#define EISCONN     106 /* Transport endpoint is already connected */
#define ENOTCONN    107 /* Transport endpoint is not connected */
#define ESHUTDOWN   108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS    109 /* Too many references: cannot splice */
#define ETIMEDOUT   110 /* Connection timed out */
#define ECONNREFUSED    111 /* Connection refused */
#define EHOSTDOWN   112 /* Host is down */
#define EHOSTUNREACH    113 /* No route to host */
#define EALREADY    114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE      116 /* Stale NFS file handle */
#define EUCLEAN     117 /* Structure needs cleaning */
#define ENOTNAM     118 /* Not a XENIX named type file */
#define ENAVAIL     119 /* No XENIX semaphores available */
#define EISNAM      120 /* Is a named type file */
#define EREMOTEIO   121 /* Remote I/O error */
#define EDQUOT      122 /* Quota exceeded */

#define ENOMEDIUM   123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED   125 /* Operation Canceled */
#define ENOKEY      126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED    129 /* Key was rejected by service */

/* for robust mutexes */
#define EOWNERDEAD  130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */

#endif

Linux Terminal Komutları
1: "cd" istenilen klasöre girilmesi
2: "ls" klasör içeriğinin görülmesi
3: "mkdir" klasör oluşturulması
4: "gedit" dosya açılması yada düzenlenmesi
5: "su" yönetici olarak girilmesi
6: "dmesg" kernel/debug mesajlarının görülmesi
7: "make" kernele ait komut olup derlenme işlemini yapar
8: "insmod" kernel modülünün aktif olması
9: "rmmod" kernel modülünün inaktif olması
10: "echo" veri yazılması
11: "cat" veri okunması
12: "lsmod" modüllerin listelenmesi

*tty_driver kaynak kodu (Tıklayınız)
Grup Üyeleri
DEMET AKYOL (Takım Lideri)

Yorumlar

Bu blogdaki popüler yayınlar

Web Servis ve Kimlik Doğrulama (Authentication) Yöntemleri

Linux Kernel ile Raspberry Pi 3'den TCP Protolü Ile Sensör Verileri Alınması

Yazılım Kalite Metrikleri