/* * ISR for DMA mode Tx */ void rt_hw_serial_dma_tx_isr(struct rt_serial_device *serial) { const void *data_ptr; rt_size_t data_size; if (RT_EOK == rt_data_queue_pop(&(serial->tx_dq), &data_ptr, &data_size, 0)) { /* transmit next data node */ serial->ops->dma_transmit(serial, data_ptr, data_size); } else { serial->dma_flag = RT_FALSE; } /* invoke callback */ if (serial->parent.tx_complete != RT_NULL) { serial->parent.tx_complete(&serial->parent, RT_NULL); } }
/* ISR for serial interrupt */ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) { switch (event & 0xff) { case RT_SERIAL_EVENT_RX_IND: { int ch = -1; rt_base_t level; struct rt_serial_rx_fifo* rx_fifo; /* interrupt mode receive */ rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); while (1) { ch = serial->ops->getc(serial); if (ch == -1) break; /* disable interrupt */ level = rt_hw_interrupt_disable(); rx_fifo->buffer[rx_fifo->put_index] = ch; rx_fifo->put_index += 1; if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0; /* if the next position is read index, discard this 'read char' */ if (rx_fifo->put_index == rx_fifo->get_index) { rx_fifo->get_index += 1; if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; } /* enable interrupt */ rt_hw_interrupt_enable(level); } /* invoke callback */ if (serial->parent.rx_indicate != RT_NULL) { rt_size_t rx_length; /* get rx length */ level = rt_hw_interrupt_disable(); rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index): (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index)); rt_hw_interrupt_enable(level); serial->parent.rx_indicate(&serial->parent, rx_length); } break; } case RT_SERIAL_EVENT_TX_DONE: { struct rt_serial_tx_fifo* tx_fifo; tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx; rt_completion_done(&(tx_fifo->completion)); break; } case RT_SERIAL_EVENT_TX_DMADONE: { const void *data_ptr; rt_size_t data_size; const void *last_data_ptr; struct rt_serial_tx_dma* tx_dma; tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx; rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0); if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK) { /* transmit next data node */ tx_dma->activated = RT_TRUE; serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX); } else { tx_dma->activated = RT_FALSE; } /* invoke callback */ if (serial->parent.tx_complete != RT_NULL) { serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr); } break; } case RT_SERIAL_EVENT_RX_DMADONE: { int length; struct rt_serial_rx_dma* rx_dma; rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; /* get DMA rx length */ length = (event & (~0xff)) >> 8; serial->parent.rx_indicate(&(serial->parent), length); rx_dma->activated = RT_FALSE; break; } } }
static rt_size_t rt_serial_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) { rt_uint8_t *ptr; rt_size_t write_nbytes = 0; struct rt_serial_device *serial; RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; ptr = (rt_uint8_t*)buffer; if (dev->flag & RT_DEVICE_FLAG_INT_TX) { /* warning: data will be discarded if buffer is full */ while (size) { if (serial_ringbuffer_putchar(serial->int_tx, *ptr) != -1) { ptr ++; size --; } else break; } } else if (dev->flag & RT_DEVICE_FLAG_DMA_TX) { const void *data_ptr = RT_NULL; rt_size_t data_size = 0; rt_base_t level; rt_err_t result; RT_ASSERT(0 == (dev->flag & RT_DEVICE_FLAG_STREAM)); result = rt_data_queue_push(&(serial->tx_dq), buffer, size, 20); if (result == RT_EOK) { level = rt_hw_interrupt_disable(); if (serial->dma_flag == RT_FALSE) { serial->dma_flag = RT_TRUE; rt_hw_interrupt_enable(level); if (RT_EOK == rt_data_queue_pop(&(serial->tx_dq), &data_ptr, &data_size, 0)) { serial->ops->dma_transmit(serial, data_ptr, data_size); } } else rt_hw_interrupt_enable(level); return size; } else { rt_set_errno(result); return 0; } } else { /* polling mode */ while (size) { /* * to be polite with serial console add a line feed * to the carriage return character */ if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM)) { serial->ops->putc(serial, '\r'); } serial->ops->putc(serial, *ptr); ++ ptr; -- size; } } write_nbytes = (rt_uint32_t)ptr - (rt_uint32_t)buffer; if (write_nbytes == 0) { rt_set_errno(-RT_EFULL); } return write_nbytes; }