Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
 
9
/*
10
 * 8250 UART and compatibles.
11
 */
12
enum {
13
	Uart0		= 0x3F8,	/* COM1 */
14
	Uart0IRQ	= 4,
15
	Uart1		= 0x2F8,	/* COM2 */
16
	Uart1IRQ	= 3,
17
 
18
	UartFREQ	= 1843200,
19
};
20
 
21
enum {					/* I/O ports */
22
	Rbr		= 0,		/* Receiver Buffer (RO) */
23
	Thr		= 0,		/* Transmitter Holding (WO) */
24
	Ier		= 1,		/* Interrupt Enable */
25
	Iir		= 2,		/* Interrupt Identification (RO) */
26
	Fcr		= 2,		/* FIFO Control (WO) */
27
	Lcr		= 3,		/* Line Control */
28
	Mcr		= 4,		/* Modem Control */
29
	Lsr		= 5,		/* Line Status */
30
	Msr		= 6,		/* Modem Status */
31
	Scr		= 7,		/* Scratch Pad */
32
	Dll		= 0,		/* Divisor Latch LSB */
33
	Dlm		= 1,		/* Divisor Latch MSB */
34
};
35
 
36
enum {					/* Ier */
37
	Erda		= 0x01,		/* Enable Received Data Available */
38
	Ethre		= 0x02,		/* Enable Thr Empty */
39
	Erls		= 0x04,		/* Enable Receiver Line Status */
40
	Ems		= 0x08,		/* Enable Modem Status */
41
};
42
 
43
enum {					/* Iir */
44
	Ims		= 0x00,		/* Ms interrupt */
45
	Ip		= 0x01,		/* Interrupt Pending (not) */
46
	Ithre		= 0x02,		/* Thr Empty */
47
	Irda		= 0x04,		/* Received Data Available */
48
	Irls		= 0x06,		/* Receiver Line Status */
49
	Ictoi		= 0x0C,		/* Character Time-out Indication */
50
	IirMASK		= 0x3F,
51
	Ife		= 0xC0,		/* FIFOs enabled */
52
};
53
 
54
enum {					/* Fcr */
55
	FIFOena		= 0x01,		/* FIFO enable */
56
	FIFOrclr	= 0x02,		/* clear Rx FIFO */
57
	FIFOtclr	= 0x04,		/* clear Tx FIFO */
58
	FIFO1		= 0x00,		/* Rx FIFO trigger level 1 byte */
59
	FIFO4		= 0x40,		/*	4 bytes */
60
	FIFO8		= 0x80,		/*	8 bytes */
61
	FIFO14		= 0xC0,		/*	14 bytes */
62
};
63
 
64
enum {					/* Lcr */
65
	Wls5		= 0x00,		/* Word Length Select 5 bits/byte */
66
	Wls6		= 0x01,		/*	6 bits/byte */
67
	Wls7		= 0x02,		/*	7 bits/byte */
68
	Wls8		= 0x03,		/*	8 bits/byte */
69
	WlsMASK		= 0x03,
70
	Stb		= 0x04,		/* 2 stop bits */
71
	Pen		= 0x08,		/* Parity Enable */
72
	Eps		= 0x10,		/* Even Parity Select */
73
	Stp		= 0x20,		/* Stick Parity */
74
	Brk		= 0x40,		/* Break */
75
	Dlab		= 0x80,		/* Divisor Latch Access Bit */
76
};
77
 
78
enum {					/* Mcr */
79
	Dtr		= 0x01,		/* Data Terminal Ready */
80
	Rts		= 0x02,		/* Ready To Send */
81
	Out1		= 0x04,		/* no longer in use */
82
	Ie		= 0x08,		/* IRQ Enable */
83
	Dm		= 0x10,		/* Diagnostic Mode loopback */
84
};
85
 
86
enum {					/* Lsr */
87
	Dr		= 0x01,		/* Data Ready */
88
	Oe		= 0x02,		/* Overrun Error */
89
	Pe		= 0x04,		/* Parity Error */
90
	Fe		= 0x08,		/* Framing Error */
91
	Bi		= 0x10,		/* Break Interrupt */
92
	Thre		= 0x20,		/* Thr Empty */
93
	Temt		= 0x40,		/* Tramsmitter Empty */
94
	FIFOerr		= 0x80,		/* error in receiver FIFO */
95
};
96
 
97
enum {					/* Msr */
98
	Dcts		= 0x01,		/* Delta Cts */
99
	Ddsr		= 0x02,		/* Delta Dsr */
100
	Teri		= 0x04,		/* Trailing Edge of Ri */
101
	Ddcd		= 0x08,		/* Delta Dcd */
102
	Cts		= 0x10,		/* Clear To Send */
103
	Dsr		= 0x20,		/* Data Set Ready */
104
	Ri		= 0x40,		/* Ring Indicator */
105
	Dcd		= 0x80,		/* Data Set Ready */
106
};
107
 
108
typedef struct Ctlr {
109
	int	io;
110
	int	irq;
111
	int	tbdf;
112
	int	iena;
113
 
114
	uchar	sticky[8];
115
 
116
	Lock;
117
	int	fifo;
118
	int	fena;
119
} Ctlr;
120
 
121
extern PhysUart i8250physuart;
122
 
123
static Ctlr i8250ctlr[2] = {
124
{	.io	= Uart0,
125
	.irq	= Uart0IRQ,
126
	.tbdf	= BUSUNKNOWN, },
127
 
128
{	.io	= Uart1,
129
	.irq	= Uart1IRQ,
130
	.tbdf	= BUSUNKNOWN, },
131
};
132
 
133
static Uart i8250uart[2] = {
134
{	.regs	= &i8250ctlr[0],
135
	.name	= "COM1",
136
	.freq	= UartFREQ,
137
	.phys	= &i8250physuart,
138
	.special=0,
139
	.next	= &i8250uart[1], },
140
 
141
{	.regs	= &i8250ctlr[1],
142
	.name	= "COM2",
143
	.freq	= UartFREQ,
144
	.phys	= &i8250physuart,
145
	.special=0,
146
	.next	= nil, },
147
};
148
 
149
#define csr8r(c, r)	inb((c)->io+(r))
150
#define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))
151
 
152
static long
153
i8250status(Uart* uart, void* buf, long n, long offset)
154
{
155
	char *p;
156
	Ctlr *ctlr;
157
	uchar ier, lcr, mcr, msr;
158
 
159
	ctlr = uart->regs;
160
	p = malloc(READSTR);
161
	mcr = ctlr->sticky[Mcr];
162
	msr = csr8r(ctlr, Msr);
163
	ier = ctlr->sticky[Ier];
164
	lcr = ctlr->sticky[Lcr];
165
	snprint(p, READSTR,
166
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
167
		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
168
 
169
		uart->baud,
170
		uart->hup_dcd, 
171
		(msr & Dsr) != 0,
172
		uart->hup_dsr,
173
		(lcr & WlsMASK) + 5,
174
		(ier & Ems) != 0, 
175
		(lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
176
		(mcr & Rts) != 0,
177
		(lcr & Stb) ? 2: 1,
178
		ctlr->fena,
179
 
180
		uart->dev,
181
		uart->type,
182
		uart->ferr,
183
		uart->oerr, 
184
		(msr & Cts) ? " cts": "",
185
		(msr & Dsr) ? " dsr": "",
186
		(msr & Dcd) ? " dcd": "",
187
		(msr & Ri) ? " ring": ""
188
	);
189
	n = readstr(offset, buf, n, p);
190
	free(p);
191
 
192
	return n;
193
}
194
 
195
static void
196
i8250fifo(Uart* uart, int on)
197
{
198
	int i;
199
	Ctlr *ctlr;
200
 
201
	/*
202
	 * Toggle FIFOs:
203
	 * if none, do nothing;
204
	 * reset the Rx and Tx FIFOs;
205
	 * empty the Rx buffer and clear any interrupt conditions;
206
	 * if enabling, try to turn them on.
207
	 */
208
	ctlr = uart->regs;
209
 
210
	ilock(ctlr);
211
	if(!ctlr->fifo){
212
		csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr);
213
		for(i = 0; i < 16; i++){
214
			csr8r(ctlr, Iir);
215
			csr8r(ctlr, Rbr);
216
		}
217
 
218
		ctlr->fena = 0;
219
		if(on){
220
			csr8w(ctlr, Fcr, FIFO4|FIFOena);
221
			if(!(csr8r(ctlr, Iir) & Ife))
222
				ctlr->fifo = 1;
223
			ctlr->fena = 1;
224
		}
225
	}
226
	iunlock(ctlr);
227
}
228
 
