pc100.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:13k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* Interface driver for the PACCOMM PC-100 board for the IBM PC */
  2. /* UNFINISHED, DOESN'T WORK YET - work in progress by Bdale */
  3. /* currently only attempting to use the AMD7910 on Channel A */
  4. #include <stdio.h>
  5. #include <dos.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "pktdrvr.h"
  10. #include "netuser.h"
  11. #include "pc100.h"
  12. #include "z8530.h"
  13. #include "ax25.h"
  14. #include "trace.h"
  15. #include "nospc.h"
  16. static void hspint(struct hdlc *hp);
  17. static void hexint(struct hdlc *hp);
  18. static void hrxint(struct hdlc *hp);
  19. static void htxint(register struct hdlc *hp);
  20. static void rts(uint16 base,int x);
  21. static void hdlcparam(struct hdlc *hp);
  22. static int pc_raw(struct iface *iface,struct mbuf **bpp);
  23. static int pc_stop(struct iface *iface);
  24. static struct pc100 Pc100[NPC];
  25. static INTERRUPT (*Pchandle[])() = { pc0vec };
  26. static struct hdlc Hdlc[2*NPC];
  27. static uint16 Npc;
  28. /* Branch table for interrupt handler */
  29. static void (*Svec[])(struct hdlc *hp) = {
  30. htxint, hexint, hrxint, hspint
  31. };
  32. /* Master interrupt handler for the PC-100 card. All interrupts come
  33.  * here first, then are switched out to the appropriate routine.
  34.  */
  35. INTERRUPT (far *(pcint)(dev))()
  36. int dev;
  37. {
  38. register char iv;
  39. register uint16 pcbase;
  40. struct hdlc *hp;
  41. struct pc100 *pcp;
  42. pcp = &Pc100[dev];
  43. pcp->ints++;
  44. pcbase = pcp->addr;
  45. /* Read interrupt vector, including status, from channel B */
  46. iv = read_scc(CTL+pcbase+CHANB,R2);
  47. hp = &Hdlc[2 * dev + ((iv & 0x80)? 0 : 1)];
  48. /* Now switch to appropriate routine */
  49. (*Svec[(iv>>1) & 0x3])(hp);
  50. /* Reset interrupt pending state (register A only) */
  51. write_scc(CTL+pcbase+CHANA,R0,RES_H_IUS);
  52. /* Wang the 8530 hardware interrupt acknowledge line - Bdale */
  53. inportb(pcbase+INTACK);
  54. return pcp->chain ? pcp->oldvec : NULL;
  55. }
  56. /* HDLC Special Receive Condition interrupt
  57.  * The most common event that triggers this interrupt is the
  58.  * end of a frame; it can also be caused by a receiver overflow.
  59.  */
  60. static void
  61. hspint(hp)
  62. register struct hdlc *hp;
  63. {
  64. register char c;
  65. hp->spints++;
  66. c = read_scc(CTL+hp->base,R1); /* Fetch latched bits */
  67. if((c & (END_FR|CRC_ERR)) == END_FR && hp->rcvbuf != NULL
  68. && hp->rcvbuf->cnt > 1){
  69. /* End of valid frame */
  70. hp->rcvbuf->cnt--; /* Toss 1st crc byte */
  71. enqueue(&hp->rcvq,&hp->rcvbuf);
  72. hp->rcvbuf = NULL;
  73. hp->rcvcnt++;
  74. } else {
  75. /* An overflow or CRC error occurred; restart receiver */
  76. hp->crcerr++;
  77. if(hp->rcvbuf != NULL){
  78. hp->rcp = hp->rcvbuf->data;
  79. hp->rcvbuf->cnt = 0;
  80. }
  81. }
  82. write_scc(CTL+hp->base,R0,ERR_RES);
  83. }
  84. /* HDLC SIO External/Status interrupts
  85.  * The only one of direct interest is a receiver abort; the other
  86.  * usual cause is a change in the modem control leads, so kick the
  87.  * transmit interrupt routine.
  88.  */
  89. static void
  90. hexint(hp)
  91. register struct hdlc *hp;
  92. {
  93. hp->exints++;
  94. hp->status = read_scc(CTL+hp->base,R0); /* Fetch status */
  95. if((hp->status & BRK_ABRT) && hp->rcvbuf != NULL){
  96. hp->aborts++;
  97. /* Restart receiver */
  98. hp->rcp = hp->rcvbuf->data;
  99. hp->rcvbuf->cnt = 0;
  100. }
  101. write_scc(CTL+hp->base,R0,RES_EXT_INT);
  102. write_scc(CTL+hp->base,R0,RES_H_IUS);
  103. /* Kick the transmit interrupt routine for a possible modem change */
  104. htxint(hp);
  105. }
  106. /* HDLC receiver interrupt handler. Allocates buffers off the freelist,
  107.  * fills them with receive data, and puts them on the receive queue.
  108.  */
  109. static void
  110. hrxint(hp)
  111. register struct hdlc *hp;
  112. {
  113. struct mbuf *bp;
  114. register uint16 base;
  115. hp->rxints++;
  116. base = hp->base;
  117. /* Allocate a receive buffer if not already present */
  118. if((bp = hp->rcvbuf) == NULL){
  119. bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  120. if(bp == NULL){
  121. /* No memory, abort receiver */
  122. hp->nomem++;
  123. write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  124. (void) inportb(base+DATA);
  125. return;
  126. }
  127. hp->rcp = hp->rcvbuf->data;
  128. }
  129. while(read_scc(CTL+base,R0) & Rx_CH_AV){
  130. if(bp->cnt++ >= hp->bufsiz){
  131. /* Too large; abort the receiver, toss buffer */
  132. hp->toobig++;
  133. write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  134. (void) inportb(base+DATA);
  135. free_p(&bp);
  136. hp->rcvbuf = NULL;
  137. break;
  138. }
  139. /* Normal save */
  140. *hp->rcp++ = inportb(base+DATA);
  141. }
  142. }
  143. static int ctswait;
  144. /* HDLC transmit interrupt service routine
  145.  *
  146.  * The state variable tstate, along with some static pointers,
  147.  * represents the state of the transmit "process".
  148.  */
  149. static void
  150. htxint(hp)
  151. register struct hdlc *hp;
  152. {
  153. register uint16 base;
  154. int c;
  155. int i_state;
  156. hp->txints++;
  157. base = hp->base;
  158. i_state = dirps();
  159. while(read_scc(CTL+base,R0) & Tx_BUF_EMP){
  160. switch(hp->tstate){
  161. /* First here for efficiency */
  162. case ACTIVE: /* Sending frame */
  163. if((c = PULLCHAR(&hp->sndbuf)) != -1){
  164. outportb(base+DATA,c);
  165. } else {
  166. /* Do this after sending the last byte */
  167. write_scc(CTL+base,R0,RES_Tx_P);
  168. if((hp->sndbuf = dequeue(&hp->sndq)) == NULL){
  169. switch(hp->mode){
  170. case CSMA:
  171. /* Begin transmitter shutdown */
  172. hp->tstate = FLUSH;
  173. break;
  174. case FULLDUP:
  175. hp->tstate = IDLE;
  176. break;
  177. }
  178. }
  179. }
  180. continue;
  181. case IDLE:
  182. /* Transmitter idle. Find a frame for transmission */
  183. if((hp->sndbuf = dequeue(&hp->sndq)) == NULL)
  184. goto ret;
  185. case DEFER: /* note fall-thru */
  186. if(hp->mode == CSMA && (hp->status & DCD)){
  187. hp->tstate = DEFER;
  188. goto ret;
  189. }
  190. rts(base,ON); /* Transmitter on */
  191. case KEYUP: /* note fall-thru */
  192. if((hp->status & CTS) == 0){
  193. ctswait++;
  194. hp->tstate = KEYUP;
  195. goto ret;
  196. }
  197. write_scc(CTL+base,R0,RES_Tx_CRC);
  198. c = PULLCHAR(&hp->sndbuf);
  199. outportb(hp->base+DATA,c);
  200. hp->tstate = ACTIVE;
  201. write_scc(CTL+base,R0,RES_EOM_L);
  202. continue;
  203. case FLUSH: /* Sending flush character */
  204. outportb(hp->base+DATA,0);
  205. hp->tstate = FIN2;
  206. continue;
  207. case FIN2:
  208. write_scc(CTL+base,R0,SEND_ABORT);
  209. hp->tstate = IDLE;
  210. rts(base,OFF);
  211. write_scc(CTL+base,R0,RES_Tx_P);
  212. continue;
  213. }
  214. }
  215. ret: restore(i_state);
  216. }
  217. /* Set request-to-send on modem */
  218. static void
  219. rts(base,x)
  220. uint16 base;
  221. int x;
  222. {
  223. uint16 cmd;
  224. if(x)
  225. cmd = TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR;
  226. else
  227. cmd = TxCRC_ENAB | TxENAB | Tx8 | DTR;
  228. write_scc(CTL+base,R5,cmd);
  229. }
  230. /* (re)Initialize HDLC controller parameters */
  231. static void
  232. hdlcparam(hp)
  233. register struct hdlc *hp;
  234. {
  235. uint16 tc;
  236. register uint16 base;
  237. int i_state;
  238. /* Initialize 8530 channel for SDLC operation */
  239. base = hp->base;
  240. i_state = dirps();
  241. switch(base & 2){
  242. case 0:
  243. write_scc(CTL+base,R9,CHRA); /* Reset channel A */
  244. break;
  245. case 2:
  246. write_scc(CTL+base,R9,CHRB); /* Reset channel B */
  247. break;
  248. }
  249. /* Wait/DMA disable, Int on all Rx chars + spec condition,
  250.  * parity NOT spec condition, TxINT enable, Ext Int enable
  251.  */
  252. write_scc(CTL+base,R1,INT_ALL_Rx | TxINT_ENAB | EXT_INT_ENAB);
  253. /* Dummy interrupt vector, will be modified by interrupt type
  254.  * (This probably isn't necessary)
  255.  */
  256. write_scc(CTL+base,R2,0);
  257. /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  258.  * no address search, no inhibit sync chars, enable RX
  259.  */
  260. write_scc(CTL+base,R3,Rx8|RxCRC_ENAB|RxENABLE);
  261. /* X1 clock, SDLC mode, Sync modes enable, parity disable
  262.  * (Note: the DPLL does a by-32 clock division, so it's not necessary
  263.  * to divide here).
  264.  */
  265. write_scc(CTL+base,R4,X1CLK | SDLC | SYNC_ENAB);
  266. /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  267.  * RTS off, TxCRC enable
  268.  */
  269. write_scc(CTL+base,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  270. /* SDLC flag */
  271. write_scc(CTL+base,R7,FLAG);
  272. /* No reset, status low, master int enable, enable lower chain,
  273.  * no vector, vector includes status
  274.  */
  275. write_scc(CTL+base,R9,MIE|NV|VIS);
  276. /* CRC preset 1, NRZI encoding, no active on poll, flag idle,
  277.  * flag on underrun, no loop mode, 8 bit sync
  278.  */
  279. write_scc(CTL+base,R10,CRCPS|NRZI);
  280. /* Board no longer channel-specific for clk.  The board should be set
  281.  * up to run from the 4.9152Mhz onboard crystal connected to PCLK.
  282.  * Both channels get receive clock at 32x from PCLK via the DPLL,
  283.  * with TRxC as an output, via a 4040 div by 32 counter to RTxC set
  284.  * us as an input to provide the transmit clock.
  285.  */
  286. /*            TRxC = BR Generator Output, TRxC O/I,
  287.  *       transmit clock = RTxC pin, 
  288.  *       receive clock = DPLL output
  289.  */
  290. write_scc(CTL+base,R11,TRxCBR|TRxCOI|TCRTxCP|RCDPLL);
  291. /* Compute and load baud rate generator time constant
  292.  * DPLL needs x32 clock
  293.  * XTAL is defined in pc100.h to be the crystal clock / (2 * 32)
  294.  */
  295. tc = XTAL/(hp->speed) - 2;
  296. write_scc(CTL+base,R12,tc);
  297. write_scc(CTL+base,R13,tc >> 8);
  298. write_scc(CTL+base,R14,SNRZI); /* Set NRZI mode */
  299. write_scc(CTL+base,R14,SSBR); /* Set DPLL source = BR generator */
  300. write_scc(CTL+base,R14,SEARCH); /* Enter search mode */
  301. /* Set baud rate gen source = PCLK, enable baud rate gen */
  302. write_scc(CTL+base,R14,BRENABL|BRSRC);
  303. /* Break/abort IE, TX EOM IE, CTS IE, no SYNC/HUNT IE, DCD IE,
  304.  * no Zero Count IE
  305.  */
  306. write_scc(CTL+base,R15,BRKIE|TxUIE|CTSIE|DCDIE);
  307. restore(i_state);
  308. if(hp->mode == FULLDUP){
  309. rts(base,ON);
  310. } else if(hp->tstate == IDLE){
  311. rts(base,OFF);
  312. }
  313. }
  314. /* Attach a PC-100 interface to the system
  315.  * argv[0]: hardware type, must be "pc100"
  316.  * argv[1]: I/O address, e.g., "0x380"
  317.  * argv[2]: vector, e.g., "2"
  318.  * argv[3]: mode, must be:
  319.  *     "ax25ui" (AX.25 UI frame format)
  320.  *     "ax25i" (AX.25 I frame format)
  321.  * argv[4]: interface label, e.g., "pc0"
  322.  * argv[5]: receiver packet buffer size in bytes
  323.  * argv[6]: maximum transmission unit, bytes
  324.  * argv[7]: interface speed, e.g, "9600"
  325.  * argv[8]: First IP address, optional (defaults to Ip_addr)
  326.  * argv[9]: Second IP address, optional (defaults to Ip_addr)
  327.  */
  328. int
  329. pc_attach(argc,argv,p)
  330. int argc;
  331. char *argv[];
  332. void *p;
  333. {
  334. register struct iface *if_pca,*if_pcb;
  335. struct hdlc *hp;
  336. int dev;
  337. char *cp;
  338. if(Npc >= NPC){
  339. printf("Too many pc100 controllersn");
  340. return -1;
  341. }
  342. if(if_lookup(argv[4]) != NULL){
  343. printf("Interface %s already existsn",argv[4]);
  344. return -1;
  345. }
  346. if(setencap(NULL,argv[3]) == -1){
  347. printf("Mode %s unknown for interface %sn",
  348. argv[3],argv[4]);
  349. return -1;
  350. }
  351. if(Mycall[0] == ''){
  352. printf("set mycall firstn");
  353. return -1;
  354. }
  355. dev = Npc++;
  356. /* Initialize hardware-level control structure */
  357. Pc100[dev].addr = htoi(argv[1]);
  358. Pc100[dev].vec = atoi(argv[2]);
  359. if(strchr(argv[2],'c') != NULL)
  360. Pc100[dev].chain = 1;
  361. else
  362. Pc100[dev].chain = 0;
  363. /* Initialize modems */
  364. outportb(Pc100[dev].addr + MODEM_CTL,0x22);
  365. /* Save original interrupt vector */
  366. Pc100[dev].oldvec = getirq(Pc100[dev].vec);
  367. /* Set new interrupt vector */
  368. if(setirq(Pc100[dev].vec,Pchandle[dev]) == -1){
  369. printf("IRQ %u out of rangen",Pc100[dev].vec);
  370. Npc--;
  371. return -1;
  372. }
  373. /* Create interface structures and fill in details */
  374. if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  375. if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  376. if_pca->addr = if_pcb->addr = Ip_addr;
  377. if(argc > 8)
  378. if_pca->addr = resolve(argv[8]);
  379. if(argc > 9)
  380. if_pcb->addr = resolve(argv[9]);
  381. if(if_pca->addr == 0 || if_pcb->addr == 0){
  382. printf(Noipaddr);
  383. free(if_pca);
  384. free(if_pcb);
  385. return -1;
  386. }
  387. if_pca->name = strdup(argv[4]);
  388. if_pcb->name = strdup(argv[4]);
  389. if_pcb->name[strlen(argv[4]) - 1]++; /* kludge */
  390. if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  391. if_pca->dev = 2*dev;
  392. if_pcb->dev = 2*dev + 1;
  393. if_pcb->stop = if_pca->stop = pc_stop;
  394. if_pcb->raw = pc_raw;
  395. setencap(if_pca,argv[3]);
  396. setencap(if_pcb,argv[3]);
  397. if(if_pcb->hwaddr == NULL)
  398. if_pcb->hwaddr = mallocw(AXALEN);
  399. memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  400. if_pca->next = if_pcb;
  401. if_pcb->next = Ifaces;
  402. Ifaces = if_pca;
  403. hp = &Hdlc[2*dev+1];
  404. hp->speed = (uint16)atoi(argv[7]);
  405. hp->base = Pc100[dev].addr + CHANB;
  406. hp->bufsiz = atoi(argv[5]);
  407. hdlcparam(hp);
  408. hp = &Hdlc[2*dev];
  409. hp->speed = (uint16)atoi(argv[7]);
  410. hp->base = Pc100[dev].addr + CHANA;
  411. hp->bufsiz = atoi(argv[5]);
  412. hdlcparam(hp);
  413. /* Clear mask (enable interrupt) in 8259 interrupt controller */
  414. clrbit(INTMASK,(char)(1<<Pc100[dev].vec));
  415. cp = if_name(if_pca," tx");
  416. if_pca->txproc = newproc(cp,512,if_tx,0,if_pca,NULL,0);
  417. free(cp);
  418. cp = if_name(if_pcb," tx");
  419. if_pcb->txproc = newproc(cp,512,if_tx,0,if_pcb,NULL,0);
  420. free(cp);
  421. return 0;
  422. }
  423. static int
  424. pc_stop(iface)
  425. struct iface *iface;
  426. {
  427. int dev;
  428. dev = iface->dev;
  429. if(dev & 1)
  430. return 0;
  431. dev >>= 1; /* Convert back into PC100 number */
  432. /* Turn off interrupts */
  433. maskoff(Pc100[dev].vec);
  434. /* Restore original interrupt vector */
  435. setirq(Pc100[dev].vec,Pc100[dev].oldvec);
  436. /* Force hardware reset */
  437. write_scc(CTL+Pc100[dev].addr + CHANA,R9,FHWRES);
  438. return 0;
  439. }
  440. /* Send raw packet on PC-100 */
  441. static int
  442. pc_raw(
  443. struct iface *iface,
  444. struct mbuf **bpp
  445. ){
  446. char kickflag;
  447. struct hdlc *hp;
  448. dump(iface,IF_TRACE_OUT,*bpp);
  449. iface->rawsndcnt++;
  450. iface->lastsent = secclock();
  451. hp = &Hdlc[iface->dev];
  452. kickflag = (hp->sndq == NULL);
  453. enqueue(&hp->sndq,bpp);
  454. if(kickflag)
  455. htxint(&Hdlc[iface->dev]);
  456. return 0;
  457. }