乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      字符設(shè)備基礎(chǔ)

       wanwanstudy 2012-02-20
      bash> ls -l /dev
      total 0
      crw-------   1 root root     5,   1 Jul 16 10:02 console
      ...
      lrwxrwxrwx   1 root root          3 Oct 6 10:02  cdrom -> hdc
      ...
      brw-rw----   1 root disk     3,   0 Oct 6 2007   hda
      brw-rw----   1 root disk     3,   1 Oct 6 2007   hda1
      ...
      crw-------   1 root tty      4,   1 Oct 6 10:20  tty1
      crw-------   1 root tty      4,   2 Oct 6 10:02  tty2
      第一個(gè)字符:c:字符設(shè)備、l:symlink、b:塊設(shè)備
      第五個(gè)字符5,1:主設(shè)備號,次設(shè)備號;主設(shè)備號能夠?qū)ふ业津?qū)動,而次設(shè)備號則能夠定位設(shè)備。
      字符設(shè)備和塊設(shè)備的空間不一樣,因此,可以使用同一主設(shè)備號
      從編碼角度看需要:(1)、初始化并注冊設(shè)備。(2)、應(yīng)用通過/dev下節(jié)點(diǎn)的文件系統(tǒng)調(diào)用:open()、read()、ioctl()、llseek()、write()
      (3)中斷處理程序、底半部、時(shí)鐘處理、內(nèi)核輔助線程和其他支撐架構(gòu)。
      從數(shù)據(jù)流角度看,字符設(shè)備需要:(1)設(shè)備對應(yīng)結(jié)構(gòu)體;(2)struct cdev;(3)、struct file_operation;(4)struct file。
       
      Device Example:System CMOS
      BIOS使用CMOS來存儲諸如startup option,boot order,and the system date,您可以通過BIOS啟動菜單修改。例子CMOS驅(qū)動可以像普通文件一樣訪問2個(gè)PC CMOS塊,應(yīng)用程序可以操作/dev/cmos/0和/dev/cmos/1,并使用I/O系統(tǒng)調(diào)用來訪問兩個(gè)bank里面的數(shù)據(jù)。因?yàn)锽IOS給CMOS區(qū)域以位級粒度,驅(qū)動也能夠以位級訪問。所以read()可以讀取指定的位數(shù),并移動相應(yīng)位數(shù)指針。

      Table 5.1. Register Layout on the CMOS
      Register NameDescription
      CMOS_BANK0_INDEX_PORTSpecify the desired CMOS bank 0 offset in this register.
      CMOS_BANK0_DATA_PORTRead/write data from/to the address specified in CMOS_BANK0_INDEX_PORT.
      CMOS_BANK1_INDEX_PORTSpecify the desired CMOS bank 1 offset in this register.
      CMOS_BANK1_DATA_PORTRead/write data from/to the address specified in CMOS_BANK1_INDEX_PORT.
      Driver Initialization
       init()的責(zé)任:(1)請求分配設(shè)備主設(shè)備號;(2)為每個(gè)設(shè)備結(jié)構(gòu)分配內(nèi)存;(3)鏈接字符設(shè)備驅(qū)動cdev的入口點(diǎn)(open()、read()等);(4)聯(lián)系主設(shè)備號和驅(qū)動的cdev;(5)在/dev和/sys下創(chuàng)建節(jié)點(diǎn);(6)初始化硬件。以下是示例程序:
      Listing 5.1. CMOS Driver Initialization

      #include <linux/fs.h>
      
      /* Per-device (per-bank) structure */
      struct cmos_dev {
        unsigned short current_pointer; /* Current pointer within the
                                           bank */
        unsigned int size;              /* Size of the bank */
        int bank_number;                /* CMOS bank number */
        struct cdev cdev;               /* The cdev structure */
        char name[10];                  /* Name of I/O region */
        /* ... */                       /* Mutexes, spinlocks, wait
                                           queues, .. */
      } *cmos_devp;
      
      /* File operations structure. Defined in linux/fs.h */
      static struct file_operations cmos_fops = {
        .owner    =   THIS_MODULE,      /* Owner */
        .open     =   cmos_open,        /* Open method */
        .release  =   cmos_release,     /* Release method */
        .read     =   cmos_read,        /* Read method */
        .write    =   cmos_write,       /* Write method */
        .llseek   =   cmos_llseek,      /* Seek method */
        .ioctl    =   cmos_ioctl,       /* Ioctl method */
      };
      
      static dev_t cmos_dev_number;   /* Allotted device number */
      struct class *cmos_class;       /* Tie with the device model */
      
      #define NUM_CMOS_BANKS          2
      #define CMOS_BANK_SIZE          (0xFF*8)
      #define DEVICE_NAME             "cmos"
      #define CMOS_BANK0_INDEX_PORT   0x70
      #define CMOS_BANK0_DATA_PORT    0x71
      #define CMOS_BANK1_INDEX_PORT   0x72
      #define CMOS_BANK1_DATA_PORT    0x73
      
      unsigned char addrports[NUM_CMOS_BANKS] = {CMOS_BANK0_INDEX_PORT,
                                                 CMOS_BANK1_INDEX_PORT,};
      
      unsigned char dataports[NUM_CMOS_BANKS] = {CMOS_BANK0_DATA_PORT,
                                                 CMOS_BANK1_DATA_PORT,};
      
      /*
       * Driver Initialization
       */
      int __init
      cmos_init(void)
      {
        int i;
      
        /* Request dynamic allocation of a device major number */
        if (alloc_chrdev_region(&cmos_dev_number, 0,
                                NUM_CMOS_BANKS, DEVICE_NAME) < 0) {
          printk(KERN_DEBUG "Can't register device\n"); return -1;
        }
      
        /* Populate sysfs entries */
        cmos_class = class_create(THIS_MODULE, DEVICE_NAME);
      
        for (i=0; i<NUM_CMOS_BANKS; i++) {
          /* Allocate memory for the per-device structure */
          cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
          if (!cmos_devp) {
            printk("Bad Kmalloc\n"); return 1;
          }
      
          /* Request I/O region */
          sprintf(cmos_devp->name, "cmos%d", i);
          if (!(request_region(addrports[i], 2, cmos_devp->name)) {
            printk("cmos: I/O port 0x%x is not free.\n", addrports[i]);
            return –EIO;
          }
          /* Fill in the bank number to correlate this device
             with the corresponding CMOS bank */
          cmos_devp->bank_number = i;
      
          /* Connect the file operations with the cdev */
          cdev_init(&cmos_devp->cdev, &cmos_fops);
          cmos_devp->cdev.owner = THIS_MODULE;
      
          /* Connect the major/minor number to the cdev */
          if (cdev_add(&cmos_devp->cdev, (dev_number + i), 1)) {
            printk("Bad cdev\n");
            return 1;
          }
      
          /* Send uevents to udev, so it'll create /dev nodes */
          class_device_create(cmos_class, NULL, (dev_number + i),
                              NULL, "cmos%d", i);
        }
      
        printk("CMOS Driver Initialized.\n");
        return 0;
      }
      
      /* Driver Exit */
      void __exit
      cmos_cleanup(void)
      {
        int i;
      
        /* Remove the cdev */
        cdev_del(&cmos_devp->cdev);
      
        /* Release the major number */
        unregister_chrdev_region(MAJOR(dev_number), NUM_CMOS_BANKS);
      
        /* Release I/O region */
        for (i=0; i<NUM_CMOS_BANKS; i++) {
          class_device_destroy(cmos_class, MKDEV(MAJOR(dev_number), i));
          release_region(addrports[i], 2);
        }
        /* Destroy cmos_class */
        class_destroy(cmos_class);
        return();
      }
      
      module_init(cmos_init);
      module_exit(cmos_cleanup);

      cmos_init()使用alloc_chrdev_region()來動態(tài)請求未使用的主設(shè)備號,dev_number包含了得到的主設(shè)備號,第二個(gè)和第三個(gè)參數(shù)用于指定起始次設(shè)備號和支持的次設(shè)備數(shù)目,最后一個(gè)參數(shù)是設(shè)備名,可用于在/proc/devices中指定CMOS:
      bash> cat /proc/devices | grep cmos
      253 cmos
      在2.6以前,無法動態(tài)分配主設(shè)備號,只有通過register_chrdev()來注冊指定的主設(shè)備號。
      cdev_init()把文件操作cmos_fopscdev聯(lián)系起來,cdev_add()alloc_chrdev_region()分配的主/次設(shè)備號給cdev。
      class_create()為該設(shè)備產(chǎn)生一個(gè)sysfs入口,class_device_create()則導(dǎo)致產(chǎn)生兩個(gè)uevent:cmos0和cmos1,udevd會偵聽uevent并在查詢/etc/udev/rules.d里的規(guī)則庫后產(chǎn)生/dev/cmos/0和/dev/cmos/1對應(yīng)的設(shè)備節(jié)點(diǎn)。要在/etc/udev/rules.d/里面加入:
      KERNEL="cmos[0-1]*", NAME="cmos/%n"
      設(shè)備驅(qū)動需要操作一個(gè)I/O地址范圍,因此使用request_region()來請求該地址,該技術(shù)會使其他請求該I/O地址空間的請求者失敗,直到擁有者釋放空間release_region().request_region()通常由總線申請,如PCI、ISA。request_region()的最后一個(gè)參數(shù)是/proc/ioports使用的標(biāo)記,因此:
      bash>  grep cmos /proc/ioports
      0070-0071  :  cmos0
      0072-0073  :  cmos1
      Open and Release
      當(dāng)應(yīng)用程序打開節(jié)點(diǎn)時(shí),就會激發(fā)驅(qū)動程序的open()。您可以通過bash> cat /dev/cmos/0來激發(fā)cmos_open()的執(zhí)行,當(dāng)cat關(guān)閉/dev/cmos/0的文件描述符時(shí),會導(dǎo)致cmos_release()的執(zhí)行。
      Listing 5.2. Open and Release

      /*
       * Open CMOS bank
       */
      int
      cmos_open(struct inode *inode, struct file *file)
      {
        struct cmos_dev *cmos_devp;
      
        /* Get the per-device structure that contains this cdev */
        cmos_devp = container_of(inode->i_cdev, struct cmos_dev, cdev);
      
        /* Easy access to cmos_devp from rest of the entry points */
        file->private_data = cmos_devp;
      
        /* Initialize some fields */
        cmos_devp->size = CMOS_BANK_SIZE;
        cmos_devp->current_pointer = 0;
      
        return 0;
      }
      
      /*
       * Release CMOS bank
       */
      int
      cmos_release(struct inode *inode, struct file *file)
      {
        struct cmos_dev *cmos_devp = file->private_data;
      
        /* Reset file pointer */
        cmos_devp->current_pointer = 0;
      
        return 0;
      }

      Exchanging Data

      read()和write()是用戶空間和設(shè)備交換的基本函數(shù),其他的還有fsync(),aio_read(),aio_write()和mmap()

      COMS是一個(gè)簡單的memory設(shè)備,因此CMOS數(shù)據(jù)訪問程序不必是sleep-wait 設(shè)備IO完成,但其他的一些字符設(shè)備都要支持blocking和nonblocking操作。除非設(shè)備文件以nonblocking(O_NONBLOCK)方式打開,否則read()和write()允許calling進(jìn)程睡眠直到相應(yīng)操作完成;(2)CMOS驅(qū)動以完全同步方式而不是依賴于中斷。
      內(nèi)核空間和用戶空間的交互使用函數(shù)copy_to_user()和copy_from_user(),由于這兩個(gè)函數(shù)會陷入睡眠,所以調(diào)用時(shí)不能持有spinlock鎖。讀取或?qū)懭氩煌笮〉臄?shù)據(jù)使用一些架構(gòu)無關(guān)的函數(shù)in[b|w|l|sb|sl]()和out[b|w|l|sb|sl]().
      Listing 5.3. Read and Write

      /*
       * Read from a CMOS Bank at bit-level granularity
       */
      ssize_t
      cmos_read(struct file *file, char *buf,
                size_t count, loff_t *ppos)
      {
        struct cmos_dev *cmos_devp = file->private_data;
        char data[CMOS_BANK_SIZE];
        unsigned char mask;
        int xferred = 0, i = 0, l, zero_out;
        int start_byte = cmos_devp->current_pointer/8;
        int start_bit  = cmos_devp->current_pointer%8;
      
        if (cmos_devp->current_pointer >= cmos_devp->size) {
          return 0; /*EOF*/
        }
      
        /* Adjust count if it edges past the end of the CMOS bank */
        if (cmos_devp->current_pointer + count > cmos_devp->size) {
          count = cmos_devp->size - cmos_devp->current_pointer;
        }
      
        /* Get the specified number of bits from the CMOS */
        while (xferred < count) {
          data[i] = port_data_in(start_byte, cmos_devp->bank_number)
                    >> start_bit;
          xferred += (8 - start_bit);
          if ((start_bit) && (count + start_bit > 8)) {
            data[i] |= (port_data_in (start_byte + 1,
                        cmos_devp->bank_number) << (8 - start_bit));
            xferred += start_bit;
          }
          start_byte++;
          i++;
        }
        if (xferred > count) {
          /* Zero out (xferred-count) bits from the MSB
             of the last data byte */
          zero_out = xferred - count;
          mask = 1 << (8 - zero_out);
          for (l=0; l < zero_out; l++) {
            data[i-1] &= ~mask; mask <<= 1;
          }
          xferred = count;
        }
      
        if (!xferred) return -EIO;
      
        /* Copy the read bits to the user buffer */
        if (copy_to_user(buf, (void *)data, ((xferred/8)+1)) != 0) {
          return -EIO;
        }
      
        /* Increment the file pointer by the number of xferred bits */
        cmos_devp->current_pointer += xferred;
        return xferred; /* Number of bits read */
      }
      
      /*
       * Write to a CMOS bank at bit-level granularity. 'count' holds the
       * number of bits to be written.
       */
      ssize_t
      cmos_write(struct file *file, const char *buf,
                 size_t count, loff_t *ppos)
      {
        struct cmos_dev *cmos_devp = file->private_data;
        int xferred = 0, i = 0, l, end_l, start_l;
        char *kbuf, tmp_kbuf;
        unsigned char tmp_data = 0, mask;
        int start_byte = cmos_devp->current_pointer/8;
        int start_bit  = cmos_devp->current_pointer%8;
      
        if (cmos_devp->current_pointer >= cmos_devp->size) {
          return 0; /* EOF */
        }
        /* Adjust count if it edges past the end of the CMOS bank */
        if (cmos_devp->current_pointer + count > cmos_devp->size) {
          count = cmos_devp->size - cmos_devp->current_pointer;
        }
      
        kbuf = kmalloc((count/8)+1,GFP_KERNEL);
        if (kbuf==NULL)
          return -ENOMEM;
      
        /* Get the bits from the user buffer */
        if (copy_from_user(kbuf,buf,(count/8)+1)) {
          kfree(kbuf);
          return -EFAULT;
        }
      
        /* Write the specified number of bits to the CMOS bank */
        while (xferred < count) {
          tmp_data = port_data_in(start_byte, cmos_devp->bank_number);
          mask = 1 << start_bit;
          end_l = 8;
          if ((count-xferred) < (8 - start_bit)) {
            end_l = (count - xferred) + start_bit;
          }
      
          for (l = start_bit; l < end_l; l++) {
            tmp_data &= ~mask; mask <<= 1;
          }
          tmp_kbuf = kbuf[i];
          mask = 1 << end_l;
          for (l = end_l; l < 8; l++) {
            tmp_kbuf &= ~mask;
            mask <<= 1;
          }
      
          port_data_out(start_byte,
                        tmp_data |(tmp_kbuf << start_bit),
                        cmos_devp->bank_number);
          xferred += (end_l - start_bit);
      
          if ((xferred < count) && (start_bit) &&
              (count + start_bit > 8)) {
            tmp_data = port_data_in(start_byte+1,
                                    cmos_devp->bank_number);
            start_l = ((start_bit + count) % 8);
            mask = 1 << start_l;
            for (l=0; l < start_l; l++) {
              mask >>= 1;
              tmp_data &= ~mask;
            }
            port_data_out((start_byte+1),
                          tmp_data |(kbuf[i] >> (8 - start_bit)),
                          cmos_devp->bank_number);
            xferred += start_l;
          }
      
          start_byte++;
          i++;
        }
      
        if (!xferred) return -EIO;
      
        /* Push the offset pointer forward */
        cmos_devp->current_pointer += xferred;
        return xferred; /* Return the number of written bits */
      }
      
      /*
       * Read data from specified CMOS bank
       */
      unsigned char
      port_data_in(unsigned char offset, int bank)
      {
        unsigned char data;
      
        if (unlikely(bank >= NUM_CMOS_BANKS)) {
          printk("Unknown CMOS Bank\n");
          return 0;
        } else {
          outb(offset, addrports[bank]); /* Read a byte */
          data = inb(dataports[bank]);
        }
        return data;
      
      }
      /*
       * Write data to specified CMOS bank
       */
      void
      port_data_out(unsigned char offset, unsigned char data,
                      int bank)
      {
        if (unlikely(bank >= NUM_CMOS_BANKS)) {
          printk("Unknown CMOS Bank\n");
          return;
        } else {
          outb(offset, addrports[bank]); /* Output a byte */
          outb(data, dataports[bank]);
        }
        return;
      }

      當(dāng)write()成功返回時(shí),說明應(yīng)用程序已經(jīng)將數(shù)據(jù)成功傳給了驅(qū)動,但并不保證數(shù)據(jù)寫到了設(shè)備里面,如果需要這個(gè)保證,那么需要調(diào)用fsync()。當(dāng)應(yīng)用程序的數(shù)據(jù)來源自不同的分散的buffers時(shí),需要使用readv和writev(),從2.6.19以后這兩個(gè)函數(shù)被folded into Linux AIO層里面了,the vector driver相關(guān)的原型包括:

      ssize_t aio_read(struct kiocb *iocb, const struct iovec *vector,
                       unsigned long count, loff_t offset);
      ssize_t aio_write(struct kiocb *iocb, const struct iovec *vector,
                        unsigned long count, loff_t offset);
      第一個(gè)參數(shù)描述了AIO操作,第二個(gè)參數(shù)則是iovecs的數(shù)組,記錄了buffers的地址和長度,可查看iovecs的定義和/drivers/net/tun.c下對vectors drivers的實(shí)現(xiàn)。另外一個(gè)數(shù)據(jù)訪問方法是mmap(),它將設(shè)備內(nèi)存和用戶虛擬內(nèi)存聯(lián)系起來。應(yīng)用可以調(diào)用同名系統(tǒng)調(diào)用mmap(),并在返回的內(nèi)存區(qū)域上直接操作設(shè)備駐留內(nèi)存??刹榭?drivers/char/mem.c查看實(shí)例。
      Seek
      內(nèi)核使用內(nèi)部指針來跟蹤文件內(nèi)訪問位置,應(yīng)用程序調(diào)用lseek(),進(jìn)而調(diào)用相應(yīng)的驅(qū)動llseek()。這里的CMOS驅(qū)動是按bit移動的。先看一下lseek()使用的幾個(gè)參數(shù):(1)SEEK_SET,從文件頭計(jì)算;(2)SEEK_CUR,從當(dāng)前位置計(jì)算;(3)SEEK_END,從文件尾部計(jì)算。
      Listing 5.4. Seek

      /*
       * Seek to a bit offset within a CMOS bank
       */
      static loff_t
      cmos_llseek(struct file *file, loff_t offset,
                  int orig)
      {
        struct cmos_dev *cmos_devp = file->private_data;
      
        switch (orig) {
          case 0: /* SEEK_SET */
            if (offset >= cmos_devp->size) {
              return -EINVAL;
            }
            cmos_devp->current_pointer = offset; /* Bit Offset */
            break;
      
          case 1: /* SEEK_CURR */
            if ((cmos_devp->current_pointer + offset) >=
                 cmos_devp->size) {
              return -EINVAL;
            }
            cmos_devp->current_pointer = offset; /* Bit Offset */
            break;
      
          case 2: /* SEEK_END - Not supported */
            return -EINVAL;
      
          default:
            return -EINVAL;
        }
      
        return(cmos_devp->current_pointer);
      }

       Control
      ioctl用于接收用戶空間命令并請求特殊操作,CMOS memory由cyclic redundancy check(CRC)算法保護(hù)。為檢測數(shù)據(jù)是否崩潰,CMOS驅(qū)動支持兩個(gè)ioctl命令:(1)Adjust checksum,用于當(dāng)CMOS內(nèi)容改變后重新計(jì)算CRC。計(jì)算出的checksum放在實(shí)現(xiàn)定義好的CMOS bank1的某處。(2)Verify checksum,用于檢查CMOS的內(nèi)容是否healthy,通過比較當(dāng)前內(nèi)容的CRC和預(yù)存的CRC來判斷。應(yīng)用程序想進(jìn)行校驗(yàn)操作時(shí),就將這些命令通過ioctl()系統(tǒng)調(diào)用發(fā)給驅(qū)動。
      Listing 5.5. I/O Control

      #define CMOS_ADJUST_CHECKSUM 1
      #define CMOS_VERIFY_CHECKSUM 2
      
      #define CMOS_BANK1_CRC_OFFSET 0x1E
      
      /*
       * Ioctls to adjust and verify CRC16s.
       */
      static int
      cmos_ioctl(struct inode *inode, struct file *file,
                 unsigned int cmd, unsigned long arg)
      {
        unsigned short crc = 0;
        unsigned char buf;
      
        switch (cmd) {
          case CMOS_ADJUST_CHECKSUM:
            /* Calculate the CRC of bank0 using a seed of 0 */
            crc = adjust_cmos_crc(0, 0);
      
            /* Seed bank1 with CRC of bank0 */
            crc = adjust_cmos_crc(1, crc);
      
            /* Store calculated CRC */
            port_data_out(CMOS_BANK1_CRC_OFFSET,
                          (unsigned char)(crc & 0xFF), 1);
            port_data_out((CMOS_BANK1_CRC_OFFSET + 1),
                          (unsigned char) (crc >> 8), 1);
            break;
      
          case CMOS_VERIFY_CHECKSUM:
           /* Calculate the CRC of bank0 using a seed of 0 */
            crc = adjust_cmos_crc(0, 0);
      
           /* Seed bank1 with CRC of bank0 */
           crc = adjust_cmos_crc(1, crc);
      
           /* Compare the calculated CRC with the stored CRC */
           buf = port_data_in(CMOS_BANK1_CRC_OFFSET, 1);
           if (buf != (unsigned char) (crc & 0xFF)) return -EINVAL;
      
           buf = port_data_in((CMOS_BANK1_CRC_OFFSET+1), 1);
           if (buf != (unsigned char)(crc >> 8)) return -EINVAL;
           break;
           default:
             return -EIO;
        }
      
        return 0;
      }

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多