亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2009 | 回復(fù): 1
打印 上一主題 下一主題

ldd3 read note Capter 10 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2009-08-06 09:33 |只看該作者 |倒序?yàn)g覽

                    
   
   
           
2009.7.2
CHAPTER 10   Interrupt Handling
并口中斷

口中斷的作用是讓打印機(jī)可以通知lp驅(qū)動, 已經(jīng)做好接受下一個(gè)字符的準(zhǔn)備.port2的bit 4  (0x37a,0x27a)是中斷使能. 位.
一但中斷使能后, 當(dāng)pin10 (status port bit 6) (ACK bit) 從low變成high, 就會觸發(fā)一個(gè)中斷.

最簡單的辦法就是吧pin9 和 pin 10 鏈接起來. 然后可以向 /dev/short0寫入二進(jìn)制數(shù)據(jù)來觸發(fā)中斷(注意,ascii不成, ascii最高bit都是0).
*
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *dev_name, void *dev_id); //返回0代表成功, 負(fù)值代表失敗
//dev_id是共享中斷的時(shí)候使用的,建議無論共享與否,都把它指向device structure
flag:
SA_INTERRUPT : 中斷過程中禁止其他中斷
SA_SHIRQ : 中斷可以被共享
SA_SAMPLE_RANDOM : 可以給/dev/random and /dev/urandom貢獻(xiàn)熵.(中斷時(shí)間不確定)
void free_irq(unsigned int irq, void *dev_id);

果不能共享中斷, 在模塊初始化的時(shí)候安裝中斷并不是一個(gè)好注意, 這樣有時(shí)候會浪費(fèi)中斷資源. 最好在第一次打開的時(shí)候(在中斷產(chǎn)生前)掛接中斷,
在最后一次釋放后釋放中斷. 但是自己要有統(tǒng)計(jì)計(jì)數(shù). (short呢,不在open內(nèi)申請中斷, 而是在初始化的時(shí)候)
if (short_irq >= 0) {
   result = request_irq(short_irq, short_interrupt,
   SA_INTERRUPT, "short", NULL);
   if (result) {
       printk(KERN_INFO "short: can't get assigned irq %i\n",short_irq);
       short_irq = -1;
   }
   else { /* actually enable it -- assume this *is* a parallel port */
            outb(0x10,short_base+2);
   }
}
int can_request_irq(unsigned int irq, unsigned long flags); //是否被占用
一般情況下kernel總是嘗試cpu0處理中斷(一般情況下是cpu0處理中斷),保證cach locality.
/proc/interrupts   #體系結(jié)構(gòu)無關(guān)
cat /proc/stat     #特定體系結(jié)構(gòu)
intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406 9291 50 0 0
/proc/stat 這個(gè)intr的統(tǒng)計(jì)是統(tǒng)計(jì)所有中斷歷史次數(shù). 而/proc/interrupts則沒有當(dāng)前未使用的中斷的統(tǒng)計(jì).
Autodetecting the IRQ Number
*short操控的LPT還是有默認(rèn)值可以用的.
if (short_irq
unsigned long probe_irq_on(void); //返回一個(gè)未分配的中斷位圖
產(chǎn)生一個(gè)中斷,(記著要關(guān)閉.)
int probe_irq_off(unsigned long); //傳入未分配中斷位圖, 返回>0是探測到的irq, =0是沒有中斷,

irqreturn_t short_probing(int irq, void *dev_id, struct pt_regs *regs)
{
   if (short_irq = = 0) short_irq = irq; /* found */
   if (short_irq != irq) short_irq = -irq; /* ambiguous */
   return IRQ_HANDLED;
}
Fast and Slow Handlers
SA_INTERRUPT: 禁止其他中斷. 建議快速處理的中斷使用.(這時(shí),其他cpu還是可以處理其他中斷的). 除非理由充分,不要用這個(gè)標(biāo)記.
Implementing a Handler
*不能訪問user space
*不能睡眠(不能lock, 不能kmalloc without GFP_ATOMIC)
*不能調(diào)用schedule
中斷任務(wù),開始是處理..., 最后如果設(shè)備有 interrupt pending bit, 要clear掉,否則不會產(chǎn)生下一個(gè)中斷. 但是并口是沒有pending的不用ack設(shè)備.
一個(gè)中斷的典型任務(wù)就是喚醒在隊(duì)列上等待數(shù)據(jù)的進(jìn)程. 如果需要大量計(jì)算, 還是推遲到tasklet或者workqueue吧.


沒有barrier, 編譯器會把new直接優(yōu)化掉, 直接更新index,然后再根據(jù)條件調(diào)整index. 這樣就有一個(gè)窗口, index的值是錯(cuò)誤的. 這個(gè)也算是lock free了.
short提供/dev/shortprint可以驅(qū)動一個(gè)真正的打印機(jī).
Handler Arguments and Return Value
irq, reg就不提了. dev_id就是request的時(shí)候傳入的. 如果共享中斷的設(shè)備, 這個(gè)dev_id可以指向device結(jié)構(gòu). 中斷里就可以直接訪問這個(gè)個(gè)結(jié)構(gòu)了.
static irqreturn_t sample_interrupt(int irq, void *dev_id, struct pt_regs
*regs)
{
   struct sample_dev *dev = dev_id;
   /* now `dev' points to the right hardware item */
   /* .... */
}
static void sample_open(struct inode *inode, struct file *filp)
{
  struct sample_dev *dev = hwinfo + MINOR(inode->i_rdev);
  request_irq(dev->irq, sample_interrupt,
   0  /* flags */, "sample", dev /* dev_id */);
  /*....*/
  return 0;
}
如果確實(shí)是設(shè)備發(fā)生中斷, 需要返回IRQ_HANDLED,否則返回IRQ_NONE. 有個(gè)宏可以利用: IRQ_RETVAL(handled)
如果不知道是否是自己設(shè)備產(chǎn)生的,就返回IRQ_HANDLED.
Enabling and Disabling Interrupts
禁止中斷不是互斥手段,極少使用. driver用spinlock的時(shí)候一般要禁止中斷,以免造成死鎖(肯定是和進(jìn)程/softirq用同一個(gè)spin了...).
Disabling a single interrupt
禁止什么中斷都極少用.特別是共享中斷,這么做是不成的.
*
void disable_irq(int irq);
void disable_irq_nosync(int irq);
void enable_irq(int irq);

以嵌套使用,兩次disable需要兩次enable...., 這些函數(shù)操作PIC/APIC來禁止單個(gè)中斷pin. disable
irq會等待當(dāng)前正在運(yùn)行的中斷. 如果進(jìn)程在持有資源的的情況下(如spin), 調(diào)用這個(gè)函數(shù),可能引起死鎖.
disable_irq_nosync 不會等待, 但是仍有部分競爭窗口存在.
plip 的例子
plip device 使用串口模擬網(wǎng)卡.  在接受報(bào)文的時(shí)候禁止中斷.  有個(gè)模式的plip最多一次接受5bit(因?yàn)榇蛴C(jī)電纜的原因),有一個(gè)bit作為handshake. 下圖是這種NULL電纜.

