日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

PCI驱动编程

發布時間:2023/12/18 编程问答 120 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PCI驱动编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、字符設備和塊設備
Linux抽象了對硬件的處理,所有的硬件設備都可以像普通文件一樣來看待:它們可以使用和操作文件相同的、標準的系統調用接口來完成打開、關閉、讀寫和I/O控制操作,而驅動程序的主要任務也就是要實現這些系統調用函數。Linux系統中的所有硬件設備都使用一個特殊的設備文件來表示,例如,系統中的第一個IDE硬盤使用/dev/hda表示。每個設備文件對應有兩個設備號:一個是主設備號,標識該設備的種類,也標識了該設備所使用的驅動程序;另一個是次設備號,標識使用同一設備驅動程序的不同硬件設備。設備文件的主設備號必須與設備驅動程序在登錄該設備時申請的主設備號一致,否則用戶進程將無法訪問到設備驅動程序。

在Linux操作系統下有兩類主要的設備文件:一類是字符設備,另一類則是塊設備。字符設備是以字節為單位逐個進行I/O操作的設備,在對字符設備發出讀寫請求時,實際的硬件I/O緊接著就發生了,一般來說字符設備中的緩存是可有可無的,而且也不支持隨機訪問。塊設備則是利用一塊系統內存作為緩沖區,當用戶進程對設備進行讀寫請求時,驅動程序先查看緩沖區中的內容,如果緩沖區中的數據能滿足用戶的要求就返回相應的數據,否則就調用相應的請求函數來進行實際的I/O操作。塊設備主要是針對磁盤等慢速設備設計的,其目的是避免耗費過多的CPU時間來等待操作的完成。一般說來,PCI卡通常都屬于字符設備。

所有已經注冊(即已經加載了驅動程序)的硬件設備的主設備號可以從/proc/devices文件中得到。使用mknod命令可以創建指定類型的設備文件,同時為其分配相應的主設備號和次設備號。例如,下面的命令:
[root@gary root]# mknod /dev/lp0 c 6 0
將建立一個主設備號為6,次設備號為0的字符設備文件/dev/lp0。當應用程序對某個設備文件進行系統調用時,Linux內核會根據該設備文件的設備類型和主設備號調用相應的驅動程序,并從用戶態進入到核心態,再由驅動程序判斷該設備的次設備號,最終完成對相應硬件的操作。

二、設備驅動程序接口
Linux中的I/O子系統向內核中的其他部分提供了一個統一的標準設備接口,這是通過include/linux/fs.h中的數據結構file_operations來完成的:

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **);long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); };

當應用程序對設備文件進行諸如open、close、read、write等操作時,Linux內核將通過file_operations結構訪問驅動程 序提供的函數。例如,當應用程序對設備文件執行讀操作時,內核將調用file_operations結構中的read函數。

三、設備驅動程序模塊
Linux下的設備驅動程序可以按照兩種方式進行編譯,一種是直接靜態編譯成內核的一部分,另一種則是編譯成可以動態加載的模塊。如果編譯進內核的話,會增加內核的大小,還要改動內核的源文件,而且不能動態地卸載,不利于調試,所有推薦使用模塊方式。

從本質上來講,模塊也是內核的一部分,它不同于普通的應用程序,不能調用位于用戶態下的C或者C++庫函數,而只能調用Linux內核提供的函數,在/proc/ksyms中可以查看到內核提供的所有函數。

在以模塊方式編寫驅動程序時,要實現兩個必不可少的函數init_module( )和cleanup_module( ),而且至少要包含和兩 個頭文件。一般使用LDD3 例程中使用的makefile 作為基本的版本,稍作改變之后用來編譯驅動,編譯生成的模塊(一般為.ko文件)可以使用命令insmod載入Linux內核,從而成為內核的一個組成部分,此時內核會調用 模塊中的函數init_module( )。當不需要該模塊時,可以使用rmmod命令進行卸載,此進內核會調用模塊中的函數cleanup_module( )。任何時候都可以使用命令來lsmod查看目前已經加載的模塊以及正在使用該模塊的用戶數。

四、設備驅動程序結構
了解設備驅動程序的基本結構(或者稱為框架),對開發人員而言是非常重要的,Linux的設備驅動程序大致可以分為如下幾個部分:驅動程序的注冊與注銷、設備的打開與釋放、設備的讀寫操作、設備的控制操作、設備的中斷和輪詢處理。

1.驅動程序的注冊與注銷
向系統增加一個驅動程序意味著要賦予它一個主設備號,這可以通過在驅動程序的初始化過程中調用alloc_chrdev_region( )或者register_chrdev_region( )來完成。而在關閉字符設備時,則需要通過調用unregister_chrdev_region( )從內核中注銷設備,同時釋放占用的主設備號。

2.設備的打開與釋放
打開設備是通過調用file_operations結構中的函數open( )來完成的,它是驅動程序用來為今后的操作完成初始化準備工作的。在大部分驅動程序中,open( )通常需要完成下列工作:
a. 檢查設備相關錯誤,如設備尚未準備好等。
b. 如果是第一次打開,則初始化硬件設備。
c. 識別次設備號,如果有必要則更新讀寫操作的當前位置指針f_ops。
d. 分配和填寫要放在file->private_data里的數據結構。
e. 使用計數增1。
釋放設備是通過調用file_operations結構中的函數release( )來完成的,這個設備方法有時也被稱為close( ),它的作用正好與open( )相反,通常要完成下列工作:
a. 使用計數減1。
b. 釋放在file->private_data中分配的內存。
c. 如果使用計算為0,則關閉設備。

3.設備的讀寫操作
字符設備的讀寫操作相對比較簡單,直接使用函數read( )和write( )就可以了。但如果是塊設備的話,則需要調用函數block_read( )和block_write( )來進行數據讀寫,這兩個函數將向設備請求表中增加讀寫請求,以便Linux內核可以對請求順序進行優化。由于是對內存緩沖區而不是直接對設備進行操作的,因此能很大程度上加快讀寫速度。如果內存緩沖區中沒有所要讀入的數據,或者需要執行寫操作將數據寫入設備,那么就要執行真正的數據傳輸,這是通過調用數據結構blk_dev_struct中的函數request_fn( )來完成的。

4.設備的控制操作
除了讀寫操作外,應用程序有時還需要對設備進行控制,這可以通過設備驅動程序中的函數ioctl( )來完成,ioctl 系統調用有下面的原型: int ioctl(int fd, unsigned long cmd, …),第一個參數是文件描述符,第二個參數是具體的命令,一般使用宏定義來確定,第三個參數一般是傳遞給驅動中處理設備控制操作函數的參數。ioctl( )的用法與具體設備密切關聯,因此需要根據設備的實際情況進行具體分析。

5.設備的中斷和輪詢處理
對于不支持中斷的硬件設備,讀寫時需要輪流查詢設備狀態,以便決定是否繼續進行數據傳輸。如果設備支持中斷,則可以按中斷方式進行操作。

五、PCI驅動程序框架
1.關鍵數據結構
PCI設備上有三種地址空間:PCI的I/O空間、PCI的存儲空間和PCI的配置空間。CPU可以訪問PCI設備上的所有地址空間,其中I/O空間和存儲空間提供給設備驅動程序使用,而配置空間則由Linux內核中的PCI初始化代碼使用。內核在啟動時負責對所有PCI設備進行初始化,配置好所有的PCI設備,包括中斷號以及I/O基址,并在文件/proc/pci中列出所有找到的PCI設備,以及這些設備的參數和屬性。

