19 Mart 2011 Cumartesi

Windows Sağ Tuş Menüsünü Yönetmek


Bu yazı daha önce saltokunur.org e-dergisinde yayınlanmıştır. 

Bilgisayarınıza çok sık program kurup kaldırıyorsunuz ve gün geçtikçe sağ tuş menünüz ne işe yaradığını bile bilmediğiniz girdilerle doldu. Ya da belirli dosyalar/klasörler üzerinde bazı işlemleri çok sık yapıyorsunuz ve "keşke şu işlem için bir kısayol olsa" diye düşünüyorsunuz.
Bu ay hem sağ tuş menüsünü gereksiz girdilerden temizleyip bu can sıkıcı durumu düzeltiyor hem de yararlı kısayollar ekleyip bilgisayar deneyiminizi daha eğlenceli hale getiriyoruz. Hadi başlayalım.

Türkçe'ye kullanımından Sağ Tuş Menüsü (STM) olarak çevirebileceğimiz menü, herhangi bir klasöre, programa, dosyaya masaüstünde ya da herhangi bir klasörün içindeyken farenin sağ tuşuna basılınca çıkan menüdür. Bilgisayar dünyasında Sağ Tuş Menü (Right Click Menu), Dizin Menüsü (Context Menu), Kabuk Menüsü (Shell Menu), İşlev Menüsü şeklinde isimleri vardır.
Windows'ta STM girdisi genelde iki şekilde eklenir.
Birincisi Windows Kayıt Defteri'ne programın ya da sistemin uygun girdisi altında "shell" ya da "shellex" altında yeni girdileri oluşturulup uygun ayarlar atanırsa STM'ye girdi eklenmiş olur. Buralardaki girdiler değiştirilip silinerek STM yönetilebilir.
İkinci yöntem ise "context menu dll'lerini" sisteme kaydettirmek (DLL Register işlemi). Bazı programlar STM girdilerini bir dll dosyası içinde tutar. Bu dll dosyalarını Program Files altında bulabilirsiniz. Windows komut satırından "regsvr32 dosyaAdi.dll" komutunu çalıştırarak, STM'ye programın girdisini ekleyebilirsiniz. "regsvr32 /u dosyaAdi.dll" komutu da sistemde kayıtlı bir girdiyi kaldırmaya yarar. Bu duruma canlı bir örnek vermek gerekirse, çoğumuzun kullandığı Notepad++ programının Program Files dizininde "nppcm.dll" adında bir dosya var. Bu dosyaya sağ tıklayıp özelliklerine bakarsanız dosyanın STM girdisi oluşturduğunu görürsünüz (Context Handler Menu for Notepad++). Az önceki komutları kullanarak Notepad++ girdisini STM'den kaldırabilirsiniz.







Kayıt Defteri Kullanarak STM'den Girdilerini Düzenlemek
STM girdileri kayıt defterinde genellikle HKEY_CLASSES_ROOT altında tutulur. HKEY_CLASSES_ROOT altında sisteminizin tanıdığı bütün dosya uzantılarını görebilirsiniz. Burada \shellex 'in altındaki girdileri düzenleyip ayrı ayrı her dosya tipi için STM girdilerini belirleyebilirsiniz. En üstte bulunan "*" altında ise  sadece belli bir dosya tipine göre değil tüm STM'lerde beliren girdiler bulunur. Eğer girdiler {XXXXXXXX­XXXX­XXXX­XXXX­XXXXXXXXXXXX} şeklinde ise, ifadeyi Kayıt Defteri'nde ya da Google'da aratarak ne işe yaradığı hakkında fikir edinebilirsiniz. Diğer önemli STM kayıtlarının bulunduğu Kayıt Defteri girdileri: 
  • Bilgisayarım: CLSID\{20D04FE0­3AEA­1069­A2D8­08002B30309D}\shell  
  • Internet Explorer: CLSID\{871C5380­42A0­1069­A2EA­08002B30309D}\shell  
  • : CLSID\{F02C1A0D­BE21­4350­88B0­7367FC96EF3C}\shell  
  • Başlat Menüsü: Directory\Shell

Klasör Seçenekleri'ni Kullanarak STM Girdilerini Düzenlemek
Sadece belirli dosya türlerine ait STM girdilerini düzenlemek için Denetim Masası>Klasör Seçenekleri>Dosya Türleri altından bulanan seçenekleri kullanabilirsiniz. Burada istediğiniz dosya türünü seçip "Gelişmiş" e tıkladığınızda, o dosya türüne ait tüm girdileri görebilir, yeni girdiler ekleyip, istemediklerinizi silebilirsiniz.























Bir çok programın STM'ye girdi ekleyip eklememesini programın ayarlarından kontrol edebilirsiniz. Genelde programın ayarlar bölümünde sistem sekmesi altında STM ile ilgili seçenekler bulunur. Şimdi size bazı durumda STM'nüzü neredeyse yarıya indirecek bir ipucu vereyim. Bazı dosyalara sağ tıkladığınızda WinRAR'ın çıldırmış gibi STM'yü doldurmuş oldurduğunu görürsünüz (Ekran görüntüsünde 8 tane :) Ama WinRAR'ın ayarları içinden "Bütünleşme" sekmesinde "Uzayan işlev menüleri" seçeneğini aktifleştirirsiniz bütün bu winrar girdileri STM'de bir alt menü altında görüntülenecektir.

Kişiselleştirme
STM'müzü gereksiz girdilerden temizledik şimdi ona daha gelişmiş özellikler katmaya ne dersiniz.
Bilgisayarınızda çok sık yaptığınız işlemler için STM'ye kısayollar, özelikler ekleyebilirsiniz. Örneğin sık sık bir dosyayı/klasörü açıyorsunuz, komut satırı üzerinden "cd" ile bulunduğunuz dizini değiştiriyorsunuz, dosyaların uzantılarını, gizli dosyaları gösterip gizliyorsunuz...
Bu işlemlerini hepsi ve daha fazlası için küçük STM eklentilerini internetten bulabilirsiniz. (“Sağ tuş eklentileri” diye google’da arama yapmanız yeterli). İşinize yarayabilecek girdilerden bazıları:

 

Masaüstü STM:
  • Gizli dosyaları göster gizle
  • Klasöre kopyala-taşı
  • Komut penceresi aç
  • Masaüstünü göster










Bilgisayarım STM:
  • Program Ekle Kaldır
  • Disk Temizle
  • Denetim Masası
  • Aygıt Yöneticisi
  • Olay Görüntüleyicisi
  • Kayıt Defteri
  • Hizmetler













STM'ye kendinize ait girdiler eklemek ise çok kolay. Belli bir dosya tipine özel bir girdi ekleyecekseniz yukarıda anlattığım Klasör Seçenekleri ipucunu takip edebilirsiniz. Dosya türünü düzenlediğiniz ekranda "Yeni" düğmesine tıklayarak girdiye bir isim ve girdinin çalıştıracağı komutu belirmeniz yeterli.
Kayıt Defteri ipucunda anlattığım yerlere özel bir girdi ekleyecekseniz, istediğiniz Kayıt Defteri yolu altında "\shell" altında yeni bir anahtar oluşturun. Anahtarın adı STM'de gözüken metin olacaktır.
HKEY_CLASSES_ROOT\CLSID\{20D04FE0­3AEA­1069­A2D8­08002B30309D}\shell\Filmleri Aç
Bu anahtarın altında "command" adında yeni bir anahtar oluşturun. "(Varsayılan-Default)" kayıt girdisine çalıştırılacak komutu girin.
Vista kullanıcılarına özel bir ipucu: Vista’da herhangi bir klasörde boş bir yere “Shift” tuşu basılıyken sağ tıklarsanız, normalde gizli olan “Komut Satırı Aç” girdisini görebilirsiniz. Sık sık cmd’de “cd” ile klasör değiştirenlerin işine yarayacaktır.
STM'nüzü düzenlemek için illa ki her program için kayıt defterinde iğne aramak, hangi dll in ne işe yaradığını bilmenize gerek yok. Bu iş kullanabileceğiniz birkaç ücretsiz program:
ShellExView: Bu program STM'ye kaydolmuş bütün girdileri ad, uzantı,program ad ve özelliklerine göre listeliyor. Program içinden girdileri aktif edip kapatabilir, böylelikle daha temiz bir STM'ye sahip olabilirsiniz.



Folder Guide: Sıklıkla açtığınız klasörleri programa ekliyorsunuz. Ekranda herhangi bir yere sağ tıkladığınızda klasörleriz emrinizde.



FileMenuTools:STM'nünüzü yönetmek için bir başka güzel araç. Üstelik ücretsiz.



WinBubble: Windows için ayar (Tweak) aracı.

Gönder (Send To) Menüsünü Düzenlemek
Gönder Menüsü aslında “C:\Documents and Settings\Kullanıcı_Adı“  (Vista için: “C:\Users\Kullanici_Adi” olabilir) altında Send To adında bir klasördür (Bu klasör genelde gizlidir, görünmüyorsa gizli dosyaları göstermeniz gerekebilir). Burada Gönder menüsündeki programların "kısayolları" bulunur. Bu kısayolları silerek istemediğiniz girdileri kaldırabilirsiniz. Ya da kendi kısayolunuzu ekleyerek yeni bir girdi ekleyebilirsiniz.
Örneğin arşiv amaçlı kullandığınız bir klasörünüz var. Bu klasöre kopyalayacağınız dosyaları sadece Sağ Tık>Gönder komutu ile kopyalamak ister miydiniz? Hem de dosyalarınız nerde olursa olsun. Send To klasörünün içinde sağ tıklayıp "Yeni>Kısayol" komutu ile ona bir kısayol oluşturmanız yeterli.





Gelecek ay görüşmek dileğiyle…

Kaynaklar

Linux Sürücü Yazma-3

Bu yazı daha önce saltokunur.org e-dergisinde yayınlanmıştır.


Herkese merhabalar. İki aydır sürücü yazmak için gerekli bilgileri öğrendik. Artık bu kadar uğraşımızın meyvesini almaya, sürücümüzü yazmanın vakti geldi.
Daha önce öğrendiğimiz bilgiler ışığında ne yapmak istediğimizi kararlaştıralım. Biz kesmelerle çalışan, char tipli bir USB Fare için sürücü yazmaya çalışıyoruz.
Bu yazıda anlatılan kodların tamamı David Olivera’nın Logitech Media Play Cordless Mouse için yazdığı lmpcm_usb.c sürücüsü temel alınarak yazılmış ve A4Tech R7 Mouse için bazı değişiklikler yapılmıştır. Benim de hala anlamadığım ve açıklamakta zorlandığım noktalar var. Ama elimden geldiğince açıklamaya çalışacağım.

