Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / isic / i4b_isic.c
1 /*
2  * Copyright (c) 1997, 2001 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  *      i4b_isic.c - global isic stuff
28  *      ==============================
29  *
30  * $FreeBSD: src/sys/i4b/layer1/isic/i4b_isic.c,v 1.4.2.1 2001/08/10 14:08:38 obrien Exp $
31  *
32  *      last edit-date: [Wed Jan 24 09:29:42 2001]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "isic.h"
37 #include "opt_i4b.h"
38
39 #if NISIC > 0
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/socket.h>
44 #include <net/if.h>
45
46 #include <machine/i4b_debug.h>
47 #include <machine/i4b_ioctl.h>
48 #include <machine/i4b_trace.h>
49
50 #include <i4b/layer1/i4b_l1.h>
51
52 #include <i4b/layer1/isic/i4b_isic.h>
53 #include <i4b/layer1/isic/i4b_isic_ext.h>
54 #include <i4b/layer1/isic/i4b_ipac.h>
55 #include <i4b/layer1/isic/i4b_isac.h>
56 #include <i4b/layer1/isic/i4b_hscx.h>
57
58 #include <i4b/include/i4b_global.h>
59
60 static char *ISACversion[] = {
61         "2085 Version A1/A2 or 2086/2186 Version 1.1",
62         "2085 Version B1",
63         "2085 Version B2",
64         "2085 Version V2.3 (B3)",
65         "Unknown Version"
66 };
67
68 static char *HSCXversion[] = {
69         "82525 Version A1",
70         "Unknown (0x01)",
71         "82525 Version A2",
72         "Unknown (0x03)",
73         "82525 Version A3",
74         "82525 or 21525 Version 2.1",
75         "Unknown Version"
76 };
77
78 /* jump table for multiplex routines */
79 struct i4b_l1mux_func isic_l1mux_func = {
80         isic_ret_linktab,
81         isic_set_linktab,
82         isic_mph_command_req,
83         isic_ph_data_req,
84         isic_ph_activate_req,
85 };
86
87 /*---------------------------------------------------------------------------*
88  *      isic - device driver interrupt routine
89  *---------------------------------------------------------------------------*/
90 void
91 isicintr(struct l1_softc *sc)
92 {
93         if(sc->sc_ipac == 0)    /* HSCX/ISAC interupt routine */
94         {
95                 u_char was_hscx_irq = 0;
96                 u_char was_isac_irq = 0;
97
98                 register u_char hscx_irq_stat;
99                 register u_char isac_irq_stat;
100
101                 for(;;)
102                 {
103                         /* get hscx irq status from hscx b ista */
104                         hscx_irq_stat =
105                             HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK;
106         
107                         /* get isac irq status */
108                         isac_irq_stat = ISAC_READ(I_ISTA);
109         
110                         /* do as long as there are pending irqs in the chips */
111                         if(!hscx_irq_stat && !isac_irq_stat)
112                                 break;
113         
114                         if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF |
115                                             HSCX_ISTA_RSC | HSCX_ISTA_XPR |
116                                             HSCX_ISTA_TIN | HSCX_ISTA_EXB))
117                         {
118                                 isic_hscx_irq(sc, hscx_irq_stat,
119                                                 HSCX_CH_B,
120                                                 hscx_irq_stat & HSCX_ISTA_EXB);
121                                 was_hscx_irq = 1;                       
122                         }
123                         
124                         if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA))
125                         {
126                                 isic_hscx_irq(sc,
127                                     HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK,
128                                     HSCX_CH_A,
129                                     hscx_irq_stat & HSCX_ISTA_EXA);
130                                 was_hscx_irq = 1;
131                         }
132         
133                         if(isac_irq_stat)
134                         {
135                                 isic_isac_irq(sc, isac_irq_stat); /* isac handler */
136                                 was_isac_irq = 1;
137                         }
138                 }
139
140                 HSCX_WRITE(0, H_MASK, 0xff);
141                 ISAC_WRITE(I_MASK, 0xff);
142                 HSCX_WRITE(1, H_MASK, 0xff);
143         
144 #ifdef ELSA_QS1ISA
145                 DELAY(80);
146                 
147                 if((sc->sc_cardtyp == CARD_TYPEP_ELSAQS1ISA) && (sc->clearirq))
148                 {
149                         sc->clearirq(sc);
150                 }
151 #else
152                 DELAY(100);
153 #endif  
154         
155                 HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
156                 ISAC_WRITE(I_MASK, ISAC_IMASK);
157                 HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
158         }
159         else    /* IPAC interrupt routine */
160         {
161                 register u_char ipac_irq_stat;
162                 register u_char was_ipac_irq = 0;
163
164                 for(;;)
165                 {
166                         /* get global irq status */
167                         
168                         ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f;
169                         
170                         /* check hscx a */
171                         
172                         if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA))
173                         {
174                                 /* HSCX A interrupt */
175                                 isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA),
176                                                 HSCX_CH_A,
177                                                 ipac_irq_stat & IPAC_ISTA_EXA);
178                                 was_ipac_irq = 1;                       
179                         }
180                         if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB))
181                         {
182                                 /* HSCX B interrupt */
183                                 isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA),
184                                                 HSCX_CH_B,
185                                                 ipac_irq_stat & IPAC_ISTA_EXB);
186                                 was_ipac_irq = 1;                       
187                         }
188                         if(ipac_irq_stat & IPAC_ISTA_ICD)
189                         {
190                                 /* ISAC interrupt */
191                                 isic_isac_irq(sc, ISAC_READ(I_ISTA));
192                                 was_ipac_irq = 1;
193                         }
194                         if(ipac_irq_stat & IPAC_ISTA_EXD)
195                         {
196                                 /* force ISAC interrupt handling */
197                                 isic_isac_irq(sc, ISAC_ISTA_EXI);
198                                 was_ipac_irq = 1;
199                         }
200         
201                         /* do as long as there are pending irqs in the chip */
202                         if(!ipac_irq_stat)
203                                 break;
204                 }
205
206                 IPAC_WRITE(IPAC_MASK, 0xff);
207                 DELAY(50);
208                 IPAC_WRITE(IPAC_MASK, 0xc0);
209         }               
210 }
211
212 /*---------------------------------------------------------------------------*
213  *      isic_recover - try to recover from irq lockup
214  *---------------------------------------------------------------------------*/
215 void
216 isic_recover(struct l1_softc *sc)
217 {
218         u_char byte;
219         
220         /* get hscx irq status from hscx b ista */
221
222         byte = HSCX_READ(HSCX_CH_B, H_ISTA);
223
224         NDBGL1(L1_ERROR, "HSCX B: ISTA = 0x%x", byte);
225
226         if(byte & HSCX_ISTA_ICA)
227                 NDBGL1(L1_ERROR, "HSCX A: ISTA = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_ISTA));
228
229         if(byte & HSCX_ISTA_EXB)
230                 NDBGL1(L1_ERROR, "HSCX B: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_B, H_EXIR));
231
232         if(byte & HSCX_ISTA_EXA)
233                 NDBGL1(L1_ERROR, "HSCX A: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_EXIR));
234
235         /* get isac irq status */
236
237         byte = ISAC_READ(I_ISTA);
238
239         NDBGL1(L1_ERROR, "  ISAC: ISTA = 0x%x", byte);
240         
241         if(byte & ISAC_ISTA_EXI)
242                 NDBGL1(L1_ERROR, "  ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR));
243
244         if(byte & ISAC_ISTA_CISQ)
245         {
246                 byte = ISAC_READ(I_CIRR);
247         
248                 NDBGL1(L1_ERROR, "  ISAC: CISQ = 0x%x", byte);
249                 
250                 if(byte & ISAC_CIRR_SQC)
251                         NDBGL1(L1_ERROR, "  ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR));
252         }
253
254         NDBGL1(L1_ERROR, "HSCX B: IMASK = 0x%x", HSCX_B_IMASK);
255         NDBGL1(L1_ERROR, "HSCX A: IMASK = 0x%x", HSCX_A_IMASK);
256
257         HSCX_WRITE(0, H_MASK, 0xff);
258         HSCX_WRITE(1, H_MASK, 0xff);
259         DELAY(100);     
260         HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
261         HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
262         DELAY(100);
263
264         NDBGL1(L1_ERROR, "  ISAC: IMASK = 0x%x", ISAC_IMASK);
265
266         ISAC_WRITE(I_MASK, 0xff);       
267         DELAY(100);
268         ISAC_WRITE(I_MASK, ISAC_IMASK);
269 }
270
271 /*---------------------------------------------------------------------------*
272  *      isic_attach_common - common attach routine for all busses
273  *---------------------------------------------------------------------------*/
274 int
275 isic_attach_common(device_t dev)
276 {
277         char *drvid = NULL;
278         int unit = device_get_unit(dev);
279         struct l1_softc *sc = &l1_sc[unit];
280         
281         sc->sc_unit = unit;
282         
283         sc->sc_isac_version = 0;
284         sc->sc_hscx_version = 0;
285
286         if(sc->sc_ipac)
287         {
288                 sc->sc_ipac_version = IPAC_READ(IPAC_ID);
289
290                 switch(sc->sc_ipac_version)
291                 {
292                         case IPAC_V11:
293                         case IPAC_V12:
294                                 break;
295
296                         default:
297                                 printf("isic%d: Error, IPAC version %d unknown!\n",
298                                         unit, sc->sc_ipac_version);
299                                 return(0);
300                                 break;
301                 }
302         }
303         else
304         {
305                 sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03;
306         
307                 switch(sc->sc_isac_version)
308                 {
309                         case ISAC_VA:
310                         case ISAC_VB1:
311                         case ISAC_VB2:
312                         case ISAC_VB3:
313                                 break;
314         
315                         default:
316                                 printf("isic%d: Error, ISAC version %d unknown!\n",
317                                         unit, sc->sc_isac_version);
318                                 return ENXIO;
319                                 break;
320                 }
321
322                 sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf;
323
324                 switch(sc->sc_hscx_version)
325                 {
326                         case HSCX_VA1:
327                         case HSCX_VA2:
328                         case HSCX_VA3:
329                         case HSCX_V21:
330                                 break;
331                                 
332                         default:
333                                 printf("isic%d: Error, HSCX version %d unknown!\n",
334                                         unit, sc->sc_hscx_version);
335                                 return ENXIO;
336                                 break;
337                 }
338         }
339         
340         isic_isac_init(sc);             /* ISAC setup */
341
342         /* HSCX setup */
343
344         isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0);
345         
346         isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0);
347
348         isic_init_linktab(sc);          /* setup linktab */
349
350         sc->sc_trace = TRACE_OFF;       /* set trace level */
351
352         sc->sc_state = ISAC_IDLE;       /* set state */
353
354         sc->sc_ibuf = NULL;             /* input buffering */
355         sc->sc_ib = NULL;
356         sc->sc_ilen = 0;
357
358         sc->sc_obuf = NULL;             /* output buffering */
359         sc->sc_op = NULL;
360         sc->sc_ol = 0;
361         sc->sc_freeflag = 0;
362
363         sc->sc_obuf2 = NULL;            /* second output buffer */
364         sc->sc_freeflag2 = 0;
365
366         /* timer setup */
367         
368         callout_handle_init(&sc->sc_T3_callout);
369         callout_handle_init(&sc->sc_T4_callout);        
370         
371         /* init higher protocol layers */
372         
373         i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &isic_l1mux_func);
374
375         /* announce manufacturer and card type for ISA cards */
376         
377         switch(sc->sc_cardtyp)
378         {
379                 case CARD_TYPEP_8:
380                         drvid = "Teles S0/8 (or compatible)";
381                         break;
382
383                 case CARD_TYPEP_16:
384                         drvid = "Teles S0/16 (or compatible)";
385                         break;
386
387                 case CARD_TYPEP_16_3:
388                         drvid = "Teles S0/16.3";
389                         break;
390
391                 case CARD_TYPEP_AVMA1:
392                         drvid = "AVM A1 or Fritz!Card Classic";
393                         break;
394
395                 case CARD_TYPEP_PCFRITZ:
396                         drvid = "AVM Fritz!Card PCMCIA";
397                         break;
398
399                 case CARD_TYPEP_USRTA:
400                         drvid = "USRobotics Sportster ISDN TA intern";
401                         break;
402
403                 case CARD_TYPEP_ITKIX1:
404                         drvid = "ITK ix1 micro";
405                         break;
406
407                 case CARD_TYPEP_PCC16:
408                         drvid = "ELSA MicroLink ISDN/PCC-16";
409                         break;
410
411                 default:
412                         drvid = NULL;   /* pnp/pci cards announce themselves */
413                         break;
414         }
415
416         if(drvid)
417                 printf("isic%d: %s\n", unit, drvid);
418         
419         if(bootverbose)
420         {
421                 /* announce chip versions */
422                 
423                 if(sc->sc_ipac)
424                 {
425                         if(sc->sc_ipac_version == IPAC_V11)
426                                 printf("isic%d: IPAC PSB2115 Version 1.1\n", unit);
427                         else
428                                 printf("isic%d: IPAC PSB2115 Version 1.2\n", unit);
429                 }
430                 else
431                 {
432                         printf("isic%d: ISAC %s (IOM-%c)\n",
433                                 unit,
434                                 ISACversion[sc->sc_isac_version],
435                                 sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
436
437                         printf("isic%d: HSCX %s\n",
438                                 unit,
439                                 HSCXversion[sc->sc_hscx_version]);
440                 }
441         }
442         return 0;
443 }
444
445 /*---------------------------------------------------------------------------*
446  *      isic_detach_common - common detach routine for all busses
447  *---------------------------------------------------------------------------*/
448 void
449 isic_detach_common(device_t dev)
450 {
451         struct l1_softc *sc = &l1_sc[device_get_unit(dev)];
452         int i;
453
454         sc->sc_cardtyp = CARD_TYPEP_UNK;
455
456         /* free interrupt resources */
457         
458         if(sc->sc_resources.irq)
459         {
460                 /* tear down interupt handler */
461                 bus_teardown_intr(dev, sc->sc_resources.irq,
462                                         (void(*)(void *))isicintr);
463
464                 /* free irq */
465                 bus_release_resource(dev, SYS_RES_IRQ,
466                                         sc->sc_resources.irq_rid,
467                                         sc->sc_resources.irq);
468                 sc->sc_resources.irq_rid = 0;
469                 sc->sc_resources.irq = 0;
470         }
471
472         /* free memory resource */
473         
474         if(sc->sc_resources.mem)
475         {
476                 bus_release_resource(dev,SYS_RES_MEMORY,
477                                         sc->sc_resources.mem_rid,
478                                         sc->sc_resources.mem);
479                 sc->sc_resources.mem_rid = 0;
480                 sc->sc_resources.mem = 0;
481         }
482
483         /* free iobases */
484
485         for(i=0; i < INFO_IO_BASES ; i++)
486         {
487                 if(sc->sc_resources.io_base[i])
488                 {
489                         bus_release_resource(dev, SYS_RES_IOPORT,
490                                                 sc->sc_resources.io_rid[i],
491                                                 sc->sc_resources.io_base[i]);
492                         sc->sc_resources.io_rid[i] = 0;
493                         sc->sc_resources.io_base[i] = 0;                        
494                 }
495         }
496 }
497
498 #endif /* NISIC > 0 */
499