1 /* $NetBSD: com_cardbus.c,v 1.22 2008/06/24 19:44:52 drochner Exp $ */
4 * Copyright (c) 2000 Johan Danielsson
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of author nor the names of any contributors may
19 * be used to endorse or promote products derived from this
20 * software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /* A driver for CardBus based serial devices.
37 If the CardBus device only has one BAR (that is not also the CIS
38 BAR) listed in the CIS, it is assumed to be the one to use. For
39 devices with more than one BAR, the list of known devices has to be
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: com_cardbus.c,v 1.22 2008/06/24 19:44:52 drochner Exp $");
45 #include <sys/param.h>
46 #include <sys/systm.h>
48 #include <sys/device.h>
50 #include <dev/cardbus/cardbusvar.h>
51 #include <dev/pci/pcidevs.h>
53 #include <dev/pcmcia/pcmciareg.h>
55 #include <dev/ic/comreg.h>
56 #include <dev/ic/comvar.h>
58 struct com_cardbus_softc
{
59 struct com_softc cc_com
;
61 cardbus_devfunc_t cc_ct
;
72 #define DEVICET(CSC) ((CSC)->cc_com.sc_dev)
74 static int com_cardbus_match (device_t
, cfdata_t
, void*);
75 static void com_cardbus_attach (device_t
, device_t
, void*);
76 static int com_cardbus_detach (device_t
, int);
78 static void com_cardbus_setup(struct com_cardbus_softc
*);
79 static int com_cardbus_enable (struct com_softc
*);
80 static void com_cardbus_disable(struct com_softc
*);
82 CFATTACH_DECL_NEW(com_cardbus
, sizeof(struct com_cardbus_softc
),
83 com_cardbus_match
, com_cardbus_attach
, com_cardbus_detach
, NULL
);
91 { PCI_VENDOR_XIRCOM
, PCI_PRODUCT_XIRCOM_MODEM56
,
92 CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
},
93 { PCI_VENDOR_INTEL
, PCI_PRODUCT_INTEL_MODEM56
,
94 CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
},
95 { PCI_VENDOR_3COM
, PCI_PRODUCT_3COM_3C656_M
,
96 CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
},
97 { PCI_VENDOR_3COM
, PCI_PRODUCT_3COM_3C656B_M
,
98 CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
},
99 { PCI_VENDOR_3COM
, PCI_PRODUCT_3COM_3C656C_M
,
100 CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
},
103 static const int ncsdevs
= sizeof(csdevs
) / sizeof(csdevs
[0]);
106 find_csdev(struct cardbus_attach_args
*ca
)
110 for(cp
= csdevs
; cp
< csdevs
+ ncsdevs
; cp
++)
111 if(cp
->vendor
== CARDBUS_VENDOR(ca
->ca_id
) &&
112 cp
->product
== CARDBUS_PRODUCT(ca
->ca_id
))
118 com_cardbus_match(device_t parent
, cfdata_t match
, void *aux
)
120 struct cardbus_attach_args
*ca
= aux
;
122 /* known devices are ok */
123 if(find_csdev(ca
) != NULL
)
126 /* as are serial devices with a known UART */
127 if(ca
->ca_cis
.funcid
== PCMCIA_FUNCTION_SERIAL
&&
128 ca
->ca_cis
.funce
.serial
.uart_present
!= 0 &&
129 (ca
->ca_cis
.funce
.serial
.uart_type
== 0 || /* 8250 */
130 ca
->ca_cis
.funce
.serial
.uart_type
== 1 || /* 16450 */
131 ca
->ca_cis
.funce
.serial
.uart_type
== 2)) /* 16550 */
138 gofigure(struct cardbus_attach_args
*ca
, struct com_cardbus_softc
*csc
)
141 cardbusreg_t cis_ptr
;
144 /* If this device is listed above, use the known values, */
147 csc
->cc_reg
= cp
->reg
;
148 csc
->cc_type
= cp
->type
;
152 cis_ptr
= Cardbus_conf_read(csc
->cc_ct
, csc
->cc_tag
, CARDBUS_CIS_REG
);
154 /* otherwise try to deduce which BAR and type to use from CIS. If
155 there is only one BAR, it must be the one we should use, if
156 there are more, we're out of luck. */
157 for(i
= 0; i
< 7; i
++) {
158 /* ignore zero sized BARs */
159 if(ca
->ca_cis
.bar
[i
].size
== 0)
161 /* ignore the CIS BAR */
162 if(CARDBUS_CIS_ASI_BAR(cis_ptr
) ==
163 CARDBUS_CIS_ASI_BAR(ca
->ca_cis
.bar
[i
].flags
))
170 aprint_error(": couldn't find any base address tuple\n");
173 csc
->cc_reg
= CARDBUS_CIS_ASI_BAR(ca
->ca_cis
.bar
[index
].flags
);
174 if ((ca
->ca_cis
.bar
[index
].flags
& 0x10) == 0)
175 csc
->cc_type
= CARDBUS_MAPREG_TYPE_MEM
;
177 csc
->cc_type
= CARDBUS_MAPREG_TYPE_IO
;
181 aprint_error(": there are more than one possible base\n");
183 aprint_error_dev(DEVICET(csc
), "address for this device, "
184 "please report the following information\n");
185 aprint_error_dev(DEVICET(csc
), "vendor 0x%x product 0x%x\n",
186 CARDBUS_VENDOR(ca
->ca_id
), CARDBUS_PRODUCT(ca
->ca_id
));
187 for(i
= 0; i
< 7; i
++) {
188 /* ignore zero sized BARs */
189 if(ca
->ca_cis
.bar
[i
].size
== 0)
191 /* ignore the CIS BAR */
192 if(CARDBUS_CIS_ASI_BAR(cis_ptr
) ==
193 CARDBUS_CIS_ASI_BAR(ca
->ca_cis
.bar
[i
].flags
))
195 aprint_error_dev(DEVICET(csc
),
196 "base address %x type %s size %x\n",
197 CARDBUS_CIS_ASI_BAR(ca
->ca_cis
.bar
[i
].flags
),
198 (ca
->ca_cis
.bar
[i
].flags
& 0x10) ? "i/o" : "mem",
199 ca
->ca_cis
.bar
[i
].size
);
205 com_cardbus_attach (device_t parent
, device_t self
, void *aux
)
207 struct com_softc
*sc
= device_private(self
);
208 struct com_cardbus_softc
*csc
= device_private(self
);
209 struct cardbus_attach_args
*ca
= aux
;
210 bus_space_handle_t ioh
;
214 csc
->cc_ct
= ca
->ca_ct
;
215 csc
->cc_tag
= Cardbus_make_tag(csc
->cc_ct
);
217 if(gofigure(ca
, csc
) != 0)
220 if(Cardbus_mapreg_map(ca
->ca_ct
,
227 &csc
->cc_size
) != 0) {
228 aprint_error("failed to map memory");
232 COM_INIT_REGS(sc
->sc_regs
, iot
, ioh
, csc
->cc_addr
);
234 csc
->cc_base
= csc
->cc_addr
;
235 csc
->cc_csr
= CARDBUS_COMMAND_MASTER_ENABLE
;
236 if(csc
->cc_type
== CARDBUS_MAPREG_TYPE_IO
) {
237 csc
->cc_base
|= CARDBUS_MAPREG_TYPE_IO
;
238 csc
->cc_csr
|= CARDBUS_COMMAND_IO_ENABLE
;
239 csc
->cc_cben
= CARDBUS_IO_ENABLE
;
241 csc
->cc_csr
|= CARDBUS_COMMAND_MEM_ENABLE
;
242 csc
->cc_cben
= CARDBUS_MEM_ENABLE
;
245 sc
->sc_frequency
= COM_FREQ
;
247 sc
->enable
= com_cardbus_enable
;
248 sc
->disable
= com_cardbus_disable
;
251 if (ca
->ca_cis
.cis1_info
[0] && ca
->ca_cis
.cis1_info
[1]) {
252 aprint_normal(": %s %s\n", ca
->ca_cis
.cis1_info
[0],
253 ca
->ca_cis
.cis1_info
[1]);
254 aprint_normal("%s", device_xname(DEVICET(csc
)));
257 com_cardbus_setup(csc
);
261 Cardbus_function_disable(csc
->cc_ct
);
265 com_cardbus_setup(struct com_cardbus_softc
*csc
)
267 cardbus_devfunc_t ct
= csc
->cc_ct
;
268 cardbus_chipset_tag_t cc
= ct
->ct_cc
;
269 cardbus_function_tag_t cf
= ct
->ct_cf
;
272 Cardbus_conf_write(ct
, csc
->cc_tag
, csc
->cc_reg
, csc
->cc_base
);
274 /* enable accesses on cardbus bridge */
275 (*cf
->cardbus_ctrl
)(cc
, csc
->cc_cben
);
276 (*cf
->cardbus_ctrl
)(cc
, CARDBUS_BM_ENABLE
);
278 /* and the card itself */
279 reg
= Cardbus_conf_read(ct
, csc
->cc_tag
, CARDBUS_COMMAND_STATUS_REG
);
280 reg
&= ~(CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
);
282 Cardbus_conf_write(ct
, csc
->cc_tag
, CARDBUS_COMMAND_STATUS_REG
, reg
);
285 * Make sure the latency timer is set to some reasonable
288 reg
= cardbus_conf_read(cc
, cf
, csc
->cc_tag
, CARDBUS_BHLC_REG
);
289 if (CARDBUS_LATTIMER(reg
) < 0x20) {
290 reg
&= ~(CARDBUS_LATTIMER_MASK
<< CARDBUS_LATTIMER_SHIFT
);
291 reg
|= (0x20 << CARDBUS_LATTIMER_SHIFT
);
292 cardbus_conf_write(cc
, cf
, csc
->cc_tag
, CARDBUS_BHLC_REG
, reg
);
297 com_cardbus_enable(struct com_softc
*sc
)
299 struct com_cardbus_softc
*csc
= (struct com_cardbus_softc
*)sc
;
300 struct cardbus_softc
*psc
=
301 device_private(device_parent(sc
->sc_dev
));
302 cardbus_chipset_tag_t cc
= psc
->sc_cc
;
303 cardbus_function_tag_t cf
= psc
->sc_cf
;
305 Cardbus_function_enable(csc
->cc_ct
);
307 com_cardbus_setup(csc
);
309 /* establish the interrupt. */
310 csc
->cc_ih
= cardbus_intr_establish(cc
, cf
, psc
->sc_intrline
,
311 IPL_SERIAL
, comintr
, sc
);
312 if (csc
->cc_ih
== NULL
) {
313 aprint_error_dev(DEVICET(csc
),
314 "couldn't establish interrupt\n");
322 com_cardbus_disable(struct com_softc
*sc
)
324 struct com_cardbus_softc
*csc
= (struct com_cardbus_softc
*)sc
;
325 struct cardbus_softc
*psc
=
326 device_private(device_parent(sc
->sc_dev
));
327 cardbus_chipset_tag_t cc
= psc
->sc_cc
;
328 cardbus_function_tag_t cf
= psc
->sc_cf
;
330 cardbus_intr_disestablish(cc
, cf
, csc
->cc_ih
);
333 Cardbus_function_disable(csc
->cc_ct
);
337 com_cardbus_detach(device_t self
, int flags
)
339 struct com_cardbus_softc
*csc
= device_private(self
);
340 struct com_softc
*sc
= device_private(self
);
341 struct cardbus_softc
*psc
= device_private(device_parent(self
));
344 if ((error
= com_detach(self
, flags
)) != 0)
347 if (csc
->cc_ih
!= NULL
)
348 cardbus_intr_disestablish(psc
->sc_cc
, psc
->sc_cf
, csc
->cc_ih
);
350 Cardbus_mapreg_unmap(csc
->cc_ct
, csc
->cc_reg
, sc
->sc_regs
.cr_iot
,
351 sc
->sc_regs
.cr_ioh
, csc
->cc_size
);