1 | /* $NetBSD: com_pcmcia.c,v 1.61 2009/11/23 02:13:47 rmind Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
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 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /*- |
33 | * Copyright (c) 1991 The Regents of the University of California. |
34 | * All rights reserved. |
35 | * |
36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions |
38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. Neither the name of the University nor the names of its contributors |
45 | * may be used to endorse or promote products derived from this software |
46 | * without specific prior written permission. |
47 | * |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. |
59 | * |
60 | * @(#)com.c 7.5 (Berkeley) 5/16/91 |
61 | */ |
62 | |
63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: com_pcmcia.c,v 1.61 2009/11/23 02:13:47 rmind Exp $" ); |
65 | |
66 | #include <sys/param.h> |
67 | #include <sys/systm.h> |
68 | #include <sys/ioctl.h> |
69 | #include <sys/select.h> |
70 | #include <sys/tty.h> |
71 | #include <sys/proc.h> |
72 | #include <sys/conf.h> |
73 | #include <sys/file.h> |
74 | #include <sys/uio.h> |
75 | #include <sys/kernel.h> |
76 | #include <sys/syslog.h> |
77 | #include <sys/device.h> |
78 | |
79 | #include <sys/intr.h> |
80 | #include <sys/bus.h> |
81 | |
82 | #include <dev/pcmcia/pcmciavar.h> |
83 | #include <dev/pcmcia/pcmciareg.h> |
84 | #include <dev/pcmcia/pcmciadevs.h> |
85 | |
86 | #include <dev/ic/comreg.h> |
87 | #include <dev/ic/comvar.h> |
88 | |
89 | #include <dev/isa/isareg.h> |
90 | |
91 | int com_pcmcia_match(device_t, cfdata_t , void *); |
92 | int com_pcmcia_validate_config(struct pcmcia_config_entry *); |
93 | void com_pcmcia_attach(device_t, device_t, void *); |
94 | int com_pcmcia_detach(device_t, int); |
95 | |
96 | int com_pcmcia_enable(struct com_softc *); |
97 | void com_pcmcia_disable(struct com_softc *); |
98 | |
99 | struct com_pcmcia_softc { |
100 | struct com_softc sc_com; /* real "com" softc */ |
101 | |
102 | /* PCMCIA-specific goo */ |
103 | struct pcmcia_function *sc_pf; /* our PCMCIA function */ |
104 | void *sc_ih; /* interrupt handler */ |
105 | int sc_attached; |
106 | }; |
107 | |
108 | CFATTACH_DECL_NEW(com_pcmcia, sizeof(struct com_pcmcia_softc), |
109 | com_pcmcia_match, com_pcmcia_attach, com_pcmcia_detach, NULL); |
110 | |
111 | static const struct pcmcia_product com_pcmcia_products[] = { |
112 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
113 | PCMCIA_CIS_MEGAHERTZ_XJ2288 }, |
114 | { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_BLUETOOTH_PCCARD, |
115 | PCMCIA_CIS_INVALID }, |
116 | }; |
117 | static const size_t com_pcmcia_nproducts = |
118 | sizeof(com_pcmcia_products) / sizeof(com_pcmcia_products[0]); |
119 | |
120 | int |
121 | com_pcmcia_match(device_t parent, cfdata_t match, void *aux) |
122 | { |
123 | int comportmask; |
124 | struct pcmcia_attach_args *pa = aux; |
125 | struct pcmcia_config_entry *cfe; |
126 | |
127 | /* 1. Does it claim to be a serial device? */ |
128 | if (pa->pf->function == PCMCIA_FUNCTION_SERIAL) |
129 | return 1; |
130 | |
131 | /* 2. Does it have all four 'standard' port ranges? */ |
132 | comportmask = 0; |
133 | SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) { |
134 | switch (cfe->iospace[0].start) { |
135 | case IO_COM1: |
136 | comportmask |= 1; |
137 | break; |
138 | case IO_COM2: |
139 | comportmask |= 2; |
140 | break; |
141 | case IO_COM3: |
142 | comportmask |= 4; |
143 | break; |
144 | case IO_COM4: |
145 | comportmask |= 8; |
146 | break; |
147 | } |
148 | } |
149 | |
150 | if (comportmask == 15) |
151 | return 1; |
152 | |
153 | /* 3. Is this a card we know about? */ |
154 | if (pcmcia_product_lookup(pa, com_pcmcia_products, com_pcmcia_nproducts, |
155 | sizeof(com_pcmcia_products[0]), NULL)) |
156 | return 1; |
157 | |
158 | return 0; |
159 | } |
160 | |
161 | int |
162 | com_pcmcia_validate_config(struct pcmcia_config_entry *cfe) |
163 | { |
164 | if (cfe->iftype != PCMCIA_IFTYPE_IO || |
165 | cfe->num_iospace != 1) |
166 | return (EINVAL); |
167 | /* Some cards have a memory space, but we don't use it. */ |
168 | cfe->num_memspace = 0; |
169 | return (0); |
170 | } |
171 | |
172 | void |
173 | com_pcmcia_attach(device_t parent, device_t self, void *aux) |
174 | { |
175 | struct com_pcmcia_softc *psc = device_private(self); |
176 | struct com_softc *sc = &psc->sc_com; |
177 | struct pcmcia_attach_args *pa = aux; |
178 | struct pcmcia_config_entry *cfe; |
179 | int error; |
180 | |
181 | sc->sc_dev = self; |
182 | psc->sc_pf = pa->pf; |
183 | |
184 | error = pcmcia_function_configure(pa->pf, com_pcmcia_validate_config); |
185 | if (error) { |
186 | aprint_error_dev(self, "configure failed, error=%d\n" , error); |
187 | return; |
188 | } |
189 | |
190 | cfe = pa->pf->cfe; |
191 | COM_INIT_REGS(sc->sc_regs, cfe->iospace[0].handle.iot, |
192 | cfe->iospace[0].handle.ioh, -1); |
193 | |
194 | error = com_pcmcia_enable(sc); |
195 | if (error) |
196 | goto fail; |
197 | |
198 | sc->enabled = 1; |
199 | |
200 | sc->sc_frequency = COM_FREQ; |
201 | |
202 | sc->enable = com_pcmcia_enable; |
203 | sc->disable = com_pcmcia_disable; |
204 | |
205 | aprint_normal("%s" , device_xname(self)); |
206 | |
207 | com_attach_subr(sc); |
208 | |
209 | if (!pmf_device_register1(self, com_suspend, com_resume, |
210 | com_cleanup)) |
211 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
212 | |
213 | sc->enabled = 0; |
214 | |
215 | psc->sc_attached = 1; |
216 | com_pcmcia_disable(sc); |
217 | return; |
218 | |
219 | fail: |
220 | pcmcia_function_unconfigure(pa->pf); |
221 | } |
222 | |
223 | int |
224 | com_pcmcia_detach(device_t self, int flags) |
225 | { |
226 | struct com_pcmcia_softc *psc = device_private(self); |
227 | int error; |
228 | |
229 | if (!psc->sc_attached) |
230 | return (0); |
231 | |
232 | if ((error = com_detach(self, flags)) != 0) |
233 | return error; |
234 | |
235 | pmf_device_deregister(self); |
236 | |
237 | pcmcia_function_unconfigure(psc->sc_pf); |
238 | return (0); |
239 | } |
240 | |
241 | int |
242 | com_pcmcia_enable(struct com_softc *sc) |
243 | { |
244 | struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; |
245 | struct pcmcia_function *pf = psc->sc_pf; |
246 | int error; |
247 | |
248 | /* establish the interrupt. */ |
249 | psc->sc_ih = pcmcia_intr_establish(pf, IPL_SERIAL, comintr, sc); |
250 | if (psc->sc_ih == NULL) { |
251 | aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n" ); |
252 | return (1); |
253 | } |
254 | |
255 | if ((error = pcmcia_function_enable(pf)) != 0) { |
256 | pcmcia_intr_disestablish(pf, psc->sc_ih); |
257 | psc->sc_ih = 0; |
258 | return (error); |
259 | } |
260 | |
261 | if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) || |
262 | (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) || |
263 | (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556INT)) { |
264 | int reg; |
265 | |
266 | /* turn off the ethernet-disable bit */ |
267 | reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); |
268 | if (reg & 0x08) { |
269 | reg &= ~0x08; |
270 | pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); |
271 | } |
272 | } |
273 | |
274 | return (0); |
275 | } |
276 | |
277 | void |
278 | com_pcmcia_disable(struct com_softc *sc) |
279 | { |
280 | struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; |
281 | |
282 | pcmcia_function_disable(psc->sc_pf); |
283 | pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); |
284 | psc->sc_ih = 0; |
285 | } |
286 | |