接受數(shù)據(jù)和組合niblle參考plip_receive() (當(dāng)然從status寄存器中讀取數(shù)據(jù)了). 在NB0和NB1的數(shù)據(jù)有效bit是不同的,一切為了寫程序方便.
發(fā)送的時(shí)候第一次觸發(fā)對方的ack, 然后發(fā)送nb的時(shí)候中斷被禁止, ack作為數(shù)據(jù)的一個(gè)bit.
Disabling all interrupts
void local_irq_save(unsigned long flags);
void local_irq_disable(void);
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
在2.6中全系統(tǒng)的中斷什么時(shí)候都不能關(guān)閉....
Top and Bottom Halves

典型的top half 將數(shù)據(jù)存入設(shè)備的buffer,然后調(diào)度后半部分就結(jié)束了. bottom部分做喚醒進(jìn)程, 開始下次io的各種工作. bottom有兩種技術(shù), tasklet和workqueu. 前者必須全程atomic,后者容許睡眠.
Tasklets
*多次調(diào)度一次運(yùn)行(在運(yùn)行前)
*在一個(gè)軟中斷環(huán)境中運(yùn)行
*同一個(gè)tasklet不會同時(shí)運(yùn)行
*可以和另一個(gè)tasklet同時(shí)運(yùn)行
*和調(diào)度的cpu在同一個(gè)cpu運(yùn)行: 中斷不會被自己的tasklet打斷, 但是tasklet可以被自己的中斷打斷
void short_do_tasklet(unsigned long);DECLARE_TASKLET(short_tasklet, short_do_tasklet, 0);irqreturn_t short_tl_interrupt(int irq, void *dev_id, struct pt_regs *regs){    do_gettimeofday((struct timeval *) tv_head); /* cast to stop 'volatile' warning */    short_incr_tv(&tv_head);    tasklet_schedule(&short_tasklet);    short_wq_count++; /* record that an interrupt arrived */    return IRQ_HANDLED;}void short_do_tasklet (unsigned long unused){   int savecount = short_wq_count, written;   short_wq_count = 0; /* we have already been removed from the queue */  /*   * The bottom half reads the tv array, filled by the top half,   * and prints it to the circular text buffer, which is then consumed   * by reading processes   */   /* First write the number of interrupts that occurred before this bh */   written = sprintf((char *)short_head,"bh after %6i\n",savecount);   short_incr_bp(&short_head, written);   /*   * Then, write the time values. Write exactly 16 bytes at a time,   * so it aligns with PAGE_SIZE   */   do {      written = sprintf((char *)short_head,"%08u.%06u\n",     (int)(tv_tail->tv_sec % 100000000),      (int)(tv_tail->tv_usec));      short_incr_bp(&short_head, written);       short_incr_tv(&tv_tail); //   } while (tv_tail != tv_head);   wake_up_interruptible(&short_queue); /* awake any reading process */}

Workqueues

*運(yùn)行在一個(gè)特殊內(nèi)核進(jìn)程
*不能訪問user space
static struct work_struct short_wq;
/* this line is in short_init( ) */
INIT_WORK(&short_wq, (void (*)(void *)) short_do_tasklet, NULL);
irqreturn_t short_wq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
  /* Grab the current time information. */
   do_gettimeofday((struct timeval *) tv_head);
   short_incr_tv(&tv_head);
  /* Queue the bh. Don't worry about multiple enqueueing */
   schedule_work(&short_wq);
   short_wq_count++; /* record that an interrupt arrived */
   return IRQ_HANDLED;
}

Interrupt Sharing

PCI需要共享中斷, linux提供了在所有bus上共享中斷的手段,在ISA上也提供了共享.
*必須傳遞SA_SHIRQ
*dev_id必須唯一, 在共享的情況下為NULL顯然不合適
*在中斷是無人使用或者大家都是共享的情況下可以注冊成功
*需要快速判斷是不是自己設(shè)備產(chǎn)生了中斷, 不是則返回IRQ_NONE(每個(gè)共享的handler都得到調(diào)用)
*共享中斷不能使用內(nèi)核提供的機(jī)制進(jìn)行probe, 不過這種不能提供irq卻要共享的硬件似乎沒有
*不要禁止irq, 這個(gè)irq不是你自己的了
irqreturn_t short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
  int value, written;
  struct timeval tv;
   /* If it wasn't short, return immediately */
   value = inb(short_base);
   if (!(value & 0x80))
       return IRQ_NONE;
   /* clear the interrupting bit */
    outb(value & 0x7F, short_base); //假定9,10pin被跳線短接
   /* the rest is unchanged */
   do_gettimeofday(&tv);
   written = sprintf((char *)short_head,"%08u.%06u\n",
   (int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));
   short_incr_bp(&short_head, written);
   wake_up_interruptible(&short_queue); /* awake any reading process */
   return IRQ_HANDLED;
}
注意: 真正的打印機(jī)不能辨識是否自己發(fā)出了中斷, 不支持中斷共享.
Interrupt-Driven I/O
driver buffer 可以隔離read/write和真正的數(shù)據(jù)接受.一個(gè)中斷驅(qū)動的io,設(shè)備應(yīng)該有如下能力:
*在數(shù)據(jù)到達(dá)可以被cpu接受的時(shí)候發(fā)出中斷, 然后使用io/內(nèi)存映射或者DMA來進(jìn)行數(shù)據(jù)傳輸.
*發(fā)送成功或者可以接受新的數(shù)據(jù)的時(shí)候發(fā)出中斷.
shortprint driver

