Interrupt%20Handling - PowerPoint PPT Presentation

About This Presentation
Title:

Interrupt%20Handling

Description:

... generate an interrupt. Generally waits for interrupt to be acknowledged ... Setting bit 4 of port 2 (0x37a or 0x27a) enables interrupt reporting (via outb call) ... – PowerPoint PPT presentation

Number of Views:246
Avg rating:3.0/5.0
Slides: 70
Provided by: csF2
Learn more at: http://www.cs.fsu.edu
Category:

less

Transcript and Presenter's Notes

Title: Interrupt%20Handling


1
Interrupt Handling
  • Ted Baker ? Andy Wang
  • CIS 4930 / COP 5641

2
Interrupts
  • Prevent CPUs from busy waiting
  • A signal that the hardware can send when it wants
    the CPUs attention
  • Need to pay attention to concurrency issues

3
Topics
  • Interrupt handling
  • Registration of handlers
  • Interaction with hardware
  • Limitations of handlers
  • Deregistration
  • Probing for interrupts
  • Tasklets and bottom halves
  • Interrupt sharing

4
Interrupt/Masking/Disabling/Blocking
  • Independent mechanisms exist at several levels
  • CPU
  • Can be set to ignore all interrupts
  • Interrupts stay pending until unmasked/unblocked
  • E.g., local_irq_disable
  • Software IRQ layer
  • Interrupt handled by common handler code
  • Handler not called if disabled
  • E.g., disable_irq_nosync

5
Interrupt/Masking/Disabling/Blocking
  • Interrupt controller
  • Sits between CPU and devices that generate
    interrupts
  • Can be instructed not to pass interrupts through
  • E.g., disable_8259A_irq
  • I/O device
  • Generates interrupts
  • May be instructed whether it is OK to generate an
    interrupt
  • Generally waits for interrupt to be acknowledged
    by CPU
  • E.g., see enabling of parallel port interrupt in
    short.c

6
Preparing the Parallel Port
  • Setting bit 4 of port 2 (0x37a or 0x27a) enables
    interrupt reporting (via outb call)
  • Once enabled, the parallel interface generates an
    interrupt whenever the electrical signal at pin
    10 (ACK bit) changes from low to high
    (edge-triggered)

7
Preparing the Parallel Port
  • Without a printer, one can connect pins 9 and 10
    of the parallel connector
  • Pin 9 is the most significant bit of the parallel
    data byte
  • Writing ASCII to /dev/short0 will not generate
    any interrupts
  • Writing a binary data will generate several
    interrupts

8
Installing an Interrupt Handler
  • Without a interrupt handler installed for an
    interrupt, Linux simply acknowledges and ignores
    it
  • Since interrupt lines are few, sharing is
    expected

9
Installing an Interrupt Handler
  • A good idea to initialize interrupt handlers when
    the device is first opened (vs. when a driver is
    initialized)
  • Before the hardware is instructed to generate
    interrupts
  • Many loaded modules are not used
  • Many devices are not used at the same time
  • Call free_irq in the last close
  • After the hardware is told not to create
    interrupts

10
Installing an Interrupt Handler
  • To register an interrupt handler, call
  • include ltlinux/interrupt.hgt
  • int request_irq(unsigned int irq,
  • irqreturn_t (handler) (int, void
    ,
  • struct
    pt_regs ),
  • unsigned long flags, const char
    dev_name,
  • void dev_id)
  • irq the requested interrupt number
  • handler the interrupt handler function pointer
  • dev_name for /proc/interrupts
  • dev_id pointer for shared interrupt lines (can
    be set to NULL if not shared)

11
Installing an Interrupt Handler
In 2.6.25, they are mapped to IRQF_DISABLED,
IRQF_SHARED, IRQF_SAMPLE_RANDOM
  • flags
  • SA_INTERRUPT indicates a fast interrupt handler
  • Interrupts are disabled on the current processor
  • SA_SHIRG signals that the interrupt can be shared
  • SA_SAMPLE_RANDOM indicates that the generated
    interrupts can contribute to generate random
    numbers (used by /dev/random and /dev/urandom)
  • To query the availability of an interrupt line
    (x86), call
  • int can_request_irq(unsigned int irq, unsigned
    long flags)
  • Returns nonzero on success (for that moment)

