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