Dikkat!!! İLERİ DERECE C BÖLGESİ
Yazının buradan sonrası ağır derecede C içerir. Okuyucuların ileri derece C konuları ile aşina olması gerekliliği vardır. Yoksa okuduğunuzdan hiçbir şey anlamayabilirsiniz. Alıcılarınızın ayarlarıyla oynamayın !!! 

Sürücümüzü bir modül halinde yazacağımızı daha önce belirtmiştik. Sürücüsünü yazacağımız farenin marka ve modeli A4Tech R7 olduğu için sürümüze a4r7mouse ismini veriyoruz ve diskimizde a4r7mouse.c adında bir C dosyası oluşturuyoruz. Bu dosyaya ilk önce aşağıdaki satırlar ile gerekli kütüphaneleri ekliyoruz.

#include <linux kernel.h>
#include <linux slab.h>
#include <linux input.h>
#include <linux module.h>
#include <linux init.h>
#include <linux usb.h>

Sonra aşağıdaki tanımlamaları yapıp devamındaki makrolarla sürücünün bilgilerini çekirdeğe giriyoruz.

#define DRIVER_VERSION "v0.0.1"
#define DRIVER_AUTHOR "Hamza Apaydin hamzaapaydin@hotmail.com"
#define DRIVER_DESC "USB A4Tech Power Saver R7 Wireless Mouse Driver"
#define DRIVER_LICENSE "GPL"

MODULE_AUTHOR ( DRIVER_AUTHOR );
MODULE_DESCRIPTION ( DRIVER_DESC );
MODULE_LICENSE ( DRIVER_LICENSE );

Sonra ne işe yaradığını benim de bilmediğim, ama çekirdeğin kullandığını tahmin ettiğim bazı koşullu derleme komutlarını ekliyoruz.

#ifdef SLAB_ATOMIC
# define ATOMIC SLAB_ATOMIC
#else
# define ATOMIC GFP_ATOMIC
#endif

Sonra sürücümüzün en temel yapısını (struct) yazıyoruz. Bu yapı sisteme bağlanan A4Tech R7 Mouse’un çekirdekteki mantıksal (logic) karşılığı olacak. Biz bu yapının bir örneğini oluşturup yanına bu yapıdaki URB ‘ler için IH’ler yazıp, daha başka eklerle sisteme bir struct usb_driver örneği olarak kaydedeceğiz.

typedef struct usb_a4r7mouse {
 // Cihazın adı
 char name[128];  
 // USB gelen interrupt verisi. İşte cihazdan gelen verilere buradan erişeceğiz.
 signed char *data;  
 //TODO bunun ne anlama geldiğini bul
 char phys[64];
 // cihazın DMA adresi
 dma_addr_t data_dma;
 //USB portuna takılan cihazın logic gösterimini tutan struct
 struct usb_device *usbdev;
 // cihazdan girdileri almada kullanacağımız struct
 struct input_dev *inputdev;
 // cihazdan gelen USB Request block
 struct urb *urb;
 // cihazın açılma sayısı
 int open;
} a4r7mouse_t;
//En son olarak bu yapıdan a4r7mouse_t adında bir örnek oluşturuyoruz.

Sonra bu oluşturduğumuz örneğe ilk değerlerini atayacak olan (initialize) fonksiyonu yazıyoruz. memset ile hafızada a4r7mouse yapısının boyutu kadar yer ayırıyoruz.

void a4r7mouse_init ( a4r7mouse_t *a4r7mouse ) {
 memset(a4r7mouse, 0, sizeof(a4r7mouse_t));
 a4r7mouse->inputdev = NULL;
 a4r7mouse->urb = NULL;
 a4r7mouse->data = NULL;
}

Burada cihaz sistemden kaldırıldığında cihazın kullandığı kaynakları serbest bırakan fonksiyonu yazıyoruz. Cihazın urb’si boş değilse usb_free_urb ile, data’sı boş değilse de cihazın kullandığı tampon usb_buffer_free ile serbest bırakıyor.

void a4r7mouse_free ( a4r7mouse_t *a4r7mouse ) {
 if ( a4r7mouse->urb )
  usb_free_urb(a4r7mouse->urb);
 if ( a4r7mouse->data )
  usb_buffer_free(a4r7mouse->usbdev,8,a4r7mouse->data,a4r7mouse->data_dma);
 kfree(a4r7mouse);
}

Bu fonksiyon ise parametre olarak bir usb_device struct’ı alıp geriye yeni a4r7mouse nesnesi döndürüyor. Bu fonksiyonun kullanımını aşağıda probe fonksiyonu içinde çağırımından sonra daha iyi anlayacaksınız.
Buradaki usb_device sistemdeki USB Core’ı tarafından
Sisteme her USB cihaz bağlandığında cihazın bağlandığı USB interface alınır ve aşağıdaki probe fonksiyonunda

a4r7mouse_t *a4r7mouse_new ( struct usb_device *dev ) {
 a4r7mouse_t *a4r7mouse;
 // kmalloc ile struct’a bellekten yer ayrılıyor.
 if (!(a4r7mouse = kmalloc(sizeof(a4r7mouse_t), GFP_KERNEL)))
  return NULL;
 // az önce yazdığımız init fonk. Çağrılarak a4r7mouse örneği initialize ediyor.
 a4r7mouse_init(a4r7mouse);
 // Input device için yer ayrılıyor.
 if ( (a4r7mouse->inputdev = input_allocate_device()) == NULL ) {
  a4r7mouse_free(a4r7mouse);
  return NULL;
 }
 //  urb handler için bellekte yer ayır.
 if (!(a4r7mouse->urb = usb_alloc_urb(0, GFP_KERNEL))) {
  a4r7mouse_free(a4r7mouse);
  return NULL;
 }
 // urb deki data’yı göndermek ve almak için kullanılacak tamponu oluştur.
 if (!(a4r7mouse->data = usb_buffer_alloc(dev,8,ATOMIC,&a4r7mouse->data_dma))) {
  a4r7mouse_free(a4r7mouse);
  return NULL;
 }
 //  a4r7mouse nin  usb device alanına fonksiyona parametre olarak gelen usb_device’ı ata
 a4r7mouse->usbdev = dev;
 return a4r7mouse;
} 

İşte URB’den gelen datayı alıp, işleyip Linux çekirdeğine gönderen fonksiyonumuz. Burada data dizisinden bitmapte gösterildiği sırada verileri alıyoruz. input_report_key() fonksiyonları ile sisteme girdi tuşlarını kaydediyoruz. Bu fonksiyonun çağrılarında kullanılan BTN_LEFT gibi sabitler input.h’da tanımlıdır. Burada yapılacak herhangi bir değişiklik ile örneğin;

input_report_key(dev, BTN_LEFT,    GETBIT(btn,0)); 
satırında KEY_A yazılırsa farenin sol tuşuna basılınca, sol tıklama olayı değil de klavyeden A tuşuna basılmış gibi bir tepki verir bilgisayar.

void input_send_data ( struct input_dev *dev, char *data ) {
 //data dizisindeki bitleri alıyoruz.
 char btn = data[0], // ilk 8 bit. Sol, sağ, orta tuş için
  x = data[1], // X  ekseninde hareket
  y = data[2], // Y ekseninde hareket
  w = data[3]; // tekerleğin hareketi 

Burada printk ile data bitlerini yazdırırsak tuşların bit karşılıklarını buluruz ve bir çeşit tersine mühendislik yapmış oluruz. Biz de burada bunu yaparak faremizdeki ekstra tuşların bit haritasını elde edebiliriz.

input_report_key(dev, BTN_LEFT,    GETBIT(btn,0));
 input_report_key(dev, BTN_RIGHT,   GETBIT(btn,1));
 input_report_key(dev, BTN_MIDDLE,  GETBIT(btn,2));
 input_report_key(dev, BTN_SIDE,   GETBIT(btn,3));
 input_report_key(dev, BTN_EXTRA,   GETBIT(btn,4));

 input_report_rel(dev, REL_X,     x);
 input_report_rel(dev, REL_Y,     y);
 input_report_rel(dev, REL_WHEEL, w);
}

GETBIT(btn,0) 

İfadesi ise datanın bitlerini maskelemeye yarayan GETBIT makrosunun çağrısıdır. Bu makro data dizisinin ikinci parametrede belirtilen bitini döner. Tabii bu makronun tanımı da kodların arasına eklemelisiniz.

#define GETBIT(v,n)     ((v>>(n))0x01)
#define SETBIT(v,n)     (v |= (0x01<<(n))) 

Bu fonksiyon ise cihazımızdan her URB geldiğinde çalışacak olan Interrupt Handler. Burada URB’nin içinden fare nesnesi elde ediliyor. Taşıdığı data alınıyor. Az önce yazdığımız input_send_data() çağrısı ile basılan tuşlar sisteme kaydediliyor. En son usb_submit_urb çağrısı ile URB USB Core’a gönderiliyor.

static void usb_a4r7mouse_handle(struct urb *urb) {
 a4r7mouse_t *mouse = urb->context;
 signed char *data = mouse->data;
 struct input_dev *inputdev = mouse->inputdev;
 // Check returned status
 if (urb->status) return ;
 // Send data to input interface
 input_send_data(inputdev,data);
 input_sync(inputdev);
 usb_submit_urb(urb,ATOMIC);
} 

Cihazın açma ve kapatma fonksiyonları

static int usb_a4r7mouse_open(struct input_dev *dev) {
 a4r7mouse_t *mouse = input_get_drvdata(dev);
 if (mouse->open++)
  return 0;
 mouse->urb->dev = mouse->usbdev;
 if (usb_submit_urb(mouse->urb, GFP_KERNEL)) {
  mouse->open--;
  return -EIO;
 }
 return 0;
}

static void usb_a4r7mouse_close(struct input_dev *dev) {
 //a4r7mouse_t *mouse = dev->private;
 a4r7mouse_t *mouse = input_get_drvdata(dev);
 if (!--mouse->open)
  usb_kill_urb(mouse->urb);
} 

Yazdığımız modülün çekirdek tarafından sürücü olarak tanınması olarak tanınması için. Bir “struct usb_driver” örneği oluşturup, bu örneğin içini gerekli bilgilerle doldurmalıyız. Bu yapıda; name sürücünün adını belirtir ve sistemde benzersiz olmalıdır probe ise sürücünün iş yapan fonksiyonuna bir işaretçidir. Donanım ile iletişime geçen fonksiyon budur. Disconnect de cihaz sistemden kaldırıldığında çalışacak olan (muhtemelen cihaza ayrılan sistem kaynaklarının serbest bırakıldığı) fonksiyona bir işaretçidir. İd_table ise geçen sayıda anlattığımız bu sürücünün hangi cihazlar için yüklenmesi gerektiğini belirten, bu cihazların Vendor ve Product ID’lerinin tutulduğu bir “usb_device_id” dizisidir.

static struct usb_driver usb_a4r7mouse_driver = {
 .name  = "a4r7mouse_usb",
 .probe  = usb_a4r7mouse_probe,
 .disconnect = usb_a4r7mouse_disconnect,
 .id_table = usb_a4r7mouse_id_table
}; 

Bizim cihazımız için bu dizi şu biçimdedir:
static struct usb_device_id usb_a4r7mouse_id_table [] = {
 { USB_DEVICE(0x09da, 0x021f) },
 { }
}; 

Buradaki 09da değerinin geçen sayıda elde ettiğimiz Vendor ID’ye 021f değerinin ise Product ID’ye karşılık geldiğine dikkat edin. Bu yapının içini cihaz ve üretici numaraları ile değil de usb.h içinde tanımlı olan bazı sabitleri kullanarak sadece bir cihaz için değil de belli bir tür sınıf (cihazın ayar registerlarında tanımlı olan) cihaz için geçerli olmasını sağlayabiliriz. Şu makro ile id_table ımızın bir usb id_table’ı olduğunu belirtiyoruz.

MODULE_DEVICE_TABLE (usb, usb_a4r7mouse_id_table); 

Disconnect metodumuz ise şöyle:

static void usb_a4r7mouse_disconnect(struct usb_interface *intf) {
 a4r7mouse_t *mouse = usb_get_intfdata(intf);
 usb_set_intfdata(intf,NULL);
 if (mouse) {
  usb_kill_urb(mouse->urb);
  input_unregister_device(mouse->inputdev);
  a4r7mouse_free(mouse);
 }
} 

Burada cihazın bağlı olduğu usb interface’den somut bir a4r7mouse nesnesi oluşturuyoruz. Sonra bu interface’ı boşaltıyoruz. Cihaz sistemden ayrılmadan önce bir urb göndermiş olabilir bu yüzden geçerli urb’yi öldürüyoruz (kill). Cihazı sistemden silip (input_unregister_device), Mouse nesnemizi boşaltıyoruz. Sonra yazı dizimizin ikinci bölümünde bahsettiğim, modülümüzün init fonksiyonunu yazıyoruz.

static int __init usb_a4r7mouse_init(void) {
 int rv;
 // usb sürücüyü sisteme kaydet
 rv = usb_register(&usb_a4r7mouse_driver);
 return rv;
} 

Hatırlarsanız modülleri anlatırken “bir modül init fonksiyonu içinde sürücüyü sisteme kaydetmelidir” demiştir. İşte burada da

rv = usb_register(&usb_a4r7mouse_driver); 

Çağrısı ile tam olarak bunu yapıyoruz. Modülün exit fonksiyonunda sürücüyü sistemden kaldırıyoruz.

static void __exit usb_a4r7mouse_exit(void) {
 usb_deregister(&usb_a4r7mouse_driver);
} 

Ve şu iki makro ile init ve exit fonksiyonlarını çekirdeğe tanıtıyoruz.

module_init(usb_a4r7mouse_init);
module_exit(usb_a4r7mouse_exit); 

Dikkat ettiğiyseniz usb_a4r7mouse_driver yapısının probe fonksiyonun açıklamadan geçtim. Asıl işi yapacak bu fonksiyon olduğu ve çok uzun olduğu için sona sakladım. Açıklamayı adım adım yapacağım önce fonksiyonun tanımı verelim sonra içini dolduralım.

static int usb_a4r7mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) { }

Bu fonksiyonu yazdığımız sürücünün hiçbir yerinde çağırmadığımıza dikkat edin. Bu fonksiyonu çekirdek cihazın bağlı olduğu interface ve cihazın vendor ve product id bilgisi ile birlikte çağırır ve sürücünün çalışması başlar. İlk satır ile fonksiyona gelen interface bilgisinden bir usb_device nesnesi elde ediyoruz.

struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
a4r7mouse_t *mouse;
int pipe, maxp;
char *buf; 

Her USB interface için o interface’in bilgilerini tutan endpoint denilen bir yapı vardır. Burada interface üzerinden endpoint alınıyor.

// Get mouse endpoint
interface = intf->cur_altsetting;
if ( interface->desc.bNumEndpoints != 1 ) return -ENODEV;
endpoint = &interface->endpoint[0].desc; 

Burada endpoint özellikleri kontrol ediliyor. Eğer endpointimiz interrupt ile veri gönderen bir endpoint ise bizim cihazımızın özelliklerini taşıyor demektir.

if (!(endpoint->bEndpointAddress & USB_DIR_IN))
  return -ENODEV;
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
  return -ENODEV; 

Endpoint ile iletişime geçecek pipe (kanal) oluşturuluyor.

pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 

Artık elimizdeki cihaz bir a4r7mouse nesnesi olabilecek niteliktedir. Elimizdeki dev nesnesinde bir a4r7mouse nesnesi oluşturuyoruz.

if (!(mouse = a4r7mouse_new(dev)))
 return -ENOMEM;
Ve bir input_device oluşturuyor ve initiliaze ediyoruz. Bu fonksiyonun açıklamasını daha sonra yapacağız.

input_device_init(mouse->inputdev,intf,mouse,dev); 

Bunların ne yaptığını ben de bilmiyorum :)

// Set device name
 if (!(buf = kmalloc(63, GFP_KERNEL))) {
  a4r7mouse_free(mouse);
  return -ENOMEM;
 }
 if (dev->descriptor.iManufacturer &&
  usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
   strcat(mouse->name, buf);
 if (dev->descriptor.iProduct &&
  usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
   sprintf(mouse->name, "%s %s", mouse->name, buf);
 if (!strlen(mouse->name))
sprintf(mouse->name, "a4r7mouse.c: A4Tech Power Saver R7 Wireless Mouse on usb%04x:%04x",
   mouse->inputdev->id.vendor, mouse->inputdev->id.product);
 kfree(buf); 

Burada bir başka önemli işlem yapılıyor. Bu cihaz için yazdığımız URB Handler (usb_a4r7mouse_handle) sisteme kaydediliyor. Ve cihazın dma modları ayarlanıyor.

usb_fill_int_urb(mouse->urb,dev,pipe,mouse->data,((maxp > 8)?8:maxp),usb_a4r7mouse_handle,mouse,endpoint->bInterval);
 mouse->urb->transfer_dma = mouse->data_dma;
 mouse->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

Cihaz input device olarak kaydediliyor. Artık bu cihazdan gelen sinyaller input API’ye gönderilecek.

input_register_device(mouse->inputdev);

Üzerinde çalışığımız inteface’in device bilgisi bizim Mouse nesnemize set ediliyor.

usb_set_intfdata(intf,mouse);
 return 0;

Son olarak input_device_dev fonksiyonu.

static void input_device_init ( struct input_dev *inputdev, struct usb_interface *intf, void *private, struct usb_device *dev ) {}
 
Tekrardan fonksiyona void pointer ile geçirilen a4r7mouse nesnemizi elde ediyoruz.

char path[64];
a4r7mouse_t *mouse = (a4r7mouse_t *) private;

input device ın özellikleri atanıyor. Önce farenin tıklama ve bırakma olayları.

inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);

Temel tuşlar

inputdev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) |    BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);

x-y ekreninde hareket

inputdev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);

Tekerin hareketi

inputdev->relbit[0] |= BIT_MASK(REL_WHEEL); 

Cihazla ilgili özellikler ayarlanıp fonksiyon bitiriliyor. (üretici, ad, versiyon, adres, açma kapama fonk.)

input_set_drvdata(inputdev, mouse);

 // Input file operations

 inputdev->open = usb_a4r7mouse_open;
 inputdev->close = usb_a4r7mouse_close;

 // Device

 inputdev->name = mouse->name;

 usb_make_path(dev,path,64);
 snprintf(mouse->phys,64,"%s/input0",path);

 inputdev->phys = mouse->phys;
 inputdev->id.bustype = BUS_USB;
 inputdev->id.vendor = dev->descriptor.idVendor;
 inputdev->id.product = dev->descriptor.idProduct;
 inputdev->id.version = dev->descriptor.bcdDevice;

Sürücüyü Çalıştır(ama)ma
Şimdi normalde daha önce verdiğim makefile ile bu modülü derleyip, insmod ile yüklediğinizde sürücünün çalışması lazım. Ancak daha önce sistemde hazır gelen sürücü fare sınıfındaki bütün cihazlar için tanımlandığı için bizim sürücümüzün önene geçmektedir. Yapmamız gereken bizim sürücümüzün bu genel sürücüden önce yüklenmesini sağlamaktır. Tabii bu söylendiği kadar kolay olmamaktadır. Bildiğiniz gibi linux’ta sürücüler modül olarak gelebildiği gibi çekirdeğin derlenmesinde sisteme yerleştirilerek gömülü olarak da gelebilmektedir. Burada yapmamız gereken dağıtımınıza bağlı olarak değişebildiği gibi genelde şudur. Linux’ta sisteme yüklenen bütün modüller “/etc/” dosyasında tanımlıdır. Bu dosyadan bizim sürücümüzü engelleyen sürücüyü bulup, “/etc/insmod/blacklist.conf” dosyasına “blacklist modüladi” şeklinde yazıp, sürücüyü kara listeye almak ve modülün yüklenmesini engellemektir.
Eğer sürücü çekirdeğe gömülü olarak geliyorsa yapmanız gereken bu sürücüyü çekirdekten çıkarıp tekrar derlemektir. Bu adımda yapacaklarınız bir yazı dizisinde daha bahsedilebilecek kadar bilgi gerektirdiğinden Allah size kolaylık versin diyorum.

Sonuç
Yukarıda anlattığım nedenlerden dolayı kendi sürücümüzü bir türlü sisteme yükleyemedik. Yani 3 aydır kafa patlattığımız yazımız sonucunda çalışır hiçbir kod elde edemedik (Hellomodül dışında). Eğer konu ilginizi çekti ve ben illaki bu sürücüyü çalıştıracağım diyorsanız, dağıtımınızın belgelerine bakmanızı, bizim örnek aldığımız David Olivera’nın Logitech sürücüsünü incelemenizi öneririm.

Uzun ve yorucu bir dizi oldu. Gelecek ay görüşmek dileğiyle.

Kaynaklar
Linux Device Drivers, Robert Corbert, O’Reilly, 2005
Linux Kernel Development, Robert Love, Novell Press, 2005
www.kernel.org
David Olivera Logitech Sürücüsü

18 Mart 2011 Cuma

Linux Sürücü Yazma-2


Bu yazı daha önce saltokunur.org e-dergisinde yayınlanmıştır.

Herkese merhabalar. Geçen ay başladığımız Linux sürücüsü yazma serüvenimizin ikinci yazısıyla yine beraberiz (TV programı girişi gibi oldu :) Yazının birinci kısmında Linux çekirdeğine giriş yapmış ve sürücü yazarken işimize yarayacak çeşitli konulara (sistem çağrıları gibi) değinmiştik. Bu ay bu konulara kaldığımız yerden devam ediyoruz.

Kesmeler
İşletim sisteminin donanımdaki değişiklikleri ya da ondan gelen sinyalleri algılaması (örneğin klavyeden bir tuşa basılması) için iki genel yöntem bulunur. Bunlardan birincisi polling denilen CPU’nun sürekli donanımda bir değişiklik var mı diye onu kontrol etmesidir. Ama bu yöntem sürekli işlemciyi meşgul edeceği için terk edilmiştir. İkinci ve en çok kullanılan bir yöntem ise donanımın CPU’ya kesme göndermesidir.
Mesela bilgisayarınızda Half-Life oynuyorsunuz. İşlemci siz oyunu oynarken o sırada ekranda görülmesi gereken nesnelerinin durumlarını hesaplamakla meşguldür. Patlamalar, kurşunların hedefte zarara yok açması gibi... Birden klavyeden W-A-S-D tuşlarına basarak konumunuzu değiştirdiniz. Artık ekranda farklı cisimlerin gözükmesi gerekir. İşte bu noktada klavye CPU’ya yaptığı işi KESME'sini ve klavyeden basılan tuşlara göre oyuncunun yeni konumunu hesaplaması ve ekranda gösterilecek yeni nesnelerin durumlarını hesaplamasını söyler.
Kesmeler temelde önce kesme yönetici (interrupt controller)’ ne oradan da CPU’ya gönderilen elektrik sinyalleridir. İşlemci bu sinyalleri alır ve işlemek üzere işletim sistemine gönderir. İşletim sistemi tarafında bir Interrupt’a cevap verilmek üzere çalıştırılacak olan kodların bulunduğu fonksiyona Interrupt Handler denir.
İşletim sistemi de Interrupt Handler ‘leri çağırarak bu kesmelere cevap verir. İşletim sistemi tarafından her donanıma farklı bir kesme numarası verilir. Böylece gelen kesmenin hangi donanım tarafından üretildiği belirlenir. Kesme numarasıyla birlikte bunlara Interrupt Request (IRQ) denir.
Günümüz PC’leri iç mimarilerinde donanımlar arası haberleşme için PCI veri yolunu kullanır. PCI veri yolunda IRQ’lar dinamik olarak belirlenebilir. Bu da tak ve kullan cihazların sistemin yeniden başlatılmasına gerek kalmadan hemen kullanılmasını sağlar.



Çekirdek tarafında bir IRQ’ya cevap olarak çalışan fonksiyonlara Interrupt Handler(IH) denir. Biz de sürücümüzü yazarken, donanımdan gelen isteklere cevap vermek üzere bir IH yazacağız. IH'lar normal C fonksiyonlarıdır. Çekirdek bu fonksiyonları kesmelere cevap olarak çağırır. Bir IH donanımdan gelen isteğe göre istenilen işi yapmalı ve donanıma işin sonucuna göre bir cevap vermelidir.

Bir IH'yi Sisteme Kaydetmek
Bir IH’nin donanımdan gelen isteklere cevap vermesi için IRQ ile IH’nin birbirine bağlanması gerekir. Bu request_irq() fonksiyonu ile yapılır. Bu fonksiyondaki ikinci parametre olan IH, birinci parametre olan kesmeyi işleyecek şekilde sisteme kaydedilir. Bundan sonra irq numaralı kesme geldiğinde ikinci parametredeki fonksiyon çağrılacaktır. 

int request_irq(int irq, irqreturn_t (*handler) (int, void *, struct pt_regs *),
long flags, char *devname, void *dev_id)

Burada ilk parametre gelen kesmenin numarası, ikinci parametre bu kesmeyi işleyecek IH’yi işaret eden bir fonksiyona göstericisi, flag parametresi çeşitli ayarlar için kullanılan bayrak değişkeni, dördüncü parametre cihazın adı, beşinci parametre cihazı gösteren işaretçidir.

IH Yazmak
Bir IH fonksiyonu şu prototipe uyar:
static irqreturn_t int_handler(int irq, void *dev_id,
 struct pt_regs *regs)
Burada irq kesme numarası, dev_id ise donanımı gösteren bir işaretçidir. Bu fonksiyonun içinde donanımdan gelen kesmelere cevap olacak işlemlerin yapılması gerekir. Örneğin kullanıcı klavyeden ‘A’ tuşuna bastıysa sisteme ‘A’ tuşuna basıldı sinyalinin verilmesi ve buna cevap bir işlem yapılmalıdır.


Resim 6.1 de donanımdan gelen bir kesmenin nasıl işlendiği görülüyor.

Modül Yazmak
Yavaş yavaş sürücü yazımına geçmek üzereyiz. Ancak bahsetmemiz gereken bir kaç şey daha var. Daha önce de belirttiğimiz gibi biz sürücümüzü modül olarak yazacağız ve çekirdeğe sistem çalışırken dinamik olarak yükleyeceğiz. Şimdi bu konuya bakalım.
Modüller sistem çalışırken dinamik olarak çekirdeğe yüklenebilen çekirdek programcıklarıdır. Bu özelliklerine bakarak modülleri çekirdek yamaları olarak da nitelendirebiliriz. Basit bir modül tanımı aşağıda görülmektedir. Her modülde modül ilk yüklendiğinde çekirdek tarafından çağırılan bir init fonksiyonu ve modül sistemden kaldırıldığında çağırılan bir exit fonksiyonu tanımlanmış olmalıdır. En alttaki module_init ve module_exit makroları ise bu fonksiyonları çekirdeğe bildirir. MODULE_LICENSE satırı dikkatinizi çekmiştir. Bu makro ile de modülün hangi lisans ile lisanslandığı belirtilir. Lisansın niye özellikle belirtildiği merak etmiş olabilirsiniz. Linux GPL ile dağıtıldığı için onu kullanan bütün kodların (buna modüller de dâhil) GPL ile dağıtılması gereklidir. Bu modül derlenirken açık kaynaktan başka bir lisans kullanılmışsa kod derleme sırasında hata verecektir. Açık kaynakçılar lisanslamayı bu kadar ciddi takip ediyorlar.
#include  /* Needed by all modules */
#include  /* Needed for KERN_INFO */

MODULE_LICENSE("GPL");

int __init init_module(void)
{
 printk(KERN_INFO " Merhaba Kernel Programlama \n"); 
 return 0;
}

void __exit exit_module(void)
{
 printk(KERN_INFO " Güle güle Kernel Programlama \n");
}

module_init(init_module);
module_exit(exit_module); 

Bir sürücü yazılırken yapılması gereken init fonksiyonunun içinde sürücüyü sisteme kaydetmek ve gerekli ilk yükleme işlemlerini yapmak, exit fonksiyonunun içinde ise daha önceden sürücüye tahsis edilen sistem kaynaklarını sisteme geri vermektir.

Modülü Derlemek
Daha önce anlatıldığı gibi linux-source ve linux-headers paketlerini kurduysanız, basit bir makefile yazıp modül derleme işlemini kolayca halledebilirsiniz. İçinizden makefile da ne diye soruyorsanız, makefile Linux'ta C derleyicileri için çeşitli derleme parametrelerinin ve komutlarının toplu olarak bulunduğu bir dosyadır. Derleyici bu dosyadaki ayarlara göre kaynak kodun derlemesini yapar. Biz de böylece komut satırından onlarca satır komut girmek zorunda kalmayız.

Bu da hello modülümüzü derleyecek makefile dosyasının içeriği:
ifneq ($(KERNELRELEASE),) 
 obj-m := hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
Endif

Bu makefile’da shell’e bazı komutlar gönderilip (shell uname -r), Linux başlık dosyalarının nerede olduğu bulunuyor ve buna göre kaynak kodumuzu derleniyor. Bu dosyadaki modülle ilgili en önemli komut;
obj-m :=hello.o
Derleyici hello.c’yi derledikten sonra oluşan hello.o dosyasından hello.ko biçiminde bir modül oluşturacaktır.
Bu makefile ile modülümüzü derledikten sonra elimizde hello.ko modülü oluşur. insmod programı modülü çekirdeğe yüklemek için kullanılır.
insmod hello.ko
Bu komut çağırılır çağrılmaz, modülün init fonksiyonu çağrılır ve komut satırında printk ile yazdırdığımız mesaj gözükür. Bazı dağıtımlarda bu çıktılar komut satırı yerine sistem loglarına basılabilir. /var/log/syslog dosyasına bakabilirsiniz.



rmmod ise modülü sistemden kaldırmak için kullanılır.
rmmod hello.ko komutunu çalıştırdığınızda modül sistemden kaldırılır ve modülün exit fonksiyonu çağrılır.

Donanım Çeşitleri
Donanımlar bilgisayarla haberleşme yöntemlerine göre 3'e ayrılır.
char: char donanımlar giriş-çıkış portlarına elektrik sinyalleri halinde tekli sırada, stream (akış) şeklinde veri gönderen cihazlardır. Klavye, fare, yazıcı, projeksiyon cihazı bunlara örnek verilebilir. Örneğin klavyeden basılan tuşlar bir akış halinde sırayla bilgisayara gönderilir. Bu cihazlar bilgisayara interrupt verisi gönderir.
block: içindeki verilere tek bir akıştan sabit hızda değil de, donanımın farklı konumlarından aynı anda rastgele ve farklı hızlarda erişilen donanımlardır. En iyi örnek hard disk gibi depolama birimleridir. Bu cihazlar ise bilgisayarla haberleşmek için bulk verisi gönderir.
network: ağ iletişimi için kullanılan, aynı anda hem okuma hem yazma yapabilen ve işlemleri ağın trafiğine ve topolojiye göre belirli bir sürede yapmak zorunda olan donanımlardır. Kablosuz ağ kartları örnek verilebilir. Bu cihazlar bilgisayara tty verisi gönderir.
Bilgisayarla haberleşme biçimleri farklı olduğu için, bu 3 farklı cihaz türünün de sürücüsü yazılırken farklı yollar izlenir. Açıklamalardan da anlayabileceğiniz sürücüsünü yazacağımız fare char tipli bir donanımdır ve iletişim için bilgisayara interrupt gönderir. Bu yüzden biz sürücü yazmayı sadece char donanımlara göre anlatacağız ve sadece interrupt verisi işleyen bir sürücü yazacağız.

