??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久久毛片免费播放,精品蜜臀久久久久99网站,久久久久久无码Av成人影院http://www.shnenglu.com/aaxron/category/18045.html记录修行的印? zh-cnMon, 24 Mar 2014 19:29:34 GMTMon, 24 Mar 2014 19:29:34 GMT60韦根驱动http://www.shnenglu.com/aaxron/archive/2014/03/21/206265.html天下天下Fri, 21 Mar 2014 09:33:00 GMThttp://www.shnenglu.com/aaxron/archive/2014/03/21/206265.htmlhttp://www.shnenglu.com/aaxron/comments/206265.htmlhttp://www.shnenglu.com/aaxron/archive/2014/03/21/206265.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/206265.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/206265.html#include <linux/types.h>
#include 
<linux/module.h>
#include 
<linux/init.h>
#include 
<linux/poll.h>
#include 
<linux/errno.h>
#include 
<linux/gpio.h>
#include 
<linux/interrupt.h>
#include 
<linux/miscdevice.h>
#include 
<linux/ioport.h>
#include 
<linux/device.h>
#include 
<asm/io.h>
#include 
<asm/irq.h>
#include 
<mach/irqs.h>
#include 
<mach/regs-gpio.h>

#include 
"../ioctl_new.h"

static spinlock_t    wiegand_lock;
static int            wiegand_in = 0;
static int            wiegand_in_cur = 0;
static int            wiegand_in_stime = 0;
static int            wiegand_in1_stime = 0;
static int            wiegand_in2_stime = 0;
static unsigned char wiegand_data[40];
static WIEGAND_TYPE    wiegand_mode;

inline 
void wiegand_delay(int microseconds)
{
    
int i;
    
while (microseconds--)
    {
        
for (i=0; i<65; i++) __asm("NOP");
    }
}

static int wiegand_gettickcount(void)
{
    
static int __start_time = 0//second
    struct timeval tv;

    do_gettimeofday(
&tv);

    
if (__start_time == 0)
        __start_time 
= tv.tv_sec;

    
return ((tv.tv_sec - __start_time) * 1000 + tv.tv_usec / 1000);
}

