11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux driver for HYSDN cards
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scheduler routines for handling exchange card <-> pc.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 by Werner Cornelius (werner@titro.de)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hysdn_defs.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hysdn_sched_rx is called from the cards handler to announce new data is   */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* available from the card. The routine has to handle the data and return    */
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* with a nonzero code if the data could be worked (or even thrown away), if */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* no room to buffer the data is available a zero return tells the card      */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* to keep the data until later.                                             */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
31c721bccece2b3abca4f7b0b95108e68b78445cecAndrew Mortonhysdn_sched_rx(hysdn_card *card, unsigned char *buf, unsigned short len,
32475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       unsigned short chan)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (chan) {
36475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CHAN_NDIS_DATA:
37475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (hynet_enable & (1 << card->myid)) {
38475be4d85a274d0961593db41cf85689db1d583cJoe Perches			/* give packet to network handler */
39475be4d85a274d0961593db41cf85689db1d583cJoe Perches			hysdn_rx_netpkt(card, buf, len);
40475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
41475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CHAN_ERRLOG:
44475be4d85a274d0961593db41cf85689db1d583cJoe Perches		hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
45475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (card->err_log_state == ERRLOG_STATE_ON)
46475be4d85a274d0961593db41cf85689db1d583cJoe Perches			card->err_log_state = ERRLOG_STATE_START;	/* start new fetch */
47475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HYSDN_CAPI
49475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CHAN_CAPI:
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* give packet to CAPI handler */
51475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (hycapi_enable & (1 << card->myid)) {
52475be4d85a274d0961593db41cf85689db1d583cJoe Perches			hycapi_rx_capipkt(card, buf, len);
53475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
54475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_HYSDN_CAPI */
56475be4d85a274d0961593db41cf85689db1d583cJoe Perches	default:
57475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
58475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* switch rx channel */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (1);		/* always handled */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}				/* hysdn_sched_rx */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hysdn_sched_tx is called from the cards handler to announce that there is */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* room in the tx-buffer to the card and data may be sent if needed.         */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the routine wants to send data it must fill buf, len and chan with the */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* appropriate data and return a nonzero value. With a zero return no new    */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* data to send is assumed. maxlen specifies the buffer size available for   */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sending.                                                                  */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
74c721bccece2b3abca4f7b0b95108e68b78445cecAndrew Mortonhysdn_sched_tx(hysdn_card *card, unsigned char *buf,
75475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       unsigned short volatile *len, unsigned short volatile *chan,
76475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       unsigned short maxlen)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->net_tx_busy) {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->net_tx_busy = 0;	/* reset flag */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hysdn_tx_netack(card);	/* acknowledge packet send */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* a network packet has completely been transferred */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* first of all async requests are handled */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->async_busy) {
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (card->async_len <= maxlen) {
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(buf, card->async_data, card->async_len);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*len = card->async_len;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*chan = card->async_channel;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			card->async_busy = 0;	/* reset request */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (1);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->async_busy = 0;	/* in case of length error */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* async request */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((card->err_log_state == ERRLOG_STATE_START) &&
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(buf, ERRLOG_CMD_REQ);	/* copy the command */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*len = ERRLOG_CMD_REQ_SIZE;	/* buffer length */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*chan = CHAN_ERRLOG;	/* and channel */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->err_log_state = ERRLOG_STATE_ON;	/* new state is on */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (1);	/* tell that data should be send */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* error log start and able to send */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((card->err_log_state == ERRLOG_STATE_STOP) &&
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(buf, ERRLOG_CMD_STOP);	/* copy the command */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*len = ERRLOG_CMD_STOP_SIZE;	/* buffer length */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*chan = CHAN_ERRLOG;	/* and channel */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->err_log_state = ERRLOG_STATE_OFF;		/* new state is off */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (1);	/* tell that data should be send */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* error log start and able to send */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now handle network interface packets */
112475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if ((hynet_enable & (1 << card->myid)) &&
113475be4d85a274d0961593db41cf85689db1d583cJoe Perches	    (skb = hysdn_tx_netget(card)) != NULL)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb->len <= maxlen) {
116d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo			/* copy the packet to the buffer */
117d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo			skb_copy_from_linear_data(skb, buf, skb->len);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*len = skb->len;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*chan = CHAN_NDIS_DATA;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			card->net_tx_busy = 1;	/* we are busy sending network data */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (1);	/* go and send the data */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hysdn_tx_netack(card);	/* aknowledge packet -> throw away */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* send a network packet if available */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HYSDN_CAPI
126475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (((hycapi_enable & (1 << card->myid))) &&
127475be4d85a274d0961593db41cf85689db1d583cJoe Perches	    ((skb = hycapi_tx_capiget(card)) != NULL))
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb->len <= maxlen) {
130d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo			skb_copy_from_linear_data(skb, buf, skb->len);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*len = skb->len;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*chan = CHAN_CAPI;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hycapi_tx_capiack(card);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (1);	/* go and send the data */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_HYSDN_CAPI */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);		/* nothing to send */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}				/* hysdn_sched_tx */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* send one config line to the card and return 0 if successful, otherwise a */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* negative error code.                                                      */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The function works with timeouts perhaps not giving the greatest speed    */
14625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* sending the line, but this should be meaningless because only some lines  */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* are to be sent and this happens very seldom.                              */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
150c721bccece2b3abca4f7b0b95108e68b78445cecAndrew Mortonhysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cnt = 50;		/* timeout intervalls */
153c721bccece2b3abca4f7b0b95108e68b78445cecAndrew Morton	unsigned long flags;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->debug_flags & LOG_SCHED_ASYN)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (card->async_busy) {
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (card->debug_flags & LOG_SCHED_ASYN)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hysdn_addlog(card, "async tx-cfg delayed");
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep_interruptible(20);		/* Timeout 20ms */
1641f604c4bc078213aa1c4576efa0e8dad98522fa7Amol Lad		if (!--cnt)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-ERR_ASYNC_TIME);	/* timed out */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* wait for buffer to become free */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681f604c4bc078213aa1c4576efa0e8dad98522fa7Amol Lad	spin_lock_irqsave(&card->hysdn_lock, flags);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(card->async_data, line);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->async_len = strlen(line) + 1;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->async_channel = chan;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->async_busy = 1;	/* request transfer */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now queue the task */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	schedule_work(&card->irq_queue);
1761f604c4bc078213aa1c4576efa0e8dad98522fa7Amol Lad	spin_unlock_irqrestore(&card->hysdn_lock, flags);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->debug_flags & LOG_SCHED_ASYN)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hysdn_addlog(card, "async tx-cfg data queued");
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cnt++;			/* short delay */
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (card->async_busy) {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (card->debug_flags & LOG_SCHED_ASYN)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep_interruptible(20);		/* Timeout 20ms */
1891f604c4bc078213aa1c4576efa0e8dad98522fa7Amol Lad		if (!--cnt)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (-ERR_ASYNC_TIME);	/* timed out */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* wait for buffer to become free again */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->debug_flags & LOG_SCHED_ASYN)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hysdn_addlog(card, "async tx-cfg data send");
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);		/* line send correctly */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}				/* hysdn_tx_cfgline */
198