if (enable) { /* Clear the status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &val); if (status) goto err;
status = smb_wr16(SECOCEC_STATUS_REG_1, val); if (status) goto err;
/* Enable the interrupts */
status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); if (status) goto err;
status = smb_wr16(SECOCEC_ENABLE_REG_1,
val | SECOCEC_ENABLE_REG_1_CEC); if (status) goto err;
dev_dbg(dev, "Device enabled\n");
} else { /* Clear the status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
status = smb_wr16(SECOCEC_STATUS_REG_1, val);
/* Disable the interrupts */
status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
~SECOCEC_ENABLE_REG_1_CEC &
~SECOCEC_ENABLE_REG_1_IR);
/* Disable device */
status = smb_rd16(SECOCEC_ENABLE_REG_1, &enable_val); if (status) return status;
status = smb_wr16(SECOCEC_ENABLE_REG_1,
enable_val & ~SECOCEC_ENABLE_REG_1_CEC); if (status) return status;
/* Write logical address * NOTE: CEC_LOG_ADDR_INVALID is mapped to the 'Unregistered' LA
*/
status = smb_wr16(SECOCEC_DEVICE_LA, logical_addr & 0xf); if (status) return status;
/* Re-enable device */
status = smb_wr16(SECOCEC_ENABLE_REG_1,
enable_val | SECOCEC_ENABLE_REG_1_CEC); if (status) return status;
/* Device msg len already accounts for header */
payload_id_len = msg->len - 1;
/* Send data length */
status = smb_wr16(SECOCEC_WRITE_DATA_LENGTH, payload_id_len); if (status) goto err;
/* Send Operation ID if present */ if (payload_id_len > 0) {
status = smb_wr16(SECOCEC_WRITE_OPERATION_ID, msg->msg[1]); if (status) goto err;
} /* Send data if present */ if (payload_id_len > 1) { /* Only data; */
payload_len = msg->len - 2;
payload_msg = &msg->msg[2];
/* Copy message into registers */ for (i = 0; i < payload_len; i += 2) { /* hi byte */
val = payload_msg[i + 1] << 8;
/* lo byte */
val |= payload_msg[i];
status = smb_wr16(SECOCEC_WRITE_DATA_00 + i / 2, val); if (status) goto err;
}
} /* Send msg source/destination and fire msg */
destination = msg->msg[0];
status = smb_wr16(SECOCEC_WRITE_BYTE0, destination); if (status) goto err;
if (status_val & SECOCEC_STATUS_RX_OVERFLOW_MASK) { /* NOTE: Untested, it also might not be necessary */
dev_warn(dev, "Received more than 16 bytes. Discarding\n");
flag_overflow = true;
}
if (status_val & SECOCEC_STATUS_RX_ERROR_MASK) {
dev_warn(dev, "Message received with errors. Discarding\n");
status = -EIO; goto rxerr;
}
/* Read message length */
status = smb_rd16(SECOCEC_READ_DATA_LENGTH, &val); if (status) return;
/* Device msg len already accounts for the header */
msg.len = min(val + 1, CEC_MAX_MSG_SIZE);
/* Read logical address */
status = smb_rd16(SECOCEC_READ_BYTE0, &val); if (status) return;
/* device stores source LA and destination */
msg.msg[0] = val;
/* Read operation ID */
status = smb_rd16(SECOCEC_READ_OPERATION_ID, &val); if (status) return;
msg.msg[1] = val;
/* Read data if present */ if (msg.len > 1) {
payload_len = msg.len - 2;
payload_msg = &msg.msg[2];
/* device stores 2 bytes in every 16-bit val */ for (i = 0; i < payload_len; i += 2) {
status = smb_rd16(SECOCEC_READ_DATA_00 + i / 2, &val); if (status) return;
/* Read status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &status_val); if (status) goto err;
if (status_val & SECOCEC_STATUS_REG_1_CEC) { /* Read CEC status register */
status = smb_rd16(SECOCEC_STATUS, &cec_val); if (status) goto err;
if (cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK)
secocec_rx_done(cec->cec_adap, cec_val);
if (cec_val & SECOCEC_STATUS_MSG_SENT_MASK)
secocec_tx_done(cec->cec_adap, cec_val);
if ((~cec_val & SECOCEC_STATUS_MSG_SENT_MASK) &&
(~cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK))
dev_warn_once(dev, "Message not received or sent, but interrupt fired");
val = SECOCEC_STATUS_REG_1_CEC;
}
if (status_val & SECOCEC_STATUS_REG_1_IR) {
val |= SECOCEC_STATUS_REG_1_IR;
secocec_ir_rx(cec);
}
/* Reset status register */
status = smb_wr16(SECOCEC_STATUS_REG_1, val); if (status) goto err;
staticstruct device *secocec_cec_find_hdmi_dev(struct device *dev, constchar **conn)
{ int i;
for (i = 0 ; i < ARRAY_SIZE(secocec_dmi_match_table) ; ++i) { conststruct cec_dmi_match *m = &secocec_dmi_match_table[i];
if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
dmi_match(DMI_PRODUCT_NAME, m->product_name)) { struct device *d;
/* Find the device, bail out if not yet registered */
d = bus_find_device_by_name(&pci_bus_type, NULL,
m->devname); if (!d) return ERR_PTR(-EPROBE_DEFER);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.