1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 8 /* 9 * SMC1 in UART mode 10 */ 11 12 typedef struct Uartsmc Uartsmc; 13 struct Uartsmc { 14 IOCparam; 15 ushort maxidl; 16 ushort idlc; 17 ushort brkln; 18 ushort brkec; 19 ushort brkcr; 20 ushort rmask; 21 }; 22 23 typedef struct Uart Uart; 24 struct Uart 25 { 26 int port; 27 int setup; 28 uchar txbusy; 29 30 Queue* iq; 31 Queue* oq; 32 void (*rx)(Queue*, int); 33 void (*boot)(uchar*, int); 34 35 ulong frame; 36 ulong overrun; 37 uchar rxbuf[128]; 38 char txbuf[16]; 39 BD* rxb; 40 BD* txb; 41 }; 42 43 Uart uart[1]; 44 int predawn = 1; 45 46 static void uartintr(Ureg*, void*); 47 static void uartkick(void*); 48 49 static int 50 baudgen(int baud) 51 { 52 int d; 53 54 d = ((m->cpuhz/baud)+8)>>4; 55 if(d >= (1<<12)) 56 return ((d+15)>>3)|1; 57 return d<<1; 58 } 59 60 static void 61 smcsetup(Uart *up, int baud) 62 { 63 IMM *io; 64 Uartsmc *p; 65 BD *bd; 66 SMC *smc; 67 68 archenableuart(SMC1ID, 0); 69 io = m->iomem; 70 io->pbpar |= IBIT(24)|IBIT(25); /* enable SMC1 TX/RX */ 71 io->pbdir &= ~(IBIT(24)|IBIT(25)); 72 io->brgc1 = baudgen(baud) | BaudEnable; 73 io->simode &= ~0xF000; /* SMC1 to NMSI mode, Tx/Rx clocks are BRG1 */ 74 75 bd = bdalloc(1); 76 p = (Uartsmc*)KADDR(SMC1P); 77 p->rbase = (ushort)bd; 78 up->rxb = bd; 79 bd->status = BDEmpty|BDWrap|BDInt; 80 bd->length = 0; 81 bd->addr = PADDR(up->rxbuf); 82 bd = bdalloc(1); 83 p->tbase = (ushort)bd; 84 up->txb = bd; 85 bd->status = BDWrap|BDInt; 86 bd->length = 0; 87 bd->addr = PADDR(up->txbuf); 88 89 cpmop(InitRxTx, SMC1ID, 0); 90 91 /* protocol parameters */ 92 p->rfcr = 0x18; 93 p->tfcr = 0x18; 94 p->mrblr = 1; 95 p->maxidl = 1; 96 p->brkln = 0; 97 p->brkec = 0; 98 p->brkcr = 1; 99 smc = IOREGS(0xA80, SMC); 100 smc->smce = 0xff; /* clear events */ 101 smc->smcm = 0x17; /* enable all possible interrupts */ 102 setvec(VectorCPIC+4, uartintr, up); 103 smc->smcmr = 0x4820; /* 8-bit mode, no parity, 1 stop bit, UART mode, ... */ 104 smc->smcmr |= 3; /* enable rx/tx */ 105 } 106 107 static void 108 uartintr(Ureg*, void *arg) 109 { 110 Uart *up; 111 int ch, i; 112 BD *bd; 113 SMC *smc; 114 Block *b; 115 116 up = arg; 117 smc = IOREGS(0xA80, SMC); 118 smc->smce = 0xff; /* clear all events */ 119 if((bd = up->rxb) != nil && (bd->status & BDEmpty) == 0){ 120 if(up->iq != nil && bd->length > 0){ 121 if(up->boot != nil){ 122 up->boot(up->rxbuf, bd->length); 123 }else if(up->rx != nil){ 124 for(i=0; i<bd->length; i++){ 125 ch = up->rxbuf[i]; 126 up->rx(up->iq, ch); 127 } 128 }else{ 129 b = iallocb(bd->length); 130 memmove(b->wp, up->rxbuf, bd->length); 131 b->wp += bd->length; 132 qbwrite(up->iq, b); 133 } 134 } 135 bd->status |= BDEmpty|BDInt; 136 } else if((bd = up->txb) != nil && (bd->status & BDReady) == 0){ 137 ch = -1; 138 if(up->oq) 139 ch = qbgetc(up->oq); 140 if(ch != -1){ 141 up->txbuf[0] = ch; 142 bd->length = 1; 143 bd->status |= BDReady; 144 }else 145 up->txbusy = 0; 146 } 147 /* TO DO: modem status, errors, etc */ 148 } 149 150 static void 151 uartkick(void *arg) 152 { 153 Uart *up = arg; 154 int s, c, i; 155 156 s = splhi(); 157 while(up->txbusy == 0 && (c = qbgetc(up->oq)) != -1){ 158 if(predawn){ 159 while(up->txb->status & BDReady) 160 ; 161 } else { 162 for(i = 0; i < 100; i++){ 163 if((up->txb->status & BDReady) == 0) 164 break; 165 delay(1); 166 } 167 } 168 up->txbuf[0] = c; 169 up->txb->length = 1; 170 up->txb->status |= BDReady; 171 up->txbusy = !predawn; 172 } 173 splx(s); 174 } 175 176 void 177 uartspecial(int port, int baud, Queue **iq, Queue **oq, void (*rx)(Queue*,int)) 178 { 179 Uart *up = &uart[0]; 180 181 if(up->setup) 182 return; 183 up->setup = 1; 184 185 *iq = up->iq = qopen(4*1024, 0, 0, 0); 186 *oq = up->oq = qopen(16*1024, 0, uartkick, up); 187 up->rx = rx; 188 USED(port); 189 up->port = SMC1ID; 190 if(baud == 0) 191 baud = 9600; 192 smcsetup(up, baud); 193 /* if using SCCn's UART, would also set DTR and RTS, but SMC doesn't use them */ 194 } 195 196 void 197 uartsetboot(void (*f)(uchar*, int)) 198 { 199 uart[0].boot = f; 200 } 201 202 void 203 uartputs(char *s, int n) 204 { 205 Uart *up = &uart[0]; 206 Block *b; 207 int nl; 208 char *p; 209 210 nl = 0; 211 for(p = s; p < s+n; p++) 212 if(*p == '\n') 213 nl++; 214 b = iallocb(n+nl); 215 while(n--){ 216 if(*s == '\n') 217 *b->wp++ = '\r'; 218 *b->wp++ = *s++; 219 } 220 qbwrite(up->oq, b); 221 } 222 223 void 224 uartwait(void) 225 { 226 Uart *up = &uart[0]; 227 228 while(up->txbusy) 229 ; 230 } 231