Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / ihfc / i4b_ihfc_pnp.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_pnp.c - common hfc ISA PnP-bus interface
28  *      -------------------------------------------------
29  *
30  *      - Everything which has got anything to to with "PnP" bus setup has
31  *        been put here, except the chip spesific "PnP" setup.
32  *
33  *
34  *      last edit-date: [Tue Jan 23 16:03:33 2001]
35  *
36  *      $Id: i4b_ihfc_pnp.c,v 1.9 2000/09/19 13:50:36 hm Exp $
37  *
38  * $FreeBSD: src/sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c,v 1.5.2.1 2001/08/10 14:08:37 obrien Exp $
39  *     
40  *---------------------------------------------------------------------------*/
41
42 #include "ihfc.h"
43
44 #if (NIHFC > 0)
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/socket.h>
50 #include <net/if.h>
51
52
53 #include <i4b/include/i4b_global.h>
54
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_trace.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 #include <machine/bus.h>
63 #include <machine/resource.h>
64 #include <sys/bus.h>
65 #include <sys/rman.h>
66
67 #include <isa/isavar.h>
68
69 /*---------------------------------------------------------------------------*
70  *      Softc
71  *---------------------------------------------------------------------------*/
72 ihfc_sc_t               ihfc_softc[IHFC_MAXUNIT];
73
74 /*---------------------------------------------------------------------------*
75  *      Prototypes
76  *---------------------------------------------------------------------------*/
77 static int ihfc_isa_probe       (device_t dev);
78 static int ihfc_pnp_probe       (device_t dev);
79 static int ihfc_pnp_attach      (device_t dev);
80 static int ihfc_pnp_detach      (device_t dev, u_int flag);
81 static int ihfc_pnp_shutdown    (device_t dev);
82
83 const struct ihfc_pnp_ids
84 {
85         u_long  vid;            /* vendor id                    */
86         int     flag;           /*                              */
87         u_char  hfc;            /* chip type                    */
88         u_char  iirq;           /* internal irq                 */
89         u_short iio;            /* internal io-address          */
90         u_char  stdel;          /* S/T delay compensation       */
91 }
92         ihfc_pnp_ids[] =
93 {
94         { 0x10262750, CARD_TYPEP_16_3C,   HFC_S,  2, 0x200, 0x2d},
95         { 0x20262750, CARD_TYPEP_16_3C,   HFC_SP, 0, 0x000, 0x0f},
96         { 0x1411d805, CARD_TYPEP_ACERP10, HFC_S,  1, 0x300, 0x0e},
97         { 0 }
98 };
99
100 typedef const struct ihfc_pnp_ids ihfc_id_t;
101
102 /*---------------------------------------------------------------------------*
103  *      PCB layout
104  *
105  *      IIRQx: Internal IRQ cross reference for a card
106  *      IRQx : Supported IRQ's for a card
107  *      IOx  : Supported IO-bases for a card
108  *
109  *      IO0, IRQ0, IIRQ0: TELEINT ISDN SPEED No. 1
110  *                 IIRQ3: Teles 16.3c PnP (B version)
111  *---------------------------------------------------------------------------*/
112                       /* IRQ  ->  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
113 #define IIRQ0 ((const u_char []){ 0, 0, 0, 1, 2, 3, 0, 4, 0, 0, 5, 6, 0, 0, 0, 0 })
114 #define IRQ0  ((const u_char []){          3, 4, 5,    7,     0xa, 0xb, 0 })
115
116 #define IO0   ((const u_long []){ 0x300, 0x330, 0x278, 0x2e8, 0 })
117
118 #define IIRQ3 ((const u_char []){ 0, 0, 0, 7, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 0, 6 })
119
120 /*---------------------------------------------------------------------------*
121  *      ISA PnP setup
122  *---------------------------------------------------------------------------*/
123 static device_method_t ihfc_pnp_methods[] = 
124 {
125         DEVMETHOD(device_probe,         ihfc_pnp_probe),
126         DEVMETHOD(device_attach,        ihfc_pnp_attach),
127         DEVMETHOD(device_shutdown,      ihfc_pnp_shutdown),
128         { 0, 0 }
129 };                              
130
131 static driver_t ihfc_pnp_driver = 
132 {
133         "ihfc",
134         ihfc_pnp_methods,
135         0,
136 };
137
138 static devclass_t ihfc_devclass;
139
140 DRIVER_MODULE(ihfcpnp, isa, ihfc_pnp_driver, ihfc_devclass, 0, 0);
141
142 /*---------------------------------------------------------------------------*
143  *      probe for ISA "PnP" card
144  *---------------------------------------------------------------------------*/
145 int
146 ihfc_pnp_probe(device_t dev)
147 {
148         u_int          unit = device_get_unit(dev);     /* get unit       */
149         u_int32_t       vid = isa_get_vendorid(dev);    /* vendor id      */
150         ihfc_id_t      *ids = &ihfc_pnp_ids[0];         /* ids ptr        */
151         ihfc_sc_t       *sc = &ihfc_softc[unit];        /* softc          */
152         u_char         flag = 0;                        /* flag           */
153         void         *dummy = 0;                        /* a dummy        */
154
155         HFC_VAR;
156
157         if (unit >= IHFC_MAXUNIT)
158         {
159                 printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
160                 return ENXIO;
161         }
162
163         if (!vid) return ihfc_isa_probe(dev);
164
165         HFC_BEG;
166
167         for ( ;(ids->vid); ids++)
168         {
169                 if (ids->vid == vid)
170                 {
171                         flag = 0;
172
173                         bzero(sc, sizeof(ihfc_sc_t));           /* reset data structure.*
174                                                                  * Zero is default for  *
175                                                                  * most, so calling the *
176                                                                  * int. handler now will*
177                                                                  * not be a problem.    */
178
179                         S_IOBASE[0] = bus_alloc_resource(
180                                 dev, SYS_RES_IOPORT, &S_IORID[0],
181                                 0UL, ~0UL, 2, RF_ACTIVE
182                                 );
183
184                         S_IRQ = bus_alloc_resource(
185                                 dev, SYS_RES_IRQ, &S_IRQRID,
186                                 0UL, ~0UL, 1, RF_ACTIVE
187                                 );
188
189                         S_DLP     = IHFC_DLP;           /* set D-priority       */
190                         S_HFC     = ids->hfc;           /* set chip type        */
191                         S_I4BFLAG = ids->flag;          /* set flag             */
192                         S_NTMODE  = IHFC_NTMODE;        /* set mode             */
193                         S_STDEL   = ids->stdel;         /* set delay            */
194
195                         S_I4BUNIT = L0IHFCUNIT(unit);   /* set "i4b" unit       */
196                         S_TRACE   = TRACE_OFF;          /* set trace mask       */
197                         S_UNIT    = unit;               /* set up unit numbers  */
198
199                         if (S_IOBASE[0] && S_IRQ)
200                         {
201                                 if (ids->iio)
202                                 {
203                                         S_IIO  = ids->iio;
204                                         S_IIRQ = ids->iirq;
205                                 }
206                                 else
207                                 {
208                                         S_IIO  = rman_get_start(S_IOBASE[0]) & 0x3ff;
209                                         S_IIRQ = IIRQ3[rman_get_start(S_IRQ) & 0xf];
210                                 }
211
212                                 /* setup interrupt routine now to avvoid stray  *
213                                  * interrupts.                                  */
214
215                                 bus_setup_intr(dev, S_IRQ, INTR_TYPE_NET, (void(*)(void*))
216                                         HFC_INTR, sc, &dummy);
217
218                                 flag = 1;
219
220                                 if (!HFC_CONTROL(sc, 1))
221                                 {
222                                         HFC_END;
223                                         return 0;       /* success */
224                                 }
225                                 else
226                                 {
227                                         printf("ihfc%d: Chip seems corrupted. "
228                                         "Please hard reboot your computer!\n",
229                                         unit);                                  
230                                 }
231                         }
232
233                         ihfc_pnp_detach(dev, flag);
234                 }
235         }
236
237         HFC_END;
238         return ENXIO;   /* failure */
239 }
240
241 /*---------------------------------------------------------------------------*
242  *      probe for "ISA" cards
243  *---------------------------------------------------------------------------*/
244 int
245 ihfc_isa_probe(device_t dev)
246 {
247         u_int           unit = device_get_unit(dev);    /* get unit       */
248         ihfc_sc_t        *sc = &ihfc_softc[unit];       /* softc          */
249         const u_char    *irq = &IRQ0[0];                /* irq's to try   */
250         const u_long *iobase = &IO0[0];                 /* iobases to try */
251         u_char          flag = 0;                       /* flag           */
252         void          *dummy = 0;                       /* a dummy        */
253
254         HFC_VAR;
255
256         bzero(sc, sizeof(ihfc_sc_t));           /* reset data structure  *
257                                                  * We must reset the     *
258                                                  * datastructure here,   *
259                                                  * else we risk zero-out *
260                                                  * our gotten resources. */
261         HFC_BEG;
262
263   j0:   while(*irq)     /* get supported IRQ */
264         {
265                 if ((S_IRQ = bus_alloc_resource(
266                         dev, SYS_RES_IRQ, &S_IRQRID,
267                         *irq, *irq, 1, RF_ACTIVE
268                         )
269                    ))
270                                 break;
271                 else
272                                 irq++;
273         }
274
275         while(*iobase)  /* get supported IO-PORT */
276         {
277                 if ((S_IOBASE[0] = bus_alloc_resource(
278                         dev, SYS_RES_IOPORT, &S_IORID[0],
279                         *iobase, *iobase, 2, RF_ACTIVE
280                         )
281                    ))
282                                 break;
283                 else
284                                 iobase++;
285         }
286
287         flag = 0;
288
289         if (*irq && *iobase)    /* we got our resources, now test chip */
290         {
291                 S_DLP     = IHFC_DLP;           /* set D-priority       */
292                 S_HFC     = HFC_1;              /* set chip type        */
293                 S_I4BFLAG = CARD_TYPEP_TELEINT_NO_1; /* set flag        */
294                 S_NTMODE  = IHFC_NTMODE;        /* set mode             */
295                 S_STDEL   = 0x00;               /* set delay (not used) */
296
297                 S_I4BUNIT = L0IHFCUNIT(unit);   /* set "i4b" unit       */
298                 S_TRACE   = TRACE_OFF;          /* set trace mask       */
299                 S_UNIT    = unit;               /* set up unit numbers  */
300
301                 S_IIRQ    = IIRQ0[*irq];        /* set internal irq     */
302                 S_IIO     = *iobase;            /* set internal iobase  */
303
304                 /* setup interrupt routine now to avvoid stray  *
305                  * interrupts.                                  */
306
307                 bus_setup_intr(dev, S_IRQ, INTR_TYPE_NET, (void(*)(void*))
308                         HFC_INTR, sc, &dummy);
309
310                 flag = 1;
311
312                 if (!HFC_CONTROL(sc, 1))
313                 {
314                         device_set_desc(dev, "TELEINT ISDN SPEED No. 1");
315
316                         HFC_END;
317                         return 0;       /* success */
318                 }
319         }
320
321         ihfc_pnp_detach(dev, flag);
322
323         if (*irq && *++iobase) goto j0; /* try again */
324
325         HFC_END;
326
327         printf("ihfc%d: Chip not found. "
328         "A hard reboot may help!\n", unit);
329
330         return ENXIO;   /* failure */
331 }
332
333 /*---------------------------------------------------------------------------*
334  *      attach ISA "PnP" card
335  *---------------------------------------------------------------------------*/
336 int
337 ihfc_pnp_attach(device_t dev)
338 {
339         u_int      unit = device_get_unit(dev);         /* get unit     */
340         ihfc_sc_t   *sc = &ihfc_softc[unit];            /* softc        */
341         HFC_VAR;
342  
343         HFC_BEG;
344
345         ihfc_B_linkinit(sc);    /* Setup B-Channel linktabs */
346
347         i4b_l1_mph_status_ind(S_I4BUNIT, STI_ATTACH, S_I4BFLAG, &ihfc_l1mux_func);
348         
349         HFC_INIT(sc, 0, 0, 1);  /* Setup D - Channel */
350
351         HFC_INIT(sc, 2, 0, 0);  /* Init B1 - Channel */
352         HFC_INIT(sc, 4, 0, 0);  /* Init B2 - Channel */
353
354         HFC_END;
355         return 0;       /* success */
356
357         HFC_END;
358         return ENXIO;   /* failure */
359 }
360
361 /*---------------------------------------------------------------------------*
362  *      shutdown for our ISA PnP card
363  *---------------------------------------------------------------------------*/
364 int
365 ihfc_pnp_shutdown(device_t dev)
366 {
367         u_int      unit = device_get_unit(dev);         /* get unit     */
368         ihfc_sc_t   *sc = &ihfc_softc[unit];            /* softc        */
369         HFC_VAR;
370
371         HFC_BEG;
372
373         if (unit >= IHFC_MAXUNIT)
374         {
375                 printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
376                 goto f0;
377         }
378
379         HFC_CONTROL(sc, 2);     /* shutdown chip */
380
381         HFC_END;
382         return 0;
383   f0:
384         HFC_END;
385         return ENXIO;
386
387 }
388
389 /*---------------------------------------------------------------------------*
390  *      detach for our ISA PnP card
391  *
392  *      flag:   bit[0] set: teardown interrupt handler too
393  *---------------------------------------------------------------------------*/
394 int
395 ihfc_pnp_detach (device_t dev, u_int flag)
396 {
397         u_int      unit = device_get_unit(dev);         /* get unit     */
398         ihfc_sc_t   *sc = &ihfc_softc[unit];            /* softc        */
399         u_char        i;
400
401         if (unit >= IHFC_MAXUNIT)
402         {
403                 printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
404                 return 0;
405         }
406
407         /* free interrupt resources */
408
409         if(S_IRQ)
410         {
411                 if (flag & 1)
412                 {
413                         /* tear down interrupt handler */
414                         bus_teardown_intr(dev, S_IRQ, (void(*)(void *))HFC_INTR);
415                 }
416
417                 /* free irq */
418                 bus_release_resource(dev, SYS_RES_IRQ, S_IRQRID, S_IRQ);
419
420                 S_IRQRID = 0;
421                 S_IRQ = 0;
422         }
423
424
425         /* free iobases */
426
427         for (i = IHFC_IO_BASES; i--;)
428         {
429                 if(S_IOBASE[i])
430                 {
431                         bus_release_resource(dev, SYS_RES_IOPORT,
432                                         S_IORID[i], S_IOBASE[i]);
433                         S_IORID[i] = 0;
434                         S_IOBASE[i] = 0;                        
435                 }
436         }
437
438         return 0;
439 }
440
441 #endif /* NIHFC > 0 */