root/drivers/staging/isdn/hysdn/hysdn_sched.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hysdn_sched_rx
  2. hysdn_sched_tx
  3. hysdn_tx_cfgline

   1 /* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $
   2  *
   3  * Linux driver for HYSDN cards
   4  * scheduler routines for handling exchange card <-> pc.
   5  *
   6  * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH
   7  * Copyright 1999 by Werner Cornelius (werner@titro.de)
   8  *
   9  * This software may be used and distributed according to the terms
  10  * of the GNU General Public License, incorporated herein by reference.
  11  *
  12  */
  13 
  14 #include <linux/signal.h>
  15 #include <linux/kernel.h>
  16 #include <linux/ioport.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/delay.h>
  19 #include <asm/io.h>
  20 
  21 #include "hysdn_defs.h"
  22 
  23 /*****************************************************************************/
  24 /* hysdn_sched_rx is called from the cards handler to announce new data is   */
  25 /* available from the card. The routine has to handle the data and return    */
  26 /* with a nonzero code if the data could be worked (or even thrown away), if */
  27 /* no room to buffer the data is available a zero return tells the card      */
  28 /* to keep the data until later.                                             */
  29 /*****************************************************************************/
  30 int
  31 hysdn_sched_rx(hysdn_card *card, unsigned char *buf, unsigned short len,
  32                unsigned short chan)
  33 {
  34 
  35         switch (chan) {
  36         case CHAN_NDIS_DATA:
  37                 if (hynet_enable & (1 << card->myid)) {
  38                         /* give packet to network handler */
  39                         hysdn_rx_netpkt(card, buf, len);
  40                 }
  41                 break;
  42 
  43         case CHAN_ERRLOG:
  44                 hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
  45                 if (card->err_log_state == ERRLOG_STATE_ON)
  46                         card->err_log_state = ERRLOG_STATE_START;       /* start new fetch */
  47                 break;
  48 #ifdef CONFIG_HYSDN_CAPI
  49         case CHAN_CAPI:
  50 /* give packet to CAPI handler */
  51                 if (hycapi_enable & (1 << card->myid)) {
  52                         hycapi_rx_capipkt(card, buf, len);
  53                 }
  54                 break;
  55 #endif /* CONFIG_HYSDN_CAPI */
  56         default:
  57                 printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
  58                 break;
  59 
  60         }                       /* switch rx channel */
  61 
  62         return (1);             /* always handled */
  63 }                               /* hysdn_sched_rx */
  64 
  65 /*****************************************************************************/
  66 /* hysdn_sched_tx is called from the cards handler to announce that there is */
  67 /* room in the tx-buffer to the card and data may be sent if needed.         */
  68 /* If the routine wants to send data it must fill buf, len and chan with the */
  69 /* appropriate data and return a nonzero value. With a zero return no new    */
  70 /* data to send is assumed. maxlen specifies the buffer size available for   */
  71 /* sending.                                                                  */
  72 /*****************************************************************************/
  73 int
  74 hysdn_sched_tx(hysdn_card *card, unsigned char *buf,
  75                unsigned short volatile *len, unsigned short volatile *chan,
  76                unsigned short maxlen)
  77 {
  78         struct sk_buff *skb;
  79 
  80         if (card->net_tx_busy) {
  81                 card->net_tx_busy = 0;  /* reset flag */
  82                 hysdn_tx_netack(card);  /* acknowledge packet send */
  83         }                       /* a network packet has completely been transferred */
  84         /* first of all async requests are handled */
  85         if (card->async_busy) {
  86                 if (card->async_len <= maxlen) {
  87                         memcpy(buf, card->async_data, card->async_len);
  88                         *len = card->async_len;
  89                         *chan = card->async_channel;
  90                         card->async_busy = 0;   /* reset request */
  91                         return (1);
  92                 }
  93                 card->async_busy = 0;   /* in case of length error */
  94         }                       /* async request */
  95         if ((card->err_log_state == ERRLOG_STATE_START) &&
  96             (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
  97                 strcpy(buf, ERRLOG_CMD_REQ);    /* copy the command */
  98                 *len = ERRLOG_CMD_REQ_SIZE;     /* buffer length */
  99                 *chan = CHAN_ERRLOG;    /* and channel */
 100                 card->err_log_state = ERRLOG_STATE_ON;  /* new state is on */
 101                 return (1);     /* tell that data should be send */
 102         }                       /* error log start and able to send */
 103         if ((card->err_log_state == ERRLOG_STATE_STOP) &&
 104             (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
 105                 strcpy(buf, ERRLOG_CMD_STOP);   /* copy the command */
 106                 *len = ERRLOG_CMD_STOP_SIZE;    /* buffer length */
 107                 *chan = CHAN_ERRLOG;    /* and channel */
 108                 card->err_log_state = ERRLOG_STATE_OFF;         /* new state is off */
 109                 return (1);     /* tell that data should be send */
 110         }                       /* error log start and able to send */
 111         /* now handle network interface packets */
 112         if ((hynet_enable & (1 << card->myid)) &&
 113             (skb = hysdn_tx_netget(card)) != NULL)
 114         {
 115                 if (skb->len <= maxlen) {
 116                         /* copy the packet to the buffer */
 117                         skb_copy_from_linear_data(skb, buf, skb->len);
 118                         *len = skb->len;
 119                         *chan = CHAN_NDIS_DATA;
 120                         card->net_tx_busy = 1;  /* we are busy sending network data */
 121                         return (1);     /* go and send the data */
 122                 } else
 123                         hysdn_tx_netack(card);  /* aknowledge packet -> throw away */
 124         }                       /* send a network packet if available */
 125 #ifdef CONFIG_HYSDN_CAPI
 126         if (((hycapi_enable & (1 << card->myid))) &&
 127             ((skb = hycapi_tx_capiget(card)) != NULL))
 128         {
 129                 if (skb->len <= maxlen) {
 130                         skb_copy_from_linear_data(skb, buf, skb->len);
 131                         *len = skb->len;
 132                         *chan = CHAN_CAPI;
 133                         hycapi_tx_capiack(card);
 134                         return (1);     /* go and send the data */
 135                 }
 136         }
 137 #endif /* CONFIG_HYSDN_CAPI */
 138         return (0);             /* nothing to send */
 139 }                               /* hysdn_sched_tx */
 140 
 141 
 142 /*****************************************************************************/
 143 /* send one config line to the card and return 0 if successful, otherwise a */
 144 /* negative error code.                                                      */
 145 /* The function works with timeouts perhaps not giving the greatest speed    */
 146 /* sending the line, but this should be meaningless because only some lines  */
 147 /* are to be sent and this happens very seldom.                              */
 148 /*****************************************************************************/
 149 int
 150 hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
 151 {
 152         int cnt = 50;           /* timeout intervalls */
 153         unsigned long flags;
 154 
 155         if (card->debug_flags & LOG_SCHED_ASYN)
 156                 hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
 157 
 158         while (card->async_busy) {
 159 
 160                 if (card->debug_flags & LOG_SCHED_ASYN)
 161                         hysdn_addlog(card, "async tx-cfg delayed");
 162 
 163                 msleep_interruptible(20);               /* Timeout 20ms */
 164                 if (!--cnt)
 165                         return (-ERR_ASYNC_TIME);       /* timed out */
 166         }                       /* wait for buffer to become free */
 167 
 168         spin_lock_irqsave(&card->hysdn_lock, flags);
 169         strcpy(card->async_data, line);
 170         card->async_len = strlen(line) + 1;
 171         card->async_channel = chan;
 172         card->async_busy = 1;   /* request transfer */
 173 
 174         /* now queue the task */
 175         schedule_work(&card->irq_queue);
 176         spin_unlock_irqrestore(&card->hysdn_lock, flags);
 177 
 178         if (card->debug_flags & LOG_SCHED_ASYN)
 179                 hysdn_addlog(card, "async tx-cfg data queued");
 180 
 181         cnt++;                  /* short delay */
 182 
 183         while (card->async_busy) {
 184 
 185                 if (card->debug_flags & LOG_SCHED_ASYN)
 186                         hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
 187 
 188                 msleep_interruptible(20);               /* Timeout 20ms */
 189                 if (!--cnt)
 190                         return (-ERR_ASYNC_TIME);       /* timed out */
 191         }                       /* wait for buffer to become free again */
 192 
 193         if (card->debug_flags & LOG_SCHED_ASYN)
 194                 hysdn_addlog(card, "async tx-cfg data send");
 195 
 196         return (0);             /* line send correctly */
 197 }                               /* hysdn_tx_cfgline */

/* [<][>][^][v][top][bottom][index][help] */