diff --git a/arch/arm/src/lpc17xx/lpc17_serial.c b/arch/arm/src/lpc17xx/lpc17_serial.c index dcee165c18c..d58ce7c037a 100755 --- a/arch/arm/src/lpc17xx/lpc17_serial.c +++ b/arch/arm/src/lpc17xx/lpc17_serial.c @@ -74,7 +74,7 @@ #if defined(CONFIG_USE_SERIALDRIVER) && defined(HAVE_UART) -/* Configuration *********************************************************************/ +/* Configuration ************************************************************/ /**************************************************************************** * Private Types @@ -281,7 +281,7 @@ static uart_dev_t g_uart3port = # ifdef CONFIG_LPC17_UART3 # define TTYS3_DEV g_uart3port /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS2;UART3=ttyS3 */ # else - undef TTYS3_DEV /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS;No ttyS3 */ +# undef TTYS3_DEV /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS;No ttyS3 */ # endif # else # ifdef CONFIG_LPC17_UART3 @@ -780,9 +780,8 @@ static inline uint32_t lpc17_uartdl(uint32_t baud, uint8_t divcode) * Name: up_setup * * Description: - * Configure the UART baud, bits, parity, fifos, etc. This - * method is called the first time that the serial port is - * opened. + * Configure the UART baud, bits, parity, fifos, etc. This method is + * called the first time that the serial port is opened. * ****************************************************************************/ @@ -858,8 +857,7 @@ static int up_setup(struct uart_dev_s *dev) * Name: up_shutdown * * Description: - * Disable the UART. This method is called when the serial - * port is closed + * Disable the UART. This method is called when the serial port is closed * ****************************************************************************/ @@ -924,12 +922,11 @@ static void up_detach(struct uart_dev_s *dev) * Name: up_interrupt * * Description: - * This is the UART interrupt handler. It will be invoked - * when an interrupt received on the 'irq' It should call - * uart_transmitchars or uart_receivechar to perform the - * appropriate data transfers. The interrupt handling logic\ - * must be able to map the 'irq' number into the approprite - * uart_dev_s structure in order to call these functions. + * This is the UART interrupt handler. It will be invoked when an + * interrupt received on the 'irq' It should call uart_transmitchars or + * uart_receivechar to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'irq' number into the + * appropriate uart_dev_s structure in order to call these functions. * ****************************************************************************/ diff --git a/arch/arm/src/lpc17xx/lpc17_uart.h b/arch/arm/src/lpc17xx/lpc17_uart.h index 36ede428ba0..830c3244d54 100755 --- a/arch/arm/src/lpc17xx/lpc17_uart.h +++ b/arch/arm/src/lpc17xx/lpc17_uart.h @@ -184,7 +184,7 @@ #define UART_IIR_INTID_MASK (7 << UART_IIR_INTID_SHIFT) # define UART_IIR_INTID_MSI (0 << UART_IIR_INTID_SHIFT) /* Modem Status (UART1 only) */ # define UART_IIR_INTID_THRE (1 << UART_IIR_INTID_SHIFT) /* THRE Interrupt */ -# define UART_IIR_INTID_RDA (2 << UART_IIR_INTID_SHIFT) /* 2a - Receive Data Available (RDA */ +# define UART_IIR_INTID_RDA (2 << UART_IIR_INTID_SHIFT) /* 2a - Receive Data Available (RDA) */ # define UART_IIR_INTID_RLS (3 << UART_IIR_INTID_SHIFT) /* 1 - Receive Line Status (RLS) */ # define UART_IIR_INTID_CTI (6 << UART_IIR_INTID_SHIFT) /* 2b - Character Time-out Indicator (CTI) */ /* Bits 4-5: Reserved */ diff --git a/arch/x86/src/i486/i486_utils.S b/arch/x86/src/i486/i486_utils.S index d94024f78a1..ee89c0c68d4 100644 --- a/arch/x86/src/i486/i486_utils.S +++ b/arch/x86/src/i486/i486_utils.S @@ -42,6 +42,8 @@ #include + .file "i486_utils.S" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -49,73 +51,14 @@ #define KSEG 0x10 /**************************************************************************** - * Nasm - ****************************************************************************/ - -#ifdef CONFIG_X86_NASM - -/**************************************************************************** - * Nasm externals - ****************************************************************************/ - -global gdt_flush -global idt_flush - -/**************************************************************************** - * Nasm macros - ****************************************************************************/ - -/**************************************************************************** - * Nasm .text - ****************************************************************************/ - -SECTION .text -BITS 32 - -/**************************************************************************** - * Name: gdt_flush - ****************************************************************************/ - -gdt_flush: - mov eax, [esp+4] /* Get the pointer to the GDT, passed as a parameter */ - lgdt [eax] /* Load the new GDT pointer */ - - mov $KSEG, ax /* KSEG is the offset in the GDT to our data segment */ - mov ax, ds /* Load all data segment selectors */ - mov ax, es - mov ax, fs - mov ax, gs - mov ax, ss - jmp 0x08:.gflush /* 0x08 is the offset to our code segment: Far jump! */ -.gflush: - ret - -/**************************************************************************** - * Name: idt_flush - ****************************************************************************/ - -idt_flush: - mov eax, [esp+4] /* Get the pointer to the IDT, passed as a parameter */ - lidt [eax] /* Load the IDT pointer */ - ret - -#else /* !CONFIG_X86_NASM (GAS) */ - -/**************************************************************************** - * GAS - ****************************************************************************/ - - .file "i486_utils.S" - -/**************************************************************************** - * GAS Globals + * Globals ****************************************************************************/ .globl gdt_flush .globl idt_flush /**************************************************************************** - * GAS .text + * .text ****************************************************************************/ .text @@ -151,4 +94,3 @@ idt_flush: ret .size idt_flush, . - idt_flush .end -#endif /* CONFIG_X86_NASM */ diff --git a/arch/x86/src/qemu/qemu_fullcontextrestore.S b/arch/x86/src/qemu/qemu_fullcontextrestore.S index 6f15662dd67..7d25e9072ed 100644 --- a/arch/x86/src/qemu/qemu_fullcontextrestore.S +++ b/arch/x86/src/qemu/qemu_fullcontextrestore.S @@ -45,34 +45,36 @@ #include #include "up_internal.h" + .file "qemu_fullcontextrestore.S" + /************************************************************************** * Pre-processor Definitions **************************************************************************/ -/************************************************************************** - * Private Types - **************************************************************************/ - -/************************************************************************** - * Private Function Prototypes - **************************************************************************/ - /************************************************************************** * Global Variables **************************************************************************/ -/************************************************************************** - * Private Variables - **************************************************************************/ +/**************************************************************************** + * Macros + ****************************************************************************/ -/************************************************************************** - * Private Functions - **************************************************************************/ +/* Trace macros, use like trace 'i' to print char to serial port. */ + + .macro trace, ch +#ifdef CONFIG_DEBUG + mov $0x3f8, %dx + mov $\ch, %al + out %al, %dx +#endif + .endm /************************************************************************** * Public Functions **************************************************************************/ + .text + /************************************************************************** * Name: up_fullcontextrestore * @@ -81,11 +83,6 @@ * **************************************************************************/ -#ifdef CONFIG_X86_NASM -# warning "No Nasm support" -#else - .file "qemu_fullcontextrestore.S" - .text .globl up_fullcontextrestore .type up_fullcontextrestore, @function up_fullcontextrestore: @@ -105,38 +102,54 @@ up_fullcontextrestore: movl (4*REG_SP)(%eax), %esp - /* Save the return address, EFLAGS, and the values as well the - * values of EBX and EAC on the new stack. + /* Create an interrupt stack frame for the final iret. + * + * SP Before -> + * SS + * ESP + * EFLAGS + * CS + * SP After -> EIP */ - movl (4*REG_EIP)(%eax), %ebx + mov (4*REG_SS)(%eax), %ebx + push %ebx + movl (4*REG_SP)(%eax), %ebx push %ebx movl (4*REG_EFLAGS)(%eax), %ebx push %ebx + mov (4*REG_CS)(%eax), %ebx + push %ebx + movl (4*REG_EIP)(%eax), %ebx + push %ebx + + /* Save the value of EAX on the stack too */ + movl (4*REG_EAX)(%eax), %ebx push %ebx /* Now restore the remaining registers */ - movl (4*REG_EDI)(%eax), %edi movl (4*REG_ESI)(%eax), %esi + movl (4*REG_EDI)(%eax), %edi movl (4*REG_EBP)(%eax), %ebp + movl (4*REG_EBX)(%eax), %ebx movl (4*REG_EDX)(%eax), %edx movl (4*REG_ECX)(%eax), %ecx - movl (4*REG_EBX)(%eax), %ebx - /* Restore the segment registers */ + /* Restore the data segment register. I think there is an issue that will + * need to be address here at some time: If the register save area is in + * one data segment and the stack is in another, then the above would not + * work (and, conversely, if they are in the same data segment, the + * following is unnecessary and redundant). + */ mov (4*REG_DS)(%eax), %ds - mov (4*REG_CS)(%eax), %cs - mov (4*REG_SS)(%eax), %ss - /* Restore the correct value of EAX, EBX, and the EFLAGS then return */ + /* Restore the correct value of EAX and then return */ popl %eax - popf - ret + iret .size up_fullcontextrestore, . - up_fullcontextrestore .end -#endif /* CONFIG_X86_NASM */ diff --git a/arch/x86/src/qemu/qemu_head.S b/arch/x86/src/qemu/qemu_head.S index 096705f46bd..9933d91ffb9 100755 --- a/arch/x86/src/qemu/qemu_head.S +++ b/arch/x86/src/qemu/qemu_head.S @@ -39,6 +39,8 @@ #include + .file "qemu_head.S" + /**************************************************************************** * Pre-processor definitions ****************************************************************************/ @@ -56,94 +58,35 @@ #define HEAP_BASE (STACKBASE+CONFIG_IDLETHREAD_STACKSIZE) /**************************************************************************** - * Nasm .text + * Macros ****************************************************************************/ -#ifdef CONFIG_X86_NASM -global __start /* Making entry point visible to linker */ -global g_heapbase /* The start of the heap */ -extern os_start /* os_start is defined elsewhere */ -extern up_lowsetup /* up_lowsetup is defined elsewhere */ - -/* Setting up the Multiboot header - see GRUB docs for details */ +/* Trace macros, use like trace 'i' to print char to serial port. */ -MODULEALIGN equ 1<<0 /* Align loaded modules on page boundaries */ -MEMINFO equ 1<<1 /* Provide memory map */ -FLAGS equ MODULEALIGN | MEMINFO /* This is the Multiboot 'flag' field */ -MAGIC equ 0x1badb002 /* 'magic number' lets bootloader find the header */ -CHECKSUM equ -(MAGIC + FLAGS) /* Checksum required */ - -section .text -align 4 -MultiBootHeader: - dd MAGIC - dd FLAGS - dd CHECKSUM - -__start: - /* Set up the stack */ - - mov esp, idle_stack + CONFIG_IDLETHREAD_STACKSIZE - - /* Multiboot setup */ - - push eax /* Pass Multiboot magic number */ - push ebx /* Pass Multiboot info structure */ - - /* Initialize and start NuttX */ - - call up_lowsetup /* Low-level, pre-OS initialization */ - call os_start /* Start NuttX */ - - /* NuttX will not return */ - - cli -hang: - hlt /* Halt machine should NuttX return */ - jmp hang - -/**************************************************************************** - * .bss - ****************************************************************************/ - -/* The stack for the IDLE task thread is declared in .bss. NuttX boots and - * initializes on the IDLE thread, then at the completion of OS startup, this - * thread becomes the thread that executes when there is nothing else to - * do in the system (see up_idle()). - */ - -section .bss -align 4 -idle_stack: - resb CONFIG_IDLETHREAD_STACKSIZE + .macro trace, ch +#ifdef CONFIG_DEBUG + mov $0x3f8, %dx + mov $\ch, %al + out %al, %dx +#endif + .endm /**************************************************************************** - * .rodata + * Global Symbols ****************************************************************************/ -section .rodata - -/* HEAP BASE: _sbss is the start of the BSS region (see ld.script) _ebss is - * the end of the BSS region (see ld.script). The heap continues from there - * until the end of memory. - */ - -align 4 -g_heapbase: - dd _ebss - -#else /* !CONFIG_X86_NASM (GAS) */ - -/**************************************************************************** - * GAS .text - ****************************************************************************/ - - .file "qemu_head.S" .global __start /* Making entry point visible to linker */ .global os_start /* os_start is defined elsewhere */ .global up_lowsetup /* up_lowsetup is defined elsewhere */ .global g_heapbase /* The start of the heap */ +/**************************************************************************** + * .text + ****************************************************************************/ +/**************************************************************************** + * Multiboot Header + ****************************************************************************/ + /* Setting up the Multiboot header - see GRUB docs for details */ .set ALIGN, 1<<0 /* Align loaded modules on page boundaries */ @@ -158,28 +101,24 @@ g_heapbase: .long FLAGS .long CHECKSUM +/**************************************************************************** + * Name: Start + ****************************************************************************/ + .type __start, @function __start: /* Set up the stack */ - mov $'a', %ax - mov $0x3f8, %dx - outb %al, %dx + mov $(idle_stack + CONFIG_IDLETHREAD_STACKSIZE), %esp /* Multiboot setup */ push %eax /* Multiboot magic number */ push %ebx /* Multiboot data structure */ - mov $'b', %ax - mov $0x3f8, %dx - outb %al, %dx /* Initialize and start NuttX */ call up_lowsetup /* Low-level, pre-OS initialization */ - mov $'c', %ax - mov $0x3f8, %dx - outb %al, %dx call os_start /* Start NuttX */ /* NuttX will not return */ @@ -220,4 +159,3 @@ g_heapbase: .long _ebss .size g_heapbase, . - g_heapbase .end -#endif /* CONFIG_X86_NASM */ diff --git a/arch/x86/src/qemu/qemu_irq.c b/arch/x86/src/qemu/qemu_irq.c index f266f67144b..b92db788226 100755 --- a/arch/x86/src/qemu/qemu_irq.c +++ b/arch/x86/src/qemu/qemu_irq.c @@ -78,6 +78,8 @@ uint32_t *current_regs; * Private Data ****************************************************************************/ +static struct idt_entry_s idt_entries[256]; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -171,10 +173,7 @@ static void up_idtentry(struct idt_entry_s *entry, uint32_t base, static inline void up_idtinit(void) { - /* This uses a ton of stack! */ - - struct idt_entry_s idt_entries[256]; - struct idt_ptr_s idt_ptr; + struct idt_ptr_s idt_ptr; idt_ptr.limit = sizeof(struct idt_entry_s) * 256 - 1; idt_ptr.base = (uint32_t)&idt_entries; diff --git a/arch/x86/src/qemu/qemu_lowsetup.c b/arch/x86/src/qemu/qemu_lowsetup.c index bbc7f12299f..bc5aa52e71f 100644 --- a/arch/x86/src/qemu/qemu_lowsetup.c +++ b/arch/x86/src/qemu/qemu_lowsetup.c @@ -52,6 +52,8 @@ * Private Data ****************************************************************************/ +static struct gdt_entry_s gdt_entries[5]; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -93,8 +95,7 @@ static void up_gdtentry(struct gdt_entry_s *entry, uint32_t base, static void up_gdtinit(void) { - struct gdt_entry_s gdt_entries[5]; - struct gdt_ptr_s gdt_ptr; + struct gdt_ptr_s gdt_ptr; up_gdtentry(&gdt_entries[0], 0, 0, 0, 0); /* Null segment */ up_gdtentry(&gdt_entries[1], 0, 0xffffffff, 0x9a, 0xcf); /* Code segment */ diff --git a/arch/x86/src/qemu/qemu_saveusercontext.S b/arch/x86/src/qemu/qemu_saveusercontext.S index 4e38784a4f4..ffa1cf7f627 100644 --- a/arch/x86/src/qemu/qemu_saveusercontext.S +++ b/arch/x86/src/qemu/qemu_saveusercontext.S @@ -45,33 +45,31 @@ #include #include "up_internal.h" -/************************************************************************** - * Private Definitions - **************************************************************************/ + .file "qemu_saveusercontext.S" /************************************************************************** - * Private Types + * Pre-processor Definitions **************************************************************************/ -/************************************************************************** - * Private Function Prototypes - **************************************************************************/ +/**************************************************************************** + * Macros + ****************************************************************************/ + +/* Trace macros, use like trace 'i' to print char to serial port. */ + + .macro trace, ch +#ifdef CONFIG_DEBUG + mov $0x3f8, %dx + mov $\ch, %al + out %al, %dx +#endif + .endm /************************************************************************** - * Global Variables + * .text **************************************************************************/ -/************************************************************************** - * Private Variables - **************************************************************************/ - -/************************************************************************** - * Private Functions - **************************************************************************/ - -/************************************************************************** - * Public Functions - **************************************************************************/ + .text /************************************************************************** * Name: up_saveusercontext @@ -95,11 +93,6 @@ * **************************************************************************/ -#ifdef CONFIG_X86_NASM -# warning "No Nasm support" -#else - .file "qemu_saveusercontext.S" - .text .globl up_saveusercontext .type up_saveusercontext, @function up_saveusercontext: @@ -151,4 +144,3 @@ up_saveusercontext: ret .size up_saveusercontext, . - up_saveusercontext .end -#endif diff --git a/arch/x86/src/qemu/qemu_vectors.S b/arch/x86/src/qemu/qemu_vectors.S index 068ce00c226..a512e1f9516 100755 --- a/arch/x86/src/qemu/qemu_vectors.S +++ b/arch/x86/src/qemu/qemu_vectors.S @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/x86/src/qemu/qemu_head.S + * arch/x86/src/qemu/qemu_head.S * * Copyright (C) 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -43,6 +43,8 @@ #include #include + .file "qemu_vectors.S" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -50,242 +52,20 @@ #define KSEG 0x10 /**************************************************************************** - * Nasm .text + * .text ****************************************************************************/ -#ifdef CONFIG_X86_NASM + .text /**************************************************************************** - * Nasm externals - ****************************************************************************/ - -extern irq_handler -extern isr_handler - -/**************************************************************************** - * Nasm macros - ****************************************************************************/ - -/* Trace macros, use like trace 'i' to print char to serial port. */ - -%macro io_outb 2 - mov dx, %1 /* param1 = address, param2 = data. */ - mov al, %2 - out dx, al -%endmacro - -%macro trace 1 - io_outb 0x3f8, %1 /* diagnostic character */ -%endmacro - -/* This macro creates a stub for an ISR which does NOT pass it's own - * error code (adds a dummy errcode byte). - */ - -%macro ISR_NOERRCODE 1 - global vector_isr%1 - vector_isr%1: - cli /* Disable interrupts firstly. */ - push byte 0 /* Push a dummy error code. */ - push byte %1 /* Push the interrupt number. */ - jmp isr_common /* Go to our common handler code. */ -%endmacro - -/* This macro creates a stub for an ISR which passes it's own - * error code. - */ - -%macro ISR_ERRCODE 1 - global vector_isr%1 - vector_isr%1: - cli /* Disable interrupts. */ - push byte %1 /* Push the interrupt number */ - jmp isr_common -%endmacro - -/* This macro creates a stub for an IRQ - the first parameter is - * the IRQ number, the second is the ISR number it is remapped to. - */ - -%macro IRQ 2 - global vector_irq%1 - vector_irq%1: - cli - push byte 0 - push byte %2 - jmp irq_common -%endmacro - -/**************************************************************************** - * Nasm vectors - ****************************************************************************/ - -/* The following will be the vector address programmed into the IDT */ - -ISR_NOERRCODE ISR0 -ISR_NOERRCODE ISR1 -ISR_NOERRCODE ISR2 -ISR_NOERRCODE ISR3 -ISR_NOERRCODE ISR4 -ISR_NOERRCODE ISR5 -ISR_NOERRCODE ISR6 -ISR_NOERRCODE ISR7 -ISR_ERRCODE ISR8 -ISR_NOERRCODE ISR9 -ISR_ERRCODE ISR10 -ISR_ERRCODE ISR11 -ISR_ERRCODE ISR12 -ISR_ERRCODE ISR13 -ISR_ERRCODE ISR14 -ISR_NOERRCODE ISR15 -ISR_NOERRCODE ISR16 -ISR_NOERRCODE ISR17 -ISR_NOERRCODE ISR18 -ISR_NOERRCODE ISR19 -ISR_NOERRCODE ISR20 -ISR_NOERRCODE ISR21 -ISR_NOERRCODE ISR22 -ISR_NOERRCODE ISR23 -ISR_NOERRCODE ISR24 -ISR_NOERRCODE ISR25 -ISR_NOERRCODE ISR26 -ISR_NOERRCODE ISR27 -ISR_NOERRCODE ISR28 -ISR_NOERRCODE ISR29 -ISR_NOERRCODE ISR30 -ISR_NOERRCODE ISR31 -IRQ 0, IRQ0 -IRQ 1, IRQ1 -IRQ 2, IRQ2 -IRQ 3, IRQ3 -IRQ 4, IRQ4 -IRQ 5, IRQ5 -IRQ 6, IRQ6 -IRQ 7, IRQ7 -IRQ 8, IRQ8 -IRQ 9, IRQ9 -IRQ 10, IRQ10 -IRQ 11, IRQ11 -IRQ 12, IRQ12 -IRQ 13, IRQ13 -IRQ 14, IRQ14 -IRQ 15, IRQ15 - -/**************************************************************************** - * Name: isr_common - * - * Description: - * This is the common ISR logic. It saves the processor state, sets up for - * kernel mode segments, calls the C-level fault handler, and finally - * restores the stack frame. - * - ****************************************************************************/ - -isr_common: -/* trace 'S' */ - pusha /* Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax */ - - mov ax, ds /* Lower 16-bits of eax = ds. */ - push eax /* Save the data segment descriptor */ - - mov ax, KSEG /* Load the kernel data segment descriptor */ - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - /* The current value of the SP points to the beginning of the state save - * structure. Save that on the stack as the input parameter to isr_handler. - */ - - mov esp, eax - push eax - call isr_handler - jmp .Lreturn - -/**************************************************************************** - * Name: irq_common - * - * Description: - * This is the common IRQ logic. It saves the processor state, sets up for - * kernel mode segments, calls the C-level fault handler, and finally - * restores the stack frame. - * - ****************************************************************************/ - -irq_common: -/* trace 'R' */ - pusha /* Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax */ - - mov ax, ds /* Lower 16-bits of eax = ds. */ - push eax /* Save the data segment descriptor */ - - mov ax, KSEG /* Load the kernel data segment descriptor */ - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - /* The current value of the SP points to the beginning of the state save - * structure. Save that on the stack as the input parameter to irq_handler. - */ - - mov esp, eax - push eax - call irq_handler - - /* The common return point for both isr_handler and irq_handler */ - -.Lreturn: - add 4, esp - - /* EAX may possibly hold a pointer to a different regiser save area on - * return. Are we switching to a new context? - */ - - cmp eax, esp - je .Lnoswitch - - /* A context swith will be performed. EAX holds the address of the new - * register save structure. - * - * 'Jump' to up_fullcontextrestore(). We perform a call here, but that function - * never returns. The address of the new register save block is the argument - * to the up_fullcontextrestore(). - */ - - push eax - jmp up_fullcontext - -.Lnoswitch: - pop ebx /* Reload the original data segment descriptor */ - mov ds, bx - mov es, bx - mov fs, bx - mov gs, bx - - popa /* Pops edi,esi,ebp... */ - add esp, 8 /* Cleans up the pushed error code and pushed ISR number */ - sti - iret /* Pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP */ - -#else /* !CONFIG_X86_NASM (GAS) */ - -/**************************************************************************** - * GAS .text - ****************************************************************************/ - - .file "qemu_vectors.S" - -/**************************************************************************** - * GAS globals + * Globals ****************************************************************************/ .globl irq_handler .globl isr_handler /**************************************************************************** - * GAS macros + * Macros ****************************************************************************/ /* Trace macros, use like trace 'i' to print char to serial port. */ @@ -334,7 +114,10 @@ vector_irq\irqno: jmp isr_common /* Go to the common handler code. */ .endm - /* The following will be the vector address programmed into the IDT */ +/**************************************************************************** + * IDT Vectors + ****************************************************************************/ +/* The following will be the vector addresses programmed into the IDT */ ISR_NOERRCODE ISR0 ISR_NOERRCODE ISR1 @@ -487,4 +270,3 @@ irq_common: iret /* Pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP */ .size irq_common, . - irq_common .end -#endif /* CONFIG_X86_NASM */ diff --git a/configs/qemu-i486/ostest/defconfig b/configs/qemu-i486/ostest/defconfig index e7541be174a..f0e558d4a82 100644 --- a/configs/qemu-i486/ostest/defconfig +++ b/configs/qemu-i486/ostest/defconfig @@ -68,7 +68,6 @@ # the 100 second delay then adjust CONFIG_BOARD_LOOPSPERMSEC until # the delay actually is 100 seconds. # CONFIG_ARCH_DMA - Support DMA initialization -# CONFIG_X86_NASM - Using Nasm instead of GAS # CONFIG_ARCH=x86 CONFIG_ARCH_X86=y @@ -87,7 +86,6 @@ CONFIG_ARCH_LEDS=n CONFIG_ARCH_BUTTONS=n CONFIG_ARCH_CALIBRATION=n CONFIG_ARCH_DMA=n -CONFIG_X86_NASM=n # # General OS setup @@ -149,8 +147,8 @@ CONFIG_X86_NASM=n # to be closed in the new task. # CONFIG_APP_DIR=examples/ostest -CONFIG_DEBUG=y -CONFIG_DEBUG_VERBOSE=y +CONFIG_DEBUG=n +CONFIG_DEBUG_VERBOSE=n CONFIG_DEBUG_SYMBOLS=n CONFIG_MM_REGIONS=1 CONFIG_ARCH_LOWPUTC=y diff --git a/drivers/serial/uart_16550.c b/drivers/serial/uart_16550.c new file mode 100755 index 00000000000..e65d5ccedf3 --- /dev/null +++ b/drivers/serial/uart_16550.c @@ -0,0 +1,1092 @@ +/**************************************************************************** + * drivers/serial/uart_16550.c + * Serial driver for 16550 UART + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#ifdef CONFIG_UART_16550 + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct uart_16550_s +{ + uart_addrwidth_t uartbase; /* Base address of UART registers */ + uint32_t baud; /* Configured baud */ + uint32_t uartclk; /* UART clock frequency */ + uart_datawidth_t ier; /* Saved IER value */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int uart_setup(struct uart_dev_s *dev); +static void uart_shutdown(struct uart_dev_s *dev); +static int uart_attach(struct uart_dev_s *dev); +static void uart_detach(struct uart_dev_s *dev); +static int uart_interrupt(int irq, void *context); +static int uart_ioctl(struct file *filep, int cmd, unsigned long arg); +static int uart_receive(struct uart_dev_s *dev, uint32_t *status); +static void uart_rxint(struct uart_dev_s *dev, bool enable); +static bool uart_rxavailable(struct uart_dev_s *dev); +static void uart_send(struct uart_dev_s *dev, int ch); +static void uart_txint(struct uart_dev_s *dev, bool enable); +static bool uart_txready(struct uart_dev_s *dev); +static bool uart_txempty(struct uart_dev_s *dev); + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +struct uart_ops_s g_uart_ops = +{ + .setup = uart_setup, + .shutdown = uart_shutdown, + .attach = uart_attach, + .detach = uart_detach, + .ioctl = uart_ioctl, + .receive = uart_receive, + .rxint = uart_rxint, + .rxavailable = uart_rxavailable, + .send = uart_send, + .txint = uart_txint, + .txready = uart_txready, + .txempty = uart_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_16550_UART0 +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; +#endif +#ifdef CONFIG_16550_UART1 +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif +#ifdef CONFIG_16550_UART2 +static char g_uart2rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif +#ifdef CONFIG_16550_UART3 +static char g_uart3rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart3txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif + +/* This describes the state of the LPC17xx uart0 port. */ + +#ifdef CONFIG_16550_UART0 +static struct uart_16550_s g_uart0priv = +{ + .uartbase = CONFIG_16550_UART0_BASE, + .baud = CONFIG_UART0_BAUD, + .uartclk = CONFIG_16550_UART0_CLOCK, + .irq = CONFIG_16550_UART0_IRQ, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, +}; + +static uart_dev_t g_uart0port = +{ + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +/* This describes the state of the LPC17xx uart1 port. */ + +#ifdef CONFIG_16550_UART1 +static struct uart_16550_s g_uart1priv = +{ + .uartbase = CONFIG_16550_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .uartclk = CONFIG_16550_UART1_CLOCK, + .irq = CONFIG_16550_UART1_IRQ, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, +}; + +static uart_dev_t g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +/* This describes the state of the LPC17xx uart1 port. */ + +#ifdef CONFIG_16550_UART2 +static struct uart_16550_s g_uart2priv = +{ + .uartbase = CONFIG_16550_UART2_BASE, + .baud = CONFIG_UART2_BAUD, + .uartclk = CONFIG_16550_UART2_CLOCK, + .irq = CONFIG_16550_UART2_IRQ, + .parity = CONFIG_UART2_PARITY, + .bits = CONFIG_UART2_BITS, + .stopbits2 = CONFIG_UART2_2STOP, +}; + +static uart_dev_t g_uart2port = +{ + .recv = + { + .size = CONFIG_UART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +/* This describes the state of the LPC17xx uart1 port. */ + +#ifdef CONFIG_16550_UART3 +static struct uart_16550_s g_uart3priv = +{ + .uartbase = CONFIG_16550_UART3_BASE, + .baud = CONFIG_UART3_BAUD, + .uartclk = CONFIG_16550_UART3_CLOCK, + .irq = CONFIG_16550_UART3_IRQ, + .parity = CONFIG_UART3_PARITY, + .bits = CONFIG_UART3_BITS, + .stopbits2 = CONFIG_UART3_2STOP, +}; + +static uart_dev_t g_uart3port = +{ + .recv = + { + .size = CONFIG_UART3_RXBUFSIZE, + .buffer = g_uart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART3_TXBUFSIZE, + .buffer = g_uart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart3priv, +}; +#endif + +/* Which UART with be tty0/console and which tty1? tty2? tty3? */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port /* UART0=console */ +# define TTYS0_DEV g_uart0port /* UART0=ttyS0 */ +# ifdef CONFIG_16550_UART1 +# define TTYS1_DEV g_uart1port /* UART0=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_16550_UART2 +# define TTYS2_DEV g_uart2port /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS2 */ +# ifdef CONFIG_16550_UART3 +# define TTYS3_DEV g_uart3port /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS2;UART3=ttyS3 */ +# else +# undef TTYS3_DEV /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART0=ttyS0;UART1=ttyS1;UART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART0=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART2 +# define TTYS1_DEV g_uart2port /* UART0=ttyS0;UART2=ttyS1;No ttyS3 */ +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART0=ttyS0;UART2=ttyS1;UART3=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART0=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_16550_UART3 +# define TTYS1_DEV g_uart3port /* UART0=ttyS0;UART3=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* UART0=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1=console */ +# define TTYS0_DEV g_uart1port /* UART1=ttyS0 */ +# ifdef CONFIG_16550_UART +# define TTYS1_DEV g_uart0port /* UART1=ttyS0;UART0=ttyS1 */ +# ifdef CONFIG_16550_UART2 +# define TTYS2_DEV g_uart2port /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS2 */ +# ifdef CONFIG_16550_UART3 +# define TTYS3_DEV g_uart3port /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS2;UART3=ttyS3 */ +# else +# undef TTYS3_DEV /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART1=ttyS0;UART0=ttyS1;UART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART1=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART2 +# define TTYS1_DEV g_uart2port /* UART1=ttyS0;UART2=ttyS1 */ +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART1=ttyS0;UART2=ttyS1;UART3=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART1=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_16550_UART3 +# define TTYS1_DEV g_uart3port /* UART1=ttyS0;UART3=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* UART1=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* UART2=console */ +# define TTYS0_DEV g_uart2port /* UART2=ttyS0 */ +# ifdef CONFIG_16550_UART +# define TTYS1_DEV g_uart0port /* UART2=ttyS0;UART0=ttyS1 */ +# ifdef CONFIG_16550_UART1 +# define TTYS2_DEV g_uart1port /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS2 */ +# ifdef CONFIG_16550_UART3 +# define TTYS3_DEV g_uart3port /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS2;UART3=ttyS3 */ +# else +# undef TTYS3_DEV /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART2=ttyS0;UART0=ttyS1;UART3=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART2=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART1 +# define TTYS1_DEV g_uart1port /* UART2=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_16550_UART3 +# define TTYS2_DEV g_uart3port /* UART2=ttyS0;UART1=ttyS1;UART3=ttyS2 */ +# else +# undef TTYS2_DEV /* UART2=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_16550_UART3 +# define TTYS1_DEV g_uart3port /* UART2=ttyS0;UART3=ttyS1;No ttyS3 */ +# else +# undef TTYS1_DEV /* UART2=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +#elif defined(CONFIG_UART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart3port /* UART3=console */ +# define TTYS0_DEV g_uart3port /* UART3=ttyS0 */ +# ifdef CONFIG_16550_UART +# define TTYS1_DEV g_uart0port /* UART3=ttyS0;UART0=ttyS1 */ +# ifdef CONFIG_16550_UART1 +# define TTYS2_DEV g_uart1port /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS2 */ +# ifdef CONFIG_16550_UART2 +# define TTYS3_DEV g_uart2port /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS2;UART2=ttyS3 */ +# else +# undef TTYS3_DEV /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS;No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART2 +# define TTYS2_DEV g_uart2port /* UART3=ttyS0;UART0=ttyS1;UART2=ttys2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART3=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# else +# ifdef CONFIG_16550_UART1 +# define TTYS1_DEV g_uart1port /* UART3=ttyS0;UART1=ttyS1 */ +# ifdef CONFIG_16550_UART2 +# define TTYS2_DEV g_uart2port /* UART3=ttyS0;UART1=ttyS1;UART2=ttyS2;No ttyS3 */ +# else +# undef TTYS2_DEV /* UART3=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS3_DEV /* No ttyS3 */ +# else +# ifdef CONFIG_16550_UART2 +# define TTYS1_DEV g_uart2port /* UART3=ttyS0;UART2=ttyS1;No ttyS3;No ttyS3 */ +# undef TTYS3_DEV /* UART3=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ +# else +# undef TTYS1_DEV /* UART3=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ +# endif +# undef TTYS2_DEV /* No ttyS2 */ +# undef TTYS3_DEV /* No ttyS3 */ +# endif +# endif +#endif + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +/**************************************************************************** + * Name: uart_serialin + ****************************************************************************/ + +static inline uart_datawidth_t uart_serialin(struct uart_16550_s *priv, int offset) +{ + return uart_getreg(priv->uartbase, offset); +} + +/**************************************************************************** + * Name: uart_serialout + ****************************************************************************/ + +static inline void uart_serialout(struct uart_16550_s *priv, int offset, uart_datawidth_t value) +{ + uart_putreg(priv->uartbase, offset, value); +} + +/**************************************************************************** + * Name: uart_disableuartint + ****************************************************************************/ + +static inline void uart_disableuartint(struct uart_16550_s *priv, uart_datawidth_t *ier) +{ + if (ier) + { + *ier = priv->ier & UART_IER_ALLIE; + } + + priv->ier &= ~UART_IER_ALLIE; + uart_serialout(priv, UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: uart_restoreuartint + ****************************************************************************/ + +static inline void uart_restoreuartint(struct uart_16550_s *priv, uint32_t ier) +{ + priv->ier |= ier & UART_IER_ALLIE; + uart_serialout(priv, UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: uart_enablebreaks + ****************************************************************************/ + +static inline void uart_enablebreaks(struct uart_16550_s *priv, bool enable) +{ + uint32_t lcr = uart_serialin(priv, UART_LCR_OFFSET); + if (enable) + { + lcr |= UART_LCR_BRK; + } + else + { + lcr &= ~UART_LCR_BRK; + } + uart_serialout(priv, UART_LCR_OFFSET, lcr); +} + +/************************************************************************************ + * Name: uart_divisor + * + * Descrption: + * Select a divider to produce the BAUD from the UART_CLK. + * + * BAUD = UART_CLK / (16 * DL), or + * DIV = UART_CLK / BAUD / 16 + * + * Ignoring the fractional divider for now. + * + ************************************************************************************/ + +static inline uint32_t uart_divisor(struct uart_16550_s *priv) +{ + return (priv->uartclk + (priv->baud << 3)) / (priv->baurd << 4); +} + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uart_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial port is + * opened. + * + ****************************************************************************/ + +static int uart_setup(struct uart_dev_s *dev) +{ +#ifndef CONFIG_16550_SUPRESS_CONFIG + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + uint16_t div; + uint32_t lcr; + + /* Clear fifos */ + + uart_serialout(priv, UART_FCR_OFFSET, (UART_FCR_RXRST|UART_FCR_TXRST)); + + /* Set trigger */ + + uart_serialout(priv, UART_FCR_OFFSET, (UART_FCR_FIFOEN|UART_FCR_RXTRIGGER_8)); + + /* Set up the IER */ + + priv->ier = uart_serialin(priv, UART_IER_OFFSET); + + /* Set up the LCR */ + + lcr = 0; + switch (priv->bits) + { + case 5 : + lcr |= UART_LCR_WLS_7BIT; + break; + + case 6 : + lcr |= UART_LCR_WLS_7BIT; + break; + + case 7 : + lcr |= UART_LCR_WLS_7BIT; + break; + + default: + case 8 : + lcr |= UART_LCR_WLS_7BIT; + break; + } + + if (priv->stopbits2) + { + lcr |= UART_LCR_STB; + } + + if (priv->parity == 1) + { + lcr |= UART_LCR_PEN; + } + else if (priv->parity == 2) + { + lcr |= (UART_LCR_PEN|UART_LCR_EPS); + } + + /* Enter DLAB=1 */ + + uart_serialout(priv, UART_LCR_OFFSET, (lcr | UART_LCR_DLAB)); + + /* Set the BAUD divisor */ + + div = uart_divisor(priv); + uart_serialout(priv, UART_DLM_OFFSET, div >> 8); + uart_serialout(priv, UART_DLL_OFFSET, div & 0xff); + + /* Clear DLAB */ + + uart_serialout(priv, UART_LCR_OFFSET, lcr); + + /* Configure the FIFOs */ + + uart_serialout(priv, UART_FCR_OFFSET, + (UART_FCR_RXTRIGGER_8|UART_FCR_TXRST|UART_FCR_RXRST|UART_FCR_FIFOEN)); +#endif + return OK; +} + +/**************************************************************************** + * Name: uart_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void uart_shutdown(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + uart_disableuartint(priv, NULL); +} + +/**************************************************************************** + * Name: uart_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method is + * called when the serial port is opened. Normally, this is just after the + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless the + * hardware supports multiple levels of interrupt enabling). The RX and TX + * interrupts are not enabled until the txint() and rxint() methods are called. + * + ****************************************************************************/ + +static int uart_attach(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, uart_interrupt); +#ifndef CONFIG_ARCH_NOINTC + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + uart_enable_irq(priv->irq); + } +endif + return ret; +} + +/**************************************************************************** + * Name: uart_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The exception is + * the serial console which is never shutdown. + * + ****************************************************************************/ + +static void uart_detach(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; +#ifndef CONFIG_ARCH_NOINTC + uart_disable_irq(priv->irq); +#endif + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: uart_interrupt + * + * Description: + * This is the UART interrupt handler. It will be invoked when an + * interrupt received on the 'irq' It should call uart_transmitchars or + * uart_receivechar to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'irq' number into the + * appropriate uart_16550_s structure in order to call these functions. + * + ****************************************************************************/ + +static int uart_interrupt(int irq, void *context) +{ + struct uart_dev_s *dev = NULL; + struct uart_16550_s *priv; + uint32_t status; + int passes; + +#ifdef CONFIG_16550_UART0 + if (g_uart0priv.irq == irq) + { + dev = &g_uart0port; + } + else +#endif +#ifdef CONFIG_16550_UART1 + if (g_uart1priv.irq == irq) + { + dev = &g_uart1port; + } + else +#endif +#ifdef CONFIG_16550_UART2 + if (g_uart2priv.irq == irq) + { + dev = &g_uart2port; + } + else +#endif +#ifdef CONFIG_16550_UART3 + if (g_uart3priv.irq == irq) + { + dev = &g_uart3port; + } + else +#endif + { + PANIC(OSERR_INTERNAL); + } + priv = (struct uart_16550_s*)dev->priv; + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + for (passes = 0; passes < 256; passes++) + { + /* Get the current UART status and check for loop + * termination conditions + */ + + status = uart_serialin(priv, UART_IIR_OFFSET); + + /* The UART_IIR_INTSTATUS bit should be zero if there are pending + * interrupts + */ + + if ((status & UART_IIR_INTSTATUS) != 0) + { + /* Break out of the loop when there is no longer a + * pending interrupt + */ + + break; + } + + /* Handle the interrupt by its interrupt ID field */ + + switch (status & UART_IIR_INTID_MASK) + { + /* Handle incoming, receive bytes (with or without timeout) */ + + case UART_IIR_INTID_RDA: + case UART_IIR_INTID_CTI: + { + uart_recvchars(dev); + break; + } + + /* Handle outgoing, transmit bytes */ + + case UART_IIR_INTID_THRE: + { + uart_xmitchars(dev); + break; + } + + /* Just clear modem status interrupts (UART1 only) */ + + case UART_IIR_INTID_MSI: + { + /* Read the modem status register (MSR) to clear */ + + status = uart_serialin(priv, UART_MSR_OFFSET); + vdbg("MSR: %02x\n", status); + break; + } + + /* Just clear any line status interrupts */ + + case UART_IIR_INTID_RLS: + { + /* Read the line status register (LSR) to clear */ + + status = uart_serialin(priv, UART_LSR_OFFSET); + vdbg("LSR: %02x\n", status); + break; + } + + /* There should be no other values */ + + default: + { + dbg("Unexpected IIR: %02x\n", status); + break; + } + } + } + return OK; +} + +/**************************************************************************** + * Name: uart_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int uart_ioctl(struct file *filep, int cmd, unsigned long arg) +{ + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + int ret = OK; + + switch (cmd) + { + case TIOCSERGSTRUCT: + { + struct uart_16550_s *user = (struct uart_16550_s*)arg; + if (!user) + { + *get_errno_ptr() = EINVAL; + ret = ERROR; + } + else + { + memcpy(user, dev, sizeof(struct uart_16550_s)); + } + } + break; + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + { + irqstate_t flags = irqsave(); + uart_enablebreaks(priv, true); + irqrestore(flags); + } + break; + + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + { + irqstate_t flags; + flags = irqsave(); + uart_enablebreaks(priv, false); + irqrestore(flags); + } + break; + + default: + *get_errno_ptr() = ENOTTY; + ret = ERROR; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: uart_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int uart_receive(struct uart_dev_s *dev, uint32_t *status) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + uint32_t rbr; + + *status = uart_serialin(priv, UART_LSR_OFFSET); + rbr = uart_serialin(priv, UART_RBR_OFFSET); + return rbr; +} + +/**************************************************************************** + * Name: uart_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void uart_rxint(struct uart_dev_s *dev, bool enable) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ier |= UART_IER_ERBFI; +#endif + } + else + { + priv->ier &= ~UART_IER_ERBFI; + } + uart_serialout(priv, UART_IER_OFFSET, priv->ier); +} + +/**************************************************************************** + * Name: uart_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool uart_rxavailable(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + return ((uart_serialin(priv, UART_LSR_OFFSET) & UART_LSR_RDR) != 0); +} + +/**************************************************************************** + * Name: uart_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void uart_send(struct uart_dev_s *dev, int ch) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + uart_serialout(priv, UART_THR_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: uart_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void uart_txint(struct uart_dev_s *dev, bool enable) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + irqstate_t flags; + + flags = irqsave(); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ier |= UART_IER_ETBEI; + uart_serialout(priv, UART_IER_OFFSET, priv->ier); + + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); +#endif + } + else + { + priv->ier &= ~UART_IER_ETBEI; + uart_serialout(priv, UART_IER_OFFSET, priv->ier); + } + irqrestore(flags); +} + +/**************************************************************************** + * Name: uart_txready + * + * Description: + * Return true if the tranmsit fifo is not full + * + ****************************************************************************/ + +static bool uart_txready(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + return ((uart_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) != 0); +} + +/**************************************************************************** + * Name: uart_txempty + * + * Description: + * Return true if the transmit fifo is empty + * + ****************************************************************************/ + +static bool uart_txempty(struct uart_dev_s *dev) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)dev->priv; + return ((uart_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) != 0); +} + +/**************************************************************************** + * Public Funtions + ****************************************************************************/ + +/**************************************************************************** + * Name: uart_serialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before uart_serialinit. + * + * NOTE: Configuration of the CONSOLE UART was performed by uart_lowsetup() + * very early in the boot sequence. + * + ****************************************************************************/ + +void uart_earlyserialinit(void) +{ + /* Configure all UARTs (except the CONSOLE UART) and disable interrupts */ + +#ifdef CONFIG_16550_UART0 + uart_disableuartint(&g_uart0priv, NULL); +#endif +#ifdef CONFIG_16550_UART1 + uart_disableuartint(&g_uart1priv, NULL); +#endif + uart_disableuartint(&g_uart2priv, NULL); +#endif + uart_disableuartint(&g_uart3priv, NULL); +#endif + + /* Configuration whichever one is the console */ + +#ifdef CONSOLE_DEV + CONSOLE_DEV.isconsole = true; + uart_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: uart_serialinit + * + * Description: + * Register serial console and serial ports. This assumes that + * uart_earlyserialinit was called previously. + * + ****************************************************************************/ + +void uart_serialinit(void) +{ +#ifdef CONSOLE_DEV + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif +#ifdef TTYS0_DEV + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#endif +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +#ifdef TTYS3_DEV + (void)uart_register("/dev/ttyS3", &TTYS3_DEV); +#endif +} + +/**************************************************************************** + * Name: uart_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +#ifdef HAVE_16550_CONSOLE +int uart_putc(int ch) +{ + struct uart_16550_s *priv = (struct uart_16550_s*)CONSOLE_DEV.priv; + uart_datawidth_t ier; + + uart_disableuartint(priv, &ier); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + uart_lowputc('\r'); + } + + uart_lowputc(ch); + uart_restoreuartint(priv, ier); + return ch; +} +#endif + +#endif /* CONFIG_UART_16550 */ diff --git a/include/nuttx/ioctl.h b/include/nuttx/ioctl.h index c3b83cf0487..5eaf886c8aa 100644 --- a/include/nuttx/ioctl.h +++ b/include/nuttx/ioctl.h @@ -52,13 +52,13 @@ */ #define _TIOCBASE (0x5400) /* Terminal I/O ioctl commands */ -#define _WDIOCBASE (0x5400) /* Watchdog driver ioctl commands */ +#define _WDIOCBASE (0x5500) /* Watchdog driver ioctl commands */ #define _FIOCBASE (0x8700) /* File system ioctl commands */ #define _DIOCBASE (0x8800) /* Character driver ioctl commands */ #define _BIOCBASE (0x8900) /* Block driver ioctl commands */ #define _MTDIOCBASE (0x8a00) /* MTD ioctl commands */ -#define _SIOCBASE (0x8b00) /* Socket ioctl commandss */ -#define _ARPBASE (0x8c00) /* ARP ioctl commandss */ +#define _SIOCBASE (0x8b00) /* Socket ioctl commands */ +#define _ARPBASE (0x8c00) /* ARP ioctl commands */ /* Macros used to manage ioctl commands */ diff --git a/include/nuttx/uart_16550.h b/include/nuttx/uart_16550.h new file mode 100755 index 00000000000..cdad637e019 --- /dev/null +++ b/include/nuttx/uart_16550.h @@ -0,0 +1,351 @@ +/************************************************************************************ + * include/nuttx/uart_16550.h + * Serial driver for 16550 UART + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __INCLUDE_NUTTX_UART_16550_H +#define __INCLUDE_NUTTX_UART_16550_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#ifdef CONFIG_UART_16550 + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* CONFIGURATION ********************************************************************/ + +/* Are any UARTs enabled? */ + +#undef HAVE_UART +#if defined(CONFIG_16550_UART0) || defined(CONFIG_16550_UART1) || \ + defined(CONFIG_16550_UART2) || defined(CONFIG_16550_UART3) +# define HAVE_UART 1 +#endif + +/* We need to be told the address increment between registers and the register bit + * width. + */ + +#ifndef CONFIG_16550_REGINCR +# error "CONFIG_16550_REGINCR not defined" +#endif + +#if CONFIG_16550_REGINCR != 1 && CONFIG_16550_REGINCR != 2 && CONFIG_16550_REGINCR != 4 +# error "CONFIG_16550_REGINCR not supported" +#endif + +#ifndef CONFIG_16550_REGWIDTH +# error "CONFIG_16550_REGWIDTH not defined" +#endif + +#if CONFIG_16550_REGWIDTH != 1 && CONFIG_16550_REGWIDTH != 2 && CONFIG_16550_REGWIDTH != 4 +# error "CONFIG_16550_REGWIDTH not supported" +#endif + +#ifndef CONFIG_16550_ADDRWIDTH +# error "CONFIG_16550_ADDRWIDTH not defined" +#endif + +#if CONFIG_16550_ADDRWIDTH != 1 && CONFIG_16550_ADDRWIDTH != 2 && CONFIG_16550_ADDRWIDTH != 4 +# error "CONFIG_16550_ADDRWIDTH not supported" +#endif + +/* If a UART is enabled, then its base address, clock, and IRQ must also be provided */ + +#ifdef CONFIG_16550_UART0 +# ifndef CONFIG_16550_UART0_BASE +# error "CONFIG_16550_UART0_BASE not provided" +# undef CONFIG_16550_UART0 +# endif +# ifndef CONFIG_16550_UART0_CLOCK +# error "CONFIG_16550_UART0_CLOCK not provided" +# undef CONFIG_16550_UART0 +# endif +# ifndef CONFIG_16550_UART0_IRQ +# error "CONFIG_16550_UART0_IRQ not provided" +# undef CONFIG_16550_UART0 +# endif +#endif + +#ifdef CONFIG_16550_UART1 +# ifndef CONFIG_16550_UART1_BASE +# error "CONFIG_16550_UART1_BASE not provided" +# undef CONFIG_16550_UART1 +# endif +# ifndef CONFIG_16550_UART1_CLOCK +# error "CONFIG_16550_UART1_CLOCK not provided" +# undef CONFIG_16550_UART1 +# endif +# ifndef CONFIG_16550_UART1_IRQ +# error "CONFIG_16550_UART1_IRQ not provided" +# undef CONFIG_16550_UART1 +# endif +#endif + +#ifdef CONFIG_16550_UART2 +# ifndef CONFIG_16550_UART2_BASE +# error "CONFIG_16550_UART2_BASE not provided" +# undef CONFIG_16550_UART2 +# endif +# ifndef CONFIG_16550_UART2_CLOCK +# error "CONFIG_16550_UART2_CLOCK not provided" +# undef CONFIG_16550_UART2 +# endif +# ifndef CONFIG_16550_UART2_IRQ +# error "CONFIG_16550_UART2_IRQ not provided" +# undef CONFIG_16550_UART2 +# endif +#endif + +#ifdef CONFIG_16550_UART3 +# ifndef CONFIG_16550_UART3_BASE +# error "CONFIG_16550_UART3_BASE not provided" +# undef CONFIG_16550_UART3 +# endif +# ifndef CONFIG_16550_UART3_CLOCK +# error "CONFIG_16550_UART3_CLOCK not provided" +# undef CONFIG_16550_UART3 +# endif +# ifndef CONFIG_16550_UART3_IRQ +# error "CONFIG_16550_UART3_IRQ not provided" +# undef CONFIG_16550_UART3 +# endif +#endif + +/* Is there a serial console? There should be at most one defined. It could be on + * any UARTn, n=0,1,2,3 + */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) && defined(CONFIG_16550_UART0) +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# define HAVE_16550_CONSOLE 1 +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_16550_UART1) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# define HAVE_16550_CONSOLE 1 +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) && defined(CONFIG_16550_UART2) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# define HAVE_16550_CONSOLE 1 +#elif defined(CONFIG_UART3_SERIAL_CONSOLE) && defined(CONFIG_16550_UART3) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# define HAVE_16550_CONSOLE 1 +#else +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef HAVE_16550_CONSOLE +#endif + +/* Register offsets *****************************************************************/ + +#define UART_RBR_INCR 0 /* (DLAB =0) Receiver Buffer Register */ +#define UART_THR_INCR 0 /* (DLAB =0) Transmit Holding Register */ +#define UART_DLL_INCR 0 /* (DLAB =1) Divisor Latch LSB */ +#define UART_DLM_INCR 1 /* (DLAB =1) Divisor Latch MSB */ +#define UART_IER_INCR 1 /* (DLAB =0) Interrupt Enable Register */ +#define UART_IIR_INCR 2 /* Interrupt ID Register */ +#define UART_FCR_INCR 2 /* FIFO Control Register */ +#define UART_LCR_INCR 3 /* Line Control Register */ +#define UART_MCR_INCR 4 /* Modem Control Register */ +#define UART_LSR_INCR 5 /* Line Status Register */ +#define UART_MSR_INCR 6 /* Modem Status Register */ +#define UART_SCR_INCR 7 /* Scratch Pad Register */ + +#define UART_RBR_OFFSET (CONFIG_16550_REGINCR*UART_RBR_INCR) +#define UART_THR_OFFSET (CONFIG_16550_REGINCR*UART_THR_INCR) +#define UART_DLL_OFFSET (CONFIG_16550_REGINCR*UART_DLL_INCR) +#define UART_DLM_OFFSET (CONFIG_16550_REGINCR*UART_DLM_INCR) +#define UART_IER_OFFSET (CONFIG_16550_REGINCR*UART_IER_INCR) +#define UART_IIR_OFFSET (CONFIG_16550_REGINCR*UART_IIR_INCR) +#define UART_FCR_OFFSET (CONFIG_16550_REGINCR*UART_FCR_INCR) +#define UART_LCR_OFFSET (CONFIG_16550_REGINCR*UART_LCR_INCR) +#define UART_MCR_OFFSET (CONFIG_16550_REGINCR*UART_MCR_INCR) +#define UART_LSR_OFFSET (CONFIG_16550_REGINCR*UART_LSR_INCR) +#define UART_MSR_OFFSET (CONFIG_16550_REGINCR*UART_MSR_INCR) +#define UART_SCR_OFFSET (CONFIG_16550_REGINCR*UART_SCR_INCR) + +/* Register bit definitions *********************************************************/ + +/* RBR (DLAB =0) Receiver Buffer Register */ + +#define UART_RBR_MASK (0xff) /* Bits 0-7: Oldest received byte in RX FIFO */ + /* Bits 8-31: Reserved */ + +/* THR (DLAB =0) Transmit Holding Register */ + +#define UART_THR_MASK (0xff) /* Bits 0-7: Adds byte to TX FIFO */ + /* Bits 8-31: Reserved */ + +/* DLL (DLAB =1) Divisor Latch LSB */ + +#define UART_DLL_MASK (0xff) /* Bits 0-7: DLL */ + /* Bits 8-31: Reserved */ + +/* DLM (DLAB =1) Divisor Latch MSB */ + +#define UART_DLM_MASK (0xff) /* Bits 0-7: DLM */ + /* Bits 8-31: Reserved */ + +/* IER (DLAB =0) Interrupt Enable Register */ + +#define UART_IER_ERBFI (1 << 0) /* Bit 0: Enable received data available interrupt */ +#define UART_IER_ETBEI (1 << 1) /* Bit 1: Enable THR empty interrupt */ +#define UART_IER_ELSI (1 << 2) /* Bit 2: Enable receiver line status interrupt */ +#define UART_IER_EDSSI (1 << 3) /* Bit 3: Enable MODEM status interrupt */ + /* Bits 4-7: Reserved */ +#define UART_IER_ALLIE (0x0f) + +/* IIR Interrupt ID Register */ + +#define UART_IIR_INTSTATUS (1 << 0) /* Bit 0: Interrupt status (active low) */ +#define UART_IIR_INTID_SHIFT (1) /* Bits 1-3: Interrupt identification */ +#define UART_IIR_INTID_MASK (7 << UART_IIR_INTID_SHIFT) +# define UART_IIR_INTID_MSI (0 << UART_IIR_INTID_SHIFT) /* Modem Status */ +# define UART_IIR_INTID_THRE (1 << UART_IIR_INTID_SHIFT) /* THR Empty Interrupt */ +# define UART_IIR_INTID_RDA (2 << UART_IIR_INTID_SHIFT) /* Receive Data Available (RDA) */ +# define UART_IIR_INTID_RLS (3 << UART_IIR_INTID_SHIFT) /* Receiver Line Status (RLS) */ +# define UART_IIR_INTID_CTI (6 << UART_IIR_INTID_SHIFT) /* Character Time-out Indicator (CTI) */ + /* Bits 4-5: Reserved */ +#define UART_IIR_FIFOEN_SHIFT (6) /* Bits 6-7: RCVR FIFO interrupt */ +#define UART_IIR_FIFOEN_MASK (3 << UART_IIR_FIFOEN_SHIFT) + +/* FCR FIFO Control Register */ + +#define UART_FCR_FIFOEN (1 << 0) /* Bit 0: Enable FIFOs */ +#define UART_FCR_RXRST (1 << 1) /* Bit 1: RX FIFO Reset */ +#define UART_FCR_TXRST (1 << 2) /* Bit 2: TX FIFO Reset */ +#define UART_FCR_DMAMODE (1 << 3) /* Bit 3: DMA Mode Select */ + /* Bits 4-5: Reserved */ +#define UART_FCR_RXTRIGGER_SHIFT (6) /* Bits 6-7: RX Trigger Level */ +#define UART_FCR_RXTRIGGER_MASK (3 << UART_FCR_RXTRIGGER_SHIFT) +# define UART_FCR_RXTRIGGER_1 (0 << UART_FCR_RXTRIGGER_SHIFT) /* Trigger level 0 (1 character) */ +# define UART_FCR_RXTRIGGER_4 (1 << UART_FCR_RXTRIGGER_SHIFT) /* Trigger level 1 (4 characters) */ +# define UART_FCR_RXTRIGGER_8 (2 << UART_FCR_RXTRIGGER_SHIFT) /* Trigger level 2 (8 characters) */ +# define UART_FCR_RXTRIGGER_14 (3 << UART_FCR_RXTRIGGER_SHIFT) /* Trigger level 3 (14 characters) */ + +/* LCR Line Control Register */ + +#define UART_LCR_WLS_SHIFT (0) /* Bit 0-1: Word Length Select */ +#define UART_LCR_WLS_MASK (3 << UART_LCR_WLS_SHIFT) +# define UART_LCR_WLS_5BIT (0 << UART_LCR_WLS_SHIFT) +# define UART_LCR_WLS_6BIT (1 << UART_LCR_WLS_SHIFT) +# define UART_LCR_WLS_7BIT (2 << UART_LCR_WLS_SHIFT) +# define UART_LCR_WLS_8BIT (3 << UART_LCR_WLS_SHIFT) +#define UART_LCR_STB (1 << 2) /* Bit 2: Number of Stop Bits */ +#define UART_LCR_PEN (1 << 3) /* Bit 3: Parity Enable */ +#define UART_LCR_EPS (1 << 4) /* Bit 4: Even Parity Select */ +#define UART_LCR_STICKY (1 << 5) /* Bit 5: Stick Parity */ +#define UART_LCR_BRK (1 << 6) /* Bit 6: Break Control */ +#define UART_LCR_DLAB (1 << 7) /* Bit 7: Divisor Latch Access Bit (DLAB) */ + +/* MCR Modem Control Register */ + +#define UART_MCR_DTR (1 << 0) /* Bit 0: DTR Control Source for DTR output */ +#define UART_MCR_RTS (1 << 1) /* Bit 1: Control Source for RTS output */ +#define UART_MCR_OUT1 (1 << 2) /* Bit 2: Auxiliary user-defined output 1 */ +#define UART_MCR_OUT2 (1 << 3) /* Bit 3: Auxiliary user-defined output 2 */ +#define UART_MCR_LPBK (1 << 4) /* Bit 4: Loopback Mode Select */ + /* Bit 5-7: Reserved */ + +/* LSR Line Status Register */ + +#define UART_LSR_DR (1 << 0) /* Bit 0: Data Ready */ +#define UART_LSR_OE (1 << 1) /* Bit 1: Overrun Error */ +#define UART_LSR_PE (1 << 2) /* Bit 2: Parity Error */ +#define UART_LSR_FE (1 << 3) /* Bit 3: Framing Error */ +#define UART_LSR_BI (1 << 4) /* Bit 4: Break Interrupt */ +#define UART_LSR_THRE (1 << 5) /* Bit 5: Transmitter Holding Register Empty */ +#define UART_LSR_TEMT (1 << 6) /* Bit 6: Transmitter Empty */ +#define UART_LSR_RXFE (1 << 7) /* Bit 7: Error in RX FIFO (RXFE) */ + +/* SCR Scratch Pad Register */ + +#define UART_SCR_MASK (0xff) /* Bits 0-7: SCR data */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +#if CONFIG_16550_REGWIDTH == 1 +typedef uint8_t uart_datawidth_t; +#elif CONFIG_16550_REGWIDTH == 2 +typedef uint16_t uart_datawidth_t; +#elif CONFIG_16550_REGWIDTH == 4 +typedef uint32_t uart_datawidth_t; +#endif + +#if CONFIG_16550_REGWIDTH == 1 +typedef uint8_t uart_addrwidth_t; +#elif CONFIG_16550_REGWIDTH == 2 +typedef uint16_t uart_addrwidth_t; +#elif CONFIG_16550_REGWIDTH == 4 +typedef uint32_t uart_addrwidth_t; +#endif + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: uart_getreg(), uart_putreg() + * + * Description: + * These functions must be provided by the processor-specific code in order to + * correctly access 16550 registers + * + ************************************************************************************/ + +extern uart_datawidth_t uart_getreg(uart_addrwidth_t base, unsigned int offset); +extern void uart_putreg(uart_addrwidth_t base, unsigned int offset, uart_datawidth_t value); + +#endif /* CONFIG_UART_16550 */ +#endif /* __INCLUDE_NUTTX_UART_16550_H */