/*===========================================================================* * atl2_reset * *===========================================================================*/ static int atl2_reset(void) { /* Reset the device to a known good state. */ u32_t val; int i; /* Issue a soft reset, and wait for the device to respond. */ ATL2_WRITE_U32(ATL2_MASTER_REG, ATL2_MASTER_SOFT_RESET); for (i = 0; i < ATL2_RESET_NTRIES; i++) { val = ATL2_READ_U32(ATL2_MASTER_REG); if (!(val & ATL2_MASTER_SOFT_RESET)) break; micro_delay(ATL2_RESET_DELAY); } if (i == ATL2_RESET_NTRIES) return FALSE; /* Wait until everything is idle. */ for (i = 0; i < ATL2_IDLE_NTRIES; i++) { if (ATL2_READ_U32(ATL2_IDLE_REG) == 0) break; micro_delay(ATL2_IDLE_DELAY); } return (i < ATL2_IDLE_NTRIES); }
/*===========================================================================* * atl2_read_vpd * *===========================================================================*/ static int atl2_read_vpd(int index, u32_t *res) { /* Read a value from the VPD register area. */ u32_t off, val; int i; ATL2_WRITE_U32(ATL2_VPD_DATA_REG, 0); off = ATL2_VPD_REGBASE + index * sizeof(u32_t); ATL2_WRITE_U32(ATL2_VPD_CAP_REG, (off << ATL2_VPD_CAP_ADDR_SHIFT) & ATL2_VPD_CAP_ADDR_MASK); for (i = 0; i < ATL2_VPD_NTRIES; i++) { micro_delay(ATL2_VPD_DELAY); val = ATL2_READ_U32(ATL2_VPD_CAP_REG); if (val & ATL2_VPD_CAP_DONE) break; } if (i == ATL2_VPD_NTRIES) { printf("ATL2: timeout reading EEPROM register %d\n", index); return FALSE; } *res = ATL2_READ_U32(ATL2_VPD_DATA_REG); return TRUE; }
static void rtl8169_update_stat(re_t *rep) { static u64_t last_miss = 0, last_coll = 0; u64_t miss, coll; port_t port; int i; port = rep->re_base_port; /* Dump Tally Counter Command */ rl_outl(port, RL_DTCCR_HI, 0); /* 64 bits */ rl_outl(port, RL_DTCCR_LO, rep->dtcc_buf | RL_DTCCR_CMD); for (i = 0; i < 1000; i++) { if (!(rl_inl(port, RL_DTCCR_LO) & RL_DTCCR_CMD)) break; micro_delay(10); } /* Update counters */ miss = rep->v_dtcc_buf->MissPkt; netdriver_stat_ierror(miss - last_miss); last_miss = miss; coll = rep->v_dtcc_buf->Tx1Col + rep->v_dtcc_buf->TxMCol; netdriver_stat_coll(coll - last_coll); last_coll = coll; }
/*===========================================================================* * atl2_read_mdio * *===========================================================================*/ static int atl2_read_mdio(int addr, u16_t *res) { /* Read a MII PHY register using MDIO. */ u32_t rval; int i; rval = ((addr << ATL2_MDIO_ADDR_SHIFT) & ATL2_MDIO_ADDR_MASK) | ATL2_MDIO_START | ATL2_MDIO_READ | ATL2_MDIO_SUP_PREAMBLE | ATL2_MDIO_CLK_25_4; ATL2_WRITE_U32(ATL2_MDIO_REG, rval); for (i = 0; i < ATL2_MDIO_NTRIES; i++) { micro_delay(ATL2_MDIO_DELAY); rval = ATL2_READ_U32(ATL2_MDIO_REG); if (!(rval & (ATL2_MDIO_START | ATL2_MDIO_BUSY))) break; } if (i == ATL2_MDIO_NTRIES) return FALSE; *res = (u16_t) (rval & ATL2_MDIO_DATA_MASK); return TRUE; }
static void rtl8169_update_stat(re_t *rep) { port_t port; int i; port = rep->re_base_port; /* Fetch Missed Packets */ rep->re_stat.ets_missedP += rl_inw(port, RL_MPC); rl_outw(port, RL_MPC, 0x00); /* Dump Tally Counter Command */ rl_outl(port, RL_DTCCR_HI, 0); /* 64 bits */ rl_outl(port, RL_DTCCR_LO, rep->dtcc_buf | RL_DTCCR_CMD); for (i = 0; i < 1000; i++) { if (!(rl_inl(port, RL_DTCCR_LO) & RL_DTCCR_CMD)) break; micro_delay(10); } /* Update counters */ rep->re_stat.ets_frameAll = rep->v_dtcc_buf->FAE; rep->re_stat.ets_transDef = rep->v_dtcc_buf->TxUndrn; rep->re_stat.ets_transAb = rep->v_dtcc_buf->TxAbt; rep->re_stat.ets_collision = rep->v_dtcc_buf->Tx1Col + rep->v_dtcc_buf->TxMCol; }
/*----------------------------------------------------------------------------* reset the 1 wire. Parameters: Returns: 1 if presence detect. *----------------------------------------------------------------------------*/ int owr_reset(void) { int result; cli(); gpio_set_output(GPIO_1WR); gpio_set_off(GPIO_1WR); micro_delay(tRSTL); gpio_set_input(GPIO_1WR); micro_delay(tMSP); result = gpio_get(GPIO_1WR); micro_delay(tRSTL); sei(); return !result; }
/*===========================================================================* * atl2_stop * *===========================================================================*/ static int atl2_stop(void) { /* Stop the device. */ u32_t val; int i; /* Clear and disable interrupts. */ ATL2_WRITE_U32(ATL2_IMR_REG, 0); ATL2_WRITE_U32(ATL2_ISR_REG, 0xffffffff); /* Stop Rx/Tx MACs. */ val = ATL2_READ_U32(ATL2_MAC_REG); if (val & (ATL2_MAC_RX_EN | ATL2_MAC_TX_EN)) { val &= ~(ATL2_MAC_RX_EN | ATL2_MAC_TX_EN); ATL2_WRITE_U32(ATL2_MAC_REG, val); } ATL2_WRITE_U8(ATL2_DMAWRITE_REG, 0); ATL2_WRITE_U8(ATL2_DMAREAD_REG, 0); /* Wait until everything is idle. */ for (i = 0; i < ATL2_IDLE_NTRIES; i++) { if (ATL2_READ_U32(ATL2_IDLE_REG) == 0) break; micro_delay(ATL2_IDLE_DELAY); } /* The caller will generally ignore this return value. */ return (i < ATL2_IDLE_NTRIES); }
/*----------------------------------------------------------------------------* read one byte on 1 wire Parameters: Returns: value. *----------------------------------------------------------------------------*/ unsigned owr_readb(void) { unsigned result = 0; int i; for(i = 0; i < 8; i++) { result >>= 1; gpio_set_output(GPIO_1WR); micro_delay(tRL); gpio_set_input(GPIO_1WR); micro_delay(tMSR); if(gpio_get(GPIO_1WR)) { result |= 0x80; } micro_delay(tSLOT - tRL); } return result; }
static int hdmi_ddc_enable(void) { int r; /* Soft Reset DDC Bus */ r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG, HDMI_CTRL_RESET_DDC_MASK); if (r != OK) { return r; } micro_delay(100000); r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG, HDMI_CTRL_RESET_DDC_MASK); if (r != OK) { return r; } micro_delay(100000); /* Enable DDC */ r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CTRL_REG, HDMI_CTRL_DDC_EN_MASK); if (r != OK) { return r; } /* Setup the clock (I think) */ r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CLK_REG, HDMI_CTRL_DDC_CLK_EN_MASK); if (r != OK) { return r; } r = hdmi_write(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_DDC_CLK_REG, HDMI_HDCP_OTP_DDC_CLK_MASK); if (r != OK) { return r; } log_debug(&log, "DDC Enabled\n"); return OK; }
/*----------------------------------------------------------------------------* write one byte on 1 wire. Parameters: bytes to write. Returns: *----------------------------------------------------------------------------*/ void owr_writeb(unsigned byte) { int i; for(i = 0; i < 8; i++) { if(byte & 0x01) { gpio_set_output(GPIO_1WR); micro_delay(tW1L); gpio_set_input(GPIO_1WR); micro_delay(tSLOT - tW1L); } else { gpio_set_output(GPIO_1WR); micro_delay(tW0L); gpio_set_input(GPIO_1WR); micro_delay(tSLOT - tW0L); } byte >>= 1; } }
endpoint_t bdev_driver_update(dev_t dev) { /* Update the endpoint of a driver. The caller of this function already knows * that the current endpoint may no longer be valid, and must be updated. * Return the new endpoint upon success, and NONE otherwise. */ endpoint_t endpt; int r, major, nr_tries; major = major(dev); assert(major >= 0 && major < NR_DEVICES); assert(driver_tab[major].label[0] != '\0'); /* Repeatedly retrieve the endpoint for the driver label, and see if it is a * different, valid endpoint. If retrieval fails at first, we have to wait. * We use polling, as opposed to a DS subscription, for a number of reasons: * 1) DS supports only one subscription per process, and our main program may * already have a subscription; * 2) if we block on receiving a notification from DS, we cannot impose an * upper bound on the retry time; * 3) temporarily subscribing and then unsubscribing may cause leftover DS * notifications, which the main program would then have to deal with. * As of writing, unsubscribing from DS is not possible at all, anyway. * * In the normal case, the driver's label/endpoint mapping entry disappears * completely for a short moment, before being replaced with the new mapping. * Hence, failure to retrieve the entry at all does not constitute permanent * failure. In fact, there is no way to determine reliably that a driver has * failed permanently in the current approach. For this we simply rely on the * retry limit. */ for (nr_tries = 0; nr_tries < DS_NR_TRIES; nr_tries++) { r = ds_retrieve_label_endpt(driver_tab[major].label, &endpt); if (r == OK && endpt != NONE && endpt != driver_tab[major].endpt) { driver_tab[major].endpt = endpt; return endpt; } if (nr_tries < DS_NR_TRIES - 1) micro_delay(DS_DELAY); } driver_tab[major].endpt = NONE; return NONE; }
static void mdio_write(u16_t port, int regaddr, int value) { int i; rl_outl(port, RL_PHYAR, 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); for (i = 20; i > 0; i--) { /* * Check if the RTL8169 has completed writing to the specified * MII register */ if (!(rl_inl(port, RL_PHYAR) & 0x80000000)) break; else micro_delay(50); } }
/*===========================================================================* * do_initialize * *===========================================================================*/ static void do_initialize() { /* Set global variables and initialize the printer. */ if(sys_outb(port_base + 2, INIT_PRINTER) != OK) { printf("printer: sys_outb of %x failed\n", port_base+2); panic("do_initialize: sys_outb init failed"); } micro_delay(1000000/20); /* easily satisfies Centronics minimum */ if(sys_outb(port_base + 2, PR_SELECT) != OK) { printf("printer: sys_outb of %x failed\n", port_base+2); panic("do_initialize: sys_outb select failed"); } irq_hook_id = 0; if(sys_irqsetpolicy(PRINTER_IRQ, 0, &irq_hook_id) != OK || sys_irqenable(&irq_hook_id) != OK) { panic("do_initialize: irq enabling failed"); } }
/*===========================================================================* * do_write * *===========================================================================*/ static ssize_t printer_write(devminor_t UNUSED(minor), u64_t UNUSED(position), endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) { /* The printer is used by sending write requests to it. Process one. */ int retries; u32_t status; /* Reject command if last write is not yet finished, the count is not * positive, or we're asked not to block. */ if (writing) return EIO; if (size <= 0) return EINVAL; if (flags & CDEV_NONBLOCK) return EAGAIN; /* not supported */ /* If no errors occurred, continue printing with the caller. * First wait until the printer is online to prevent stupid errors. */ caller = endpt; user_left = size; orig_count = size; user_vir_d = 0; /* Offset. */ writing = TRUE; grant_nr = grant; write_id = id; retries = MAX_ONLINE_RETRIES + 1; while (--retries > 0) { if (sys_inb(port_base + 1, &status) != OK) { printf("printer: sys_inb of %x failed\n", port_base+1); panic("sys_inb failed"); } if (status & ON_LINE) { /* printer online! */ prepare_output(); printer_intr(0); return EDONTREPLY; /* we may already have sent a reply */ } micro_delay(500000); /* wait before retry */ } /* If we reach this point, the printer was not online in time. */ done_status = status; output_done(); return EDONTREPLY; }
static int mdio_read(u16_t port, int regaddr) { int i, value = -1; rl_outl(port, RL_PHYAR, (regaddr & 0x1F) << 16); for (i = 20; i > 0; i--) { /* * Check if the RTL8169 has completed retrieving data from * the specified MII register */ if (rl_inl(port, RL_PHYAR) & 0x80000000) { value = (int)(rl_inl(port, RL_PHYAR) & 0xFFFF); break; } else micro_delay(50); } return value; }
/***************************************************************************** * hermes_issue_cmd * * * * Issue a command to the chip. Waiting for it to complete is the caller's * * problem. The only thing we have to do first is to see whether we can * * actually write something in the CMD register: is it unbusy? * * Returns -EBUSY if the command register is busy, 0 on success. * *****************************************************************************/ static int hermes_issue_cmd (hermes_t * hw, u16_t cmd, u16_t param0) { int k = HERMES_CMD_BUSY_TIMEOUT; u16_t reg; /* First wait for the command register to unbusy */ reg = hermes_read_reg (hw, HERMES_CMD); while ((reg & HERMES_CMD_BUSY) && k) { k--; micro_delay (1); reg = hermes_read_reg (hw, HERMES_CMD); } /* it takes too long. Bailing out */ if (reg & HERMES_CMD_BUSY) { printf("Hermes: HERMES_CMD_BUSY timeout\n"); return -EBUSY; } /* write the values to the right registers */ hermes_write_reg (hw, HERMES_PARAM2, 0); hermes_write_reg (hw, HERMES_PARAM1, 0); hermes_write_reg (hw, HERMES_PARAM0, param0); hermes_write_reg (hw, HERMES_CMD, cmd); return 0; }
/*============================================================================* * lan8710a_init_hw * *============================================================================*/ static int lan8710a_init_hw(netdriver_addr_t * addr, unsigned int instance) { int r, i; /* * Set the interrupt handler and policy. Do not automatically * re-enable interrupts. Return the IRQ line number on interrupts. */ lan8710a_state.irq_rx_hook = RX_INT; if ((r = sys_irqsetpolicy(LAN8710A_RX_INTR, 0, &lan8710a_state.irq_rx_hook)) != OK) { panic("sys_irqsetpolicy failed: %d", r); } lan8710a_state.irq_tx_hook = TX_INT; if ((r = sys_irqsetpolicy(LAN8710A_TX_INTR, 0, &lan8710a_state.irq_tx_hook)) != OK) { panic("sys_irqsetpolicy failed: %d", r); } /* Reset hardware. */ lan8710a_reset_hw(); /* * Select the Interface (GMII/RGMII/MII) Mode in the Control Module. * Port1 GMII/MII Mode, Port2 not used. */ lan8710a_reg_write(GMII_SEL, (GMII2_SEL_BIT1 | GMII2_SEL_BIT0)); /* * Configure pads (PIN muxing) as per the Interface Selected using the * appropriate pin muxing conf_xxx registers in the Control Module. * * CONF_MOD_SLEW_CTRL when 0 - Fast Mode, when 1 - Slow Mode * CONF_MOD_RX_ACTIVE when 0 - Only output, when 1 - Also input * CONF_MOD_PU_TYPESEL when 0 - Pull-down, when 1 - Pull-up * CONF_MOD_PUDEN when 0 Pull* enabled, when 1 Pull* disabled * CONF_MOD_MMODE_MII selects pin to work for MII interface */ lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TX_EN, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TXD3, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TXD2, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TXD1, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TXD0, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MDIO, CONF_MOD_SLEW_CTRL); lan8710a_reg_set(CONF_MDIO, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MDIO, CONF_MOD_PU_TYPESEL); lan8710a_reg_unset(CONF_MDIO, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MDIO, CONF_MOD_MMODE_MII); lan8710a_reg_unset(CONF_MDC, CONF_MOD_SLEW_CTRL); lan8710a_reg_unset(CONF_MDC, CONF_MOD_RX_ACTIVE); lan8710a_reg_set(CONF_MDC, CONF_MOD_PUDEN); lan8710a_reg_unset(CONF_MDC, CONF_MOD_MMODE_MII); /* Apply soft reset to 3PSW Subsytem, CPSW_3G, CPGMAC_SL, and CPDMA. */ lan8710a_reg_write(CPSW_SS_SOFT_RESET, SOFT_RESET); lan8710a_reg_write(CPSW_SL_SOFT_RESET(1), SOFT_RESET); lan8710a_reg_write(CPSW_SL_SOFT_RESET(2), SOFT_RESET); /* Wait for software resets completion */ while ((lan8710a_reg_read(CPSW_SS_SOFT_RESET) & SOFT_RESET) || (lan8710a_reg_read(CPSW_SL_SOFT_RESET(1)) & SOFT_RESET) || (lan8710a_reg_read(CPSW_SL_SOFT_RESET(2)) & SOFT_RESET)); /* Configure the Statistics Port Enable register. */ /* Enable port 0 and 1 statistics. */ lan8710a_reg_write(CPSW_SS_STAT_PORT_EN, (CPSW_P1_STAT_EN | CPSW_P0_STAT_EN)); /* * Configure the ALE. * Enabling Ale. * All packets received on ports 1 are * sent to the host (only to the host). */ lan8710a_reg_write(CPSW_ALE_CONTROL, (CPSW_ALE_ENABLE | CPSW_ALE_BYPASS)); /* Port 0 (host) in forwarding mode. */ lan8710a_reg_write(CPSW_ALE_PORTCTL0, CPSW_ALE_PORT_FWD); /* Port 1 in forwarding mode. */ lan8710a_reg_write(CPSW_ALE_PORTCTL1, CPSW_ALE_PORT_FWD); /* * Configure CPSW_SL Register * Full duplex mode. */ lan8710a_reg_write(CPSW_SL_MACCONTROL(1), CPSW_SL_FULLDUPLEX); /* Initialize MDIO Protocol */ lan8710a_init_mdio(); /* Getting MAC Address */ lan8710a_init_addr(addr, instance); /* Initialize descriptors */ lan8710a_init_desc(); /* Reset and initialize CPDMA */ lan8710a_dma_reset_init(); /* * Configure the Interrupts. * Routing all channel Rx int to RX_PULSE signal. */ lan8710a_reg_set(CPSW_WR_C0_RX_EN, CPSW_FIRST_CHAN_INT); /* * Enabling LAN8710A Auto-negotiation */ lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_AUTO_NEG); /* Waiting for auto-negotiaion completion. */ for (i = 0; !(lan8710a_phy_read(LAN8710A_STATUS_REG) & LAN8710A_AUTO_NEG_COMPL); ++i) { if (i == 100) { LAN8710A_DEBUG_PRINT(("Autonegotiation failed")); break; } micro_delay(1666666); } /* GMII RX and TX release from reset. */ lan8710a_reg_set(CPSW_SL_MACCONTROL(1), CPSW_SL_GMII_EN); /* Enable interrupts. */ lan8710a_enable_interrupt(RX_INT | TX_INT); return TRUE; }
/***************************************************************************** * hermes_init * * * * Initialize the card * *****************************************************************************/ int hermes_init (hermes_t * hw) { u32_t status, reg, resp0; int err = 0; int k; /* We don't want to be interrupted while resetting the chipset. By * setting the control mask for hardware interrupt generation to 0, * we won't be disturbed*/ hw->inten = 0x0; hermes_write_reg (hw, HERMES_INTEN, 0); /* Acknowledge any pending events waiting for acknowledgement. We * assume there won't be any important to take care off */ hermes_write_reg (hw, HERMES_EVACK, 0xffff); /* Normally it's a "can't happen" for the command register to * be busy when we go to issue a command because we are * serializing all commands. However we want to have some * chance of resetting the card even if it gets into a stupid * state, so we actually wait to see if the command register * will unbusy itself here. */ k = HERMES_CMD_BUSY_TIMEOUT; reg = hermes_read_reg (hw, HERMES_CMD); while (k && (reg & HERMES_CMD_BUSY)) { if (reg == 0xffff) { /* Special case - the card has probably * been removed, so don't wait for the * timeout */ printf("Hermes: Card removed?\n"); return -ENODEV; } k--; micro_delay (1); reg = hermes_read_reg (hw, HERMES_CMD); } /* No need to explicitly handle the timeout - if we've timed * out hermes_issue_cmd() will probably return -EBUSY below. * But i check to be sure :-) */ if (reg & HERMES_CMD_BUSY) { printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n"); return -EBUSY; } /* According to the documentation, EVSTAT may contain * obsolete event occurrence information. We have to acknowledge * it by writing EVACK. */ reg = hermes_read_reg (hw, HERMES_EVSTAT); hermes_write_reg (hw, HERMES_EVACK, reg); err = hermes_issue_cmd (hw, HERMES_CMD_INIT, 0); if (err){ printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n", err); return err; } /* here we start waiting for the above command,CMD_INIT, to complete. * Completion is noticeable when the HERMES_EV_CMD bit in the * HERMES_EVSTAT register is set to 1 */ reg = hermes_read_reg (hw, HERMES_EVSTAT); k = HERMES_CMD_INIT_TIMEOUT; while ((!(reg & HERMES_EV_CMD)) && k) { k--; micro_delay (10); reg = hermes_read_reg (hw, HERMES_EVSTAT); } /* the software support register 0 (there are 3) is filled with a * magic number. With this one can test the availability of the card */ hermes_write_reg (hw, HERMES_SWSUPPORT0, HERMES_MAGIC); if (!hermes_present (hw)) { printf("Hermes: Card not present?: got mag. nr.0x%x\n", hermes_read_reg (hw, HERMES_SWSUPPORT0)); } if (!(reg & HERMES_EV_CMD)) { printf("hermes @ %x: Timeout waiting for card to reset\n", hw->iobase); return -ETIMEDOUT; } status = hermes_read_reg (hw, HERMES_STATUS); resp0 = hermes_read_reg (hw, HERMES_RESP0); /* after having issued the command above, the completion set a bit in * the EVSTAT register. This has to be acknowledged, as follows */ hermes_write_reg (hw, HERMES_EVACK, HERMES_EV_CMD); /* Was the status, the result of the issued command, ok? */ /* The expression below should be zero. Non-zero means an error */ if (status & HERMES_STATUS_RESULT) { printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n", (status & HERMES_STATUS_RESULT) >> 8); err = -EIO; }
/***************************************************************************** * milli_delay * * * * Wait msecs milli seconds * *****************************************************************************/ PRIVATE void milli_delay(unsigned int msecs) { micro_delay((long)msecs * 1000); }
/** * The main function. */ int main( void ) { /* Stop the watchdog timer. */ WDTCTL = WDTPW + WDTHOLD; /* Setup MCLK 8MHz and SMCLK 1MHz */ set_mcu_speed_xt2_mclk_8MHz_smclk_1MHz(); /* Enable Interrupts */ eint(); LEDS_INIT(); LEDS_ON(); uart0_init(UART0_CONFIG_1MHZ_115200); printf("CC2420 TX test program with address recognition and acknowledge frames\r\n"); cc2420_init(); cc2420_io_sfd_register_cb(sfd_cb); cc2420_io_sfd_int_set_falling(); cc2420_io_sfd_int_clear(); cc2420_io_sfd_int_enable(); cc2420_set_txpower(CC2420_2_45GHz_TX_0dBm); uint8_t fcf[2] = {0x21, 0x88}; /* -> 00100001 10001000 -> reverse of bits for each byte -> 10000100 00010001 -> ack bit = 1 (6th bit), Frame type = 001 (don't forget to read from right to left) */ uint8_t seq_numb = 0x01; uint8_t dest_pan_id[2] = {0x22, 0x00}; uint8_t dest_addr[2] = {0x11, 0x11}; uint8_t src_pan_id[2] = {0x22, 0x01}; uint8_t src_addr[2] = {0x11, 0x12}; while ( (cc2420_get_status() & 0x40) == 0 ); // waiting for xosc being stable cc2420_set_panid(src_pan_id); // save pan id in ram cc2420_set_shortadr(src_addr); // save short address in ram printf("CC2420 initialized\r\n"); LEDS_OFF(); while (1) { cc2420_cmd_idle(); cc2420_cmd_flushtx(); txlength = sprintf((char *)txframe, "Hello World #%i", seq_numb); printf("Sent : %s of length %d\r\n", txframe,txlength); txlength += 13; cc2420_fifo_put(&txlength, 1); cc2420_fifo_put(fcf, 2); cc2420_fifo_put(&seq_numb, 1); cc2420_fifo_put(dest_pan_id, 2); cc2420_fifo_put(dest_addr, 2); cc2420_fifo_put(src_pan_id, 2); cc2420_fifo_put(src_addr, 2); cc2420_fifo_put(txframe, txlength-13); LED_BLUE_TOGGLE(); cc2420_cmd_tx(); micro_delay(0xFFFF); while (cc2420_io_sfd_read()); printf("Waiting for acknowledge frame...\n"); if (rx_ack()) { seq_numb ++; } else { printf("No Acknowledge frame received for frame number #%i - Retrying...\r\n\n", seq_numb); LED_RED_TOGGLE(); } micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); micro_delay(0xFFFF); } return 0; }
/*===========================================================================* * atl2_setup * *===========================================================================*/ static int atl2_setup(void) { /* Set up the device for normal operation. */ u32_t val; atl2_stop(); if (!atl2_reset()) return FALSE; /* Initialize PCIE module. Magic. */ ATL2_WRITE_U32(ATL2_LTSSM_TESTMODE_REG, ATL2_LTSSM_TESTMODE_DEFAULT); ATL2_WRITE_U32(ATL2_DLL_TX_CTRL_REG, ATL2_DLL_TX_CTRL_DEFAULT); /* Enable PHY. */ ATL2_WRITE_U32(ATL2_PHY_ENABLE_REG, ATL2_PHY_ENABLE); micro_delay(1000); /* Clear and disable interrupts. */ ATL2_WRITE_U32(ATL2_ISR_REG, 0xffffffff); /* Set the MAC address. */ ATL2_WRITE_U32(ATL2_HWADDR0_REG, state.hwaddr[0]); ATL2_WRITE_U32(ATL2_HWADDR1_REG, state.hwaddr[1]); /* Initialize ring buffer addresses and sizes. */ ATL2_WRITE_U32(ATL2_DESC_ADDR_HI_REG, 0); /* no 64 bit */ ATL2_WRITE_U32(ATL2_TXD_ADDR_LO_REG, state.txd_phys); ATL2_WRITE_U32(ATL2_TXS_ADDR_LO_REG, state.txs_phys); ATL2_WRITE_U32(ATL2_RXD_ADDR_LO_REG, state.rxd_phys); ATL2_WRITE_U16(ATL2_RXD_COUNT_REG, ATL2_RXD_COUNT); ATL2_WRITE_U16(ATL2_TXD_BUFSIZE_REG, ATL2_TXD_BUFSIZE / sizeof(u32_t)); ATL2_WRITE_U16(ATL2_TXS_COUNT_REG, ATL2_TXS_COUNT); /* A whole lot of other initialization copied from Linux/FreeBSD. */ ATL2_WRITE_U32(ATL2_IFG_REG, ATL2_IFG_DEFAULT); ATL2_WRITE_U32(ATL2_HDPX_REG, ATL2_HDPX_DEFAULT); ATL2_WRITE_U16(ATL2_IMT_REG, ATL2_IMT_DEFAULT); val = ATL2_READ_U32(ATL2_MASTER_REG); ATL2_WRITE_U32(ATL2_MASTER_REG, val | ATL2_MASTER_IMT_EN); ATL2_WRITE_U16(ATL2_ICT_REG, ATL2_ICT_DEFAULT); ATL2_WRITE_U32(ATL2_CUT_THRESH_REG, ATL2_CUT_THRESH_DEFAULT); ATL2_WRITE_U16(ATL2_FLOW_THRESH_HI_REG, (ATL2_RXD_COUNT / 8) * 7); ATL2_WRITE_U16(ATL2_FLOW_THRESH_LO_REG, ATL2_RXD_COUNT / 12); /* Set MTU. */ ATL2_WRITE_U16(ATL2_MTU_REG, ATL2_MTU_DEFAULT); /* Reset descriptors, and enable DMA. */ state.txd_tail = state.txs_tail = state.rxd_tail = 0; state.txd_num = state.txs_num = 0; state.flags &= ~ATL2_FLAG_RX_AVAIL; ATL2_WRITE_U16(ATL2_TXD_IDX_REG, 0); ATL2_WRITE_U16(ATL2_RXD_IDX_REG, 0); ATL2_WRITE_U8(ATL2_DMAREAD_REG, ATL2_DMAREAD_EN); ATL2_WRITE_U8(ATL2_DMAWRITE_REG, ATL2_DMAWRITE_EN); /* Did everything go alright? */ val = ATL2_READ_U32(ATL2_ISR_REG); if (val & ATL2_ISR_PHY_LINKDOWN) { printf("ATL2: initialization failed\n"); return FALSE; } /* Clear interrupt status. */ ATL2_WRITE_U32(ATL2_ISR_REG, 0x3fffffff); ATL2_WRITE_U32(ATL2_ISR_REG, 0); /* Enable interrupts. */ ATL2_WRITE_U32(ATL2_IMR_REG, ATL2_IMR_DEFAULT); /* Configure MAC. */ ATL2_WRITE_U32(ATL2_MAC_REG, ATL2_MAC_DEFAULT); /* Inet does not tell us about the multicast addresses that it is * interested in, so we have to simply accept all multicast packets. */ ATL2_WRITE_U32(ATL2_MHT0_REG, 0xffffffff); ATL2_WRITE_U32(ATL2_MHT1_REG, 0xffffffff); atl2_set_mode(); /* Enable Tx/Rx. */ val = ATL2_READ_U32(ATL2_MAC_REG); ATL2_WRITE_U32(ATL2_MAC_REG, val | ATL2_MAC_TX_EN | ATL2_MAC_RX_EN); return TRUE; }
/*===========================================================================* * do_int * *===========================================================================*/ static void do_int(struct port *pp) { int devind, vcc_5v, vcc_3v, vcc_Xv, vcc_Yv, socket_5v, socket_3v, socket_Xv, socket_Yv; spin_t spin; u32_t csr_event, csr_present, csr_control; u8_t v8; u16_t v16; #if USE_INTS int r; #endif devind= pp->p_devind; v8= pci_attr_r8(devind, TI_CARD_CTRL); if (v8 & TI_CCR_IFG) { printf("ti1225: got functional interrupt\n"); pci_attr_w8(devind, TI_CARD_CTRL, v8); } if (debug) { printf("Socket event: 0x%x\n", pp->csr_ptr->csr_event); printf("Socket mask: 0x%x\n", pp->csr_ptr->csr_mask); } csr_present= pp->csr_ptr->csr_present; csr_control= pp->csr_ptr->csr_control; if ((csr_present & (CP_CDETECT1|CP_CDETECT2)) != 0) { if (debug) printf("do_int: no card present\n"); return; } if (csr_present & CP_BADVCCREQ) { printf("do_int: Bad Vcc request\n"); /* return; */ } if (csr_present & CP_DATALOST) { /* Do we care? */ if (debug) printf("do_int: Data lost\n"); /* return; */ } if (csr_present & CP_NOTACARD) { printf("do_int: Not a card\n"); return; } if (debug) { if (csr_present & CP_CBCARD) printf("do_int: Cardbus card detected\n"); if (csr_present & CP_16BITCARD) printf("do_int: 16-bit card detected\n"); } if (csr_present & CP_PWRCYCLE) { if (debug) printf("do_int: powered up\n"); return; } vcc_5v= !!(csr_present & CP_5VCARD); vcc_3v= !!(csr_present & CP_3VCARD); vcc_Xv= !!(csr_present & CP_XVCARD); vcc_Yv= !!(csr_present & CP_YVCARD); if (debug) { printf("do_int: card supports:%s%s%s%s\n", vcc_5v ? " 5V" : "", vcc_3v ? " 3V" : "", vcc_Xv ? " X.X V" : "", vcc_Yv ? " Y.Y V" : ""); } socket_5v= !!(csr_present & CP_5VSOCKET); socket_3v= !!(csr_present & CP_3VSOCKET); socket_Xv= !!(csr_present & CP_XVSOCKET); socket_Yv= !!(csr_present & CP_YVSOCKET); if (debug) { printf("do_int: socket supports:%s%s%s%s\n", socket_5v ? " 5V" : "", socket_3v ? " 3V" : "", socket_Xv ? " X.X V" : "", socket_Yv ? " Y.Y V" : ""); } if (vcc_5v && socket_5v) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_5V; pp->csr_ptr->csr_control= csr_control; if (debug) printf("do_int: applying 5V\n"); } else if (vcc_3v && socket_3v) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_3V; pp->csr_ptr->csr_control= csr_control; if (debug) printf("do_int: applying 3V\n"); } else if (vcc_Xv && socket_Xv) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_XV; pp->csr_ptr->csr_control= csr_control; printf("do_int: applying X.X V\n"); } else if (vcc_Yv && socket_Yv) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_YV; pp->csr_ptr->csr_control= csr_control; printf("do_int: applying Y.Y V\n"); } else { printf("do_int: socket and card are not compatible\n"); return; } csr_event= pp->csr_ptr->csr_event; if (csr_event) { if (debug) printf("clearing socket event\n"); pp->csr_ptr->csr_event= csr_event; if (debug) { printf("Socket event (cleared): 0x%x\n", pp->csr_ptr->csr_event); } } devind= pp->p_devind; v8= pci_attr_r8(devind, TI_CARD_CTRL); if (v8 & TI_CCR_IFG) { printf("ti1225: got functional interrupt\n"); pci_attr_w8(devind, TI_CARD_CTRL, v8); } if (debug) { v8= pci_attr_r8(devind, TI_CARD_CTRL); printf("TI_CARD_CTRL: 0x%02x\n", v8); } spin_init(&spin, 100000); do { csr_present= pp->csr_ptr->csr_present; if (csr_present & CP_PWRCYCLE) break; } while (spin_check(&spin)); if (!(csr_present & CP_PWRCYCLE)) { printf("do_int: not powered up?\n"); return; } /* Reset device */ v16= pci_attr_r16(devind, CBB_BRIDGECTRL); v16 |= CBB_BC_CRST; pci_attr_w16(devind, CBB_BRIDGECTRL, v16); /* Wait one microsecond. Is this correct? What are the specs? */ micro_delay(1); /* Clear CBB_BC_CRST */ v16= pci_attr_r16(devind, CBB_BRIDGECTRL); v16 &= ~CBB_BC_CRST; pci_attr_w16(devind, CBB_BRIDGECTRL, v16); /* Wait one microsecond after clearing the reset line. Is this * correct? What are the specs? */ micro_delay(1); pci_rescan_bus(pp->p_cb_busnr); #if USE_INTS r= sys_irqenable(&pp->p_hook); if (r != OK) panic("unable enable interrupts: %d", r); #endif }
static int read_edid(uint8_t * buf, size_t count) { int r; int i, j; int tries; int edid_ready; uint8_t val; log_debug(&log, "Reading edid...\n"); if (buf == NULL || count < EDID_LEN) { log_warn(&log, "Expected 128 byte data buffer\n"); return -1; } r = hdmi_clear(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG, HDMI_HDCP_OTP_SOME_MASK); if (r != OK) { log_warn(&log, "Failed to clear bit in HDCP OTP reg\n"); return -1; } /* Enable EDID Block Read Interrupt */ r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG, HDMI_CTRL_INT_EDID_MASK); if (r != OK) { log_warn(&log, "Failed to enable EDID Block Read interrupt\n"); return -1; } /* enable global interrupts */ r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_INTR_CTRL_REG, HDMI_CTRL_INTR_EN_GLO_MASK); if (r != OK) { log_warn(&log, "Failed to enable interrupts\n"); return -1; } /* Set Device Address */ r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_DEV_ADDR_REG, HDMI_EDID_DEV_ADDR); if (r != OK) { log_warn(&log, "Couldn't set device address\n"); return -1; } /* Set Offset */ r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_OFFSET_REG, HDMI_EDID_OFFSET); if (r != OK) { log_warn(&log, "Couldn't set offset\n"); return -1; } /* Set Segment Pointer Address */ r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_PTR_ADDR_REG, HDMI_EDID_SEG_PTR_ADDR); if (r != OK) { log_warn(&log, "Couldn't set segment pointer address\n"); return -1; } /* Set Segment Address */ r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_ADDR_REG, HDMI_EDID_SEG_ADDR); if (r != OK) { log_warn(&log, "Couldn't set segment address\n"); return -1; } /* * Toggle EDID Read Request Bit to request a read. */ r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG, HDMI_EDID_REQ_READ_MASK); if (r != OK) { log_warn(&log, "Couldn't set Read Request bit\n"); return -1; } r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG, 0x00); if (r != OK) { log_warn(&log, "Couldn't clear Read Request bit\n"); return -1; } log_debug(&log, "Starting polling\n"); /* poll interrupt status flag */ edid_ready = 0; for (tries = 0; tries < 100; tries++) { r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG, &val); if (r != OK) { log_warn(&log, "Read failed while polling int flag\n"); return -1; } if (val & HDMI_CTRL_INT_EDID_MASK) { log_debug(&log, "Mask Set\n"); edid_ready = 1; break; } micro_delay(1000); } if (!edid_ready) { log_warn(&log, "Data Ready interrupt never fired.\n"); return EBUSY; } log_debug(&log, "Ready to read\n"); /* Finally, perform the read. */ memset(buf, '\0', count); r = hdmi_read_block(HDMI_EDID_PAGE, HDMI_EDID_DATA_REG, buf, EDID_LEN); if (r != OK) { log_warn(&log, "Failed to read EDID data\n"); return -1; } /* Disable EDID Block Read Interrupt */ r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG, HDMI_CTRL_INT_EDID_MASK); if (r != OK) { log_warn(&log, "Failed to disable EDID Block Read interrupt\n"); return -1; } r = hdmi_set(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG, HDMI_HDCP_OTP_SOME_MASK); if (r != OK) { log_warn(&log, "Failed to set bit in HDCP/OTP reg\n"); return -1; } log_debug(&log, "Done EDID Reading\n"); return OK; }
/** * The main function. */ int main( void ) { uint8_t i; uint8_t length; /* Stop the watchdog timer. */ WDTCTL = WDTPW + WDTHOLD; /* Setup MCLK 8MHz and SMCLK 1MHz */ set_mcu_speed_xt2_mclk_8MHz_smclk_1MHz(); /* Enable Interrupts */ eint(); LEDS_INIT(); LEDS_ON(); uart0_init(UART0_CONFIG_1MHZ_115200); printf("CC2420 RX test program with address recognition and acknowledge frames\r\n"); cc2420_init(); cc2420_io_sfd_register_cb(sfd_cb); cc2420_io_sfd_int_set_falling(); cc2420_io_sfd_int_clear(); cc2420_io_sfd_int_enable(); uint8_t src_pan_id[2] = {0x22,0x00}; uint8_t src_addr[2] = {0x11,0x11}; while ( (cc2420_get_status() & 0x40) == 0 ); // waiting for xosc being stable cc2420_set_panid(src_pan_id); // save pan id in ram cc2420_set_shortadr(src_addr); // save short address in ram printf("CC2420 initialized\r\n"); LEDS_OFF(); while(1) { cc2420_cmd_idle(); cc2420_cmd_flushrx(); cc2420_cmd_rx(); while (flag == 0) ; micro_delay(0xFFFF); flag = 0; LED_GREEN_TOGGLE(); cc2420_fifo_get(&length, 1); if ( length < 128 ) { cc2420_fifo_get(rxframe, length); // check CRC if ( (rxframe[length-1] & 0x80) != 0 ) { printf("Frame received with rssi=%ddBm:\r\n", ((signed int)((signed char)(rxframe[length-2])))-45); LED_BLUE_TOGGLE(); // ignore 11 first bytes (fcf,seq,addr) and the 2 last ones (crc) for (i=11; i<length-2; i++) { printf("%c",rxframe[i]); } printf("\r\n\n"); } else { printf("CRC non OK, erreur de transmission?\n"); printf("\r\n"); LED_RED_TOGGLE(); } } } return 0; }