USB Cihazlar
USB sürücüsü yazmaya çalıştığımız için bu noktada, USB’nin hangi türe girdiğini merak etmiş olabilirsiniz. Cevap E Hepsi :)
Usb arayüzü genel amaçlı bir arayüz olduğu için yukarıda sayılan türdeki cihazların hepsi (fare, usb hard disk, kablosuz ağ kartı) bu porta takılabilir. Bu yüzden USB sürücüsü yazma diğer arayüzlere sürücü yazmaktan daha karmaşıktır. USB sürücülerin bir sorunu da şudur ki, bir bilgisayarda genelde birden fazla USB girişi vardır. Bu yüzden USB portuna takılan bir cihazın bilgisayarın I/O portları üzerindeki adresi sabit değildir.

PCI Sistem İletişim Yolu
Güncel PC mimarisi donanımlar arası haberleşme için PCI veri yolunu kullanır. I/O portları bilgisayarın içinde hep PCI veri yollarına bağlıdır. Linux’ta lspci komutu bütün PCI cihazlarının listesini verir. Aşağıdaki komut satırı çıktısından bütün I/O portlarının ve bunların bağlı olduğu microcontroller’ların PCI veri yoluna bağlı olduğu görülür.

hamza@hamza-laptop:~$ lspci
00:00.0 Host bridge: Intel Corporation Mobile 945GM/PM/GMS, 943/940GML and 945GT Express Memory Controller Hub (rev 03)
00:01.0 PCI bridge: Intel Corporation Mobile 945GM/PM/GMS, 943/940GML and 945GT Express PCI Express Root Port (rev 03) 
00:1b.0 Audio device: Intel Corporation 82801G (ICH7 Family) High Definition Audio Controller (rev 02)                 
00:1c.0 PCI bridge: Intel Corporation 82801G (ICH7 Family) PCI Express Port 1 (rev 02)
00:1c.1 PCI bridge: Intel Corporation 82801G (ICH7 Family) PCI Express Port 2 (rev 02)
00:1c.2 PCI bridge: Intel Corporation 82801G (ICH7 Family) PCI Express Port 3 (rev 02)
00:1d.0 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #3 (rev 02)
00:1d.3 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #4 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801G (ICH7 Family) USB2 EHCI Controller (rev 02)
00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev e2)
00:1f.0 ISA bridge: Intel Corporation 82801GBM (ICH7-M) LPC Interface Bridge (rev 02)
00:1f.2 IDE interface: Intel Corporation 82801GBM/GHM (ICH7 Family) SATA IDE Controller (rev 02)
00:1f.3 SMBus: Intel Corporation 82801G (ICH7 Family) SMBus Controller (rev 02)
01:00.0 VGA compatible controller: nVidia Corporation G73 [GeForce Go 7600] (rev a1)
05:00.0 Network controller: Intel Corporation PRO/Wireless 3945ABG [Golan] Network Connection (rev 02)
07:06.0 CardBus bridge: Texas Instruments PCIxx12 Cardbus Controller
07:06.1 FireWire (IEEE 1394): Texas Instruments PCIxx12 OHCI Compliant IEEE 1394 Host Controller
07:06.2 Mass storage controller: Texas Instruments 5-in-1 Multimedia Card Reader (SD/MMC/MS/MS PRO/xD)
07:06.3 SD Host controller: Texas Instruments PCIxx12 SDA Standard Compliant SD Host Controller
07:08.0 Ethernet controller: Intel Corporation PRO/100 VE Network Connection (rev 02)


Sürücüler Donanımlarla Nasıl Eşleştirilir?
Bilmiyorum daha önce hiç aklınıza geldi mi ama (benim bu konuyu araştırmadan önce hiç aklıma gelmemişti) sürücülerin donanımlarla nasıl eşleştirildiğini hiç merak ettiniz mi? Soruyu daha açık bir şekilde sorarsam: Sistemimizde kullandığımız bütün cihazlar için sürücüler yüklenmiş durumda. Cihazımızı PC’mize bağlayınca hiç sorunsuz şekilde o cihaza ait sürücü çekirdek tarafından otomatik olarak yükleniyor ve cihazın isteklerine cevap vermek üzere çalıştırılıyor. Peki, çekirdek o kadar sürücü arasından hangisinin hangi cihaza (örneğin fare) ait olduğunu nereden anlıyor?
Bunun için bir PCI cihazın içindeki kontrol registerlarına bakmamız gerekiyor.

PCI Cihazların Kontrol Registerları



Yukarıdaki fotoğrafta bir PCI cihazın ayar registerları görülüyor. Bu registerlarda cihazla ilgili çeşitli özellikler (Üretici numarası, cihaz numarası, cihazın sınıfı, adres hatları ile ilgili bilgiler, IRQ numarası…) saklanıyor.
Buradaki registerlardan Vendor ID, PCI cihazlarının standardizasyonunu yapan kuruluş tarafından cihazın üreticisine verilmiş bir üretici numarasıdır. Bu numaranın verilmesindeki mantığın aynısı ağ kartlarına MAC numarası verilmesinde de uygulanır.
Device ID ise, o cihaza üreticisi tarafından verilmiş cihaz numarasıdır. Vendor ID ile birleşince dünyadaki bütün PCI cihazların benzersiz bir ürün numarası olmuş olur. Cihazlara sürücü yazılırken de bu numaralar sürücülerin içine koyulur. Böylece çekirdek sürücüde belirtilen numaralı cihaz sisteme bağlandığında, bağlanan cihazla ilişkilendireceği sürücüyü bu numaralar bakarak belirler.
Cihaz sürücüleri sadece belli bir cihazı çalıştıracak şekilde özel olarak yazıldığı gibi, belli bir tür cihazı çalıştıracak şekilde, genel sürücüler de yazılabilir. Buna USB Fare veya Klavye sürücüleri örnek verilebilir. Bilgisayar dünyasında bu tür genel cihazların yapıları standarttır. Böylece, örneğin bir USB Fare bağlandığında bu genel sürücü yüklenerek, cihaza özel bir sürücüye gerek kalman çalıştırılabilir (Zaten sürücüsünü yazacağımız fare bizim yazacağımız sürücü olmadan da çalışıyor. Ancak USB standardı dışındaki ekstra tuşları çalışmıyor. Biz bu yüzden bu cihaza özel sürücü yazacağız). Peki çekirdek bağlanan cihazın bir fare olduğunu ve ona özel sürücü değil de genel fare sürücüsünü yüklemesi gerektiğini nerden anlıyor? Bunu da yine yukarıdaki registerlara bakarak anlıyor. Şekilde Class Code registerı cihazın hangi tür bir cihaz olduğunu belirtiyor.

USB Portu



USB portunda kullanıcıdan gelen istekleri donanıma ulaştırırken, isteğin geçtiği katmanlar şekilde görülüyor. Buna göre, gelen istek USB cihazı hangi tür bir cihaz ise (char, network, block) o türe göre farklı işlemlerden geçip önce sürücüye geçiyor, sürücüden isteklerin yorumlandığı USB Core’a, oradan da ilgili cihaza donanımsal olarak bağlı olan USB Host Controller (ki isteğin hangi adresteki cihaza gideceğini controller biliyor) üzerinden donanıma erişiliyor.
Buraya kadar anlattığım her şey genel bilgisayar mimarisi için geçerlidir. USB portu söz konusu olunca anlatılan birçok şey farklı isimlendirilme ya da bakış açılarına tabii tutuluyor. Örneğin;
USB portundan gelen kesmelere özel olarak URB (USB Request Block) deniyor. Biz sürücümüzde bu URB’leri alıp içindeki veriye göre sistemimizde farklı tepkiler oluşmasını sağlayacağız.
Tabii IRQ’dan URB ‘ye olan değişim sadece isimde olmuyor. URB’lere cevap verecek IH’ler ve bunların sisteme kaydı işlemi normalden farklı hale geliyor. Sürücüyü yazarken ayrıca inceleyeceğiz ama şimdilik şunu söyleyebilirim ki, bu işlem usb_fill_int_urb() isminde daha özel bir fonksiyonla yapılıyor. Burada fonksiyon adında geçen int bu fonksiyonun interrupt yani kesme ile çalışan bir cihaza ait URB’lere cevap vereceğini belirtiyor.
PCI cihazlarınkine benzer şekilde, ancak USB’lere özel daha ayrıntılı bilgiler listeleyen bir komutumuz var: lsusb.
lsusb komutu bilgisayara bağlı bütün USB cihazlarını tüm detayına kadar listeler.
hamza@hamza-pardus ~ $ lsusb
Bus 001 Device 004: ID 058f:6387 Alcor Micro Corp. Transcend JetFlash Flash Drive
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 002: ID 0930:0508 Toshiba Corp. Integrated Bluetooth HCI
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 002: ID 09da:021f A4 Tech Co., Ltd
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bu çıktıda : ile ayrılmış hex numaraların birincisi cihazın Vendor ID’si, ikincisi ise Device ID’sidir. İşte biz bu numaraları sürücünün içinde belirteceğiz. Yani çekirdeğe “bu numaralı cihazlar sisteme bağlandığında bu sürücüyü yükle diyeceğiz.” Buna göre sürücüsü yazmaya çalıştığımız cihazın Vendor ID: 09da
 Device ID’si: 021f
Lsusb komutu çeşitli parametrelerle çalıştırıldığında cihazla ilgili tüm bilgileri listeler. Cihaz adı, üreticisi, numarası, iletişim şekli, türü, gücü, tipi, tamponu…

Usb Interface, Usb Endpoint
Bilgisayarın USB cihazların takıldığı USB portlarına özel bir adlandırmayla USB Interface denir. Bu USB Interface’lerin mantıksal karşılılıkları USB Endpoint’lerdir. USB Endpoint’ler, karşılık geldikleri USB Interface’ler hakkında bazı bilgileri bize sağlar. Bu bilgilerden bizim işimize yarayacak olan, cihazın Vendor ve Product ID’si, cihazın tipi (char, block, network), tamponunun boyutu, türü bilgileridir.

USB Potu Bit Haritası
USB Portu 64 bitlik bir porttur. USB’den haberleşen cihazlar 64 bitlik bir veri yolu kullanır. Yani her USB isteği, sinyali, URB’si sisteme 64 bitlik veri gönderir. Aşağıdaki şekilde bir USB Fare için bit haritası görülüyor. Bu haritaya göre en anlamlı 8 bit temel tuşlar için, sonraki byte’lar ise sırayla X, Y eksenlerinde ve tekerin hareketi için kullanılır.
Sürücü yazarken bizim yapacağımız URB deki bu 64 biti teker teker alıp hangi tuşa karşılık geliyorsa Linux çekirdeğine kayıt ettirmek olacak. Böylece fareden bir tuşa basıldığında ve bu tuşun bit sinyali USB Controller’a geldiğinde, Linux Çekirdeği hangi tuşa basıldığını bilebilecektir.



Sayısal örnek vermek gerekirse;
10000000-00000000-00000000-0000000-00000000-00000000-0000000-00000000 : Sol Tuş
01000000-00000000-00000000-0000000-00000000-00000000-0000000-00000000 : Sağ Tuş
00100000-00000000-00000000-0000000-00000000-00000000-0000000-00000000 : Orta Tuş 

Yazarken kendimi kaptırmışım. Çok uzun bir yazı olmuş. Bu aylık veda vakti geldi. Sürücüyü yazmak için öğrenmemiz gereken bilgiler bu kadardı. Bir sonraki yazıda artık sürücümüzü yazmaya başlayacağız.
Sağlıcakla Kalın.

Kaynaklar
Linux Device Drivers, Robert Corbert, O’Reilly, 2005
Linux Kernel Development, Robert Love, Novell Press, 2005

Linux Sürücü Yazma-1


Bu yazı daha önce saltokunur.org e-dergisinde yayınlanmıştır. 

Herkese merhabalar. Bu ay Linux'ta donanım sürücülerini inceleyeceğiz ve bir sürücü yazmaya çalışacağız. Konu detaylı ve uzun olduğundan makaleyi bir yazı dizisi şeklinde yayınlamayı düşünüyorum. Yolumuz uzun olduğundan hemen başlayalım. Ne demişler: "Erken kalkan yol alır."
Elimde çok sevdiğim, kullanışlı, güzel bir farem var (A4Tech Power Saver R7). Farenin sevdiğim özelliklerinden birisi de üzerinde fazladan tuşlarının olması ve Windows sürücü yazılımıyla bu tuşlara çeşitli kısayollar atanabilmesi. Bu kısayollar sayesinde fare bilgisayar deneyiminizi çok eğlenceli hale getiriyor. Ancak ne yazık ki bu farenin bir Linux sürücüsü bulunmuyor. Bu yazı dizisinde bahsettiğim fazlalık tuşlara Linux altında işlevlik kazandırmak için sürücü yazmaya çalışacağız.

 
Sürücü yazmaya girişmeden önce bazı önemli Linux Kernel (Çekirdek) özelliklerinden ve terimlerinde bahsedeceğiz. Sonra bunları bir USB Fare sürücüsü yazmada kullanacağız.
Linux'ta sürücüler genelde iki ayrı yöntem izlenerek yazılıyor. Birincisi Linux çekirdeğine inip çekirdek seviyesinde kodlar yazıp, bu kodları çekirdeğe gömmek. İkincisi ise çeşitli 3. parti API'ler kullanarak sürücü yazmak. Aslında bu 3. parti API'ler de yine çekirdek programlamayla yazılmış biraz daha üst seviye C fonksiyonları. Standart C'yi kullanmaya izin verdiği için kodlanması ve baş edilmesi daha kolay. Şimdi aklınıza "Yoksa Kernel kodları Standart C'yi kullanmıyor mu?" diye bir soru gelebilir. O zaman Linux Kernel'a Giriş - 101 'e hoş geldiniz.

Linux Kernel'a Giriş - 101
Kernel bir işletim sisteminin çekirdeğidir (Gerçekten çok açıklayıcı oldu :) Sistemde çalışan programların ve proseslerin önceliğini, çalışma sırasını, bellek erişimini ve belleğin prosesler arasında nasıl paylaşılacağını, sisteme gelen kesmeleri ve bu kesmelere göre işlemcinin nasıl davranacağını, dosya sistemine erişimi ve dosyaların burada nasıl tutulacağını, bilgisayarın donanımla nasıl haberleşeceğini belirlediği giriş-çıkış portlarını yönetir -ki biz bu konuya değineceğiz.
Linux çekirdeği ilk olarak 1991 tarihinde Finlandiyalı bir üniversite öğrencisi olan Linus Torvalds tarafından, o zamanın önemli işletim sistemlerinde Minix'in eksikliklerini tamamlamak için yayınlanmıştır. İlk olarak Intel 80386 mikroişlemcisi için yazılmıştır. Bugün içlerinde AMD, ARM, Compaq Alfha, CRIS, DECVAX, H8/300, Hitachi SuperH, HP/PA-RISC, IBM S/390, Intel IA-64, MISP, Motorola 6800 Serisi, PowerPC, Sun SPARC 'ın da bulunduğu 20 ye yakın mimariyi desteklemektedir. İlk yayınladığında yaklaşık olarak 10000 satırdır ve bunun %80 'i C ile %20 si Assembly ile yazılmıştır. Bu yazı yazıldığında Linux'un 2.6.33 çekirdeği yayınlanmıştı. 2.6.30 versiyonundan alınan istatistiklere göre, Linux çekirdeği 11.5 M satır ve tar.gz sıkıştırma ile yaklaşık 62 MB tutmakta. Bir ilginç istatistik daha: Her gün 5000 geliştirici Linux çekirdeğine yaklaşık 13 K satır eklemektedir.
Linux çekirdeği işletim sistemi seviyesinde çok önemli işler gerçekleştirdiği için geliştirilmesinde kullanılan yöntemler, performansı en üst düzeye çıkarmak amaçlıdır. Bu amaç için geliştiriciler bazı önemli kısıtlamalar doğrultusunda geliştirmeler yapmaktadır.
İşletim sistemlerinde prosesler işlemci düzeyi olarak iki ayrı düzeyde çalıştırılır: Kernel ve User. User düzeydeki prosesler sistemi etkilemeyen, kullanıcının çalıştırdığı programlar gibi çekirdeği kullanan proseslerdir. Kernel prosesler ise sistemi yöneten proseslerdir. Giriş-çıkış portlarına erişim, kullanılan veya boş olan belleğin hesaplanması ve burada dinamik yer tahsisi gibi işlemler kernel modda çalışır. Çekirdek thread’leri, dinamik kütüphane eklenmesini (sistem çalışırken modüller halinde çekirdeğe yazılım parçaları yüklenmesini destekler. Bu konuya sonradan detaylı bir şekilde değineceğiz. Çünkü sürücümüzü modül olarak yazıp çekirdeğe yükleyeceğiz).
Linux çekirdeği GNU C ile yazılmıştır. Bu özellik çekirdek programlamaya önemli kısıtlamalar getirir. Hiçbir standart C Kütüphanesi bir çekirdek koduna ekleyip, hiçbir C çağrısını çekirdek içinde kullanamazsınız. Kernel geliştiricileri çekirdeğin daha performanslı çalışması için, kullanacakları bütün C fonksiyonlarını baştan yazmışlardır. Örneğin printf() metodu kernel kodunda çalışmaz, onun yerine kernel programcıları çok benzeri olan printk() metodunu sıfırdan yazmışlardır. Bu fonksiyonun örnek kullanımı şöyle:

printk(KERN_INFO "Merhaba Kernel Programlama");

KERN_INFO 'dan sonra virgül koyulması gerektiğini düşünebilirsiniz. Ama bu gösterimde hiçbir yanlışlık yok. Bu fonksiyonun çıktısı normalde konsola yapılması gerekiyor. Ama bu özellik dağıtımdan dağıtıma değişiyor. Örneğin Pardus'da bu çıktı /var/log altındaki sistem loglarına yazılıyor (syslog, ken.log) Baştaki KERN_INFO bildirisi log'lama için kullanılır.



Ya da şöyle bir fonksiyon tanımı görebilirsiniz. ("__" ile başlayan isimlendirmeler kernel’a özeldir.)

static int __init usb_a4r7mouse_init(void) {}

Burada fonksiyonun dönüş değeri (int) ile adı arasında (usb_a4r7mouse_init) "__init" ifadesi fonksiyonun modülün sadece ilk yükleme "init" sırasında kullanılacağını belirtir. Böylece kernel bu fonksiyondaki değişkenler için ayırdığı belleği ilk yükleme işleminden sonra sisteme geri verebilir.
Her tanımlandığı yerde tekrar derlenen, böylece çalışma performansını artıran inline fonksiyonlar görebilirsiniz.
asm() çağrısı ile doğrudan assembly çağrıları görebilirsiniz.
Kernel’ın bellek koruması yoktur. User-space bir program yasaklı bir bellek bölgesine erişmek istediğinde ya null döndürülür ya da bir hata bildirilir. Böyle bir mekanizma kernel seviyesinde yoktur. Yanlış bir bellek bölgesinde değişiklik yaparsanız... Yani yapmamaya çalışın.
Kernel belleği sayfalanamaz (paging).
Kernel prosesler floating point işlem yapamaz.
Kernel-space bir proses’in stack'i sadece 4KB dır ve dinamik olarak değiştirilemez.
Linux Kernel'ı ücretsiz olarak www.kernel.org 'dan indirilebilir. tar.gz şeklinde indirdiğiniz sıkıştırılmış dosyanın içindeki dizin yapısı şöyledir.



  • arch - Mimariye bağımlı fonksiyonların bulunduğu kaynak kodlar.
  • crypto - Şifreleme API
  • Documantation
  • drivers
  • fs - File System
  • include - C başlık dosyaları
  • init - İlk yükleme kodları
  • ipc - inter proses com.
  • kernel - çekirdek sistem
  • lib
  • mm - hafıza yönetimi (memory management)
  • net - network
  • scripts
  • security
  • sound
  • usr - user space code

IDE Ayarları
Kernel geliştirmesini bir IDE üzerende yapacaksınız, buradaki klasörlerden include içindeki başlık dosyalarını ve arch altında kendi platformunuza uygun başlık dosyalarını (yine include altında) projenize eklemelisiniz. (Biz Netbeans kullandık, Netbans'te projeye sağ tıklayıp Code Assintance kısmından ya da Properties kısmından C Complier altında Include Directories kısmından bu klasörlerin yollarını gösterin.) Her ne kadar kaynaklarda "Kernel kodu geliştirmek için gerekli herşey buradadır" diye yazsa da, Linux dağıtımları temel kernel kodunu aşırı biçimde yamalanmış halde kullanmaktadır. Kullandığınız dağıtıma özel kodlar ve başlık (.h) dosyaları bulunabilir. Bunları internetten bulup kullandığınız derleyici ve IDE ye tanıtmanız gerekebilir. Örneğin Ubuntu için autoconf.h dosyası özeldir. Kernel koduyla birlikte gelmez. Bu dosyayı elde etmenin en kolay yolu Synaptic Paket Yöneticisinde linux-source ve linux-headers paketlerini kurmaktır. Pardus’ta ise PİSİ paket yöneticisinden adında kernel-header ve kernel-source geçen bütün paketleri kurmalısınız. Kurulan başlık dosyaları /usr/src/linux-headers-2.6.31-19-generic/include altına yerleştirilir. Bu dizini de projenin başlık dosyaları kısmına eklemeniz gerekebilir.



IDE ayarlanması ile ilgili son bir şey daha: Bütün kernel kodları bir #ifdef-#endif içerisinde "__KERNEL__" önişlemci bildirimini yapmak zorundadır. Netbeans'te bu başlık dosyalarını eklediğimiz kısımda "Preprosesor Definitions" kısmında "__KERNEL__" önişlemci bildiriminin yapılması gerekir. Aksi halde Netbeans bazı başlık dosyalarında bazı tanımlamaları bulamayacağını söyleyip, projede hatalar veriyor. Siz de bu ayarları kendi IDE’nize göre özelleştirmelisiniz.



Sistem Çağrıları
Linux çekirdeği user-space’te çalışan proseslere sistemle etkileşim, kaynaklara ve donanım'a erişim, için bir arayüz sunar. Bu sayede user -space programlar sistemin kritik noktalarını bozmadan kritik kaynaklara erişimi çekirdeğe bırakır ve isteklerini çekirdeğe yaparlar, çekirdek de bu isteklere cevap verir. Bellek tahsisi buna örnek verilebilir. Çünkü bir user-space program belleğin hangi gözünün boş hangisinin kullanımda olduğunu bilemez ama çekirdek bilir.
Bugün Linux'ta x86 platformu için 250 ye yakın sistem çağrısı vardır.
Programcılık açısından bakıldığında sistem çağrıları çekirdek tarafından user-space programlara kullandırılan C fonksiyonlarıdır. Hepsi sys_xxx yapısındadır. Dönüş değeri olarak başarı ya da hata kodu belirten long tipinde bir veri döner.



En çok kullanılan sistem çağrılarına bir örnek write() dır. Bir user-space program C dilinde printf() çağrısı ile bir dosyaya yazmak istediyse, önce bunun C kütüphanesinde karşılığı olan write(), sonra da sys_write() sistem çağrısı çağrılır ve bu fonksiyonun içinde hard diske yazma işlemi yapılır.



Sistem çağrıları mimariye bağımlıdır. x86 mimarisi için sistem çağrıları tablosu /arch/x86/kernel/syscall_table_32.S altındadır. Dosyanın uzantısının .S olduğuna dikkat edin. Bu uzantı assembly dosyalarının uzantısıdır.

Gelecek Ay Yazının Devamıyla Görüşmek Üzere.

Kaynaklar
Linux Device Drivers, Robert Corbert, O’Reilly, 2005
Linux Kernel Development, Robert Love, Novell Press, 2005

Katılımsız Kurulum


Bu yazı daha önce saltokunur.org e-derginin Ocak 2010 sayısında yayınlanmıştır. 

-- ...zaten %95'imiz Windows'a program kurarken bütün seçeneklere "Next" deyip programın bir an önce kurulmasını istiyoruz. Keşke programlar varsayılan ayarlarıyla kendileri otomatik kurulsa, yani şu "Next" lere de basmasak. Mesela kurulacak program Program Files'da kendi varsayılan yerine kurulsa, başlat menüsüne, hızlı başlata, masaüstüne kısayol koysa, sağ tuş menüye kaydolsa, uygun dosya tipleriyle kendini ilişkilendirse. Ama bunların hepsini otomatik yapsa, biz bir şekilde kurulumu tetiklesek sonra da "ta taaa" program hazır...
-- Okumaya devam.

Konuyu özetlemeye çalışan bu diyalog girişten sonra yazımıza başlayabiliriz. Bu ayki konumuz Katılımsız Kurulum (Unattended Setup). Giriş diyalogundan anlamış olacağız üzere katılımsız kurulumda kullanıcı bir şekilde kurulumu tetikler (çift tıklama, ya da bir script yardımıyla) sonrasında kullanıcı kurulumla ilgilenmeden program kurulmuş olur.

Nerelerde Kullanılır?
Kullanım yerleri hayal gücünüzle sınırlı olmakla birlikte katılımsız kurulum, internet kafe, bilgisayar laboratuarları gibi aynı programın defalarca kurulması gerektiği durumlarda işe yarayabilir.
Kurulduğunda çeşitli programlar ve sürücüleriyle birlikte kurulan, kullanıcı ismi, şifre, yerel ayarları sormayan Windows CD'leri oluşturmada kullanılır.

Nasıl Yapılır?
Katılımsız kurulumlu programlar genelde üç şekilde oluşturulur.
i.Bir script yardımıyla
ii.Bir program yardımıyla
iii.Elle

i.Bir script yardımıyla
Bu yöntemde katılımsız kurulum yapılacak programlar zaten önceden bu işleme hazır halde gelirler. Yapmamız gereken kurulum dosyasını programın katılımsız kurulum parametresiyle çalıştırmaktır. Bunun için önce programın katılımsız kurulum parametresini bulmamız gerekiyor.

Katılımsız kurulum parametresi bulmak
Windows'ta bir programın kurulum dosyasını çeşitli parametrelerle çalıştırarak farklı ayarlarla ve farklı biçimlerle kurulmasını sağlayabiliriz. Örneğin bu ayarların bazıları kurulacak yer, program herkes için mi yoksa sadece oturum açmış kullanıcı için mi kurulacağı olabilir. Zaten normal program kurarken karşımıza gelen arayüzler de (hani şu "Next" lere bastığımız) programın setup dosyasına parametre gönderen InstallShield, NSIS gibi programlardır. Bir programın hangi parametrelerle kurulabileceğini programı /? parametresiyle çalıştırarak öğrenebilirsiniz. Çıkan pencerede çeşitli parametreler ve ne işe yaradıkları yazar. Bunlardan Silent Install, No User Interaction, Unattended Setup vb. özellikler programın katılımsız kurulmasını sağlar. Setup dosyasını bu parametrelerle çalıştırıp programı katılımsız kurabilirsiniz.


Katılımsız kurulum parametresi bulmanın bir diğer yolu USSF (Universal Silent Switch Finder) kullanmak. Bu programla birçok programın katılımsız kurulum parametresini bulabilirsiniz.


Uzantısı (*.msi) olan kurulum dosyaları Microsoft'un kendi yükleyici dosyalarıdır. Genelde bu uzantıya sahip dosyalar /? ile çalıştırıldığında ekran görüntüsündeki çıktıyı verir.


En son internette araştırma da yapabilirsiniz.

1) 7zip
Katılımsız kurulum parametremizi bulduktan sonra, şimdi sadece çift tıklamayla kurulan bir kurulum dosyası yapalım.
Birinci ve en çok kullanılan yöntem 7zip installer oluşturmak. 7zip temelde bir sıkıştırma programı olsa da bazı ek dosyalar yardımıyla yükleyici dosyaları da oluşturmaya da yarar.
  • Önce içinde çalışacağınız bir klasör oluşturun, sonra bu klasörün içinde "Bin" adında bir klasör oluşturun.
  • Katılımsız kurulumunu oluşturacağınız programı bütün gerekli dosyalarıyla birlikte bin içine kopyalayın.
  • İnternetten 7za.exe,7zsd.sfx,upx.exe dosyalarını indirin ve içinde çalıştığınız klasöre kopyalayın.
  • Yine bu klasörde "Config.txt" dosyasını oluşturun. İçine şunları yazın:

;!@Install@!UTF-8!
GUIMode="2"
RunProgram="tvc.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-"
;!@InstallEnd@!


Burada,
RunProgram="tvc.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-"
satırında tırnaklar arasına bin klasöründeki kulum dosyasının tam adını katılımsız kurulum parametresi ile birlikte yazın.

  • Aynı klasöre Create.cmd dosyası oluşturun , içine şunları yazın:
upx --ultra-brute 7zsd.sfx
cd Bin
..\7za a -mx=9 "..\Program.7z" *
cd ..
copy /b 7zsd.sfx + Config.txt + Program.7z tvc.exe
del Program.7z

  • Create.bat çift tıklayıp çalıştırın.
  • İşlem tamamlandıktan aynı klasörde Program.exe adıyla katılımsız kurulum dosyanız hazır.



2) AutoIt Script
AutoIt scriptleriyle çalışmakta olan processlere çeşitli klavye, fare sinyalleri gönderebilirsiniz. Örneğin bir autoit scriptiyle bir kurulum dosyasını çalıştırıp, sonra ona bu script yardımıyla butonlara (kurulum dosyasındaki "Next"), checkbox'lara tıklatabilir, klavye girdisi verebilirsiniz.
Script'i yazdıktan sonra AutoIt ile derleyip kuracağınız programla aynı klasöre koyup,scripti tetiklediğinizde katılımsız kurulumun gerçekleştiğini göreceksiniz.
Örneğin KMPlayer'ın katılımsız kurulum parametresi /S dir. KMP'nin kurulum dosyasını bu parametreyle çalıştırsanız bile ilk başta kurulum dilini soruyor, sonra katılımsız kurulumu gerçekleştiriyor. AutoIt ile kurulum dilini sorduğu ekranda "Next" e tıklatmamız yeterli. Aşağıdaki kodları .ac3 uzantılı bir dosyaya kaydedip AutoIt ile derleyip, kmpsetup.exe'nin yanında çalıştırın. Katılımsız kurulumun gerçekleştiğini göreceksiniz.

Run("kmpsetup.exe /S")
WinWait("Installer Language","Please select the language of the installer")
ControlClick("Installer Language","Please select the language of the installer","Button1")


