Sun 12 Jan 19:29:58 CET 2025
This commit is contained in:
		
							parent
							
								
									bab1b053bf
								
							
						
					
					
						commit
						528fc9432e
					
				|  | @ -16,6 +16,8 @@ See the file LICENSE for details. | ||||||
| #include "interrupt.h" | #include "interrupt.h" | ||||||
| #include "string.h" | #include "string.h" | ||||||
| #include "device.h" | #include "device.h" | ||||||
|  | #include "event.h" | ||||||
|  | #include "event_queue.h" | ||||||
| 
 | 
 | ||||||
| #define COM1 0x3f8 | #define COM1 0x3f8 | ||||||
| #define COM2 0x2F8 | #define COM2 0x2F8 | ||||||
|  | @ -24,7 +26,8 @@ See the file LICENSE for details. | ||||||
| 
 | 
 | ||||||
| #define SERIAL_DATA 0		// If DLAB disabled in LCR
 | #define SERIAL_DATA 0		// If DLAB disabled in LCR
 | ||||||
| 
 | 
 | ||||||
| #define SERIAL_IRQ_ENABLE 1	// If DLAB disabled in LCR
 | #define SERIAL_IER  1  | ||||||
|  | 
 | ||||||
| #define SERIAL_IRQ_DATA_AVAILABILE (0x01 << 0) | #define SERIAL_IRQ_DATA_AVAILABILE (0x01 << 0) | ||||||
| #define SERIAL_IRQ_TRASMITTER_EMPTY (0x01 << 1) | #define SERIAL_IRQ_TRASMITTER_EMPTY (0x01 << 1) | ||||||
| #define SERIAL_IRQ_ERROR (0x01 << 2) | #define SERIAL_IRQ_ERROR (0x01 << 2) | ||||||
|  | @ -64,21 +67,32 @@ See the file LICENSE for details. | ||||||
| #define SERIAL_SCRATCH 7 | #define SERIAL_SCRATCH 7 | ||||||
| 
 | 
 | ||||||
| // units 0,1,2,3
 | // units 0,1,2,3
 | ||||||
| static const int serial_ports[4] = { COM1, COM2, COM3, COM4 }; | static const int serial_ports[2] = { COM1, COM2 }; | ||||||
| static const int serial_ports_irq[4] = { 4, 3, 4, 3 }; | static const int serial_ports_irq[2] = { 4, 3 }; | ||||||
|  | static struct event_queue *queue[2]; | ||||||
| 
 | 
 | ||||||
| static void serial_interrupt(int i, int intr_code) | static void serial_interrupt(int intr, int intr_code) | ||||||
| { | { | ||||||
|   printf("serial_interrupt %d %d\n",i,intr_code); |   intr=intr-32; // reduce by IRQ table offset; IRQ is not unique! We may only support 2 COMs!
 | ||||||
|  |   int port_no=intr==4?0:1, | ||||||
|  |       port = serial_ports[port_no]; | ||||||
|  |   while(inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE) { | ||||||
|  |     char ch=inb(port); | ||||||
|  | 	  struct event e; | ||||||
|  | 	  e.type = EVENT_DATA; | ||||||
|  | 	  e.code = ch; | ||||||
|  | 	  event_queue_post(queue[port_no],&e); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | static int serial_init_port(int unit) | ||||||
| 
 |  | ||||||
| static void serial_init_port(int unit) |  | ||||||
| { | { | ||||||
|   int port = serial_ports[unit]; |   int port = serial_ports[unit]; | ||||||
|  |    | ||||||
|  |   // probe for hardware
 | ||||||
|  |   if(inb(port+SERIAL_LSR)==0xff) return 0; | ||||||
| 	//Disable interrupts
 | 	//Disable interrupts
 | ||||||
| 	outb(0x00, port + SERIAL_IRQ_ENABLE); | 	outb(0x00, port + SERIAL_IER); | ||||||
| 	//Enable DLAB(set baud rate divisor)
 | 	//Enable DLAB(set baud rate divisor)
 | ||||||
| 	outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); | 	outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); | ||||||
| 	//Set divisor to 3(lo byte) 38400 baud
 | 	//Set divisor to 3(lo byte) 38400 baud
 | ||||||
|  | @ -87,18 +101,24 @@ static void serial_init_port(int unit) | ||||||
| 	outb(0x00, port + SERIAL_DIVISOR_HI); | 	outb(0x00, port + SERIAL_DIVISOR_HI); | ||||||
| 	//8 bits, no parity, one stop bit
 | 	//8 bits, no parity, one stop bit
 | ||||||
| 	outb(SERIAL_CHARLEN_START * 3, port + SERIAL_LCR); | 	outb(SERIAL_CHARLEN_START * 3, port + SERIAL_LCR); | ||||||
|  | #ifdef SERIALFIFO | ||||||
| 	//Enable FIFO, clear them, with 14 - byte threshold
 | 	//Enable FIFO, clear them, with 14 - byte threshold
 | ||||||
| 	outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR); | 	outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR); | ||||||
|  | #else | ||||||
|  |   outb(0 , port + SERIAL_FCR); | ||||||
|  | #endif | ||||||
| 	//IRQs enabled, RTS / DSR set
 | 	//IRQs enabled, RTS / DSR set
 | ||||||
| 	outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); | 	outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); | ||||||
| 
 | 
 | ||||||
| 	// setup interrupt support
 | 	// setup interrupt support (need to add 32 to IRQ number!!!!)
 | ||||||
|   interrupt_register(serial_ports_irq[unit], serial_interrupt); |   interrupt_register(32+serial_ports_irq[unit], serial_interrupt); | ||||||
|   interrupt_enable(serial_ports_irq[unit]); |   interrupt_enable(32+serial_ports_irq[unit]); | ||||||
|   // + received data available
 |   // + received data available
 | ||||||
| 	outb(0x01, port + SERIAL_IRQ_ENABLE);  | 	outb(SERIAL_IRQ_DATA_AVAILABILE, port + SERIAL_IER);  | ||||||
|    |    | ||||||
| 	printf("[COM%d] serial_init_port %x: ready.\n",unit,port); | 	queue[unit]=event_queue_create(); | ||||||
|  | 	printf("[COM%d] serial_init_port %x: ready [IRQ=%d QUE=%x].\n",unit,port,serial_ports_irq[unit],queue[unit]); | ||||||
|  | 	return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -117,6 +137,9 @@ static int is_valid_port(uint8_t port_no) | ||||||
| 	return port_no < sizeof(serial_ports) / sizeof(int); | 	return port_no < sizeof(serial_ports) / sizeof(int); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |   Polling read | ||||||
|  | */ | ||||||
| int serial_read(uint8_t port_no) | int serial_read(uint8_t port_no) | ||||||
| { | { | ||||||
| 	if(!is_valid_port(port_no)) | 	if(!is_valid_port(port_no)) | ||||||
|  | @ -127,6 +150,20 @@ int serial_read(uint8_t port_no) | ||||||
| 	return inb(serial_ports[port_no]);   | 	return inb(serial_ports[port_no]);   | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |   Interrupt driven event queue (blocks process if no dat ais available) | ||||||
|  | */ | ||||||
|  | int serial_getchar(uint8_t port_no) { | ||||||
|  |   struct event e; | ||||||
|  | 	if(!is_valid_port(port_no)) | ||||||
|  | 		return -1; | ||||||
|  |    | ||||||
|  |   event_queue_read(queue[port_no],&e,sizeof(e)); | ||||||
|  | 
 | ||||||
|  |   if(e.type==EVENT_DATA) return (int)e.code; | ||||||
|  |   return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int serial_read_nonblock(uint8_t port_no) | int serial_read_nonblock(uint8_t port_no) | ||||||
| { | { | ||||||
| 	if(!is_valid_port(port_no)) | 	if(!is_valid_port(port_no)) | ||||||
|  | @ -152,7 +189,8 @@ int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) | ||||||
| 	if(unit<0 || unit>3) return 0; | 	if(unit<0 || unit>3) return 0; | ||||||
| 	// TODO probing for real hardware
 | 	// TODO probing for real hardware
 | ||||||
| 	// reinit, second time (first time in serial_init, but needed to register the device)
 | 	// reinit, second time (first time in serial_init, but needed to register the device)
 | ||||||
| 	serial_init_port(unit); | 	int status=serial_init_port(unit); | ||||||
|  | 	if (!status) return -1; | ||||||
| 	*blocksize = 1; | 	*blocksize = 1; | ||||||
| 	*nblocks = 0; | 	*nblocks = 0; | ||||||
| 	strcpy(info,"serial"); | 	strcpy(info,"serial"); | ||||||
|  | @ -206,7 +244,7 @@ void serial_init() | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	for(i = 0; i < sizeof(serial_ports) / sizeof(int); i++) { | 	for(i = 0; i < sizeof(serial_ports) / sizeof(int); i++) { | ||||||
| 		serial_init_port(i); | 		int status = serial_init_port(i); | ||||||
| 	} | 	} | ||||||
| 	device_driver_register(&serial_driver); | 	device_driver_register(&serial_driver); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user