18 Eylül 2017 Pazartesi

Linux Device Driver

Giriş
Şuna benzer satırlar dahil edilir.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/delay.h>
İskelet
Şöyledir
MODULE_LICENSE("GPL");
MODULE_AUTHOR("...");

static int __init irq_ex_init(void)
{
  ...
}

static void __exit irq_ex_exit(void)
{
  ...
}

module_init(irq_ex_init);
module_exit(irq_ex_exit);
module_init
Her sürücü için modülü yükleyen  şu metod lazım.
module_init(mydriver_init);
mydriver_init'in imzası şöyle. Metodun static olması isteğe bağlı
static int mydriver_init(void)
{...}
veya bazen __init ile kullanılıyor. Yani şöyle
static int __init mydirver_init(void)
{...}
Bu metodun içinde printk kullanılabilir. Sonuç olarak 0 dönülebilir. Şöyle yaparız.
int mydriver_init(void)
{
  printk(KERN_DEBUG "module initiated\n");
  ...
  return 0;
}
module_exit
Her sürücü için modülü kaldıran şu metod lazım.
module_exit(mydriver_exit);
mydriver_exit'in imzası şöyle.
static void mydriver_exit(void)
{...}
veya bazen __exit ile kullanılıyor.  Yani şöyle
static void __exit mydriver_exit(void)
{...}
Bu metodun içinde print kullanılabilir. Şöyle yaparız.
void mydriver_exit(void)
{
  ...
  printk(KERN_DEBUG "module removed\n");
}
MODULE_X Macroları
Şöyle yaparız.
module_init(initialize);
module_exit(final);

MODULE_AUTHOR("...");
MODULE_DESCRIPTION("...");
MODULE_LICENSE Macrosu
Şöyle yaparız.
MODULE_LICENSE("GPL");
Şöyle yaparız.
MODULE_LICENSE("Dual BSD/GPL");
Struct ve Function Pointer
Device Deriver yazarken bir sürü struct ve function pointer kullanıyoruz. Mantık şuna benziyor. Önce bir header dosyasında struct ve function imzaları tanımlarız.
struct tune_if_t
{
  void (*init_radio)      (void);
  void (*calibrate_radio) (void);
};

extern const struct tune_if_t tune_if;
Daha sonra bu struct'ın bir nesnesini yaratırız ve ilklendiririz.
// function bodies that do things
void radio1_init_radio(void) {}
void radio1_calibrate_radio(void) {} 

// populate global tune interface
const struct tune_if_t tune_if =
{
  .init_radio        = radio1_init_radio,
  .calibrate_radio   = radio1_calibrate_radio
}
Bu struct artık class gibi kullanılabilir. Sanırım bu yüzden Linux Device Drive kodlarındaki alanlar . karakteri ile başlıyor.
int main( void )
{
  // interface calls
  tune_if.init_radio();
  tune_if.calibrate_radio();

  return 0;
}
pci sürücü yaratma

1. pci_module_init metodu
mydriver_init içinde pci_module_init metodu çağrılarak yapılır. Önce cihazımız için kullanacağımız metodları bir yapıya yerleştiririz. Aşağıdaki örnekte suspend ve resume alanlar gösterilmiyor.
static struct pci_driver pci_drv = {
  .name= "pci_drv",
  .id_table= pci_drv_tbl,
  .probe= device_init,
  .remove= device_deinit,
};
Daha sonra cihazımı ilklendiririz.
pci_module_init(&pci_drv)
Bu çağrı sonucu tanımladığımız probe metodumuz tetiklenir

pci_driver yapısını ilklendirirken kullanacağımız metodların imzaları şöyle.

2. pci_enable_device metodu
Bu metod pci_request_regions() çağrısından önce yapılır.

3. id_table alanı 
Kullanılan değerler şöyle
// Hardware specific part
#define MY_VENDOR_ID 0x5333
#define MY_DEVICE_ID 0x8e40
Yapısı şöyle
static struct pci_device_id pci_drv_tbl[] __devinitdata = {
{ MY_VENDOR_ID,           // manufacturer identifier
  MY_DEVICE_ID,           // device identifier
  PCI_ANY_ID,             // subsystem manufacturer identifier
  PCI_ANY_ID,             // subsystem device identifier
  0,                      // device class
  0,                      // mask for device class
  0 },                    // driver specific data
  { 0, }
};
4. probe metodu
probe metodu şöyle bir imzaya sahip.
// Check if this driver is for the new device
static int device_init(struct pci_dev *dev,const struct pci_device_id *id)
{...}
5. remove
remove metodu şöyle bir imzaya sahip.
// Function for deinitialization of the device
static void device_deinit( struct pci_dev *pdev )
{...}
6. request_irq metodu
Interrupt callback için kullanılır. İmzası şöyle. Birinci parametre IRQ index sayısıdır.
request_irq(int num, void * interrupt_handler, static char *interrupt_name,
 struct platform_device *platform);
pci_dev yapısı
bus alanı
Şöyledir
struct pci_bus  *bus;
devfn Alanı
Açıklaması şöyle.
Devfn contains the device number in bits 7:3 and the function number in bits 2:0.
Şöyle yaparız.
device = PCI_SLOT(pdev->devfn);
fn =  PCI_FUNC(pdev->devfn);
function alanı
Şöyledir
unsigned int    devfn;  
printk metodu
Bu metod tek parametre alır. Şöyle yaparız.
printk(KERN_ALERT "hello, this is hello module");
Şu örnek derlenmez.
printk(KERN_ALERT, "hello, this is hello module");




Hiç yorum yok:

Yorum Gönder