Annotation of sys/dev/cardbus/com_cardbus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: com_cardbus.c,v 1.30 2007/05/08 21:28:11 deraadt Exp $ */
2: /* $NetBSD: com_cardbus.c,v 1.4 2000/04/17 09:21:59 joda Exp $ */
3:
4: /*
5: * Copyright (c) 2000 Johan Danielsson
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: *
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: *
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * 3. Neither the name of author nor the names of any contributors may
20: * be used to endorse or promote products derived from this
21: * software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
27: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: /* This is a driver for CardBus based serial devices. It is less
37: generic than it could be, but it keeps the complexity down. So far
38: it assumes that anything that reports itself as a `serial' device
39: is infact a 16x50 or 8250, which is not necessarily true (in
40: practice this shouldn't be a problem). It also does not handle
41: devices in the `multiport serial' or `modem' sub-classes, I've
42: never seen any of these, so I don't know what they might look like.
43:
44: If the CardBus device only has one BAR (that is not also the CIS
45: BAR) listed in the CIS, it is assumed to be the one to use. For
46: devices with more than one BAR, the list of known devies has to be
47: updated below. */
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/tty.h>
52: #include <sys/device.h>
53:
54: #include <dev/cardbus/cardbusvar.h>
55: #include <dev/pci/pcidevs.h>
56:
57: #include <dev/pcmcia/pcmciareg.h>
58:
59: #include "com.h"
60: #ifdef i386
61: #include "pccom.h"
62: #endif
63:
64: #include <dev/ic/comreg.h>
65: #if NPCCOM > 0
66: #include <i386/isa/pccomvar.h>
67: #endif
68: #if NCOM > 0
69: #include <dev/ic/comvar.h>
70: #endif
71: #include <dev/ic/ns16550reg.h>
72:
73: #define com_lcr com_cfcr
74:
75: struct com_cardbus_softc {
76: struct com_softc cc_com;
77: void *cc_ih;
78: cardbus_devfunc_t cc_ct;
79: bus_addr_t cc_addr;
80: cardbusreg_t cc_base;
81: bus_size_t cc_size;
82: cardbusreg_t cc_csr;
83: int cc_cben;
84: cardbustag_t cc_tag;
85: cardbusreg_t cc_reg;
86: int cc_type;
87: u_char cc_bug;
88: };
89:
90: #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
91:
92: int com_cardbus_match(struct device *, void *, void *);
93: void com_cardbus_attach(struct device *, struct device *, void *);
94: int com_cardbus_detach(struct device *, int);
95:
96: void com_cardbus_setup(struct com_cardbus_softc *);
97: int com_cardbus_enable(struct com_softc *);
98: void com_cardbus_disable(struct com_softc *);
99: struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
100: int com_cardbus_gofigure(struct cardbus_attach_args *,
101: struct com_cardbus_softc *);
102:
103: #if NCOM_CARDBUS
104: struct cfattach com_cardbus_ca = {
105: sizeof(struct com_cardbus_softc), com_cardbus_match,
106: com_cardbus_attach, com_cardbus_detach, com_activate
107: };
108: #elif NPCCOM_CARDBUS
109: struct cfattach pccom_cardbus_ca = {
110: sizeof(struct com_cardbus_softc), com_cardbus_match,
111: com_cardbus_attach, com_cardbus_detach, com_activate
112: };
113: #endif
114:
115: #define BUG_BROADCOM 0x01
116:
117: static struct csdev {
118: u_short vendor;
119: u_short product;
120: cardbusreg_t reg;
121: u_char type;
122: u_char bug;
123: } csdevs[] = {
124: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
125: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
126: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
127: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
128: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4322,
129: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
130: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
131: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
132: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
133: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
134: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
135: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
136: { PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
137: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
138: { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
139: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
140: { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
141: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
142: };
143:
144: static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
145:
146: struct csdev*
147: com_cardbus_find_csdev(struct cardbus_attach_args *ca)
148: {
149: struct csdev *cp;
150:
151: for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
152: if (cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
153: cp->product == CARDBUS_PRODUCT(ca->ca_id))
154: return (cp);
155: return (NULL);
156: }
157:
158: int
159: com_cardbus_match(struct device *parent, void *match, void *aux)
160: {
161: struct cardbus_attach_args *ca = aux;
162:
163: /* known devices are ok */
164: if (com_cardbus_find_csdev(ca) != NULL)
165: return (10);
166:
167: /* as are serial devices with a known UART */
168: if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
169: ca->ca_cis.funce.serial.uart_present != 0 &&
170: (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
171: ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
172: ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
173: return (1);
174:
175: return (0);
176: }
177:
178: int
179: com_cardbus_gofigure(struct cardbus_attach_args *ca,
180: struct com_cardbus_softc *csc)
181: {
182: int i, index = -1;
183: cardbusreg_t cis_ptr;
184: struct csdev *cp;
185:
186: /* If this device is listed above, use the known values, */
187: cp = com_cardbus_find_csdev(ca);
188: if (cp != NULL) {
189: csc->cc_reg = cp->reg;
190: csc->cc_type = cp->type;
191: csc->cc_bug = cp->bug;
192: return (0);
193: }
194:
195: cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
196:
197: /* otherwise try to deduce which BAR and type to use from CIS. If
198: there is only one BAR, it must be the one we should use, if
199: there are more, we're out of luck. */
200: for (i = 0; i < 7; i++) {
201: /* ignore zero sized BARs */
202: if (ca->ca_cis.bar[i].size == 0)
203: continue;
204: /* ignore the CIS BAR */
205: if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
206: CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
207: continue;
208: if (index != -1)
209: goto multi_bar;
210: index = i;
211: }
212: if (index == -1) {
213: printf(": couldn't find any base address tuple\n");
214: return (1);
215: }
216: csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
217: if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
218: csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
219: else
220: csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
221: return (0);
222:
223: multi_bar:
224: printf(": there are more than one possible base\n");
225:
226: printf("%s: address for this device, "
227: "please report the following information\n",
228: DEVNAME(csc));
229: printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
230: CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
231: for (i = 0; i < 7; i++) {
232: /* ignore zero sized BARs */
233: if (ca->ca_cis.bar[i].size == 0)
234: continue;
235: /* ignore the CIS BAR */
236: if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
237: CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
238: continue;
239: printf("%s: base address %x type %s size %x\n",
240: DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
241: (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
242: ca->ca_cis.bar[i].size);
243: }
244: return (1);
245: }
246:
247: void
248: com_cardbus_attach(struct device *parent, struct device *self, void *aux)
249: {
250: struct com_softc *sc = (struct com_softc*)self;
251: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
252: struct cardbus_attach_args *ca = aux;
253:
254: csc->cc_ct = ca->ca_ct;
255: csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
256:
257: if (com_cardbus_gofigure(ca, csc) != 0)
258: return;
259:
260: if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
261: &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
262: printf("failed to map memory");
263: return;
264: }
265:
266: csc->cc_base = csc->cc_addr;
267: csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
268: if (csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
269: csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
270: csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
271: csc->cc_cben = CARDBUS_IO_ENABLE;
272: } else {
273: csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
274: csc->cc_cben = CARDBUS_MEM_ENABLE;
275: }
276:
277: sc->sc_iobase = csc->cc_addr;
278: sc->sc_frequency = COM_FREQ;
279:
280: sc->enable = com_cardbus_enable;
281: sc->disable = com_cardbus_disable;
282: sc->enabled = 0;
283:
284: if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
285: printf(": %s %s\n", ca->ca_cis.cis1_info[0],
286: ca->ca_cis.cis1_info[1]);
287: printf("%s", DEVNAME(csc));
288: }
289:
290: if (com_cardbus_enable(sc))
291: printf(": function enable failed\n");
292: sc->enabled = 1;
293:
294: sc->sc_hwflags = 0;
295: sc->sc_swflags = 0;
296:
297: if (csc->cc_bug & BUG_BROADCOM)
298: sc->sc_fifolen = 15;
299:
300: com_attach_subr(sc);
301: }
302:
303: void
304: com_cardbus_setup(struct com_cardbus_softc *csc)
305: {
306: cardbus_devfunc_t ct = csc->cc_ct;
307: cardbus_chipset_tag_t cc = ct->ct_cc;
308: cardbus_function_tag_t cf = ct->ct_cf;
309: cardbusreg_t reg;
310:
311: cardbus_conf_write(cc, cf, csc->cc_tag, csc->cc_reg, csc->cc_base);
312:
313: /* enable accesses on cardbus bridge */
314: cf->cardbus_ctrl(cc, csc->cc_cben);
315: cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
316:
317: /* and the card itself */
318: reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
319: reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
320: reg |= csc->cc_csr;
321: cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
322:
323: /*
324: * Make sure the latency timer is set to some reasonable
325: * value.
326: */
327: reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
328: if (CARDBUS_LATTIMER(reg) < 0x20) {
329: reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
330: reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
331: cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
332: }
333: }
334:
335: int
336: com_cardbus_enable(struct com_softc *sc)
337: {
338: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
339: struct cardbus_softc *psc =
340: (struct cardbus_softc *)sc->sc_dev.dv_parent;
341: cardbus_chipset_tag_t cc = psc->sc_cc;
342: cardbus_function_tag_t cf = psc->sc_cf;
343:
344: Cardbus_function_enable(csc->cc_ct);
345:
346: com_cardbus_setup(csc);
347:
348: /* establish the interrupt. */
349: csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
350: IPL_TTY, comintr, sc, DEVNAME(csc));
351: if (csc->cc_ih == NULL) {
352: printf("%s: couldn't establish interrupt\n", DEVNAME(csc));
353: return (1);
354: }
355:
356: printf(": irq %d", psc->sc_intrline);
357:
358: return (0);
359: }
360:
361: void
362: com_cardbus_disable(struct com_softc *sc)
363: {
364: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
365: struct cardbus_softc *psc =
366: (struct cardbus_softc *)sc->sc_dev.dv_parent;
367: cardbus_chipset_tag_t cc = psc->sc_cc;
368: cardbus_function_tag_t cf = psc->sc_cf;
369:
370: cardbus_intr_disestablish(cc, cf, csc->cc_ih);
371: Cardbus_function_disable(csc->cc_ct);
372: }
373:
374: int
375: com_cardbus_detach(struct device *self, int flags)
376: {
377: struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
378: struct com_softc *sc = (struct com_softc *) self;
379: struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
380: int error;
381:
382: if ((error = com_detach(self, flags)) != 0)
383: return (error);
384:
385: cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
386:
387: Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
388: csc->cc_size);
389:
390: return (0);
391: }
CVSweb