inline 
void wiegand_minus_interrupt(void)
{
    
if (wiegand_in != WGNSTAT_RECVFULL)
    {
        
if (wiegand_gettickcount() - wiegand_in_stime >= 100)
            wiegand_in_cur 
= 0;
        wiegand_in_stime 
= wiegand_gettickcount();
        wiegand_data[wiegand_in_cur
++= 0;
        
if (wiegand_in_cur >= 34)
            wiegand_in 
= WGNSTAT_RECVFULL;
        
else if (wiegand_in_cur >= 26)
            wiegand_in 
= WGNSTAT_RECV26;
    }
}

inline 
void wiegand_plus_interrupt(void)
{
    
if (wiegand_in != WGNSTAT_RECVFULL)
    {
        
if (wiegand_gettickcount() - wiegand_in_stime >= 100)
            wiegand_in_cur 
= 0;
        wiegand_in_stime 
= wiegand_gettickcount();
        wiegand_data[wiegand_in_cur
++= 1;
        
if (wiegand_in_cur >= 34)
            wiegand_in 
= WGNSTAT_RECVFULL;
        
else if (wiegand_in_cur >= 26)
            wiegand_in 
= WGNSTAT_RECV26;
    }
}

static irqreturn_t wiegand_minus1_interrupt(int irq, void *dev_id)
{
    spin_lock(
&wiegand_lock);
//    printk("wiegand_minus1_interrupt\n");
    if (wiegand_gettickcount() - wiegand_in2_stime > 200)
    {
        wiegand_minus_interrupt();
        wiegand_in1_stime 
= wiegand_in_stime;
    }
    spin_unlock(
&wiegand_lock);
    
return IRQ_HANDLED;
}

static irqreturn_t wiegand_plus1_interrupt(int irq, void *dev_id)
{
    spin_lock(
&wiegand_lock);
//    printk("wiegand_plus1_interrupt\n");
    if (wiegand_gettickcount() - wiegand_in2_stime > 200)
    {
        wiegand_plus_interrupt();
        wiegand_in1_stime 
= wiegand_in_stime;
    }
    spin_unlock(
&wiegand_lock);
    
return IRQ_HANDLED;
}


static int wiegand_open(struct inode * inode, struct file * filp);
static int wiegand_release(struct inode * inode,struct file * filp);
static ssize_t wiegand_read(struct file *flip, char *buf, size_t len, loff_t *pos);
static ssize_t wiegand_write(struct file *flip, const char *buf, size_t len, loff_t *pos);
static long wiegand_ioctl(struct file *file, unsigned int cmd, unsigned long arg);

static struct file_operations wiegand_fops = {
    owner:        THIS_MODULE,
    open:        wiegand_open,
    release:    wiegand_release,
    read:        wiegand_read,
    write:        wiegand_write,
    unlocked_ioctl:        wiegand_ioctl,
};

static struct miscdevice wiegand_dev = {
    WIEGAND_MINOR,
    WIEGAND_MODULE_NAME,
    
&wiegand_fops
};

static void config_wiegand_pins(void)
{
    s3c2410_gpio_cfgpin(WGNIN_0, WGNIN_0_CON);
    s3c2410_gpio_cfgpin(WGNIN_1, WGNIN_1_CON);
    s3c2410_gpio_cfgpin(WGNOUT0, WGNOUT0_CON);
    s3c2410_gpio_cfgpin(WGNOUT1, WGNOUT1_CON);
#if 0
    
if (request_irq(WGNIN_0_IRQ_NUM, &wiegand_minus1_interrupt, 
        IORESOURCE_IRQ 
| IRQF_TRIGGER_RISING, 
        WIEGAND_IRQ_MINUS, 
        
&wiegand_dev)         
        
|| request_irq(WGNIN_1_IRQ_NUM, &wiegand_plus1_interrupt,  
        IORESOURCE_IRQ 
| IRQF_TRIGGER_RISING, 
        WIEGAND_IRQ_PLUS, 
        
&wiegand_dev))
        
    {
        printk(
"WIEGAND request_irq Fail\n");
    }
#endif
}

static int wiegand_open(struct inode * inode, struct file * filp)
{
    config_wiegand_pins();
    
return 0;
}

static int wiegand_release(struct inode * inode,struct file * filp)
{
#if 0
    free_irq(WGNIN_0_IRQ_NUM, 
&wiegand_dev);
    free_irq(WGNIN_1_IRQ_NUM, 
&wiegand_dev);
#endif
    
return 0;
}

static ssize_t wiegand_read(struct file *flip, char *buf, size_t len, loff_t *pos)
{
    
int result;
    spin_lock(
&wiegand_lock);
    
if (wiegand_in == WGNSTAT_NONE || len > sizeof(wiegand_data) || (wiegand_gettickcount() - wiegand_in_stime > 1800))        //500
    {
        wiegand_in 
= WGNSTAT_NONE;
        spin_unlock(
&wiegand_lock);
        
return 0;
    }
    
if (len > wiegand_in_cur)
        len 
= wiegand_in_cur;
    result 
= copy_to_user(buf, wiegand_data, len);
    wiegand_in 
= WGNSTAT_NONE;
    wiegand_in_cur 
= 0;
    spin_unlock(
&wiegand_lock);
    
return len;
}

static ssize_t wiegand_write(struct file *flip, const char *buf, size_t len, loff_t *pos)
{
    
int i;
    
char data[40];

    
if (len > sizeof(data))
        
return 0;

    i 
= copy_from_user(data, buf, len);
    
for (i=0; i<len; i++)
    {
        
if (data[i] == 0)
        {
            WGNOUT0_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT0_0;
        }
        
else
        {
            WGNOUT1_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT1_0;
        }
        wiegand_delay(wiegand_mode.dwTpi);
    }

    
return len;
}

static long wiegand_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    
int result = 0;
    spin_lock(
&wiegand_lock);
    
switch(cmd)
    {
    
case WIEGAND_MODE_SET:
        result 
= copy_from_user(&wiegand_mode, (void*)arg, sizeof(WIEGAND_TYPE));
        
break;
    }
    spin_unlock(
&wiegand_lock);
    
return (result == sizeof(WIEGAND_TYPE) ? 0 : -1);
}



static int __init s3c2416_wiegand_init(void)
{
    
int ret = 0;
    
    ret 
= misc_register(&wiegand_dev);
    
if (ret)
    {
        printk(
"probuck s3c2416 WIEGAND Driver" WIEGAND_DRIVER_VERSION "Fail\n");
        
goto exit_sb3kt_wiegand_init;
    }
    spin_lock_init(
&wiegand_lock);

    printk(
"probuck s3c2416 WIEGAND Driver" WIEGAND_DRIVER_VERSION "\n");
    
exit_sb3kt_wiegand_init:
    
return ret;
}

static void __exit s3c2416_wiegand_cleanup(void)
{
    misc_deregister(
&wiegand_dev);
}

module_init(s3c2416_wiegand_init);
module_exit(s3c2416_wiegand_cleanup);
MODULE_LICENSE(
"GPL");

MODULE_DESCRIPTION(
"s3c2416 WIEGAND Driver");
MODULE_SUPPORTED_DEVICE(
"s3c2416 WIEGAND");



天下 2014-03-21 17:33 发表评论
]]>
Linux内核的同步机?2)信号量(semaphoreQ?/title><link>http://www.shnenglu.com/aaxron/archive/2013/04/12/199387.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Fri, 12 Apr 2013 10:22:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2013/04/12/199387.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/199387.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2013/04/12/199387.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/199387.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/199387.html</trackback:ping><description><![CDATA[<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->Linux内核的同步机?2)信号量(semaphoreQ?br /><br />  信号量在创徏旉要设|一个初始|表示同时可以有几个Q务可以访问该信号量保护的׃n资源Q初始gؓ1变成互斥锁QMutexQ,卛_时只能有一个Q务可以访问信号量保护的共享资源?br /><br />  一个Q务要惌问共享资源,首先必须得到信号量,获取信号量的操作把信号量的值减1Q若当前信号量的gؓ负数Q表明无法获得信号量Q该d必须挂v在该信号量的{待队列{待该信号量可用Q若当前信号量的gؓ非负敎ͼ表示可以获得信号量,因而可以立刻访问被该信号量保护的共享资源?br /><br />  当Q务访问完被信号量保护的共享资源后Q必释放信号量Q释放信号量通过把信号量的值加1实现Q如果信号量的gؓ非正敎ͼ表明有Q务等待当前信号量Q因此它也唤醒所有等待该信号量的d?br /><br />信号量的API有:<br />DECLARE_MUTEX(name)<br />该宏声明一个信号量nameq初始化它的gؓ1Q即声明一个互斥锁?br /><br /><span style="color: #008000; ">//</span><span style="color: #008000; ">在Linux2.6.26中没扑ֈ该宏</span><span style="color: #008000; "><br /></span>DECLARE_MUTEX_LOCKED(name)<br />该宏声明一个互斥锁nameQ但把它的初始D|ؓ0Q即锁在创徏时就处在已锁状态。因此对于这U锁Q一般是先释攑֐获得?br /><br /><span style="color: #0000FF; ">void</span> sema_init (<span style="color: #0000FF; ">struct</span> semaphore *sem, <span style="color: #0000FF; ">int</span> val);<br />该函用于数初始化讄信号量的初|它设|信号量sem的gؓval?br /><br /><span style="color: #0000FF; ">void</span> init_MUTEX (<span style="color: #0000FF; ">struct</span> semaphore *sem);<br />该函数用于初始化一个互斥锁Q即它把信号量sem的D|ؓ1?br /><br /><span style="color: #0000FF; ">void</span> init_MUTEX_LOCKED (<span style="color: #0000FF; ">struct</span> semaphore *sem);<br />该函C用于初始化一个互斥锁Q但它把信号量sem的D|ؓ0Q即一开始就处在已锁状态?br /><br /><span style="color: #0000FF; ">void</span> down(<span style="color: #0000FF; ">struct</span> semaphore * sem);<br />该函数用于获得信号量semQ它会导致睡眠,因此不能在中断上下文Q包括IRQ上下文和softirq上下文)使用该函数。该函数把sem的值减1Q如果信号量sem的值非负,q接返回,否则调用者将被挂P直到别的d释放该信号量才能l箋q行?br /><br /><span style="color: #0000FF; ">int</span> down_interruptible(<span style="color: #0000FF; ">struct</span> semaphore * sem);<br />该函数功能与downcMQ不同之处ؓQdown不会被信PsignalQ打断,但down_interruptible能被信号打断Q因此该函数有返回值来区分是正常返回还是被信号中断Q如果返?Q表C得信号量正常q回Q如果被信号打断Q返?EINTR?br /><br /><span style="color: #0000FF; ">int</span> down_trylock(<span style="color: #0000FF; ">struct</span> semaphore * sem);<br />该函数试着获得信号量semQ如果能够立刻获得,它就获得该信号量q返?Q否则,表示不能获得信号量semQ返回gؓ?倹{因此,它不会导致调用者睡眠,可以在中断上下文使用?br /><br /><span style="color: #0000FF; ">void</span> up(<span style="color: #0000FF; ">struct</span> semaphore * sem);<br />该函数释放信号量semQ即把sem的值加1Q如果sem的gؓ非正敎ͼ表明有Q务等待该信号量,因此唤醒q些{待者?nbsp;<br /><br />头文?<br />#include <linux/semaphore.h><br /><span style="color: #008000; ">/*</span><span style="color: #008000; "><br /> * Copyright (c) 2008 Intel Corporation<br /> * Author: Matthew Wilcox <willy@linux.intel.com><br /> *<br /> * Distributed under the terms of the GNU GPL, version 2<br /> *<br /> * Please see kernel/semaphore.c for documentation of these functions<br /> </span><span style="color: #008000; ">*/</span><br />#ifndef __LINUX_SEMAPHORE_H<br /><span style="color: #0000FF; ">#define</span> __LINUX_SEMAPHORE_H<br /><br />#include <linux/list.h><br />#include <linux/spinlock.h><br /><br /><span style="color: #008000; ">/*</span><span style="color: #008000; "> Please don't access any members of this structure directly </span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">struct</span> semaphore {<br />    spinlock_t        <span style="color: #0000FF; ">lock</span>;<br />    unsigned <span style="color: #0000FF; ">int</span>        count;<br />    <span style="color: #0000FF; ">struct</span> list_head    wait_list;<br />};<br /><br /><span style="color: #0000FF; ">#define</span> __SEMAPHORE_INITIALIZER(name, n)                \<br />{                                    \<br />    .<span style="color: #0000FF; ">lock</span>        = __SPIN_LOCK_UNLOCKED((name).<span style="color: #0000FF; ">lock</span>),        \<br />    .count        = n,                        \<br />    .wait_list    = LIST_HEAD_INIT((name).wait_list),        \<br />}<br /><br /><span style="color: #0000FF; ">#define</span> __DECLARE_SEMAPHORE_GENERIC(name, count) \<br />    <span style="color: #0000FF; ">struct</span> semaphore name = __SEMAPHORE_INITIALIZER(name, count)<br /><br /><span style="color: #0000FF; ">#define</span> DECLARE_MUTEX(name)    __DECLARE_SEMAPHORE_GENERIC(name, 1)<br /><br /><span style="color: #0000FF; ">static</span> inline <span style="color: #0000FF; ">void</span> sema_init(<span style="color: #0000FF; ">struct</span> semaphore *sem, <span style="color: #0000FF; ">int</span> val)<br />{<br />    <span style="color: #0000FF; ">static</span> <span style="color: #0000FF; ">struct</span> lock_class_key __key;<br />    *sem = (<span style="color: #0000FF; ">struct</span> semaphore) __SEMAPHORE_INITIALIZER(*sem, val);<br />    lockdep_init_map(&sem-><span style="color: #0000FF; ">lock</span>.dep_map, "semaphore->lock", &__key, 0);<br />}<br /><br /><span style="color: #0000FF; ">#define</span> init_MUTEX(sem)        sema_init(sem, 1)<br /><span style="color: #0000FF; ">#define</span> init_MUTEX_LOCKED(sem)    sema_init(sem, 0)<br /><br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> down(<span style="color: #0000FF; ">struct</span> semaphore *sem);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">int</span> __must_check down_interruptible(<span style="color: #0000FF; ">struct</span> semaphore *sem);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">int</span> __must_check down_killable(<span style="color: #0000FF; ">struct</span> semaphore *sem);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">int</span> __must_check down_trylock(<span style="color: #0000FF; ">struct</span> semaphore *sem);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">int</span> __must_check down_timeout(<span style="color: #0000FF; ">struct</span> semaphore *sem, <span style="color: #0000FF; ">long</span> jiffies);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> up(<span style="color: #0000FF; ">struct</span> semaphore *sem);<br /><br /><span style="color: #0000FF; ">#endif</span> /* __LINUX_SEMAPHORE_H */</div><img src ="http://www.shnenglu.com/aaxron/aggbug/199387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2013-04-12 18:22 <a href="http://www.shnenglu.com/aaxron/archive/2013/04/12/199387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux内核的同步机?1)自旋锁(spinlockQ?/title><link>http://www.shnenglu.com/aaxron/archive/2013/04/12/199386.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Fri, 12 Apr 2013 10:21:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2013/04/12/199386.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/199386.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2013/04/12/199386.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/199386.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/199386.html</trackback:ping><description><![CDATA[<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->Linux内核的同步机?1)、自旋锁QspinlockQ?br /><br />  自旋锁与互斥锁有点类|只是自旋锁不会引赯用者睡眠,如果自旋锁已l被别的执行单元保持Q调用者就一直@环在那里看是否该自旋锁的保持者已l释放了锁,"自旋"一词就是因此而得名?br /><br />  ׃自旋锁用者一般保持锁旉非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率q高于互斥锁?br /><br />  信号量和d信号量适合于保持时间较长的情况Q它们会D调用者睡眠,因此只能在进E上下文使用Q_trylock的变U能够在中断上下文用)Q而自旋锁适合于保持时间非常短的情况,它可以在M上下文用?br /><br />  如果被保护的׃n资源只在q程上下文访问,使用信号量保护该׃n资源非常合适,如果对共巯源的讉K旉非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部卌Y中断Q,必M用自旋锁?br /><br />  自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作?br /><br />  跟互斥锁一P一个执行单元要惌问被自旋锁保护的׃n资源Q必d得到锁,在访问完׃n资源后,必须释放锁。如果在获取自旋锁时Q没有Q何执行单元保持该锁,那么立卛_到锁Q如果在获取自旋锁时锁已l有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁?br /><br />  无论是互斥锁Q还是自旋锁Q在M时刻Q最多只能有一个保持者,也就_在Q何时L多只能有一个执行单元获得锁?br /><br />自旋锁的API有:<br /><br />spin_lock_init(x)<br />该宏用于初始化自旋锁x。自旋锁在真正用前必须先初始化。该宏用于动态初始化?br />    <br />DEFINE_SPINLOCK(x)<br />该宏声明一个自旋锁xq初始化它。该宏在2.6.11中第一ơ被定义Q在先前的内怸q没有该宏?br />    <br />SPIN_LOCK_UNLOCKED<br />该宏用于静态初始化一个自旋锁?br /><br />DEFINE_SPINLOCK(x){同于spinlock_t x = SPIN_LOCK_UNLOCKED<br />    <br />spin_is_locked(x)<br />该宏用于判断自旋锁x是否已经被某执行单元保持Q即被锁Q,如果是,q回真,否则q回假?br />    <br />spin_unlock_wait(x)<br />该宏用于{待自旋锁x变得没有被Q何执行单元保持,如果没有M执行单元保持该自旋锁Q该宏立卌回,否则@环在那里Q直到该自旋锁被保持者释放?br />    <br />spin_trylock(<span style="color: #0000FF; ">lock</span>)<br />该宏力获得自旋锁lockQ如果能立即获得锁,它获得锁q返回真Q否则不能立卌得锁Q立卌回假。它不会自旋{待lock被释放?br />    <br />spin_lock(<span style="color: #0000FF; ">lock</span>)<br />该宏用于获得自旋锁lockQ如果能够立卌得锁Q它马上返回,否则Q它自旋在那里Q直到该自旋锁的保持者释放,q时Q它获得锁ƈq回。MQ只有它获得锁才q回?br />    <br />spin_lock_irqsave(<span style="color: #0000FF; ">lock</span>, flags)<br />该宏获得自旋锁的同时把标志寄存器的g存到变量flags中ƈ失效本地中断?br />    <br />spin_lock_irq(<span style="color: #0000FF; ">lock</span>)<br />该宏cM于spin_lock_irqsaveQ只是该宏不保存标志寄存器的倹{?br />    <br />spin_lock_bh(<span style="color: #0000FF; ">lock</span>)<br />该宏在得到自旋锁的同时失效本地Y中断?br />    <br />spin_unlock(<span style="color: #0000FF; ">lock</span>)<br />该宏释放自旋锁lockQ它与spin_trylock或spin_lock配对使用。如果spin_trylockq回假,表明没有获得自旋锁,因此不必使用spin_unlock释放?br />    <br />spin_unlock_irqrestore(<span style="color: #0000FF; ">lock</span>, flags)<br />该宏释放自旋锁lock的同Ӟ也恢复标志寄存器的gؓ变量flags保存的倹{它与spin_lock_irqsave配对使用?br />    <br />spin_unlock_irq(<span style="color: #0000FF; ">lock</span>)<br />该宏释放自旋锁lock的同Ӟ也能本C断。它与spin_lock_irq配对应用?br />    <br />spin_unlock_bh(<span style="color: #0000FF; ">lock</span>)<br />该宏释放自旋锁lock的同Ӟ也能本地的软中断。它与spin_lock_bh配对使用?br />    <br />spin_trylock_irqsave(<span style="color: #0000FF; ">lock</span>, flags)<br />该宏如果获得自旋锁lockQ它也将保存标志寄存器的值到变量flags中,q且失效本地中断Q如果没有获得锁Q它什么也不做?br />  因此如果能够立即获得锁,它等同于spin_lock_irqsaveQ如果不能获得锁Q它{同于spin_trylock。如果该宏获得自旋锁lockQ那需要用spin_unlock_irqrestore来释放?br /><br />spin_trylock_irq(<span style="color: #0000FF; ">lock</span>)<br />该宏cM于spin_trylock_irqsaveQ只是该宏不保存标志寄存器。如果该宏获得自旋锁lockQ需要用spin_unlock_irq来释放?br />    <br />spin_trylock_bh(<span style="color: #0000FF; ">lock</span>)<br />该宏如果获得了自旋锁Q它也将失效本地软中断。如果得不到锁,它什么也不做。因此,如果得到了锁Q它{同于spin_lock_bhQ如果得不到锁,它等同于spin_trylock。如果该宏得C自旋锁,需要用spin_unlock_bh来释放?br /><br />spin_can_lock(<span style="color: #0000FF; ">lock</span>)<br />该宏用于判断自旋锁lock是否能够被锁Q它实际是spin_is_locked取反。如果lock没有被锁Q它q回真,否则Q返回假。该宏在2.6.11中第一ơ被定义Q在先前的内怸q没有该宏?nbsp;<br /><br />  获得自旋锁和释放自旋锁有好几个版本,因此让读者知道在什么样的情况下使用什么版本的获得和释N的宏是非常必要的?nbsp;<br /><br />  如果被保护的׃n资源只在q程上下文访问和软中断上下文讉KQ那么当在进E上下文讉K׃n资源Ӟ可能被Y中断打断Q从而可能进入Y中断上下文来对被保护的共享资源访问,因此对于q种情况Q对׃n资源的访问必M用spin_lock_bh和spin_unlock_bh来保护?nbsp;<br /><br />  当然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和spin_unlock_irqrestore也可以,它们失效了本地硬中断Q失效硬中断隐式C失效了Y中断。但是用spin_lock_bh和spin_unlock_bh是最恰当的,它比其他两个快?nbsp;<br /><br />  如果被保护的׃n资源只在q程上下文和tasklet或timer上下文访问,那么应该使用与上面情늛同的获得和释N的宏Q因为tasklet和timer是用软中断实现的?nbsp;<br /><br />  如果被保护的׃n资源只在一个tasklet或timer上下文访问,那么不需要Q何自旋锁保护Q因为同一个tasklet或timer只能在一个CPU上运行,即是在SMP环境下也是如此。实际上tasklet在调用tasklet_schedule标记光要被调度时已l把该taskletl定到当前CPUQ因此同一个tasklet决不可能同时在其他CPU上运行?nbsp;<br /><br />  timer也是在其被用add_timerd到timer队列中时已经被帮定到当前CPUQ所以同一个timerl不可能q行在其他CPU上。当然同一个tasklet有两个实例同时运行在同一个CPU更不可能了?nbsp;<br /><br />  如果被保护的׃n资源只在两个或多个tasklet或timer上下文访问,那么对共享资源的讉K仅需要用spin_lock和spin_unlock来保护,不必使用_bh版本Q因为当tasklet或timerq行Ӟ不可能有其他tasklet或timer在当前CPU上运行?nbsp;<br /><br />  如果被保护的׃n资源只在一个Y中断Qtasklet和timer除外Q上下文讉KQ那么这个共享资源需要用spin_lock和spin_unlock来保护,因ؓ同样的Y中断可以同时在不同的CPU上运行?nbsp;<br /><br />  如果被保护的׃n资源在两个或多个软中断上下文讉KQ那么这个共享资源当然更需要用spin_lock和spin_unlock来保护,不同的Y中断能够同时在不同的CPU上运行?nbsp;<br /><br />  如果被保护的׃n资源在Y中断Q包括tasklet和timerQ或q程上下文和中断上下文讉KQ那么在软中断或q程上下文访问期_可能被硬中断打断Q从而进入硬中断上下文对׃n资源q行讉KQ因此,在进E或软中断上下文需要用spin_lock_irq和spin_unlock_irq来保护对׃n资源的访问?nbsp;<br /><br />  而在中断处理句柄中用什么版本,需依情况而定Q如果只有一个中断处理句柄访问该׃n资源Q那么在中断处理句柄中仅需要spin_lock和spin_unlock来保护对׃n资源的访问就可以了?nbsp;<br /><br />  因ؓ在执行中断处理句柄期_不可能被同一CPU上的软中断或q程打断。但是如果有不同的中断处理句柄访问该׃n资源Q那么需要在中断处理句柄中用spin_lock_irq和spin_unlock_irq来保护对׃n资源的访问?nbsp;<br /><br />  在用spin_lock_irq和spin_unlock_irq的情况下Q完全可以用spin_lock_irqsave和spin_unlock_irqrestore取代Q那具体应该使用哪一个也需要依情况而定Q如果可以确信在对共享资源访问前中断是能的Q那么用spin_lock_irq更好一些?nbsp;<br /><br />  因ؓ它比spin_lock_irqsave要快一些,但是如果你不能确定是否中断能,那么使用spin_lock_irqsave和spin_unlock_irqrestore更好Q因为它恢复访问共享资源前的中断标志而不是直接能中断?nbsp;<br /><br />  当然Q有些情况下需要在讉K׃n资源时必M断失效,而访问完后必M断能,q样的情形用spin_lock_irq和spin_unlock_irq最好?nbsp;<br /><br />  需要特别提醒读者,spin_lock用于L在不同CPU上的执行单元对共享资源的同时讉K以及不同q程上下文互相抢占导致的对共享资源的非同步访问,而中断失效和软中断失效却是ؓ了阻止在同一CPU上Y中断或中断对׃n资源的非同步讉K?nbsp;   <br />  <br /><br />#include <linux/spinlock.h><br /><br />头文?<br />#include<linux/spinlock_types.h><br /><br />#ifndef __LINUX_SPINLOCK_TYPES_H<br /><span style="color: #0000FF; ">#define</span> __LINUX_SPINLOCK_TYPES_H<br /><br /><span style="color: #008000; ">/*</span><span style="color: #008000; "><br /> * include/linux/spinlock_types.h - generic spinlock type definitions<br /> *                                  and initializers<br /> *<br /> * portions Copyright 2005, Red Hat, Inc., Ingo Molnar<br /> * Released under the General Public License (GPL).<br /> </span><span style="color: #008000; ">*/</span><br /><br /><span style="color: #008000; ">//</span><span style="color: #008000; ">对称多处理器</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">#if</span> defined(CONFIG_SMP)<br />    #include <asm/spinlock_types.h><br /><span style="color: #0000FF; ">#else</span><br />    #include <linux/spinlock_types_up.h><br /><span style="color: #0000FF; ">#endif</span><br /><br />#include <linux/lockdep.h><br /><br />typedef <span style="color: #0000FF; ">struct</span> {<br />    raw_spinlock_t raw_lock;<br />#ifdef CONFIG_GENERIC_LOCKBREAK<br />    unsigned <span style="color: #0000FF; ">int</span> break_lock;<br /><span style="color: #0000FF; ">#endif</span><br />} spinlock_t;<br /><br /><span style="color: #0000FF; ">#define</span> SPINLOCK_MAGIC        0xdead4ead<br /><br />typedef <span style="color: #0000FF; ">struct</span> {<br />    raw_rwlock_t raw_lock;<br />#ifdef CONFIG_GENERIC_LOCKBREAK<br />    unsigned <span style="color: #0000FF; ">int</span> break_lock;<br /><span style="color: #0000FF; ">#endif</span><br />} rwlock_t;<br /><br /><span style="color: #0000FF; ">#define</span> RWLOCK_MAGIC        0xdeaf1eed<br /><br /><span style="color: #0000FF; ">#define</span> SPINLOCK_OWNER_INIT    ((void *)-1L)<br /><br /># define __SPIN_LOCK_UNLOCKED(lockname) \<br />    (spinlock_t)    {    .raw_lock = __RAW_SPIN_LOCK_UNLOCKED,    \<br />                SPIN_DEP_MAP_INIT(lockname) }<br /><span style="color: #0000FF; ">#define</span> __RW_LOCK_UNLOCKED(lockname) \<br />    (rwlock_t)    {    .raw_lock = __RAW_RW_LOCK_UNLOCKED,    \<br />                RW_DEP_MAP_INIT(lockname) }<br /><br /><span style="color: #008000; ">/*</span><span style="color: #008000; "><br /> * SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and<br /> * are hence deprecated.<br /> * Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or<br /> * __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate.<br /> </span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">#define</span> SPIN_LOCK_UNLOCKED    __SPIN_LOCK_UNLOCKED(old_style_spin_init)<br /><span style="color: #0000FF; ">#define</span> RW_LOCK_UNLOCKED    __RW_LOCK_UNLOCKED(old_style_rw_init)<br /><br /><span style="color: #0000FF; ">#define</span> DEFINE_SPINLOCK(x)    spinlock_t x = __SPIN_LOCK_UNLOCKED(x)<br /><span style="color: #0000FF; ">#define</span> DEFINE_RWLOCK(x)    rwlock_t x = __RW_LOCK_UNLOCKED(x)<br /><br /><span style="color: #0000FF; ">#endif</span> /* __LINUX_SPINLOCK_TYPES_H */<br />  </div><img src ="http://www.shnenglu.com/aaxron/aggbug/199386.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2013-04-12 18:21 <a href="http://www.shnenglu.com/aaxron/archive/2013/04/12/199386.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原]linux中断处理(2)下半部机?tasklethttp://www.shnenglu.com/aaxron/archive/2013/04/10/199306.html天下天下Wed, 10 Apr 2013 07:29:00 GMThttp://www.shnenglu.com/aaxron/archive/2013/04/10/199306.htmlhttp://www.shnenglu.com/aaxron/comments/199306.htmlhttp://www.shnenglu.com/aaxron/archive/2013/04/10/199306.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/199306.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/199306.html[原]linux中断处理(2)下半部机?tasklet
1.softirq 
适用于性能敏感的子pȝ

2.tasklet
建立在softirq之上,使用更简?br />softirq的不同实例可q行在不同的处理器上,而tasklet则不允许
必须使用define DECLARE_TASKLET 声明tasklet
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

void short_do_tasklet(unsigned long);
DECLARE_TASKLET(short_do_tasklet,short_tasklet,0);

3. 工作队列(work queue)
struct work_struct my_work;      //定义一个工作队?/span>
void my_work_func(unsigned long); //定义一个处理函?/span>



头文?br />#include <linux/interrupt.h>
/* Tasklets --- multithreaded analogue of BHs.

Main feature differing them of generic softirqs: tasklet
is running only on one CPU simultaneously.

Main feature differing them of BHs: different tasklets
may be run simultaneously on different CPUs.

Properties:
* If tasklet_schedule() is called, then tasklet is guaranteed
to be executed on some cpu at least once after this.
* If the tasklet is already scheduled, but its excecution is still not
started, it will be executed only once.
* If this tasklet is already running on another CPU (or schedule is called
from tasklet itself), it is rescheduled for later.
* Tasklet is strictly serialized wrt itself, but not
wrt another tasklets. If client needs some intertask synchronization,
he makes it with spinlocks.
*/

struct tasklet_struct
{
    struct tasklet_struct *next;
    unsigned long state;
    atomic_t count;
    void (*func)(unsigned long);
    unsigned long data;
};

#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }


使用CZ:
static atomic_t fpstatues;
static atomic_t has_image = {0};

static void gc0303_vsync_do_tasklet(ulong data)
{
    ulong curr = gettickcount();
    debug("curr:%lu",curr);

    if (atomic_read(&fpstatues)==0)
    {
        s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_FLUSH);
        gc0303_dma_buf.dma_addr = img_phys;
        gc0303_dma_buf.size = bmp_w*bmp_h;
        s3c2410_dma_enqueue(DMACH_XD0, 
            (void *)&gc0303_dma_buf, 
            gc0303_dma_buf.dma_addr, 
            gc0303_dma_buf.size);
        atomic_set(&fpstatues,1);
    }
}

