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