12
Installing an Interrupt Handler
  • The short example
  • if (short_irq gt 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 / enable it -- assume this is a
    parallel port /
  • outb(0x10,short_base2)

13
The /proc Interface
  • /proc/interrupts shows interrupts with installed
    handlers
  • CPU0 CPU1
  • 0 4848108 34 IO-APIC-edge timer
  • 2 0 0 XT-PIC cascade
  • 8 3 1 IO-APIC-edge rtc
  • 10 4335 1 IO-APIC-level aic7xxx
  • 11 8903 0 IO-APIC-level uhci_hcd
  • 12 49 1 IO-APIC-edge i8042
  • NMI 0 0
  • LOC 4848187 4848186
  • ERR 0
  • MIS 0

Device names
Programmable interrupt controllers
Linux handles interrupts on the first CPU to
maximize cache locality
14
The /proc Interface
  • /proc/stat shows number of interrupts received
    since system boot
  • Architecture dependent file format
  • Look for the intr string
  • intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406
    9291 50 0 0

Interrupt number 4 used 4907 times
Total number
15
Autodetecting the IRQ Number
  • A bad practice to require the user to specify the
    interrupt number
  • The user doesnt know any better
  • Might not be aware of the jumper settings
  • For many devices, autodetection depends on common
    default settings

16
Autodetecting the IRQ Number
  • The short example
  • if (short_irq lt 0) / not yet specified force
    the default on /
  • switch(short_base)
  • case 0x378 short_irq 7 break
  • case 0x278 short_irq 2 break
  • case 0x3bc short_irq 5 break
  • ...
  • The user can also override the default at load
    time
  • insmod ./short.ko irqx

17
Autodetecting the IRQ Number
  • The PCI standard requires devices to declare what
    interrupt line(s) they are going to use
  • Autodetection involves just probing the device
  • The driver tells the device to generate
    interrupts

18
Kernel-assisted Probing
  • Works for nonshared interrupts
  • Consists of two functions
  • include ltlinux/interrupt.hgt
  • / returns a bit mask of unassigned interrupts /
  • unsigned long probe_irq_on(void)
  • / called after the device has requested an
    interrupt /
  • / returns 0 if no interrupts occurred /
  • / returns the IRQ number if only one interrupt
    occurred /
  • / returns a negative value if multiple
    interrupts occurred /
  • int probe_irq_off(unsigned long)

19
Kernel-assisted Probing
  • The short example
  • int count 0
  • do
  • unsigned long mask
  • mask probe_irq_on()
  • outb_p(0x10,short_base2) / enable reporting
    /
  • outb_p(0x00,short_base) / clear the bit /
  • outb_p(0xFF,short_base) / set the bit
    interrupt! /
  • outb_p(0x00,short_base2) / disable reporting
    /
  • udelay(5) / give it some time /
  • short_irq probe_irq_off(mask)
  • if (short_irq 0) / none of them? /
  • printk(KERN_INFO "short no irq reported by
    probe\n")
  • short_irq -1
  • while (short_irq lt 0 count lt 5)

20
Kernel-assisted Probing
  • if (short_irq lt 0)
  • printk("short probe failed i times, giving
    up\n", count)
  • Probing can be a lengthy task
  • Frame grabber requires a delay of at least 20 ms
  • Probe one interrupt one at a time
  • Probing is not necessary for certain platforms
    (PowerPC, MIPS, and SPARC)

21
Do-it-yourself Probing
  • The short example performs do-it-yourself probing
    with probe2
  • Probe only commonly used IRQs
  • void short_selfprobe(void)
  • int trials 3, 5, 7, 9, 0
  • int tried 0, 0, 0, 0, 0
  • int i, count 0
  • for (i 0 trialsi i) / install the
    probing handler /
  • / request_irq returns 0 on success or EBUSY
    /
  • triedi request_irq(trialsi,
    short_probing,
  • SA_INTERRUPT, "short probe", NULL)

0 is the termination marker
22
Do-it-yourself Probing
  • do
  • short_irq 0 / none got, yet /
  • outb_p(0x10,short_base2) / enable /
  • outb_p(0x00,short_base)
  • outb_p(0xFF,short_base) / toggle the bit /
  • outb_p(0x00,short_base2) / disable /
  • udelay(5) / see if short_probing is invoked
    /
  • / the value has been set by the handler /
  • if (short_irq 0) / none of them? /
  • printk(KERN_INFO "short no irq reported by
    probe\n")
  • / short_irq lt 0 if multiple lines are
    activated /
  • while (short_irq lt0 count lt 5)

23
Do-it-yourself Probing
  • / end of loop, uninstall the handler /
  • for (i 0 trialsi i)
  • if (triedi 0)
  • free_irq(trialsi, NULL)
  • if (short_irq lt 0)
  • printk("short probe failed i times, giving
    up\n", count)
  • 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

24
Do-it-yourself Probing
  • Without knowing the commonly used IRQs
  • Needs to probe IRQ 0 to IRQ NR_IRQS 1
  • NR_IRQS defined in ltasm/irq.hgt

25
Fast and Slow Handlers
  • Fast interrupts are requested with the
    SA_INTERRUPT flag (e.g., timer interrupt)
  • Disables all other interrupts on the current CPU
  • Other CPUs can still handle interrupts
  • No two CPUs handle the same IRQ at the same time
  • Slow interrupts have other interrupts enabled

26
The Internals of Interrupt Handling on x86
  • arch/i386/kernel/entry.S contains
    ENTRY(interrupt)
  • Jumps to do_IRQ in arch/i386/kernel/irq.c
  • Prevents other CPUs from handling this IRQ
  • Calls the particular handler
  • If there is no handler, return
  • If a device is interrupting
  • Call handle_IRQ_event in arch/i386/kernel/irq/hand
    le.c

27
Implementing a Handler
  • Cannot transfer data to and from user space
  • Cannot sleep
  • Cannot call schedule, wait_event, down
  • Can only use GFP_ATOMIC to allocate memory
  • Might need to clear a bit on the interface board
  • Allows subsequent interrupts to be received

28
Implementing a Handler
  • Wakes up processes waiting for the interrupt
  • The frame grabber example
  • Read blocks while waiting for a frame
  • The interrupt handler wakes up the process as
    each new frame arrives
  • The handler needs to execute in a minimum amount
    of time
  • Uses tasklet or workqueue to schedule computation

29
Implementing a Handler
  • The short example
  • irqreturn_t short_interrupt(int irq, void
    dev_id,
  • struct pt_regs regs)
  • struct timeval tv
  • int written
  • 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)
  • return IRQ_HANDLED

This argument is removed in 2.6.21
30
Implementing a Handler
Variable can be accessed externally at any time
  • static inline void short_incr_bp(volatile
    unsigned long index,
  • int delta)
  • unsigned long new index delta
  • barrier() / Don't optimize these two together
    /
  • index
  • (new gt (short_buffer PAGE_SIZE)) ?
    short_buffer new
  • Without barrier
  • static inline void short_incr_bp(volatile
    unsigned long index,
  • int delta)
  • index index delta / could expose an
    incorrect value /
  • if (index gt (short_buffer PAGE_SIZE))
  • index short_buffer

31
Implementing a Handler
  • To read the buffer, use /dev/shortint
  • ssize_t short_i_read(struct file filp, char
    __user buf,
  • size_t count, loff_t f_pos)
  • int count0
  • DEFINE_WAIT(wait)
  • while (short_head short_tail)
  • prepare_to_wait(short_queue, wait,
    TASK_INTERRUPTIBLE)
  • if (short_head short_tail)
  • schedule()
  • finish_wait(short_queue, wait)
  • if (signal_pending(current)) / a signal
    arrived /
  • return -ERESTARTSYS / tell the fs layer
    to handle it /

32
Implementing a Handler
  • / count0 is the number of readable data bytes
    /
  • count0 short_head - short_tail
  • if (count0 lt 0) / wrapped /
  • count0 short_buffer PAGE_SIZE -
    short_tail
  • if (count0 lt count)
  • count count0
  • if (copy_to_user(buf, (char )short_tail,
    count))
  • return -EFAULT
  • short_incr_bp(short_tail, count) / wrap the
    tail pointer /
  • return count

33
Implementing a Handler
  • To raise interrupts
  • Connect pins 9 and 10 of the parallel connector
  • Write to /dev/shortint
  • Which alternately writes 0x00 and 0xff to the
    parallel port
  • An interrupt is raised whenever the electrical
    signal at pin 10 (ACK bit) changes from low to
    high

34
Implementing a Handler
  • To write to /dev/shortint
  • ssize_t short_i_write(struct file filp, const
    char __user buf,
  • size_t count, loff_t
    f_pos)
  • int written 0, odd f_pos 1
  • unsigned long port short_base
  • void address (void ) short_base
  • if (use_mem) / memory-mapped /
  • while (written lt count)
  • iowrite8(0xff((written odd) 1),
    address)
  • else
  • while (written lt count)
  • outb(0xff((written odd) 1), port)
  • f_pos count
  • return written

35
Implementing a Handler
  • Without connecting pins 9 and 10
  • Use /dev/shortprint to drive a printer

36
Handler Arguments and Return Value
  • Typical use of the argument in an interrupt
    handler
  • 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
    /
  • / .... /
  • irq for printk
  • dev_id for finding out which instance of device
    is in charge of the current interrupt event

37
Handler Arguments and Return Value
  • pt_regs holds the snapshot of the processors
    context before running the interrupt code
    (linux/include/asm-i386/ptrace.h)
  • Returns IRQ_HANDLED if the device needs
    attention otherwise, returns IRQ_NONE
  • Typical open code
  • static void sample_open(struct inode inode,
    struct file filp)
  • struct sample_dev dev hwinfo
    MINOR(inode-gti_rdev)
  • request_irq(dev-gtirq, sample_interrupt, 0 /
    flags /,
  • "sample", dev / dev_id /)
  • /..../
  • return 0

38
Enabling and Disabling Interrupts
  • Often, interrupts must be blocked while holding a
    spinlock to avoid deadlocks
  • Also, there are ways of disabling interrupts that
    do not involve spinlocks
  • Should not be used within a driver

39
Disabling a Single Interrupt
  • Three functions
  • Their use is discouraged
  • Cannot disable shared interrupt lines
  • include ltasm/irq.hgt
  • void disable_irq(int irq)
  • void disable_irq_nosync(int irq)
  • void enable_irq(int irq)
  • Calls can be nested
  • If disable_irq is called twice, two enable_irq
    calls are required to reenable the IRQ

40
Disabling a Single Interrupt
  • The calling thread of the disable_irq should not
    hold resource needed by the current interrupt to
    complete
  • disable_irq_nosync returns immediately
  • Need to handle potential race conditions
  • Why disabling interrupts?
  • Sometimes to reduce the performance overhead

41
Disabling All Interrupts
  • To disable all interrupts on the current CPU,
    call either one
  • include ltasm/system.hgt
  • / disables interrupts after saving the current
    interrupt state into flags /
  • void local_irq_save(unsigned long flags)
  • / shuts off interrupts without saving the state
    /
  • void local_irq_disable(void)
  • Avoid doing this when possible
  • Almost never use local_irq_disable

42
Disabling All Interrupts
  • To enable all interrupts on the current CPU, call
    the corresponding function
  • include ltasm/system.hgt
  • void local_irq_restore(unsigned long flags)
  • / does not keep track multiple calls /
  • void local_irq_enable(void)

43
Top and Bottom Halves
  • Interrupt handling sometimes needs to perform
    lengthy tasks
  • This problem is resolved by splitting the
    interrupt handler into two halves
  • Top half responds to the interrupt
  • The one registered to request_irq
  • Saves data to device-specific buffer and
    schedules the bottom half
  • Bottom half is scheduled by the top half to
    execute later
  • With all interrupts enabled
  • Wakes up processes, starts I/O operations, etc.

44
Top and Bottom Halves
  • Two mechanisms may be used to implement bottom
    halves
  • Tasklets
  • No sleep
  • Workqueues
  • Can sleep

45
Tasklets
  • Cannot run in parallel with itself
  • Can run in parallel with other tasklets on SMP
    systems
  • Guaranteed to run on the same CPU that first
    scheduled them

46
Tasklets
  • In the short example, use tasklet1 to install
    the tasklet-based interrupt handler
  • 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)
  • / cast to stop 'volatile' warning /
  • do_gettimeofday((struct timeval ) tv_head)
  • short_incr_tv(tv_head)
  • tasklet_schedule(short_tasklet)
  • short_wq_count / record that an interrupt
    arrived /
  • return IRQ_HANDLED

47
Tasklets
  • void short_do_tasklet (unsigned long unused)
  • int savecount short_wq_count, written
  • short_wq_count 0 / number of interrupts
    before this call /
  • written sprintf((char )short_head,
  • "bh after 6i\n",savecount)
  • short_incr_bp(short_head, written)
  • do / write the time values /
  • written sprintf((char )short_head,"08u.06
    u\n",
  • (int)(tv_tail-gttv_sec
    100000000),
  • (int)(tv_tail-gttv_usec))
  • short_incr_bp(short_head, written)
  • short_incr_tv(tv_tail)
  • while (tv_tail ! tv_head)
  • wake_up_interruptible(short_queue)

48
Workqueues
  • Can sleep
  • Cannot copy data to and from user space

49
Workqueues
  • In the short example, set wq1 to install the
    workqueue-based interrupt handler
  • static struct work_struct short_wq
  • / this line is in the 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)
  • do_gettimeofday((struct timeval ) tv_head)
  • short_incr_tv(tv_head)
  • schedule_work(short_wq)
  • short_wq_count / record that an interrupt
    arrived /
  • return IRQ_HANDLED

50
Interrupt Sharing
  • Installing a shared handler
  • Set SA_SHIRQ flag when requesting the interrupt
  • The dev_id must be unique
  • Cannot be NULL
  • Returns IRQ_NONE if the handler is not the target
    handler
  • request_irq suceeds if
  • The interrupt line is free
  • All handlers registered agree to share

51
Interrupt Sharing
  • When an interrupt arrives, the kernel invokes
    every handler registered for that interrupt
  • The handler must be able to recognize its own
    interrupts
  • No probing function is available for shared
    handlers
  • Most hardware designed for interrupt sharing can
    tell the CPU which interrupt it is using
  • No need for explicit probing

52
Interrupt Sharing
  • free_irq needs the correct dev_id
  • Watch out for enable_irq and disable_irq
  • Not a good idea to disable other devices
    interrupts
  • Does not work well with edge-triggered interrupts
  • Interrupts from other devices may be lost while
    one device is holding the line active

53
Running a Handler
  • In the short example, use shared1 to install a
    shared interrupted handler
  • 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)

Check the most significant bit
54
Running a Handler
  • / 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)
  • return IRQ_HANDLED
  • Assumes that pins 9 and 10 are connected
  • The example would not work for printers, since
    the printer protocol disallow sharing

