diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/ip2/i2lib.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/ip2/i2lib.c')
-rw-r--r-- | drivers/char/ip2/i2lib.c | 2219 |
1 files changed, 2219 insertions, 0 deletions
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c new file mode 100644 index 000000000000..82c5f30375ac --- /dev/null +++ b/drivers/char/ip2/i2lib.c | |||
@@ -0,0 +1,2219 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * (c) 1999 by Computone Corporation | ||
4 | * | ||
5 | ******************************************************************************** | ||
6 | * | ||
7 | * | ||
8 | * PACKAGE: Linux tty Device Driver for IntelliPort family of multiport | ||
9 | * serial I/O controllers. | ||
10 | * | ||
11 | * DESCRIPTION: High-level interface code for the device driver. Uses the | ||
12 | * Extremely Low Level Interface Support (i2ellis.c). Provides an | ||
13 | * interface to the standard loadware, to support drivers or | ||
14 | * application code. (This is included source code, not a separate | ||
15 | * compilation module.) | ||
16 | * | ||
17 | *******************************************************************************/ | ||
18 | //------------------------------------------------------------------------------ | ||
19 | // Note on Strategy: | ||
20 | // Once the board has been initialized, it will interrupt us when: | ||
21 | // 1) It has something in the fifo for us to read (incoming data, flow control | ||
22 | // packets, or whatever). | ||
23 | // 2) It has stripped whatever we have sent last time in the FIFO (and | ||
24 | // consequently is ready for more). | ||
25 | // | ||
26 | // Note also that the buffer sizes declared in i2lib.h are VERY SMALL. This | ||
27 | // worsens performance considerably, but is done so that a great many channels | ||
28 | // might use only a little memory. | ||
29 | //------------------------------------------------------------------------------ | ||
30 | |||
31 | //------------------------------------------------------------------------------ | ||
32 | // Revision History: | ||
33 | // | ||
34 | // 0.00 - 4/16/91 --- First Draft | ||
35 | // 0.01 - 4/29/91 --- 1st beta release | ||
36 | // 0.02 - 6/14/91 --- Changes to allow small model compilation | ||
37 | // 0.03 - 6/17/91 MAG Break reporting protected from interrupts routines with | ||
38 | // in-line asm added for moving data to/from ring buffers, | ||
39 | // replacing a variety of methods used previously. | ||
40 | // 0.04 - 6/21/91 MAG Initial flow-control packets not queued until | ||
41 | // i2_enable_interrupts time. Former versions would enqueue | ||
42 | // them at i2_init_channel time, before we knew how many | ||
43 | // channels were supposed to exist! | ||
44 | // 0.05 - 10/12/91 MAG Major changes: works through the ellis.c routines now; | ||
45 | // supports new 16-bit protocol and expandable boards. | ||
46 | // - 10/24/91 MAG Most changes in place and stable. | ||
47 | // 0.06 - 2/20/92 MAG Format of CMD_HOTACK corrected: the command takes no | ||
48 | // argument. | ||
49 | // 0.07 -- 3/11/92 MAG Support added to store special packet types at interrupt | ||
50 | // level (mostly responses to specific commands.) | ||
51 | // 0.08 -- 3/30/92 MAG Support added for STAT_MODEM packet | ||
52 | // 0.09 -- 6/24/93 MAG i2Link... needed to update number of boards BEFORE | ||
53 | // turning on the interrupt. | ||
54 | // 0.10 -- 6/25/93 MAG To avoid gruesome death from a bad board, we sanity check | ||
55 | // some incoming. | ||
56 | // | ||
57 | // 1.1 - 12/25/96 AKM Linux version. | ||
58 | // - 10/09/98 DMC Revised Linux version. | ||
59 | //------------------------------------------------------------------------------ | ||
60 | |||
61 | //************ | ||
62 | //* Includes * | ||
63 | //************ | ||
64 | |||
65 | #include <linux/sched.h> | ||
66 | #include "i2lib.h" | ||
67 | |||
68 | |||
69 | //*********************** | ||
70 | //* Function Prototypes * | ||
71 | //*********************** | ||
72 | static void i2QueueNeeds(i2eBordStrPtr, i2ChanStrPtr, int); | ||
73 | static i2ChanStrPtr i2DeQueueNeeds(i2eBordStrPtr, int ); | ||
74 | static void i2StripFifo(i2eBordStrPtr); | ||
75 | static void i2StuffFifoBypass(i2eBordStrPtr); | ||
76 | static void i2StuffFifoFlow(i2eBordStrPtr); | ||
77 | static void i2StuffFifoInline(i2eBordStrPtr); | ||
78 | static int i2RetryFlushOutput(i2ChanStrPtr); | ||
79 | |||
80 | // Not a documented part of the library routines (careful...) but the Diagnostic | ||
81 | // i2diag.c finds them useful to help the throughput in certain limited | ||
82 | // single-threaded operations. | ||
83 | static void iiSendPendingMail(i2eBordStrPtr); | ||
84 | static void serviceOutgoingFifo(i2eBordStrPtr); | ||
85 | |||
86 | // Functions defined in ip2.c as part of interrupt handling | ||
87 | static void do_input(void *); | ||
88 | static void do_status(void *); | ||
89 | |||
90 | //*************** | ||
91 | //* Debug Data * | ||
92 | //*************** | ||
93 | #ifdef DEBUG_FIFO | ||
94 | |||
95 | unsigned char DBGBuf[0x4000]; | ||
96 | unsigned short I = 0; | ||
97 | |||
98 | static void | ||
99 | WriteDBGBuf(char *s, unsigned char *src, unsigned short n ) | ||
100 | { | ||
101 | char *p = src; | ||
102 | |||
103 | // XXX: We need a spin lock here if we ever use this again | ||
104 | |||
105 | while (*s) { // copy label | ||
106 | DBGBuf[I] = *s++; | ||
107 | I = I++ & 0x3fff; | ||
108 | } | ||
109 | while (n--) { // copy data | ||
110 | DBGBuf[I] = *p++; | ||
111 | I = I++ & 0x3fff; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void | ||
116 | fatality(i2eBordStrPtr pB ) | ||
117 | { | ||
118 | int i; | ||
119 | |||
120 | for (i=0;i<sizeof(DBGBuf);i++) { | ||
121 | if ((i%16) == 0) | ||
122 | printk("\n%4x:",i); | ||
123 | printk("%02x ",DBGBuf[i]); | ||
124 | } | ||
125 | printk("\n"); | ||
126 | for (i=0;i<sizeof(DBGBuf);i++) { | ||
127 | if ((i%16) == 0) | ||
128 | printk("\n%4x:",i); | ||
129 | if (DBGBuf[i] >= ' ' && DBGBuf[i] <= '~') { | ||
130 | printk(" %c ",DBGBuf[i]); | ||
131 | } else { | ||
132 | printk(" . "); | ||
133 | } | ||
134 | } | ||
135 | printk("\n"); | ||
136 | printk("Last index %x\n",I); | ||
137 | } | ||
138 | #endif /* DEBUG_FIFO */ | ||
139 | |||
140 | //******** | ||
141 | //* Code * | ||
142 | //******** | ||
143 | |||
144 | static inline int | ||
145 | i2Validate ( i2ChanStrPtr pCh ) | ||
146 | { | ||
147 | //ip2trace(pCh->port_index, ITRC_VERIFY,ITRC_ENTER,2,pCh->validity, | ||
148 | // (CHANNEL_MAGIC | CHANNEL_SUPPORT)); | ||
149 | return ((pCh->validity & (CHANNEL_MAGIC_BITS | CHANNEL_SUPPORT)) | ||
150 | == (CHANNEL_MAGIC | CHANNEL_SUPPORT)); | ||
151 | } | ||
152 | |||
153 | //****************************************************************************** | ||
154 | // Function: iiSendPendingMail(pB) | ||
155 | // Parameters: Pointer to a board structure | ||
156 | // Returns: Nothing | ||
157 | // | ||
158 | // Description: | ||
159 | // If any outgoing mail bits are set and there is outgoing mailbox is empty, | ||
160 | // send the mail and clear the bits. | ||
161 | //****************************************************************************** | ||
162 | static inline void | ||
163 | iiSendPendingMail(i2eBordStrPtr pB) | ||
164 | { | ||
165 | if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) ) | ||
166 | { | ||
167 | if (iiTrySendMail(pB, pB->i2eOutMailWaiting)) | ||
168 | { | ||
169 | /* If we were already waiting for fifo to empty, | ||
170 | * or just sent MB_OUT_STUFFED, then we are | ||
171 | * still waiting for it to empty, until we should | ||
172 | * receive an MB_IN_STRIPPED from the board. | ||
173 | */ | ||
174 | pB->i2eWaitingForEmptyFifo |= | ||
175 | (pB->i2eOutMailWaiting & MB_OUT_STUFFED); | ||
176 | pB->i2eOutMailWaiting = 0; | ||
177 | pB->SendPendingRetry = 0; | ||
178 | } else { | ||
179 | /* The only time we hit this area is when "iiTrySendMail" has | ||
180 | failed. That only occurs when the outbound mailbox is | ||
181 | still busy with the last message. We take a short breather | ||
182 | to let the board catch up with itself and then try again. | ||
183 | 16 Retries is the limit - then we got a borked board. | ||
184 | /\/\|=mhw=|\/\/ */ | ||
185 | |||
186 | if( ++pB->SendPendingRetry < 16 ) { | ||
187 | |||
188 | init_timer( &(pB->SendPendingTimer) ); | ||
189 | pB->SendPendingTimer.expires = jiffies + 1; | ||
190 | pB->SendPendingTimer.function = (void*)(unsigned long)iiSendPendingMail; | ||
191 | pB->SendPendingTimer.data = (unsigned long)pB; | ||
192 | add_timer( &(pB->SendPendingTimer) ); | ||
193 | } else { | ||
194 | printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" ); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | //****************************************************************************** | ||
201 | // Function: i2InitChannels(pB, nChannels, pCh) | ||
202 | // Parameters: Pointer to Ellis Board structure | ||
203 | // Number of channels to initialize | ||
204 | // Pointer to first element in an array of channel structures | ||
205 | // Returns: Success or failure | ||
206 | // | ||
207 | // Description: | ||
208 | // | ||
209 | // This function patches pointers, back-pointers, and initializes all the | ||
210 | // elements in the channel structure array. | ||
211 | // | ||
212 | // This should be run after the board structure is initialized, through having | ||
213 | // loaded the standard loadware (otherwise it complains). | ||
214 | // | ||
215 | // In any case, it must be done before any serious work begins initializing the | ||
216 | // irq's or sending commands... | ||
217 | // | ||
218 | //****************************************************************************** | ||
219 | static int | ||
220 | i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) | ||
221 | { | ||
222 | int index, stuffIndex; | ||
223 | i2ChanStrPtr *ppCh; | ||
224 | |||
225 | if (pB->i2eValid != I2E_MAGIC) { | ||
226 | COMPLETE(pB, I2EE_BADMAGIC); | ||
227 | } | ||
228 | if (pB->i2eState != II_STATE_STDLOADED) { | ||
229 | COMPLETE(pB, I2EE_BADSTATE); | ||
230 | } | ||
231 | |||
232 | LOCK_INIT(&pB->read_fifo_spinlock); | ||
233 | LOCK_INIT(&pB->write_fifo_spinlock); | ||
234 | LOCK_INIT(&pB->Dbuf_spinlock); | ||
235 | LOCK_INIT(&pB->Bbuf_spinlock); | ||
236 | LOCK_INIT(&pB->Fbuf_spinlock); | ||
237 | |||
238 | // NO LOCK needed yet - this is init | ||
239 | |||
240 | pB->i2eChannelPtr = pCh; | ||
241 | pB->i2eChannelCnt = nChannels; | ||
242 | |||
243 | pB->i2Fbuf_strip = pB->i2Fbuf_stuff = 0; | ||
244 | pB->i2Dbuf_strip = pB->i2Dbuf_stuff = 0; | ||
245 | pB->i2Bbuf_strip = pB->i2Bbuf_stuff = 0; | ||
246 | |||
247 | pB->SendPendingRetry = 0; | ||
248 | |||
249 | memset ( pCh, 0, sizeof (i2ChanStr) * nChannels ); | ||
250 | |||
251 | for (index = stuffIndex = 0, ppCh = (i2ChanStrPtr *)(pB->i2Fbuf); | ||
252 | nChannels && index < ABS_MOST_PORTS; | ||
253 | index++) | ||
254 | { | ||
255 | if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) { | ||
256 | continue; | ||
257 | } | ||
258 | LOCK_INIT(&pCh->Ibuf_spinlock); | ||
259 | LOCK_INIT(&pCh->Obuf_spinlock); | ||
260 | LOCK_INIT(&pCh->Cbuf_spinlock); | ||
261 | LOCK_INIT(&pCh->Pbuf_spinlock); | ||
262 | // NO LOCK needed yet - this is init | ||
263 | // Set up validity flag according to support level | ||
264 | if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) { | ||
265 | pCh->validity = CHANNEL_MAGIC | CHANNEL_SUPPORT; | ||
266 | } else { | ||
267 | pCh->validity = CHANNEL_MAGIC; | ||
268 | } | ||
269 | pCh->pMyBord = pB; /* Back-pointer */ | ||
270 | |||
271 | // Prepare an outgoing flow-control packet to send as soon as the chance | ||
272 | // occurs. | ||
273 | if ( pCh->validity & CHANNEL_SUPPORT ) { | ||
274 | pCh->infl.hd.i2sChannel = index; | ||
275 | pCh->infl.hd.i2sCount = 5; | ||
276 | pCh->infl.hd.i2sType = PTYPE_BYPASS; | ||
277 | pCh->infl.fcmd = 37; | ||
278 | pCh->infl.asof = 0; | ||
279 | pCh->infl.room = IBUF_SIZE - 1; | ||
280 | |||
281 | pCh->whenSendFlow = (IBUF_SIZE/5)*4; // when 80% full | ||
282 | |||
283 | // The following is similar to calling i2QueueNeeds, except that this | ||
284 | // is done in longhand, since we are setting up initial conditions on | ||
285 | // many channels at once. | ||
286 | pCh->channelNeeds = NEED_FLOW; // Since starting from scratch | ||
287 | pCh->sinceLastFlow = 0; // No bytes received since last flow | ||
288 | // control packet was queued | ||
289 | stuffIndex++; | ||
290 | *ppCh++ = pCh; // List this channel as needing | ||
291 | // initial flow control packet sent | ||
292 | } | ||
293 | |||
294 | // Don't allow anything to be sent until the status packets come in from | ||
295 | // the board. | ||
296 | |||
297 | pCh->outfl.asof = 0; | ||
298 | pCh->outfl.room = 0; | ||
299 | |||
300 | // Initialize all the ring buffers | ||
301 | |||
302 | pCh->Ibuf_stuff = pCh->Ibuf_strip = 0; | ||
303 | pCh->Obuf_stuff = pCh->Obuf_strip = 0; | ||
304 | pCh->Cbuf_stuff = pCh->Cbuf_strip = 0; | ||
305 | |||
306 | memset( &pCh->icount, 0, sizeof (struct async_icount) ); | ||
307 | pCh->hotKeyIn = HOT_CLEAR; | ||
308 | pCh->channelOptions = 0; | ||
309 | pCh->bookMarks = 0; | ||
310 | init_waitqueue_head(&pCh->pBookmarkWait); | ||
311 | |||
312 | init_waitqueue_head(&pCh->open_wait); | ||
313 | init_waitqueue_head(&pCh->close_wait); | ||
314 | init_waitqueue_head(&pCh->delta_msr_wait); | ||
315 | |||
316 | // Set base and divisor so default custom rate is 9600 | ||
317 | pCh->BaudBase = 921600; // MAX for ST654, changed after we get | ||
318 | pCh->BaudDivisor = 96; // the boxids (UART types) later | ||
319 | |||
320 | pCh->dataSetIn = 0; | ||
321 | pCh->dataSetOut = 0; | ||
322 | |||
323 | pCh->wopen = 0; | ||
324 | pCh->throttled = 0; | ||
325 | |||
326 | pCh->speed = CBR_9600; | ||
327 | |||
328 | pCh->flags = 0; | ||
329 | |||
330 | pCh->ClosingDelay = 5*HZ/10; | ||
331 | pCh->ClosingWaitTime = 30*HZ; | ||
332 | |||
333 | // Initialize task queue objects | ||
334 | INIT_WORK(&pCh->tqueue_input, do_input, pCh); | ||
335 | INIT_WORK(&pCh->tqueue_status, do_status, pCh); | ||
336 | |||
337 | #ifdef IP2DEBUG_TRACE | ||
338 | pCh->trace = ip2trace; | ||
339 | #endif | ||
340 | |||
341 | ++pCh; | ||
342 | --nChannels; | ||
343 | } | ||
344 | // No need to check for wrap here; this is initialization. | ||
345 | pB->i2Fbuf_stuff = stuffIndex; | ||
346 | COMPLETE(pB, I2EE_GOOD); | ||
347 | |||
348 | } | ||
349 | |||
350 | //****************************************************************************** | ||
351 | // Function: i2DeQueueNeeds(pB, type) | ||
352 | // Parameters: Pointer to a board structure | ||
353 | // type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW | ||
354 | // Returns: | ||
355 | // Pointer to a channel structure | ||
356 | // | ||
357 | // Description: Returns pointer struct of next channel that needs service of | ||
358 | // the type specified. Otherwise returns a NULL reference. | ||
359 | // | ||
360 | //****************************************************************************** | ||
361 | static i2ChanStrPtr | ||
362 | i2DeQueueNeeds(i2eBordStrPtr pB, int type) | ||
363 | { | ||
364 | unsigned short queueIndex; | ||
365 | unsigned long flags; | ||
366 | |||
367 | i2ChanStrPtr pCh = NULL; | ||
368 | |||
369 | switch(type) { | ||
370 | |||
371 | case NEED_INLINE: | ||
372 | |||
373 | WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); | ||
374 | if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip) | ||
375 | { | ||
376 | queueIndex = pB->i2Dbuf_strip; | ||
377 | pCh = pB->i2Dbuf[queueIndex]; | ||
378 | queueIndex++; | ||
379 | if (queueIndex >= CH_QUEUE_SIZE) { | ||
380 | queueIndex = 0; | ||
381 | } | ||
382 | pB->i2Dbuf_strip = queueIndex; | ||
383 | pCh->channelNeeds &= ~NEED_INLINE; | ||
384 | } | ||
385 | WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); | ||
386 | break; | ||
387 | |||
388 | case NEED_BYPASS: | ||
389 | |||
390 | WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); | ||
391 | if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip) | ||
392 | { | ||
393 | queueIndex = pB->i2Bbuf_strip; | ||
394 | pCh = pB->i2Bbuf[queueIndex]; | ||
395 | queueIndex++; | ||
396 | if (queueIndex >= CH_QUEUE_SIZE) { | ||
397 | queueIndex = 0; | ||
398 | } | ||
399 | pB->i2Bbuf_strip = queueIndex; | ||
400 | pCh->channelNeeds &= ~NEED_BYPASS; | ||
401 | } | ||
402 | WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); | ||
403 | break; | ||
404 | |||
405 | case NEED_FLOW: | ||
406 | |||
407 | WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); | ||
408 | if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip) | ||
409 | { | ||
410 | queueIndex = pB->i2Fbuf_strip; | ||
411 | pCh = pB->i2Fbuf[queueIndex]; | ||
412 | queueIndex++; | ||
413 | if (queueIndex >= CH_QUEUE_SIZE) { | ||
414 | queueIndex = 0; | ||
415 | } | ||
416 | pB->i2Fbuf_strip = queueIndex; | ||
417 | pCh->channelNeeds &= ~NEED_FLOW; | ||
418 | } | ||
419 | WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); | ||
420 | break; | ||
421 | default: | ||
422 | printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type); | ||
423 | break; | ||
424 | } | ||
425 | return pCh; | ||
426 | } | ||
427 | |||
428 | //****************************************************************************** | ||
429 | // Function: i2QueueNeeds(pB, pCh, type) | ||
430 | // Parameters: Pointer to a board structure | ||
431 | // Pointer to a channel structure | ||
432 | // type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW | ||
433 | // Returns: Nothing | ||
434 | // | ||
435 | // Description: | ||
436 | // For each type of need selected, if the given channel is not already in the | ||
437 | // queue, adds it, and sets the flag indicating it is in the queue. | ||
438 | //****************************************************************************** | ||
439 | static void | ||
440 | i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) | ||
441 | { | ||
442 | unsigned short queueIndex; | ||
443 | unsigned long flags; | ||
444 | |||
445 | // We turn off all the interrupts during this brief process, since the | ||
446 | // interrupt-level code might want to put things on the queue as well. | ||
447 | |||
448 | switch (type) { | ||
449 | |||
450 | case NEED_INLINE: | ||
451 | |||
452 | WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); | ||
453 | if ( !(pCh->channelNeeds & NEED_INLINE) ) | ||
454 | { | ||
455 | pCh->channelNeeds |= NEED_INLINE; | ||
456 | queueIndex = pB->i2Dbuf_stuff; | ||
457 | pB->i2Dbuf[queueIndex++] = pCh; | ||
458 | if (queueIndex >= CH_QUEUE_SIZE) | ||
459 | queueIndex = 0; | ||
460 | pB->i2Dbuf_stuff = queueIndex; | ||
461 | } | ||
462 | WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); | ||
463 | break; | ||
464 | |||
465 | case NEED_BYPASS: | ||
466 | |||
467 | WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); | ||
468 | if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS)) | ||
469 | { | ||
470 | pCh->channelNeeds |= NEED_BYPASS; | ||
471 | queueIndex = pB->i2Bbuf_stuff; | ||
472 | pB->i2Bbuf[queueIndex++] = pCh; | ||
473 | if (queueIndex >= CH_QUEUE_SIZE) | ||
474 | queueIndex = 0; | ||
475 | pB->i2Bbuf_stuff = queueIndex; | ||
476 | } | ||
477 | WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); | ||
478 | break; | ||
479 | |||
480 | case NEED_FLOW: | ||
481 | |||
482 | WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); | ||
483 | if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW)) | ||
484 | { | ||
485 | pCh->channelNeeds |= NEED_FLOW; | ||
486 | queueIndex = pB->i2Fbuf_stuff; | ||
487 | pB->i2Fbuf[queueIndex++] = pCh; | ||
488 | if (queueIndex >= CH_QUEUE_SIZE) | ||
489 | queueIndex = 0; | ||
490 | pB->i2Fbuf_stuff = queueIndex; | ||
491 | } | ||
492 | WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); | ||
493 | break; | ||
494 | |||
495 | case NEED_CREDIT: | ||
496 | pCh->channelNeeds |= NEED_CREDIT; | ||
497 | break; | ||
498 | default: | ||
499 | printk(KERN_ERR "i2QueueNeeds called with bad type:%x\n",type); | ||
500 | break; | ||
501 | } | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | //****************************************************************************** | ||
506 | // Function: i2QueueCommands(type, pCh, timeout, nCommands, pCs,...) | ||
507 | // Parameters: type - PTYPE_BYPASS or PTYPE_INLINE | ||
508 | // pointer to the channel structure | ||
509 | // maximum period to wait | ||
510 | // number of commands (n) | ||
511 | // n commands | ||
512 | // Returns: Number of commands sent, or -1 for error | ||
513 | // | ||
514 | // get board lock before calling | ||
515 | // | ||
516 | // Description: | ||
517 | // Queues up some commands to be sent to a channel. To send possibly several | ||
518 | // bypass or inline commands to the given channel. The timeout parameter | ||
519 | // indicates how many HUNDREDTHS OF SECONDS to wait until there is room: | ||
520 | // 0 = return immediately if no room, -ive = wait forever, +ive = number of | ||
521 | // 1/100 seconds to wait. Return values: | ||
522 | // -1 Some kind of nasty error: bad channel structure or invalid arguments. | ||
523 | // 0 No room to send all the commands | ||
524 | // (+) Number of commands sent | ||
525 | //****************************************************************************** | ||
526 | static int | ||
527 | i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, | ||
528 | cmdSyntaxPtr pCs0,...) | ||
529 | { | ||
530 | int totalsize = 0; | ||
531 | int blocksize; | ||
532 | int lastended; | ||
533 | cmdSyntaxPtr *ppCs; | ||
534 | cmdSyntaxPtr pCs; | ||
535 | int count; | ||
536 | int flag; | ||
537 | i2eBordStrPtr pB; | ||
538 | |||
539 | unsigned short maxBlock; | ||
540 | unsigned short maxBuff; | ||
541 | short bufroom; | ||
542 | unsigned short stuffIndex; | ||
543 | unsigned char *pBuf; | ||
544 | unsigned char *pInsert; | ||
545 | unsigned char *pDest, *pSource; | ||
546 | unsigned short channel; | ||
547 | int cnt; | ||
548 | unsigned long flags = 0; | ||
549 | rwlock_t *lock_var_p = NULL; | ||
550 | |||
551 | // Make sure the channel exists, otherwise do nothing | ||
552 | if ( !i2Validate ( pCh ) ) { | ||
553 | return -1; | ||
554 | } | ||
555 | |||
556 | ip2trace (CHANN, ITRC_QUEUE, ITRC_ENTER, 0 ); | ||
557 | |||
558 | pB = pCh->pMyBord; | ||
559 | |||
560 | // Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT | ||
561 | if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) { | ||
562 | return -2; | ||
563 | } | ||
564 | // If the board has gone fatal, return bad, and also hit the trap routine if | ||
565 | // it exists. | ||
566 | if (pB->i2eFatal) { | ||
567 | if ( pB->i2eFatalTrap ) { | ||
568 | (*(pB)->i2eFatalTrap)(pB); | ||
569 | } | ||
570 | return -3; | ||
571 | } | ||
572 | // Set up some variables, Which buffers are we using? How big are they? | ||
573 | switch(type) | ||
574 | { | ||
575 | case PTYPE_INLINE: | ||
576 | flag = INL; | ||
577 | maxBlock = MAX_OBUF_BLOCK; | ||
578 | maxBuff = OBUF_SIZE; | ||
579 | pBuf = pCh->Obuf; | ||
580 | break; | ||
581 | case PTYPE_BYPASS: | ||
582 | flag = BYP; | ||
583 | maxBlock = MAX_CBUF_BLOCK; | ||
584 | maxBuff = CBUF_SIZE; | ||
585 | pBuf = pCh->Cbuf; | ||
586 | break; | ||
587 | default: | ||
588 | return -4; | ||
589 | } | ||
590 | // Determine the total size required for all the commands | ||
591 | totalsize = blocksize = sizeof(i2CmdHeader); | ||
592 | lastended = 0; | ||
593 | ppCs = &pCs0; | ||
594 | for ( count = nCommands; count; count--, ppCs++) | ||
595 | { | ||
596 | pCs = *ppCs; | ||
597 | cnt = pCs->length; | ||
598 | // Will a new block be needed for this one? | ||
599 | // Two possible reasons: too | ||
600 | // big or previous command has to be at the end of a packet. | ||
601 | if ((blocksize + cnt > maxBlock) || lastended) { | ||
602 | blocksize = sizeof(i2CmdHeader); | ||
603 | totalsize += sizeof(i2CmdHeader); | ||
604 | } | ||
605 | totalsize += cnt; | ||
606 | blocksize += cnt; | ||
607 | |||
608 | // If this command had to end a block, then we will make sure to | ||
609 | // account for it should there be any more blocks. | ||
610 | lastended = pCs->flags & END; | ||
611 | } | ||
612 | for (;;) { | ||
613 | // Make sure any pending flush commands go out before we add more data. | ||
614 | if ( !( pCh->flush_flags && i2RetryFlushOutput( pCh ) ) ) { | ||
615 | // How much room (this time through) ? | ||
616 | switch(type) { | ||
617 | case PTYPE_INLINE: | ||
618 | lock_var_p = &pCh->Obuf_spinlock; | ||
619 | WRITE_LOCK_IRQSAVE(lock_var_p,flags); | ||
620 | stuffIndex = pCh->Obuf_stuff; | ||
621 | bufroom = pCh->Obuf_strip - stuffIndex; | ||
622 | break; | ||
623 | case PTYPE_BYPASS: | ||
624 | lock_var_p = &pCh->Cbuf_spinlock; | ||
625 | WRITE_LOCK_IRQSAVE(lock_var_p,flags); | ||
626 | stuffIndex = pCh->Cbuf_stuff; | ||
627 | bufroom = pCh->Cbuf_strip - stuffIndex; | ||
628 | break; | ||
629 | default: | ||
630 | return -5; | ||
631 | } | ||
632 | if (--bufroom < 0) { | ||
633 | bufroom += maxBuff; | ||
634 | } | ||
635 | |||
636 | ip2trace (CHANN, ITRC_QUEUE, 2, 1, bufroom ); | ||
637 | |||
638 | // Check for overflow | ||
639 | if (totalsize <= bufroom) { | ||
640 | // Normal Expected path - We still hold LOCK | ||
641 | break; /* from for()- Enough room: goto proceed */ | ||
642 | } | ||
643 | } | ||
644 | |||
645 | ip2trace (CHANN, ITRC_QUEUE, 3, 1, totalsize ); | ||
646 | |||
647 | // Prepare to wait for buffers to empty | ||
648 | WRITE_UNLOCK_IRQRESTORE(lock_var_p,flags); | ||
649 | serviceOutgoingFifo(pB); // Dump what we got | ||
650 | |||
651 | if (timeout == 0) { | ||
652 | return 0; // Tired of waiting | ||
653 | } | ||
654 | if (timeout > 0) | ||
655 | timeout--; // So negative values == forever | ||
656 | |||
657 | if (!in_interrupt()) { | ||
658 | current->state = TASK_INTERRUPTIBLE; | ||
659 | schedule_timeout(1); // short nap | ||
660 | } else { | ||
661 | // we cannot sched/sleep in interrrupt silly | ||
662 | return 0; | ||
663 | } | ||
664 | if (signal_pending(current)) { | ||
665 | return 0; // Wake up! Time to die!!! | ||
666 | } | ||
667 | |||
668 | ip2trace (CHANN, ITRC_QUEUE, 4, 0 ); | ||
669 | |||
670 | } // end of for(;;) | ||
671 | |||
672 | // At this point we have room and the lock - stick them in. | ||
673 | channel = pCh->infl.hd.i2sChannel; | ||
674 | pInsert = &pBuf[stuffIndex]; // Pointer to start of packet | ||
675 | pDest = CMD_OF(pInsert); // Pointer to start of command | ||
676 | |||
677 | // When we start counting, the block is the size of the header | ||
678 | for (blocksize = sizeof(i2CmdHeader), count = nCommands, | ||
679 | lastended = 0, ppCs = &pCs0; | ||
680 | count; | ||
681 | count--, ppCs++) | ||
682 | { | ||
683 | pCs = *ppCs; // Points to command protocol structure | ||
684 | |||
685 | // If this is a bookmark request command, post the fact that a bookmark | ||
686 | // request is pending. NOTE THIS TRICK ONLY WORKS BECAUSE CMD_BMARK_REQ | ||
687 | // has no parameters! The more general solution would be to reference | ||
688 | // pCs->cmd[0]. | ||
689 | if (pCs == CMD_BMARK_REQ) { | ||
690 | pCh->bookMarks++; | ||
691 | |||
692 | ip2trace (CHANN, ITRC_DRAIN, 30, 1, pCh->bookMarks ); | ||
693 | |||
694 | } | ||
695 | cnt = pCs->length; | ||
696 | |||
697 | // If this command would put us over the maximum block size or | ||
698 | // if the last command had to be at the end of a block, we end | ||
699 | // the existing block here and start a new one. | ||
700 | if ((blocksize + cnt > maxBlock) || lastended) { | ||
701 | |||
702 | ip2trace (CHANN, ITRC_QUEUE, 5, 0 ); | ||
703 | |||
704 | PTYPE_OF(pInsert) = type; | ||
705 | CHANNEL_OF(pInsert) = channel; | ||
706 | // count here does not include the header | ||
707 | CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader); | ||
708 | stuffIndex += blocksize; | ||
709 | if(stuffIndex >= maxBuff) { | ||
710 | stuffIndex = 0; | ||
711 | pInsert = pBuf; | ||
712 | } | ||
713 | pInsert = &pBuf[stuffIndex]; // Pointer to start of next pkt | ||
714 | pDest = CMD_OF(pInsert); | ||
715 | blocksize = sizeof(i2CmdHeader); | ||
716 | } | ||
717 | // Now we know there is room for this one in the current block | ||
718 | |||
719 | blocksize += cnt; // Total bytes in this command | ||
720 | pSource = pCs->cmd; // Copy the command into the buffer | ||
721 | while (cnt--) { | ||
722 | *pDest++ = *pSource++; | ||
723 | } | ||
724 | // If this command had to end a block, then we will make sure to account | ||
725 | // for it should there be any more blocks. | ||
726 | lastended = pCs->flags & END; | ||
727 | } // end for | ||
728 | // Clean up the final block by writing header, etc | ||
729 | |||
730 | PTYPE_OF(pInsert) = type; | ||
731 | CHANNEL_OF(pInsert) = channel; | ||
732 | // count here does not include the header | ||
733 | CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader); | ||
734 | stuffIndex += blocksize; | ||
735 | if(stuffIndex >= maxBuff) { | ||
736 | stuffIndex = 0; | ||
737 | pInsert = pBuf; | ||
738 | } | ||
739 | // Updates the index, and post the need for service. When adding these to | ||
740 | // the queue of channels, we turn off the interrupt while doing so, | ||
741 | // because at interrupt level we might want to push a channel back to the | ||
742 | // end of the queue. | ||
743 | switch(type) | ||
744 | { | ||
745 | case PTYPE_INLINE: | ||
746 | pCh->Obuf_stuff = stuffIndex; // Store buffer pointer | ||
747 | WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); | ||
748 | |||
749 | pB->debugInlineQueued++; | ||
750 | // Add the channel pointer to list of channels needing service (first | ||
751 | // come...), if it's not already there. | ||
752 | i2QueueNeeds(pB, pCh, NEED_INLINE); | ||
753 | break; | ||
754 | |||
755 | case PTYPE_BYPASS: | ||
756 | pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer | ||
757 | WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); | ||
758 | |||
759 | pB->debugBypassQueued++; | ||
760 | // Add the channel pointer to list of channels needing service (first | ||
761 | // come...), if it's not already there. | ||
762 | i2QueueNeeds(pB, pCh, NEED_BYPASS); | ||
763 | break; | ||
764 | } | ||
765 | |||
766 | ip2trace (CHANN, ITRC_QUEUE, ITRC_RETURN, 1, nCommands ); | ||
767 | |||
768 | return nCommands; // Good status: number of commands sent | ||
769 | } | ||
770 | |||
771 | //****************************************************************************** | ||
772 | // Function: i2GetStatus(pCh,resetBits) | ||
773 | // Parameters: Pointer to a channel structure | ||
774 | // Bit map of status bits to clear | ||
775 | // Returns: Bit map of current status bits | ||
776 | // | ||
777 | // Description: | ||
778 | // Returns the state of data set signals, and whether a break has been received, | ||
779 | // (see i2lib.h for bit-mapped result). resetBits is a bit-map of any status | ||
780 | // bits to be cleared: I2_BRK, I2_PAR, I2_FRA, I2_OVR,... These are cleared | ||
781 | // AFTER the condition is passed. If pCh does not point to a valid channel, | ||
782 | // returns -1 (which would be impossible otherwise. | ||
783 | //****************************************************************************** | ||
784 | static int | ||
785 | i2GetStatus(i2ChanStrPtr pCh, int resetBits) | ||
786 | { | ||
787 | unsigned short status; | ||
788 | i2eBordStrPtr pB; | ||
789 | |||
790 | ip2trace (CHANN, ITRC_STATUS, ITRC_ENTER, 2, pCh->dataSetIn, resetBits ); | ||
791 | |||
792 | // Make sure the channel exists, otherwise do nothing */ | ||
793 | if ( !i2Validate ( pCh ) ) | ||
794 | return -1; | ||
795 | |||
796 | pB = pCh->pMyBord; | ||
797 | |||
798 | status = pCh->dataSetIn; | ||
799 | |||
800 | // Clear any specified error bits: but note that only actual error bits can | ||
801 | // be cleared, regardless of the value passed. | ||
802 | if (resetBits) | ||
803 | { | ||
804 | pCh->dataSetIn &= ~(resetBits & (I2_BRK | I2_PAR | I2_FRA | I2_OVR)); | ||
805 | pCh->dataSetIn &= ~(I2_DDCD | I2_DCTS | I2_DDSR | I2_DRI); | ||
806 | } | ||
807 | |||
808 | ip2trace (CHANN, ITRC_STATUS, ITRC_RETURN, 1, pCh->dataSetIn ); | ||
809 | |||
810 | return status; | ||
811 | } | ||
812 | |||
813 | //****************************************************************************** | ||
814 | // Function: i2Input(pChpDest,count) | ||
815 | // Parameters: Pointer to a channel structure | ||
816 | // Pointer to data buffer | ||
817 | // Number of bytes to read | ||
818 | // Returns: Number of bytes read, or -1 for error | ||
819 | // | ||
820 | // Description: | ||
821 | // Strips data from the input buffer and writes it to pDest. If there is a | ||
822 | // collosal blunder, (invalid structure pointers or the like), returns -1. | ||
823 | // Otherwise, returns the number of bytes read. | ||
824 | //****************************************************************************** | ||
825 | static int | ||
826 | i2Input(i2ChanStrPtr pCh) | ||
827 | { | ||
828 | int amountToMove; | ||
829 | unsigned short stripIndex; | ||
830 | int count; | ||
831 | unsigned long flags = 0; | ||
832 | |||
833 | ip2trace (CHANN, ITRC_INPUT, ITRC_ENTER, 0); | ||
834 | |||
835 | // Ensure channel structure seems real | ||
836 | if ( !i2Validate( pCh ) ) { | ||
837 | count = -1; | ||
838 | goto i2Input_exit; | ||
839 | } | ||
840 | WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); | ||
841 | |||
842 | // initialize some accelerators and private copies | ||
843 | stripIndex = pCh->Ibuf_strip; | ||
844 | |||
845 | count = pCh->Ibuf_stuff - stripIndex; | ||
846 | |||
847 | // If buffer is empty or requested data count was 0, (trivial case) return | ||
848 | // without any further thought. | ||
849 | if ( count == 0 ) { | ||
850 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
851 | goto i2Input_exit; | ||
852 | } | ||
853 | // Adjust for buffer wrap | ||
854 | if ( count < 0 ) { | ||
855 | count += IBUF_SIZE; | ||
856 | } | ||
857 | // Don't give more than can be taken by the line discipline | ||
858 | amountToMove = pCh->pTTY->ldisc.receive_room( pCh->pTTY ); | ||
859 | if (count > amountToMove) { | ||
860 | count = amountToMove; | ||
861 | } | ||
862 | // How much could we copy without a wrap? | ||
863 | amountToMove = IBUF_SIZE - stripIndex; | ||
864 | |||
865 | if (amountToMove > count) { | ||
866 | amountToMove = count; | ||
867 | } | ||
868 | // Move the first block | ||
869 | pCh->pTTY->ldisc.receive_buf( pCh->pTTY, | ||
870 | &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); | ||
871 | // If we needed to wrap, do the second data move | ||
872 | if (count > amountToMove) { | ||
873 | pCh->pTTY->ldisc.receive_buf( pCh->pTTY, | ||
874 | pCh->Ibuf, NULL, count - amountToMove ); | ||
875 | } | ||
876 | // Bump and wrap the stripIndex all at once by the amount of data read. This | ||
877 | // method is good regardless of whether the data was in one or two pieces. | ||
878 | stripIndex += count; | ||
879 | if (stripIndex >= IBUF_SIZE) { | ||
880 | stripIndex -= IBUF_SIZE; | ||
881 | } | ||
882 | pCh->Ibuf_strip = stripIndex; | ||
883 | |||
884 | // Update our flow control information and possibly queue ourselves to send | ||
885 | // it, depending on how much data has been stripped since the last time a | ||
886 | // packet was sent. | ||
887 | pCh->infl.asof += count; | ||
888 | |||
889 | if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) { | ||
890 | pCh->sinceLastFlow -= pCh->whenSendFlow; | ||
891 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
892 | i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); | ||
893 | } else { | ||
894 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
895 | } | ||
896 | |||
897 | i2Input_exit: | ||
898 | |||
899 | ip2trace (CHANN, ITRC_INPUT, ITRC_RETURN, 1, count); | ||
900 | |||
901 | return count; | ||
902 | } | ||
903 | |||
904 | //****************************************************************************** | ||
905 | // Function: i2InputFlush(pCh) | ||
906 | // Parameters: Pointer to a channel structure | ||
907 | // Returns: Number of bytes stripped, or -1 for error | ||
908 | // | ||
909 | // Description: | ||
910 | // Strips any data from the input buffer. If there is a collosal blunder, | ||
911 | // (invalid structure pointers or the like), returns -1. Otherwise, returns the | ||
912 | // number of bytes stripped. | ||
913 | //****************************************************************************** | ||
914 | static int | ||
915 | i2InputFlush(i2ChanStrPtr pCh) | ||
916 | { | ||
917 | int count; | ||
918 | unsigned long flags; | ||
919 | |||
920 | // Ensure channel structure seems real | ||
921 | if ( !i2Validate ( pCh ) ) | ||
922 | return -1; | ||
923 | |||
924 | ip2trace (CHANN, ITRC_INPUT, 10, 0); | ||
925 | |||
926 | WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); | ||
927 | count = pCh->Ibuf_stuff - pCh->Ibuf_strip; | ||
928 | |||
929 | // Adjust for buffer wrap | ||
930 | if (count < 0) { | ||
931 | count += IBUF_SIZE; | ||
932 | } | ||
933 | |||
934 | // Expedient way to zero out the buffer | ||
935 | pCh->Ibuf_strip = pCh->Ibuf_stuff; | ||
936 | |||
937 | |||
938 | // Update our flow control information and possibly queue ourselves to send | ||
939 | // it, depending on how much data has been stripped since the last time a | ||
940 | // packet was sent. | ||
941 | |||
942 | pCh->infl.asof += count; | ||
943 | |||
944 | if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow ) | ||
945 | { | ||
946 | pCh->sinceLastFlow -= pCh->whenSendFlow; | ||
947 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
948 | i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); | ||
949 | } else { | ||
950 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
951 | } | ||
952 | |||
953 | ip2trace (CHANN, ITRC_INPUT, 19, 1, count); | ||
954 | |||
955 | return count; | ||
956 | } | ||
957 | |||
958 | //****************************************************************************** | ||
959 | // Function: i2InputAvailable(pCh) | ||
960 | // Parameters: Pointer to a channel structure | ||
961 | // Returns: Number of bytes available, or -1 for error | ||
962 | // | ||
963 | // Description: | ||
964 | // If there is a collosal blunder, (invalid structure pointers or the like), | ||
965 | // returns -1. Otherwise, returns the number of bytes stripped. Otherwise, | ||
966 | // returns the number of bytes available in the buffer. | ||
967 | //****************************************************************************** | ||
968 | #if 0 | ||
969 | static int | ||
970 | i2InputAvailable(i2ChanStrPtr pCh) | ||
971 | { | ||
972 | int count; | ||
973 | |||
974 | // Ensure channel structure seems real | ||
975 | if ( !i2Validate ( pCh ) ) return -1; | ||
976 | |||
977 | |||
978 | // initialize some accelerators and private copies | ||
979 | READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); | ||
980 | count = pCh->Ibuf_stuff - pCh->Ibuf_strip; | ||
981 | READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); | ||
982 | |||
983 | // Adjust for buffer wrap | ||
984 | if (count < 0) | ||
985 | { | ||
986 | count += IBUF_SIZE; | ||
987 | } | ||
988 | |||
989 | return count; | ||
990 | } | ||
991 | #endif | ||
992 | |||
993 | //****************************************************************************** | ||
994 | // Function: i2Output(pCh, pSource, count) | ||
995 | // Parameters: Pointer to channel structure | ||
996 | // Pointer to source data | ||
997 | // Number of bytes to send | ||
998 | // Returns: Number of bytes sent, or -1 for error | ||
999 | // | ||
1000 | // Description: | ||
1001 | // Queues the data at pSource to be sent as data packets to the board. If there | ||
1002 | // is a collosal blunder, (invalid structure pointers or the like), returns -1. | ||
1003 | // Otherwise, returns the number of bytes written. What if there is not enough | ||
1004 | // room for all the data? If pCh->channelOptions & CO_NBLOCK_WRITE is set, then | ||
1005 | // we transfer as many characters as we can now, then return. If this bit is | ||
1006 | // clear (default), routine will spin along until all the data is buffered. | ||
1007 | // Should this occur, the 1-ms delay routine is called while waiting to avoid | ||
1008 | // applications that one cannot break out of. | ||
1009 | //****************************************************************************** | ||
1010 | static int | ||
1011 | i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) | ||
1012 | { | ||
1013 | i2eBordStrPtr pB; | ||
1014 | unsigned char *pInsert; | ||
1015 | int amountToMove; | ||
1016 | int countOriginal = count; | ||
1017 | unsigned short channel; | ||
1018 | unsigned short stuffIndex; | ||
1019 | unsigned long flags; | ||
1020 | int rc = 0; | ||
1021 | |||
1022 | int bailout = 10; | ||
1023 | |||
1024 | ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user ); | ||
1025 | |||
1026 | // Ensure channel structure seems real | ||
1027 | if ( !i2Validate ( pCh ) ) | ||
1028 | return -1; | ||
1029 | |||
1030 | // initialize some accelerators and private copies | ||
1031 | pB = pCh->pMyBord; | ||
1032 | channel = pCh->infl.hd.i2sChannel; | ||
1033 | |||
1034 | // If the board has gone fatal, return bad, and also hit the trap routine if | ||
1035 | // it exists. | ||
1036 | if (pB->i2eFatal) { | ||
1037 | if (pB->i2eFatalTrap) { | ||
1038 | (*(pB)->i2eFatalTrap)(pB); | ||
1039 | } | ||
1040 | return -1; | ||
1041 | } | ||
1042 | // Proceed as though we would do everything | ||
1043 | while ( count > 0 ) { | ||
1044 | |||
1045 | // How much room in output buffer is there? | ||
1046 | READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); | ||
1047 | amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; | ||
1048 | READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); | ||
1049 | if (amountToMove < 0) { | ||
1050 | amountToMove += OBUF_SIZE; | ||
1051 | } | ||
1052 | // Subtract off the headers size and see how much room there is for real | ||
1053 | // data. If this is negative, we will discover later. | ||
1054 | amountToMove -= sizeof (i2DataHeader); | ||
1055 | |||
1056 | // Don't move more (now) than can go in a single packet | ||
1057 | if ( amountToMove > (int)(MAX_OBUF_BLOCK - sizeof(i2DataHeader)) ) { | ||
1058 | amountToMove = MAX_OBUF_BLOCK - sizeof(i2DataHeader); | ||
1059 | } | ||
1060 | // Don't move more than the count we were given | ||
1061 | if (amountToMove > count) { | ||
1062 | amountToMove = count; | ||
1063 | } | ||
1064 | // Now we know how much we must move: NB because the ring buffers have | ||
1065 | // an overflow area at the end, we needn't worry about wrapping in the | ||
1066 | // middle of a packet. | ||
1067 | |||
1068 | // Small WINDOW here with no LOCK but I can't call Flush with LOCK | ||
1069 | // We would be flushing (or ending flush) anyway | ||
1070 | |||
1071 | ip2trace (CHANN, ITRC_OUTPUT, 10, 1, amountToMove ); | ||
1072 | |||
1073 | if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) ) | ||
1074 | && amountToMove > 0 ) | ||
1075 | { | ||
1076 | WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); | ||
1077 | stuffIndex = pCh->Obuf_stuff; | ||
1078 | |||
1079 | // Had room to move some data: don't know whether the block size, | ||
1080 | // buffer space, or what was the limiting factor... | ||
1081 | pInsert = &(pCh->Obuf[stuffIndex]); | ||
1082 | |||
1083 | // Set up the header | ||
1084 | CHANNEL_OF(pInsert) = channel; | ||
1085 | PTYPE_OF(pInsert) = PTYPE_DATA; | ||
1086 | TAG_OF(pInsert) = 0; | ||
1087 | ID_OF(pInsert) = ID_ORDINARY_DATA; | ||
1088 | DATA_COUNT_OF(pInsert) = amountToMove; | ||
1089 | |||
1090 | // Move the data | ||
1091 | if ( user ) { | ||
1092 | rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource, | ||
1093 | amountToMove ); | ||
1094 | } else { | ||
1095 | memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); | ||
1096 | } | ||
1097 | // Adjust pointers and indices | ||
1098 | pSource += amountToMove; | ||
1099 | pCh->Obuf_char_count += amountToMove; | ||
1100 | stuffIndex += amountToMove + sizeof(i2DataHeader); | ||
1101 | count -= amountToMove; | ||
1102 | |||
1103 | if (stuffIndex >= OBUF_SIZE) { | ||
1104 | stuffIndex = 0; | ||
1105 | } | ||
1106 | pCh->Obuf_stuff = stuffIndex; | ||
1107 | |||
1108 | WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); | ||
1109 | |||
1110 | ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex ); | ||
1111 | |||
1112 | } else { | ||
1113 | |||
1114 | // Cannot move data | ||
1115 | // becuz we need to stuff a flush | ||
1116 | // or amount to move is <= 0 | ||
1117 | |||
1118 | ip2trace(CHANN, ITRC_OUTPUT, 14, 3, | ||
1119 | amountToMove, pB->i2eFifoRemains, | ||
1120 | pB->i2eWaitingForEmptyFifo ); | ||
1121 | |||
1122 | // Put this channel back on queue | ||
1123 | // this ultimatly gets more data or wakes write output | ||
1124 | i2QueueNeeds(pB, pCh, NEED_INLINE); | ||
1125 | |||
1126 | if ( pB->i2eWaitingForEmptyFifo ) { | ||
1127 | |||
1128 | ip2trace (CHANN, ITRC_OUTPUT, 16, 0 ); | ||
1129 | |||
1130 | // or schedule | ||
1131 | if (!in_interrupt()) { | ||
1132 | |||
1133 | ip2trace (CHANN, ITRC_OUTPUT, 61, 0 ); | ||
1134 | |||
1135 | current->state = TASK_INTERRUPTIBLE; | ||
1136 | schedule_timeout(2); | ||
1137 | if (signal_pending(current)) { | ||
1138 | break; | ||
1139 | } | ||
1140 | continue; | ||
1141 | } else { | ||
1142 | |||
1143 | ip2trace (CHANN, ITRC_OUTPUT, 62, 0 ); | ||
1144 | |||
1145 | // let interrupt in = WAS restore_flags() | ||
1146 | // We hold no lock nor is irq off anymore??? | ||
1147 | |||
1148 | break; | ||
1149 | } | ||
1150 | break; // from while(count) | ||
1151 | } | ||
1152 | else if ( pB->i2eFifoRemains < 32 && !pB->i2eTxMailEmpty ( pB ) ) | ||
1153 | { | ||
1154 | ip2trace (CHANN, ITRC_OUTPUT, 19, 2, | ||
1155 | pB->i2eFifoRemains, | ||
1156 | pB->i2eTxMailEmpty ); | ||
1157 | |||
1158 | break; // from while(count) | ||
1159 | } else if ( pCh->channelNeeds & NEED_CREDIT ) { | ||
1160 | |||
1161 | ip2trace (CHANN, ITRC_OUTPUT, 22, 0 ); | ||
1162 | |||
1163 | break; // from while(count) | ||
1164 | } else if ( --bailout) { | ||
1165 | |||
1166 | // Try to throw more things (maybe not us) in the fifo if we're | ||
1167 | // not already waiting for it. | ||
1168 | |||
1169 | ip2trace (CHANN, ITRC_OUTPUT, 20, 0 ); | ||
1170 | |||
1171 | serviceOutgoingFifo(pB); | ||
1172 | //break; CONTINUE; | ||
1173 | } else { | ||
1174 | ip2trace (CHANN, ITRC_OUTPUT, 21, 3, | ||
1175 | pB->i2eFifoRemains, | ||
1176 | pB->i2eOutMailWaiting, | ||
1177 | pB->i2eWaitingForEmptyFifo ); | ||
1178 | |||
1179 | break; // from while(count) | ||
1180 | } | ||
1181 | } | ||
1182 | } // End of while(count) | ||
1183 | |||
1184 | i2QueueNeeds(pB, pCh, NEED_INLINE); | ||
1185 | |||
1186 | // We drop through either when the count expires, or when there is some | ||
1187 | // count left, but there was a non-blocking write. | ||
1188 | if (countOriginal > count) { | ||
1189 | |||
1190 | ip2trace (CHANN, ITRC_OUTPUT, 17, 2, countOriginal, count ); | ||
1191 | |||
1192 | serviceOutgoingFifo( pB ); | ||
1193 | } | ||
1194 | |||
1195 | ip2trace (CHANN, ITRC_OUTPUT, ITRC_RETURN, 2, countOriginal, count ); | ||
1196 | |||
1197 | return countOriginal - count; | ||
1198 | } | ||
1199 | |||
1200 | //****************************************************************************** | ||
1201 | // Function: i2FlushOutput(pCh) | ||
1202 | // Parameters: Pointer to a channel structure | ||
1203 | // Returns: Nothing | ||
1204 | // | ||
1205 | // Description: | ||
1206 | // Sends bypass command to start flushing (waiting possibly forever until there | ||
1207 | // is room), then sends inline command to stop flushing output, (again waiting | ||
1208 | // possibly forever). | ||
1209 | //****************************************************************************** | ||
1210 | static inline void | ||
1211 | i2FlushOutput(i2ChanStrPtr pCh) | ||
1212 | { | ||
1213 | |||
1214 | ip2trace (CHANN, ITRC_FLUSH, 1, 1, pCh->flush_flags ); | ||
1215 | |||
1216 | if (pCh->flush_flags) | ||
1217 | return; | ||
1218 | |||
1219 | if ( 1 != i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { | ||
1220 | pCh->flush_flags = STARTFL_FLAG; // Failed - flag for later | ||
1221 | |||
1222 | ip2trace (CHANN, ITRC_FLUSH, 2, 0 ); | ||
1223 | |||
1224 | } else if ( 1 != i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) ) { | ||
1225 | pCh->flush_flags = STOPFL_FLAG; // Failed - flag for later | ||
1226 | |||
1227 | ip2trace (CHANN, ITRC_FLUSH, 3, 0 ); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | static int | ||
1232 | i2RetryFlushOutput(i2ChanStrPtr pCh) | ||
1233 | { | ||
1234 | int old_flags = pCh->flush_flags; | ||
1235 | |||
1236 | ip2trace (CHANN, ITRC_FLUSH, 14, 1, old_flags ); | ||
1237 | |||
1238 | pCh->flush_flags = 0; // Clear flag so we can avoid recursion | ||
1239 | // and queue the commands | ||
1240 | |||
1241 | if ( old_flags & STARTFL_FLAG ) { | ||
1242 | if ( 1 == i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { | ||
1243 | old_flags = STOPFL_FLAG; //Success - send stop flush | ||
1244 | } else { | ||
1245 | old_flags = STARTFL_FLAG; //Failure - Flag for retry later | ||
1246 | } | ||
1247 | |||
1248 | ip2trace (CHANN, ITRC_FLUSH, 15, 1, old_flags ); | ||
1249 | |||
1250 | } | ||
1251 | if ( old_flags & STOPFL_FLAG ) { | ||
1252 | if (1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL)) { | ||
1253 | old_flags = 0; // Success - clear flags | ||
1254 | } | ||
1255 | |||
1256 | ip2trace (CHANN, ITRC_FLUSH, 16, 1, old_flags ); | ||
1257 | } | ||
1258 | pCh->flush_flags = old_flags; | ||
1259 | |||
1260 | ip2trace (CHANN, ITRC_FLUSH, 17, 1, old_flags ); | ||
1261 | |||
1262 | return old_flags; | ||
1263 | } | ||
1264 | |||
1265 | //****************************************************************************** | ||
1266 | // Function: i2DrainOutput(pCh,timeout) | ||
1267 | // Parameters: Pointer to a channel structure | ||
1268 | // Maximum period to wait | ||
1269 | // Returns: ? | ||
1270 | // | ||
1271 | // Description: | ||
1272 | // Uses the bookmark request command to ask the board to send a bookmark back as | ||
1273 | // soon as all the data is completely sent. | ||
1274 | //****************************************************************************** | ||
1275 | static void | ||
1276 | i2DrainWakeup(i2ChanStrPtr pCh) | ||
1277 | { | ||
1278 | ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires ); | ||
1279 | |||
1280 | pCh->BookmarkTimer.expires = 0; | ||
1281 | wake_up_interruptible( &pCh->pBookmarkWait ); | ||
1282 | } | ||
1283 | |||
1284 | static void | ||
1285 | i2DrainOutput(i2ChanStrPtr pCh, int timeout) | ||
1286 | { | ||
1287 | wait_queue_t wait; | ||
1288 | i2eBordStrPtr pB; | ||
1289 | |||
1290 | ip2trace (CHANN, ITRC_DRAIN, ITRC_ENTER, 1, pCh->BookmarkTimer.expires); | ||
1291 | |||
1292 | pB = pCh->pMyBord; | ||
1293 | // If the board has gone fatal, return bad, | ||
1294 | // and also hit the trap routine if it exists. | ||
1295 | if (pB->i2eFatal) { | ||
1296 | if (pB->i2eFatalTrap) { | ||
1297 | (*(pB)->i2eFatalTrap)(pB); | ||
1298 | } | ||
1299 | return; | ||
1300 | } | ||
1301 | if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) { | ||
1302 | // One per customer (channel) | ||
1303 | init_timer( &(pCh->BookmarkTimer) ); | ||
1304 | pCh->BookmarkTimer.expires = jiffies + timeout; | ||
1305 | pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup; | ||
1306 | pCh->BookmarkTimer.data = (unsigned long)pCh; | ||
1307 | |||
1308 | ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires ); | ||
1309 | |||
1310 | add_timer( &(pCh->BookmarkTimer) ); | ||
1311 | } | ||
1312 | |||
1313 | i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ ); | ||
1314 | |||
1315 | init_waitqueue_entry(&wait, current); | ||
1316 | add_wait_queue(&(pCh->pBookmarkWait), &wait); | ||
1317 | set_current_state( TASK_INTERRUPTIBLE ); | ||
1318 | |||
1319 | serviceOutgoingFifo( pB ); | ||
1320 | |||
1321 | schedule(); // Now we take our interruptible sleep on | ||
1322 | |||
1323 | // Clean up the queue | ||
1324 | set_current_state( TASK_RUNNING ); | ||
1325 | remove_wait_queue(&(pCh->pBookmarkWait), &wait); | ||
1326 | |||
1327 | // if expires == 0 then timer poped, then do not need to del_timer | ||
1328 | if ((timeout > 0) && pCh->BookmarkTimer.expires && | ||
1329 | time_before(jiffies, pCh->BookmarkTimer.expires)) { | ||
1330 | del_timer( &(pCh->BookmarkTimer) ); | ||
1331 | pCh->BookmarkTimer.expires = 0; | ||
1332 | |||
1333 | ip2trace (CHANN, ITRC_DRAIN, 3, 1, pCh->BookmarkTimer.expires ); | ||
1334 | |||
1335 | } | ||
1336 | ip2trace (CHANN, ITRC_DRAIN, ITRC_RETURN, 1, pCh->BookmarkTimer.expires ); | ||
1337 | return; | ||
1338 | } | ||
1339 | |||
1340 | //****************************************************************************** | ||
1341 | // Function: i2OutputFree(pCh) | ||
1342 | // Parameters: Pointer to a channel structure | ||
1343 | // Returns: Space in output buffer | ||
1344 | // | ||
1345 | // Description: | ||
1346 | // Returns -1 if very gross error. Otherwise returns the amount of bytes still | ||
1347 | // free in the output buffer. | ||
1348 | //****************************************************************************** | ||
1349 | static int | ||
1350 | i2OutputFree(i2ChanStrPtr pCh) | ||
1351 | { | ||
1352 | int amountToMove; | ||
1353 | unsigned long flags; | ||
1354 | |||
1355 | // Ensure channel structure seems real | ||
1356 | if ( !i2Validate ( pCh ) ) { | ||
1357 | return -1; | ||
1358 | } | ||
1359 | READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); | ||
1360 | amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; | ||
1361 | READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); | ||
1362 | |||
1363 | if (amountToMove < 0) { | ||
1364 | amountToMove += OBUF_SIZE; | ||
1365 | } | ||
1366 | // If this is negative, we will discover later | ||
1367 | amountToMove -= sizeof(i2DataHeader); | ||
1368 | |||
1369 | return (amountToMove < 0) ? 0 : amountToMove; | ||
1370 | } | ||
1371 | static void | ||
1372 | |||
1373 | ip2_owake( PTTY tp) | ||
1374 | { | ||
1375 | i2ChanStrPtr pCh; | ||
1376 | |||
1377 | if (tp == NULL) return; | ||
1378 | |||
1379 | pCh = tp->driver_data; | ||
1380 | |||
1381 | ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags, | ||
1382 | (1 << TTY_DO_WRITE_WAKEUP) ); | ||
1383 | |||
1384 | wake_up_interruptible ( &tp->write_wait ); | ||
1385 | if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) | ||
1386 | && tp->ldisc.write_wakeup ) | ||
1387 | { | ||
1388 | (tp->ldisc.write_wakeup) ( tp ); | ||
1389 | |||
1390 | ip2trace (CHANN, ITRC_SICMD, 11, 0 ); | ||
1391 | |||
1392 | } | ||
1393 | } | ||
1394 | |||
1395 | static inline void | ||
1396 | set_baud_params(i2eBordStrPtr pB) | ||
1397 | { | ||
1398 | int i,j; | ||
1399 | i2ChanStrPtr *pCh; | ||
1400 | |||
1401 | pCh = (i2ChanStrPtr *) pB->i2eChannelPtr; | ||
1402 | |||
1403 | for (i = 0; i < ABS_MAX_BOXES; i++) { | ||
1404 | if (pB->channelBtypes.bid_value[i]) { | ||
1405 | if (BID_HAS_654(pB->channelBtypes.bid_value[i])) { | ||
1406 | for (j = 0; j < ABS_BIGGEST_BOX; j++) { | ||
1407 | if (pCh[i*16+j] == NULL) | ||
1408 | break; | ||
1409 | (pCh[i*16+j])->BaudBase = 921600; // MAX for ST654 | ||
1410 | (pCh[i*16+j])->BaudDivisor = 96; | ||
1411 | } | ||
1412 | } else { // has cirrus cd1400 | ||
1413 | for (j = 0; j < ABS_BIGGEST_BOX; j++) { | ||
1414 | if (pCh[i*16+j] == NULL) | ||
1415 | break; | ||
1416 | (pCh[i*16+j])->BaudBase = 115200; // MAX for CD1400 | ||
1417 | (pCh[i*16+j])->BaudDivisor = 12; | ||
1418 | } | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | } | ||
1423 | |||
1424 | //****************************************************************************** | ||
1425 | // Function: i2StripFifo(pB) | ||
1426 | // Parameters: Pointer to a board structure | ||
1427 | // Returns: ? | ||
1428 | // | ||
1429 | // Description: | ||
1430 | // Strips all the available data from the incoming FIFO, identifies the type of | ||
1431 | // packet, and either buffers the data or does what needs to be done. | ||
1432 | // | ||
1433 | // Note there is no overflow checking here: if the board sends more data than it | ||
1434 | // ought to, we will not detect it here, but blindly overflow... | ||
1435 | //****************************************************************************** | ||
1436 | |||
1437 | // A buffer for reading in blocks for unknown channels | ||
1438 | static unsigned char junkBuffer[IBUF_SIZE]; | ||
1439 | |||
1440 | // A buffer to read in a status packet. Because of the size of the count field | ||
1441 | // for these things, the maximum packet size must be less than MAX_CMD_PACK_SIZE | ||
1442 | static unsigned char cmdBuffer[MAX_CMD_PACK_SIZE + 4]; | ||
1443 | |||
1444 | // This table changes the bit order from MSR order given by STAT_MODEM packet to | ||
1445 | // status bits used in our library. | ||
1446 | static char xlatDss[16] = { | ||
1447 | 0 | 0 | 0 | 0 , | ||
1448 | 0 | 0 | 0 | I2_CTS , | ||
1449 | 0 | 0 | I2_DSR | 0 , | ||
1450 | 0 | 0 | I2_DSR | I2_CTS , | ||
1451 | 0 | I2_RI | 0 | 0 , | ||
1452 | 0 | I2_RI | 0 | I2_CTS , | ||
1453 | 0 | I2_RI | I2_DSR | 0 , | ||
1454 | 0 | I2_RI | I2_DSR | I2_CTS , | ||
1455 | I2_DCD | 0 | 0 | 0 , | ||
1456 | I2_DCD | 0 | 0 | I2_CTS , | ||
1457 | I2_DCD | 0 | I2_DSR | 0 , | ||
1458 | I2_DCD | 0 | I2_DSR | I2_CTS , | ||
1459 | I2_DCD | I2_RI | 0 | 0 , | ||
1460 | I2_DCD | I2_RI | 0 | I2_CTS , | ||
1461 | I2_DCD | I2_RI | I2_DSR | 0 , | ||
1462 | I2_DCD | I2_RI | I2_DSR | I2_CTS }; | ||
1463 | |||
1464 | static inline void | ||
1465 | i2StripFifo(i2eBordStrPtr pB) | ||
1466 | { | ||
1467 | i2ChanStrPtr pCh; | ||
1468 | int channel; | ||
1469 | int count; | ||
1470 | unsigned short stuffIndex; | ||
1471 | int amountToRead; | ||
1472 | unsigned char *pc, *pcLimit; | ||
1473 | unsigned char uc; | ||
1474 | unsigned char dss_change; | ||
1475 | unsigned long bflags,cflags; | ||
1476 | |||
1477 | // ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 ); | ||
1478 | |||
1479 | while (HAS_INPUT(pB)) { | ||
1480 | // ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 ); | ||
1481 | |||
1482 | // Process packet from fifo a one atomic unit | ||
1483 | WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags); | ||
1484 | |||
1485 | // The first word (or two bytes) will have channel number and type of | ||
1486 | // packet, possibly other information | ||
1487 | pB->i2eLeadoffWord[0] = iiReadWord(pB); | ||
1488 | |||
1489 | switch(PTYPE_OF(pB->i2eLeadoffWord)) | ||
1490 | { | ||
1491 | case PTYPE_DATA: | ||
1492 | pB->got_input = 1; | ||
1493 | |||
1494 | // ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 3, 0 ); | ||
1495 | |||
1496 | channel = CHANNEL_OF(pB->i2eLeadoffWord); /* Store channel */ | ||
1497 | count = iiReadWord(pB); /* Count is in the next word */ | ||
1498 | |||
1499 | // NEW: Check the count for sanity! Should the hardware fail, our death | ||
1500 | // is more pleasant. While an oversize channel is acceptable (just more | ||
1501 | // than the driver supports), an over-length count clearly means we are | ||
1502 | // sick! | ||
1503 | if ( ((unsigned int)count) > IBUF_SIZE ) { | ||
1504 | pB->i2eFatal = 2; | ||
1505 | WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); | ||
1506 | return; /* Bail out ASAP */ | ||
1507 | } | ||
1508 | // Channel is illegally big ? | ||
1509 | if ((channel >= pB->i2eChannelCnt) || | ||
1510 | (NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel]))) | ||
1511 | { | ||
1512 | iiReadBuf(pB, junkBuffer, count); | ||
1513 | WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); | ||
1514 | break; /* From switch: ready for next packet */ | ||
1515 | } | ||
1516 | |||
1517 | // Channel should be valid, then | ||
1518 | |||
1519 | // If this is a hot-key, merely post its receipt for now. These are | ||
1520 | // always supposed to be 1-byte packets, so we won't even check the | ||
1521 | // count. Also we will post an acknowledgement to the board so that | ||
1522 | // more data can be forthcoming. Note that we are not trying to use | ||
1523 | // these sequences in this driver, merely to robustly ignore them. | ||
1524 | if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY) | ||
1525 | { | ||
1526 | pCh->hotKeyIn = iiReadWord(pB) & 0xff; | ||
1527 | WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); | ||
1528 | i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK); | ||
1529 | break; /* From the switch: ready for next packet */ | ||
1530 | } | ||
1531 | |||
1532 | // Normal data! We crudely assume there is room for the data in our | ||
1533 | // buffer because the board wouldn't have exceeded his credit limit. | ||
1534 | WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags); | ||
1535 | // We have 2 locks now | ||
1536 | stuffIndex = pCh->Ibuf_stuff; | ||
1537 | amountToRead = IBUF_SIZE - stuffIndex; | ||
1538 | if (amountToRead > count) | ||
1539 | amountToRead = count; | ||
1540 | |||
1541 | // stuffIndex would have been already adjusted so there would | ||
1542 | // always be room for at least one, and count is always at least | ||
1543 | // one. | ||
1544 | |||
1545 | iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); | ||
1546 | pCh->icount.rx += amountToRead; | ||
1547 | |||
1548 | // Update the stuffIndex by the amount of data moved. Note we could | ||
1549 | // never ask for more data than would just fit. However, we might | ||
1550 | // have read in one more byte than we wanted because the read | ||
1551 | // rounds up to even bytes. If this byte is on the end of the | ||
1552 | // packet, and is padding, we ignore it. If the byte is part of | ||
1553 | // the actual data, we need to move it. | ||
1554 | |||
1555 | stuffIndex += amountToRead; | ||
1556 | |||
1557 | if (stuffIndex >= IBUF_SIZE) { | ||
1558 | if ((amountToRead & 1) && (count > amountToRead)) { | ||
1559 | pCh->Ibuf[0] = pCh->Ibuf[IBUF_SIZE]; | ||
1560 | amountToRead++; | ||
1561 | stuffIndex = 1; | ||
1562 | } else { | ||
1563 | stuffIndex = 0; | ||
1564 | } | ||
1565 | } | ||
1566 | |||
1567 | // If there is anything left over, read it as well | ||
1568 | if (count > amountToRead) { | ||
1569 | amountToRead = count - amountToRead; | ||
1570 | iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); | ||
1571 | pCh->icount.rx += amountToRead; | ||
1572 | stuffIndex += amountToRead; | ||
1573 | } | ||
1574 | |||
1575 | // Update stuff index | ||
1576 | pCh->Ibuf_stuff = stuffIndex; | ||
1577 | WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags); | ||
1578 | WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); | ||
1579 | |||
1580 | #ifdef USE_IQ | ||
1581 | schedule_work(&pCh->tqueue_input); | ||
1582 | #else | ||
1583 | do_input(pCh); | ||
1584 | #endif | ||
1585 | |||
1586 | // Note we do not need to maintain any flow-control credits at this | ||
1587 | // time: if we were to increment .asof and decrement .room, there | ||
1588 | // would be no net effect. Instead, when we strip data, we will | ||
1589 | // increment .asof and leave .room unchanged. | ||
1590 | |||
1591 | break; // From switch: ready for next packet | ||
1592 | |||
1593 | case PTYPE_STATUS: | ||
1594 | ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 4, 0 ); | ||
1595 | |||
1596 | count = CMD_COUNT_OF(pB->i2eLeadoffWord); | ||
1597 | |||
1598 | iiReadBuf(pB, cmdBuffer, count); | ||
1599 | // We can release early with buffer grab | ||
1600 | WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); | ||
1601 | |||
1602 | pc = cmdBuffer; | ||
1603 | pcLimit = &(cmdBuffer[count]); | ||
1604 | |||
1605 | while (pc < pcLimit) { | ||
1606 | channel = *pc++; | ||
1607 | |||
1608 | ip2trace (channel, ITRC_SFIFO, 7, 2, channel, *pc ); | ||
1609 | |||
1610 | /* check for valid channel */ | ||
1611 | if (channel < pB->i2eChannelCnt | ||
1612 | && | ||
1613 | (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) != NULL | ||
1614 | ) | ||
1615 | { | ||
1616 | dss_change = 0; | ||
1617 | |||
1618 | switch (uc = *pc++) | ||
1619 | { | ||
1620 | /* Breaks and modem signals are easy: just update status */ | ||
1621 | case STAT_CTS_UP: | ||
1622 | if ( !(pCh->dataSetIn & I2_CTS) ) | ||
1623 | { | ||
1624 | pCh->dataSetIn |= I2_DCTS; | ||
1625 | pCh->icount.cts++; | ||
1626 | dss_change = 1; | ||
1627 | } | ||
1628 | pCh->dataSetIn |= I2_CTS; | ||
1629 | break; | ||
1630 | |||
1631 | case STAT_CTS_DN: | ||
1632 | if ( pCh->dataSetIn & I2_CTS ) | ||
1633 | { | ||
1634 | pCh->dataSetIn |= I2_DCTS; | ||
1635 | pCh->icount.cts++; | ||
1636 | dss_change = 1; | ||
1637 | } | ||
1638 | pCh->dataSetIn &= ~I2_CTS; | ||
1639 | break; | ||
1640 | |||
1641 | case STAT_DCD_UP: | ||
1642 | ip2trace (channel, ITRC_MODEM, 1, 1, pCh->dataSetIn ); | ||
1643 | |||
1644 | if ( !(pCh->dataSetIn & I2_DCD) ) | ||
1645 | { | ||
1646 | ip2trace (CHANN, ITRC_MODEM, 2, 0 ); | ||
1647 | pCh->dataSetIn |= I2_DDCD; | ||
1648 | pCh->icount.dcd++; | ||
1649 | dss_change = 1; | ||
1650 | } | ||
1651 | pCh->dataSetIn |= I2_DCD; | ||
1652 | |||
1653 | ip2trace (channel, ITRC_MODEM, 3, 1, pCh->dataSetIn ); | ||
1654 | break; | ||
1655 | |||
1656 | case STAT_DCD_DN: | ||
1657 | ip2trace (channel, ITRC_MODEM, 4, 1, pCh->dataSetIn ); | ||
1658 | if ( pCh->dataSetIn & I2_DCD ) | ||
1659 | { | ||
1660 | ip2trace (channel, ITRC_MODEM, 5, 0 ); | ||
1661 | pCh->dataSetIn |= I2_DDCD; | ||
1662 | pCh->icount.dcd++; | ||
1663 | dss_change = 1; | ||
1664 | } | ||
1665 | pCh->dataSetIn &= ~I2_DCD; | ||
1666 | |||
1667 | ip2trace (channel, ITRC_MODEM, 6, 1, pCh->dataSetIn ); | ||
1668 | break; | ||
1669 | |||
1670 | case STAT_DSR_UP: | ||
1671 | if ( !(pCh->dataSetIn & I2_DSR) ) | ||
1672 | { | ||
1673 | pCh->dataSetIn |= I2_DDSR; | ||
1674 | pCh->icount.dsr++; | ||
1675 | dss_change = 1; | ||
1676 | } | ||
1677 | pCh->dataSetIn |= I2_DSR; | ||
1678 | break; | ||
1679 | |||
1680 | case STAT_DSR_DN: | ||
1681 | if ( pCh->dataSetIn & I2_DSR ) | ||
1682 | { | ||
1683 | pCh->dataSetIn |= I2_DDSR; | ||
1684 | pCh->icount.dsr++; | ||
1685 | dss_change = 1; | ||
1686 | } | ||
1687 | pCh->dataSetIn &= ~I2_DSR; | ||
1688 | break; | ||
1689 | |||
1690 | case STAT_RI_UP: | ||
1691 | if ( !(pCh->dataSetIn & I2_RI) ) | ||
1692 | { | ||
1693 | pCh->dataSetIn |= I2_DRI; | ||
1694 | pCh->icount.rng++; | ||
1695 | dss_change = 1; | ||
1696 | } | ||
1697 | pCh->dataSetIn |= I2_RI ; | ||
1698 | break; | ||
1699 | |||
1700 | case STAT_RI_DN: | ||
1701 | // to be compat with serial.c | ||
1702 | //if ( pCh->dataSetIn & I2_RI ) | ||
1703 | //{ | ||
1704 | // pCh->dataSetIn |= I2_DRI; | ||
1705 | // pCh->icount.rng++; | ||
1706 | // dss_change = 1; | ||
1707 | //} | ||
1708 | pCh->dataSetIn &= ~I2_RI ; | ||
1709 | break; | ||
1710 | |||
1711 | case STAT_BRK_DET: | ||
1712 | pCh->dataSetIn |= I2_BRK; | ||
1713 | pCh->icount.brk++; | ||
1714 | dss_change = 1; | ||
1715 | break; | ||
1716 | |||
1717 | // Bookmarks? one less request we're waiting for | ||
1718 | case STAT_BMARK: | ||
1719 | pCh->bookMarks--; | ||
1720 | if (pCh->bookMarks <= 0 ) { | ||
1721 | pCh->bookMarks = 0; | ||
1722 | wake_up_interruptible( &pCh->pBookmarkWait ); | ||
1723 | |||
1724 | ip2trace (channel, ITRC_DRAIN, 20, 1, pCh->BookmarkTimer.expires ); | ||
1725 | } | ||
1726 | break; | ||
1727 | |||
1728 | // Flow control packets? Update the new credits, and if | ||
1729 | // someone was waiting for output, queue him up again. | ||
1730 | case STAT_FLOW: | ||
1731 | pCh->outfl.room = | ||
1732 | ((flowStatPtr)pc)->room - | ||
1733 | (pCh->outfl.asof - ((flowStatPtr)pc)->asof); | ||
1734 | |||
1735 | ip2trace (channel, ITRC_STFLW, 1, 1, pCh->outfl.room ); | ||
1736 | |||
1737 | if (pCh->channelNeeds & NEED_CREDIT) | ||
1738 | { | ||
1739 | ip2trace (channel, ITRC_STFLW, 2, 1, pCh->channelNeeds); | ||
1740 | |||
1741 | pCh->channelNeeds &= ~NEED_CREDIT; | ||
1742 | i2QueueNeeds(pB, pCh, NEED_INLINE); | ||
1743 | if ( pCh->pTTY ) | ||
1744 | ip2_owake(pCh->pTTY); | ||
1745 | } | ||
1746 | |||
1747 | ip2trace (channel, ITRC_STFLW, 3, 1, pCh->channelNeeds); | ||
1748 | |||
1749 | pc += sizeof(flowStat); | ||
1750 | break; | ||
1751 | |||
1752 | /* Special packets: */ | ||
1753 | /* Just copy the information into the channel structure */ | ||
1754 | |||
1755 | case STAT_STATUS: | ||
1756 | |||
1757 | pCh->channelStatus = *((debugStatPtr)pc); | ||
1758 | pc += sizeof(debugStat); | ||
1759 | break; | ||
1760 | |||
1761 | case STAT_TXCNT: | ||
1762 | |||
1763 | pCh->channelTcount = *((cntStatPtr)pc); | ||
1764 | pc += sizeof(cntStat); | ||
1765 | break; | ||
1766 | |||
1767 | case STAT_RXCNT: | ||
1768 | |||
1769 | pCh->channelRcount = *((cntStatPtr)pc); | ||
1770 | pc += sizeof(cntStat); | ||
1771 | break; | ||
1772 | |||
1773 | case STAT_BOXIDS: | ||
1774 | pB->channelBtypes = *((bidStatPtr)pc); | ||
1775 | pc += sizeof(bidStat); | ||
1776 | set_baud_params(pB); | ||
1777 | break; | ||
1778 | |||
1779 | case STAT_HWFAIL: | ||
1780 | i2QueueCommands (PTYPE_INLINE, pCh, 0, 1, CMD_HW_TEST); | ||
1781 | pCh->channelFail = *((failStatPtr)pc); | ||
1782 | pc += sizeof(failStat); | ||
1783 | break; | ||
1784 | |||
1785 | /* No explicit match? then | ||
1786 | * Might be an error packet... | ||
1787 | */ | ||
1788 | default: | ||
1789 | switch (uc & STAT_MOD_ERROR) | ||
1790 | { | ||
1791 | case STAT_ERROR: | ||
1792 | if (uc & STAT_E_PARITY) { | ||
1793 | pCh->dataSetIn |= I2_PAR; | ||
1794 | pCh->icount.parity++; | ||
1795 | } | ||
1796 | if (uc & STAT_E_FRAMING){ | ||
1797 | pCh->dataSetIn |= I2_FRA; | ||
1798 | pCh->icount.frame++; | ||
1799 | } | ||
1800 | if (uc & STAT_E_OVERRUN){ | ||
1801 | pCh->dataSetIn |= I2_OVR; | ||
1802 | pCh->icount.overrun++; | ||
1803 | } | ||
1804 | break; | ||
1805 | |||
1806 | case STAT_MODEM: | ||
1807 | // the answer to DSS_NOW request (not change) | ||
1808 | pCh->dataSetIn = (pCh->dataSetIn | ||
1809 | & ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) ) | ||
1810 | | xlatDss[uc & 0xf]; | ||
1811 | wake_up_interruptible ( &pCh->dss_now_wait ); | ||
1812 | default: | ||
1813 | break; | ||
1814 | } | ||
1815 | } /* End of switch on status type */ | ||
1816 | if (dss_change) { | ||
1817 | #ifdef USE_IQ | ||
1818 | schedule_work(&pCh->tqueue_status); | ||
1819 | #else | ||
1820 | do_status(pCh); | ||
1821 | #endif | ||
1822 | } | ||
1823 | } | ||
1824 | else /* Or else, channel is invalid */ | ||
1825 | { | ||
1826 | // Even though the channel is invalid, we must test the | ||
1827 | // status to see how much additional data it has (to be | ||
1828 | // skipped) | ||
1829 | switch (*pc++) | ||
1830 | { | ||
1831 | case STAT_FLOW: | ||
1832 | pc += 4; /* Skip the data */ | ||
1833 | break; | ||
1834 | |||
1835 | default: | ||
1836 | break; | ||
1837 | } | ||
1838 | } | ||
1839 | } // End of while (there is still some status packet left) | ||
1840 | break; | ||
1841 | |||
1842 | default: // Neither packet? should be impossible | ||
1843 | ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1, | ||
1844 | PTYPE_OF(pB->i2eLeadoffWord) ); | ||
1845 | |||
1846 | break; | ||
1847 | } // End of switch on type of packets | ||
1848 | } //while(board HAS_INPUT) | ||
1849 | |||
1850 | ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 ); | ||
1851 | |||
1852 | // Send acknowledgement to the board even if there was no data! | ||
1853 | pB->i2eOutMailWaiting |= MB_IN_STRIPPED; | ||
1854 | return; | ||
1855 | } | ||
1856 | |||
1857 | //****************************************************************************** | ||
1858 | // Function: i2Write2Fifo(pB,address,count) | ||
1859 | // Parameters: Pointer to a board structure, source address, byte count | ||
1860 | // Returns: bytes written | ||
1861 | // | ||
1862 | // Description: | ||
1863 | // Writes count bytes to board io address(implied) from source | ||
1864 | // Adjusts count, leaves reserve for next time around bypass cmds | ||
1865 | //****************************************************************************** | ||
1866 | static int | ||
1867 | i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve) | ||
1868 | { | ||
1869 | int rc = 0; | ||
1870 | unsigned long flags; | ||
1871 | WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); | ||
1872 | if (!pB->i2eWaitingForEmptyFifo) { | ||
1873 | if (pB->i2eFifoRemains > (count+reserve)) { | ||
1874 | pB->i2eFifoRemains -= count; | ||
1875 | iiWriteBuf(pB, source, count); | ||
1876 | pB->i2eOutMailWaiting |= MB_OUT_STUFFED; | ||
1877 | rc = count; | ||
1878 | } | ||
1879 | } | ||
1880 | WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); | ||
1881 | return rc; | ||
1882 | } | ||
1883 | //****************************************************************************** | ||
1884 | // Function: i2StuffFifoBypass(pB) | ||
1885 | // Parameters: Pointer to a board structure | ||
1886 | // Returns: Nothing | ||
1887 | // | ||
1888 | // Description: | ||
1889 | // Stuffs as many bypass commands into the fifo as possible. This is simpler | ||
1890 | // than stuffing data or inline commands to fifo, since we do not have | ||
1891 | // flow-control to deal with. | ||
1892 | //****************************************************************************** | ||
1893 | static inline void | ||
1894 | i2StuffFifoBypass(i2eBordStrPtr pB) | ||
1895 | { | ||
1896 | i2ChanStrPtr pCh; | ||
1897 | unsigned char *pRemove; | ||
1898 | unsigned short stripIndex; | ||
1899 | unsigned short packetSize; | ||
1900 | unsigned short paddedSize; | ||
1901 | unsigned short notClogged = 1; | ||
1902 | unsigned long flags; | ||
1903 | |||
1904 | int bailout = 1000; | ||
1905 | |||
1906 | // Continue processing so long as there are entries, or there is room in the | ||
1907 | // fifo. Each entry represents a channel with something to do. | ||
1908 | while ( --bailout && notClogged && | ||
1909 | (NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS)))) | ||
1910 | { | ||
1911 | WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags); | ||
1912 | stripIndex = pCh->Cbuf_strip; | ||
1913 | |||
1914 | // as long as there are packets for this channel... | ||
1915 | |||
1916 | while (stripIndex != pCh->Cbuf_stuff) { | ||
1917 | pRemove = &(pCh->Cbuf[stripIndex]); | ||
1918 | packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader); | ||
1919 | paddedSize = ROUNDUP(packetSize); | ||
1920 | |||
1921 | if (paddedSize > 0) { | ||
1922 | if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) { | ||
1923 | notClogged = 0; /* fifo full */ | ||
1924 | i2QueueNeeds(pB, pCh, NEED_BYPASS); // Put back on queue | ||
1925 | break; // Break from the channel | ||
1926 | } | ||
1927 | } | ||
1928 | #ifdef DEBUG_FIFO | ||
1929 | WriteDBGBuf("BYPS", pRemove, paddedSize); | ||
1930 | #endif /* DEBUG_FIFO */ | ||
1931 | pB->debugBypassCount++; | ||
1932 | |||
1933 | pRemove += packetSize; | ||
1934 | stripIndex += packetSize; | ||
1935 | if (stripIndex >= CBUF_SIZE) { | ||
1936 | stripIndex = 0; | ||
1937 | pRemove = pCh->Cbuf; | ||
1938 | } | ||
1939 | } | ||
1940 | // Done with this channel. Move to next, removing this one from | ||
1941 | // the queue of channels if we cleaned it out (i.e., didn't get clogged. | ||
1942 | pCh->Cbuf_strip = stripIndex; | ||
1943 | WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); | ||
1944 | } // Either clogged or finished all the work | ||
1945 | |||
1946 | #ifdef IP2DEBUG_TRACE | ||
1947 | if ( !bailout ) { | ||
1948 | ip2trace (ITRC_NO_PORT, ITRC_ERROR, 1, 0 ); | ||
1949 | } | ||
1950 | #endif | ||
1951 | } | ||
1952 | |||
1953 | //****************************************************************************** | ||
1954 | // Function: i2StuffFifoFlow(pB) | ||
1955 | // Parameters: Pointer to a board structure | ||
1956 | // Returns: Nothing | ||
1957 | // | ||
1958 | // Description: | ||
1959 | // Stuffs as many flow control packets into the fifo as possible. This is easier | ||
1960 | // even than doing normal bypass commands, because there is always at most one | ||
1961 | // packet, already assembled, for each channel. | ||
1962 | //****************************************************************************** | ||
1963 | static inline void | ||
1964 | i2StuffFifoFlow(i2eBordStrPtr pB) | ||
1965 | { | ||
1966 | i2ChanStrPtr pCh; | ||
1967 | unsigned short paddedSize = ROUNDUP(sizeof(flowIn)); | ||
1968 | |||
1969 | ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2, | ||
1970 | pB->i2eFifoRemains, paddedSize ); | ||
1971 | |||
1972 | // Continue processing so long as there are entries, or there is room in the | ||
1973 | // fifo. Each entry represents a channel with something to do. | ||
1974 | while ( (NULL != (pCh = i2DeQueueNeeds(pB,NEED_FLOW)))) { | ||
1975 | pB->debugFlowCount++; | ||
1976 | |||
1977 | // NO Chan LOCK needed ??? | ||
1978 | if ( 0 == i2Write2Fifo(pB,(unsigned char *)&(pCh->infl),paddedSize,0)) { | ||
1979 | break; | ||
1980 | } | ||
1981 | #ifdef DEBUG_FIFO | ||
1982 | WriteDBGBuf("FLOW",(unsigned char *) &(pCh->infl), paddedSize); | ||
1983 | #endif /* DEBUG_FIFO */ | ||
1984 | |||
1985 | } // Either clogged or finished all the work | ||
1986 | |||
1987 | ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_RETURN, 0 ); | ||
1988 | } | ||
1989 | |||
1990 | //****************************************************************************** | ||
1991 | // Function: i2StuffFifoInline(pB) | ||
1992 | // Parameters: Pointer to a board structure | ||
1993 | // Returns: Nothing | ||
1994 | // | ||
1995 | // Description: | ||
1996 | // Stuffs as much data and inline commands into the fifo as possible. This is | ||
1997 | // the most complex fifo-stuffing operation, since there if now the channel | ||
1998 | // flow-control issue to deal with. | ||
1999 | //****************************************************************************** | ||
2000 | static inline void | ||
2001 | i2StuffFifoInline(i2eBordStrPtr pB) | ||
2002 | { | ||
2003 | i2ChanStrPtr pCh; | ||
2004 | unsigned char *pRemove; | ||
2005 | unsigned short stripIndex; | ||
2006 | unsigned short packetSize; | ||
2007 | unsigned short paddedSize; | ||
2008 | unsigned short notClogged = 1; | ||
2009 | unsigned short flowsize; | ||
2010 | unsigned long flags; | ||
2011 | |||
2012 | int bailout = 1000; | ||
2013 | int bailout2; | ||
2014 | |||
2015 | ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_ENTER, 3, pB->i2eFifoRemains, | ||
2016 | pB->i2Dbuf_strip, pB->i2Dbuf_stuff ); | ||
2017 | |||
2018 | // Continue processing so long as there are entries, or there is room in the | ||
2019 | // fifo. Each entry represents a channel with something to do. | ||
2020 | while ( --bailout && notClogged && | ||
2021 | (NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) ) | ||
2022 | { | ||
2023 | WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); | ||
2024 | stripIndex = pCh->Obuf_strip; | ||
2025 | |||
2026 | ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff ); | ||
2027 | |||
2028 | // as long as there are packets for this channel... | ||
2029 | bailout2 = 1000; | ||
2030 | while ( --bailout2 && stripIndex != pCh->Obuf_stuff) { | ||
2031 | pRemove = &(pCh->Obuf[stripIndex]); | ||
2032 | |||
2033 | // Must determine whether this be a data or command packet to | ||
2034 | // calculate correctly the header size and the amount of | ||
2035 | // flow-control credit this type of packet will use. | ||
2036 | if (PTYPE_OF(pRemove) == PTYPE_DATA) { | ||
2037 | flowsize = DATA_COUNT_OF(pRemove); | ||
2038 | packetSize = flowsize + sizeof(i2DataHeader); | ||
2039 | } else { | ||
2040 | flowsize = CMD_COUNT_OF(pRemove); | ||
2041 | packetSize = flowsize + sizeof(i2CmdHeader); | ||
2042 | } | ||
2043 | flowsize = CREDIT_USAGE(flowsize); | ||
2044 | paddedSize = ROUNDUP(packetSize); | ||
2045 | |||
2046 | ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize ); | ||
2047 | |||
2048 | // If we don't have enough credits from the board to send the data, | ||
2049 | // flag the channel that we are waiting for flow control credit, and | ||
2050 | // break out. This will clean up this channel and remove us from the | ||
2051 | // queue of hot things to do. | ||
2052 | |||
2053 | ip2trace (CHANN, ITRC_SICMD, 5, 2, pCh->outfl.room, flowsize ); | ||
2054 | |||
2055 | if (pCh->outfl.room <= flowsize) { | ||
2056 | // Do Not have the credits to send this packet. | ||
2057 | i2QueueNeeds(pB, pCh, NEED_CREDIT); | ||
2058 | notClogged = 0; | ||
2059 | break; // So to do next channel | ||
2060 | } | ||
2061 | if ( (paddedSize > 0) | ||
2062 | && ( 0 == i2Write2Fifo(pB, pRemove, paddedSize, 128))) { | ||
2063 | // Do Not have room in fifo to send this packet. | ||
2064 | notClogged = 0; | ||
2065 | i2QueueNeeds(pB, pCh, NEED_INLINE); | ||
2066 | break; // Break from the channel | ||
2067 | } | ||
2068 | #ifdef DEBUG_FIFO | ||
2069 | WriteDBGBuf("DATA", pRemove, paddedSize); | ||
2070 | #endif /* DEBUG_FIFO */ | ||
2071 | pB->debugInlineCount++; | ||
2072 | |||
2073 | pCh->icount.tx += flowsize; | ||
2074 | // Update current credits | ||
2075 | pCh->outfl.room -= flowsize; | ||
2076 | pCh->outfl.asof += flowsize; | ||
2077 | if (PTYPE_OF(pRemove) == PTYPE_DATA) { | ||
2078 | pCh->Obuf_char_count -= DATA_COUNT_OF(pRemove); | ||
2079 | } | ||
2080 | pRemove += packetSize; | ||
2081 | stripIndex += packetSize; | ||
2082 | |||
2083 | ip2trace (CHANN, ITRC_SICMD, 6, 2, stripIndex, pCh->Obuf_strip); | ||
2084 | |||
2085 | if (stripIndex >= OBUF_SIZE) { | ||
2086 | stripIndex = 0; | ||
2087 | pRemove = pCh->Obuf; | ||
2088 | |||
2089 | ip2trace (CHANN, ITRC_SICMD, 7, 1, stripIndex ); | ||
2090 | |||
2091 | } | ||
2092 | } /* while */ | ||
2093 | if ( !bailout2 ) { | ||
2094 | ip2trace (CHANN, ITRC_ERROR, 3, 0 ); | ||
2095 | } | ||
2096 | // Done with this channel. Move to next, removing this one from the | ||
2097 | // queue of channels if we cleaned it out (i.e., didn't get clogged. | ||
2098 | pCh->Obuf_strip = stripIndex; | ||
2099 | WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); | ||
2100 | if ( notClogged ) | ||
2101 | { | ||
2102 | |||
2103 | ip2trace (CHANN, ITRC_SICMD, 8, 0 ); | ||
2104 | |||
2105 | if ( pCh->pTTY ) { | ||
2106 | ip2_owake(pCh->pTTY); | ||
2107 | } | ||
2108 | } | ||
2109 | } // Either clogged or finished all the work | ||
2110 | |||
2111 | if ( !bailout ) { | ||
2112 | ip2trace (ITRC_NO_PORT, ITRC_ERROR, 4, 0 ); | ||
2113 | } | ||
2114 | |||
2115 | ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_RETURN, 1,pB->i2Dbuf_strip); | ||
2116 | } | ||
2117 | |||
2118 | //****************************************************************************** | ||
2119 | // Function: serviceOutgoingFifo(pB) | ||
2120 | // Parameters: Pointer to a board structure | ||
2121 | // Returns: Nothing | ||
2122 | // | ||
2123 | // Description: | ||
2124 | // Helper routine to put data in the outgoing fifo, if we aren't already waiting | ||
2125 | // for something to be there. If the fifo has only room for a very little data, | ||
2126 | // go head and hit the board with a mailbox hit immediately. Otherwise, it will | ||
2127 | // have to happen later in the interrupt processing. Since this routine may be | ||
2128 | // called both at interrupt and foreground time, we must turn off interrupts | ||
2129 | // during the entire process. | ||
2130 | //****************************************************************************** | ||
2131 | static void | ||
2132 | serviceOutgoingFifo(i2eBordStrPtr pB) | ||
2133 | { | ||
2134 | // If we aren't currently waiting for the board to empty our fifo, service | ||
2135 | // everything that is pending, in priority order (especially, Bypass before | ||
2136 | // Inline). | ||
2137 | if ( ! pB->i2eWaitingForEmptyFifo ) | ||
2138 | { | ||
2139 | i2StuffFifoFlow(pB); | ||
2140 | i2StuffFifoBypass(pB); | ||
2141 | i2StuffFifoInline(pB); | ||
2142 | |||
2143 | iiSendPendingMail(pB); | ||
2144 | } | ||
2145 | } | ||
2146 | |||
2147 | //****************************************************************************** | ||
2148 | // Function: i2ServiceBoard(pB) | ||
2149 | // Parameters: Pointer to a board structure | ||
2150 | // Returns: Nothing | ||
2151 | // | ||
2152 | // Description: | ||
2153 | // Normally this is called from interrupt level, but there is deliberately | ||
2154 | // nothing in here specific to being called from interrupt level. All the | ||
2155 | // hardware-specific, interrupt-specific things happen at the outer levels. | ||
2156 | // | ||
2157 | // For example, a timer interrupt could drive this routine for some sort of | ||
2158 | // polled operation. The only requirement is that the programmer deal with any | ||
2159 | // atomiticity/concurrency issues that result. | ||
2160 | // | ||
2161 | // This routine responds to the board's having sent mailbox information to the | ||
2162 | // host (which would normally cause an interrupt). This routine reads the | ||
2163 | // incoming mailbox. If there is no data in it, this board did not create the | ||
2164 | // interrupt and/or has nothing to be done to it. (Except, if we have been | ||
2165 | // waiting to write mailbox data to it, we may do so. | ||
2166 | // | ||
2167 | // Based on the value in the mailbox, we may take various actions. | ||
2168 | // | ||
2169 | // No checking here of pB validity: after all, it shouldn't have been called by | ||
2170 | // the handler unless pB were on the list. | ||
2171 | //****************************************************************************** | ||
2172 | static inline int | ||
2173 | i2ServiceBoard ( i2eBordStrPtr pB ) | ||
2174 | { | ||
2175 | unsigned inmail; | ||
2176 | unsigned long flags; | ||
2177 | |||
2178 | |||
2179 | /* This should be atomic because of the way we are called... */ | ||
2180 | if (NO_MAIL_HERE == ( inmail = pB->i2eStartMail ) ) { | ||
2181 | inmail = iiGetMail(pB); | ||
2182 | } | ||
2183 | pB->i2eStartMail = NO_MAIL_HERE; | ||
2184 | |||
2185 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 2, 1, inmail ); | ||
2186 | |||
2187 | if (inmail != NO_MAIL_HERE) { | ||
2188 | // If the board has gone fatal, nothing to do but hit a bit that will | ||
2189 | // alert foreground tasks to protest! | ||
2190 | if ( inmail & MB_FATAL_ERROR ) { | ||
2191 | pB->i2eFatal = 1; | ||
2192 | goto exit_i2ServiceBoard; | ||
2193 | } | ||
2194 | |||
2195 | /* Assuming no fatal condition, we proceed to do work */ | ||
2196 | if ( inmail & MB_IN_STUFFED ) { | ||
2197 | pB->i2eFifoInInts++; | ||
2198 | i2StripFifo(pB); /* There might be incoming packets */ | ||
2199 | } | ||
2200 | |||
2201 | if (inmail & MB_OUT_STRIPPED) { | ||
2202 | pB->i2eFifoOutInts++; | ||
2203 | WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); | ||
2204 | pB->i2eFifoRemains = pB->i2eFifoSize; | ||
2205 | pB->i2eWaitingForEmptyFifo = 0; | ||
2206 | WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); | ||
2207 | |||
2208 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains ); | ||
2209 | |||
2210 | } | ||
2211 | serviceOutgoingFifo(pB); | ||
2212 | } | ||
2213 | |||
2214 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 8, 0 ); | ||
2215 | |||
2216 | exit_i2ServiceBoard: | ||
2217 | |||
2218 | return 0; | ||
2219 | } | ||