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

TCP/IP协议栈

开发平台:

Visual C++

  1. /*  Driver for HAPN-1 8273 card on PC
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include "global.h"
  10. #include <stdarg.h>
  11. #include "timer.h"
  12. #include "mbuf.h"
  13. #include "iface.h"
  14. #include "pktdrvr.h"
  15. #include "netuser.h"
  16. #include "hapn.h"
  17. #include "ax25.h"
  18. #include "trace.h"
  19. #include "nospc.h"
  20. #include "proc.h"
  21. static void cmd_8273(uint16 base,uint8 cmd,int np,...);
  22. static int hapn_init(struct hapn *hp);
  23. static int hapn_raw(struct iface *iface,struct mbuf **bpp);
  24. static int hapn_stop(struct iface *iface);
  25. static int hcdchk(uint16 base);
  26. static void hrxint(struct hapn *hp);
  27. static void hrxgo(struct hapn *hp);
  28. static void htxint(void *p);
  29. static struct hapn Hapn[NHAPN];
  30. static INTERRUPT (*H_handle[])() = { ha0vec };
  31. static uint16 Nhapn;
  32. /*  send command to the 8273
  33.  *  "base" = base port of 8273
  34.  *  "cmd"  = command byte
  35.  *  "np"   = number of parameter bytes
  36.  *  "p1"   = first parameter (parameters are int)
  37.  */
  38. static void
  39. cmd_8273(uint16 base, uint8 cmd, int np, ...)
  40. {
  41. int p;
  42. va_list ap;
  43. while(inportb(base+STA) & CBSY)
  44. ;
  45. outportb(base+CMD, cmd);
  46. va_start(ap,np);
  47. while(np--){
  48. while(inportb(base+STA) & CPBF)
  49. ;
  50. p = va_arg(ap,int);
  51. outportb(base+PAR, p);
  52. }
  53. va_end(ap);
  54. }
  55. /*  Start receiver of 8273 */
  56. static void
  57. hrxgo(hp)
  58. register struct hapn *hp;
  59. {
  60. cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  61. }
  62. /*  Interrupt service function.  Entered with hapn index
  63.  *  The "flag" variable is used in this routine to indicate a
  64.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  65.  *  the 8273 is reset.
  66.  */
  67. INTERRUPT (far *(haint)(dev))()
  68. int dev;
  69. {
  70. register struct hapn *hp;
  71. register uint16 base;
  72. char flag = 0;
  73. hp = &Hapn[dev];
  74. base = hp->base;
  75. /*  Check for TX interrupt  */
  76. if(inportb(base+STA) & TXINT){
  77. flag = 1; /* Valid interrupt, set flag */
  78. htxint(hp);
  79. }
  80. /*  Check for RX interrupt  */
  81. if(inportb(base+STA) & RXINT){
  82. flag = 1; /* Valid interrupt, set flag */
  83. hrxint(hp);
  84. }
  85. /* Check for unknown interrupt  */
  86. if(!flag){
  87. hp->badint++; /* Increment error counter */
  88. hapn_init(hp); /* Reinitialise the 8273 */
  89. }
  90. return hp->chain ? hp->oldvec : NULL;
  91. }
  92. /*  RX interrupt service
  93.  *  if status register bit "RXIRA" is set, interrupt is final,
  94.  *  otherwise, interrupt is data request
  95.  */
  96. static void
  97. hrxint(hp)
  98. register struct hapn *hp;
  99. {
  100. struct mbuf *bp;
  101. register uint16 base;
  102. unsigned char results[10];
  103. hp->rxints++;
  104. base = hp->base;
  105. if(inportb(base+STA) & RXIRA){
  106. /* RX result interrupt
  107.  * If the result is a good frame 3 bytes need to be read
  108.  * If an error has occurred only one byte need to be read
  109.  */
  110. /* Read first result byte and test for good data */
  111. if((results[0]=(inportb(base + RXI))) == 0xe0){
  112. /* Good result; read two more result bytes */
  113. while((inportb(base + STA) & RXIRA) == 0)
  114. ;
  115. /* Read second result byte */
  116. results[1] = inportb(base + RXI);
  117. /* Wait for third result byte  */
  118. while((inportb(base + STA) & RXIRA) == 0)
  119. ;  
  120. results[2] = inportb(base + RXI);/* Read it */
  121. /* Since this frame is ok put it on the queue */
  122. net_route(hp->iface,&hp->rcvbuf);
  123. hp->rframes++;
  124. } else {
  125. /* Error termination
  126.  * Parse RIC and act accordingly
  127.  * Only one result byte returned on error
  128.  */
  129. switch(results[0]){
  130. case CRCERR:
  131. hp->crcerr++;
  132. break;
  133. case ABORT_DET:
  134. hp->aborts++;
  135. break;
  136. case DMA_OVRN:
  137. hp->dmaorun++;
  138. break;
  139. case MEM_OVFL:
  140. hp->toobig++;
  141. break;
  142. case CD_LOSS:
  143. hp->cdloss++;
  144. hapn_init(hp); /* 8273 reset on cd error */
  145. break;
  146. case RX_ORUN:
  147. hp->rxorun++;
  148. break;
  149. }
  150. /* Throw rx buffer contents away to start over */
  151. hp->rcp = hp->rcvbuf->data;
  152. hp->rcvbuf->cnt = 0;
  153. }
  154. /* Restart the receiver */
  155. cmd_8273(base,RX_DISABLE,0);
  156. hrxgo(hp);
  157. } else {
  158. /* RX data interrupt; allocate new rx buffer if none present */
  159. if((bp = hp->rcvbuf) == NULL){
  160. bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  161. if(bp == NULL){
  162. /* No memory available */
  163. hp->nomem++;
  164. cmd_8273(base, RX_DISABLE, 0);
  165. hrxgo(hp);
  166. return;
  167. }
  168. /* Init buffer pointer */
  169. hp->rcp = hp->rcvbuf->data;
  170. }
  171. /*  Barf if rx data is more than buffer can hold (should never
  172.  *  happen since 8273 is also counting bytes).
  173.  */
  174. if(bp->cnt++ >= hp->bufsiz){
  175. hp->toobig++;
  176. cmd_8273(base, RX_DISABLE, 0);
  177. hrxgo(hp);
  178. free_p(&bp);
  179. hp->rcvbuf = NULL;
  180. return;
  181. }
  182. /* Store the received byte */
  183. *hp->rcp++ = inportb(base+RXD);
  184. }
  185. }
  186. /*  test for busy channel (CD active)
  187.  *  returns TRUE if channel busy
  188.  */
  189. static int
  190. hcdchk(base)
  191. uint16 base;
  192. {
  193. int i_state;
  194. i_state = dirps();
  195. cmd_8273(base, READ_A, 0);
  196. while(!(inportb(base+STA) & CRBF))
  197. ;
  198. restore(i_state);
  199. return((inportb(base+RES) & CD) != 0);
  200. }
  201. /*  TX interrupt service
  202.  *  if status register bit "TXIRA" is set, interrupt is final,
  203.  *  otherwise, interrupt is data request
  204.  */
  205. static void
  206. htxint(p)
  207. void *p;
  208. {
  209. register struct hapn *hp;
  210. register uint16 base;
  211. uint16 len;
  212. int c;
  213. int i_state;
  214. hp = (struct hapn *)p;
  215. hp->txints++;
  216. base = hp->base;
  217. c = 0;
  218. i_state = dirps();
  219. if(inportb(base+STA) & TXIRA){ /* TX result interupt */
  220. hp->tstate = IDLE;
  221. free_p(&hp->sndbuf);
  222. hp->sndbuf = NULL;
  223. /*  Read result  */
  224. while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  225. ;
  226. c = inportb(base+TXI);
  227. /*  Test for tx abort  */
  228. switch(c & 0x1f){
  229. case DMA_URUN:
  230. hp->t_urun++;
  231. break;
  232. case CTS_LOSS:
  233. hp->ctsloss++;
  234. break;
  235. case ABORT_CMPLT:
  236. hp->taborts++;
  237. break;
  238. }
  239. }
  240. switch(hp->tstate){
  241. case IDLE: /*  See if a buffer is ready to be sent  */
  242. if((hp->sndbuf = dequeue(&hp->sndq)) == NULL)
  243. break;
  244. case DEFER: /*  Busy-channel check  */
  245. if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  246. if(hcdchk(base)){
  247. hp->tstate = DEFER;
  248. start_timer(&hp->defer);
  249. break;
  250. }
  251. }
  252. /*  Start transmitter  */
  253. stop_timer(&hp->defer);
  254. len = len_p(hp->sndbuf);
  255. cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  256. hp->tstate = ACTIVE;
  257. hp->tframes++;
  258. break;
  259. case ACTIVE: /*  Get next byte to send  */
  260. if((c = PULLCHAR(&hp->sndbuf)) == -1){
  261. cmd_8273(base, ABORT_TXF, 0);
  262. hp->tstate = IDLE;
  263. } else
  264. outportb(base+TXD, c);
  265. break;
  266. }
  267. restore(i_state);
  268. }
  269. /*  Attach a HAPN adaptor to the system
  270.  *  argv[0]:  hardware type, must be "hapn"
  271.  *  argv[1]:  I/O address, e.g. "0x310"
  272.  *  argv[2]:  vector, e.g. "2"
  273.  *  argv[3]:  mode, must be "ax25i" or "ax25ui"
  274.  *  argv[4]:  interface name, e.g. "ha0"
  275.  *  argv[5]:  rx packet buffer size in bytes
  276.  *  argv[6]:  maximum transmission unit in bytes
  277.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  278.  *  argv[8]: IP address, optional (defaults to Ip_addr)
  279.  */
  280. int
  281. hapn_attach(argc, argv,p)
  282. int argc;
  283. char *argv[];
  284. void *p;
  285. {
  286. register struct iface *if_h;
  287. struct hapn *hp;
  288. int dev, i;
  289. static struct {
  290. char *str;
  291. char type;
  292. } ch_access [] = { "csma", 0, "full", 1 };
  293. char *cp;
  294. int i_state;
  295. if(Nhapn >= NHAPN){
  296. printf("Too many HAPN adaptorsn");
  297. return -1;
  298. }
  299. if(if_lookup(argv[4]) != NULL){
  300. printf("Interface %s already existsn",argv[4]);
  301. return -1;
  302. }
  303. if(setencap(NULL,argv[3]) == -1){
  304. printf("Mode %s unknown for interface %sn", argv[3], argv[4]);
  305. return -1;
  306. }
  307. if(Mycall[0] == ''){
  308. printf("set mycall firstn");
  309. return -1;
  310. }
  311. /*  Create new interface structure  */
  312. if_h = (struct iface *) callocw(1,sizeof(struct iface));
  313. /*  Set interface address  */
  314. if_h->addr = Ip_addr;
  315. if(argc > 8)
  316. if_h->addr = resolve(argv[8]);
  317. if(if_h->addr == 0){
  318. printf(Noipaddr);
  319. free(if_h);
  320. return -1;
  321. }
  322. dev = Nhapn++;
  323. hp = &Hapn[dev];
  324. /*  Initialize hardware constants */
  325. hp->base = htoi(argv[1]);
  326. hp->vec = atoi(argv[2]);
  327. if(strchr(argv[2],'c') != NULL)
  328. hp->chain = 1;
  329. else
  330. hp->chain = 0;
  331. /*  Save original interrupt vector  */
  332. hp->oldvec = getirq(Hapn[dev].vec);
  333. /*  Set new interrupt vector  */
  334. setirq(hp->vec, H_handle[dev]);
  335. /* Continue filling interface structure */
  336. if_h->name = strdup(argv[4]);
  337. if_h->mtu = atoi(argv[6]);
  338. if_h->dev = dev;
  339. if_h->stop = hapn_stop;
  340. if_h->raw = hapn_raw;
  341. hp->iface = if_h;
  342. setencap(if_h,argv[3]);
  343. if(if_h->hwaddr == NULL)
  344. if_h->hwaddr = mallocw(AXALEN);
  345. memcpy(if_h->hwaddr,Mycall,AXALEN);
  346. /*  Link the interface into the interface list  */
  347. if_h->next = Ifaces;
  348. Ifaces = if_h;
  349. /*  Fill the local data structure  */
  350. hp->bufsiz = atoi(argv[5]);
  351. for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  352. if(!strcmp(argv[7], ch_access[i].str))
  353. hp->mode = ch_access[i].type;
  354. /*  Initialize the hardware  */
  355. i_state = dirps();
  356. hapn_init(hp);
  357. /* Initialize the defer timer */
  358. set_timer(&hp->defer,MSPTICK);
  359. hp->defer.func = htxint;
  360. hp->defer.arg = hp;
  361. /*  Enable the interrupt  */
  362. maskon(hp->vec);
  363. restore(i_state);
  364. cp = if_name(if_h," tx");
  365. if_h->txproc = newproc(cp,512,if_tx,0,if_h,NULL,0);
  366. free(cp);
  367. return 0;
  368. }
  369. /*  initialize the HAPN adaptor */
  370. static int
  371. hapn_init(hp)
  372. register struct hapn *hp;
  373. {
  374. register uint16 base;
  375. int i_state;
  376. i_state = dirps();
  377. base = hp->base;
  378. /*  Reset the 8273 */
  379. outportb(base+RST, 1);
  380. outportb(base+RST, 0);
  381. inportb(base+TXI); /* Clear any old IR contents */
  382. inportb(base+RXI);
  383. /*  Select the operating modes  */
  384. cmd_8273(base, SET_XFER, 1, 1);
  385. cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  386. cmd_8273(base, SET_SERIAL, 1, NRZI);
  387. cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  388. cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  389. hrxgo(hp);
  390. restore(i_state);
  391. return 0;
  392. }
  393. /*  shut down the HAPN adaptor */
  394. static int
  395. hapn_stop(iface)
  396. struct iface *iface;
  397. {
  398. int dev;
  399. uint16 base;
  400. struct hapn *hp;
  401. dev = iface->dev;
  402. hp = &Hapn[dev];
  403. base = hp->base;
  404. /*  Mask off interrupt input  */
  405. maskoff(hp->vec);
  406. /*  Restore original interrupt vector  */
  407. setirq(hp->vec,hp->oldvec);
  408. /*  Reset the 8273  */
  409. outportb(base+RST, 1);
  410. outportb(base+RST, 0);
  411. return 0;
  412. }
  413. /* Display adaptor statistics */
  414. int
  415. dohapnstat(argc,argv,p)
  416. int argc;
  417. char *argv[];
  418. void *p;
  419. {
  420. struct hapn *hp;
  421. int i;
  422. if(Nhapn == 0){
  423. printf("No HAPN adaptor attachedn");
  424. return 1;
  425. }
  426. for(i = 0; i < Nhapn; i++){
  427. hp = &Hapn[i];
  428. printf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5dn", i,
  429.  hp->rxints,hp->txints,hp->badint);
  430. printf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5dn",
  431.  hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  432. printf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5dn",
  433.  hp->toobig,hp->cdloss,hp->rxorun);
  434. printf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5dn",
  435.  hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss);
  436. }
  437. return 0;
  438. }
  439. /* Send raw packet on HAPN interface */
  440. static int
  441. hapn_raw(
  442. struct iface *iface,
  443. struct mbuf **bpp
  444. ){
  445. struct hapn *hp;
  446. hp = &Hapn[iface->dev];
  447. enqueue(&hp->sndq, bpp);
  448. /*  See if anything being transmitted  */
  449. if(hp->tstate == IDLE)
  450. htxint(hp);
  451. return 0;
  452. }