/** * zd_mac_tx_to_dev - callback for USB layer * @skb: a &sk_buff pointer * @error: error value, 0 if transmission successful * * Informs the MAC layer that the frame has successfully transferred to the * device. If an ACK is required and the transfer to the device has been * successful, the packets are put on the @ack_wait_queue with * the control set removed. */ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *)skb->cb; struct ieee80211_hw *hw = cb->hw; if (likely(cb->control)) { skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) { struct ieee80211_tx_status status; memset(&status, 0, sizeof(status)); tx_status(hw, skb, &status, !error); } else { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; skb_queue_tail(q, skb); while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) zd_mac_tx_failed(hw); } } else { kfree_tx_skb(skb); } }
/** * filter_ack - filters incoming packets for acknowledgements * @dev: the mac80211 device * @rx_hdr: received header * @stats: the status for the received packet * * This functions looks for ACK packets and tries to match them with the * frames in the tx queue. If a match is found the frame will be dequeued and * the upper layers is informed about the successful transmission. If * mac80211 queues have been stopped and the number of frames still to be * transmitted is low the queues will be opened again. * * Returns 1 if the frame was an ACK, 0 if it was ignored. */ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, struct ieee80211_rx_status *stats) { u16 fc = le16_to_cpu(rx_hdr->frame_control); struct sk_buff *skb; struct sk_buff_head *q; unsigned long flags; if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) != (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK)) return 0; q = &zd_hw_mac(hw)->ack_wait_queue; spin_lock_irqsave(&q->lock, flags); for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) { struct ieee80211_hdr *tx_hdr; tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { struct ieee80211_tx_status status; memset(&status, 0, sizeof(status)); status.flags = IEEE80211_TX_STATUS_ACK; status.ack_signal = stats->ssi; __skb_unlink(skb, q); tx_status(hw, skb, &status, 1); goto out; } } out: spin_unlock_irqrestore(&q->lock, flags); return 1; }
static int term_putchar(char c) { u32 stat; stat = tx_status(term0_reg); if (stat != ST_READY && stat != ST_TRANSMITTED) return -1; term0_reg->transm_command = ((c << CHAR_OFFSET) | CMD_TRANSMIT); while ((stat = tx_status(term0_reg)) == ST_BUSY) ; term0_reg->transm_command = CMD_ACK; if (stat != ST_TRANSMITTED) return -1; else return 0; }
/** * zd_mac_tx_failed - callback for failed frames * @dev: the mac80211 wireless device * * This function is called if a frame couldn't be succesfully be * transferred. The first frame from the tx queue, will be selected and * reported as error to the upper layers. */ void zd_mac_tx_failed(struct ieee80211_hw *hw) { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff *skb; struct ieee80211_tx_status status; skb = skb_dequeue(q); if (skb == NULL) return; memset(&status, 0, sizeof(status)); tx_status(hw, skb, &status, 0); }
/** * Get ready to receive a message from the master. * * Set up our RX DMA and disable our TX DMA. Set up the data output so that * we will send preamble bytes. */ static void setup_for_transaction(void) { stm32_spi_regs_t *spi = STM32_SPI1_REGS; volatile uint8_t dummy __attribute__((unused)); /* clear this as soon as possible */ setup_transaction_later = 0; /* Not ready to receive yet */ tx_status(EC_SPI_NOT_READY); /* We are no longer actively processing a transaction */ state = SPI_STATE_PREPARE_RX; /* Stop sending response, if any */ dma_disable(STM32_DMAC_SPI1_TX); /* * Read dummy bytes in case there are some pending; this prevents the * receive DMA from getting that byte right when we start it. */ dummy = spi->dr; #ifdef CHIP_FAMILY_STM32F0 /* 4 Bytes makes sure the RX FIFO on the F0 is empty as well. */ dummy = spi->dr; dummy = spi->dr; dummy = spi->dr; #endif /* Start DMA */ dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); /* Ready to receive */ state = SPI_STATE_READY_TO_RX; tx_status(EC_SPI_OLD_READY); }
static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status) { if(status != 0) return; if(actual > rx_length) { actual = rx_length; } rx_addr += actual; rx_length -= actual; if(rx_length > 0) { rx_data(); } else { tx_status("OKAY"); rx_cmd(); } }
static void ieee_mcpspt(MAC_McpsDcfmInd_s *ev) /* packet input and output thread */ { rimeaddr_t rime; switch(ev->u8Type) { case MAC_MCPS_IND_DATA: GDB2_PUTS(","); /* new frame received */ packetbuf_clear(); packetbuf_copyfrom(asdataframe(ev).au8Sdu, asdataframe(ev).u8SduLength); packetbuf_set_datalen(asdataframe(ev).u8SduLength); packetbuf_set_addr(PACKETBUF_ADDR_SENDER, asrimeaddr(&asdataframe(ev).sSrcAddr.uAddr.sExt, &rime)); if(asdataframe(ev).sDstAddr.u8AddrMode==LONG) { /* addressed frame */ packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, asrimeaddr(&asdataframe(ev).sDstAddr.uAddr.sExt, &rime)); } else if(asdataframe(ev).sDstAddr.u8AddrMode==SHORT && asdataframe(ev).sDstAddr.u16PanId==BROADCAST_PANID && asdataframe(ev).sDstAddr.uAddr.u16Short==BROADCAST_ADDR) { /* broadcast frame */ packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null); } /* update lqi stuff and call lqi callback */ packetbuf_set_attr(PACKETBUF_ATTR_RSSI, asdataframe(ev).u8LinkQuality); if (asdataframe(ev).sSrcAddr.u8AddrMode == LONG && lqicb) lqicb(asrimeaddr(&asdataframe(ev).sSrcAddr.uAddr.sExt, &rime), asdataframe(ev).u8LinkQuality); else if (lqicb) lqicb(NULL, asdataframe(ev).u8LinkQuality); #if USE_TS current_timestamp = asdataframe(ev).timestamp; #endif //{ // static char buf[512]; // uint8_t i; // uint16_t j; // printf("delay:%d len:%d data:", (int32_t) (clock_hrtime()-asdataframe(ev).timestamp), asdataframe(ev).u8SduLength); // for (i=0,j=0; i<asdataframe(ev).u8SduLength; i++) // j+=snprintf(buf+j,sizeof(buf)-j,"0x%x ",asdataframe(ev).au8Sdu[i]); // buf[j]='\n'; // puts(buf); //} /* call upper layer */ NETSTACK_NETWORK.input(); break; case MAC_MCPS_DCFM_DATA: mac_call_sent_callback(mac_cb, mac_cb_ptr, tx_status(&asdataind(ev)), 1); break; case MAC_MCPS_DCFM_PURGE: default: HAL_BREAKPOINT(); break; } }
static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status) { if(status != 0) return; if(actual > 4095) actual = 4095; cmdbuf[actual] = 0; dprintf("\n> %s\n",cmdbuf); // dprintf("usb_rx_cmd_complete() '%s'\n", cmdbuf); if(memcmp(cmdbuf, "reboot", 6) == 0) { tx_status("OKAY"); rx_cmd(); mdelay(100); board_reboot(); } #if 0 if(memcmp(cmdbuf, "debug:", 6) == 0) { void debug(char *cmd, char *resp); memcpy(cmdbuf, "OKAY", 5); tx_status(cmdbuf); rx_cmd(); mdelay(5000); dprintf("NOW!\n"); debug(cmdbuf + 6, cmdbuf + 4); return; } #endif if(memcmp(cmdbuf, "getvar:", 7) == 0) { char response[64]; strcpy(response,"OKAY"); if(!strcmp(cmdbuf + 7, "version")) { strcpy(response + 4, VERSION); } else if(!strcmp(cmdbuf + 7, "product")) { strcpy(response + 4, PRODUCTNAME); } else if(!strcmp(cmdbuf + 7, "serialno")) { strcpy(response + 4, serialno); } else { board_getvar(cmdbuf + 7, response + 4); } tx_status(response); rx_cmd(); return; } if(memcmp(cmdbuf, "download:", 9) == 0) { char status[16]; rx_addr = kernel_addr; rx_length = hex2unsigned(cmdbuf + 9); if (rx_length > (64*1024*1024)) { tx_status("FAILdata too large"); rx_cmd(); return; } kernel_size = rx_length; dprintf("recv data addr=%x size=%x\n", rx_addr, rx_length); strcpy(status,"DATA"); num_to_hex8(rx_length, status + 4); tx_status(status); rx_data(); return; } if(memcmp(cmdbuf, "erase:", 6) == 0){ struct ptentry *ptn; ptn = flash_find_ptn(cmdbuf + 6); if(ptn == 0) { tx_status("FAILpartition does not exist"); rx_cmd(); return; } dprintf("erasing '%s'\n", ptn->name); cprintf("erasing '%s'", ptn->name); if(flash_erase(ptn)) { tx_status("FAILfailed to erase partition"); rx_cmd(); cprintf(" - FAIL\n"); return; } else { dprintf("partition '%s' erased\n", ptn->name); cprintf(" - OKAY\n"); } tx_status("OKAY"); rx_cmd(); return; } if(memcmp(cmdbuf, "flash:", 6) == 0){ struct ptentry *ptn; int extra = 0; ptn = flash_find_ptn(cmdbuf + 6); if(kernel_size == 0) { tx_status("FAILno image downloaded"); rx_cmd(); return; } if(ptn == 0) { tx_status("FAILpartition does not exist"); rx_cmd(); return; } if(!strcmp(ptn->name,"boot") || !strcmp(ptn->name,"recovery")) { if(memcmp((void*) kernel_addr, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { tx_status("FAILimage is not a boot image"); rx_cmd(); return; } } #if REQUIRE_SIGNATURE { unsigned char digest[DIGEST_SIZE]; compute_digest((void*) kernel_addr, kernel_size, digest); if (is_signature_okay(digest, signature, key_engineering)) { dprintf("verified by engineering key\n"); } else { tx_status("FAILsignature did not verify"); rx_cmd(); return; } } #endif if(!strcmp(ptn->name,"system") || !strcmp(ptn->name,"userdata")) { extra = 64; } else { kernel_size = (kernel_size + 2047) & (~2047); } dprintf("writing %d bytes to '%s'\n", kernel_size, ptn->name); cprintf("writing '%s' (%d bytes)", ptn->name, kernel_size); if(flash_write(ptn, extra, (void*) kernel_addr, kernel_size)) { tx_status("FAILflash write failure"); rx_cmd(); cprintf(" - FAIL\n"); return; } else { dprintf("partition '%s' updated\n", ptn->name); cprintf(" - OKAY\n"); } tx_status("OKAY"); rx_cmd(); return; } if(memcmp(cmdbuf, "boot", 4) == 0) { if(init_boot_linux()) { tx_status("FAILinvalid boot image"); rx_cmd(); return; } dprintf("booting linux...\n"); cprintf("\nbooting linux...\n"); tx_status("OKAY"); mdelay(10); usb_shutdown(); boot_linux(); return; } if(memcmp(cmdbuf, "signature", 9) == 0) { if (kernel_size != SIGNATURE_SIZE) { tx_status("FAILsignature not 256 bytes long"); rx_cmd(); return; } memcpy(signature, (void*)kernel_addr, SIGNATURE_SIZE); tx_status("OKAY"); rx_cmd(); return; } tx_status("FAILinvalid command"); rx_cmd(); }
/** * Handle an event on the NSS pin * * A falling edge of NSS indicates that the master is starting a new * transaction. A rising edge indicates that we have finsihed * * @param signal GPIO signal for the NSS pin */ void spi_event(enum gpio_signal signal) { stm32_dma_chan_t *rxdma; uint16_t *nss_reg; uint32_t nss_mask; uint16_t i; /* If not enabled, ignore glitches on NSS */ if (!enabled) return; /* Check chip select. If it's high, the AP ended a transaction. */ nss_reg = gpio_get_level_reg(GPIO_SPI1_NSS, &nss_mask); if (REG16(nss_reg) & nss_mask) { enable_sleep(SLEEP_MASK_SPI); /* * If the buffer is still used by the host command, postpone * the DMA rx setup. */ if (state == SPI_STATE_PROCESSING) { setup_transaction_later = 1; return; } /* Set up for the next transaction */ spi_init(); /* Fix for bug chrome-os-partner:31390 */ return; } disable_sleep(SLEEP_MASK_SPI); /* Chip select is low = asserted */ if (state != SPI_STATE_READY_TO_RX) { /* * AP started a transaction but we weren't ready for it. * Tell AP we weren't ready, and ignore the received data. */ CPRINTS("SPI not ready"); tx_status(EC_SPI_NOT_READY); state = SPI_STATE_RX_BAD; return; } /* We're now inside a transaction */ state = SPI_STATE_RECEIVING; tx_status(EC_SPI_RECEIVING); rxdma = dma_get_channel(STM32_DMAC_SPI1_RX); /* Wait for version, command, length bytes */ if (wait_for_bytes(rxdma, 3, nss_reg, nss_mask)) goto spi_event_error; if (in_msg[0] == EC_HOST_REQUEST_VERSION) { /* Protocol version 3 */ struct ec_host_request *r = (struct ec_host_request *)in_msg; int pkt_size; /* Wait for the rest of the command header */ if (wait_for_bytes(rxdma, sizeof(*r), nss_reg, nss_mask)) goto spi_event_error; /* * Check how big the packet should be. We can't just wait to * see how much data the host sends, because it will keep * sending dummy data until we respond. */ pkt_size = host_request_expected_size(r); if (pkt_size == 0 || pkt_size > sizeof(in_msg)) goto spi_event_error; /* Wait for the packet data */ if (wait_for_bytes(rxdma, pkt_size, nss_reg, nss_mask)) goto spi_event_error; spi_packet.send_response = spi_send_response_packet; spi_packet.request = in_msg; spi_packet.request_temp = NULL; spi_packet.request_max = sizeof(in_msg); spi_packet.request_size = pkt_size; /* Response must start with the preamble */ memcpy(out_msg, out_preamble, sizeof(out_preamble)); spi_packet.response = out_msg + sizeof(out_preamble); /* Reserve space for the preamble and trailing past-end byte */ spi_packet.response_max = sizeof(out_msg) - sizeof(out_preamble) - EC_SPI_PAST_END_LENGTH; spi_packet.response_size = 0; spi_packet.driver_result = EC_RES_SUCCESS; /* Move to processing state */ state = SPI_STATE_PROCESSING; tx_status(EC_SPI_PROCESSING); host_packet_receive(&spi_packet); return; } else if (in_msg[0] >= EC_CMD_VERSION0) { /* * Protocol version 2 * * TODO(crosbug.com/p/20257): Remove once kernel supports * version 3. */ #ifdef CHIP_FAMILY_STM32F0 CPRINTS("WARNING: Protocol version 2 is not supported on the F0" " line due to crbug.com/31390"); #endif args.version = in_msg[0] - EC_CMD_VERSION0; args.command = in_msg[1]; args.params_size = in_msg[2]; /* Wait for parameters */ if (wait_for_bytes(rxdma, 3 + args.params_size, nss_reg, nss_mask)) goto spi_event_error; /* * Params are not 32-bit aligned in protocol version 2. As a * workaround, move them to the beginning of the input buffer * so they are aligned. */ if (args.params_size) memmove(in_msg, in_msg + 3, args.params_size); args.params = in_msg; args.send_response = spi_send_response; /* Allow room for the header bytes */ args.response = out_msg + SPI_PROTO2_OFFSET; args.response_max = sizeof(out_msg) - SPI_PROTO2_OVERHEAD; args.response_size = 0; args.result = EC_RES_SUCCESS; /* Move to processing state */ state = SPI_STATE_PROCESSING; tx_status(EC_SPI_PROCESSING); host_command_received(&args); return; } spi_event_error: /* Error, timeout, or protocol we can't handle. Ignore data. */ tx_status(EC_SPI_RX_BAD_DATA); state = SPI_STATE_RX_BAD; CPRINTS("SPI rx bad data"); CPRINTF("in_msg=["); for (i = 0; i < dma_bytes_done(rxdma, sizeof(in_msg)); i++) CPRINTF("%02x ", in_msg[i]); CPRINTF("]\n"); }