*shortprint driver maintains a one-page circular output buffer
*write 函數(shù)不進(jìn)行任何I/O, 只是吧數(shù)據(jù)寫入上述buffer
shortp_write core:
*有sem 保護(hù)這段代碼
*使用workqueue向設(shè)備發(fā)送數(shù)據(jù), 訪問shortp_output_active 用spinlock來保護(hù).

static void shortp_start_output(void)
{
   if (shortp_output_active) /* Should never happen */
     return;
   /* Set up our 'missed interrupt' timer */
   shortp_output_active = 1;
   shortp_timer.expires = jiffies + TIMEOUT;
   add_timer(&shortp_timer);
   /* And get the process going. */
   queue_work(shortp_workqueue, &shortp_work);
}
*中斷有可能丟失, 用了一個(gè);顃imer
下面代碼是workqueue core:


下面是寫一個(gè)字符到打印機(jī)

static irqreturn_t shortp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
  if (! shortp_output_active)
       return IRQ_NONE;
   /* Remember the time, and farm off the rest to the workqueue function */
   do_gettimeofday(&shortp_tv);
   queue_work(shortp_workqueue, &shortp_work);
   return IRQ_HANDLED;
}

               
               
               
               
               

本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/79526/showart_2019289.html

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2014-05-23 07:33 |只看該作者
請問你運(yùn)行過這個(gè)程序嗎? 能產(chǎn)生中斷嗎?
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP