rs232dbg/aip_com.c
changeset 0 05c992bf5847
child 5 6f2508af550c
equal deleted inserted replaced
-1:000000000000 0:05c992bf5847
       
     1 /** rt_com
       
     2  *  ======
       
     3  *
       
     4  * RT-Linux kernel module for communication across serial lines.
       
     5  *
       
     6  * Copyright (C) 1997 Jens Michaelsen
       
     7  * Copyright (C) 1997-2000 Jochen Kupper
       
     8  * Copyright (C) 1999 Hua Mao <hmao@nmt.edu>
       
     9  * Copyright (C) 1999 Roberto Finazzi
       
    10  * Copyright (C) 2000-2002 Giuseppe Renoldi
       
    11  *
       
    12  * This program is free software; you can redistribute it and/or
       
    13  * modify it under the terms of the GNU General Public License as
       
    14  * published by the Free Software Foundation; either version 2 of the
       
    15  * License, or (at your option) any later version.
       
    16  *
       
    17  * This program is distributed in the hope that it will be useful, but
       
    18  * WITHOUT ANY WARRANTY; without even the implied warranty of
       
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    20  * General Public License for more details.
       
    21  *
       
    22  * You should have received a copy of the GNU General Public License
       
    23  * along with this program; see the file License. if not, write to the
       
    24  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       
    25  * MA 02111-1307, USA.
       
    26  *
       
    27  * $Id: aip_com.c,v 1.1 2005/09/16 14:16:31 hm Exp hm $ */
       
    28 #define VERSION "0.6.pre2-rtaicvs (modified by Hm, IgH for aip)"   //Hm, IgH
       
    29 
       
    30 #include <linux/config.h>
       
    31 #include <linux/errno.h>
       
    32 #include <linux/ioport.h>
       
    33 #include <linux/kernel.h>
       
    34 #include <linux/module.h>
       
    35 #include <linux/version.h>
       
    36 
       
    37 #include <asm/system.h>
       
    38 #include <asm/io.h>
       
    39 
       
    40 #ifdef _RTAI
       
    41 #include <rtai.h>
       
    42 #endif
       
    43 
       
    44 #include "aip_com.h"
       
    45 #include "aip_comP.h"
       
    46 
       
    47 /* Hm, IgH
       
    48 MODULE_AUTHOR("Jochen Kuepper");
       
    49 MODULE_DESCRIPTION("real-time serial port driver");
       
    50 MODULE_LICENSE("GPL");
       
    51 */
       
    52 
       
    53 
       
    54 /* size of internal queues
       
    55 * This is the default value. */
       
    56 unsigned int            rt_com_buffersize = RT_COM_BUF_SIZ;
       
    57 
       
    58 /** Default: mode=0 - no hw flow control
       
    59  *           used=0 - port and irq setting by rt_com_hwparam.
       
    60  *                    If you want to work like
       
    61  *                    a standard rt_com you can set used=1. */
       
    62 struct rt_com_struct    rt_com_table[] = { 
       
    63        {    // ttyS0 - COM1
       
    64         RT_COM_BASE_BAUD,   // int baud_base;
       
    65         0x3f8,          // int port;
       
    66         4,              // int irq;
       
    67         rt_com0_isr,    // void (*isr)(void);
       
    68         115200,  // int baud;
       
    69         8,  // unsigned int wordlength;
       
    70         RT_COM_PARITY_NONE, // unsigned int parity;
       
    71         1,  // stopbits;
       
    72         RT_COM_NO_HAND_SHAKE,   // int mode;
       
    73         RT_COM_FIFO_SIZE_8,     // int fifotrig;
       
    74         1 //Hm, IgH   // int used;
       
    75     }, {    // ttyS1 - COM2
       
    76         RT_COM_BASE_BAUD,   // int baud_base;
       
    77         0x2f8,          // int port;
       
    78         3,              // int irq;
       
    79         rt_com1_isr,    // void (*isr)(void);
       
    80         0,  // int baud;
       
    81         8,  // unsigned int wordlength;
       
    82         RT_COM_PARITY_NONE, // unsigned int parity;
       
    83         1,  // stopbits;
       
    84         RT_COM_NO_HAND_SHAKE,   // int mode;
       
    85         RT_COM_FIFO_SIZE_8,     // int fifotrig;
       
    86         0   // int used;
       
    87     }
       
    88 };
       
    89 
       
    90 /** Number and descriptions of serial ports to manage.  You also need
       
    91  * to create an ISR ( rt_comN_isr() ) for each port.  */
       
    92 #define RT_COM_CNT  (sizeof(rt_com_table) / sizeof(struct rt_com_struct))
       
    93 
       
    94 /** Internal: Remaining free space of buffer
       
    95  *
       
    96  * @return amount of free space remaining in a buffer (input or output)
       
    97  *
       
    98  * @author Jochen Kupper
       
    99  * @version 2000/03/10 */
       
   100 static inline unsigned int rt_com_buffer_free(unsigned int head, unsigned int tail)
       
   101 {
       
   102     return(head < tail) ? (tail - head) : (rt_com_buffersize - (head - tail));
       
   103 }
       
   104 
       
   105 /** Clear input buffer.
       
   106  *
       
   107  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   108  * @return       0 if all right, -ENODEV or -EPERM on error.
       
   109  *
       
   110  * @author Roberto Finazzi, Jochen Kupper
       
   111  * @version 2000/03/12 */
       
   112 int rt_com_clear_input(unsigned int ttyS)
       
   113 {
       
   114     if (ttyS >= RT_COM_CNT) {
       
   115         return(-ENODEV);
       
   116     }
       
   117     else if (0 >= (rt_com_table[ttyS]).used) {
       
   118         return(-EPERM);
       
   119     }
       
   120     else {
       
   121         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   122         struct rt_buf_struct    *b = &(p->ibuf);
       
   123         long                    state;
       
   124         rt_com_irq_off(state);
       
   125         b->tail = b->head;
       
   126         if (p->fifotrig)
       
   127             outb(inb(p->port + RT_COM_FCR) | FCR_INPUT_FIFO_RESET, p->port + RT_COM_FCR);
       
   128         rt_com_irq_on(state);
       
   129         if (p->mode & RT_COM_HW_FLOW) {
       
   130             /* with hardware flow set RTS */
       
   131             p->mcr |= MCR_RTS;
       
   132             outb(p->mcr, p->port + RT_COM_MCR);
       
   133         }
       
   134 
       
   135         return(0);
       
   136     }
       
   137 }
       
   138 
       
   139 /** Clear output buffer.
       
   140  *
       
   141  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   142  * @return       0 if all right, negative error conditions otherwise
       
   143  *
       
   144  * @author Roberto Finazzi, Jochen Kupper
       
   145  * @version 2000/03/12
       
   146  */
       
   147 int rt_com_clear_output(unsigned int ttyS)
       
   148 {
       
   149     if (ttyS >= RT_COM_CNT) {
       
   150         return(-ENODEV);
       
   151     }
       
   152     else {
       
   153         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   154         if (0 >= (rt_com_table[ttyS]).used) {
       
   155             return(-EPERM);
       
   156         }
       
   157         else {
       
   158             struct rt_buf_struct    *b = &(p->obuf);
       
   159             long                    state;
       
   160             rt_com_irq_off(state);
       
   161             p->ier &= ~IER_ETBEI;
       
   162             outb(p->ier, p->port | RT_COM_IER);
       
   163             b->tail = b->head;
       
   164             if (p->fifotrig)
       
   165                 outb(inb(p->port + RT_COM_FCR) | FCR_OUTPUT_FIFO_RESET, p->port + RT_COM_FCR);
       
   166             rt_com_irq_on(state);
       
   167             return(0);
       
   168         }
       
   169     }
       
   170 }
       
   171 
       
   172 /** Set functioning mode.
       
   173  *
       
   174  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   175  * @param mode   functioning mode 
       
   176  * @return       0 if all right, negative on error
       
   177  *
       
   178  * @author Roberto Finazzi, Jochen Kupper
       
   179  * @version 2000/03/12
       
   180  */
       
   181 int rt_com_set_mode(unsigned int ttyS, int mode)
       
   182 {
       
   183     if (ttyS >= RT_COM_CNT) {
       
   184         return(-ENODEV);
       
   185     }
       
   186     else {
       
   187         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   188         if (0 >= p->used) {
       
   189             return(-EPERM);
       
   190         }
       
   191         else {
       
   192             p->mode = mode;
       
   193             if (p->used & RT_COM_PORT_SETUP) {
       
   194                 /* setup done */
       
   195                 if (mode == RT_COM_NO_HAND_SHAKE) {
       
   196                     /* if no hw signals disable modem interrupts */
       
   197                     p->ier &= ~IER_EDSSI;
       
   198                 }
       
   199                 else {
       
   200                     /* else enable it */
       
   201                     p->ier |= IER_EDSSI;
       
   202                 }
       
   203 
       
   204                 outb(p->ier, p->port + RT_COM_IER);
       
   205             }
       
   206 
       
   207             return(0);
       
   208         }
       
   209     }
       
   210 }
       
   211 
       
   212 /** Set receiver fifo trigger level.
       
   213  *
       
   214  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   215  * @param fifotrig   receiver fifo trigger level 
       
   216  * @return           0 if all right, negative on error
       
   217  *
       
   218  * @author Roberto Finazzi, Jochen Kupper
       
   219  * @version 2000/03/12
       
   220  */
       
   221 int rt_com_set_fifotrig(unsigned int ttyS, int fifotrig)
       
   222 {
       
   223     if (ttyS >= RT_COM_CNT) {
       
   224         return(-ENODEV);
       
   225     }
       
   226     else {
       
   227         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   228         p->fifotrig = fifotrig;
       
   229         if (p->used & RT_COM_PORT_SETUP) {
       
   230             /* setup done */
       
   231             if (p->fifotrig)
       
   232                 outb(FCR_FIFO_ENABLE | p->fifotrig, p->port + RT_COM_FCR);  // enable fifo
       
   233             else
       
   234                 outb(0, p->port + RT_COM_FCR);  // disable fifo	
       
   235         }
       
   236     }
       
   237 
       
   238     return(0);
       
   239 }
       
   240 
       
   241 /** Set output signal for modem control (DTR, RTS).
       
   242  *
       
   243  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   244  * @param signal Output signals: RT_COM_DTR or RT_COM_RTS.
       
   245  * @param value  Status: 0 or 1. 
       
   246  * @return       0 if all right, negative error code otherwise
       
   247  *
       
   248  * @author Roberto Finazzi, Jochen Kupper
       
   249  * @version 2000/03/12 */
       
   250 int rt_com_write_modem(unsigned int ttyS, int signal, int value)
       
   251 {
       
   252     if (ttyS >= RT_COM_CNT) {
       
   253         return(-ENODEV);
       
   254     }
       
   255     else if (value &~0x01) {
       
   256         return(-EINVAL);
       
   257     }
       
   258     else {
       
   259         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   260         if (0 >= p->used) {
       
   261             return(-EPERM);
       
   262         }
       
   263         else {
       
   264             if (value)
       
   265                 p->mcr |= signal;
       
   266             else
       
   267                 p->mcr &= ~signal;
       
   268             outb(p->mcr, p->port + RT_COM_MCR);
       
   269             return(0);
       
   270         }
       
   271     }
       
   272 }
       
   273 
       
   274 /** Read input signal from modem (CTS, DSR, RI, DCD).
       
   275  *
       
   276  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   277  * @param signal Input signals: RT_COM_CTS, RT_COM_DSR, RT_COM_RI, RT_COM_DCD
       
   278  *               or any combination.  
       
   279  * @return       input signal status; that is the bitwise-OR of the signal
       
   280  *               argument and the MSR register.
       
   281  *
       
   282  * @author Roberto Finazzi, Jochen Kupper
       
   283  * @version 2000/03/12 */
       
   284 int rt_com_read_modem(unsigned int ttyS, int signal)
       
   285 {
       
   286     if (ttyS >= RT_COM_CNT) {
       
   287         return(-ENODEV);
       
   288     }
       
   289     else if (signal & 0xf) {
       
   290         return(-EINVAL);
       
   291     }
       
   292     else {
       
   293         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   294         if (0 >= p->used) {
       
   295             return(-EPERM);
       
   296         }
       
   297         else {
       
   298             return(inb(p->port + RT_COM_MSR) & signal);
       
   299         }
       
   300     }
       
   301 }
       
   302 
       
   303 /** Return last error detected.
       
   304  *
       
   305  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   306  * @return       bit 0 :1 = Input buffer overflow
       
   307  *               bit 1 :1 = Receive data overrun 
       
   308  *               bit 2 :1 = Parity error 
       
   309  *               bit 3 :1 = Framing error
       
   310  *               bit 4 :1 = Break detected 
       
   311  *
       
   312  * @author Roberto Finazzi
       
   313  * @version 2000/03/12
       
   314  */
       
   315 int rt_com_error(unsigned int ttyS)
       
   316 {
       
   317     if (ttyS >= RT_COM_CNT) {
       
   318         return(-ENODEV);
       
   319     }
       
   320     else {
       
   321         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   322         int                     tmp = p->error;
       
   323         p->error = 0;
       
   324         return(tmp);
       
   325     }
       
   326 }
       
   327 
       
   328 /** Write data to a line.
       
   329  *
       
   330  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   331  * @param buffer Address of data.
       
   332  * @param count  Number of bytes to write. If negative, send byte only if 
       
   333  *               possible to send them all together.
       
   334  * @return       Number of bytes not written. Negative values are error
       
   335  *               conditions.
       
   336  *
       
   337  * @author Jens Michaelsen, Jochen Kupper, Giuseppe Renoldi
       
   338  * @version 2000/03/12 */
       
   339 int rt_com_write(unsigned int ttyS, char *buffer, int count)
       
   340 {
       
   341     if (ttyS >= RT_COM_CNT) {
       
   342         return(-ENODEV);
       
   343     }
       
   344     else {
       
   345         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   346         if (!(p->used & RT_COM_PORT_SETUP)) {
       
   347             return(-EPERM);
       
   348         }
       
   349         else {
       
   350             struct rt_buf_struct    *b = &(p->obuf);
       
   351             long                    state;
       
   352             int                     bytestosend;
       
   353             if (count == 0)
       
   354                 return(0);
       
   355             bytestosend = rt_com_buffer_free(b->head, b->tail);
       
   356             if (count < 0) {
       
   357                 count = -count;
       
   358                 if (count > bytestosend)
       
   359                     return(count);
       
   360                 bytestosend = count;
       
   361             }
       
   362             else {
       
   363                 if (count <= bytestosend)
       
   364                     bytestosend = count;
       
   365             }
       
   366 
       
   367             rt_com_irq_off(state);  
       
   368             while (bytestosend-- > 0) {
       
   369                 /* put byte into buffer, move pointers to next elements */
       
   370                 b->buf[b->head++] = *buffer++;
       
   371                 if (b->head >= rt_com_buffersize)
       
   372                     b->head = 0;
       
   373                 --count;
       
   374             }
       
   375 
       
   376             p->ier |= IER_ETBEI;
       
   377             outb(p->ier, p->port + RT_COM_IER);
       
   378             rt_com_irq_on(state);
       
   379             return(count);
       
   380         }
       
   381     }
       
   382 }
       
   383 
       
   384 /** Read data we got from a line.
       
   385  *
       
   386  * @param ttyS   Port to use corresponding to internal numbering scheme.
       
   387  * @param buffer Address of data buffer. Needs to be of size > cnt !
       
   388  * @param count  Number of bytes to read.
       
   389  * @return       Number of bytes actually read.
       
   390  *
       
   391  * @author Jens Michaelsen, Jochen Kupper
       
   392  * @version 2000/03/17 */
       
   393 int rt_com_read(unsigned int ttyS, char *buffer, int count)
       
   394 {
       
   395     if (0 > count) {
       
   396         return(-EINVAL);
       
   397     }
       
   398     else if (ttyS >= RT_COM_CNT) {
       
   399         return(-ENODEV);
       
   400     }
       
   401     else {
       
   402         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   403         if (!(p->used & RT_COM_PORT_SETUP)) {
       
   404             return(-EPERM);
       
   405         }
       
   406         else {
       
   407             struct rt_buf_struct    *b = &(p->ibuf);
       
   408             int                     done = 0;
       
   409             long                    state;
       
   410             rt_com_irq_off(state);
       
   411             while ((b->head != b->tail) && (--count >= 0)) {
       
   412                 done++;
       
   413                 *buffer++ = b->buf[b->tail++];
       
   414                 b->tail &= (RT_COM_BUF_SIZ - 1);
       
   415             }
       
   416 
       
   417             rt_com_irq_on(state);
       
   418             if ((p->mode & RT_COM_HW_FLOW) && (rt_com_buffer_free(b->head, b->tail) > RT_COM_BUF_HI)) {
       
   419                 /* if hardware flow and enough free space on input buffer
       
   420 				   then set RTS */
       
   421                 p->mcr |= MCR_RTS;
       
   422                 outb(p->mcr, p->port + RT_COM_MCR);
       
   423             }
       
   424 
       
   425             return(done);
       
   426         }
       
   427     }
       
   428 }
       
   429 
       
   430 /** Get first byte from the write buffer.
       
   431  *
       
   432  * @param p  rt_com_struct of the line we are writing to.
       
   433  * @param c  Address to put the char in.
       
   434  * @return   Number of characters we actually got.
       
   435  * 
       
   436  * @author Jens Michaelsen, Jochen Kupper
       
   437  * @version 1999/10/01
       
   438  */
       
   439 static inline int rt_com_irq_get(struct rt_com_struct *p, unsigned char *c)
       
   440 {
       
   441     struct rt_buf_struct    *b = &(p->obuf);
       
   442     if (b->head != b->tail) {
       
   443         *c = b->buf[b->tail++];
       
   444         b->tail &= (RT_COM_BUF_SIZ - 1);
       
   445         return(1);
       
   446     }
       
   447 
       
   448     return(0);
       
   449 }
       
   450 
       
   451 /** Concatenate a byte to the read buffer.
       
   452  *
       
   453  * @param p   rt_com_struct of the line we are writing to.
       
   454  * @param ch  Byte to put into buffer.
       
   455  *
       
   456  * @author Jens Michaelsen, Jochen Kupper
       
   457  * @version 1999/07/20 */
       
   458 static inline void rt_com_irq_put(struct rt_com_struct *p, unsigned char ch)
       
   459 {
       
   460     struct rt_buf_struct    *b = &(p->ibuf);
       
   461     b->buf[b->head++] = ch;
       
   462     b->head &= (RT_COM_BUF_SIZ - 1);
       
   463 }
       
   464 
       
   465 /** Real interrupt handler.
       
   466  *
       
   467  * This one is called by the registered ISRs and does the actual work.
       
   468  *
       
   469  * @param ttyS  Port to use corresponding to internal numbering scheme.
       
   470  *
       
   471  * @author Jens Michaelsen, Jochen Kupper, Hua Mao, Roberto Finazzi
       
   472  * @version 2000/03/17 */
       
   473 static inline int rt_com_isr(unsigned int ttyS)
       
   474 {
       
   475     struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   476     struct rt_buf_struct    *b = &(p->ibuf);
       
   477     unsigned int            base = p->port;
       
   478     int                     buff, data_to_tx;
       
   479     int                     loop = 4;
       
   480     int                     toFifo = 16;
       
   481     unsigned char           data, msr, lsr, iir;
       
   482 
       
   483     do {
       
   484         //iir=inb(base + RT_COM_IIR);
       
   485         //rt_printk("iir=0x%02x\n",iir);
       
   486         /* get available data from port */
       
   487         lsr = inb(base + RT_COM_LSR);
       
   488         if (0x1e & lsr)
       
   489             p->error = lsr & 0x1e;
       
   490         while (LSR_DATA_READY & lsr) {
       
   491             data = inb(base + RT_COM_RXB);
       
   492 
       
   493             //rt_printk("[%02x<- ",data);	
       
   494             rt_com_irq_put(p, data);
       
   495             lsr = inb(base + RT_COM_LSR);
       
   496             if (0x1e & lsr)
       
   497                 p->error = 0x1e & lsr;
       
   498         }
       
   499 
       
   500         /* controls on buffer full and RTS clear on hardware flow
       
   501            control */
       
   502         buff = rt_com_buffer_free(b->head, b->tail);
       
   503         if (buff < RT_COM_BUF_FULL)
       
   504             p->error = RT_COM_BUFFER_FULL;
       
   505 
       
   506         if ((p->mode & RT_COM_HW_FLOW) && (buff < RT_COM_BUF_LOW)) {
       
   507             p->mcr &= ~MCR_RTS;
       
   508             outb(p->mcr, p->port + RT_COM_MCR);
       
   509         }
       
   510 
       
   511         /* if possible, put data to port */
       
   512         msr = inb(base + RT_COM_MSR);
       
   513         if
       
   514         (
       
   515             (p->mode == RT_COM_NO_HAND_SHAKE) ||
       
   516             ((p->mode & RT_COM_DSR_ON_TX) && (MSR_DSR & msr) && (p->mode & RT_COM_HW_FLOW) && (MSR_CTS & msr))
       
   517         ) {
       
   518             /* (DSR && (CTS || Mode==no hw flow)) or Mode==no handshake */
       
   519             // if (THRE==1) i.e. transmitter empty
       
   520             if ((lsr = inb(base + RT_COM_LSR)) & LSR_THRE) {
       
   521                 // if there are data to transmit
       
   522                 if ((data_to_tx = rt_com_irq_get(p, &data)) != 0) {
       
   523                     do {
       
   524                         //rt_printk("->%02x] ",data);	
       
   525                         outb(data, base + RT_COM_TXB);
       
   526                     } while ((--toFifo > 0) && (data_to_tx = rt_com_irq_get(p, &data) != 0));
       
   527                 }
       
   528 
       
   529                 if (!data_to_tx) {
       
   530                     /* no data in output buffer, disable Transmitter
       
   531 	               	   Holding Register Empty Interrupt */
       
   532                     p->ier &= ~IER_ETBEI;
       
   533                     outb(p->ier, base + RT_COM_IER);
       
   534                 }
       
   535             }
       
   536         }
       
   537 
       
   538         /* check the low nibble of IIR wheather there is another pending
       
   539            interrupt.  bit 0 = 0 if interrupt pending, bits 1,2,3 
       
   540 		   are the interrupt ID */
       
   541         iir = inb(base + RT_COM_IIR);
       
   542     } while (((iir & 0x0F) != 1) && (--loop > 0));
       
   543 
       
   544 #if defined RTLINUX_V2
       
   545     rtl_hard_enable_irq(p->irq);
       
   546 #endif
       
   547     return 0;
       
   548 }
       
   549 
       
   550 /** Interrupt Service Routines
       
   551  *
       
   552  * These are the Interrupt Service Routines to be registered with the
       
   553  * OS. They simply call the genereric interrupt handler for the
       
   554  * current port to do the work.
       
   555  *
       
   556  * @author Jens Michaelsen, Jochen Kupper, Hua Mao
       
   557  * @version 1999/11/11 */
       
   558 static void rt_com0_isr(void)
       
   559 {
       
   560     //rt_printk("rt_com0_isr\n");
       
   561     rt_com_isr(0);
       
   562 }
       
   563 
       
   564 static void rt_com1_isr(void)
       
   565 {
       
   566     //rt_printk("rt_com1_isr\n");
       
   567     rt_com_isr(1);
       
   568 }
       
   569 
       
   570 /** Setup one port
       
   571  *
       
   572  * Calls from init_module + cleanup_module have baud == 0; in these
       
   573  * cases we only do some cleanup.
       
   574  *
       
   575  * To allocate a port, give usefull setup parameter, to deallocate
       
   576  * give negative baud.
       
   577  *
       
   578  * @param ttyS       Number corresponding to internal port numbering scheme.
       
   579  *                   This is esp. the index of the rt_com_table to use.
       
   580  * @param baud       Data transmission rate to use [Byte/s]. If negative,
       
   581  *                   deallocate port instead. Called with baud == 0 from
       
   582  *                   init_module for basic initialization. Needs to be called
       
   583  *                   by user-task again before use !
       
   584  * @param mode       see rt_com_set_mode docs for now
       
   585  * @param parity     Parity for transmission protocol.
       
   586  *                   (RT_COM_PARITY_EVEN, RT_COM_PARITY_ODD, RT_COM_PARITY_NONE)
       
   587  * @param stopbits   Number of stopbits to use. 1 gives you one stopbit, 2
       
   588  *                   actually gives really two stopbits for wordlengths of
       
   589  *                   6 - 8 bit, but 1.5 stopbits for a wordlength of 5 bits.
       
   590  * @param wordlength Number of bits per word (5 - 8 bits).
       
   591  * @param fifotrig   if <0 set trigger fifo using default value set
       
   592  *                   in rt_com_table[], otherwise set trigger fifo accordingly
       
   593  *                   to the parameter
       
   594  * @return           0       - all right
       
   595  *                   -ENODEV - no entry for that ttyS in rt_com_table
       
   596  *                   -EPERM  - get hardware resources first (the port needs to
       
   597  *                             be setup hardware-wise first, that means you have
       
   598  *                             to specify a positive used flag at compile time
       
   599  *                             or call rt_com_set_hwparm first.)
       
   600  *
       
   601  * @author Jens Michaelsen, Jochen Kupper, Roberto Finazzi
       
   602  * @version 2000/03/12 */
       
   603 int rt_com_setup
       
   604 (
       
   605     unsigned int    ttyS,
       
   606     int             baud,
       
   607     int             mode,
       
   608     unsigned int    parity,
       
   609     unsigned int    stopbits,
       
   610     unsigned int    wordlength,
       
   611     int             fifotrig			
       
   612 )
       
   613 {
       
   614     if (ttyS >= RT_COM_CNT) {
       
   615         return(-ENODEV);
       
   616     }
       
   617     else {
       
   618         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   619         if (0 == p->used) {
       
   620             /*  */
       
   621             return(-EPERM);
       
   622         }
       
   623         else {
       
   624             unsigned int    base = p->port;
       
   625 
       
   626             /* Stop everything, set DLAB */
       
   627             outb(0x00, base + RT_COM_IER);
       
   628             outb(0x80, base + RT_COM_LCR);
       
   629 
       
   630             /* clear irqs */
       
   631             inb(base + RT_COM_IIR);
       
   632             inb(base + RT_COM_LSR);
       
   633             inb(base + RT_COM_RXB);
       
   634             inb(base + RT_COM_MSR);
       
   635 
       
   636             /* initialize error code */
       
   637             p->error = 0;
       
   638 
       
   639             /* if 0 == baud, nothing else to do ! */
       
   640             if (baud == 0)
       
   641                 return(0);
       
   642 
       
   643             if (0 > baud) {
       
   644                 /* free the port */
       
   645                 /* disable interrupts */
       
   646                 outb(0, base + RT_COM_IER);
       
   647                 //MOD_DEC_USE_COUNT;  Hm, IgH
       
   648                 return(0);
       
   649             }
       
   650             else {
       
   651                 /* allocate and set-up the port */
       
   652                 unsigned int    divider = p->baud_base / baud;
       
   653 
       
   654                 //MOD_INC_USE_COUNT; Hm, IgH
       
   655 
       
   656                 /* set transfer rate */
       
   657                 outb(divider % 256, base + RT_COM_DLL);
       
   658                 outb(divider / 256, base + RT_COM_DLM);
       
   659 
       
   660                 /* bits 3,4 + 5 determine parity, mask away anything else */
       
   661                 parity &= 0x38;
       
   662 
       
   663                 /* set transmission parameters and clear DLAB */
       
   664                 outb((wordlength - 5) | ((stopbits - 1) << 2) | parity, base + RT_COM_LCR);
       
   665 
       
   666                 /* set-up MCR value and write it */
       
   667                 p->mcr = MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2;
       
   668                 outb(p->mcr, base + RT_COM_MCR);
       
   669 
       
   670                 /* set-up IER value and write it */
       
   671                 p->mode = mode;
       
   672                 if (p->mode == RT_COM_NO_HAND_SHAKE) {
       
   673                     /* if no handshaking signals enable only receiver interrupts  */
       
   674                     p->ier = IER_ERBI | IER_ELSI;
       
   675                 }
       
   676                 else {
       
   677                     /* enable receiver and modem interrupts */
       
   678                     p->ier = IER_ERBI | IER_ELSI | IER_EDSSI;
       
   679                 }
       
   680 
       
   681                 outb(p->ier, base + RT_COM_IER);
       
   682 		if (fifotrig>=0)
       
   683 		    p->fifotrig = fifotrig;	
       
   684                 outb(FCR_FIFO_ENABLE | p->fifotrig, base + RT_COM_FCR); // enable fifo
       
   685                 /* mark setup done */
       
   686                 p->used |= RT_COM_PORT_SETUP;
       
   687                 return(0);
       
   688             }
       
   689         }
       
   690 
       
   691         return(0);
       
   692     }
       
   693 }
       
   694 
       
   695 /** Set hardware parameter for a specific port.
       
   696  *
       
   697  * Change port address and irq setting for a specified port. The port
       
   698  * must have an entry in rt_com_table beforehand.
       
   699  *
       
   700  * To allow the specification of additional ports we would need to
       
   701  * dynamically allocate memory, that's not really feasible within a
       
   702  * real-time context, although we could preallocate a few entries in
       
   703  * init_module. However, it doesn't make too much sense, as you can
       
   704  * specify all ports that really exist (in hardware) at compile time
       
   705  * and enable only these you want to use.
       
   706  *
       
   707  * @param ttyS   Port to use; corresponding to internal numbering scheme.
       
   708  * @param port   port address, if zero, use standard value from rt_com_table
       
   709  * @param irq    irq address, if zero, use standard value from rt_com_table
       
   710  * @return        0       everything all right,
       
   711  *               -ENODEV  no entry in rt_com_table for that device,
       
   712  *               -EBUSY   port-region is used already.
       
   713  *
       
   714  * @author Roberto Finazzi, Jochen Kupper
       
   715  * @version 2000/03/10 */
       
   716 int rt_com_hwsetup(unsigned int ttyS, int port, int irq)
       
   717 {
       
   718     if (ttyS < RT_COM_CNT) {
       
   719         struct rt_com_struct    *p = &(rt_com_table[ttyS]);
       
   720         if (0 == p->used) {
       
   721             if (0 != port)
       
   722                 p->port = port;
       
   723             if (0 != irq)
       
   724                 p->irq = irq;
       
   725             if (-EBUSY == check_region(p->port, 8)) {
       
   726                 return(-EBUSY);
       
   727             }
       
   728 
       
   729             request_region(p->port, 8, RT_COM_NAME);
       
   730             rt_com_request_irq(p->irq, p->isr);
       
   731             p->used = 1;
       
   732             rt_com_setup(ttyS, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
       
   733             return(0);
       
   734         }
       
   735         else {
       
   736             if (port >= 0)
       
   737                 return(-EBUSY);
       
   738             rt_com_setup(ttyS, 0, 0, 0, 0, 0, 0);
       
   739             rt_com_free_irq(p->irq);
       
   740             release_region(p->port, 8);
       
   741             p->used = 0;
       
   742             return(0);
       
   743         }
       
   744     }
       
   745 
       
   746     return(-ENODEV);
       
   747 }
       
   748 
       
   749 /** Initialization
       
   750  *
       
   751  * For all ports that have a used flag greater than 0, request port
       
   752  * memory and register ISRs. If we cannot get the memory of all these
       
   753  * ports, release all already requested ports and return an error.
       
   754  *
       
   755  * @return Success status, zero on success. With a non-zero return
       
   756  * value of this routine, insmod will fail to load the module !
       
   757  *
       
   758  * @author Jochen Kupper, Hua Mao, Roberto Finazzi
       
   759  * @version 2000/03/10 */
       
   760 //int init_module(void)   //Hm, IgH
       
   761 int init_aip_com(void)
       
   762 {
       
   763     int             errorcode = 0;
       
   764     unsigned int    i, j;
       
   765 
       
   766     printk(KERN_INFO "rt_com: Loading real-time serial port driver (version "VERSION ").\n");
       
   767 
       
   768     for (i = 0; i < RT_COM_CNT; i++) {
       
   769         struct rt_com_struct    *p = &(rt_com_table[i]);
       
   770 
       
   771         // if used set default values
       
   772         if (p->used > 0) {
       
   773 	    printk(KERN_WARNING "RS232 testing %d\n",i);
       
   774             if (-EBUSY == check_region(p->port, 8)) {
       
   775                 errorcode = -EBUSY;
       
   776                 printk(KERN_WARNING "rt_com: error %d: cannot request port region %x\n", errorcode, p->port);
       
   777                 break;
       
   778             }
       
   779 
       
   780             request_region(p->port, 8, "rt_com");
       
   781             rt_com_request_irq(p->irq, p->isr);
       
   782 	    printk(KERN_WARNING "RS232 Request IRQ: %d\n",p->irq);
       
   783             rt_com_setup(i, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
       
   784         }
       
   785     }
       
   786 
       
   787     if (0 != errorcode) {
       
   788         printk(KERN_WARNING "rt_com: giving up.\n");
       
   789         for (j = 0; j < i; j++) {
       
   790             struct rt_com_struct    *p = &(rt_com_table[j]);
       
   791             if (0 < p->used) {
       
   792                 rt_com_free_irq(p->irq);
       
   793                 release_region(p->port, 8);
       
   794             }
       
   795         }
       
   796     }
       
   797     else {
       
   798         printk(KERN_INFO "rt_com: sucessfully loaded.\n");
       
   799     }
       
   800 
       
   801     return(errorcode);
       
   802 }
       
   803 
       
   804 /** Cleanup
       
   805  *
       
   806  * Unregister ISR and releases memory for all ports
       
   807  *
       
   808  * @author Jochen Kupper
       
   809  * @version 1999/10/01 */
       
   810 //void cleanup_module(void)  Hm, IgH
       
   811 void cleanup_aip_com(void)
       
   812 {
       
   813     int i;
       
   814     for (i = 0; i < RT_COM_CNT; i++) {
       
   815         struct rt_com_struct    *p = &(rt_com_table[i]);
       
   816         if (0 < p->used) {
       
   817             rt_com_free_irq(p->irq);
       
   818             rt_com_setup(i, 0, 0, 0, 0, 0, 0);
       
   819             release_region(p->port, 8);
       
   820         }
       
   821     }
       
   822 
       
   823     printk(KERN_INFO "rt_com: unloaded.\n");
       
   824 }
       
   825 
       
   826 /*
       
   827 EXPORT_SYMBOL(rt_com_buffersize);
       
   828 EXPORT_SYMBOL(rt_com_clear_input);
       
   829 EXPORT_SYMBOL(rt_com_clear_output);
       
   830 EXPORT_SYMBOL(rt_com_error);
       
   831 EXPORT_SYMBOL(rt_com_hwsetup);
       
   832 EXPORT_SYMBOL(rt_com_read);
       
   833 EXPORT_SYMBOL(rt_com_read_modem);
       
   834 EXPORT_SYMBOL(rt_com_setup);
       
   835 EXPORT_SYMBOL(rt_com_table);
       
   836 EXPORT_SYMBOL(rt_com_write);
       
   837 EXPORT_SYMBOL(rt_com_write_modem);
       
   838 EXPORT_SYMBOL(rt_com_set_mode);
       
   839 EXPORT_SYMBOL(rt_com_set_fifotrig);
       
   840 */
       
   841 
       
   842 /**
       
   843  * Local Variables:
       
   844  * mode: C
       
   845  * c-file-style: "Stroustrup"
       
   846  * End:
       
   847  */