]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i4b/layer1/i4b_elsa_pcc16.c
This commit was generated by cvs2svn to compensate for changes in r63516,
[FreeBSD/FreeBSD.git] / sys / i4b / layer1 / i4b_elsa_pcc16.c
1 /*
2  * Copyright (c) 1999 Hellmuth Michaelis. 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  *      isic - I4B Siemens ISDN Chipset Driver for ELSA MicroLink ISDN/PCC-16
28  *      =====================================================================
29  *
30  *      $Id: i4b_elsa_pcc16.c,v 1.2 1999/12/13 21:25:26 hm Exp $
31  *
32  * $FreeBSD$
33  *
34  *      last edit-date: [Mon Dec 13 21:59:36 1999]
35  *
36  *---------------------------------------------------------------------------*/
37
38 #include "isic.h"
39 #include "opt_i4b.h"
40
41 #if (NISIC > 0) && defined(ELSA_PCC16)
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <net/if.h>
48
49 #include <machine/clock.h>
50
51 #include <machine/i4b_debug.h>
52 #include <machine/i4b_ioctl.h>
53
54 #include <i4b/include/i4b_global.h>
55 #include <i4b/include/i4b_l1l2.h>
56 #include <i4b/include/i4b_mbuf.h>
57
58 #include <i4b/layer1/i4b_l1.h>
59 #include <i4b/layer1/i4b_isac.h>
60 #include <i4b/layer1/i4b_hscx.h>
61
62 static void i4b_epcc16_clrirq(struct l1_softc *sc);
63
64 /* masks for register encoded in base addr */
65
66 #define ELSA_BASE_MASK          0x0ffff
67 #define ELSA_OFF_MASK           0xf0000
68
69 /* register id's to be encoded in base addr */
70
71 #define ELSA_IDISAC             0x00000
72 #define ELSA_IDHSCXA            0x10000
73 #define ELSA_IDHSCXB            0x20000
74
75 /* offsets from base address */
76
77 #define ELSA_OFF_ISAC           0x00
78 #define ELSA_OFF_HSCX           0x02
79 #define ELSA_OFF_OFF            0x03
80 #define ELSA_OFF_CTRL           0x04
81 #define ELSA_OFF_CFG            0x05
82 #define ELSA_OFF_TIMR           0x06
83 #define ELSA_OFF_IRQ            0x07
84
85 /* control register (write access) */
86
87 #define ELSA_CTRL_LED_YELLOW    0x02
88 #define ELSA_CTRL_LED_GREEN     0x08
89 #define ELSA_CTRL_RESET         0x20
90 #define ELSA_CTRL_TIMEREN       0x80
91 #define ELSA_CTRL_SECRET        0x50
92
93 /*---------------------------------------------------------------------------*
94  *      ELSA MicroLink ISDN/PCC-16 clear IRQ routine
95  *---------------------------------------------------------------------------*/
96 static void
97 i4b_epcc16_clrirq(struct l1_softc *sc)
98 {
99         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
100         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
101         bus_space_write_1(t, h, ELSA_OFF_IRQ, 0);
102 }
103
104 /*---------------------------------------------------------------------------*
105  *      ELSA MicroLink ISDN/PCC-16 ISAC get fifo routine
106  *---------------------------------------------------------------------------*/
107 static void
108 epcc16_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
109 {
110         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
111         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
112
113         switch (what) {
114                 case ISIC_WHAT_ISAC:
115                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0);
116                         bus_space_read_multi_1(t, h, ELSA_OFF_ISAC, buf, size);
117                         break;
118                 case ISIC_WHAT_HSCXA:
119                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0);
120                         bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size);
121                         break;
122                 case ISIC_WHAT_HSCXB:
123                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40);
124                         bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size);
125                         break;
126         }
127 }
128
129 /*---------------------------------------------------------------------------*
130  *      ELSA MicroLink ISDN/PCC-16 ISAC put fifo routine
131  *---------------------------------------------------------------------------*/
132 static void
133 epcc16_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
134 {
135         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
136         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
137
138         switch (what) {
139                 case ISIC_WHAT_ISAC:
140                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0);
141                         bus_space_write_multi_1(t, h, ELSA_OFF_ISAC, buf, size);
142                         break;
143                 case ISIC_WHAT_HSCXA:
144                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0);
145                         bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, buf, size);
146                         break;
147                 case ISIC_WHAT_HSCXB:
148                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40);
149                         bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, buf, size);
150                         break;
151         }
152 }
153
154 /*---------------------------------------------------------------------------*
155  *      ELSA MicroLink ISDN/PCC-16 ISAC put register routine
156  *---------------------------------------------------------------------------*/
157 static void
158 epcc16_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)
159 {
160         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
161         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
162
163         switch (what) {
164                 case ISIC_WHAT_ISAC:
165                         bus_space_write_1(t, h, ELSA_OFF_OFF, offs);
166                         bus_space_write_1(t, h, ELSA_OFF_ISAC, data);
167                         break;
168                 case ISIC_WHAT_HSCXA:
169                         bus_space_write_1(t, h, ELSA_OFF_OFF, offs);
170                         bus_space_write_1(t, h, ELSA_OFF_HSCX, data);
171                         break;
172                 case ISIC_WHAT_HSCXB:
173                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs);
174                         bus_space_write_1(t, h, ELSA_OFF_HSCX, data);
175                         break;
176         }
177 }
178
179 /*---------------------------------------------------------------------------*
180  *      ELSA MicroLink ISDN/PCC-16 ISAC get register routine
181  *---------------------------------------------------------------------------*/
182 static u_int8_t
183 epcc16_read_reg(struct l1_softc *sc, int what, bus_size_t offs)
184 {
185         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
186         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
187
188         switch (what) {
189                 case ISIC_WHAT_ISAC:
190                         bus_space_write_1(t, h, ELSA_OFF_OFF, offs);
191                         return bus_space_read_1(t, h, ELSA_OFF_ISAC);
192                 case ISIC_WHAT_HSCXA:
193                         bus_space_write_1(t, h, ELSA_OFF_OFF, offs);
194                         return bus_space_read_1(t, h, ELSA_OFF_HSCX);
195                 case ISIC_WHAT_HSCXB:
196                         bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs);
197                         return bus_space_read_1(t, h, ELSA_OFF_HSCX);
198         }
199         return 0;
200 }
201
202 /*---------------------------------------------------------------------------*
203  *      isic_detach_Epcc16 - detach for ELSA MicroLink ISDN/PCC-16
204  *---------------------------------------------------------------------------*/
205 static void
206 isic_detach_Epcc16(device_t dev)
207 {
208         struct l1_softc *sc = &l1_sc[device_get_unit(dev)];
209
210         if ( sc->sc_resources.irq )
211         {
212                 bus_teardown_intr(dev,sc->sc_resources.irq,
213                         (void(*)(void *))isicintr);
214                 bus_release_resource(dev,SYS_RES_IRQ,
215                                         sc->sc_resources.irq_rid,
216                                         sc->sc_resources.irq);
217                 sc->sc_resources.irq = 0;
218         }
219         
220         if ( sc->sc_resources.io_base[0] ) {
221                 bus_release_resource(dev,SYS_RES_IOPORT,
222                                         sc->sc_resources.io_rid[0],
223                                         sc->sc_resources.io_base[0]);
224                 sc->sc_resources.io_base[0] = 0;
225         }
226 }
227
228 /*---------------------------------------------------------------------------*
229  *      isic_probe_Epcc16 - probe for ELSA MicroLink ISDN/PCC-16
230  *---------------------------------------------------------------------------*/
231 int
232 isic_probe_Epcc16(device_t dev)
233 {
234         size_t unit = device_get_unit(dev);     /* get unit */
235         struct l1_softc *sc = 0;                /* pointer to softc */
236         void *ih = 0;                           /* dummy */
237
238         /* check max unit range */
239         if(unit >= ISIC_MAXUNIT)
240         {
241                 printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA PCC-16!\n",
242                                 unit, unit);
243                 return(ENXIO);  
244         }
245
246         sc = &l1_sc[unit];              /* get pointer to softc */
247
248         sc->sc_unit = unit;             /* set unit */
249
250         sc->sc_flags = FLAG_ELSA_PCC16; /* set flags */
251
252         /* see if an io base was supplied */
253         
254         if(!(sc->sc_resources.io_base[0] =
255                         bus_alloc_resource(dev, SYS_RES_IOPORT,
256                                            &sc->sc_resources.io_rid[0],
257                                            0ul, ~0ul, 1, RF_ACTIVE)))
258         {
259                 printf("isic%d: Could not get iobase for ELSA PCC-16.\n",
260                                 unit);
261                 return(ENXIO);
262         }
263
264         /* check if we got an iobase */
265
266         sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]);
267
268         switch(sc->sc_port)
269         {
270                 case 0x160:
271                 case 0x170:
272                 case 0x260:
273                 case 0x360:
274                         break;
275                 default:
276                         printf("isic%d: Error, invalid iobase 0x%x specified for ELSA MicroLink ISDN/PCC-16!\n",
277                                 unit, sc->sc_port);
278                         isic_detach_Epcc16(dev);
279                         return(ENXIO);
280                         break;
281         }
282
283         /* setup access routines */
284
285         sc->clearirq = i4b_epcc16_clrirq;
286         sc->readreg = epcc16_read_reg;
287         sc->writereg = epcc16_write_reg;
288
289         sc->readfifo = epcc16_read_fifo;
290         sc->writefifo = epcc16_write_fifo;
291
292         /* setup card type */
293         
294         sc->sc_cardtyp = CARD_TYPEP_ELSAQS1ISA;
295
296         /* setup IOM bus type */
297         
298         sc->sc_bustyp = BUS_TYPE_IOM2;
299
300         sc->sc_ipac = 0;
301         sc->sc_bfifolen = HSCX_FIFO_LEN;        
302
303         /* 
304          * Read HSCX A/B VSTR.  Expected value for the ELSA PCC-16
305          * is 0x05 ( = version 2.1 ) in the least significant bits.
306          */
307
308         if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
309             ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
310         {
311                 printf("isic%d: HSCX VSTR test failed for ELSA MicroLink ISDN/PCC-16\n",
312                         unit);
313                 printf("isic%d: HSC0: VSTR: %#x\n",
314                         unit, HSCX_READ(0, H_VSTR));
315                 printf("isic%d: HSC1: VSTR: %#x\n",
316                         unit, HSCX_READ(1, H_VSTR));
317                 isic_detach_Epcc16(dev);
318                 return (ENXIO);
319         }                   
320
321         /* get our irq */
322
323         if(!(sc->sc_resources.irq =
324                         bus_alloc_resource(dev, SYS_RES_IRQ,
325                                         &sc->sc_resources.irq_rid,
326                                         0ul, ~0ul, 1, RF_ACTIVE)))
327         {
328                 printf("isic%d: Could not get an irq.\n",unit);
329                 isic_detach_Epcc16(dev);
330                 return ENXIO;
331         }
332
333         /* get the irq number */
334         sc->sc_irq = rman_get_start(sc->sc_resources.irq);
335
336         /* check IRQ validity */        
337         switch(sc->sc_irq)
338         {
339                 case 2:
340                 case 9:         
341                 case 3:         
342                 case 5:
343                 case 10:
344                 case 11:
345                 case 15:                
346                         break;
347                         
348                 default:
349                         printf("isic%d: Error, invalid IRQ [%d] specified for ELSA MicroLink ISDN/PCC-16!\n",
350                                 unit, sc->sc_irq);
351                         isic_detach_Epcc16(dev);
352                         return(ENXIO);
353                         break;
354         }
355
356         /* register interupt routine */
357         bus_setup_intr(dev,sc->sc_resources.irq,INTR_TYPE_NET,
358                         (void(*)(void *))(isicintr),
359                         sc,&ih);
360
361
362         return (0);
363 }
364
365 /*---------------------------------------------------------------------------*
366  * isic_attach_Epcc16 - attach for ELSA MicroLink ISDN/PCC-16
367  *---------------------------------------------------------------------------*/
368 int
369 isic_attach_Epcc16(device_t dev)
370 {
371         int unit = device_get_unit(dev);
372         struct l1_softc *sc = &l1_sc[unit];     
373         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
374         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
375
376         u_char byte = ELSA_CTRL_SECRET;
377
378         byte &= ~ELSA_CTRL_RESET;
379         bus_space_write_1(t, h, ELSA_OFF_CTRL, byte);
380         DELAY(20);
381         byte |= ELSA_CTRL_RESET;
382         bus_space_write_1(t, h, ELSA_OFF_CTRL, byte);
383
384         DELAY(20);
385         bus_space_write_1(t, h, ELSA_OFF_IRQ, 0xff);
386
387         return 0;
388 }
389
390 #endif /* (NISIC > 0) && defined(ELSA_PCC16) */