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