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