DECLARE_TASKLET(gc0303_vsync_tasklet,gc0303_vsync_do_tasklet,0);

static irqreturn_t gc0303_vsync_handler(int irq,void* dev_id)
{
    if (atomic_read(&fpstatues)==1)
    {
        s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_START);
    }
    //调度gc0303_vsync_tasklet
    tasklet_schedule(&gc0303_vsync_tasklet);
    return IRQ_HANDLED;
}






tasklet是作Z断下半部的一个很好的选择Q它在性能和易用性之间有着很好的^衡。较之于softirqQtasklet不需要考虑SMP下的q行问题Q而又比workqueues有着更好的性能?br />tasklet通常作ؓ中断的下半部来使用Q在中断中调用tasklet_schedule(t)。每ơ硬中断都会触发一ơtasklet_schedule(t)Q但是每ơ中断它只会向其中的一个CPU注册Q而不是所有的CPU。完成注册后的tasklet由tasklet_action()来执行,在SMP环境下,它保证同一时刻Q同一个tasklet只有一个副本在q行Q这样就避免了用softirq所要考虑的互斥的问题。再者,tasklet在执行tasklet->func()前,再一ơ允许tasklet可调度(注册Q,但是在该tasklet已有一个副本在其他CPU上运行的情况下,它只能退后执行。MQ同一个硬中断引v的一个tasklet_schedule()动作只会使一个tasklet被注册,而不同中断引Ltasklet则可能在不同的时刻被注册而多ơ被执行?br />
tasklet的互斥。由于同一个tasklet不能有多个副本同时运行,所以不需要在多CPU之间互斥。在taskletq行的过E中Q它会被中断打断(q也是Y中断的优点)Q所以如果tasklet和其他中断之间的互斥有可能存在?br />中断服务E序一般都是在中断h关闭的条件下执行?以避免嵌套而中断控制复杂化。但是,中断是一个随ZӞ它随时会到来Q如果关中断的时间太长,CPU׃能及时响应其他的中断hQ从而造成中断的丢失。因此,Linux内核的目标就是尽可能快的处理完中断请求,其所能把更多的处理向后推q。例如,假设一个数据块已经辑ֈ了网U,当中断控制器接受到这个中断请求信hQLinux内核只是单地标志数据到来了,然后让处理器恢复到它以前q行的状态,其余的处理稍后再q行Q如把数据移入一个缓冲区Q接受数据的q程可以在~冲区找到数据)。因此,内核把中断处理分Z部分Q上半部QtophalfQ和下半部(bottomhalfQ,上半部(是中断服务E序Q内核立x行,而下半部Q就是一些内核函敎ͼ留着E后处理Q?br />
首先Q一个快速的“上半?#8221;来处理硬件发出的hQ它必须在一个新的中断生之前终止。通常Q除了在讑֤和一些内存缓冲区Q如果你的设备用CDMAQ就不止q些Q之间移动或传送数据,定g是否处于健全的状态之外,q一部分做的工作很少?br />
下半部运行时是允怸断请求的Q而上半部q行时是关中断的Q这是二者之间的主要区别?br />
但是Q内核到底什时候执行下半部Q以何种方式l织下半部?q就是我们要讨论的下半部实现机制Q这U机制在内核的演变过E中不断得到改进Q在以前的内怸Q这个机制叫做bottomhalf(Ubh)Q在2.4以后的版本中有了新的发展和改q,改进的目标下半部可以在多处理机上ƈ行执行,q有助于驱动E序的开发者进行驱动程序的开发。下面主要介l常用的Q?Tasklet)机制?.6内核中的工作队列机制?br />
q里的小d是指对要推迟执行的函数进行组l的一U机制。其数据l构为tasklet_structQ每个结构代表一个独立的Q务,其定义如下:
structtasklet_struct {
    structtasklet_struct *next;         /*指向链表中的下一个结?/span>*/
    unsignedlong state;                 /* Q务的状?/span>*/
    atomic_t count;                        /* 引用计数?/span>*/
    void(*func) (unsigned long);        /* 要调用的函数*/
    unsignedlong data;                  /* 传递给函数的参?/span>*/
}Q?br />l构中的func域就是下半部中要推迟执行的函敎ͼdata是它唯一的参数?br />state域的取gؓTASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示Q务已被调度,正准备投入运行,TASKLET_STATE_RUN表示Q务正在运行。TASKLET_STATE_RUN只有在多处理器系l上才用,单处理器pȝ什么时候都清楚一个小d是不是正在运行(它要么就是当前正在执行的代码Q要么不是)?br />count 域是Q务的引用计数器。如果它不ؓ0Q则Q务被止Q不允许执行Q只有当它ؓӞQ务才被激z,q且在被讄为挂hQ小d才能够执行?br />1. 声明和用小d大多数情况下Qؓ了控制一个寻常的g讑֤Q小d机制是实C半部的最佳选择。小d可以动态创建,使用方便Q执行v来也比较快?br />我们既可以静态地创徏Q务,也可以动态地创徏它。选择那种方式取决于到底是惌对小dq行直接引用q是一个间接引用。如果准备静态地创徏一个小dQ也是对它直接引用Q,使用下面两个宏中的一个:
DECLARE_TASKLET(name,func, data)
DECLARE_TASKLET_DISABLED(name,func, data)
q两个宏都能Ҏl定的名字静态地创徏一个tasklet_structl构。当该小d被调度以后,l定的函数func会被执行Q它的参数由datal出。这两个宏之间的区别在于引用计数器的初始D|不同。第一个宏把创建的Q务的引用计数器设|ؓ0Q因此,该小d处于Ȁzȝ态。另一个把引用计数器设|ؓ1Q所以该Q务处于禁止状态。例如:
DECLARE_TASKLET(my_tasklet,my_tasklet_handler, dev);
q行代码其实{h?br />struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler,dev};
q样创Z一个名为my_tasklet的小dQ其处理E序为tasklet_handlerQƈ且已被激zR当处理E序被调用的时候,dev׃被传递给它?br />2.  ~写自己的小d处理E序Q务处理程序必ȝ合如下的函数cdQ?br />void tasklet_handler(unsigned long data)
׃Q务不能睡眠,因此不能在小d中用信号量或者其它生阻塞的函数。但是小dq行时可以响应中断?br />3. 调度自己的小d通过调用tasklet_schedule()函数q传递给它相应的tasklt_struct指针Q该Q务就会被调度以便适当的时候执行:
tasklet_schedule(&my_tasklet);        /*把my_tasklet标记为挂?nbsp;*/
在小d被调度以后,只要有机会它׃可能早的运行。在它还没有得到q行Z之前Q如果一个相同的Q务又被调度了Q那么它仍然只会q行一ơ?br />可以调用tasklet_disable()函数来禁止某个指定的Q务。如果该Q务当前正在执行,q个函数会等到它执行完毕再返回。调用tasklet_enable()函数可以ȀzM个小dQ如果希望把以DECLARE_TASKLET_DISABLEDQ)创徏的小dȀz,也得调用q个函数Q如Q?br />tasklet_disable(&my_tasklet);        /*Q务现在被止,q个Q务不能运?/span>*/
tasklet_enable(&my_tasklet);        /*  Q务现在被Ȁz?/span>*/
也可以调用tasklet_kill()函数从挂L队列中去掉一个小d。该函数的参数是一个指向某个小d的tasklet_struct的长指针。在Q务重新调度它自n的时候,从挂L队列中移d调度的小d会很有用。这个函数首先等待该Q务执行完毕,然后再将它移厅R?br />4.tasklet的简单用?br />下面是tasklet的一个简单应?以模块的形成加蝲?br />
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>

