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