ºìÁªLinuxÃÅ»§
Linux°ïÖú

LinuxÉ豸Çý¶¯±à³ÌÖ®¸´ÔÓÉ豸Çý¶¯

·¢²¼Ê±¼ä:2006-11-03 01:12:08À´Ô´:ºìÁª×÷Õß:Community
¡¡¡¡ÕâÀïËù˵µÄ¸´ÔÓÉ豸Çý¶¯Éæ¼°µ½PCI¡¢USB¡¢ÍøÂçÉ豸¡¢¿éÉ豸µÈ£¨ÑϸñÒâÒå¶øÑÔ£¬ÕâЩÉ豸ÔÚ¸ÅÄîÉϲ¢²»²¢ÁУ¬ÀýÈçÓë¿éÉ豸²¢ÁеÄÊÇ×Ö·ûÉ豸£¬¶øPCI¡¢USBÉ豸µÈ¶¼¿ÉÄÜÊôÓÚ×Ö·ûÉ豸£©£¬ÕâЩÉ豸µÄÇý¶¯ÖÐÓÖÉæ¼°µ½Ò»Ð©ÓëÌض¨É豸ÀàÐÍÏà¹ØµÄ½ÏΪ¸´ÔÓµÄÊý¾Ý½á¹¹ºÍ³ÌÐò½á¹¹¡£±¾ÎĽ«²»¶ÔÕâЩÉ豸Çý¶¯µÄϸ½Ú½øÐйý¶àµÄ½éÉÜ£¬½ö½ö½øÐÐÇáÃ赭дµÄÐðÊö¡£

¡¡¡¡PCI ÊÇThe Peripheral Component Interconnect -BusµÄËõд£¬CPUʹÓÃPCIÇÅchipsetÓëPCIÉ豸ͨÐÅ£¬PCIÇÅchipset´¦ÀíÁËPCI×ÓϵͳÓëÄÚ´æ×Óϵͳ¼äµÄËùÓÐÊý¾Ý½»»¥£¬PCIÉ豸ÍêÈ«±»´ÓÄÚ´æ×Óϵͳ·ÖÀë³öÀ´¡£ÏÂͼ³ÊÏÖÁËPCI×ÓϵͳµÄÔ­Àí£º

[align=center][/align]

¡¡¡¡Ã¿¸öPCIÉ豸¶¼ÓÐÒ»¸ö256×Ö½ÚµÄÉ豸ÅäÖÿ飬ÆäÖÐÇ°64×Ö½Ú×÷ΪÉ豸µÄIDºÍ»ù±¾ÅäÖÃÐÅÏ¢£¬LinuxÖÐÌṩÁËÒ»×麯ÊýÀ´´¦ÀíPCIÅäÖÿ顣ÔÚPCIÉ豸ÄܵÃÒÔʹÓÃÇ°£¬LinuxÇý¶¯³ÌÐòÐèÒª´ÓPCIÉ豸ÅäÖÿéÖеÄÐÅÏ¢¾ö¶¨É豸µÄÌض¨²ÎÊý£¬½øÐÐÏà¹ØÉèÖÃÒÔ±ãÄÜÕýÈ·²Ù×÷¸ÃPCIÉ豸¡£

¡¡¡¡Ò»°ãµÄPCIÉ豸³õʼ»¯º¯Êý´¦ÀíÁ÷³ÌΪ£º

¡¡¡¡£¨1£©¼ì²éÄÚºËÊÇ·ñÖ§³ÖPCI-Bios£»

¡¡¡¡£¨2£©¼ì²éÉ豸ÊÇ·ñ´æÔÚ£¬»ñµÃÉ豸µÄÅäÖÃÐÅÏ¢£»

¡¡¡¡1¡«2ÕâÁ½²½µÄÀý×ÓÈçÏ£º

ÒýÓÃ:
int pcidata_read_proc(char *buf, char **start, off_t offset, int len, int *eof,void *data)
{
¡¡int i, pos = 0;
¡¡int bus, devfn;
¡¡if (!pcibios_present())
¡¡¡¡return sprintf(buf, "No PCI bios present\n");

¡¡/*
¡¡* This code is derived from "drivers/pci/pci.c". This means that
¡¡* the GPL applies to this source file and credit is due to the
¡¡* original authors (Drew Eckhardt, Frederic Potter, David
¡¡* Mosberger-Tang)
¡¡*/
¡¡for (bus = 0; !bus; bus++)
¡¡{
¡¡¡¡/* only bus 0 :-) */
¡¡¡¡for (devfn = 0; devfn
¡¡¡¡ÆäÖÐʹÓõÄpci_find_slot()º¯Êý¶¨ÒåΪ£º

struct pci_dev *pci_find_slot (unsigned int bus,
unsigned int devfn)
{
¡¡struct pci_dev *pptr = kmalloc(sizeof(*pptr), GFP_KERNEL);
¡¡int index = 0;
¡¡unsigned short vendor;
¡¡int ret;

¡¡if (!pptr) return NULL;
¡¡pptr->index = index; /* 0 */
¡¡ret = pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor);
¡¡if (ret /* == PCIBIOS_DEVICE_NOT_FOUND or whatever error */
|| vendor==0xffff || vendor==0x0000) {
¡¡¡¡kfree(pptr); return NULL;
¡¡}
¡¡printk("ok (%i, %i %x)\n", bus, devfn, vendor);
¡¡/* fill other fields */
¡¡pptr->bus = bus;
¡¡pptr->devfn = devfn;
¡¡pcibios_read_config_word(pptr->bus, pptr->devfn,PCI_VENDOR_ID, &pptr->vendor);
¡¡pcibios_read_config_word(pptr->bus, pptr->devfn,PCI_DEVICE_ID, &pptr->device);
¡¡return pptr;
}


¡¡¡¡£¨3£©¸ù¾ÝÉ豸µÄÅäÖÃÐÅÏ¢ÉêÇëI/O¿Õ¼ä¼°IRQ×ÊÔ´£»

¡¡¡¡ÕâÀïËù˵µÄ¸´ÔÓÉ豸Çý¶¯Éæ¼°µ½PCI¡¢USB¡¢ÍøÂçÉ豸¡¢¿éÉ豸µÈ£¨ÑϸñÒâÒå¶øÑÔ£¬ÕâЩÉ豸ÔÚ¸ÅÄîÉϲ¢²»²¢ÁУ¬ÀýÈçÓë¿éÉ豸²¢ÁеÄÊÇ×Ö·ûÉ豸£¬¶øPCI¡¢USBÉ豸µÈ¶¼¿ÉÄÜÊôÓÚ×Ö·ûÉ豸£©£¬ÕâЩÉ豸µÄÇý¶¯ÖÐÓÖÉæ¼°µ½Ò»Ð©ÓëÌض¨É豸ÀàÐÍÏà¹ØµÄ½ÏΪ¸´ÔÓµÄÊý¾Ý½á¹¹ºÍ³ÌÐò½á¹¹¡£±¾ÎĽ«²»¶ÔÕâЩÉ豸Çý¶¯µÄϸ½Ú½øÐйý¶àµÄ½éÉÜ£¬½ö½ö½øÐÐÇáÃ赭дµÄÐðÊö¡£

¡¡¡¡PCI ÊÇThe Peripheral Component Interconnect -BusµÄËõд£¬CPUʹÓÃPCIÇÅchipsetÓëPCIÉ豸ͨÐÅ£¬PCIÇÅchipset´¦ÀíÁËPCI×ÓϵͳÓëÄÚ´æ×Óϵͳ¼äµÄËùÓÐÊý¾Ý½»»¥£¬PCIÉ豸ÍêÈ«±»´ÓÄÚ´æ×Óϵͳ·ÖÀë³öÀ´¡£ÏÂͼ³ÊÏÖÁËPCI×ÓϵͳµÄÔ­Àí£º

[align=center][/align]

¡¡¡¡Ã¿¸öPCIÉ豸¶¼ÓÐÒ»¸ö256×Ö½ÚµÄÉ豸ÅäÖÿ飬ÆäÖÐÇ°64×Ö½Ú×÷ΪÉ豸µÄIDºÍ»ù±¾ÅäÖÃÐÅÏ¢£¬LinuxÖÐÌṩÁËÒ»×麯ÊýÀ´´¦ÀíPCIÅäÖÿ顣ÔÚPCIÉ豸ÄܵÃÒÔʹÓÃÇ°£¬LinuxÇý¶¯³ÌÐòÐèÒª´ÓPCIÉ豸ÅäÖÿéÖеÄÐÅÏ¢¾ö¶¨É豸µÄÌض¨²ÎÊý£¬½øÐÐÏà¹ØÉèÖÃÒÔ±ãÄÜÕýÈ·²Ù×÷¸ÃPCIÉ豸¡£

¡¡¡¡Ò»°ãµÄPCIÉ豸³õʼ»¯º¯Êý´¦ÀíÁ÷³ÌΪ£º

¡¡¡¡£¨1£©¼ì²éÄÚºËÊÇ·ñÖ§³ÖPCI-Bios£»

¡¡¡¡£¨2£©¼ì²éÉ豸ÊÇ·ñ´æÔÚ£¬»ñµÃÉ豸µÄÅäÖÃÐÅÏ¢£»

¡¡¡¡1¡«2ÕâÁ½²½µÄÀý×ÓÈçÏ£º

ÒýÓÃ:
int pcidata_read_proc(char *buf, char **start, off_t offset, int len, int *eof,void *data)
{
¡¡int i, pos = 0;
¡¡int bus, devfn;
¡¡if (!pcibios_present())
¡¡¡¡return sprintf(buf, "No PCI bios present\n");

¡¡/*
¡¡* This code is derived from "drivers/pci/pci.c". This means that
¡¡* the GPL applies to this source file and credit is due to the
¡¡* original authors (Drew Eckhardt, Frederic Potter, David
¡¡* Mosberger-Tang)
¡¡*/
¡¡for (bus = 0; !bus; bus++)
¡¡{
¡¡¡¡/* only bus 0 :-) */
¡¡¡¡for (devfn = 0; devfn
¡¡¡¡ÆäÖÐʹÓõÄpci_find_slot()º¯Êý¶¨ÒåΪ£º

struct pci_dev *pci_find_slot (unsigned int bus,
unsigned int devfn)
{
¡¡struct pci_dev *pptr = kmalloc(sizeof(*pptr), GFP_KERNEL);
¡¡int index = 0;
¡¡unsigned short vendor;
¡¡int ret;

¡¡if (!pptr) return NULL;
¡¡pptr->index = index; /* 0 */
¡¡ret = pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor);
¡¡if (ret /* == PCIBIOS_DEVICE_NOT_FOUND or whatever error */
|| vendor==0xffff || vendor==0x0000) {
¡¡¡¡kfree(pptr); return NULL;
¡¡}
¡¡printk("ok (%i, %i %x)\n", bus, devfn, vendor);
¡¡/* fill other fields */
¡¡pptr->bus = bus;
¡¡pptr->devfn = devfn;
¡¡pcibios_read_config_word(pptr->bus, pptr->devfn,PCI_VENDOR_ID, &pptr->vendor);
¡¡pcibios_read_config_word(pptr->bus, pptr->devfn,PCI_DEVICE_ID, &pptr->device);
¡¡return pptr;
}


¡¡¡¡£¨3£©¸ù¾ÝÉ豸µÄÅäÖÃÐÅÏ¢ÉêÇëI/O¿Õ¼ä¼°IRQ×ÊÔ´£»

¡¡¿éÇý¶¯³ÌÐò×îÖÕ±ØÐëÌṩÍê³Éʵ¼Ê¿é I/O ²Ù×÷µÄ»úÖÆ£¬ÔÚ LinuxÖУ¬ÓÃÓÚÕâЩ I/O ²Ù×÷µÄ·½·¨³ÆΪ"request£¨ÇëÇó£©"¡£ÔÚ¿éÉ豸µÄ×¢²á¹ý³ÌÖУ¬ÐèÒª³õʼ»¯request¶ÓÁУ¬ÕâÒ»¶¯×÷ͨ¹ýblk_init_queueÀ´Íê³É£¬blk_init_queueº¯Êý½¨Á¢¶ÓÁУ¬²¢½«¸ÃÇý¶¯³ÌÐòµÄ request º¯Êý¹ØÁªµ½¶ÓÁС£ÔÚÄ£¿éµÄÇå³ý½×¶Î£¬Ó¦µ÷Óà blk_cleanup_queue º¯Êý¡£¿´¿´mtdblockµÄÀý×Ó£º

ÒýÓÃ:
static void handle_mtdblock_request(void)
{
¡¡struct request *req;
¡¡struct mtdblk_dev *mtdblk;
¡¡unsigned int res;

¡¡for (;;) {
¡¡¡¡INIT_REQUEST;
¡¡¡¡req = CURRENT;
¡¡¡¡spin_unlock_irq(QUEUE_LOCK(QUEUE));
¡¡¡¡mtdblk = mtdblks[minor(req->rq_dev)];
¡¡¡¡res = 0;

¡¡¡¡if (minor(req->rq_dev) >= MAX_MTD_DEVICES)
¡¡¡¡¡¡panic("%s : minor out of bound", __FUNCTION__);

¡¡¡¡if (!IS_REQ_CMD(req))
¡¡¡¡¡¡goto end_req;

¡¡¡¡if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
¡¡¡¡¡¡goto end_req;

¡¡¡¡// Handle the request
¡¡¡¡switch (rq_data_dir(req))
¡¡¡¡{
¡¡¡¡¡¡int err;

¡¡¡¡¡¡case READ:
¡¡¡¡¡¡¡¡down(&mtdblk->cache_sem);
¡¡¡¡¡¡¡¡err = do_cached_read (mtdblk, req->sector << 9, req->current_nr_sectors << 9,
req->buffer);
¡¡¡¡¡¡¡¡up(&mtdblk->cache_sem);
¡¡¡¡¡¡¡¡if (!err)
¡¡¡¡¡¡¡¡¡¡res = 1;
¡¡¡¡¡¡¡¡¡¡break;
¡¡¡¡¡¡case WRITE:
¡¡¡¡¡¡¡¡// Read only device
¡¡¡¡¡¡¡¡if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) )
¡¡¡¡¡¡¡¡¡¡break;
¡¡¡¡¡¡¡¡¡¡// Do the write
¡¡¡¡¡¡¡¡¡¡down(&mtdblk->cache_sem);
¡¡¡¡¡¡¡¡¡¡err = do_cached_write (mtdblk, req->sector << 9,req->current_nr_sectors << 9,
req->buffer);
¡¡¡¡¡¡¡¡¡¡up(&mtdblk->cache_sem);
¡¡¡¡¡¡¡¡if (!err)
¡¡¡¡¡¡¡¡¡¡res = 1;
¡¡¡¡¡¡¡¡¡¡break;
¡¡¡¡}

¡¡¡¡end_req:
¡¡¡¡¡¡spin_lock_irq(QUEUE_LOCK(QUEUE));
¡¡¡¡¡¡end_request(res);
¡¡}
}

int __init init_mtdblock(void)
{
¡¡int i;

¡¡spin_lock_init(&mtdblks_lock);
¡¡/* this lock is used just in kernels >= 2.5.x */
¡¡spin_lock_init(&mtdblock_lock);

¡¡#ifdef CONFIG_DEVFS_FS
¡¡if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
¡¡{
¡¡¡¡printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",MTD_BLOCK_MAJOR);
¡¡¡¡return -EAGAIN;
¡¡}

¡¡devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
¡¡register_mtd_user(¬ifier);
¡¡#else
¡¡if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
¡¡¡¡printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",MTD_BLOCK_MAJOR);
¡¡¡¡return -EAGAIN;
¡¡}
¡¡#endif

¡¡/* We fill it in at open() time. */
¡¡for (i=0; i< MAX_MTD_DEVICES; i++) {
¡¡¡¡mtd_sizes[i] = 0;
¡¡¡¡mtd_blksizes[i] = BLOCK_SIZE;
¡¡}
¡¡init_waitqueue_head(&thr_wq);
¡¡/* Allow the block size to default to BLOCK_SIZE. */
¡¡blksize_size[MAJOR_NR] = mtd_blksizes;
¡¡blk_size[MAJOR_NR] = mtd_sizes;

¡¡BLK_INIT_QUEUE(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request, &mtdblock_lock);

¡¡kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
¡¡return 0;
}

static void __exit cleanup_mtdblock(void)
{
¡¡leaving = 1;
¡¡wake_up(&thr_wq);
¡¡down(&thread_sem);
¡¡#ifdef CONFIG_DEVFS_FS
¡¡¡¡unregister_mtd_user(¬ifier);
¡¡¡¡devfs_unregister(devfs_dir_handle);
¡¡¡¡devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
¡¡#else
¡¡¡¡unregister_blkdev(MAJOR_NR,DEVICE_NAME);
¡¡#endif
¡¡blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
¡¡blksize_size[MAJOR_NR] = NULL;
¡¡blk_size[MAJOR_NR] = NULL;
}
ÎÄÕÂÆÀÂÛ

¹²ÓÐ 2 ÌõÆÀÂÛ

  1. onebit ÓÚ 2006-11-06 10:22:47·¢±í:

    ˵µÄÂùÇå³þµÄ

  2. fanxinghua ÓÚ 2006-11-05 21:33:06·¢±í:

    ¿´²»¶®:0)1