static struct tasklet_struct my_tasklet;

static void tasklet_handler (unsigned long d ata)
{
    printk("tasklet_handler is running.\n");
}

static int __init test_init(void)
{
    tasklet_init(&my_tasklet,tasklet_handler,0);
    tasklet_schedule(&my_tasklet);
    return0;
}

static  void __exit test_exit(void)
{
    tasklet_kill(&tasklet);
    printk("test_exit is running.\n");
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

从这个例子可以看出,所谓的Q务机制是Z半部函数的执行提供了一U执行机Ӟ也就是说Q推q处理的事情是由tasklet_handler实现Q何时执行,l由Q务机制封装后交给内核d理?/div>

天下 2013-04-10 15:29 发表评论
]]>
[原]linux中断处理(1)上半部机?/title><link>http://www.shnenglu.com/aaxron/archive/2013/04/03/199066.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Wed, 03 Apr 2013 03:54:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2013/04/03/199066.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/199066.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2013/04/03/199066.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/199066.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/199066.html</trackback:ping><description><![CDATA[<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->linux中断处理(1)上半部机?br />应用E序通过/dev/目录中的讑֤l点操作讑֤,通过/sys目录中的攉讑֤信息.<br />查看中断:<br />cat /proc/interrupts<br /><br />查看中断l计:<br />cat /proc/stat<br /><br />1、头文g <br />#include <linux/interrupt.h><br />#include <asm/arch/irqs.h><br />2、申明中断处理程?nbsp;<br /><span style="color: #0000FF; ">static</span> spinlock_t    wiegand_lock;  <span style="color: #008000; ">//</span><span style="color: #008000; "> 使用之前必须初始?spin_lock_init(&wiegand_lock);</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">static</span> irqreturn_t wiegand_minus1_interrupt(<span style="color: #0000FF; ">int</span> irq, <span style="color: #0000FF; ">void</span> *dev_id)<br />{<br />    spin_lock(&wiegand_lock);<br />    <span style="color: #008000; ">//</span><span style="color: #008000; ">do something <br />    </span><span style="color: #008000; ">//</span><span style="color: #008000; ">wiegand_minus_interrupt();</span><span style="color: #008000; "><br /></span>    spin_unlock(&wiegand_lock);<br />    <span style="color: #0000FF; ">return</span> IRQ_HANDLED;<br />}<br /><br />3.注册中断 request_irq()<br />2.6 内核 函数原型如下Q?br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">int</span> __must_check request_irq(unsigned <span style="color: #0000FF; ">int</span> irq, irq_handler_t handler, unsigned <span style="color: #0000FF; ">long</span> flags, <span style="color: #0000FF; ">const</span> <span style="color: #0000FF; ">char</span> *name, <span style="color: #0000FF; ">void</span> *dev_id); <br />W?个参?中断?是要甌的中断号<br />W?个参?中断处理函数     <br /><br />W?个参?中断触发标志<br />    IRQF_DISABLED         快中?止其他中断)<br />    IRQF_TRIGGER_RISING    讑֤在中断线上生一个上升沿?发出中断.(说明在中断之?讑֤一直将中断U保持在一个电q上)<br />    IRQF_TRIGGER_FALLING    下降沿触?br />    IRQF_TRIGGER_HIGH    高电q发中?br />    IRQF_TRIGGER_LOW    低电q发中?br />    IRQF_TRIGGER_RANDOM    为系l随机发生器提供支持<br />    IRQF_TRIGGER_SHARED    (表示׃n相同的中断号,多个讑֤׃n)<br /><span style="color: #008000; ">/*</span><span style="color: #008000; "><br /> * linux/interrupt.h<br /> * These correspond to the IORESOURCE_IRQ_* defines in<br /> * linux/ioport.h to select the interrupt line behaviour.  When<br /> * requesting an interrupt without specifying a IRQF_TRIGGER, the<br /> * setting should be assumed to be "as already configured", which<br /> * may be as per machine or firmware initialisation.<br /> </span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_NONE    0x00000000<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_RISING    0x00000001<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_FALLING    0x00000002<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_HIGH    0x00000004<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_LOW    0x00000008<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_MASK    (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \<br />                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)<br /><span style="color: #0000FF; ">#define</span> IRQF_TRIGGER_PROBE    0x00000010<br /><br />typedef irqreturn_t (*irq_handler_t)(<span style="color: #0000FF; ">int</span>, <span style="color: #0000FF; ">void</span> *);<br /><br />W?个参?中断的标?中断的标识与/proc/interrupts对应<br />W?个参?传入中断处理E序的参敎ͼ可以为NULLQ在注册׃n中断Ӟ此参C能ؓNULLQ作为共享中断时的中断区别参数?br /><br />q回?如果中断处理成功,q回IREQ_HANDLED,否则,q回IRQ_NONE<br /><span style="color: #008000; ">/*</span><span style="color: #008000; "> irqreturn.h </span><span style="color: #008000; ">*/</span><br />typedef <span style="color: #0000FF; ">int</span> irqreturn_t;<br /><span style="color: #0000FF; ">#define</span> IRQ_NONE    (0)<br /><span style="color: #0000FF; ">#define</span> IRQ_HANDLED    (1)<br /><span style="color: #0000FF; ">#define</span> IRQ_RETVAL(x)    ((x) != 0)<br /><br />中断上下?br /><br />中断上下文注意事?<br />1)中断上下文代码绝不可以停止运行。不能做M可能发生休眠的操?在从中断处理函数中调用一个内核API之前,应该仔细分手?以确保其内部不会触发d{待!<br /><br />2)Z在中断处理函C保护临界?不能使用互斥?因ؓ它们也许D睡眠,应该使用自旋锁代替互斥体.<br /><br />3)中断处理函数不能与用L间直接交互数?<br />调度器工作于q程之间,如果中断处理函数睡眠q被调度出去.无法调度回来!<br /><br />4)中断处理函数一斚w需要快速地为其他进E让出处理器,另一斚w又需要完成它的工?Z规避q种冲突,中断处理函数通常工作分成两个部?半部设一个标志以宣称它已l服务了该中?而重大的工作负蝲都被丢给了底半部,底半部的执行被g?在其执行环境?所有的中断都是使能?<br /><br />4.释放中断<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> free_irq(<span style="color: #0000FF; ">int</span> irq,<span style="color: #0000FF; ">void</span> *dev_id)<br /><br />5、启动用用中断<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> disable_irq_nosync(unsigned <span style="color: #0000FF; ">int</span> irq);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> disable_irq(unsigned <span style="color: #0000FF; ">int</span> irq);<br /><span style="color: #0000FF; ">extern</span> <span style="color: #0000FF; ">void</span> enable_irq(unsigned <span style="color: #0000FF; ">int</span> irq);</div><img src ="http://www.shnenglu.com/aaxron/aggbug/199066.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2013-04-03 11:54 <a href="http://www.shnenglu.com/aaxron/archive/2013/04/03/199066.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动学习W记(1)http://www.shnenglu.com/aaxron/archive/2012/12/04/195955.html天下天下Tue, 04 Dec 2012 00:59:00 GMThttp://www.shnenglu.com/aaxron/archive/2012/12/04/195955.htmlhttp://www.shnenglu.com/aaxron/comments/195955.htmlhttp://www.shnenglu.com/aaxron/archive/2012/12/04/195955.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/195955.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/195955.html
内核W号列表:

