Annotation of sys/dev/pcmcia/if_rln_pcmcia.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_rln_pcmcia.c,v 1.15 2005/01/27 17:04:56 millert Exp $ */
2: /*
3: * David Leonard <d@openbsd.org>, 1999. Public domain.
4: *
5: * Proxim RangeLAN2 PC-Card and compatibles
6: */
7:
8: #include <sys/param.h>
9: #include <sys/systm.h>
10: #include <sys/socket.h>
11: #include <sys/device.h>
12: #include <sys/queue.h>
13:
14: #include <net/if.h>
15:
16: #ifdef INET
17: #include <netinet/in.h>
18: #include <netinet/if_ether.h>
19: #endif
20:
21: #include <machine/bus.h>
22: #include <machine/intr.h>
23:
24: #include <dev/ic/rln.h>
25: #include <dev/ic/rlnvar.h>
26: #include <dev/ic/rlnreg.h>
27:
28: #include <dev/pcmcia/pcmciareg.h>
29: #include <dev/pcmcia/pcmciavar.h>
30: #include <dev/pcmcia/pcmciadevs.h>
31:
32: struct rln_pcmcia_softc {
33: struct rln_softc psc_rln; /* real "rln" softc */
34:
35: struct pcmcia_io_handle psc_pcioh; /* PCMCIA i/o information */
36: int sc_io_window; /* i/o window for the card */
37: struct pcmcia_function *psc_pf; /* our PCMCIA function */
38: void *psc_ih; /* our interrupt handle */
39: };
40:
41: static int rln_pcmcia_match(struct device *, void *, void *);
42: static struct rln_pcmcia_product * rln_pcmcia_product_lookup(struct pcmcia_attach_args *);
43: static void rln_pcmcia_attach(struct device *, struct device *, void *);
44: static int rln_pcmcia_detach(struct device *, int);
45: static int rln_pcmcia_activate(struct device *, enum devact);
46: static int rlnintr_pcmcia(void *arg);
47:
48: struct cfattach rln_pcmcia_ca = {
49: sizeof(struct rln_pcmcia_softc), rln_pcmcia_match, rln_pcmcia_attach,
50: rln_pcmcia_detach, rln_pcmcia_activate
51: };
52:
53: static struct rln_pcmcia_product {
54: u_int16_t manufacturer;
55: u_int16_t product;
56: const char *cis[4];
57: u_int8_t flags;
58: } rln_pcmcia_products[] = {
59: /* Digital RoamAbout 2400 FH, from d@openbsd.org */
60: { PCMCIA_VENDOR_PROXIM,
61: PCMCIA_PRODUCT_PROXIM_ROAMABOUT_2400FH,
62: PCMCIA_CIS_PROXIM_ROAMABOUT_2400FH,
63: 0 },
64: /* AMP Wireless, from jimduchek@ou.edu */
65: { PCMCIA_VENDOR_COMPEX,
66: PCMCIA_PRODUCT_COMPEX_AMP_WIRELESS,
67: PCMCIA_CIS_COMPEX_AMP_WIRELESS,
68: 0 },
69: /* Proxim RangeLAN2 7401, from louis@bertrandtech.on.ca */
70: { PCMCIA_VENDOR_PROXIM,
71: PCMCIA_PRODUCT_PROXIM_RANGELAN2_7401,
72: PCMCIA_CIS_PROXIM_RANGELAN2_7401,
73: 0 },
74: /* Generic and clone cards matched by CIS alone */
75: { PCMCIA_VENDOR_INVALID,
76: PCMCIA_PRODUCT_INVALID,
77: PCMCIA_CIS_PROXIM_RL2_7200,
78: 0 },
79: { PCMCIA_VENDOR_INVALID,
80: PCMCIA_PRODUCT_INVALID,
81: PCMCIA_CIS_PROXIM_RL2_7400,
82: 0 },
83: { PCMCIA_VENDOR_INVALID,
84: PCMCIA_PRODUCT_INVALID,
85: PCMCIA_CIS_PROXIM_SYMPHONY,
86: 0 }
87: };
88: #define NPRODUCTS (sizeof rln_pcmcia_products / sizeof rln_pcmcia_products[0])
89:
90: /* Match the card information with known card types */
91: static struct rln_pcmcia_product *
92: rln_pcmcia_product_lookup(pa)
93: struct pcmcia_attach_args *pa;
94: {
95: int i, j;
96: struct rln_pcmcia_product *rpp;
97:
98: for (i = 0; i < NPRODUCTS; i++) {
99: rpp = &rln_pcmcia_products[i];
100: if (rpp->manufacturer != PCMCIA_VENDOR_INVALID &&
101: rpp->manufacturer != pa->manufacturer)
102: continue;
103: if (rpp->product != PCMCIA_PRODUCT_INVALID &&
104: rpp->product != pa->product)
105: continue;
106: for (j = 0; j < 4; j++) {
107: if (rpp->cis[j] == NULL)
108: return rpp;
109: if (pa->card->cis1_info[j] &&
110: strcmp(pa->card->cis1_info[j], rpp->cis[j]) != 0)
111: break;
112: }
113: if (j == 4)
114: return rpp;
115: }
116: return NULL;
117: }
118:
119: /* Do we know this card? */
120: static int
121: rln_pcmcia_match(parent, match, aux)
122: struct device *parent;
123: void *match, *aux;
124: {
125: struct pcmcia_attach_args *pa = aux;
126:
127: return (rln_pcmcia_product_lookup(pa) != NULL);
128: }
129:
130: /* Attach and configure */
131: void
132: rln_pcmcia_attach(parent, self, aux)
133: struct device *parent, *self;
134: void *aux;
135: {
136: struct rln_pcmcia_softc *psc = (void *) self;
137: struct rln_softc *sc = &psc->psc_rln;
138: struct pcmcia_attach_args *pa = aux;
139: struct pcmcia_config_entry *cfe;
140: struct rln_pcmcia_product *rpp;
141: const char *intrstr;
142:
143: psc->psc_pf = pa->pf;
144: cfe = SIMPLEQ_FIRST(&psc->psc_pf->cfe_head);
145:
146: /* Guess the transfer width we will be using */
147: if (cfe->flags & PCMCIA_CFE_IO16)
148: sc->sc_width = 16;
149: else if (cfe->flags & PCMCIA_CFE_IO8)
150: sc->sc_width = 8;
151: else
152: sc->sc_width = 0;
153:
154: #ifdef DIAGNOSTIC
155: /* We only expect one i/o region and no memory region */
156: if (cfe->num_memspace != 0)
157: printf(": unexpected number of memory spaces (%d)\n",
158: cfe->num_memspace);
159: if (cfe->num_iospace != 1)
160: printf(": unexpected number of i/o spaces (%d)\n",
161: cfe->num_iospace);
162: else if (cfe->iospace[0].length != RLN_NPORTS)
163: printf(": unexpected size of i/o space (0x%x)\n",
164: cfe->iospace[0].length);
165: if (sc->sc_width == 0)
166: printf(": unknown bus width\n");
167: #endif /* DIAGNOSTIC */
168:
169: pcmcia_function_init(psc->psc_pf, cfe);
170:
171: /* Allocate i/o space */
172: if (pcmcia_io_alloc(psc->psc_pf, 0, RLN_NPORTS,
173: RLN_NPORTS, &psc->psc_pcioh)) {
174: printf(": can't allocate i/o space\n");
175: return;
176: }
177:
178: sc->sc_iot = psc->psc_pcioh.iot;
179: sc->sc_ioh = psc->psc_pcioh.ioh;
180:
181: /* Map i/o space */
182: if (pcmcia_io_map(psc->psc_pf, ((sc->sc_width == 8) ? PCMCIA_WIDTH_IO8 :
183: (sc->sc_width == 16) ? PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO),
184: 0, RLN_NPORTS, &psc->psc_pcioh, &psc->sc_io_window)) {
185: printf(": can't map i/o space\n");
186: return;
187: }
188: printf(" port 0x%lx/%d", psc->psc_pcioh.addr, RLN_NPORTS);
189:
190: /* Enable the card */
191: if (pcmcia_function_enable(psc->psc_pf)) {
192: printf(": function enable failed\n");
193: return;
194: }
195:
196: #ifdef notyet
197: sc->enable = rln_pcmcia_enable;
198: sc->disable = rln_pcmcia_disable;
199: #endif
200:
201: rpp = rln_pcmcia_product_lookup(pa);
202:
203: /* Check if the device has a separate antenna module */
204: sc->sc_cardtype = 0;
205: switch (psc->psc_pf->ccr_base) {
206: case 0x0100:
207: sc->sc_cardtype |= RLN_CTYPE_ONE_PIECE;
208: break;
209: case 0x0800:
210: sc->sc_cardtype &= ~RLN_CTYPE_ONE_PIECE;
211: break;
212: #ifdef DIAGNOSTIC
213: default:
214: printf(": cannot tell if one or two piece (ccr addr %x)\n",
215: sc->sc_dev.dv_xname, psc->psc_pf->ccr_base);
216: #endif
217: }
218:
219: /* The PC-card needs to be told to use 'irq' 15 */
220: sc->sc_irq = 15;
221:
222: /*
223: * We need to get an interrupt before configuring, since
224: * polling registers (the alternative) to reading card
225: * responses, causes hard lock-ups.
226: */
227: psc->psc_ih = pcmcia_intr_establish(psc->psc_pf, IPL_NET,
228: rlnintr_pcmcia, sc, sc->sc_dev.dv_xname);
229: intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
230: if (*intrstr)
231: printf(", %s", intrstr);
232: sc->sc_ih = NULL;
233:
234: #ifdef DIAGNOSTIC
235: if (rpp->manufacturer == PCMCIA_VENDOR_INVALID)
236: printf(" manf %04x prod %04x", pa->manufacturer, pa->product);
237: #endif
238:
239: rln_reset(sc);
240: rlnconfig(sc);
241: printf("\n");
242: }
243:
244: static int
245: rln_pcmcia_detach(dev, flags)
246: struct device *dev;
247: int flags;
248: {
249: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)dev;
250: struct rln_softc *sc = (struct rln_softc *)dev;
251: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
252: int rv = 0;
253:
254: pcmcia_io_unmap(psc->psc_pf, psc->sc_io_window);
255: pcmcia_io_free(psc->psc_pf, &psc->psc_pcioh);
256:
257: ether_ifdetach(ifp);
258: if_detach(ifp);
259:
260: return (rv);
261: }
262:
263: static int
264: rln_pcmcia_activate(dev, act)
265: struct device *dev;
266: enum devact act;
267: {
268: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)dev;
269: struct rln_softc *sc = (struct rln_softc *)dev;
270: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
271: int s;
272:
273: s = splnet();
274: switch (act) {
275: case DVACT_ACTIVATE:
276: pcmcia_function_enable(psc->psc_pf);
277: psc->psc_ih = pcmcia_intr_establish(psc->psc_pf, IPL_NET,
278: rlnintr_pcmcia, psc, sc->sc_dev.dv_xname);
279: rlninit(sc);
280: break;
281:
282: case DVACT_DEACTIVATE:
283: ifp->if_timer = 0;
284: if (ifp->if_flags & IFF_RUNNING)
285: rlnstop(sc);
286: pcmcia_intr_disestablish(psc->psc_pf, psc->psc_ih);
287: pcmcia_function_disable(psc->psc_pf);
288: break;
289: }
290: splx(s);
291: return (0);
292: }
293:
294: /* Interrupt handler */
295: static int
296: rlnintr_pcmcia(arg)
297: void *arg;
298: {
299: struct rln_softc *sc = (struct rln_softc *)arg;
300: struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)sc;
301: int opt;
302: int ret;
303:
304: /* Need to immediately read/write the option register for PC-card */
305: opt = pcmcia_ccr_read(psc->psc_pf, PCMCIA_CCR_OPTION);
306: pcmcia_ccr_write(psc->psc_pf, PCMCIA_CCR_OPTION, opt);
307:
308: /* Call actual interrupt handler */
309: ret = rlnintr(sc);
310:
311: return (ret);
312: }
CVSweb