229
static void
230
i8250dtr(Uart* uart, int on)
231
{
232
	Ctlr *ctlr;
233
 
234
	/*
235
	 * Toggle DTR.
236
	 */
237
	ctlr = uart->regs;
238
	if(on)
239
		ctlr->sticky[Mcr] |= Dtr;
240
	else
241
		ctlr->sticky[Mcr] &= ~Dtr;
242
	csr8w(ctlr, Mcr, 0);
243
}
244
 
245
static void
246
i8250rts(Uart* uart, int on)
247
{
248
	Ctlr *ctlr;
249
 
250
	/*
251
	 * Toggle RTS.
252
	 */
253
	ctlr = uart->regs;
254
	if(on)
255
		ctlr->sticky[Mcr] |= Rts;
256
	else
257
		ctlr->sticky[Mcr] &= ~Rts;
258
	csr8w(ctlr, Mcr, 0);
259
}
260
 
261
static void
262
i8250modemctl(Uart* uart, int on)
263
{
264
	Ctlr *ctlr;
265
 
266
	ctlr = uart->regs;
267
	ilock(&uart->tlock);
268
	if(on){
269
		ctlr->sticky[Ier] |= Ems;
270
		csr8w(ctlr, Ier, 0);
271
		uart->modem = 1;
272
		uart->cts = csr8r(ctlr, Msr) & Cts;
273
	}
274
	else{
275
		ctlr->sticky[Ier] &= ~Ems;
276
		csr8w(ctlr, Ier, 0);
277
		uart->modem = 0;
278
		uart->cts = 1;
279
	}
280
	iunlock(&uart->tlock);
281
 
282
	/* modem needs fifo */
283
	(*uart->phys->fifo)(uart, on);
284
}
285
 
286
static int
287
i8250parity(Uart* uart, int parity)
288
{
289
	int lcr;
290
	Ctlr *ctlr;
291
 
292
	ctlr = uart->regs;
293
	lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
294
 
295
	switch(parity){
296
	case 'e':
297
		lcr |= Eps|Pen;
298
		break;
299
	case 'o':
300
		lcr |= Pen;
301
		break;
302
	case 'n':
303
	default:
304
		break;
305
	}
306
	ctlr->sticky[Lcr] = lcr;
307
	csr8w(ctlr, Lcr, 0);
308
 
309
	uart->parity = parity;
310
 
311
	return 0;
312
}
313
 
314
static int
315
i8250stop(Uart* uart, int stop)
316
{
317
	int lcr;
318
	Ctlr *ctlr;
319
 
320
	ctlr = uart->regs;
321
	lcr = ctlr->sticky[Lcr] & ~Stb;
322
 
323
	switch(stop){
324
	case 1:
325
		break;
326
	case 2:
327
		lcr |= Stb;
328
		break;
329
	default:
330
		return -1;
331
	}
332
	ctlr->sticky[Lcr] = lcr;
333
	csr8w(ctlr, Lcr, 0);
334
 
335
	uart->stop = stop;
336
 
337
	return 0;
338
}
339
 
340
static int
341
i8250bits(Uart* uart, int bits)
342
{
343
	int lcr;
344
	Ctlr *ctlr;
345
 
346
	ctlr = uart->regs;
347
	lcr = ctlr->sticky[Lcr] & ~WlsMASK;
348
 
349
	switch(bits){
350
	case 5:
351
		lcr |= Wls5;
352
		break;
353
	case 6:
354
		lcr |= Wls6;
355
		break;
356
	case 7:
357
		lcr |= Wls7;
358
		break;
359
	case 8:
360
		lcr |= Wls8;
361
		break;
362
	default:
363
		return -1;
364
	}
365
	ctlr->sticky[Lcr] = lcr;
366
	csr8w(ctlr, Lcr, 0);
367
 
368
	uart->bits = bits;
369
 
370
	return 0;
371
}
372
 