cat 
/proc/kallsyms
cat 
/proc/iomem

导出内核W号:
EXPORT_SYMBOL(sym)
1、缺省情况下QLinux2.6内核中默认不导出所有的W号,卛_2.6的内怸没有q个宏EXPORT_NO_SYMBOLS
2、如果想要自己指定导出哪些变量或函数Q先在Makefile中?/span>-DEXPORT_SYMTABQ然后在源文件中使用EXPORT_SYMBOL(xxx);导出?br />
echo 
8 > /proc/sys/kernel/printk

查看中断:
cat 
/proc/interrupts

下半部机?br />
1.tasklet
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

2. 工作队列
struct work_struct my_work;      //定义一个工作队?/span>
void my_work_func(unsigned long); //定义一个处理函?/span>

在中断处理函?tasklet和内核定时器{非q程上下文不能阻?


天下 2012-12-04 08:59 发表评论
]]>
s3c2410的dma操作的一般步?/title><link>http://www.shnenglu.com/aaxron/archive/2012/12/04/195954.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Tue, 04 Dec 2012 00:58:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2012/12/04/195954.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/195954.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2012/12/04/195954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/195954.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/195954.html</trackback:ping><description><![CDATA[     摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->s3c2410的dma操作的一般步骤一般的Q在s3c2440中,要想q行dma传输Q需要一下七个步骤:一Q?* s3c2410_request_dma * * ge...  <a href='http://www.shnenglu.com/aaxron/archive/2012/12/04/195954.html'>阅读全文</a><img src ="http://www.shnenglu.com/aaxron/aggbug/195954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2012-12-04 08:58 <a href="http://www.shnenglu.com/aaxron/archive/2012/12/04/195954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux讑֤驱动E序学习W记:(1) 字符讑֤驱动入门1http://www.shnenglu.com/aaxron/archive/2012/11/08/194881.html天下天下Thu, 08 Nov 2012 08:04:00 GMThttp://www.shnenglu.com/aaxron/archive/2012/11/08/194881.htmlhttp://www.shnenglu.com/aaxron/comments/194881.htmlhttp://www.shnenglu.com/aaxron/archive/2012/11/08/194881.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/194881.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/194881.html 

 

//q是一个最单的字符讑֤驱动,入门专用.
//scull1.h
#ifndef _SCULL1_H
#define _SCULL1_H

#include 
<linux/init.h>
#include 
<linux/module.h>
#include 
<linux/kernel.h>
#include 
<linux/types.h>
#include 
<linux/fs.h>
#include 
<linux/version.h>
#include 
<asm/uaccess.h>
#include 
<linux/cdev.h>
#include 
<linux/mm.h>
#include 
<linux/errno.h>


#define SCULL_MAJOR 0
#define SCULL_SIZE    0x1000
#define SCULL_CMD_CLEAR    0x01


struct scull_dev{
    
struct cdev cDev;
    
char   mem[SCULL_SIZE];
};


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

ssize_t scull_read(
struct file *filp, char __user *buf, size_t count,loff_t *f_pos);             

ssize_t scull_write(
struct file *filp, const char __user *buf, size_t count,loff_t *f_pos);

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

#endif






//scull1.c
#include "scull1.h"

MODULE_LICENSE(
"Dual BSD/GPL");
MODULE_AUTHOR(
"Aaron.xu");
MODULE_DESCRIPTION(
"hello driver test");
MODULE_VERSION(
"0.1");

static int scull_major = SCULL_MAJOR;
struct scull_dev mydev;

struct file_operations scull_fops = 
{
    .owner     
= THIS_MODULE,
    .open     
= scull_open,
    .release 
= scull_release,
    .read     
= scull_read,
    .write     
= scull_write,
};



static void scull_setup_cdev(void)
{
    
int err;
    dev_t devid 
= MKDEV(scull_major,0);

    
    cdev_init(
&mydev.cDev,&scull_fops);
    
    printk(KERN_INFO 
"&mydev.cDev.ops:%p \n",&mydev.cDev.ops);

    mydev.cDev.owner    
= THIS_MODULE;
    mydev.cDev.ops        
= &scull_fops;

    printk(KERN_INFO 
"&mydev.cDev.ops:%p \n",&mydev.cDev.ops);

    err    
= cdev_add(&mydev.cDev,devid,1);
    
if (err!=0)
    {
        printk(KERN_ERR 
"cdev_add Error,err:%d \n",err);
    }
}

static int scull_init(void)
{
    
int err;
    dev_t devid 
= MKDEV(scull_major,0);

    
if (scull_major)
    {
        err 
= register_chrdev_region(devid,1,"scull1");
    }
    
else
    {
        err 
= alloc_chrdev_region(&devid,0,1,"scull1");
        scull_major 
= MAJOR(devid);
    }

    
if (err !=0 )
    {
        printk(KERN_ERR 
"register chrdev region error,err:%d \n",err);
        
return err;
    }

    scull_setup_cdev();
    
return 0;
}

static void scull_exit(void)
{
    cdev_del(
&mydev.cDev);
    unregister_chrdev_region(MKDEV(scull_major,
0),1);
}


int scull_open(struct inode* inode,struct file* filp)
{
    filp
->private_data = &mydev;
    
return 0;
}

