| // Copyright 2016 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #ifndef ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_ |
| #define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_ |
| |
| #include <sys/types.h> |
| #include <zircon/rights.h> |
| #include <zircon/types.h> |
| |
| #include <kernel/event.h> |
| #include <kernel/spinlock.h> |
| #include <object/dispatcher.h> |
| #include <object/port_dispatcher.h> |
| #include <object/vcpu_dispatcher.h> |
| |
| enum class InterruptState { |
| WAITING = 0, |
| DESTROYED = 1, |
| TRIGGERED = 2, |
| NEEDACK = 3, |
| IDLE = 4, |
| }; |
| |
| // Note that unlike most Dispatcher subclasses, this one is further |
| // subclassed, and so cannot be final. |
| class InterruptDispatcher |
| : public SoloDispatcher<InterruptDispatcher, ZX_DEFAULT_INTERRUPT_RIGHTS> { |
| public: |
| InterruptDispatcher& operator=(const InterruptDispatcher&) = delete; |
| zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_INTERRUPT; } |
| uint32_t get_flags() const { return flags_; } |
| |
| zx_status_t WaitForInterrupt(zx_time_t* out_timestamp); |
| zx_status_t Trigger(zx_time_t timestamp); |
| zx_status_t Ack(); |
| zx_status_t Destroy(); |
| void InterruptHandler(); |
| zx_status_t Bind(fbl::RefPtr<PortDispatcher> port_dispatcher, uint64_t key); |
| zx_status_t Unbind(fbl::RefPtr<PortDispatcher> port_dispatcher); |
| virtual zx_status_t BindVcpu(fbl::RefPtr<VcpuDispatcher> vcpu_dispatcher) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| |
| void on_zero_handles() final; |
| |
| protected: |
| virtual void MaskInterrupt() = 0; |
| virtual void UnmaskInterrupt() = 0; |
| virtual void DeactivateInterrupt() = 0; |
| virtual void UnregisterInterruptHandler() = 0; |
| virtual bool HasVcpu() const TA_REQ(spinlock_) { return false; } |
| |
| InterruptDispatcher(); |
| void Signal() { event_.Signal(); } |
| zx_status_t set_flags(uint32_t flags); |
| bool SendPacketLocked(zx_time_t timestamp) TA_REQ(spinlock_); |
| bool HasPort() const TA_REQ(spinlock_) { return !!port_dispatcher_; } |
| InterruptState state() const TA_REQ(spinlock_) { return state_; } |
| |
| // Bits for Interrupt.flags |
| // The interrupt is virtual. |
| static constexpr uint32_t INTERRUPT_VIRTUAL = (1u << 0); |
| // The interrupt should be unmasked before waiting on the event. |
| static constexpr uint32_t INTERRUPT_UNMASK_PREWAIT = (1u << 1); |
| // The same as |INTERRUPT_UNMASK_PREWAIT| except release the dispatcher |
| // spinlock before waiting. |
| static constexpr uint32_t INTERRUPT_UNMASK_PREWAIT_UNLOCKED = (1u << 2); |
| // The interrupt should be masked following waiting. |
| static constexpr uint32_t INTERRUPT_MASK_POSTWAIT = (1u << 4); |
| |
| // Controls the access to Interrupt properties |
| DECLARE_SPINLOCK(InterruptDispatcher) spinlock_; |
| |
| private: |
| AutounsignalEvent event_; |
| // Interrupt Flags |
| uint32_t flags_; |
| |
| zx_time_t timestamp_ TA_GUARDED(spinlock_); |
| // Current state of the interrupt object |
| InterruptState state_ TA_GUARDED(spinlock_); |
| PortInterruptPacket port_packet_ TA_GUARDED(spinlock_) = {}; |
| fbl::RefPtr<PortDispatcher> port_dispatcher_ TA_GUARDED(spinlock_); |
| }; |
| |
| #endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_ |