Linux驅動程序通常使用結構(struct)來表示一種設備,而結構體中的變量則代表某一具體設備,該變量存放了與該設備相關的所有信息。好的驅動程序都應該能驅動多個同種設備,每個設備之間用次設備號進行區分,如果采用結構數據來代表所有能由該驅動程序驅動的設備,那么就可以簡單地使用數組下標來表示次設備號。

在PCI驅動程序中,下面幾個關鍵數據結構起著非常核心的作用:
a. pci_driver
這個數據結構在文件include/linux/pci.h里,其中最主要的是用于識別設備的id_table結構,以及用于檢測設備的函數probe( )和卸載設備的函數remove( ):

struct pci_driver {struct list_head node;const char *name;const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */int (*suspend_late) (struct pci_dev *dev, pm_message_t state);int (*resume_early) (struct pci_dev *dev);int (*resume) (struct pci_dev *dev); /* Device woken up */void (*shutdown) (struct pci_dev *dev);int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */const struct pci_error_handlers *err_handler;struct device_driver driver;struct pci_dynids dynids; };

b. pci_dev
這個數據結構也在文件include/linux/pci.h里,它詳細描述了一個PCI設備幾乎所有的硬件信息,包括廠商ID、設備ID、各種資源等

struct pci_dev {struct list_head bus_list; /* node in per-bus list */struct pci_bus *bus; /* bus this device is on */struct pci_bus *subordinate; /* bus this device bridges to */void *sysdata; /* hook for sys-specific extension */struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */struct pci_slot *slot; /* Physical slot this device is in */unsigned int devfn; /* encoded device & function index */unsigned short vendor;unsigned short device;unsigned short subsystem_vendor;unsigned short subsystem_device;unsigned int class; /* 3 bytes: (base,sub,prog-if) */u8 revision; /* PCI revision, low byte of class word */u8 hdr_type; /* PCI header type (`multi' flag masked out) */u8 pcie_type; /* PCI-E device/port type */u8 rom_base_reg; /* which config register controls the ROM */u8 pin; /* which interrupt pin this device uses */struct pci_driver *driver; /* which driver has allocated this device */u64 dma_mask; /* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change this if your device has broken DMA or supports 64-bit transfers. */struct device_dma_parameters dma_parms;pci_power_t current_state; /* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, and D3 being off. */int pm_cap; /* PM capability offset in the configuration space */unsigned int pme_support:5; /* Bitmask of states from which PME# can be generated */unsigned int d1_support:1; /* Low power state D1 is supported */unsigned int d2_support:1; /* Low power state D2 is supported */unsigned int no_d1d2:1; /* Only allow D0 and D3 */unsigned int wakeup_prepared:1; #ifdef CONFIG_PCIEASPMstruct pcie_link_state *link_state; /* ASPM link state. */ #endifpci_channel_state_t error_state; /* current connectivity state */struct device dev; /* Generic device interface */int cfg_size; /* Size of configuration space *//** Instead of touching interrupt line and base address registers* directly, use the values stored here. They might be different!*/unsigned int irq;struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs *//* These fields are used by common fixups */unsigned int transparent:1; /* Transparent PCI bridge */unsigned int multifunction:1;/* Part of multi-function device *//* keep track of device state */unsigned int is_added:1;unsigned int is_busmaster:1; /* device is busmaster */unsigned int no_msi:1; /* device may not use msi */unsigned int block_ucfg_access:1; /* userspace config space access is blocked */unsigned int broken_parity_status:1; /* Device generates false positive parity */unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */unsigned int msi_enabled:1;unsigned int msix_enabled:1;unsigned int ari_enabled:1; /* ARI forwarding */unsigned int is_managed:1;unsigned int is_pcie:1;unsigned int needs_freset:1; /* Dev requires fundamental reset */unsigned int state_saved:1;unsigned int is_physfn:1;unsigned int is_virtfn:1;unsigned int reset_fn:1;unsigned int is_hotplug_bridge:1;pci_dev_flags_t dev_flags;atomic_t enable_cnt; /* pci_enable_device has been called */u32 saved_config_space[16]; /* config space saved at suspend time */struct hlist_head saved_cap_space;struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */int rom_attr_enabled; /* has display of the rom attribute been enabled? */struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSIstruct list_head msi_list; #endifstruct pci_vpd *vpd; #ifdef CONFIG_PCI_IOVunion {struct pci_sriov *sriov; /* SR-IOV capability related */struct pci_dev *physfn; /* the PF this VF is associated with */};struct pci_ats *ats; /* Address Translation Service */ #endif };

2.基本框架
在用模塊方式實現PCI設備驅動程序時,通常至少要實現以下幾個部分:初始化設備模塊、設備打開模塊、數據讀寫和控制模塊、中斷處理模塊、設備釋放模塊、設備卸載模塊。下面給出一個典型的PCI設備驅動程序的基本框架,從中不難體會到這幾個關鍵模塊是如何組織起來的。

/* 指明該驅動程序適用于哪一些PCI設備 */ static struct pci_device_id demo_pci_tbl[] ={{PCI_DEVICE(PCI_VENDOR_ID_DEMO,PCI_DEVICE_ID_DEMO),},{0,}, };/* 對特定PCI設備進行描述的數據結構 */ struct device_private { /* ... */};/* 中斷處理模塊 */ static irqreturn_t device_interrupt(int irq, void *dev_id) { /* ... */}static int demo_open(struct inode *inode,struct file *file) {/* ... */try_module_get(THIS_MODULE);return 0; }static int demo_read(struct file *file,char __user *buffer,size_t count,loff_t *offp) { /* ... */}static int demo_write(struct file *file,const char __user *buffer,size_t count,loff_t *offp) { /* ... */}static int demo_mmap(struct file *file, struct vm_area_struct *vma) { /* ... */}static int demo_ioctl(struct inode *inode,struct file *file, unsigned int cmd,unsigned long arg) { switch(cmd){ case CMD1: device_func(arg); break; ... default: } /* ... */}static int demo_release(struct inode *inode,struct file *file) {/* ... */ module_put(THIS_MODULE); return 0; }/* 設備文件操作接口 */ static struct file_operations demo_fops={.owner = THIS_MODULE, /* demo_fops所屬的設備模塊 */.read = demo_read, /* 讀設備操作*/.write = demo_write, /* 寫設備操作*/.open = demo_open, /* 打開設備操作*/.ioctl = demo_ioctl, /* 控制設備操作*/.mmap = demo_mmap, /* 內存重映射操作*/.release = demo_release, /* 釋放設備操作*/ /* ... */}; static int __init demo_probe(struct pci_dev *pci_dev,const struct pci_device_id *pci_id) { /* ... */}; static void __devexit demo_remove(struct pci_dev *pci_dev) { /* ... */}; /* 設備模塊信息 */ static struct pci_driver demo_pci_driver = {.name= DEMO_MODULE_NAME, /* 設備模塊名稱 */.id_table = demo_pci_tbl, /* 能夠驅動的設備列表 */.probe = demo_probe, /* 查找并初始化設備 */.remove = demo_remove, /* 卸載設備模塊 */ /* ... */};static int __init demo_init_module (void) { pci_register_driver(&demo_pci_driver); //注冊設備驅動 /* ... */}static void __exit demo_exit_module(void) {/* ... */ pci_unregister_driver(&demo_pci_driver); }/* 加載驅動程序模塊入口 */ module_init(demo_init_module);/* 卸載驅動程序模塊入口 module_exit(demo_exit_module); */

上面這段代碼給出了一個典型的PCI設備驅動程序的框架,是一種相對固定的模式。需要注意的是,同加載和卸載模塊相關的函數或數據結構都要在前面加上 __init、__exit等標志符,以使同普通函數區分開來。構造出這樣一個框架之后,接下去的工作就是如何完成框架內的各個功能模塊了。

六、框架的具體實現之模塊操作
1.struct pci_device_id
PCI驅動程序向PCI子系統注冊其支持的廠家ID,設備ID和設備類編碼。使用這個數據庫,插入的卡通過配置空間被識別后,PCI子系統把插入的卡和對應的驅動程序綁定。
PCI設備列表

struct pci_device_id {__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/__u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */__u32 class, class_mask; /* (class,subclass,prog-if) triplet */kernel_ulong_t driver_data; /* Data private to the driver */ };

pci_device_id被用在struct pci_device 中。在示例中,創建了一個結構體數組,每一個結構表明使用該結構體數組的驅動支持的設備,數組的最后一個值是全部設置為0的空結構體,也就是{0,}。這個結構體需要被導出到用戶空間,使熱插拔和模塊裝載系統知道什么模塊對應什么硬件設備,宏MODULE_DEVICE_TABLE完成這個工作。例如:

MODULE_DEVICE_TABLE(pci, demo_pci_tbl);

2.初始化設備模塊
在Linux系統下,想要完成對一個PCI設備的初始化,需要完成以下工作:
a. 檢查PCI總線是否被Linux內核支持;
b. 檢查設備是否插在總線插槽上,如果在的話則保存它所占用的插槽的位置等信息。
c. 讀出配置頭中的信息提供給驅動程序使用。

當Linux內核啟動并完成對所有PCI設備進行掃描、登錄和分配資源等初始化操作的同時,會建立起系統中所有PCI設備的拓撲結構。系統加載模塊是調用pci_init_module函數,在這個函數中我們通過pci_register_driver 把new_pci_driver注冊到系統中。在調用pci_register_driver時,需要提供一個pci_driver結構。這個函數首先檢測id_table中定義的PCI信息是否和系統中的PCI信息有匹配,如果有則返回0,匹配成功后調用probe函數對PCI設備進行進一步的操作。

static int __init demo_init_module (void) { /* allocate (several) major number */ret = alloc_chrdev_region(&devno, 0, MAX_DEVICE, "buffer"); ret= pci_register_driver(&demo_pci_driver); }

probe函數的作用就是啟動pci設備,讀取配置空間信息,進行相應的初始化。

static int __init demo_probe(struct pci_dev *pci_dev,const struct pci_device_id *pci_id) {int result;printk("probe function is running\n");struct device_privdata *privdata;privdata->pci_dev = pci_dev; //把設備指針地址放入PCI設備中的設備指針中,便于后面調用pci_get_drvdatapci_set_drvdata(pci_dev, privdata); /* 啟動PCI設備 */if(pci_enable_device(pci_dev)){printk(KERN_ERR "%s:cannot enable device\n", pci_name(pci_dev)); return -ENODEV;} /*動態申請設備號,把fops傳進去*/privdata->cdev = cdev_alloc();privdata->cdev->ops=&jlas_fops;privdata->cdev->owner = THIS_MODULE;cdev_add(privdata->cdev,devno,1);/*動態創建設備節點*/privdata->cdev_class = class_create(THIS_MODULE,DEV_NAME);device_create(privdata->cdev_class,NULL, devno, pci_dev, DEV_NAME);privdata->irq=pci_dev->irq;privdata->iobase=pci_resource_start(privdata->pci_dev, BAR_IO);/*判斷IO資源是否可用*/if((pci_resource_flags(pci_dev, BAR_IO) & IORESOURCE_IO) != IORESOURCE_IO)goto err_out;/* 對PCI區進行標記 ,標記該區域已經分配出去*/ ret= pci_request_regions(pci_dev, DEVICE_NAME);if(ret) goto err_out;/*初始化tasklet*/tasklet_init(&(privdata->my_tasklet),jlas_1780_do_tasklet,(unsigned long )&jlas_pci_cdev); /* 初始化自旋鎖 */ spin_lock_init(&private->lock); /*初始化等待隊列*/init_waitqueue_head(&(privdata->read_queue)); /* 設置成總線主DMA模式 */ pci_set_master(pci_dev); /*申請內存*/privdata->mem = (u32 *) __get_free_pages(GFP_KERNEL|__GFP_DMA | __GFP_ZERO, memorder);if (!privdata->mem) { goto err_out;} /*DMA映射*/privdata->dma_addrp = pci_map_single(pdev, privdata->mem,PAGE_SIZE * (1 << memorder), PCI_DMA_FROMDEVICE);if (pci_dma_mapping_error(pdev, privdata->dma_addrp)) {goto err_out;} /*對硬件進行初始化設置,往寄存器中寫一些值,復位硬件等*/device_init(xx_device);return 0;err_out:printk("error process\n");resource_cleanup_dev(FCswitch); //如果出現任何問題,釋放已經分配了的資源return ret; }

3.卸載設備模塊
卸載設備模塊與初始化設備模塊是相對應的,實現起來相對比較簡單,主要是調用函數pci_unregister_driver( )從Linux內核中注銷設備驅動程序:

static void __exit demo_cleanup_module (void) {pci_unregister_driver(&demo_pci_driver); }

在卸載模塊時調用pci_cleanup_module,這個函數中通過pci_unregister_driver對new_pci_driver進行注銷,這個會調用到remove函數。remove函數的職責就是釋放一切分配過的資源,根據自己代碼的需要進行具體的操作。

static void __devexit my_pci_remove(struct pci_dev *pci_dev) {struct device_private *private;private= (struct device_private*)pci_get_drvdata(pci_dev); /*對硬件進行操作,如硬件復位*/Device_close(xx_device);pci_unmap_single(pdev, privdata->dma_mem,PAGE_SIZE * (1 << memorder), PCI_DMA_FROMDEVICE); // 釋放分配的內存空間free_pages ((unsigned long) privdata->mem, memorder);pci_clear_master(pdev); /* Nobody seems to do this */tasklet_kill(&(privdata->my_tasklet));pci_release_regions(pci_dev); // 移除動態創建的設備號和設備device_destroy(device_class, device->my_dev);class_destroy(device_class);if(privdata->pci_dev!=NULL)cdev_del(privdata->cdev); privdata->pci_dev=NULL;pci_disable_device(pci_dev);pci_set_drvdata(pci_dev,NULL); }

4.中斷處理
中斷處理,主要就是讀取中斷寄存器,然后調用中斷處理函數來處理中斷的下半部分,一般通過tasklet或者workqueue來實現。
注意:由于使用request_irq 獲得的中斷是共享中斷,因此在中斷處理函數的上半部需要區分是不是該設備發出的中斷,這就需要讀取中斷狀態寄存器的值來判斷,如果不是該設備發起的中斷則 返回 IRQ_NONE

/* 中斷處理模塊 */ void jlas_do_tasklet(unsigned long data) {spin_lock(&(privdata->my_spin_lock));//具體操作spin_unlock(&(privdata->my_spin_lock));wake_up_interruptible(&(privdata->read_queue)); }static irqreturn_t device_interrupt(int irq, void *dev_id) {struct device_privdata *privdata = dev_id;tasklet_schedule(&(privdata->my_tasklet));return IRQ_HANDLED;/* ... */}

七、框架的具體實現之設備文件操作
1.設備文件操作接口
當應用程序對設備文件進行諸如open、close、read、write等操作時,Linux內核將通過file_operations結構訪問驅動程序提供的函數。例如,當應用程序對設備文件執行讀操作時,內核將調用file_operations結構中的read函數。

/* 設備文件操作接口 */ static struct file_operations demo_fops={.owner = THIS_MODULE, /* demo_fops所屬的設備模塊 */.read = demo_read, /* 讀設備操作*/.write = demo_write, /* 寫設備操作*/.open = demo_open, /* 打開設備操作*// .ioctl = demo_ioctl, /* 控制設備操作*/.mmap = demo_mmap, /* 內存重映射操作*/.release = demo_release, /* 釋放設備操作*//* ... */};

2.打開設備
open 方法提供給驅動來做任何的初始化來準備后續的操作.在這個模塊里主要實現申請中斷、檢查讀寫模式以及申請對設備的控制權等。在申請控制權的時候,非阻塞方式遇忙返回,否則進程主動接受調度,進入睡眠狀態,等待其它進程釋放對設備的控制權。 open 方法的原型是:

int (*open)(struct inode *inode, struct file *filp);

inode 參數有我們需要的信息,以它的 i_cdev 成員的形式, 里面包含我們之前建立的cdev 結構. 唯一的問題是通常我們不想要 cdev 結構本身, 我們需要的是包含 cdev 結構的 device_private 結構.

static int demo_open(struct inode *inode, struct file *filp) {struct device_private *private;private= container_of(inode->i_cdev, struct device_private, my_cdev);filp->private_data = private;private->open_flag++; /*申請中斷*/ret = request_irq(privdata->irq,interrupt_handler, IRQF_SHARED, DEV_NAME,privdata);if(ret)return -EINVAL; ...try_module_get(THIS_MODULE);return 0; }

3.釋放設備
release 方法的角色是 open 的反面,設備方法應當進行下面的任務:
a. 釋放 open 分配在 filp->private_data 中的任何東西
b. 在最后的 close 關閉設備

static int demo_release(struct inode *inode,struct file *filp) {struct device_private *private= filp->private_data;private->open_flag--;free_irq(pdev->irq, privdata);module_put(THIS_MODULE);printk("pci device close success\n");return 0; }

4.設備數據讀寫和ioctl
PCI設備驅動程序可以通過device_fops 結構中的函數device_ioctl( ),向應用程序提供對硬件進行控制的接口。例如,通過它可以從I/O寄存器里讀取一個數據,并傳送到用戶空間里。

static int device_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) {int retval = 0;struct device_private *privdata= filp->private_data; switch (cmd){case CMD1:device_func(arg);break;...default:retval = -EINVAL;}return retval; }

5.內存映射

static int device_mmap(struct file *filp, struct vm_area_struct *vma) {int ret;struct device_private *private = filp->private_data;vma->vm_page_prot = PAGE_SHARED;//訪問權限vma->vm_pgoff = virt_to_phys(FCswitch->rx_buf_virts) >> PAGE_SHIFT;//偏移(頁幀號)ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, (unsigned long)(vma->vm_end-vma->vm_start), vma->vm_page_prot);if(ret!=0)return -EAGAIN;return 0; }

對 remap_pfn_range()函數的說明:
remap_pfn_range()函數的原型

int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot);

該函數的功能是創建頁表。其中參數vma是內核根據用戶的請求自己填寫的,而參數addr表示內存映射開始處的虛擬地址,因此,該函數為addr~addr+size之間的虛擬地址構造頁表。

另外,pfn(Page Fram Number)是虛擬地址應該映射到的物理地址的頁面號,實際上就是物理地址右移PAGE_SHIFT位。如果PAGE_SHIFT為4kb,則 PAGE_SHIFT為12,因為PAGE_SHIFT等于1 << PAGE_SHIFT 。

最后一個參數prot是新頁所要求的保護屬性。

在驅動程序中,一般能使用remap_pfn_range()映射內存中的保留頁(如X86系統中的640KB~1MB區域)和設備I/O內存。因此,如 果想把kmalloc()申請的內存映射到用戶空間,則可以通過SetPageReserved把相應的內存設置為保留后就可以。

八、附錄
1.PCI設備私有數據結構

/* 對特定PCI設備進行描述的數據結構 */ struct device_private {/*次設備號*/unsigned int minor; /*注冊字符驅動和發現PCI設備的時候使用*/struct pci_dev *pci_dev;struct cdev *cdev;struct class *cdev_class;/*中斷號*/ unsigned int irq;/* 用于獲取PCI設備配置空間的基本信息 */ unsigned long iobase;/*用于保存分配給PCI設備的內存空間的信息*/ dma_addr_t dma_addrp;char *virts_addr;/*基本的同步手段*/spinlock_t lock;/*等待隊列*/wait_queue_head_t read_queue;/*tasklet*/struct tasklet_struct my_tasklet;/*異步*/struct fasync_struct *async_queue;/*設備打開標記*/int open_flag //* .....*/ };

2.PCI配置寄存器
所有的PCI設備都有至少256字節的地址空間,前64字節是標準化的,而其余的是設備相關的。圖1顯示了設備無關的配置空間的布局。

在Linux系統上,可以通過cat /proc/pci 等命令查看系統中所有PCI設備的類別、型號以及廠商等等信息,那就是從這些寄存器來的。下面是用lspci -x命令截取的部分信息(lspci命令也是使用/proc文件作為其信息來源)(PCI寄存器是小端字節序格式的):

00:00.0 Host bridge: Intel Corp. 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01) 00: 86 80 90 71 06 00 00 02 01 00 00 06 00 00 00 00 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 ad 15 76 19 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

那么根據下面的PCI配置寄存器組的結構,這個Host bridge的Vendor ID就是0x8086。

圖1.標準化的PCI配置寄存器

參考資料:
1. LINUX設備驅動程序(第三版)
2. Linux下PCI設備驅動程序開發
http://www.ibm.com/developerworks/cn/linux/l-pci/index.html
3. Linux PCI 設備驅動基本框架(一)
http://www.cnblogs.com/zhuyp1015/archive/2012/06/30/2571400.html
4. Linux PCI 設備驅動基本框架(二)
http://www.cnblogs.com/zhuyp1015/archive/2012/06/30/2571408.html
5. 淺談Linux PCI設備驅動(一)
http://blog.csdn.net/linuxdrivers/article/details/5849698

總結

以上是生活随笔為你收集整理的PCI驱动编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

黄免费在线观看 | 精品字幕在线 | av网站在线免费观看 | 天堂在线成人 | 精品久久一区二区 | 欧美 日韩 国产 中文字幕 | 看片网站黄 | 亚洲电影网站 | 久久99精品久久久久久三级 | 伊人婷婷久久 | 91亚洲国产成人久久精品网站 | 精品在线99| а天堂中文最新一区二区三区 | 国产精品成人免费精品自在线观看 | 日韩中午字幕 | 国产精品粉嫩 | av在线h| 国产亚洲片 | 四虎在线观看精品视频 | 狠狠网站| 亚洲无毛专区 | 四虎影院在线观看av | 国产精品二区在线观看 | 婷婷激情五月 | 国产经典av | 中文字幕超清在线免费 | 免费看国产一级片 | 日韩精品一区二区三区在线播放 | 四虎影院在线观看av | 精品国产精品国产偷麻豆 | 亚洲日韩中文字幕在线播放 | 亚洲精品乱码久久久久久按摩 | 6080yy午夜一二三区久久 | 亚洲精品成人免费 | 全久久久久久久久久久电影 | 97精品超碰一区二区三区 | 99视频在线观看一区三区 | 国产丝袜制服在线 | 亚洲精品美女在线观看播放 | 天天婷婷| 国产裸体视频网站 | 国内精品久久久久影院一蜜桃 | 久久天天操 | 日韩在线网 | 色99中文字幕 | 欧美一级日韩免费不卡 | 久久精品久久99精品久久 | 国产a网站 | 日韩三级久久 | 国产香蕉久久精品综合网 | 伊人亚洲综合网 | 国产精成人品免费观看 | 毛片视频电影 | 亚洲高清在线观看视频 | 91.麻豆视频 | 91av免费在线观看 | 亚洲视频h | 天天综合网 天天 | 久草电影网 | 日本成人中文字幕在线观看 | 天堂麻豆 | 国产精品欧美久久久久三级 | 日韩精品免费一区二区三区 | 久久成电影 | 六月婷婷网 | 毛片永久免费 | 久久99热精品 | 在线小视频你懂得 | 久艹在线播放 | 国产精品视频免费观看 | 丁香色综合 | 国产精品11 | 国产精品一区二区电影 | 天天色欧美 | 亚洲欧美国产精品va在线观看 | 成人h动漫精品一区二 | 人人澡人人添人人爽一区二区 | 99一区二区三区 | 欧美性生活免费 | 日韩一区二区免费在线观看 | 一区二区三区中文字幕在线观看 | 国产一区视频在线 | av一区二区三区在线观看 | 国产在线a视频 | 亚洲一区二区三区四区精品 | 狠狠综合久久 | 国产精品视频免费观看 | 在线视频欧美精品 | 在线视频日韩欧美 | 久久国产精品区 | 国产白浆视频 | 日韩欧美精品在线视频 | 中文字幕av日韩 | 成片免费观看视频999 | 国产一级不卡视频 | 一区二区三区在线影院 | 日韩激情在线 | 久久精品5| 中文字幕在线观看第一页 | 欧美婷婷色 | 91亚洲精 | 国产免费av一区二区三区 | 欧美性另类 | 国产一区视频在线观看免费 | 精品国产一区二区三区在线观看 | 国产精品激情 | 久久免费资源 | 国产精品欧美日韩在线观看 | 亚洲另类交 | 欧美日韩不卡在线观看 | 免费视频 三区 | 日韩欧美在线观看一区 | 日本夜夜草视频网站 | 亚洲精品乱码久久久久久蜜桃动漫 | 精品福利在线视频 | 欧美激情视频在线免费观看 | 麻豆视频免费网站 | 亚洲精品系列 | 天天操夜夜叫 | www.福利视频 | 中文视频在线播放 | 国产免费二区 | 日本丶国产丶欧美色综合 | 色婷婷色 | 日本在线观看一区二区 | 欧美日韩不卡一区二区 | 色狠狠婷婷 | 久香蕉 | 国产精品久久嫩一区二区免费 | www.一区二区三区 | 国产资源网站 | 深爱激情婷婷网 | 97超视频免费观看 | 国产在线观看一 | 日韩网站在线 | 三级在线国产 | 91人人澡 | 国产精品成人a免费观看 | 99久久国产免费免费 | 久草www| 欧美色操 | 五月天激情综合 | 黄色软件在线观看 | 久久国产精品小视频 | 日本成人黄色片 | 欧美精品免费在线 | 亚洲 av网站 | 国产一区二区三区高清播放 | 网站在线观看日韩 | 国产做aⅴ在线视频播放 | 丁香资源影视免费观看 | 中文字幕在线视频一区二区三区 | 国产精品久久在线观看 | 最新真实国产在线视频 | 黄色资源网站 | 亚洲自拍偷拍色图 | 992tv在线观看网站 | 在线免费观看视频一区二区三区 | 免费国产在线精品 | 四虎影视成人精品 | 欧美一级片免费在线观看 | 亚洲日本在线视频观看 | 久久精品亚洲精品国产欧美 | 69国产精品成人在线播放 | 免费观看一级成人毛片 | 99热免费在线 | 欧美日韩免费一区二区三区 | 天天干天天玩天天操 | 国产一级淫片在线观看 | 久久久久免费精品 | 蜜臀久久99精品久久久酒店新书 | 亚洲精品一区二区在线观看 | 久久久久免费精品视频 | 国产自制av| 亚洲国产精品久久久久婷婷884 | www.一区二区三区 | 国产视频高清 | 久久国产系列 | 日韩欧美精品一区 | 2021国产精品| 91久久黄色| 热久久免费国产视频 | 91亚洲精品国偷拍自产在线观看 | 日日操天天射 | 久久伊人八月婷婷综合激情 | 国产精品青青 | 日韩av中文在线观看 | 国产录像在线观看 | 女人高潮特级毛片 | 深爱五月激情网 | av免费网站观看 | 亚洲国产电影在线观看 | 黄色小说视频网站 | 色五月色开心色婷婷色丁香 | 国产高清不卡一区二区三区 | 精品国产乱码久久久久久天美 | 久久草在线免费 | 开心色激情网 | 久久官网 | 中文字幕免费国产精品 | 成人sm另类专区 | 国产精品精品久久久久久 | 久久综合狠狠狠色97 | 国产精品自在欧美一区 | 国产精品99久久久精品 | 欧美一区二区三区激情视频 | 97超碰人人澡人人爱学生 | 中文字幕av最新更新 | 欧美午夜理伦三级在线观看 | 国产亚洲精品久久久久久大师 | 国产精品va在线观看入 | 99视频国产在线 | 天堂在线视频中文网 | 亚洲午夜精品电影 | 91pony九色丨交换 | 成人午夜免费剧场 | 久久视频精品在线观看 | 中文字幕视频三区 | 色综合天天色综合 | 久久免费a | 人人舔人人干 | 青青草在久久免费久久免费 | 蜜臀av网站| av播放在线 | 精品视频专区 | 91在线精品观看 | 日日夜夜婷婷 | 超碰97中文 | 精品1区二区 | 免费在线91 | av一区二区在线观看中文字幕 | 99热99re6国产在线播放 | 91一区一区三区 | 久久久国产精品久久久 | 国产午夜一级毛片 | 国产黄色精品在线 | 国产精品女主播一区二区三区 | 免费看特级毛片 | 99久久99久久精品国产片果冰 | 国产精品久久久久久久久免费看 | 婷婷在线免费 | 欧美精品久久久久久 | 免费能看的av | 黄网站www | 国产1级视频 | 国产精品久久99综合免费观看尤物 | 91完整版| 99视频国产精品 | 日本99久久| 91porny九色在线播放 | 91爱爱网址 | 91精品天码美女少妇 | 国产麻豆精品95视频 | 中文字幕永久免费 | 天天操天天爱天天干 | 亚洲aaa级| av在线激情 | 国产精品一区二区果冻传媒 | 日韩av不卡在线播放 | 韩国精品在线 | 最新超碰| 99看视频在线观看 | 日日夜夜噜噜噜 | 国产精品99久久久精品免费观看 | 日韩| 中文字幕免费高清av | 久精品视频在线观看 | 天躁狠狠躁 | 久精品视频在线观看 | 色吧av色av | 91成人短视频在线观看 | www黄色com| 欧美性色19p | 亚洲精品视频免费在线 | 在线视频麻豆 | 97精品国产97久久久久久粉红 | 亚洲精品xxxx | 色婷婷久久一区二区 | 美女精品网站 | 日韩欧美在线中文字幕 | 国产免费片 | 中文不卡视频在线 | 久久亚洲影视 | 天天天干天天天操 | www.com在线观看| 永久免费观看视频 | 国产视频每日更新 | 精品中文字幕在线播放 | 在线电影日韩 | 中文字幕日韩av | 在线观看黄a | 久久99久久99免费视频 | 视频在线观看一区 | 久热电影 | 最近免费中文字幕大全高清10 | 91视频黄色 | 日韩在线电影一区二区 | 狠狠操狠狠干天天操 | 中文字幕第一页在线播放 | 亚洲色图27p | 亚洲国产美女久久久久 | 精品久久久久久综合 | 国产无吗一区二区三区在线欢 | 欧美一级性生活片 | 麻豆传媒视频在线播放 | 色悠悠久久综合 | 国产免码va在线观看免费 | 久久久蜜桃 | 国产精品免费在线视频 | 亚洲91网站 | 国产资源中文字幕 | 麻豆免费观看视频 | 99视频这里只有 | 亚洲精品国产日韩 | 久久99国产精品 | av网站在线免费观看 | 日韩av在线高清 | 人人射人人爱 | 91精品区| 在线观看成人福利 | 国产在线播放一区二区 | 色九九视频 | 久久精品国亚洲 | 免费看三片 | 四虎在线免费观看 | 久久久久综合精品福利啪啪 | 亚洲国产精品一区二区久久hs | 亚洲国产精品久久久久久 | 国产香蕉在线 | 国产精品高清av | 婷婷六月激情 | 99热九九这里只有精品10 | 久久99精品国产麻豆宅宅 | 亚洲精品在线观看av | 黄a网站 | 国产精品av一区二区 | 久碰视频在线观看 | 日本精品一区二区 | www.一区二区三区 | 中文字幕在线观看免费高清完整版 | 日日操日日插 | 色综合天天综合 | 免费看日韩 | 日韩精品免费在线 | 又黄又爽又湿又无遮挡的在线视频 | 国内成人av | 91在线日韩| 久久久久久草 | 在线免费观看黄网站 | 国产午夜精品一区二区三区欧美 | 91av在线视频播放 | 99色在线播放 | 最近2019年日本中文免费字幕 | 久久精品视频网 | 亚洲精品久久久久999中文字幕 | 欧美激情综合色综合啪啪五月 | 四虎在线免费观看 | 免费91麻豆精品国产自产在线观看 | 精品一二三区 | 黄色网址国产 | 久久久综合精品 | 日韩免费成人av | 国产一二区精品 | 人人模人人爽 | 日韩三级中文字幕 | 91麻豆精品一区二区三区 | 欧美韩国日本在线观看 | www.亚洲黄色 | 亚洲美女视频网 | 日韩精品中文字幕在线 | 日本天天色| 国产999精品久久久久久 | 男女男视频| 欧美狠狠色 | 欧美地下肉体性派对 | 国产精选在线 | 色婷婷激情网 | 免费福利在线视频 | 国内精品久久久久影院日本资源 | 亚洲精品国偷拍自产在线观看 | 日韩欧美黄色网址 | 中文字幕在线看视频国产中文版 | 亚洲精品一区二区网址 | 免费看av片网站 | 青青久视频 | 日本最新高清不卡中文字幕 | 91精品国产福利 | 青青久草在线 | 欧美在线一二 | 午夜影院在线观看18 | 国产69久久 | 九色激情网 | 国内精品久久久久影院男同志 | 99久久成人 | 国产精品永久久久久久久久久 | 国产视频在线免费 | 国产免费a | 久久久久久久久久久福利 | 精品一区精品二区高清 | www免费| 成人在线视频你懂的 | 国产精品免费视频久久久 | 黄色99视频 | 欧美日韩精品免费观看 | 久久电影网站中文字幕 | 免费在线电影网址大全 | 亚洲精品9 | 最新av中文字幕 | 超碰电影在线观看 | 免费a网| 日韩精品一区二区三区在线播放 | 国产自产在线视频 | 日日操天天爽 | 中文字幕乱码电影 | 久久黄色网址 | 中文字幕在线观看免费高清电影 | 在线观看免费日韩 | 在线观看亚洲精品 | 久久国产精品一二三区 | 九九免费在线看完整版 | 天天夜夜操 | 午夜狠狠干| 欧洲精品码一区二区三区免费看 | 国产剧情一区二区在线观看 | 成人午夜性影院 | 亚洲午夜久久久久久久久 | 亚洲精品99久久久久中文字幕 | 精品二区视频 | 免费a v在线| 亚洲综合网站在线观看 | 九色视频网 | 四虎永久免费在线观看 | 色多多视频在线观看 | 少妇精69xxtheporn| 午夜私人影院久久久久 | a v在线观看 | 波多野结衣一区二区三区中文字幕 | 国产精品国产三级国产 | 国产日韩欧美在线播放 | 少妇av网 | 在线免费91| 久久久香蕉视频 | 亚洲码国产日韩欧美高潮在线播放 | 久久观看免费视频 | 草莓视频在线观看免费观看 | av高清不卡 | 成人91在线 | 97av色| 精品久久久久一区二区国产 | 在线观看成人小视频 | 91看片淫黄大片一级在线观看 | 91精品爽啪蜜夜国产在线播放 | 国产高清成人av | 91手机视频在线 | 久久久久国产精品一区二区 | 日韩视频一区二区在线 | 91看片在线免费观看 | 午夜精品婷婷 | 在线 你懂| 久久九九影视 | www.久久久精品 | 免费观看一区二区三区视频 | 免费观看一区二区三区视频 | 韩国一区二区在线观看 | 亚洲九九九在线观看 | 精品久久久久一区二区国产 | 久久久久久久久久免费视频 | 婷婷在线网站 | 日韩有码第一页 | 国产亚洲永久域名 | 日韩精品免费一区 | 久久婷婷一区二区三区 | 久久久网页 | 欧美另类高潮 | 精品国产乱码久久久久久三级人 | 视频直播国产精品 | 久久免费观看视频 | 国产精品手机在线播放 | 午夜精品婷婷 | 国产精品免费视频久久久 | 日韩综合一区二区 | 国产明星视频三级a三级点| 国产精品久久久久久久久搜平片 | 99热精品免费观看 | 久久久久婷| 四虎影视av | www夜夜操| 国产精品免费在线播放 | 久久综合狠狠综合久久激情 | 久久久91精品国产一区二区精品 | 久久人人爽人人爽人人片 | 一本大道久久精品懂色aⅴ 五月婷社区 | 天天爱av导航 | 久久草精品 | 国产精品久久电影网 | 久久99久久久久 | 91亚洲精| 日韩欧美电影在线 | 亚洲影院一区 | 97视频在线观看播放 | 日韩有码中文字幕在线 | 丁香在线观看完整电影视频 | 2023av| 成人av一区二区在线观看 | 香蕉视频网址 | 久久久黄视频 | 一区二区三区视频 | 在线中文字幕观看 | 精品久久久久一区二区国产 | 91精品视频在线观看免费 | 99久久精品网 | 精品影院一区二区久久久 | 欧美国产高清 | 97超碰人 | 99热播精品| 久久av网| 国产精品福利在线播放 | 日韩在线观看第一页 | 日韩欧美精品一区二区三区经典 | 久久区二区| 日女人电影| av动态图片 | 久久国产精品久久国产精品 | 久久综合给合久久狠狠色 | 夜夜躁狠狠燥 | 91人人爽久久涩噜噜噜 | 久久最新视频 | 色视频在线免费 | 亚洲日本一区二区在线 | 亚洲国产精品999 | www日韩在线观看 | 丰满少妇麻豆av | 久草影视在线观看 | 日韩视频一区二区三区在线播放免费观看 | 国产成人一区三区 | 亚洲精品国产综合99久久夜夜嗨 | 激情网在线视频 | 国产精品午夜在线 | 国产手机在线精品 | 特黄特色特刺激视频免费播放 | 欧美一二区在线 | 伊人激情综合 | 国产精品伦一区二区三区视频 | 欧美成人h版 | 黄色片免费在线 | 天天干,天天操,天天射 | 日韩精品免费专区 | 成人免费在线观看入口 | 日日碰狠狠添天天爽超碰97久久 | 国产在线不卡一区 | 四虎在线影视 | 久久久久久久久黄色 | 欧美一级片在线 | 国产成人久久久77777 | 91精品视频网站 | 国产精品黑丝在线观看 | 精品伦理一区二区三区 | 日韩一区二区三区高清免费看看 | av在线之家电影网站 | 在线免费黄色av | 一区二区中文字幕在线 | 日本99干网 | 成人黄在线 | 日韩 在线观看 | 日本夜夜草视频网站 | 久久视频在线观看 | 久久免费黄色网址 | 青青河边草免费观看完整版高清 | 最近2019好看的中文字幕免费 | 成人小视频在线 | 麻豆精品视频在线观看免费 | 在线观看视频91 | 天天干天天操天天搞 | 九色视频网 | 在线观看色网站 | av高清一区二区三区 | 91视频下载 | 一区二区三区四区不卡 | 狂野欧美激情性xxxx | 亚洲视频免费在线观看 | 国产色一区 | 免费国产亚洲视频 | 免费日韩电影 | 人人揉人人揉人人揉人人揉97 | 午夜精品福利影院 | 99色在线播放 | 免费a视频 | 顶级bbw搡bbbb搡bbbb | 国产美女主播精品一区二区三区 | 日韩欧美大片免费观看 | 国产无遮挡又黄又爽在线观看 | 欧美性成人| 久久99热国产| 成人手机在线视频 | 综合婷婷 | 久久99久久久久久 | 亚洲成人xxx | 国产无遮挡又黄又爽在线观看 | 久精品在线| 很黄很黄的网站免费的 | 国产精品成人自产拍在线观看 | 349k.cc看片app | 99在线热播精品免费 | 国产一区二区三区高清播放 | 精品一区在线 | 天天色天天综合网 | 久久伊人婷婷 | 91成人在线观看高潮 | 日韩久久精品一区二区 | 午夜在线观看一区 | 91桃色免费视频 | 亚洲天堂视频在线 | 综合成人在线 | 在线免费中文字幕 | 国产一区二区在线影院 | 美女久久久久久久 | 欧美天堂久久 | 免费看精品久久片 | 日本黄色免费在线 | 久热这里有精品 | 人人澡人人舔 | 最近中文字幕第一页 | 亚洲v欧美v国产v在线观看 | 亚洲精品综合久久 | 国内成人精品视频 | 亚洲综合在线观看视频 | 狠狠色综合网站久久久久久久 | 最新午夜 | 日韩成人xxxx| 欧美中文字幕久久 | 在线免费中文字幕 | 蜜臀一区二区三区精品免费视频 | 日韩欧美视频在线观看免费 | 国产传媒一区在线 | 正在播放五月婷婷狠狠干 | 色多多在线观看 | 国语精品免费视频 | 国产91国语对白在线 | 狠狠狠狠狠狠干 | 欧美日韩电影在线播放 | 一区二区精品视频 | 在线视频1卡二卡三卡 | 久久精品久久精品 | 国产不卡在线观看视频 | 亚洲一级黄色片 | 9999免费视频 | 一区二区三区四区免费视频 | 欧美日韩国产一区二区三区 | 天天操天天弄 | 免费在线成人av电影 | 看黄色91 | 一区二区精 | 97在线观看免费高清完整版在线观看 | 成人黄色电影在线播放 | 日韩亚洲在线视频 | 精品久久91 | 亚洲理论影院 | 色网站在线看 | 欧美精品v国产精品v日韩精品 | av在线免费播放 | 99精品国自产在线 | 黄色网在线免费观看 | 成人在线免费视频 | 在线观看91精品国产网站 | 韩国三级在线一区 | 国语自产偷拍精品视频偷 | 久久精品麻豆 | 国产免费三级在线观看 | 日日夜夜人人天天 | 免费看国产曰批40分钟 | 中文字幕在线观看完整版电影 | 人人干在线 | 国产区在线 | 久久精品久久久久电影 | 欧美激情va永久在线播放 | 国产一区免费在线观看 | 在线一区二区三区 | 国产婷婷一区二区 | 超碰在线9 | 色综合久久悠悠 | 日韩视频一区二区三区在线播放免费观看 | 国产精品亚州 | 国产福利精品一区二区 | 国产中的精品av小宝探花 | 日本精品久久久久久 | 国产精品免费在线观看视频 | 国产区欧美| 97超碰影视 | www色| 成人av在线一区二区 | 欧美日韩不卡一区二区三区 | 国产亚洲综合性久久久影院 | 偷拍精品一区二区三区 | 成人免费大片黄在线播放 | 777视频在线观看 | 亚洲黄色在线 | 99九九99九九九视频精品 | 亚洲理论片 | 日韩欧美视频在线播放 | 久久极品 | 丁香久久激情 | 中文字幕超清在线免费 | 黄色特级片 | 国产成人精品一区二区三区 | 国内少妇自拍视频一区 | 午夜精选视频 | 天天爽综合网 | a视频在线观看免费 | 91视频亚洲 | 免费一级特黄录像 | 五月天天av | 亚洲国产欧美在线人成大黄瓜 | 91成人免费电影 | 国产亚洲综合性久久久影院 | 国产美女黄网站免费 | 综合网成人 | 蜜臀久久99精品久久久酒店新书 | 国产97超碰| 国产一区 在线播放 | 久章草在线观看 | 国内丰满少妇猛烈精品播放 | 日韩国产精品久久久久久亚洲 | 精品国产99国产精品 | 综合成人在线 | 精品夜夜嗨av一区二区三区 | 中文字幕中文字幕在线一区 | 在线看一级片 | 亚洲激情综合 | 最近中文字幕mv | 九九热在线视频免费观看 | 中文字幕在线看视频国产 | 精品91视频| 开心激情婷婷 | 激情视频二区 | 91麻豆精品国产91久久久久久 | 亚洲精品小视频在线观看 | 国产精品久久久久久麻豆一区 | 91丨porny丨九色 | 天天摸天天操天天爽 | 午夜久久久久久久久 | 韩国精品视频在线观看 | 99视屏 | 国产午夜三级一二三区 | 一级免费看视频 | 天天射,天天干 | 欧美日韩裸体免费视频 | 欧美日韩一区二区在线观看 | 少妇av片| 二区三区在线视频 | 久久综合电影 | 国产xx在线| 精品国产欧美一区二区 | 国产高清视频在线播放一区 | 成年人三级网站 | 色午夜 | 人人看人人做人人澡 | 精品特级毛片 | 色婷婷九月 | 日本在线观看中文字幕无线观看 | 在线精品观看 | 国产精品永久免费在线 | 久久精品福利视频 | 韩日三级av| www黄在线 | 国产精品麻豆91 | 超碰个人在线 | 国产日韩欧美在线播放 | 亚洲成人第一区 | 国产免费三级在线观看 | 国产福利小视频在线 | av电影免费在线看 | 国产精品毛片一区视频播 | 欧美精品二区 | 免费日韩电影 | 久久亚洲影院 | 射射射综合网 | 最近中文字幕免费观看 | 久草久草在线 | 少妇bbw撒尿 | 六月丁香六月婷婷 | 国产日本亚洲高清 | 精品一二三区 | 国产精品综合久久久 | 国产精品理论在线观看 | 国产精品九九视频 | 五月综合网站 | 国产精品自产拍在线观看中文 | 国产精品日韩在线观看 | 日韩专区在线 | 色姑娘综合网 | av成人免费在线 | 日韩免费观看一区二区 | 国产女v资源在线观看 | 日韩免费在线播放 | av高清在线观看 | 亚洲3级| 99久久精品久久久久久清纯 | 99在线观看视频网站 | 免费国产一区二区 | 91麻豆视频| 久久艹在线 | 日本黄色大片免费 | 亚洲在线看 | 免费亚洲黄色 | 久久久久免费精品国产小说色大师 | 久久久免费精品视频 | 久久国产91 | 国产小视频福利在线 | 91精品视频导航 | 国产黄色免费在线观看 | 日韩欧美一区二区三区视频 | 超碰97在线看 | 伊人狠狠干 | 欧美一区免费在线观看 | 日韩精品一区二区在线视频 | 中文字幕av影院 | 亚洲精品国偷自产在线91正片 | 天天天综合 | 亚洲精品乱码久久久久久 | 99精品系列 | 91天天视频| 91人人揉日日捏人人看 | 婷婷色网址 | 国产剧情在线一区 | 日韩av高潮| 色99色| 九九在线国产视频 | 国产日韩三级 | 欧美日韩中文字幕在线视频 | www九九热| 日韩精品视频在线观看免费 | 欧美片一区二区三区 | 国产不卡精品 | 国产一区二区在线播放 | 中文资源在线官网 | 在线欧美日韩 | 亚洲在线视频网站 | 亚洲另类视频在线 | 奇米影视四色8888 | 免费观看黄 | 麻豆视频网址 | 色www免费视频 | 二区在线播放 | 91大神精品视频在线观看 | bbw av | 国产一区二区在线视频观看 | 99久久久国产免费 | 久久久久免费网 | 91在线九色| 中文字幕av最新 | 日韩理论在线播放 | 麻豆免费看片 | 69国产精品成人在线播放 | 亚洲成人黄色av | 特级a毛片 | 日韩免费福利 | av片在线看 | 成人中文字幕av | 美女网站视频色 | 成人av电影在线观看 | 香蕉视频在线网站 | 婷婷丁香七月 | 国色天香永久免费 | 韩国三级在线一区 | 69国产成人综合久久精品欧美 | 99久久激情视频 | 天天干夜夜夜操天 | 亚洲成人一二三 | 久草91视频 | 青青啪 | 国产小视频在线观看 | 黄色国产精品 | 免费黄色av. | 精选久久| 欧美久久精品 | 97超级碰碰碰视频在线观看 | 欧美一区日韩精品 | 亚洲精品国产精品久久99 | 成人a免费| 欧美综合在线观看 | 亚洲综合国产精品 | 久久视频精品 | 日操操 | 黄色成人在线 | 69视频在线播放 | 五月亚洲综合 | 国内免费的中文字幕 | 中文字幕视频播放 | 91亚洲精品久久久久图片蜜桃 | 国产黄色免费在线观看 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 国产精品入口传媒 | 亚洲涩涩一区 | 亚洲区色 | 色婷婷激情电影 | 精品久久网 | 激情网站| 欧美日韩亚洲第一页 | 中文字幕久久精品亚洲乱码 | 国产一级在线免费观看 | 日韩激情视频在线 | 日韩在线观看视频中文字幕 | 久草在线免费电影 | 少妇bbw揉bbb欧美 | 最近免费中文字幕大全高清10 | 国产成人av一区二区三区在线观看 | 欧美成人中文字幕 | 国产免费一区二区三区最新6 | 国产五月 | 在线亚洲成人 | 蜜臀av网站| 久精品在线观看 | 亚洲精品小区久久久久久 | 久久丝袜视频 | 国产欧美日韩精品一区二区免费 | 天天久久综合 | 国产91精品在线观看 | 亚州天堂 | 99国产精品久久久久久久久久 | 国产精品久久久精品 | 99久久久国产精品免费99 | 久青草视频在线观看 | 亚洲午夜不卡 | 亚洲网久久| 久久精品亚洲 | 午夜久久久久久久久久久 | 亚洲影院色 | 久久精品国产免费 | 国产精品久久久一区二区三区网站 | 最近日本字幕mv免费观看在线 | www.夜夜骑.com | 六月天综合网 | 91在线中文字幕 | 亚洲精品88欧美一区二区 | 波多野结衣久久资源 | 韩国精品福利一区二区三区 | 国产在线视频资源 | 久久久精品一区二区 | 99热只有精品在线观看 | 久久久久久久久久久久av | 国产精品久久久一区二区三区网站 | 日日日操操 | 青青河边草观看完整版高清 | 狠狠插狠狠干 | 免费看一级特黄a大片 | 国内视频在线 | 久久久久久久久毛片精品 | 91精品久久久久久综合五月天 | 亚洲3级 | 日韩手机在线观看 | 精品免费一区 | 2019天天干天天色 | 麻豆国产视频 | 97超碰人人澡人人 | 国产精品一区二区三区免费视频 | 久久视频网址 | 在线精品视频免费播放 | 西西444www| 香蕉影视app | 黄污视频网站大全 | 成年人免费看片 | 人人爽夜夜爽 | 日韩有码网站 | 欧美一二三区在线观看 | 国产精品色视频 | 99欧美 | 中文字幕二区在线观看 | 337p日本大胆噜噜噜噜 | 中文成人字幕 | 国产精品成人一区二区 | 国产一区二区三区免费视频 | 亚洲成人动漫在线观看 | 中文在线| 国产精品资源在线 | 国产精品成人自产拍在线观看 | 日韩一二区在线观看 | 亚洲专区 国产精品 | 黄色免费观看视频 | 亚洲激情 欧美激情 | 狠狠干干| 久热免费在线 | 一区精品在线 | 狠狠的日日 | 欧美久久99 | 激情综合网五月婷婷 | www.亚洲黄| 久久久精品福利视频 | 色多视频在线观看 | 久久一区二区三区国产精品 | 国产精品一区二区视频 | 国产午夜精品一区二区三区欧美 | 久久久久久久国产精品影院 | 久久精品女人毛片国产 | 一区二区成人国产精品 | 国语精品久久 | 国产伦精品一区二区三区无广告 | 99色在线观看视频 | 日韩精品免费一线在线观看 |