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