ssize_t scull_read(
struct file *filp, char __user *buf, size_t count,loff_t *f_pos)               
{
    unsigned 
long pos = *f_pos;
    
int err = 0;
    
int ret = 0;
    
struct scull_dev* p_mydev = filp->private_data;

    
if (pos >= SCULL_SIZE)
    {
        
return 0;
    }

    
if (count > (SCULL_SIZE - pos) )
    {
        count 
= SCULL_SIZE - pos;
    }

    err 
= copy_to_user(buf,p_mydev->mem+pos,count);
    
if (err !=0 )
    {
        ret 
= -EFAULT;
    }
    
else
    {
        
*f_pos += count;
        ret 
= count;
        printk(KERN_INFO 
"read %d byte(s) from %lu \n",ret,pos);
    }
    
return ret;
}

ssize_t scull_write(
struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
    unsigned 
long pos = *f_pos;
    
int err = 0;
    
int ret = 0;
    
struct scull_dev* p_mydev = filp->private_data;

    
if (pos >= SCULL_SIZE)
    {
        
return 0;
    }

    
if (count > (SCULL_SIZE - pos) )
    {
        count 
= SCULL_SIZE - pos;
    }

    err 
= copy_from_user(p_mydev->mem+pos,buf,count);
    
if (err !=0 )
    {
        ret 
= -EFAULT;
    }
    
else
    {
        
*f_pos += count;
        ret 
= count;
        printk(KERN_INFO 
"write %d byte(s) from %lu \n",ret,pos);
    }
    
return ret;
}

int scull_release(struct inode* inode,struct file* filp)
{
    
return 0;
}


module_init(scull_init);
module_exit(scull_exit);



//Makefile
obj-m    +=scull1.o
KERNELDIR    :
= /usr/src/linux-headers-2.6.32-5-686
PWD    :
=$(shell pwd)
.PHONY: test clean all
all:
    $(MAKE) 
-C $(KERNELDIR) M=$(PWD) modules
clean:
    rm 
-rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsm *.order *.symvers .tmp_versions

test:
    insmod .
/scull1.ko
    rmmod scull1
    dmesg 
-c