ii.Bir program yardımıyla
1) WinRAR SFX Arşiv
WinRAR ile .exe uzantılı Kendi Açılır Arşivler (Self Extractor Archive) oluşturabilirsiniz. Bu dosyalar çift tıklandıklarında katılımsız kurulumda olduğu gibi kullanıcıya soru sormadan belirlenen konumlara dosyaları çıkarır. Ayarlamalar yapılırsa çıkarma başlamadan önce ve sonra çeşitli script ve programları çalıştıracak komutlar girebilirsiniz. "SFX Arşivi Oluştur" u seçip, "Gelişmiş" sekmesinde "SFX Ayarlarına" tıklamanız yeterli.

2)Çeşitli Programlar
Program Files'daki dosyaları bir setup dosyasında toplayan, WinRAR SFX Arşiv gibi ama daha gelişmiş özelliklere sahip kurulum dosyası oluşturan programları kullanabilirsiniz. Bu programlarla şu dosyaları Program Files'a kopyalara, şunlara kısayol oluştur, şu kayıtları kayıt defterine ekle, falanca .dll leri sisteme kaydet, kurulumu da katılımsız yap diyebilirsiniz.


iii.Elle
inf Dosyası Yazmak
Windows'ta kurulumların nasıl yapılacağını belirten .inf uzantılı ayar dosyaları vardır. Katılımsız yapacağınız programın kurulmuş (Program Files’a çıkartılmış) dosyalarını bir .CAB dosyasında sıkıştırıp, bir inf ayar dosyası ile bu dosyaları istediğiniz yere kopyalayabilir, istediğiniz programları çalıştırabilir, kayıt defterine kayıt girebilir, sisteme  dll kaydedebilir, masaüstü, başlat menüsüne kısayol atabilirsiniz. Kurulum yapmak için inf dosyasına sağ tıklayıp Yükle’yi tıklayın.
Ama bunların hepsini elle yamanız gerekir. Bu konu burada anlatılmayacak kadar karmaşık ve uzun. Yazmaya kalksam 3 sayılık yazı dizisi olur. Merak edenler internette araştırabilir.


Katılımsız Kurulum CD’si Oluşturmak
Katılımsız kurumlar en çok, katılımsız kurulumlu Windows CD'leri oluşturmada kullanılır. Bahsettimiz yöntemlerle oluşturulan dosyalar, katılımsız kurulum addon larına dönüştürülür ve nLite, RVMintegrator gibi programlarla CD'lere entegre edilir. Kurulumda lazım olan bilgiler (kullanıcı ismi, ürün şifresi, klavye düzeni...) bir dosyaya (winnt.sif) yazılır. Sistem yüklenirken, katılımsız kurulumlar bir script tarafından tetiklenir (WPI, RunOnce..).

Gelecek ay buluşmak dileğiyle...

Google Arama Püfleri

Bu yazı daha önce saltokunur.org e-dergisinde yayınlanmıştır.


İnterneteki içeriğin forumlar, bloglar gibi sistemlerle kullanıcı tarafından dinamik olarak oluşturulduğu web 2.0 mantığının yayılmasıyla internet bir bilgi deryasına dönüştü. Öyle ki artık internete bağlanabilen ve klavye başında yazı yazabilen herkes istediği içeriği zametsizce paylaşabiliyor. Paylaşım tarafı güzel de doğruluğuna ve kalitesine dikkat edilmeden paylaşılan bilgi interneti bir bilgi cennetinden çok bir çöplüğe dönüştürüyor. Öyle ki ödevinizi araştırırken sizinle hiçbir alakası olmayan birinin blog’undan geçen gün öğle yemeğinde ne yediğini öğrenebiliyorsunuz.

Bir konu hakkında bilgi edinmek istediğimizde hepimiz öncelikle internete başvuruyoruz. İnternet öyle bir derya ki ne başı - sonu belli, ne bir kullanma kılavuzu var ne de içindekiler listesi. Biz de aradığımız bilgiye en kolay şekilde ulaşabilmek için arama motorlarını, en çok da Google’ı kullanıyoruz.
Google’da arama yapan kullanıcılar sonuçlarda hep aynı kopyalanmış bilgilerin çıkmasından ve kaliteli içerik ile sadece siteye ziyaretçi çekmek için oluşturulmuş çöp içeriği ayırt edememekten şikayetçi. Bilmiyorum aranızda gerçekten samanlıkta iğne arayanınız oldu mu ama, sanal alemde yaptığımız tam anlamıyla da bu.
Bu yazıda google aralamalarında verimliliği artıracak, milyonlarca sonuç içerisinde kaybolmadan ihtayacınız olan içeriği bulmanızı sağlayacak olan bazı püf noktalarına değineceğiz.

Genel Taktikler
Google arama sonuçlarını yerelleştirerek size sunar. Türkiye için düşünürsek, bulunan sitenin dili Türkçe olmasa bile arattığınız anahtar kelimelerin sonuçları önce meta verinde "Tr" bilgisi olan siteler görüntülenir. Yani google.com.tr “TR” öncelikli arama yapar. Arama dilini İngilizce bile yapsanız, google size sonuçları bu özelliklere göre ama bu sefer ingilizce olarak verir. Bu yüzden yabancı bir ülkeye ait bir içerik arıyorsanız, Google’un o ülkeye ait yerel sitesine gidip o sitede arama yapmanız daha sağlıklı sonuçlar verir.
Tek tek kelime değil de birkaç kelimeden oluşan bir ifade arıyorsanız, ifadeyi tırnak işaretleri içine alın. Örneğin medeni kanun diye arama yaparsanız medeni ve kanun kelimelerini ayrı ayrı aranırken "medeni kanun" ifadesini ise birlikte aranır. Ayrıca "" işaretini aramalarda tam olarak eşlenmesini istediğniz ifadelerde de kullanabilirsiniz.
Arama motorlarına doğrudan soru yazabilirsiniz. Örneğin bilgisayarda karşılaştığınız bir sorunun çözümünü arıyorsanız “how to... – nasıl yapılır...” diye arama sizi doğrudan forumlardaki o sorunlarla ilgili iletilere götürür.
Düzenli ifadeleri (RegEx) kullanabilirsiniz. Aşağıdaki gibi bir ifade içinde ebook, ebooks, books, book tan en az birinin geçtiği belirtilen uzantılardan birine sahip aramaları getirir. Bunu ebook ararken kullanabilirsiniz.
(ebook | ebooks | books | book) (*.pdf | *.chm | *.lit | *.rar | *.zip) "parent directory" intitle:"index of /" kitap ismi
Aramaların daha sağlıklı olması için mantıksal işaretleri kullanabilirsiniz.:
  • ·         (+): Örneğin, Sakarya+üniversitesi ifadesi içerisinde hem sakarya hem de üniversitesi kelimelerinin bulunduğu sayfaları bulur.
  • ·         (-): Arama sonuçlarında olmamasını istediğiniz kelimelerin önüne – işareti koyabilirsiniz. Free kelimesi reklam amaçlı bütün siteler tarafından kullanıcı çekmek için kullnılır. Aramalarınıza  ”-free” ekleyerek reklam, spam amaçlı, illegal içerikli bir çok sitenin listelenmesini engelleyebilirsiniz.
  • ·         (|)-(OR): Veya. Anahtar kelimelerin arasına veya işareti koyabilirsiniz. Sonuçlarda bu kelimelerden herhangi birinin bulunduğu siteler listelenir. Aynı anlamdaki kelimeler ile yapılan aramalarda kullanılabilir. Örneğin;
ebook | ebooks | books | book

Anahtar Kelimeler
inurl: Adreslerinde arattığınız sözcükler bulunan sayfaları listeler. Çok etkilidir. Sayfanın adresinde aranan kelime varsa sonuç neredeyse garantidir. Örnek:  +inurl:wma|mp3|ogg site:rapidshare.com. Rapidshare.com ‘da adresinde wma veya mp3 veya ogg kelimeleri geçen sayfaları arar. Bildiniz müzik araması 
allinurl: Birden fazla kelime için inurl özelliği kullanacaksanız hepsine ayrı ayrı inurl: yazmak zorunda değilsiniz.
intitle: Aranılan kelimelerin sayfanın başlığında bulunduğu sayfaları listeler. Başlığa göre aradığı için verimli sonuç döndürür. Örnek: altyazı intitle:”Pulp Fiction”. Başlığında Pulp Fiction, içinde altyazı geçen sayfaları bulur.
allintitle:Birden fazla kelime için intitle özelliği kullanabilirsiniz.
intext: Aranılan kelimelerin sayfanın metin kısmında olduğu sayfaları döndürür. Örnek bilgisayar intext:saltokunur. Sayfanın metin kısmında saltokunur kelimesinin geçtiği sonuçları döndürür.
site: Anahtar kelimelerden önce site:siteadi yazarsanız yalnızca o sitede arama yapar. Örn: site:saltokunur.org e-dergi
cache: Bu kelimenin ardından bir site yazarsanız, sitenin google hafızasındaki görüntüsü verilir. Örnek: cache:www.siteadi.org
link: Link komutu bir web adresiyle birlikte girildiğinde, belirtilen adrese giden link içeren bütün sayfa ve belgeler görüntülenir. Örneğin: link:www.siteadi.org satırı siteadi.org sitesine link içeren sayfa ve belgeleri bulur.
info: Bu komutla Google, komut satırında adı geçen web sitesine dair kendi arşivinde tuttuğu kısa bilgileri görüntüler. Örnek: info:www.siteadi.org
filetype: Dosya türene göre de arama yapabilirsiniz. Örneğin: filetype:doc bilgisayar.  Araması adında bilgisayar kelimesi geçen DOC uzantılı dosyaları bulur.
define: Google bir sözlük gibi de kullanılabilir. Bunun için tanımlanmasını istediğiniz kelime ya da kelimelerin önüne define yazarak arattığınız kelimenin açıklamasını öğrenebilirsiniz. Örnek: define:php
book: Verilen kelime ile ilgili kitpları bulur. Örnek: book firefox (book operatöründen sonra “:” işareti kullanılmaz). Filetype ile birlikte kullanıldığında mükemmel sonuç verir.

İpuçları
  • ProgramAdi adi ile belirtilen programları bulur: "parent directory" ProgramAdi -xxx -html -htm -php -shtml -opendivx -md5 -md5sums
  • Sitedeki belirli türdeki dosyaları bulmak istiyorsanız *.pdf, *.zip *.jpg gibi yazmanız yeterli. Örn: www.ebook.com .pdf
  • Google’u hesap makinesi olarak kullanabilirsiniz. 32+2345*3-234= yazdığınızda sonucu size söylecektir.
  • Birim dönüştürme yapabilirsiniz. 100F=?C ile Fahrenheit Celcius’a çevrilir.
  • ?intitle:index.of? .*avi Konu : Satırı ile konu hakkında avi dosyası araması yapabilirsiniz.