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