//创徏讑֤节点
make_dev_node
#
!/bin/bash
DEVICE
="scull1"
MAJOR
=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices`
cmd
="mknod /dev/$DEVICE c $MAJOR 0"
echo $cmd
`$cmd`

 



天下 2012-11-08 16:04 发表评论
]]>
module_param()说明http://www.shnenglu.com/aaxron/archive/2012/11/06/194716.html天下天下Tue, 06 Nov 2012 07:54:00 GMThttp://www.shnenglu.com/aaxron/archive/2012/11/06/194716.htmlhttp://www.shnenglu.com/aaxron/comments/194716.htmlhttp://www.shnenglu.com/aaxron/archive/2012/11/06/194716.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/194716.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/194716.htmlmodule_param()说明
在用h下~程可以通过main()的来传递命令行参数Q而编写一个内核模块则通过module_param() 
module_param宏是Linux 
2.6内核中新增的Q该宏被定义在include/linux/moduleparam.h文g中,具体定义如下Q?br />
#define module_param(name, type, perm)      \
    module_param_named(name, name, type, perm)

其中使用?nbsp;
3 个参?要传递的参数变量? 变量的数据类? 以及讉K参数的权限?br />
perm参数的作用是什么?

最后的 module_param 字段是一个权限?表示此参数在sysfs文gpȝ中所对应的文件节点的属性。你应当使用 
<linux/stat.h> 中定义的? q个值控制谁可以存取q些模块参数?nbsp;sysfs 中的表示.当perm?Ӟ表示此参C存在 sysfs文gpȝ下对应的文g节点?nbsp;否则, 模块被加载后Q在/sys/module/ 目录下将出现以此模块名命名的目录, 带有l定的权??br />权限在include/linux/stat.h中有定义
比如Q?br />
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

使用 S_IRUGO 作ؓ参数可以被所有hd, 但是不能改变; S_IRUGO
|S_IWUSR 允许 root 来改变参? 注意, 如果一个参数被 sysfs 修改, 你的模块看到的参数g改变? 但是你的模块没有M其他的通知. 你应当不要模块参数可写, 除非你准备好这个改变ƈ且因而作出反?

>>> 

q个宏定义应当放在Q何函C? 典型地是出现在源文g的前?定义如:

static char *whom = "world";
static int howmany = 1;
module_param(howmany, 
int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

模块参数支持许多cd:
bool 
invbool 
一个布型( 
true 或?nbsp;false)?相关的变量应当是 int cd). invbool cd颠倒了? 所以真值变?nbsp;false, 反之亦然. 

charp Q一个字W指针? 内存为用h供的字串分配, 指针因此讄. 
int 
long 
short 
uint 
ulong 
ushort 
基本的变长整型? ?nbsp;u 开头的是无W号? 

数组参数, 用逗号间隔的列表提供的? 模块加蝲者也支持. 声明一个数l参? 使用: 
module_param_array(name,type,num,perm); 

q里 name 是你的数l的名子(也是参数?, 
type 是数l元素的cd, 
num 是一个整型变? 
perm 是通常的权限? 

如果数组参数在加载时讄, num 被设|成提供的数的个? 模块加蝲者拒l比数组能放下的多的? 

试模块Q源E序hello.c内容如下Q?nbsp;

#include 
<linux/init.h> 
#include 
<linux/module.h>
#include 
<linux/moduleparam.h>         

MODULE_LICENSE(
"Dual BSD/GPL");     

static char *who= "world";             
static int times = 1;       
module_param(times,
int,S_IRUSR);     
module_param(who,charp,S_IRUSR);   

static int hello_init(void)       
{
    
int i;
    
for(i=0;i<times;i++)
       printk(KERN_ALERT 
"(%d) hello, %s!\n",i,who);
     
return 0;
}

static void hello_exit(void
{
    printk(KERN_ALERT
"Goodbye, %s!\n",who);
}

module_init(hello_init);
module_exit(hello_exit);

~译生成可执行文件hello

插入: 
# insmod hello.ko who
="world" times=5 

出现5?/span>"hello,world!"Q?nbsp;

#Q?/span>1Qhello,world! 
#Q?/span>2Qhello,world! 
#Q?/span>3Qhello,world! 
#Q?/span>4Qhello,world! 
#Q?/span>5Qhello,world! 

卸蝲Q?nbsp;
# rmmod hello 

出现Q?nbsp;
#Goodbye,world
!


天下 2012-11-06 15:54 发表评论
]]>
深入理解linux内核W三?定时试)http://www.shnenglu.com/aaxron/archive/2012/08/03/186172.html天下天下Fri, 03 Aug 2012 08:40:00 GMThttp://www.shnenglu.com/aaxron/archive/2012/08/03/186172.htmlhttp://www.shnenglu.com/aaxron/comments/186172.htmlhttp://www.shnenglu.com/aaxron/archive/2012/08/03/186172.html#Feedback0http://www.shnenglu.com/aaxron/comments/commentRss/186172.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/186172.html






天下 2012-08-03 16:40 发表评论
]]>
Linux讑֤驱动E序:gnu make 扩展语法http://www.shnenglu.com/aaxron/archive/2012/03/16/168055.html天下天下Fri, 16 Mar 2012 03:11:00 GMThttp://www.shnenglu.com/aaxron/archive/2012/03/16/168055.htmlhttp://www.shnenglu.com/aaxron/comments/168055.htmlhttp://www.shnenglu.com/aaxron/archive/2012/03/16/168055.html#Feedback1http://www.shnenglu.com/aaxron/comments/commentRss/168055.htmlhttp://www.shnenglu.com/aaxron/services/trackbacks/168055.html要点:
在用L间驱动程?/span>
insmod
modprobe
rmmod


一些宏:
LINUX_VERSION_CODE
整数?/span>


GNU make 扩展语法
obj-m   +=hello.o
KERNELDIR   := /usr/src/linux-headers-2.6.32-5-686
PWD :=$(shell pwd)
.PHONY: test clean all
all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsm *.order *.symvers .tmp_versions

test:
    insmod ./hello.ko
    rmmod hello
    dmesg -c

obj-m
由内核构造系l用的makefiletW号,用来定在当前目录中应构造哪些模?
即m:指定把对象编译ؓ模块

obj-y
指定把对象编译进内核?/span>

如果我们要构造的模块为module.ko,q由file1.c和file2.c则正的makefile可如下编?
obj-m :=module.o
module-objs :=file1.o file2.o

Z让上面的makefile可以工作,必须在大的内核构造系l环境中调用它们,所以上q命令首先要改变-C指定的目??
 $(MAKE) -C $(KERNELDIR)
然后指定M变量目录,卌makefile在构造modules目标之前q回到模块源代码的目?既当前目?M=$(PWD),最后modules目标指向obj-m变量中设定的模块.


M不是一个编译选项Q而是一个变量,从顶层makefile文g里可以找到它的定?
文g?/span>
/usr/src/linux-headers-2.6.32-5-common/Makefile

69 ifeq ("$(origin M)", "command line")
70   KBUILD_EXTMOD := $(M)
71 endif


-C 用于指定内核源代码的目录

-M 用于module所在的目录

 

如果一个模块包括了多个.c文g(?file1.c , file2.c),则应该以如下方式~写Makefile
obj-m := modulename.o
module-objs := file1.o file2.o



天下 2012-03-16 11:11 发表评论
]]>
中断及中断处理过E?/title><link>http://www.shnenglu.com/aaxron/archive/2011/11/16/160280.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Wed, 16 Nov 2011 09:25:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2011/11/16/160280.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/160280.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2011/11/16/160280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/160280.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/160280.html</trackback:ping><description><![CDATA[<div><div><div>中断及中断处理过E?/div></div><div>1. 中断和异常的概念区别</div><div>   Intel的官Ҏ档里中断和异常理解ZU中断当前程序执行的不同机制。这是中断和异常的共同点。不同点在于Q?/div><div>   中断(interrupt)是异步的事gQ典型的比如由I/O讑֤触发Q异?exception)是同步的事gQ典型的比如处理器执行某条指令时发现出错了等{?/div><div>   中断又可以分为可屏蔽中断和非可屏蔽中断,异常又分为故障、陷阱和异常中止3U,它们的具体区别很多书c和官方文档都解释的比较清楚q里不再赘述?/div><div>关于它们的区别有两点是需要注意的Q?/div><div>1Q^常所说的屏蔽中断是不包括异常的,卛_怸会因为CPU的IF位被清(关中断,指oQcliQ而受影响Q比如缺异常,即关了中断也会触发CPU的处理?/div><div>2Q通常说的int 80hq种pȝ调用使用的中断方式实际上g上是理解为异常处理的Q因此也不会被屏蔽掉Q这也很好理解,int 80hq种中断方式是程序里d触发的,对于CPU来说属于同步事gQ因此也属于异常的范畴?/div><div></div><div>2. 中断Q异常)处理q程</div><div>   需要明的一ҎCPU对于中断和异常的具体处理机制本质上是完全一致的Q即Q?/div><div>当CPU收到中断或者异常的信号Ӟ它会暂停执行当前的程序或dQ通过一定的机制跌{到负责处理这个信L相关处理E序中,在完成对q个信号的处理后再蟩回到刚才被打断的E序或Q务中。这里只描述保护模式下的处理q程Q搞清楚了保护模式下的处理过E(更复杂)Q实模式下的处理机制也就Ҏ理解了?/div><div></div><div>具体的处理过E如下:</div><div>0Q中断响应的事前准备Q?/div><div>pȝ要想能够应对各种不同的中断信Pȝ来看是需要知道每U信号应该由哪个中断服务E序负责以及q些中断服务E序具体是如何工作的。系l只有事前对q两件事都知道得很清楚,才能正确地响应各U中断信号和异常?/div><div>[a]pȝ所有的中断信号l一q行了编P一?56个:0?55Q,q个LZ断向量,具体哪个中断向量表示哪种中断有的是规定好的,也有的是在给定范围内自行讑֮的? </div><div>中断向量和中断服务程序的对应关系主要是由IDTQ中断向量表Q负责。操作系l在IDT中设|好各种中断向量对应的中断描q符Q一共有三类中断门描q符QQ务门、中断门和陷阱门Q,留待CPU查询使用。而IDT本n的位|是由idtr保存的,当然q个地址也是由OS填充的?/div><div></div><div>[b]中断服务E序具体负责处理中断Q异常)的代码是pYӞ也就是操作系l实现的Q这部分代码属于操作pȝ内核代码。也是说从CPU中断信号到加蝲中断服务E序以及从中断服务程序中恢复执行被暂停的E序Q这个流E基本上是硬件确定下来的Q而具体的中断向量和服务程序的对应关系讄和中断服务程序的内容是由操作pȝ定的?/div><div></div><div>1QCPU查是否有中断/异常信号</div><div>   CPU在执行完当前E序的每一条指令后Q都会去认在执行刚才的指oq程中中断控制器Q如Q?259AQ是否发送中断请求过来,如果有那么CPU׃在相应的旉脉冲到来时从ȝ上读取中断请求对应的中断向量[2]?/div><div>对于异常和系l调用那L软中断,因ؓ中断向量是直接给出的Q所以和通过IRQQ中断请求)U发送的g中断h不同Q不会再专门d其对应的中断向量?/div><div></div><div>2Q根据中断向量到IDT表中取得处理q个向量的中断程序的D选择W?/div><div>   CPUҎ得到的中断向量到IDT表里扑ֈ该向量对应的中断描述W,中断描述W里保存着中断服务E序的段选择W?/div><div></div><div>3Q根据取得的D选择W到GDT中找相应的段描述W?/div><div>   CPU使用IDT查到的中断服务程序的D选择W从GDT中取得相应的D|q符Q段描述W里保存了中断服务程序的D基址和属性信息,此时CPU得C中断服务E序的v始地址?/div><div>   q里QCPU会根据当前cs寄存器里的CPL和GDT的段描述W的DPLQ以保中断服务E序是高于当前程序的Q如果这ơ中断是~程异常Q如Qint 80hpȝ调用Q,那么q要查CPL和IDT表中中断描述W的DPLQ以保证当前E序有权限用中断服务程序,q可以避免用户应用程序访问特D的陷阱门和中断门[3]?/div><div></div><div></div><div>4QCPUҎҎU的判断讑֮卛_q行的中断服务程序要使用的栈的地址</div><div>   CPU会根据CPL和中断服务程序段描述W的DPL信息认是否发生了特权的{换,比如当前E序正运行在用户态,而中断程序是q行在内核态的Q则意味着发生了特权的{换,q时CPU会从当前E序的TSS信息Q该信息在内存中的首地址存在TR寄存器中Q里取得该程序的内核栈地址Q即包括ss和esp的|q立卛_pȝ当前使用的栈切换成新的栈。这个栈是卛_q行的中断服务程序要使用的栈。紧接着将当前E序使用的ss,esp压到新栈中保存v来?/div><div></div><div>6Q保护当前程序的现场</div><div>   CPU开始利用栈保护被暂停执行的E序的现场:依次压入当前E序使用的eflagsQcsQeipQerrorCodeQ如果是有错误码的异常)信息?/div><div>官方文档[1]l出的栈变化的示意图如下Q?/div><div></div><div></div><div>7Q蟩转到中断服务E序的第一条指令开始执?/div><div>   CPU利用中断服务E序的段描述W将其第一条指令的地址加蝲到cs和eip寄存器中Q开始执行中断服务程序。这意味着先前的程序被暂停执行Q中断服务程序正式开始工作?/div><div></div><div>8Q中断服务程序处理完毕,恢复执行先前中断的程?/div><div>   在每个中断服务程序的最后,必须有中断完成返回先前程序的指oQ这是iretQ或iretdQ。程序执行这条返回指令时Q会从栈里弹出先前保存的被暂停程序的现场信息Q即eflags,cs,eip重新开始执行?br /><img src="http://www.shnenglu.com/images/cppblog_com/aaxron/中断.png" alt="" /></div></div><div></div><img src ="http://www.shnenglu.com/aaxron/aggbug/160280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2011-11-16 17:25 <a href="http://www.shnenglu.com/aaxron/archive/2011/11/16/160280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Debian 6 驱动开发环境搭?/title><link>http://www.shnenglu.com/aaxron/archive/2011/11/01/159454.html</link><dc:creator>天下</dc:creator><author>天下</author><pubDate>Tue, 01 Nov 2011 06:24:00 GMT</pubDate><guid>http://www.shnenglu.com/aaxron/archive/2011/11/01/159454.html</guid><wfw:comment>http://www.shnenglu.com/aaxron/comments/159454.html</wfw:comment><comments>http://www.shnenglu.com/aaxron/archive/2011/11/01/159454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/aaxron/comments/commentRss/159454.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aaxron/services/trackbacks/159454.html</trackback:ping><description><![CDATA[<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">Debian </span><span style="color: #800000; ">6</span><span style="color: #000000; "> 驱动开发环境搭?br /></span><span style="color: #800000; ">1</span><span style="color: #000000; ">.</span><span style="color: #000000; ">安装相关工具<br />apt</span><span style="color: #000000; ">-</span><span style="color: #000000; ">get install </span><span style="color: #000000; ">-</span><span style="color: #000000; ">y gcc g</span><span style="color: #000000; ">++</span><span style="color: #000000; "> gdb make build</span><span style="color: #000000; ">-</span><span style="color: #000000; ">essential<br /><br /></span><span style="color: #800000; ">2</span><span style="color: #000000; ">.</span><span style="color: #000000; ">查看pȝ版本</span><span style="color: #000000; ">,</span><span style="color: #000000; ">q安装内核头文g<br />root@</span><span style="color: #800000; ">192.168</span><span style="color: #000000; ">.</span><span style="color: #800000; ">20.128</span><span style="color: #000000; ">:~/</span><span style="color: #000000; "> </span><span style="color: #008000; ">#</span><span style="color: #008000; "> uname -r</span><span style="color: #008000; "><br /></span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br />apt</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cache search linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br />apt</span><span style="color: #000000; ">-</span><span style="color: #000000; ">get install </span><span style="color: #000000; ">-</span><span style="color: #000000; ">y linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br /><br /></span><span style="color: #800000; ">3</span><span style="color: #000000; ">.</span><span style="color: #000000; ">查看内核头文件位|?br />看下会安装到?/span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />apt</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cache show linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br /><br />有这么句</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />These files are going to be installed into<br /></span><span style="color: #000000; ">/</span><span style="color: #000000; ">usr</span><span style="color: #000000; ">/</span><span style="color: #000000; ">src</span><span style="color: #000000; ">/</span><span style="color: #000000; ">linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; ">,</span><span style="color: #000000; "> and can be used </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> building modules<br /><br />是q里?/span><span style="color: #000000; ">.</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">/</span><span style="color: #000000; ">usr</span><span style="color: #000000; ">/</span><span style="color: #000000; ">src</span><span style="color: #000000; ">/</span><span style="color: #000000; ">linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br /><br /></span><span style="color: #800000; ">4</span><span style="color: #000000; ">.</span><span style="color: #000000; ">好了</span><span style="color: #000000; ">,</span><span style="color: #000000; ">接下来写试例子</span><span style="color: #000000; ">:</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">,</span><span style="color: #000000; ">抄了http</span><span style="color: #000000; ">://</span><span style="color: #000000; ">bbs</span><span style="color: #000000; ">.</span><span style="color: #000000; ">chinaunix</span><span style="color: #000000; ">.</span><span style="color: #000000; ">net</span><span style="color: #000000; ">/</span><span style="color: #000000; ">thread</span><span style="color: #000000; ">-</span><span style="color: #800000; ">3570849</span><span style="color: #000000; ">-</span><span style="color: #800000; ">1</span><span style="color: #000000; ">-</span><span style="color: #800000; ">1</span><span style="color: #000000; ">.</span><span style="color: #000000; ">html<br />上的代码</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />文g1</span><span style="color: #000000; ">:</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">.</span><span style="color: #000000; ">c<br /></span><span style="color: #008000; ">#</span><span style="color: #008000; ">include <linux/init.h><br />#include <linux/module.h></span><span style="color: #008000; "><br /></span><span style="color: #000000; ">MODULE_LICENSE(</span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; font-weight: bold; ">GPL</span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; ">);<br /><br />static </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> hello_init(void)<br />{<br />    printk(KERN_ALERT </span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; font-weight: bold; ">Hello, world\n</span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; ">);<br />    </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #800000; ">0</span><span style="color: #000000; ">;<br />}<br /><br />static void hello_exit(void)<br />{<br />    printk(KERN_ALERT </span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; font-weight: bold; ">Goodbye, cruel world\n</span><span style="color: #000000; font-weight: bold; ">"</span><span style="color: #000000; ">);<br />}<br /><br />module_init(hello_init);<br />module_exit(hello_exit);<br /><br />文g2</span><span style="color: #000000; ">:</span><span style="color: #000000; ">Makefile</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />obj</span><span style="color: #000000; ">-</span><span style="color: #000000; ">m   </span><span style="color: #000000; ">+=</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">.</span><span style="color: #000000; ">o<br />KERNELDIR   </span><span style="color: #000000; ">:=</span><span style="color: #000000; "> </span><span style="color: #000000; ">/</span><span style="color: #000000; ">usr</span><span style="color: #000000; ">/</span><span style="color: #000000; ">src</span><span style="color: #000000; ">/</span><span style="color: #000000; ">linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "><br />PWD </span><span style="color: #000000; ">:=</span><span style="color: #000000; ">$(shell pwd)<br /></span><span style="color: #000000; ">.</span><span style="color: #000000; ">PHONY</span><span style="color: #000000; ">:</span><span style="color: #000000; "> test clean all<br />all</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />    $(MAKE) </span><span style="color: #000000; ">-</span><span style="color: #000000; ">C $(KERNELDIR) M</span><span style="color: #000000; ">=</span><span style="color: #000000; ">$(PWD) modules<br />clean</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />    rm </span><span style="color: #000000; ">-</span><span style="color: #000000; ">rf </span><span style="color: #000000; ">*.</span><span style="color: #000000; ">o </span><span style="color: #000000; ">*~</span><span style="color: #000000; "> core </span><span style="color: #000000; ">.</span><span style="color: #000000; ">depend </span><span style="color: #000000; ">.*.</span><span style="color: #000000; ">cmd </span><span style="color: #000000; ">*.</span><span style="color: #000000; ">ko </span><span style="color: #000000; ">*.</span><span style="color: #000000; ">mod</span><span style="color: #000000; ">.</span><span style="color: #000000; ">c </span><span style="color: #000000; ">.</span><span style="color: #000000; ">tmp_versionsm </span><span style="color: #000000; ">*.</span><span style="color: #000000; ">order </span><span style="color: #000000; ">*.</span><span style="color: #000000; ">symvers<br /><br />test</span><span style="color: #000000; ">:</span><span style="color: #000000; "><br />    insmod </span><span style="color: #000000; ">./</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">.</span><span style="color: #000000; ">ko<br />    rmmod hello<br />    dmesg </span><span style="color: #000000; ">-</span><span style="color: #000000; ">c<br />    <br /></span><span style="color: #800000; ">5</span><span style="color: #000000; ">.</span><span style="color: #000000; ">好了</span><span style="color: #000000; ">,</span><span style="color: #000000; ">现在试开?/span><span style="color: #000000; ">,</span><span style="color: #000000; ">成功的话</span><span style="color: #000000; ">,</span><span style="color: #000000; ">可以看C面的文字?/span><span style="color: #000000; ">.</span><span style="color: #000000; "><br />如果有问题的?/span><span style="color: #000000; ">,</span><span style="color: #000000; ">向google大神h?/span><span style="color: #000000; ">.</span><span style="color: #000000; ">另外要看<br />root@</span><span style="color: #800000; ">192.168</span><span style="color: #000000; ">.</span><span style="color: #800000; ">20.128</span><span style="color: #000000; ">:~/</span><span style="color: #000000; ">cpp </span><span style="color: #008000; ">#</span><span style="color: #008000; "> make </span><span style="color: #008000; "><br /></span><span style="color: #000000; ">make </span><span style="color: #000000; ">-</span><span style="color: #000000; ">C </span><span style="color: #000000; ">/</span><span style="color: #000000; ">usr</span><span style="color: #000000; ">/</span><span style="color: #000000; ">src</span><span style="color: #000000; ">/</span><span style="color: #000000; ">linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; "> M</span><span style="color: #000000; ">=/</span><span style="color: #000000; ">root</span><span style="color: #000000; ">/</span><span style="color: #000000; ">cpp modules<br />make[</span><span style="color: #800000; ">1</span><span style="color: #000000; ">]</span><span style="color: #000000; ">:</span><span style="color: #000000; "> Entering directory `</span><span style="color: #000000; ">/</span><span style="color: #000000; ">usr</span><span style="color: #000000; ">/</span><span style="color: #000000; ">src</span><span style="color: #000000; ">/</span><span style="color: #000000; ">linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">headers</span><span style="color: #000000; ">-</span><span style="color: #800000; ">2.6</span><span style="color: #000000; ">.</span><span style="color: #800000; ">32</span><span style="color: #000000; ">-</span><span style="color: #800000; ">5</span><span style="color: #000000; ">-</span><span style="color: #800000; ">686</span><span style="color: #000000; font-weight: bold; ">'</span><span style="color: #000000; font-weight: bold; "><br />  CC [M]  /root/cpp/hello.o<br />  Building modules, stage 2.<br />  MODPOST 1 modules<br />  CC      /root/cpp/hello.mod.o<br />  LD [M]  /root/cpp/hello.ko<br />make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-5-686</span><span style="color: #000000; font-weight: bold; ">'</span><span style="color: #000000; "><br />root@</span><span style="color: #800000; ">192.168</span><span style="color: #000000; ">.</span><span style="color: #800000; ">20.128</span><span style="color: #000000; ">:~/</span><span style="color: #000000; ">cpp </span><span style="color: #008000; ">#</span><span style="color: #008000; "> make test</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">insmod </span><span style="color: #000000; ">./</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">.</span><span style="color: #000000; ">ko<br />rmmod hello<br />dmesg </span><span style="color: #000000; ">-</span><span style="color: #000000; ">c<br />[  </span><span style="color: #800000; ">673.500413</span><span style="color: #000000; ">] Hello</span><span style="color: #000000; ">,</span><span style="color: #000000; "> world<br />[  </span><span style="color: #800000; ">673.504907</span><span style="color: #000000; ">] Goodbye</span><span style="color: #000000; ">,</span><span style="color: #000000; "> cruel world<br />root@</span><span style="color: #800000; ">192.168</span><span style="color: #000000; ">.</span><span style="color: #800000; ">20.128</span><span style="color: #000000; ">:~/</span><span style="color: #000000; ">cpp </span><span style="color: #008000; ">#<br /></span><span style="color: #000000; "><br /><br /></span><span style="color: #800000; ">6</span><span style="color: #000000; ">.</span><span style="color: #000000; ">最?/span><span style="color: #000000; ">.</span><span style="color: #000000; ">安装开发帮助文?br />apt</span><span style="color: #000000; ">-</span><span style="color: #000000; ">get install </span><span style="color: #000000; ">-</span><span style="color: #000000; ">y manpages</span><span style="color: #000000; ">-</span><span style="color: #000000; ">kernel</span><span style="color: #000000; ">-</span><span style="color: #000000; ">dev linux</span><span style="color: #000000; ">-</span><span style="color: #000000; ">manual<br />man </span><span style="color: #800000; ">9</span><span style="color: #000000; "> printk<br />man </span><span style="color: #800000; ">9</span><span style="color: #000000; "> module_init<br /><br />参考资?/span><span style="color: #000000; ">:</span><span style="color: #000000; "> <br />http</span><span style="color: #000000; ">://</span><span style="color: #000000; ">bbs</span><span style="color: #000000; ">.</span><span style="color: #000000; ">chinaunix</span><span style="color: #000000; ">.</span><span style="color: #000000; ">net</span><span style="color: #000000; ">/</span><span style="color: #000000; ">thread</span><span style="color: #000000; ">-</span><span style="color: #800000; ">3570849</span><span style="color: #000000; ">-</span><span style="color: #800000; ">1</span><span style="color: #000000; ">-</span><span style="color: #800000; ">1</span><span style="color: #000000; ">.</span><span style="color: #000000; ">html</span></div> <img src ="http://www.shnenglu.com/aaxron/aggbug/159454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aaxron/" target="_blank">天下</a> 2011-11-01 14:24 <a href="http://www.shnenglu.com/aaxron/archive/2011/11/01/159454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.utql.cn" target="_blank">þ̳</a>| <a href="http://www.aystone.cn" target="_blank">þþƷ</a>| <a href="http://www.jituansms.cn" target="_blank">99þ㽶߿</a>| <a href="http://www.e-bizcard.cn" target="_blank">2020¾þþӾƷ</a>| <a href="http://www.zzxinwen.com.cn" target="_blank">AVþþþò</a>| <a href="http://www.ssc695.cn" target="_blank">þպƬ</a>| <a href="http://www.kzwn.net.cn" target="_blank">97þþƷ</a>| <a href="http://www.ed34.cn" target="_blank">þþƷþ˼˼</a>| <a href="http://www.ynymdp.cn" target="_blank">ھƷþþþù</a>| <a href="http://www.sobseo.cn" target="_blank">88þþƷһëƬ</a>| <a href="http://www.265zz.cn" target="_blank">þƵᆱƷ99㽶</a>| <a href="http://www.giep.cn" target="_blank">޹˾Ʒþþþþۺ </a>| <a href="http://www.leyuzhe.cn" target="_blank">ݺۺϾþۺ88</a>| <a href="http://www.0791gogo.cn" target="_blank">99þþƷѾƷһ </a>| <a href="http://www.fq2.com.cn" target="_blank">þݺҹҹ96׽ </a>| <a href="http://www.hgndg.cn" target="_blank">wwwþþcom</a>| <a href="http://www.node-js.cn" target="_blank">žžþ99ۺһ</a>| <a href="http://www.e-bizcard.cn" target="_blank">þþƷݲݲ</a>| <a href="http://www.sxxnjy.cn" target="_blank">Ӱ7777þþƷ</a>| <a href="http://www.0513act.cn" target="_blank">һaƬþëƬëƬ</a>| <a href="http://www.piaozen.cn" target="_blank">Ʒ˾þ˵Ӱ</a>| <a href="http://www.chazhaoyouhui.cn" target="_blank">þþžžþƷ</a>| <a href="http://www.zzjinshan.cn" target="_blank">vaþþþ</a>| <a href="http://www.znaw.cn" target="_blank">þӰۺ</a>| <a href="http://www.55542.com.cn" target="_blank">˾þþƷ鶹һ</a>| <a href="http://www.hotfan.cn" target="_blank">ˮϵþþƷ</a>| <a href="http://www.4wfgg.cn" target="_blank">һɫþ99һۺ</a>| <a href="http://www.vcdordvd.cn" target="_blank">ۺϾþøϾþúݺݺ97ɫ</a>| <a href="http://www.b5ezt1.cn" target="_blank">þþƷӰԺ</a>| <a href="http://www.0546bbs.cn" target="_blank">ƷžžþƵ</a>| <a href="http://www.malmoarts.cn" target="_blank">Ʒþþþþø69</a>| <a href="http://www.duansisi.cn" target="_blank">þþþþaëƬ</a>| <a href="http://www.himalayasmuseum.com.cn" target="_blank">þþƷAVӰԺ</a>| <a href="http://www.jiehuchong.cn" target="_blank">91ƷۺϾþþþþ</a>| <a href="http://www.job158.cn" target="_blank">պƷþĻ </a>| <a href="http://www.liaojieta.cn" target="_blank">þþwww</a>| <a href="http://www.hhh328.cn" target="_blank">99þþƷһ</a>| <a href="http://www.liushishipin.cn" target="_blank">ɫݺݾþۺ</a>| <a href="http://www.yy2b.cn" target="_blank">þAAAƬ69</a>| <a href="http://www.sz5111.cn" target="_blank">ɫþˬˬƬAV</a>| <a href="http://www.jxjiahegs.cn" target="_blank">˳վþ99ȹ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>