Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 */ |