📄 serial.c
字号:
} } else { ret_code = DE_INVAL; } return ret_code;}/* * Set Speed control operation */static DevError c501uart_set_params(DeviceID devid, const ParameterConfig * conf){ word speed; word baud_word; word control_reg; const unsigned int port = SerCtrl(devid)->port; C501UARTReg *const serchip = c501uart_Address(port); if (!Angel_FindParam(AP_BAUD_RATE, conf, &speed)) { LogWarning(LOG_SERIAL, ("c501uart_set_params: Speed parameter not found in config\n")); return DE_OKAY; } switch (speed) { case 1200: baud_word = C501_BAUD_1200; break; case 2400: baud_word = C501_BAUD_2400; break; case 4800: baud_word = C501_BAUD_4800; break; case 9600: baud_word = C501_BAUD_9600; break; case 19200: baud_word = C501_BAUD_19200; break; case 38400: baud_word = C501_BAUD_38400; break; case 57600: baud_word = C501_BAUD_57600; break; case 115200: baud_word = C501_BAUD_115200; break; default: return DE_BAD_OP; } LogInfo(LOG_SERIAL, ("c501uart_set_params: Speed %d (div %d)\n", speed, baud_word)); /* wait for current transmits to complete */ serial_tx_drain(devid); /* This could really hurt with interrupts disabled, so do it here */ /* disable interrupts */ Angel_EnterCriticalSection(); /* disable chip */ control_reg = c501uart_GetControlReg(serchip); c501uart_SetControlReg(serchip, 0); /* Set port for 8 bit, one stop, no parity */ c501uart_SetLineControl( serchip, (ULCR8bits)); /* Enable interrupt operation on UART, needed for normal operation */ c501uart_SetControlReg( serchip, (UCRRxM | UCRTxM)); /* Set baud rate */ c501uart_SetBaudRate( serchip, baud_word ); c501uart_SetControlReg(serchip, control_reg); EnableInterruptNum( DEBUG_COMPORT_RX_INT ); Angel_LeaveCriticalSection(); LogInfo(LOG_SERIAL, ("c501uart_set_params: CR %x\n", control_reg)); return DE_OKAY;}/* * Function: c501uart_ResetDriver * Purpose: Give the UART a hardware reset * * Params: * Input: devid device ID of the driver * * port Serial port identifier * * Returns: Nothing */static void c501uart_ResetDriver(const unsigned int devid, const unsigned int port){ C501UARTReg *const serchip = c501uart_Address(port); DisableInterruptNum( DEBUG_COMPORT_RX_INT ); LogInfo(LOG_SERIAL, ("c501uart_ResetDriver: select 9600\n")); /* * set 9600 baud, take chip out of loopback (if in it) & enable. */ /* Set port for 8 bit, one stop, no parity */ c501uart_SetLineControl( serchip, (ULCR8bits)); /* Enable interrupt operation on UART, needed for normal operation */ c501uart_SetControlReg( serchip, (UCRRxM | UCRRxSI | UCRTxM)); /* Set baud rate */ c501uart_SetBaudRate( serchip, C501_BAUD_9600 ); /* * set default angel config */ (void)c501uart_set_params(devid, &(angel_Device[devid]->default_config));}/* * Reset control operation */static DevError c501uart_reset(DeviceID devid){ const unsigned int port = SerCtrl(devid)->port; c501uart_ResetDriver(devid, port); /* low_level reset */ /* reset private flags (LEAVE lowest 8 bits alone) */ angel_DeviceStatus[devid] &= 0xFF; c501uart_ControlRx(devid); return DE_OKAY;}static DevErrorc501uart_set_led(DeviceID devid, int state){ IGNORE(devid); IGNORE(state); return DE_OKAY;}/* * implementation of device control for serial driver * * devid is guaranteed to be in range but op is not checked as * individual devices can extend the range of operations */static DevError c501uart_Control(DeviceID devid, DeviceControl op, void *arg){ DevError ret_code; LogInfo(LOG_SERIAL, ("c501uart_Control: op %d arg %x\n", op, arg)); /* we only implement the standard ones here */ switch (op) { case DC_INIT: ret_code = c501uart_init(devid); break; case DC_RESET: ret_code = c501uart_reset(devid); break; case DC_RECEIVE_MODE: ret_code = c501uart_recv_mode(devid, (DevRecvMode) ((int)arg)); break; case DC_SET_PARAMS: ret_code = c501uart_set_params(devid, (const ParameterConfig *)arg); break; case DC_SET_LED: ret_code = c501uart_set_led(devid, (int)arg); break; default: ret_code = DE_BAD_OP; break; } return ret_code;}/* * Function: int_* * Purpose: Set of handlers for the uart interrupts. * These routines do all the urgent processing required * for the interrupt condition, and then schedule deferred * routines for the non-urgent processing. * * Pre-conditions: Processor is in IRQ / FIQ mode. * * Params: * Input: devid device ID of the driver * * port serial port identifier * * serchip address of the controller for the given port * * empty_stack top of the stack * * Returns: Nothing */static void int_txrdy(const unsigned int devid, const unsigned int port, C501UARTReg * const serchip, const unsigned int empty_stack){ bool queue_tx_deferred = FALSE; volatile unsigned int *const status = angel_DeviceStatus + devid; RingBuffer *ring = c501uart_TxRingBuf(port); if ((*status & SER_TX_FLOW_CONTROL) != 0 ) { c501uart_SerPutChar(serchip, ((*status & SER_RX_DISABLED) != 0) ? serial_XOFF : serial_XON); *status &= ~SER_TX_FLOW_CONTROL; } /* end if driver wants to send flow control to host */ else { if ( ringBufNotEmpty(ring) ) { c501uart_SerPutChar(serchip, ringBufGetChar(ring)); /* * If we have reached to low-water mark in the ring buffer then it * is time to ask for a refill, as long as there is more of the * packet to come */ if ( (ringBufCount(ring) < RING_LOW_WATER_MARK) && ((*status & SER_TX_EOD) == 0) ) { queue_tx_deferred = TRUE; } } /* end if there's data to send */ if ( ringBufEmpty(ring) ) { /* * If the end of the packet has been sent, then queue deferred * processing of this fact */ if ((*status & SER_TX_EOD) != 0) { /* Turn of interrupts at the IC */ DisableInterruptNum( DEBUG_COMPORT_TX_INT ); angel_DeviceStatus[devid] &= ~SER_TX_IRQ_EN; queue_tx_deferred = TRUE; *status &= ~SER_TX_DATA; } else { /* * queue_tx_deferred will already be set, but we need to set a * flag to tell fill_tx_ring that it needs to restart character * Tx. */ *status |= SER_TX_KICKSTART; } } /* end if there's nothing left to tx */ } /* end else normal tx operation */ if (queue_tx_deferred && ((*status & SER_TX_QUEUED) == 0)) { *status |= SER_TX_QUEUED; /* * NOTE - this routine will never return */ Angel_SerialiseISR(SerCtrl(devid)->tx_processing, (void *)devid); }}#define RXIntPendMask (1 << DEBUG_COMPORT_RX_INT)#define TXIntPendMask (1 << DEBUG_COMPORT_TX_INT)static void int_rxrdy(const unsigned int devid, const unsigned int port, C501UARTReg * const serchip, const unsigned int empty_stack){ bool queue_rx_processing = FALSE; volatile unsigned int *const status = angel_DeviceStatus + devid; RingBuffer *ring = c501uart_RxRingBuf(port); unsigned char sr, ch; /* * Unfortunately there is no FIFO on the C501, so only handle one * character at a time. */ ch = c501uart_SerGetChar(serchip); sr = c501uart_GetLineStatus(serchip); if ( (sr == 0) && ( !ringBufFull(ring) ) ) { ringBufPutChar(ring, ch); if ( (serial_ETX == ch) || (ringBufCount(ring) >= RING_HIGH_WATER_MARK ) ) { queue_rx_processing = TRUE; } } /* end if OK to copy char into ring */ else { queue_rx_processing = TRUE; ringBufSetOvr(ring); ringBufPutChar(ring, ch); } /* else this is an overflow / error condition */ if ( queue_rx_processing && ((*status & SER_RX_QUEUED) == 0) ) { *status |= SER_RX_QUEUED; /* * NOTE - this routine will never return */ Angel_SerialiseISR(SerCtrl(devid)->rx_processing, (void *)devid); } /* end if need to assign a task to process this buffer */}/* * Function: angel_C501UARTIntHandler * Purpose: Entry point for interrupts from the C501UART UART * See documentation for angel_IntHandlerFn in devdriv.h */void angel_C501UARTIntHandler(unsigned int ident, unsigned int devid, unsigned int empty_stack){ unsigned int intsrc; const unsigned int port = SerCtrl(devid)->port; C501UARTReg *const serchip = c501uart_Address(port); IGNORE(ident); intsrc = c501uart_GetInterruptStatus(serchip); /* We handle RX traffic first, so clear that interrupt, if applicable */ if ( (RXIntPendMask & ReadInterruptStatus()) != 0 ) { ClearInterruptStatusMask( RXIntPendMask ); } if ( (intsrc & (USROverrun | USRFraming | USRBreak)) != 0 ) { /* No need to waste time, let the angel driver know they have a problem with this packet */ RingBuffer *ring = c501uart_RxRingBuf(port); volatile unsigned int *const DriverStatus = angel_DeviceStatus + devid; /* Set overrun flag, so the reader function notes that there's an error on the read. */ ringBufSetOvr( ring ); ringBufPutChar( ring, c501uart_SerGetChar(serchip) ); if ( (*DriverStatus & SER_RX_QUEUED) == 0 ) { *DriverStatus |= SER_RX_QUEUED; /* * NOTE - this routine will never return */ Angel_SerialiseISR(SerCtrl(devid)->rx_processing, (void *)devid); } /* It'd be nice to know the scheduler would make sure this error is handled immediately */ } /* end if receive error */ if ( (intsrc & USRRxData) != 0 ) { /* Handle the incoming data */ int_rxrdy(devid, port, serchip, empty_stack); } /* Now handle TX traffic, so clear that interrupt, if applicable */ if ( (TXIntPendMask & ReadInterruptStatus()) != 0 ) { ClearInterruptStatusMask( TXIntPendMask ); if ( (intsrc & USRTxHoldEmpty) != 0 ) { /* Feed the uart */ int_txrdy(devid, port, serchip, empty_stack); } } /* end if there's a pending TX interrupt */ else { if ( ((intsrc & USRTxHoldEmpty) != 0) && (angel_DeviceStatus[devid] & SER_TX_DATA)) { int_txrdy(devid, port, serchip, empty_stack); } /* end if there's an opportunity to piggy back a xmit cycle */ }}#if DEBUG == 1/* Routines for logging debug information to a seperate serial port */void logserial_Reset(int port, int baudvalue){ C501UARTReg *const serchip = (C501UARTReg *)port; /* Disable interrupts */ c501uart_SetControlReg( serchip, 0 ); /* Set port for 8 bit, one stop, no parity */ c501uart_SetLineControl( serchip, (ULCR8bits)); /* Enable interrupt operation on UART, needed for normal operation */ c501uart_SetControlReg( serchip, (UCRRxM | UCRTxM)); /* Set baud rate */ c501uart_SetBaudRate( serchip, baudvalue );}#endif/* EOF serial.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -