]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/i4b/layer1/isic/i4b_tel_s016.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / i4b / layer1 / isic / i4b_tel_s016.c
1 /*-
2  *   Copyright (c) 1996 Arne Helme. All rights reserved.
3  *   Copyright (c) 1996 Gary Jennejohn. All rights reserved. 
4  *   Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *   2. Redistributions in binary form must reproduce the above copyright
13  *      notice, this list of conditions and the following disclaimer in the
14  *      documentation and/or other materials provided with the distribution.
15  *   3. Neither the name of the author nor the names of any co-contributors
16  *      may be used to endorse or promote products derived from this software
17  *      without specific prior written permission.
18  *   4. Altered versions must be plainly marked as such, and must not be
19  *      misrepresented as being the original software and/or documentation.
20  *   
21  *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  *   SUCH DAMAGE.
32  */
33
34 /*---------------------------------------------------------------------------
35  *
36  *      isic - I4B Siemens ISDN Chipset Driver for Teles S0/16 and clones
37  *      =================================================================
38  *      last edit-date: [Wed Jan 24 09:27:24 2001]
39  *
40  *---------------------------------------------------------------------------*/
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 #include "opt_i4b.h"
46
47 #if defined(TEL_S0_16)
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/socket.h>
52 #include <net/if.h>
53
54 #include <machine/md_var.h>
55 #include <i4b/include/i4b_ioctl.h>
56 #include <i4b/include/i4b_trace.h>
57
58 #include <i4b/layer1/i4b_l1.h>
59 #include <i4b/layer1/isic/i4b_isic.h>
60 #include <i4b/layer1/isic/i4b_hscx.h>
61
62 #define TELES_S016_MEMSIZE 0x1000
63
64 static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 };
65 static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 };
66
67 /*---------------------------------------------------------------------------*
68  *      Teles S0/16 write register routine
69  *---------------------------------------------------------------------------*/
70 static void
71 tels016_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)
72 {
73         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.mem);
74         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem);
75
76         offs += offset[what];
77
78         if (offs & 0x01)
79                 offs |= 0x200;
80
81         bus_space_write_1(t, h, offs, data);
82 }
83
84 /*---------------------------------------------------------------------------*
85  *      Teles S0/16 read register routine
86  *---------------------------------------------------------------------------*/
87 static u_int8_t
88 tels016_read_reg(struct l1_softc *sc,   int what, bus_size_t offs)
89 {
90         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.mem);
91         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem);
92
93         offs += offset[what];
94
95         if(offs & 0x01)
96                 offs |= 0x200;
97
98         return bus_space_read_1(t, h, offs);
99 }
100
101 /*---------------------------------------------------------------------------*
102  *      Teles S0/16 fifo write routine
103  *---------------------------------------------------------------------------*/
104 static void
105 tels016_write_fifo(struct l1_softc *sc, int what, void *data, size_t size)
106 {
107         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.mem);
108         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem);
109         bus_space_write_region_1(t, h, offset[what], data, size);
110 }
111
112 /*---------------------------------------------------------------------------*
113  *      Teles S0/16 fifo read routine
114  *---------------------------------------------------------------------------*/
115 static void
116 tels016_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
117 {
118         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.mem);
119         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem);
120         bus_space_read_region_1(t, h, offset[what], buf, size);
121 }
122
123 /*---------------------------------------------------------------------------*
124  *      isic_probe_s016 - probe for Teles S0/16 and compatibles
125  *---------------------------------------------------------------------------*/
126 int
127 isic_probe_s016(device_t dev)
128 {
129         size_t unit = device_get_unit(dev);     /* get unit */
130         struct l1_softc *sc = 0;                /* softc */
131         void *ih = 0;                           /* dummy */
132         u_int8_t b0,b1,b2;                      /* for signature */
133         bus_space_tag_t    t;                   /* bus things */
134         bus_space_handle_t h;
135
136         /* check max unit range */
137
138         if(unit >= ISIC_MAXUNIT)
139         {
140                 printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16!\n",
141                                 unit, unit);
142                 return(ENXIO);  
143         }
144
145         sc = &l1_sc[unit];                      /* get pointer to softc */
146         sc->sc_unit = unit;                     /* set unit */
147
148         /* see if an io base was supplied */
149
150         if(!(sc->sc_resources.io_base[0] =
151                         bus_alloc_resource_any(dev, SYS_RES_IOPORT,
152                                                &sc->sc_resources.io_rid[0],
153                                                RF_ACTIVE)))
154         {
155                 printf("isic%d: Could not allocate i/o port for Teles S0/16.\n", unit);
156                 return(ENXIO);
157         }
158
159         sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]);
160
161         /*
162          * check if the provided io port is valid
163          */
164
165         switch(sc->sc_port)
166         {
167                 case 0xd80:
168                 case 0xe80:
169                 case 0xf80:
170                         break;
171
172                 default:
173                         printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16!\n",
174                                 unit, sc->sc_port);
175                         isic_detach_common(dev);
176                         return(ENXIO);
177                         break;
178         }
179
180         /* allocate memory resource */
181
182         if(!(sc->sc_resources.mem =
183                         bus_alloc_resource(dev, SYS_RES_MEMORY,
184                                         &sc->sc_resources.mem_rid,
185                                         0ul, ~0ul, TELES_S016_MEMSIZE,
186                                         RF_ACTIVE)))
187         {
188                 printf("isic%d: Could not allocate memory for Teles S0/16.\n", unit);
189                 isic_detach_common(dev);
190                 return(ENXIO);
191         }
192
193         /* 
194          * get virtual addr.
195          */
196         sc->sc_vmem_addr = rman_get_virtual(sc->sc_resources.mem);
197
198         /*
199          * check for valid adresses
200          */
201         switch(kvtop(sc->sc_vmem_addr))
202         {
203                 case 0xc0000:
204                 case 0xc2000:
205                 case 0xc4000:
206                 case 0xc6000:
207                 case 0xc8000:
208                 case 0xca000:
209                 case 0xcc000:
210                 case 0xce000:
211                 case 0xd0000:
212                 case 0xd2000:
213                 case 0xd4000:
214                 case 0xd6000:
215                 case 0xd8000:
216                 case 0xda000:
217                 case 0xdc000:
218                 case 0xde000:
219                         break;
220
221                 default:
222                         printf("isic%d: Error, invalid memory address 0x%x for Teles S0/16!\n",
223                                 unit, kvtop(sc->sc_vmem_addr));
224                         isic_detach_common(dev);
225                         return(ENXIO);
226                         break;
227         }               
228         
229         /* setup ISAC access routines */
230
231         sc->clearirq = NULL;
232
233         sc->readreg = tels016_read_reg;
234         sc->writereg = tels016_write_reg;
235
236         sc->readfifo = tels016_read_fifo;
237         sc->writefifo = tels016_write_fifo;
238
239         /* setup card type */
240         sc->sc_cardtyp = CARD_TYPEP_16;
241
242         /* setup IOM bus type */
243         
244         sc->sc_bustyp = BUS_TYPE_IOM1;
245
246         sc->sc_ipac = 0;
247         sc->sc_bfifolen = HSCX_FIFO_LEN;
248
249         /* setup ISAC base addr, though we don't really need it */
250         
251         ISAC_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x100);
252
253         /* setup HSCX base addr */
254         
255         HSCX_A_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x180);
256         HSCX_B_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x1c0);
257
258         t = rman_get_bustag(sc->sc_resources.io_base[0]);
259         h = rman_get_bushandle(sc->sc_resources.io_base[0]);
260
261         /* get signature bytes */
262         b0 = bus_space_read_1(t, h, 0);
263         b1 = bus_space_read_1(t, h, 1);
264         b2 = bus_space_read_1(t, h, 2);
265
266         /* check signature bytes */
267         if(b0 != 0x51)
268         {
269                 printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16!\n",
270                         unit, b0);
271                 isic_detach_common(dev);
272                 return(ENXIO);
273         }
274         
275         if(b1 != 0x93)
276         {
277                 printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16!\n",
278                         unit, b1);
279                 isic_detach_common(dev);
280                 return(ENXIO);
281         }
282         
283         if((b2 != 0x1e) && (b2 != 0x1f))
284         {
285                 printf("isic%d: Error, signature 3 0x%x != 0x1e or 0x1f for Teles S0/16!\n",
286                         unit, b2);
287                 isic_detach_common(dev);
288                 return(ENXIO);
289         }
290
291         /* get our irq */
292
293         if(!(sc->sc_resources.irq =
294                         bus_alloc_resource_any(dev, SYS_RES_IRQ,
295                                                &sc->sc_resources.irq_rid,
296                                                RF_ACTIVE)))
297         {
298                 printf("isic%d: Could not allocate irq for Teles S0/16.\n", unit);
299                 isic_detach_common(dev);
300                 return ENXIO;
301         }
302
303         /* register interrupt routine */
304
305         if (bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, NULL,
306                         (void(*)(void *))(isicintr), sc, &ih) != 0)
307         {
308                 printf("isic%d: Could not setup irq for Teles S0/16.\n", unit);
309                 isic_detach_common(dev);
310                 return ENXIO;
311         }
312
313         /* get the irq number */
314         
315         sc->sc_irq = rman_get_start(sc->sc_resources.irq);
316
317         /* check IRQ validity */
318
319         if((intr_no[sc->sc_irq]) == 1)
320         {
321                 printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16!\n",
322                         unit, sc->sc_irq);
323                 isic_detach_common(dev);
324                 return(ENXIO);
325         }
326         
327         return (0);
328 }
329
330 /*---------------------------------------------------------------------------*
331  *      isic_attach_s016 - attach Teles S0/16 and compatibles
332  *---------------------------------------------------------------------------*/
333 int
334 isic_attach_s016(device_t dev)
335 {
336         struct l1_softc *sc = &l1_sc[device_get_unit(dev)];
337         u_long irq;
338
339         bus_space_tag_t    ta = rman_get_bustag(sc->sc_resources.mem);
340         bus_space_handle_t ha = rman_get_bushandle(sc->sc_resources.mem);
341         bus_space_tag_t    tb = rman_get_bustag(sc->sc_resources.io_base[0]);
342         bus_space_handle_t hb = rman_get_bushandle(sc->sc_resources.io_base[0]);
343
344         /* is this right for FreeBSD or off by one ? */
345         irq = intr_no[sc->sc_irq];
346
347         /* configure IRQ */
348
349         irq |= ((u_long) sc->sc_vmem_addr) >> 9;
350
351         DELAY(SEC_DELAY / 10);
352         bus_space_write_1(tb, hb, 4, irq);
353
354         DELAY(SEC_DELAY / 10);
355         bus_space_write_1(tb, hb, 4, irq | 0x01);
356
357         DELAY(SEC_DELAY / 5);
358
359         /* set card bit off */
360
361         bus_space_write_1(ta, ha, 0x80, 0);
362         DELAY(SEC_DELAY / 5);
363
364         /* set card bit on */
365         
366         bus_space_write_1(ta, ha, 0x80, 1);
367         DELAY(SEC_DELAY / 5);
368
369         return 0;
370 }
371
372 #endif /* defined(TEL_S0_16) */