55
The /proc Interface and Shared Interrupts
  • Check /proc/interrupts
  • CPU0
  • 0 892335412 XT-PIC timer
  • 1 453971 XT-PIC i8042
  • 2 0 XT-PIC cascade
  • 5 0 XT-PIC libata, ehci_hcd
  • 8 0 XT-PIC rtc
  • 9 0 XT-PIC acpi
  • 10 11365067 XT-PIC ide2, uhci_hcd, uhci_hcd,
    SysKonnect
  • 11 4391962 XT-PIC uhci_hcd, uhci_hcd
  • 12 224 XT-PIC i8042
  • 14 2787721 XT-PIC ide0
  • 15 203048 XT-PIC ide1
  • NMI 41234

56
Interrupt-Driven I/O
  • Buffering improves performance
  • Also leads to interrupt-driven I/O
  • Input buffer is filled at interrupt time
  • Emptied by the read processes
  • Output buffer is filled by write processes
  • Emptied at interrupt time
  • Hardware generates interrupts when
  • New data has arrives and is ready for retrieval
  • When it is ready to accept new data or to
    acknowledge a successful data transfer

57
A Write-Buffering Example
  • The write function calls shortp_write()
  • Calls shortp_start_output()
  • Schedules a timer that calls shortp_timeout()
  • Calls either shortp_timeout() or
    shortp_interrupt()
  • Schedules shortp_do_work()
  • Calls shortp_do_write() to write individual
    characters
  • The printer calls shortp_interrupt()
  • Schedules shortp_do_work()

