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