8253xchr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:17k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* -*- linux-c -*- */
  2. /* 
  3.  * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version
  8.  * 2 of the License, or (at your option) any later version.
  9.  *
  10.  **/
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/pci.h>
  14. #include <linux/stddef.h>
  15. #include <linux/string.h>
  16. #include <linux/sockios.h>
  17. #include <asm/io.h>
  18. #include <asm/byteorder.h>
  19. #include <asm/pgtable.h>
  20. #include <linux/skbuff.h>
  21. #include <linux/if_arp.h>
  22. #include <linux/fs.h>
  23. #include <linux/sched.h>
  24. #include <asm/uaccess.h>
  25. #include <linux/version.h>
  26. #include <linux/etherdevice.h>
  27. #include <linux/poll.h>
  28. #include "Reg9050.h"
  29. #include "8253xctl.h"
  30. #include "ring.h"
  31. #include "8253x.h"
  32. #include "crc32dcl.h"
  33. /* a raw character driver  -- theoretically for implementing custom protocols,
  34.  * async interrupts can be used for getting indication that a packet has
  35.  * been successfully transmitted.
  36.  */
  37. /* the application read routine, can block according */
  38. /* to flag, returns one packet at a time */
  39. int sab8253xc_read(struct file *filep, char *cptr, size_t cnt, loff_t *loffp)
  40. {
  41. unsigned int length;
  42. unsigned long flags;
  43. SAB_PORT *port = filep->private_data;
  44. struct sk_buff *skb;
  45. DEBUGPRINT((KERN_ALERT "Attempting to read %i bytes.n", cnt));
  46. if(port->sab8253xc_rcvbuflist == NULL)
  47. {
  48. return -ENOMEM;
  49. }
  50. save_flags(flags); cli();  
  51. if(skb_queue_len(port->sab8253xc_rcvbuflist) == 0)
  52. {
  53. port->rx_empty = 1;
  54. if(filep->f_flags & O_NONBLOCK)
  55. {
  56. restore_flags(flags);
  57. return -EAGAIN;
  58. }
  59. restore_flags(flags);
  60. interruptible_sleep_on(&port->read_wait);
  61. }
  62. else
  63. {
  64. restore_flags(flags);
  65. }
  66. skb = skb_peek(port->sab8253xc_rcvbuflist);
  67. length = skb->tail - skb->data;
  68. if(cnt < length)
  69. {
  70. return -ENOMEM;
  71. }
  72. skb = skb_dequeue(port->sab8253xc_rcvbuflist);
  73. save_flags(flags); cli();  
  74. if(skb_queue_len(port->sab8253xc_rcvbuflist) <= 0)
  75. {
  76. port->rx_empty = 1;
  77. }
  78. restore_flags(flags);
  79. DEBUGPRINT((KERN_ALERT "Copying to user space %s.n", skb->data));
  80. copy_to_user(cptr, skb->data, length);
  81. dev_kfree_skb_any(skb);
  82. return length;
  83. }
  84. /* application write */
  85. int sab8253xc_write(struct file *filep, const char *cptr, size_t cnt, loff_t *loffp)
  86. {
  87. struct sk_buff *skb;
  88. unsigned long flags;
  89. SAB_PORT *port = filep->private_data;
  90. if(cnt > sab8253xc_rbufsize) /* should not send bigger than can be received */
  91. {
  92. return -ENOMEM;
  93. }
  94. if(port->active2.transmit == NULL)
  95. {
  96. return -ENOMEM;
  97. }
  98. save_flags(flags); cli(); /* can block on write when */
  99. /* no space in transmit circular */
  100. /* array. */
  101. if((port->active2.transmit->Count & OWNER) == OWN_SAB)
  102. {
  103. ++(port->Counters.tx_drops);
  104. port->tx_full = 1;
  105. restore_flags(flags);
  106. if(filep->f_flags & O_NONBLOCK)
  107. {
  108. return -EAGAIN;
  109. }
  110. interruptible_sleep_on(&port->write_wait);
  111. }
  112. else
  113. {
  114. restore_flags(flags);
  115. }
  116. #ifndef FREEINTERRUPT
  117. if((port->active2.transmit->HostVaddr != NULL) || /* not OWN_SAB from above */
  118.    (port->active2.transmit->crcindex != 0))
  119. {
  120. register RING_DESCRIPTOR *freeme;
  121. freeme = port->active2.transmit;
  122. do
  123. {
  124. if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL))
  125. {
  126. break;
  127. }
  128. if(freeme->HostVaddr)
  129. {
  130. skb_unlink((struct sk_buff*)freeme->HostVaddr);
  131. dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr);
  132. freeme->HostVaddr = NULL;
  133. }
  134. freeme->sendcrc = 0;
  135. freeme->crcindex = 0;
  136. freeme = (RING_DESCRIPTOR*) freeme->VNext;
  137. }
  138. while((freeme->Count & OWNER) != OWN_SAB);
  139. }
  140. #endif
  141. skb = alloc_skb(cnt, GFP_KERNEL); /* not called from int as with tty */
  142. if(skb == NULL)
  143. {
  144. return -ENOMEM;
  145. }
  146. copy_from_user(skb->data, cptr, cnt);
  147. skb->tail = (skb->data + cnt);
  148. skb->len = cnt;
  149. skb->data_len = cnt;
  150. skb_queue_head(port->sab8253xbuflist, skb);
  151. port->active2.transmit->HostVaddr = skb;
  152. port->active2.transmit->sendcrc = 0;
  153. port->active2.transmit->crcindex = 0;
  154. port->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */
  155. port->active2.transmit = 
  156. (RING_DESCRIPTOR*) port->active2.transmit->VNext;
  157. port->Counters.transmitbytes += cnt;
  158. sab8253x_start_txS(port);
  159. return cnt;
  160. }
  161. static void sab8253x_receive_charsC(struct sab_port *port,
  162.     union sab8253x_irq_status *stat)
  163. {
  164. unsigned char buf[32];
  165. int free_fifo = 0;
  166. int reset_fifo = 0;
  167. int msg_done = 0;
  168. int msg_bad = 0;
  169. int count = 0;
  170. int total_size = 0;
  171. int rstatus = 0;
  172. struct sk_buff *skb;
  173. /* Read number of BYTES (Character + Status) available. */
  174. if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) )
  175. {
  176. ++msg_bad;
  177. ++free_fifo;
  178. ++reset_fifo;
  179. }
  180. else
  181. {
  182. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) 
  183. {
  184. count = port->recv_fifo_size;
  185. ++free_fifo;
  186. }
  187. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) 
  188. {
  189. count = READB(port, rbcl);
  190. count &= (port->recv_fifo_size - 1);
  191. ++msg_done;
  192. ++free_fifo;
  193. total_size = READB(port, rbch);
  194. if(total_size & SAB82532_RBCH_OV) /* need to revisit for 4096 byte frames */
  195. {
  196. msg_bad++;
  197. }
  198. rstatus = READB(port, rsta);
  199. if((rstatus & SAB82532_RSTA_VFR) == 0)
  200. {
  201. msg_bad++;
  202. }
  203. if(rstatus & SAB82532_RSTA_RDO)
  204. {
  205. msg_bad++;
  206. }
  207. if((rstatus & SAB82532_RSTA_CRC) == 0)
  208. {
  209. msg_bad++;
  210. }
  211. if(rstatus & SAB82532_RSTA_RAB)
  212. {
  213. msg_bad++;
  214. }
  215. }
  216. }
  217. /* Read the FIFO. */
  218. (*port->readfifo)(port, buf, count);
  219. /* Issue Receive Message Complete command. */
  220. if (free_fifo) 
  221. {
  222. sab8253x_cec_wait(port);
  223. WRITEB(port, cmdr, SAB82532_CMDR_RMC);
  224. }
  225. if(reset_fifo)
  226. {
  227. sab8253x_cec_wait(port);
  228. WRITEB(port, cmdr, SAB82532_CMDR_RHR);
  229. }
  230. if(msg_bad)
  231. {
  232. port->msgbufindex = 0;
  233. return;
  234. }
  235. memcpy(&port->msgbuf[port->msgbufindex], buf, count);
  236. port->msgbufindex += count;
  237. if(msg_done)
  238. {
  239. if(port->msgbufindex <= 3) /* min is 1 char + 2 CRC + status byte */
  240. {
  241. port->msgbufindex = 0;
  242. return;
  243. }
  244. total_size = port->msgbufindex - 3; /* strip off the crc16 and the status byte */
  245. port->msgbufindex = 0;
  246. /* ignore the receive buffer waiting -- we know the correct size here */
  247. if(skb = dev_alloc_skb(total_size), skb)
  248. {
  249. memcpy(skb->data, &port->msgbuf[0], total_size);
  250. skb->tail = (skb->data + total_size);
  251. skb->data_len = total_size;
  252. skb->len = total_size;
  253. skb_queue_tail(port->sab8253xc_rcvbuflist, skb);
  254. if(port->rx_empty)
  255. {
  256. port->rx_empty = 0;
  257. wake_up_interruptible(&port->read_wait);
  258. }
  259. if(port->async_queue)
  260. {
  261. kill_fasync(&port->async_queue, SIGIO, POLL_IN);
  262. }
  263. }
  264. }
  265. }
  266. static void sab8253x_check_statusC(struct sab_port *port,
  267.    union sab8253x_irq_status *stat)
  268. {
  269. int modem_change = 0;
  270. mctlsig_t         *sig;
  271. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) 
  272. {
  273. port->icount.buf_overrun++;
  274. }
  275. /* Checking DCD */
  276. sig = &port->dcd;
  277. if (stat->images[sig->irq] & sig->irqmask) 
  278. {
  279. sig->val = ISON(port,dcd);
  280. port->icount.dcd++;
  281. modem_change++;
  282. }
  283. /* Checking CTS */
  284. sig = &port->cts;
  285. if (stat->images[sig->irq] & sig->irqmask) 
  286. {
  287. sig->val = ISON(port,cts);
  288. port->icount.cts++;
  289. modem_change++;
  290. }
  291. /* Checking DSR */
  292. sig = &port->dsr;
  293. if (stat->images[sig->irq] & sig->irqmask) 
  294. {
  295. sig->val = ISON(port,dsr);
  296. port->icount.dsr++;
  297. modem_change++;
  298. }
  299. if (modem_change)
  300. {
  301. wake_up_interruptible(&port->delta_msr_wait);
  302. }
  303. sig = &port->dcd;
  304. if ((port->flags & FLAG8253X_CHECK_CD) &&
  305.     (stat->images[sig->irq] & sig->irqmask)) 
  306. {
  307. if (sig->val)
  308. {
  309. wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */
  310. }
  311. else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) &&
  312.    (port->flags & FLAG8253X_CALLOUT_NOHUP))) 
  313. {
  314. /* I think the code needs to walk through all the proces that have opened this
  315.  * port and send a SIGHUP to them -- need to investigate somewhat more*/
  316. }
  317. }
  318. }
  319. static int sab8253x_startupC(struct sab_port *port)
  320. {
  321. unsigned long flags;
  322. int retval = 0;
  323. save_flags(flags); cli();
  324. if (port->flags & FLAG8253X_INITIALIZED) 
  325. {
  326. goto errout;
  327. }
  328. if (!port->regs) 
  329. {
  330. retval = -ENODEV;
  331. goto errout;
  332. }
  333. /*
  334.  * Initialize the Hardware
  335.  */
  336. sab8253x_init_lineS(port); /* nothing in this function
  337.  * refers to tty structure */
  338. /* Activate RTS */
  339. RAISE(port,rts);
  340. /* Activate DTR */
  341. RAISE(port,dtr);
  342. /*
  343.  * Initialize the modem signals values
  344.  */
  345. port->dcd.val=ISON(port,dcd);
  346. port->cts.val=ISON(port,cts);
  347. port->dsr.val=ISON(port,dsr);
  348. /*
  349.  * Finally, enable interrupts
  350.  */
  351. port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE |
  352. SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC;
  353. #if 0
  354. ((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); /* the weird way the cards work
  355.        * when clocking CD seems to
  356.        *  monitor txclk*/
  357. #endif
  358. WRITEB(port,imr0,port->interrupt_mask0);
  359. port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR |
  360. SAB82532_IMR1_TIN | SAB82532_IMR1_XPR;
  361. WRITEB(port, imr1, port->interrupt_mask1);
  362. port->all_sent = 1;
  363. /*
  364.  * and set the speed of the serial port
  365.  */
  366. sab8253x_change_speedN(port);
  367. port->flags |= FLAG8253X_INITIALIZED; /* bad name for indicating to other functionalities status */
  368. port->receive_chars = sab8253x_receive_charsC;
  369. port->transmit_chars = sab8253x_transmit_charsS;
  370. port->check_status = sab8253x_check_statusC;
  371. port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF);
  372. port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR |
  373.        SAB82532_ISR1_XDU | SAB82532_ISR1_CSC);
  374. port->check_status_test = SAB82532_ISR1_CSC;
  375. restore_flags(flags);
  376. return 0;
  377.  errout:
  378. restore_flags(flags);
  379. return retval;
  380. }
  381. static int sab8253x_block_til_readyC(struct file* filp, struct sab_port *port)
  382. {
  383. DECLARE_WAITQUEUE(wait, current);
  384. int retval;
  385. int do_clocal = 1; /* cheating -- I need to understand how
  386.    signals behave synchronously better*/
  387. unsigned long flags;
  388. /*
  389.  * If the device is in the middle of being closed, then block
  390.  * until it's done, and then try again.
  391.  */
  392. if (port->flags & FLAG8253X_CLOSING)
  393. {
  394. interruptible_sleep_on(&port->close_wait); /* finish up previous close */
  395. #ifdef SERIAL_DO_RESTART
  396. if (port->flags & FLAG8253X_HUP_NOTIFY)
  397. {
  398. return -EAGAIN;
  399. }
  400. else
  401. {
  402. return -ERESTARTSYS;
  403. }
  404. #else
  405. return -EAGAIN;
  406. #endif
  407. }
  408. /* sort out async vs sync tty, not call out */
  409. /*
  410.  * If non-blocking mode is set, or the port is not enabled,
  411.  * then make the check up front and then exit.
  412.  */
  413. if (filp->f_flags & O_NONBLOCK) 
  414. {
  415. if (port->flags & FLAG8253X_CALLOUT_ACTIVE)
  416. {
  417. return -EBUSY;
  418. }
  419. port->flags |= FLAG8253X_NORMAL_ACTIVE;
  420. return 0;
  421. }
  422. if (port->flags & FLAG8253X_CALLOUT_ACTIVE) 
  423. {
  424. if (port->normal_termios.c_cflag & CLOCAL)
  425. {
  426. do_clocal = 1;
  427. }
  428. /*
  429.  * Block waiting for the carrier detect and the line to become
  430.  * free (i.e., not in use by the callout).  While we are in
  431.  * this loop, port->count is dropped by one, so that
  432.  * sab8253x_close() knows when to free things.  We restore it upon
  433.  * exit, either normal or abnormal.
  434.  */
  435. /* The port decrement logic is probably */
  436. /* broken -- hence if def'd out -- it does*/
  437. retval = 0;
  438. add_wait_queue(&port->open_wait, &wait); /* starts the wait but does not block here */
  439. port->blocked_open++;
  440. while (1) /* on some devices when providing clock have to just assume connection */
  441. {
  442. save_flags(flags);
  443. cli();
  444. if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE))
  445. {
  446. RAISE(port, dtr);
  447. RAISE(port, rts); /* maybe not correct for sync */
  448. /*
  449.  * ??? Why changing the mode here? 
  450.  *  port->regs->rw.mode |= SAB82532_MODE_FRTS;
  451.  *  port->regs->rw.mode &= ~(SAB82532_MODE_RTS);
  452.  */
  453. }
  454. restore_flags(flags);;
  455. current->state = TASK_INTERRUPTIBLE;
  456. if (!(port->flags & FLAG8253X_INITIALIZED)) 
  457. {
  458. #ifdef SERIAL_DO_RESTART
  459. if (port->flags & FLAG8253X_HUP_NOTIFY)
  460. {
  461. retval = -EAGAIN;
  462. }
  463. else
  464. {
  465. retval = -ERESTARTSYS;
  466. }
  467. #else
  468. retval = -EAGAIN;
  469. #endif
  470. break;
  471. }
  472. if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) &&
  473.     !(port->flags & FLAG8253X_CLOSING) &&
  474.     (do_clocal || ISON(port,dcd))) 
  475. {
  476. break;
  477. }
  478. #ifdef DEBUG_OPEN
  479. printk("sab8253x_block_til_ready:2 flags = 0x%xn",port->flags);
  480. #endif
  481. if (signal_pending(current)) 
  482. {
  483. retval = -ERESTARTSYS;
  484. break;
  485. }
  486. #ifdef DEBUG_OPEN
  487. printk("sab8253x_block_til_readyC blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02xn",
  488.        port->line, port->count, port->flags, do_clocal, READB(port,vstr));
  489. #endif
  490. schedule();
  491. }
  492. current->state = TASK_RUNNING;
  493. remove_wait_queue(&port->open_wait, &wait);
  494. port->blocked_open--;
  495. #ifdef DEBUG_OPEN
  496. printk("sab8253x_block_til_ready after blockingC: ttys%d, count = %dn",
  497.        port->line, port->count);
  498. #endif
  499. if (retval)
  500. {
  501. return retval;
  502. }
  503. port->flags |= FLAG8253X_NORMAL_ACTIVE;
  504. return 0;
  505. }
  506. int sab8253xc_open(struct inode *inodep, struct file *filep)
  507. {
  508. unsigned int line;
  509. unsigned int retval;
  510. unsigned int counter;
  511. SAB_PORT *port;
  512. line = MINOR(inodep->i_rdev); /* let's find which physical device to use */
  513. /* minor dev number indexes through the port */
  514. /* list */
  515. for(counter = 0, port = AuraPortRoot; 
  516.     (counter < line) && (port != NULL); 
  517.     ++counter)
  518. {
  519. port = port->next;
  520. }
  521. if (!port) 
  522. {
  523. printk(KERN_ALERT "sab8253xc_open: can't find structure for line %dn",
  524.        line);
  525. return -ENODEV;
  526. }
  527. if(port->function == FUNCTION_NA)
  528. { /* port 2 on 1020s and 1520s */
  529. return -ENODEV;
  530. }
  531. switch(port->open_type)
  532. {
  533. case OPEN_ASYNC:
  534. if(!(port->flags & FLAG8253X_CALLOUT_ACTIVE))
  535. {
  536. return -EBUSY;
  537. }
  538. break;
  539. case OPEN_SYNC_CHAR:
  540. case OPEN_NOT:
  541. port->tty = NULL;
  542. port->open_type = OPEN_SYNC_CHAR;
  543. break;
  544. default:
  545. return -EBUSY;
  546. }
  547. /*
  548.  * Maybe start up serial port -- may already be running in callout mode
  549.  */
  550. if(Sab8253xSetUpLists(port))
  551. {
  552. if(port->open_type == OPEN_SYNC_CHAR)
  553. {
  554. port->open_type = OPEN_NOT;
  555. }
  556. return -ENODEV;
  557. }
  558. if(Sab8253xInitDescriptors2(port, sab8253xc_listsize, sab8253xc_rbufsize))
  559. {
  560. Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */
  561. /* is the crc32 that is appended */
  562. if(port->open_type == OPEN_SYNC_CHAR)
  563. {
  564. port->open_type = OPEN_NOT;
  565. }
  566. return -ENODEV;
  567. }
  568. retval = sab8253x_startupC(port); /* does not do anything if call out active */
  569. if (retval)
  570. {
  571. if(port->open_type == OPEN_SYNC_CHAR)
  572. {
  573. port->open_type = OPEN_NOT;
  574. }
  575. return retval;
  576. }
  577. MOD_INC_USE_COUNT; /* might block */
  578. /* note logic different from tty
  579.    open failure does not call the
  580.    close routine */
  581. retval = sab8253x_block_til_readyC(filep, port); /* need to wait for completion of callout */
  582. if(retval)
  583. {
  584. if(port->open_type == OPEN_SYNC_CHAR)
  585. {
  586. port->open_type = OPEN_NOT;
  587. }
  588. MOD_DEC_USE_COUNT; /* something went wrong */
  589. return retval;
  590. }
  591. port->tty = NULL;
  592. port->open_type = OPEN_SYNC_CHAR;
  593. if(Sab8253xSetUpLists(port))
  594. {
  595. port->open_type = OPEN_NOT;
  596. return -ENODEV;
  597. }
  598. if(Sab8253xInitDescriptors2(port, sab8253xc_listsize, sab8253xc_rbufsize))
  599. {
  600. port->open_type = OPEN_NOT;
  601. Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */
  602. /* is the crc32 that is appended */
  603. return -ENODEV;
  604. }
  605. retval = sab8253x_startupC(port); /* ditto */
  606. if (retval)
  607. {
  608. port->open_type = OPEN_NOT;
  609. Sab8253xCleanUpTransceiveN(port);
  610. return retval;
  611. }
  612. port->tx_full = 0;
  613. port->rx_empty = 1;
  614. port->count++;
  615. port->session = current->session;
  616. port->pgrp = current->pgrp;
  617. filep->private_data = port;
  618. MOD_INC_USE_COUNT;
  619. return 0; /* success */
  620. }
  621. int sab8253xc_release(struct inode *inodep, struct file *filep)
  622. {
  623. SAB_PORT *port = (SAB_PORT*) filep->private_data;
  624. unsigned long flags;
  625. save_flags(flags); cli();
  626. --(port->count);
  627. if(port->count <= 0)
  628. {
  629. sab8253x_shutdownN(port);
  630. Sab8253xCleanUpTransceiveN(port);
  631. port->count = 0;
  632. port->open_type = OPEN_NOT;
  633. }
  634. sab8253xc_fasync(-1, filep, 0);
  635. MOD_DEC_USE_COUNT;
  636. restore_flags(flags);
  637. return 0;
  638. }
  639. unsigned int sab8253xc_poll(struct file *fileobj, struct poll_table_struct *polltab)
  640. {
  641. SAB_PORT *port = fileobj->private_data;
  642. unsigned int mask = 0;
  643. poll_wait(fileobj, &port->write_wait, polltab);
  644. poll_wait(fileobj, &port->read_wait, polltab);
  645. if(port->rx_empty == 0)
  646. {
  647. mask |= POLLIN | POLLRDNORM;
  648. }
  649. if(port->tx_full == 0)
  650. {
  651. mask |= POLLOUT | POLLWRNORM;
  652. }
  653. return mask;
  654. }
  655. int sab8253xc_ioctl(struct inode *iobj, struct file *fileobj, unsigned int cmd, unsigned long length)
  656. {
  657. return 0;
  658. }
  659. int sab8253xc_fasync(int fd, struct file * fileobj, int mode)
  660. {
  661. SAB_PORT *port = fileobj->private_data;
  662. return fasync_helper(fd, fileobj, mode, &port->async_queue); /* I am a little baffled -- does async_helper */
  663. /* work on the basis of a port or on an open */
  664. /* basis*/
  665. }