58
A Write-Buffering Example
write()
59
A Write-Buffering Example
  • The shortprint example maintains a one-page
    circular output buffer
  • A write system call only writes data to the
    buffer
  • The actual write is scheduled later
  • static size_t shortp_write(struct file filp,
  • const char __user
    buf,
  • size_t count, loff_t
    f_pos)
  • int space, written 0
  • unsigned long flags
  • if (down_interruptible(shortp_out_sem))
  • return ERESTARTSYS

60
A Write-Buffering Example
  • while (written lt count)
  • / Hang out until some buffer space is
    available. /
  • space shortp_out_space()
  • if (space lt 0)
  • if (wait_event_interruptible(shortp_out_queu
    e,
  • (space
    shortp_out_space())
  • gt 0))
  • goto out
  • ...

61
A Write-Buffering Example
  • / Move data into the buffer. /
  • if ((space written) gt count)
  • space count - written
  • if (copy_from_user((char ) shortp_out_head,
    buf, space))
  • up(shortp_out_sem)
  • return -EFAULT
  • shortp_incr_out_bp(shortp_out_head, space)
  • buf space
  • written space
  • ...

62
A Write-Buffering Example
  • / If no output is active, make it active. /
  • spin_lock_irqsave(shortp_out_lock, flags)
  • if (!shortp_output_active)
  • shortp_start_output()
  • spin_unlock_irqrestore(shortp_out_lock,
    flags)
  • out
  • f_pos written
  • up(shortp_out_sem)
  • return written

