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