373
static int
374
i8250baud(Uart* uart, int baud)
375
{
376
	ulong bgc;
377
	Ctlr *ctlr;
378
 
379
	/*
380
	 * Set the Baud rate by calculating and setting the Baud rate
381
	 * Generator Constant. This will work with fairly non-standard
382
	 * Baud rates.
383
	 */
384
	if(uart->freq == 0 || baud <= 0)
385
		return -1;
386
	bgc = (uart->freq+8*baud-1)/(16*baud);
387
 
388
	ctlr = uart->regs;
389
	csr8w(ctlr, Lcr, Dlab);
390
	outb(ctlr->io+Dlm, bgc>>8);
391
	outb(ctlr->io+Dll, bgc);
392
	csr8w(ctlr, Lcr, 0);
393
 
394
	uart->baud = baud;
395
 
396
	return 0;
397
}
398
 
399
static void
400
i8250break(Uart* uart, int ms)
401
{
402
	Ctlr *ctlr;
403
 
404
	/*
405
	 * Send a break.
406
	 */
407
	if(ms == 0)
408
		ms = 200;
409
 
410
	ctlr = uart->regs;
411
	csr8w(ctlr, Lcr, Brk);
412
	tsleep(&up->sleep, return0, 0, ms);
413
	csr8w(ctlr, Lcr, 0);
414
}
415
 
416
static void
417
i8250kick(Uart* uart)
418
{
419
	int i;
420
	Ctlr *ctlr;
421
 
422
	if(uart->cts == 0 || uart->blocked)
423
		return;
424
 
425
	/*
426
	 *  128 here is an arbitrary limit to make sure
427
	 *  we don't stay in this loop too long.  If the
428
	 *  chip's output queue is longer than 128, too
429
	 *  bad -- presotto
430
	 */
431
	ctlr = uart->regs;
432
	for(i = 0; i < 128; i++){
433
		if(!(csr8r(ctlr, Lsr) & Thre))
434
			break;
435
		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
436
			break;
437
		outb(ctlr->io+Thr, *(uart->op++));
438
	}
439
}
440
 
441
static void
442
i8250interrupt(Ureg*, void* arg)
443
{
444
	Ctlr *ctlr;
445
	Uart *uart;
446
	int iir, lsr, old, r;
447
 
448
	uart = arg;
449
 
450
	ctlr = uart->regs;
451
	for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
452
		switch(iir & IirMASK){
453
		case Ims:		/* Ms interrupt */
454
			r = csr8r(ctlr, Msr);
455
			if(r & Dcts){
456
				ilock(&uart->tlock);
457
				old = uart->cts;
458
				uart->cts = r & Cts;
459
				if(old == 0 && uart->cts)
460
					uart->ctsbackoff = 2;
461
				iunlock(&uart->tlock);
462
			}
463
		 	if(r & Ddsr){
464
				old = r & Dsr;
465
				if(uart->hup_dsr && uart->dsr && !old)
466
					uart->dohup = 1;
467
				uart->dsr = old;
468
			}
469
		 	if(r & Ddcd){
470
				old = r & Dcd;
471
				if(uart->hup_dcd && uart->dcd && !old)
472
					uart->dohup = 1;
473
				uart->dcd = old;
474
			}
475
			break;
476
		case Ithre:		/* Thr Empty */
477
			uartkick(uart);
478
			break;
479
		case Irda:		/* Received Data Available */
480
		case Ictoi:		/* Character Time-out Indication */
481
			/*
482
			 * Consume any received data.
483
			 * If the received byte came in with a break,
484
			 * parity or framing error, throw it away;
485
			 * overrun is an indication that something has
486
			 * already been tossed.
487
			 */
488
			while((lsr = csr8r(ctlr, Lsr)) & Dr){
489
				if(lsr & Oe)
490
					uart->oerr++;
491
				if(lsr & Pe)
492
					uart->perr++;
493
				if(lsr & Fe)
494
					uart->ferr++;
495
				r = csr8r(ctlr, Rbr);
496
				if(!(lsr & (Bi|Fe|Pe)))
497
					uartrecv(uart, r);
498
			}
499
			break;
500
		default:
501
			iprint("weird uart interrupt 0x%2.2uX\n", iir);
502
			break;
503
		}
504
	}