63
shortp_start_output
  • static DECLARE_WORK(shortp_work, shortp_do_work,
    NULL)
  • static struct workqueue struct shortp_workqueue
  • static void shortp_start_output(void)
  • if (shortp_output_active) / Should never
    happen /
  • return
  • / Set up a timer to handle occasionally missed
    interrupts /
  • shortp_output_active 1
  • shortp_timer.expires jiffies TIMEOUT
  • add_timer(shortp_timer) / calls
    shortp_timeout /
  • / And get the process going. /
  • queue_work(shortp_workqueue, shortp_work)

64
shortp_do_work
  • static void shortp_do_work(void unused)
  • int written
  • unsigned long flags
  • shortp_wait() / wait until the device is
    ready /
  • spin_lock_irqsave(shortp_out_lock, flags)
  • / Have we written everything? /
  • if (shortp_out_head shortp_out_tail) /
    empty /
  • shortp_output_active 0
  • wake_up_interruptible(shortp_empty_queue)
  • del_timer(shortp_timer)
  • else / Nope, write another byte /
  • shortp_do_write()

65
shortp_do_work
  • / If somebody's waiting, wake them up if
    enough space. /
  • if (((PAGE_SIZE shortp_out_tail -
    shortp_out_head)
  • PAGE_SIZE) gt SP_MIN_SPACE)
  • wake_up_interruptible(shortp_out_queue)
  • spin_unlock_irqrestore(shortp_out_lock,
    flags)

