Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / ihfc / i4b_ihfc_l1if.c
1 /*
2  * Copyright (c) 2000 Hans Petter Selasky. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_ihfc_l1.c - hfc layer 1 handler
28  *      -----------------------------------
29  *
30  *      The idea of this file is to separate hfcs/sp/pci data/signal
31  *      handling and the I4B data/signal handling.
32  *
33  *      Everything which has got anything to do with I4B has been put here!
34  *
35  *      last edit-date: [Wed Jul 19 09:41:03 2000]
36  *
37  *      $Id: i4b_ihfc_l1if.c,v 1.10 2000/09/19 13:50:36 hm Exp $
38  *
39  * $FreeBSD: src/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c,v 1.7.2.1 2001/08/10 14:08:37 obrien Exp $
40  *
41  *---------------------------------------------------------------------------*/
42
43 #include "ihfc.h"
44
45 #if (NIHFC > 0)
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/mbuf.h>
51 #include <sys/socket.h>
52
53
54 #include <net/if.h>
55
56 #include <machine/i4b_debug.h>
57 #include <machine/i4b_ioctl.h>
58 #include <machine/i4b_trace.h>
59
60 #include <i4b/include/i4b_mbuf.h>
61 #include <i4b/include/i4b_global.h>
62
63 #include <i4b/layer1/i4b_l1.h>
64 #include <i4b/layer1/ihfc/i4b_ihfc.h>
65 #include <i4b/layer1/ihfc/i4b_ihfc_ext.h>
66
67 /*---------------------------------------------------------------------------*
68  *      Local prototypes
69  *
70  *      NOTE: The prototypes for get/putmbuf and B_linkinit 
71  *              have been put in i4b_hfc_ext.h for global hfc use.
72  *
73  *      NOTE: channel != chan
74  *---------------------------------------------------------------------------*/
75 static
76 isdn_link_t   * ihfc_B_ret_linktab   (int unit, int channel);
77 static  void    ihfc_B_set_linktab   (int unit, int channel, drvr_link_t *B_linktab);
78
79 static  void    ihfc_B_start         (int unit, int chan);
80 static  void    ihfc_B_stat          (int unit, int chan, bchan_statistics_t *bsp);
81         void    ihfc_B_setup         (int unit, int chan, int bprot, int activate);
82
83 static  int     ihfc_mph_command_req (int unit, int command, void *parm);
84
85 static  int     ihfc_ph_activate_req (int unit);
86 static  int     ihfc_ph_data_req     (int unit, struct mbuf *m, int freeflag);
87
88 static  void    ihfc_T3_expired      (ihfc_sc_t *sc);
89
90 /*---------------------------------------------------------------------------*
91  *      Our I4B L1 mulitplexer link
92  *---------------------------------------------------------------------------*/
93 struct i4b_l1mux_func ihfc_l1mux_func = {
94         ihfc_B_ret_linktab,
95         ihfc_B_set_linktab,
96         ihfc_mph_command_req,
97         ihfc_ph_data_req,
98         ihfc_ph_activate_req,
99 };
100
101 /*---------------------------------------------------------------------------*
102  *      L2 -> L1: PH-DATA-REQUEST (D-Channel)
103  *
104  *      NOTE: We may get called here from ihfc_hdlc_Dread or isac_hdlc_Dread
105  *      via the upper layers.
106  *---------------------------------------------------------------------------*/
107 int
108 ihfc_ph_data_req(int unit, struct mbuf *m, int freeflag)
109 {
110         ihfc_sc_t *sc = &ihfc_softc[unit];
111         u_char chan = 0;
112         HFC_VAR;
113
114         if (!m) return 0;
115
116         HFC_BEG;
117
118         if(S_PHSTATE != 3)
119         {
120                 NDBGL1(L1_PRIM, "L1 was not running: "
121                         "ihfc_ph_activate_req(unit = %d)!", unit);
122
123                         ihfc_ph_activate_req(unit);
124         }
125
126         /* "Allow" I-frames (-hp) */
127
128         if (freeflag == MBUF_DONTFREE)  m = m_copypacket(m, M_DONTWAIT);
129
130         if (!_IF_QFULL(&S_IFQUEUE) && m)
131         {
132                 IF_ENQUEUE(&S_IFQUEUE, m);
133
134                 ihfc_B_start(unit, chan);       /* (recycling) */
135         }
136         else
137         {
138                 NDBGL1(L1_ERROR, "No frame out (unit = %d)", unit);
139                 if (m) i4b_Dfreembuf(m);
140
141                 HFC_END;
142                 return 0;
143         }
144
145         if (S_INTR_ACTIVE) S_INT_S1 |= 0x04;
146
147         HFC_END;
148
149         return 1;
150 }
151
152 /*---------------------------------------------------------------------------*
153  *      L2 -> L1: PH-ACTIVATE-REQUEST (B-channel and D-channel)
154  *---------------------------------------------------------------------------*/
155 int
156 ihfc_ph_activate_req(int unit)
157 {
158         ihfc_sc_t *sc = &ihfc_softc[unit];
159         HFC_VAR;
160
161         HFC_BEG;
162
163         if ((!S_STM_T3) && (S_PHSTATE != 3))
164         {
165                 HFC_FSM(sc, 1);
166
167                 S_STM_T3 = 1;
168                 S_STM_T3CALLOUT = timeout((TIMEOUT_FUNC_T)
169                                         ihfc_T3_expired, (ihfc_sc_t *)sc,
170                                         IHFC_ACTIVATION_TIMEOUT);
171         }
172
173         HFC_END;
174         return 0;
175 }
176 /*---------------------------------------------------------------------------*
177  *      T3 timeout - persistant deactivation
178  *---------------------------------------------------------------------------*/
179 void
180 ihfc_T3_expired(ihfc_sc_t *sc)
181 {
182         u_char chan = 0;
183         HFC_VAR;
184
185         HFC_BEG;
186
187         S_STM_T3 = 0;
188
189         if (S_PHSTATE != 3)     /* line was not activated */
190         {
191                 i4b_Dcleanifq(&S_IFQUEUE);
192                 i4b_l1_ph_deactivate_ind(S_I4BUNIT);
193
194                 i4b_l1_mph_status_ind(S_I4BUNIT, STI_PDEACT, 0, 0);
195
196                 HFC_FSM(sc, 2);         /* L1 deactivate */
197         }
198
199         HFC_END;
200 }
201
202 /*---------------------------------------------------------------------------*
203  *      Command from the upper layers (B-channel and D-channel)
204  *---------------------------------------------------------------------------*/
205 int
206 ihfc_mph_command_req(int unit, int command, void *parm)
207 {
208         ihfc_sc_t *sc = &ihfc_softc[unit];
209
210         switch(command)
211         {
212                 case CMR_DOPEN:         /* daemon running */
213                         NDBGL1(L1_PRIM,
214                                 "unit %d, command = CMR_DOPEN", unit);
215                         S_ENABLED = 1;
216                         break;
217                         
218                 case CMR_DCLOSE:        /* daemon not running */
219                         NDBGL1(L1_PRIM,
220                                 "unit %d, command = CMR_DCLOSE", unit);
221                         S_ENABLED = 0;
222                         break;
223
224                 case CMR_SETTRACE:      /* set new trace mask */
225                         NDBGL1(L1_PRIM,
226                                 "unit %d, command = CMR_SETTRACE, parm = %d",
227                                 unit, (unsigned int)parm);
228                         S_TRACE = (unsigned int)parm;
229                         break;
230
231                 case CMR_GCST:          /* get chip statistic */
232                         NDBGL1(L1_PRIM,
233                                 "unit %d, command = CMR_GCST, parm = %d",
234                                 unit, (unsigned int)parm);
235
236                         #define CST ((struct chipstat *)parm)
237
238                         CST->driver_type = L1DRVR_IHFC;
239
240                         /* XXX CST->xxxx_stat = xxx; */
241
242                         #undef CST
243                         break;
244
245                 default:
246                         NDBGL1(L1_ERROR, 
247                                 "ERROR, unknown command = %d, unit = %d, parm = %d",
248                                 command, unit, (unsigned int)parm);
249                         break;
250         }
251
252         return 0;
253 }
254
255 /*---------------------------------------------------------------------------*
256  *      Data source switch for Read channels - 1, 3 and 5 (B and D-Channel)
257  *---------------------------------------------------------------------------*/
258 void
259 ihfc_putmbuf (ihfc_sc_t *sc, u_char chan, struct mbuf *m)
260 {
261         i4b_trace_hdr_t hdr;
262
263         if (chan < 2)
264         {
265                 if(S_TRACE & TRACE_D_RX)
266                 {
267                         hdr.count = ++S_DTRACECOUNT;
268                         hdr.dir   = FROM_NT;
269                         hdr.type  = TRC_CH_D;
270                         hdr.unit  = S_I4BUNIT;
271
272                         MICROTIME(hdr.time);
273
274                         i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
275                 }
276
277                 if (!S_ENABLED) { i4b_Dfreembuf(m); return; }
278
279                 m->m_pkthdr.len = m->m_len;
280         
281                 i4b_l1_ph_data_ind(S_I4BUNIT, m);
282         }
283         else
284         {
285                 if(S_TRACE & TRACE_B_RX)
286                 {
287                         hdr.count = ++S_BTRACECOUNT;
288                         hdr.dir   = FROM_NT;
289                         hdr.type  = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2;
290                         hdr.unit  = S_I4BUNIT;
291
292                         MICROTIME(hdr.time);
293
294                         i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
295                 }
296
297                 if (!S_ENABLED) { i4b_Bfreembuf(m); return; }
298
299                 if (S_PROT == BPROT_NONE)
300                 {
301                         if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len))
302                         {
303                                 S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_RX);
304                         }
305
306                         if (!_IF_QFULL(&S_IFQUEUE))
307                         {
308                                 S_BYTES += m->m_len;
309                                 IF_ENQUEUE(&S_IFQUEUE, m);
310                                 S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit);
311                         }
312
313                         return;
314                 }
315
316                 if (S_PROT == BPROT_RHDLC)
317                 {
318                         S_MBUFDUMMY = m;
319                         S_BYTES    += m->m_pkthdr.len = m->m_len;
320                         S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit);
321                         S_MBUFDUMMY = NULL;
322
323                         return;
324                 }
325
326                 NDBGL1(L1_ERROR, "Unknown protocol: %d", S_PROT);
327         }
328 }
329
330 /*---------------------------------------------------------------------------*
331  *      Data destinator switch for write channels - 0, 2 and 4
332  *---------------------------------------------------------------------------*/
333 struct mbuf *
334 ihfc_getmbuf (ihfc_sc_t *sc, u_char chan)
335 {
336         register struct mbuf  *m;
337         i4b_trace_hdr_t hdr;
338
339         if (chan < 2)
340         {
341                 IF_DEQUEUE(&S_IFQUEUE, m);
342
343                 if((S_TRACE & TRACE_D_TX) && m)
344                 {
345                         hdr.count = ++S_DTRACECOUNT;
346                         hdr.dir   = FROM_TE;
347                         hdr.type  = TRC_CH_D;
348                         hdr.unit  = S_I4BUNIT;
349
350                         MICROTIME(hdr.time);
351
352                         i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
353                 }
354         }
355         else
356         {
357                 IF_DEQUEUE(&S_IFQUEUE, m);
358
359                 if (!m)
360                 {
361                         S_BDRVLINK->bch_tx_queue_empty(S_BDRVLINK->unit);
362
363                         IF_DEQUEUE(&S_IFQUEUE, m);
364                 }
365                 if (m)
366                 {
367                         if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len))
368                         {
369                                 S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_TX);
370                         }
371
372                         S_BYTES += m->m_len;
373
374                         if(S_TRACE & TRACE_B_TX)
375                         {
376                                 hdr.count = ++S_BTRACECOUNT;
377                                 hdr.dir   = FROM_TE;
378                                 hdr.type  = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2;
379                                 hdr.unit  = S_I4BUNIT;
380
381                                 MICROTIME(hdr.time);
382
383                                 i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
384                         }
385                 }
386         }
387
388         return(m);
389 }
390
391 /*---------------------------------------------------------------------------*
392  *      Initialize rx/tx data structures (B-channel)
393  *---------------------------------------------------------------------------*/
394 void
395 ihfc_B_setup(int unit, int chan, int bprot, int activate)
396 {
397         ihfc_sc_t *sc = &ihfc_softc[unit];
398         HFC_VAR;
399
400         if (((u_int)chan > 5) || ((u_int)chan < 2)) return;
401
402         HFC_BEG;
403
404         HFC_INIT(sc, chan, bprot, activate);
405
406         HFC_END;
407 }
408
409 /*---------------------------------------------------------------------------*
410  *      Start transmission (B-channel or D-channel tx)
411  *      NOTE: if "chan" variable is corrupted, it will not cause any harm,
412  *      but data may be lost and there may be software sync. errors.
413  *---------------------------------------------------------------------------*/
414 void
415 ihfc_B_start(int unit, int chan)
416 {
417         ihfc_sc_t *sc = &ihfc_softc[unit];
418         HFC_VAR;
419
420         if ((u_int)chan > 5) return;
421
422         HFC_BEG;
423
424         if (S_FILTER && !S_MBUF && !S_INTR_ACTIVE)
425         {
426                 S_INTR_ACTIVE |= 2;     /* never know what *
427                                          * they put in the *
428                                          * L2 code         */
429
430                 S_FILTER(sc, chan);     /* quick tx */
431
432                 S_INTR_ACTIVE &= ~2;
433         }
434
435         HFC_END;
436 }
437
438 /*---------------------------------------------------------------------------*
439  *      Fill statistics struct (B-channel)
440  *---------------------------------------------------------------------------*/
441 void
442 ihfc_B_stat(int unit, int chan, bchan_statistics_t *bsp)
443 {
444         ihfc_sc_t *sc = &ihfc_softc[unit];
445         HFC_VAR;
446
447         if ((u_int)chan > 5) return;
448
449         chan &= ~1;
450
451         HFC_BEG;
452
453         bsp->inbytes  = S_BYTES; S_BYTES = 0;
454
455         chan++;
456
457         bsp->outbytes = S_BYTES; S_BYTES = 0;
458
459         HFC_END;
460 }
461
462 /*---------------------------------------------------------------------------*
463  *      Return the address of IHFC linktab to I4B (B-channel)
464  *---------------------------------------------------------------------------*/
465 isdn_link_t *
466 ihfc_B_ret_linktab(int unit, int channel)
467 {
468         ihfc_sc_t *sc = &ihfc_softc[unit];
469
470         if (channel < 2)
471                 return(&sc->sc_blinktab[channel]);
472         else
473                 return 0;
474 }
475  
476 /*---------------------------------------------------------------------------*
477  *      Set the I4B driver linktab for IHFC use (B-channel)
478  *---------------------------------------------------------------------------*/
479 void
480 ihfc_B_set_linktab(int unit, int channel, drvr_link_t *B_linktab)
481 {
482         ihfc_sc_t *sc = &ihfc_softc[unit];
483
484         if (channel < 2)
485                 sc->sc_bdrvlinktab[channel] = B_linktab;
486 }
487
488 /*---------------------------------------------------------------------------*
489  *      Initialize linktab for I4B use (B-channel)
490  *---------------------------------------------------------------------------*/
491 void
492 ihfc_B_linkinit(ihfc_sc_t *sc)
493 {
494         u_char chan;
495
496         /* make sure the hardware driver is known to layer 4 */
497         ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab;
498         ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_ret_linktab;
499
500         for (chan = 2; chan < 6; chan++)
501         {
502                 S_BLINK.unit          = S_UNIT;
503                 S_BLINK.channel       = chan;           /* point to tx-chan */
504                 S_BLINK.bch_config    = ihfc_B_setup;
505                 S_BLINK.bch_tx_start  = ihfc_B_start;
506                 S_BLINK.bch_stat      = ihfc_B_stat;
507                 
508                 /* This is a transmit channel (even) */
509                 S_BLINK.tx_queue   = &S_IFQUEUE;
510                 chan++;
511                 /* This is a receive channel (odd) */
512                 S_BLINK.rx_queue   = &S_IFQUEUE;
513                 S_BLINK.rx_mbuf    = &S_MBUFDUMMY;
514         }
515 }
516
517 #endif /* NIHFC > 0 */