1#![allow(non_camel_case_types)]
10
11use bitflags::bitflags;
12use core::ffi::{c_char, c_uchar};
13
14use crate::constants::*;
15use crate::{LogicalAddress, PhysicalAddress, Timestamp};
16
17#[derive(Debug, Clone)]
19#[repr(C)]
20pub struct cec_msg {
21 pub tx_ts: Timestamp,
24 pub rx_ts: Timestamp,
27 pub len: u32,
29 pub timeout: u32,
37 pub sequence: u32,
40 pub flags: CEC_MSG_FL,
42 pub msg: [u8; CEC_MAX_MSG_SIZE],
44 pub reply: u8,
63 pub rx_status: CEC_RX_STATUS,
65 pub tx_status: CEC_TX_STATUS,
67 pub tx_arb_lost_cnt: u8,
69 pub tx_nack_cnt: u8,
71 pub tx_low_drive_cnt: u8,
73 pub tx_error_cnt: u8,
75}
76
77bitflags! {
78 #[derive(Debug, Copy, Clone, Default)]
80 pub struct CEC_MSG_FL: u32 {
81 const REPLY_TO_FOLLOWERS = CEC_MSG_FL_REPLY_TO_FOLLOWERS;
82 const RAW = CEC_MSG_FL_RAW;
83 }
84}
85
86bitflags! {
87 #[derive(Debug, Copy, Clone)]
89 pub struct CEC_TX_STATUS: u8 {
90 const OK = CEC_TX_STATUS_OK;
91 const ARB_LOST = CEC_TX_STATUS_ARB_LOST;
92 const NACK = CEC_TX_STATUS_NACK;
93 const LOW_DRIVE = CEC_TX_STATUS_LOW_DRIVE;
94 const ERROR = CEC_TX_STATUS_ERROR;
95 const MAX_RETRIES = CEC_TX_STATUS_MAX_RETRIES;
96 const ABORTED = CEC_TX_STATUS_ABORTED;
97 const TIMEOUT = CEC_TX_STATUS_TIMEOUT;
98 }
99}
100
101bitflags! {
102 #[derive(Debug, Copy, Clone)]
104 pub struct CEC_RX_STATUS: u8 {
105 const OK = CEC_RX_STATUS_OK;
106 const TIMEOUT = CEC_RX_STATUS_TIMEOUT;
107 const FEATURE_ABORT = CEC_RX_STATUS_FEATURE_ABORT;
108 const ABORTED = CEC_RX_STATUS_ABORTED;
109 }
110}
111
112impl cec_msg {
113 #[inline]
115 #[must_use]
116 pub fn initiator(&self) -> u8 {
117 self.msg[0] >> 4
118 }
119
120 #[inline]
122 #[must_use]
123 pub fn destination(&self) -> u8 {
124 self.msg[0] & 0xf
125 }
126
127 #[inline]
129 #[must_use]
130 pub fn opcode(&self) -> Option<u8> {
131 if self.len > 1 {
132 Some(self.msg[1])
133 } else {
134 None
135 }
136 }
137
138 #[inline]
140 #[must_use]
141 pub fn is_broadcast(&self) -> bool {
142 (self.msg[0] & 0xf) == 0xf
143 }
144
145 #[inline]
154 #[must_use]
155 pub fn new(initiator: LogicalAddress, destination: LogicalAddress) -> cec_msg {
156 let mut msg = cec_msg {
157 tx_ts: 0,
158 rx_ts: 0,
159 len: 1,
160 timeout: 0,
161 sequence: 0,
162 flags: CEC_MSG_FL::empty(),
163 msg: [0; 16],
164 reply: 0,
165 rx_status: CEC_RX_STATUS::empty(),
166 tx_status: CEC_TX_STATUS::empty(),
167 tx_arb_lost_cnt: 0,
168 tx_nack_cnt: 0,
169 tx_low_drive_cnt: 0,
170 tx_error_cnt: 0,
171 };
172 msg.msg[0] = (initiator << 4) | destination;
173
174 msg
175 }
176
177 #[inline]
178 #[must_use]
179 pub fn with_timeout(mut self, timeout_ms: u32) -> cec_msg {
180 self.timeout = timeout_ms;
181 self
182 }
183
184 #[inline]
185 #[must_use]
186 pub fn from_timeout(timeout_ms: u32) -> cec_msg {
187 cec_msg {
188 tx_ts: 0,
189 rx_ts: 0,
190 len: 0,
191 timeout: timeout_ms,
192 sequence: 0,
193 flags: CEC_MSG_FL::empty(),
194 msg: [0; 16],
195 reply: 0,
196 rx_status: CEC_RX_STATUS::empty(),
197 tx_status: CEC_TX_STATUS::empty(),
198 tx_arb_lost_cnt: 0,
199 tx_nack_cnt: 0,
200 tx_low_drive_cnt: 0,
201 tx_error_cnt: 0,
202 }
203 }
204
205 #[inline]
213 pub fn set_reply_to(&mut self, orig: &cec_msg) {
214 self.msg[0] = (orig.destination() << 4) | orig.initiator();
216 self.reply = 0;
217 self.timeout = 0;
218 }
219
220 #[inline]
222 #[must_use]
223 pub fn recv_is_tx_result(&self) -> bool {
224 self.sequence != 0 && !self.tx_status.is_empty() && self.rx_status.is_empty()
225 }
226
227 #[inline]
229 #[must_use]
230 pub fn recv_is_rx_result(&self) -> bool {
231 self.sequence != 0 && self.tx_status.is_empty() && !self.rx_status.is_empty()
232 }
233
234 #[inline]
235 #[must_use]
236 pub fn status_is_ok(&self) -> bool {
237 if !self.tx_status.is_empty() && !self.tx_status.contains(CEC_TX_STATUS::OK) {
238 return false;
239 }
240 if !self.rx_status.is_empty() && !self.rx_status.contains(CEC_RX_STATUS::OK) {
241 return false;
242 }
243 if self.tx_status.is_empty() && self.rx_status.is_empty() {
244 return false;
245 }
246 !self.rx_status.contains(CEC_RX_STATUS::FEATURE_ABORT)
247 }
248}
249
250bitflags! {
251 #[derive(Debug, Copy, Clone, Default)]
253 pub struct CEC_LOG_ADDR_MASK: u16 {
254 const TV = CEC_LOG_ADDR_MASK_TV;
255 const MASK_RECORD = CEC_LOG_ADDR_MASK_RECORD;
256 const TUNER = CEC_LOG_ADDR_MASK_TUNER;
257 const PLAYBACK = CEC_LOG_ADDR_MASK_PLAYBACK;
258 const AUDIOSYSTEM = CEC_LOG_ADDR_MASK_AUDIOSYSTEM;
259 const BACKUP = CEC_LOG_ADDR_MASK_BACKUP;
260 const SPECIFIC = CEC_LOG_ADDR_MASK_SPECIFIC;
261 const UNREGISTERED = CEC_LOG_ADDR_MASK_UNREGISTERED;
262 }
263}
264
265bitflags! {
266 #[derive(Debug, Copy, Clone, Default)]
268 pub struct CEC_CAP: u32 {
269 const PHYS_ADDR = CEC_CAP_PHYS_ADDR;
271 const LOG_ADDRS = CEC_CAP_LOG_ADDRS;
273 const TRANSMIT = CEC_CAP_TRANSMIT;
275 const PASSTHROUGH = CEC_CAP_PASSTHROUGH;
277 const RC = CEC_CAP_RC;
279 const MONITOR_ALL = CEC_CAP_MONITOR_ALL;
281 const NEEDS_HPD = CEC_CAP_NEEDS_HPD;
283 const MONITOR_PIN = CEC_CAP_MONITOR_PIN;
285 const CONNECTOR_INFO = CEC_CAP_CONNECTOR_INFO;
287 const REPLY_VENDOR_ID = CEC_CAP_REPLY_VENDOR_ID;
289 }
290}
291
292#[derive(Debug, Clone, Default)]
294#[repr(C)]
295pub struct cec_caps {
296 pub driver: [c_char; 32],
298 pub name: [c_char; 32],
300 pub available_log_addrs: u32,
302 pub capabilities: CEC_CAP,
304 pub version: u32,
306}
307
308#[derive(Debug, Clone, Default)]
310#[repr(C)]
311pub struct cec_log_addrs {
312 pub log_addr: [u8; CEC_MAX_LOG_ADDRS],
314 pub log_addr_mask: CEC_LOG_ADDR_MASK,
316 pub cec_version: u8,
318 pub num_log_addrs: u8,
320 pub vendor_id: VendorId,
322 pub flags: CEC_LOG_ADDRS_FL,
324 pub osd_name: [c_uchar; 15],
326 pub primary_device_type: [u8; CEC_MAX_LOG_ADDRS],
328 pub log_addr_type: [u8; CEC_MAX_LOG_ADDRS],
330
331 pub all_device_types: [u8; CEC_MAX_LOG_ADDRS],
334 pub features: [[u8; 12]; CEC_MAX_LOG_ADDRS],
336}
337
338impl cec_log_addrs {
339 #[inline]
342 #[must_use]
343 pub fn is_2nd_tv(&self) -> bool {
344 self.num_log_addrs != 0
349 && self.log_addr[0] >= CEC_LOG_ADDR_SPECIFIC
350 && self.primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_TV
351 }
352
353 #[inline]
354 #[must_use]
355 pub fn is_processor(&self) -> bool {
356 self.num_log_addrs != 0
361 && self.log_addr[0] >= CEC_LOG_ADDR_BACKUP_1
362 && self.primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_PROCESSOR
363 }
364
365 #[inline]
366 #[must_use]
367 pub fn is_switch(&self) -> bool {
368 self.num_log_addrs == 1
373 && self.log_addr[0] == CEC_LOG_ADDR_UNREGISTERED
374 && self.primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH
375 && !self.flags.contains(CEC_LOG_ADDRS_FL::CDC_ONLY)
376 }
377
378 #[inline]
379 #[must_use]
380 pub fn is_cdc_only(&self) -> bool {
381 self.num_log_addrs == 1
386 && self.log_addr[0] == CEC_LOG_ADDR_UNREGISTERED
387 && self.primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH
388 && self.flags.contains(CEC_LOG_ADDRS_FL::CDC_ONLY)
389 }
390}
391
392bitflags! {
393 #[derive(Debug, Copy, Clone, Default)]
395 pub struct CEC_LOG_ADDRS_FL: u32 {
396 const ALLOW_UNREG_FALLBACK = CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK;
398 const ALLOW_RC_PASSTHRU = CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU;
400 const CDC_ONLY = CEC_LOG_ADDRS_FL_CDC_ONLY;
402 }
403}
404
405#[derive(Debug, Copy, Clone, Default)]
407#[repr(C)]
408pub struct cec_drm_connector_info {
409 pub card_no: u32,
411 pub connector_id: u32,
413}
414
415#[derive(Copy, Clone)]
416#[repr(C)]
417pub union cec_connector_info_union {
418 pub drm: cec_drm_connector_info,
420 pub raw: [u32; 16],
422}
423
424#[derive(Clone)]
426#[repr(C)]
427pub struct cec_connector_info {
428 pub ty: u32,
430 pub data: cec_connector_info_union,
431}
432
433impl Default for cec_connector_info {
434 #[inline]
435 fn default() -> cec_connector_info {
436 cec_connector_info {
437 ty: CEC_CONNECTOR_TYPE_NO_CONNECTOR,
438 data: cec_connector_info_union { raw: [0; 16] },
439 }
440 }
441}
442
443bitflags! {
444 #[derive(Debug, Copy, Clone, Default)]
446 pub struct CEC_EVENT_FL: u32 {
447 const INITIAL_STATE = CEC_EVENT_FL_INITIAL_STATE;
448 const DROPPED_EVENTS = CEC_EVENT_FL_DROPPED_EVENTS;
449 }
450}
451
452#[derive(Debug, Copy, Clone)]
454#[repr(C)]
455pub struct cec_event_state_change {
456 pub phys_addr: PhysicalAddress,
458 pub log_addr_mask: CEC_LOG_ADDR_MASK,
460 pub have_conn_info: u16,
468}
469
470#[derive(Debug, Copy, Clone)]
472#[repr(C)]
473pub struct cec_event_lost_msgs {
474 pub lost_msgs: u32,
476}
477
478#[derive(Copy, Clone)]
479#[repr(C)]
480pub union cec_event_union {
481 pub state_change: cec_event_state_change,
483 pub lost_msgs: cec_event_lost_msgs,
485 pub raw: [u32; 16],
487}
488
489#[derive(Clone)]
491#[repr(C)]
492pub struct cec_event {
493 pub ts: Timestamp,
495 pub event: u32,
497 pub flags: CEC_EVENT_FL,
499 pub data: cec_event_union,
500}
501
502impl Default for cec_event {
503 #[inline]
504 fn default() -> cec_event {
505 cec_event {
506 ts: 0,
507 event: 0,
508 flags: CEC_EVENT_FL::default(),
509 data: cec_event_union { raw: [0; 16] },
510 }
511 }
512}
513
514#[derive(Copy, Clone, Debug, PartialEq, Eq)]
516#[repr(transparent)]
517pub struct VendorId(u32);
518
519impl Default for VendorId {
520 #[inline]
521 fn default() -> Self {
522 VendorId(CEC_VENDOR_ID_NONE)
523 }
524}
525
526impl TryFrom<u32> for VendorId {
527 type Error = ();
528
529 #[inline]
530 fn try_from(val: u32) -> Result<VendorId, ()> {
531 if val < 0x1_00_00_00 || val == CEC_VENDOR_ID_NONE {
532 Ok(VendorId(val))
533 } else {
534 Err(())
535 }
536 }
537}
538
539impl From<VendorId> for u32 {
540 #[inline]
541 fn from(val: VendorId) -> u32 {
542 val.0
543 }
544}
545
546impl VendorId {
547 #[inline]
548 #[must_use]
549 pub fn is_none(self) -> bool {
550 self.0 == CEC_VENDOR_ID_NONE
551 }
552
553 #[inline]
554 #[must_use]
555 pub fn is_valid(self) -> bool {
556 self.0 < 0x1_00_00_00
557 }
558}