66
shortp_do_write
  • static void shortp_do_write(void)
  • unsigned char cr inb(shortp_base
    SP_CONTROL)
  • / Reset the timer /
  • mod_timer(shortp_timer, jiffies TIMEOUT)
  • / Strobe a byte out to the device /
  • outb_p(shortp_out_tail, shortp_baseSP_DATA)
  • shortp_incr_out_bp(shortp_out_tail, 1)
  • if (shortp_delay) udelay(shortp_delay)
  • outb_p(cr SP_CR_STROBE, shortp_baseSP_CONTROL
    )
  • if (shortp_delay) udelay(shortp_delay)
  • outb_p(cr SP_CR_STROBE, shortp_baseSP_CONTRO
    L)

67
shortp_interrupt
  • 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

68
shortp_timtout
  • static void shortp_timeout(unsigned long unused)
  • unsigned long flags
  • unsigned char status
  • if (!shortp_output_active)
  • return
  • spin_lock_irqsave(shortp_out_lock, flags)
  • status inb(shortp_base SP_STATUS)

69
shortp_timtout
  • / If the printer is still busy we just reset
    the timer /
  • if ((status SP_SR_BUSY) 0 (status
    SP_SR_ACK))
  • shortp_timer.expires jiffies TIMEOUT
  • add_timer(shortp_timer)
  • spin_unlock_irqrestore(shortp_out_lock,
    flags)
  • return
  • / Otherwise we must have dropped an interrupt.
    /
  • spin_unlock_irqrestore(shortp_out_lock,
    flags)
  • shortp_interrupt(shortp_irq, NULL, NULL)
Write a Comment
User Comments (0)
About PowerShow.com