505
}
506
 
507
static void
508
i8250disable(Uart* uart)
509
{
510
	Ctlr *ctlr;
511
 
512
	/*
513
 	 * Turn off DTR and RTS, disable interrupts and fifos.
514
	 */
515
	(*uart->phys->dtr)(uart, 0);
516
	(*uart->phys->rts)(uart, 0);
517
	(*uart->phys->fifo)(uart, 0);
518
 
519
	ctlr = uart->regs;
520
	ctlr->sticky[Ier] = 0;
521
	csr8w(ctlr, Ier, 0);
522
}
523
 
524
static void
525
i8250enable(Uart* uart, int ie)
526
{
527
	Ctlr *ctlr;
528
 
529
	/*
530
 	 * Enable interrupts and turn on DTR and RTS.
531
	 * Be careful if this is called to set up a polled serial line
532
	 * early on not to try to enable interrupts as interrupt-
533
	 * -enabling mechanisms might not be set up yet.
534
	 */
535
	ctlr = uart->regs;
536
	if(ie){
537
		if(ctlr->iena == 0){
538
			intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
539
			ctlr->iena = 1;
540
		}
541
		ctlr->sticky[Ier] = Ethre|Erda;
542
		ctlr->sticky[Mcr] |= Ie;
543
	}
544
	else{
545
		ctlr->sticky[Ier] = 0;
546
		ctlr->sticky[Mcr] = 0;
547
	}
548
	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
549
	csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
550
 
551
	(*uart->phys->dtr)(uart, 1);
552
	(*uart->phys->rts)(uart, 1);
553
}
554
 
555
static Uart*
556
i8250pnp(void)
557
{
558
	return i8250uart;
559
}
560
 
561
static int
562
i8250getc(Uart *uart)
563
{
564
	Ctlr *ctlr;
565
 
566
	ctlr = uart->regs;
567
	while(!(csr8r(ctlr, Lsr)&Dr))
568
		delay(1);
569
	return csr8r(ctlr, Rbr);
570
}
571
 
572
static void
573
i8250putc(Uart *uart, int c)
574
{
575
	int i;
576
	Ctlr *ctlr;
577
 
578
	ctlr = uart->regs;
579
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
580
		delay(1);
581
	outb(ctlr->io+Thr, c);
582
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
583
		delay(1);
584
}
585
 
586
PhysUart i8250physuart = {
587
	.name		= "i8250",
588
	.pnp		= i8250pnp,
589
	.enable		= i8250enable,
590
	.disable	= i8250disable,
591
	.kick		= i8250kick,
592
	.dobreak	= i8250break,
593
	.baud		= i8250baud,
594
	.bits		= i8250bits,
595
	.stop		= i8250stop,
596
	.parity		= i8250parity,
597
	.modemctl	= i8250modemctl,
598
	.rts		= i8250rts,
599
	.dtr		= i8250dtr,
600
	.status		= i8250status,
601
	.fifo		= i8250fifo,
602
	.getc		= i8250getc,
603
	.putc		= i8250putc,
604
};
605
 
606
void
607
i8250console(void)
608
{
609
	Uart *uart;
610
	int n;
611
	char *cmd, *p;
612
 
613
	if((p = getconf("console")) == nil)
614
		return;
615
	n = strtoul(p, &cmd, 0);
616
	if(p == cmd)
617
		return;
618
	switch(n){
619
	default:
620
		return;
621
	case 0:
622
		uart = &i8250uart[0];
623
		break;
624
	case 1:
625
		uart = &i8250uart[1];
626
		break;	
627
	}
628
 
629
	uartctl(uart, "b9600 l8 pn s1");
630
	if(*cmd != '\0')
631
		uartctl(uart, cmd);
632
	(*uart->phys->enable)(uart, 0);
633
 
634
	consuart = uart;
635
	uart->console = 1;
636
}