?? n8250.c
字號(hào):
if(cnt > tmp)
cnt = tmp; /* Limit to data on hand */
fp->cnt -= cnt;
restore(i_state);
break;
}
restore(i_state);
if((errno = kwait(fp)) != 0)
return -1;
}
tmp = cnt;
while(tmp-- != 0){
/* This can be optimized later if necessary */
c = *fp->rp++;
if(fp->rp >= &fp->buf[fp->bufsize])
fp->rp = fp->buf;
*obp++ = c;
}
return cnt;
}
/* Blocking read from asynch line
* Returns character or -1 if aborting
*/
int
get_asy(dev)
int dev;
{
uint8 c;
int tmp;
if((tmp = asy_read(dev,&c,1)) == 1)
return c;
else
return tmp;
}
/* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
INTERRUPT (far *(asyint)(dev))()
int dev;
{
return asycom(&Asy[dev]);
}
/* Interrupt handler for AST 4-port board (called from fourport.asm) */
INTERRUPT (far *(fpint)(dev))()
int dev;
{
int iv;
struct fport *fport;
int i;
fport = &Fport[dev];
/* Read special interrupt demux register to see which port is active */
while(((iv = inportb(fport->iv)) & 0xf) != 0xf){
for(i=0;i<4;i++){
if((iv & (1 << i)) == 0 && fport->asy[i] != NULL)
asycom(fport->asy[i]);
}
}
return NULL;
}
/* Common interrupt handler code for 8250/16550 port */
static INTERRUPT (far *(asycom)(asyp))(void)
struct asy *asyp;
{
unsigned base;
char iir;
base = asyp->addr;
while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
switch(iir & IIR_ID_MASK){
case IIR_RDA: /* Receiver interrupt */
asyrxint(asyp);
break;
case IIR_THRE: /* Transmit interrupt */
asytxint(asyp);
break;
case IIR_MSTAT: /* Modem status change */
asymsint(asyp);
asyp->msint_count++;
break;
}
/* should happen at end of a single packet */
if(iir & IIR_FIFO_TIMEOUT)
asyp->fifotimeouts++;
}
return asyp->chain ? asyp->save.vec : NULL;
}
/* Process 8250 receiver interrupts */
static int
asyrxint(asyp)
struct asy *asyp;
{
register struct fifo *fp;
unsigned base;
uint8 c,lsr;
int cnt = 0;
int trigseen = FALSE;
asyp->rxints++;
base = asyp->addr;
fp = &asyp->fifo;
for(;;){
lsr = inportb(base+LSR);
if(lsr & LSR_OE)
asyp->overrun++;
if(lsr & LSR_DR){
asyp->rxchar++;
c = inportb(base+RBR);
if(asyp->trigchar == -1 || asyp->trigchar == c)
trigseen = TRUE;
/* If buffer is full, we have no choice but
* to drop the character
*/
if(fp->cnt != fp->bufsize){
*fp->wp++ = c;
if(fp->wp >= &fp->buf[fp->bufsize])
/* Wrap around */
fp->wp = fp->buf;
fp->cnt++;
if(fp->cnt > fp->hiwat)
fp->hiwat = fp->cnt;
cnt++;
} else
fp->overrun++;
} else
break;
}
if(cnt > asyp->rxhiwat)
asyp->rxhiwat = cnt;
if(trigseen)
ksignal(fp,1);
return cnt;
}
/* Handle 8250 transmitter interrupts */
static void
asytxint(asyp)
struct asy *asyp;
{
register struct dma *dp;
register unsigned base;
register int count;
base = asyp->addr;
dp = &asyp->dma;
asyp->txints++;
if(!dp->busy || (asyp->cts && !(asyp->msr & MSR_CTS))){
/* These events "shouldn't happen". Either the
* transmitter is idle, in which case the transmit
* interrupts should have been disabled, or flow control
* is enabled but CTS is low, and interrupts should also
* have been disabled.
*/
clrbit(base+IER,IER_TxE);
return; /* Nothing to send */
}
if(!(inportb(base+LSR) & LSR_THRE))
return; /* Not really ready */
/* If it's a 16550A, load up to 16 chars into the tx hw fifo
* at once. With an 8250, it can be one char at most.
*/
if(asyp->is_16550a){
count = min(dp->cnt,OUTPUT_FIFO_SIZE);
/* 16550A: LSR_THRE will drop after the first char loaded
* so we can't look at this bit to determine if the hw fifo is
* full. There seems to be no way to determine if the tx fifo
* is full (any clues?). So we should never get here while the
* fifo isn't empty yet.
*/
asyp->txchar += count;
dp->cnt -= count;
#ifdef notdef /* This is apparently too fast for some chips */
dp->data = outbuf(base+THR,dp->data,count);
#else
while(count-- != 0)
outportb(base+THR,*dp->data++);
#endif
} else { /* 8250 */
do {
asyp->txchar++;
outportb(base+THR,*dp->data++);
} while(--dp->cnt != 0 && (inportb(base+LSR) & LSR_THRE));
}
if(dp->cnt == 0){
dp->busy = 0;
/* Disable further transmit interrupts */
clrbit(base+IER,IER_TxE);
ksignal(&asyp->dma,1);
}
}
/* Handle 8250 modem status change interrupt */
static void
asymsint(asyp)
struct asy *asyp;
{
unsigned base = asyp->addr;
asyp->msr = inportb(base+MSR);
if(asyp->cts && (asyp->msr & MSR_DCTS)){
/* CTS has changed and we care */
if(asyp->msr & MSR_CTS){
/* CTS went up */
if(asyp->dma.busy){
/* enable transmit interrupts and kick */
setbit(base+IER,IER_TxE);
asytxint(asyp);
}
} else {
/* CTS now dropped, disable Transmit interrupts */
clrbit(base+IER,IER_TxE);
}
}
if(asyp->rlsd && (asyp->msr & MSR_DRLSD)){
/* RLSD just changed and we care, signal it */
ksignal( &(asyp->rlsd), 1 );
/* Keep count */
asyp->cdchanges++;
}
ksignal(&asyp->msr,0);
}
/* Wait for a signal that the RLSD modem status has changed */
int
get_rlsd_asy(dev, new_rlsd)
int dev;
int new_rlsd;
{
struct asy *ap = &Asy[dev];
if(ap->rlsd == 0)
return -1;
for(;;){
if(new_rlsd && (ap->msr & MSR_RLSD))
return 1;
if(!new_rlsd && !(ap->msr & MSR_RLSD))
return 0;
/* Wait for state change to requested value */
ppause(2L);
kwait( &(ap->rlsd) );
}
}
/* Poll the asynch input queues; called on every clock tick.
* This helps limit the interrupt ring buffer occupancy when long
* packets are being received.
*/
void
asytimer()
{
register struct asy *asyp;
register struct fifo *fp;
register int i;
int i_state;
for(i=0;i<ASY_MAX;i++){
asyp = &Asy[i];
fp = &asyp->fifo;
if(fp->cnt != 0)
ksignal(fp,1);
if(asyp->dma.busy
&& (inportb(asyp->addr+LSR) & LSR_THRE)
&& (!asyp->cts || (asyp->msr & MSR_CTS))){
asyp->txto++;
i_state = dirps();
asytxint(asyp);
restore(i_state);
}
}
}
int
doasystat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct asy *asyp;
struct iface *ifp;
int i;
if(argc < 2){
for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
if(asyp->iface != NULL)
pasy(asyp);
}
return 0;
}
for(i=1;i<argc;i++){
if((ifp = if_lookup(argv[i])) == NULL){
printf("Interface %s unknown\n",argv[i]);
continue;
}
for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
if(asyp->iface == ifp){
pasy(asyp);
break;
}
}
if(asyp == &Asy[ASY_MAX])
printf("Interface %s not asy\n",argv[i]);
}
return 0;
}
static void
pasy(asyp)
struct asy *asyp;
{
int mcr;
printf("%s:",asyp->iface->name);
if(asyp->is_16550a)
printf(" [NS16550A]");
if(asyp->trigchar != -1)
printf(" [trigger 0x%02x]",asyp->trigchar);
if(asyp->cts)
printf(" [cts flow control]");
if(asyp->rlsd)
printf(" [rlsd line control]");
printf(" %lu bps\n",asyp->speed);
mcr = inportb(asyp->addr+MCR);
printf(" MC: int %lu DTR %s RTS %s CTS %s DSR %s RI %s CD %s\n",
asyp->msint_count,
(mcr & MCR_DTR) ? "On" : "Off",
(mcr & MCR_RTS) ? "On" : "Off",
(asyp->msr & MSR_CTS) ? "On" : "Off",
(asyp->msr & MSR_DSR) ? "On" : "Off",
(asyp->msr & MSR_RI) ? "On" : "Off",
(asyp->msr & MSR_RLSD) ? "On" : "Off");
printf(" RX: int %lu chars %lu hw over %lu hw hi %lu",
asyp->rxints,asyp->rxchar,asyp->overrun,asyp->rxhiwat);
asyp->rxhiwat = 0;
if(asyp->is_16550a)
printf(" fifo TO %lu",asyp->fifotimeouts);
printf(" sw over %lu sw hi %u\n",
asyp->fifo.overrun,asyp->fifo.hiwat);
asyp->fifo.hiwat = 0;
printf(" TX: int %lu chars %lu THRE TO %lu%s\n",
asyp->txints,asyp->txchar,asyp->txto,
asyp->dma.busy ? " BUSY" : "");
}
/* Send a message on the specified serial line */
int
asy_send(dev,bpp)
int dev;
struct mbuf **bpp;
{
if(dev < 0 || dev >= ASY_MAX){
free_p(bpp);
return -1;
}
while(*bpp != NULL){
/* Send the buffer */
asy_write(dev,(*bpp)->data,(*bpp)->cnt);
/* Now do next buffer on chain */
*bpp = free_mbuf(bpp);
}
return 0;
}
/* Attach an AST 4-port serial interface (or clone) to the system
* argv[0]: hardware type, must be "4port"
* argv[1]: I/O address, e.g., "0x2a0"
* argv[2]: vector, e.g., "5",
*/
int
fp_attach(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i;
struct fport *fp;
for(i=0;i<FPORT_MAX;i++){
if(Fport[i].base == 0)
break;
}
if(i == FPORT_MAX){
printf("Too many 4port devices\n");
return 1;
}
fp = &Fport[i];
fp->base = htoi(argv[1]);
fp->irq = atoi(argv[2]);
fp->iv = fp->base + 0x1f;
setirq(fp->irq,Fphand[i]);
maskon(fp->irq);
outportb(fp->iv,0x80); /* Enable global interrupts */
return 0;
}
void
fp_stop()
{
int i;
struct fport *fp;
for(i=0;i<FPORT_MAX;i++){
if(Fport[i].base == 0)
continue;
fp = &Fport[i];
outportb(fp->iv,0); /* Disable global interrupts */
maskoff(fp->irq);
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -