1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2*4882a593Smuzhiyun /*======================================================================
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun A driver for PCMCIA serial devices
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun serial_cs.c 1.134 2002/05/04 05:48:53
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun The contents of this file are subject to the Mozilla Public
9*4882a593Smuzhiyun License Version 1.1 (the "License"); you may not use this file
10*4882a593Smuzhiyun except in compliance with the License. You may obtain a copy of
11*4882a593Smuzhiyun the License at http://www.mozilla.org/MPL/
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun Software distributed under the License is distributed on an "AS
14*4882a593Smuzhiyun IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15*4882a593Smuzhiyun implied. See the License for the specific language governing
16*4882a593Smuzhiyun rights and limitations under the License.
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun The initial developer of the original code is David A. Hinds
19*4882a593Smuzhiyun <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
20*4882a593Smuzhiyun are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun Alternatively, the contents of this file may be used under the
23*4882a593Smuzhiyun terms of the GNU General Public License version 2 (the "GPL"), in which
24*4882a593Smuzhiyun case the provisions of the GPL are applicable instead of the
25*4882a593Smuzhiyun above. If you wish to allow the use of your version of this file
26*4882a593Smuzhiyun only under the terms of the GPL and not to allow others to use
27*4882a593Smuzhiyun your version of this file under the MPL, indicate your decision
28*4882a593Smuzhiyun by deleting the provisions above and replace them with the notice
29*4882a593Smuzhiyun and other provisions required by the GPL. If you do not delete
30*4882a593Smuzhiyun the provisions above, a recipient may use your version of this
31*4882a593Smuzhiyun file under either the MPL or the GPL.
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun ======================================================================*/
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include <linux/module.h>
36*4882a593Smuzhiyun #include <linux/moduleparam.h>
37*4882a593Smuzhiyun #include <linux/kernel.h>
38*4882a593Smuzhiyun #include <linux/ptrace.h>
39*4882a593Smuzhiyun #include <linux/slab.h>
40*4882a593Smuzhiyun #include <linux/string.h>
41*4882a593Smuzhiyun #include <linux/timer.h>
42*4882a593Smuzhiyun #include <linux/serial_core.h>
43*4882a593Smuzhiyun #include <linux/delay.h>
44*4882a593Smuzhiyun #include <linux/major.h>
45*4882a593Smuzhiyun #include <asm/io.h>
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
48*4882a593Smuzhiyun #include <pcmcia/ciscode.h>
49*4882a593Smuzhiyun #include <pcmcia/ds.h>
50*4882a593Smuzhiyun #include <pcmcia/cisreg.h>
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #include "8250.h"
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*====================================================================*/
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* Parameters that can be set with 'insmod' */
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* Enable the speaker? */
60*4882a593Smuzhiyun static int do_sound = 1;
61*4882a593Smuzhiyun /* Skip strict UART tests? */
62*4882a593Smuzhiyun static int buggy_uart;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun module_param(do_sound, int, 0444);
65*4882a593Smuzhiyun module_param(buggy_uart, int, 0444);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /*====================================================================*/
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Table of multi-port card ID's */
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun struct serial_quirk {
72*4882a593Smuzhiyun unsigned int manfid;
73*4882a593Smuzhiyun unsigned int prodid;
74*4882a593Smuzhiyun int multi; /* 1 = multifunction, > 1 = # ports */
75*4882a593Smuzhiyun void (*config)(struct pcmcia_device *);
76*4882a593Smuzhiyun void (*setup)(struct pcmcia_device *, struct uart_8250_port *);
77*4882a593Smuzhiyun void (*wakeup)(struct pcmcia_device *);
78*4882a593Smuzhiyun int (*post)(struct pcmcia_device *);
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun struct serial_info {
82*4882a593Smuzhiyun struct pcmcia_device *p_dev;
83*4882a593Smuzhiyun int ndev;
84*4882a593Smuzhiyun int multi;
85*4882a593Smuzhiyun int slave;
86*4882a593Smuzhiyun int manfid;
87*4882a593Smuzhiyun int prodid;
88*4882a593Smuzhiyun int c950ctrl;
89*4882a593Smuzhiyun int line[4];
90*4882a593Smuzhiyun const struct serial_quirk *quirk;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun struct serial_cfg_mem {
94*4882a593Smuzhiyun tuple_t tuple;
95*4882a593Smuzhiyun cisparse_t parse;
96*4882a593Smuzhiyun u_char buf[256];
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
101*4882a593Smuzhiyun * manfid 0x0160, 0x0104
102*4882a593Smuzhiyun * This card appears to have a 14.7456MHz clock.
103*4882a593Smuzhiyun */
104*4882a593Smuzhiyun /* Generic Modem: MD55x (GPRS/EDGE) have
105*4882a593Smuzhiyun * Elan VPU16551 UART with 14.7456MHz oscillator
106*4882a593Smuzhiyun * manfid 0x015D, 0x4C45
107*4882a593Smuzhiyun */
quirk_setup_brainboxes_0104(struct pcmcia_device * link,struct uart_8250_port * uart)108*4882a593Smuzhiyun static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun uart->port.uartclk = 14745600;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
quirk_post_ibm(struct pcmcia_device * link)113*4882a593Smuzhiyun static int quirk_post_ibm(struct pcmcia_device *link)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun u8 val;
116*4882a593Smuzhiyun int ret;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun ret = pcmcia_read_config_byte(link, 0x800, &val);
119*4882a593Smuzhiyun if (ret)
120*4882a593Smuzhiyun goto failed;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun ret = pcmcia_write_config_byte(link, 0x800, val | 1);
123*4882a593Smuzhiyun if (ret)
124*4882a593Smuzhiyun goto failed;
125*4882a593Smuzhiyun return 0;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun failed:
128*4882a593Smuzhiyun return -ENODEV;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /*
132*4882a593Smuzhiyun * Nokia cards are not really multiport cards. Shouldn't this
133*4882a593Smuzhiyun * be handled by setting the quirk entry .multi = 0 | 1 ?
134*4882a593Smuzhiyun */
quirk_config_nokia(struct pcmcia_device * link)135*4882a593Smuzhiyun static void quirk_config_nokia(struct pcmcia_device *link)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun struct serial_info *info = link->priv;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (info->multi > 1)
140*4882a593Smuzhiyun info->multi = 1;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
quirk_wakeup_oxsemi(struct pcmcia_device * link)143*4882a593Smuzhiyun static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct serial_info *info = link->priv;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (info->c950ctrl)
148*4882a593Smuzhiyun outb(12, info->c950ctrl + 1);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* request_region? oxsemi branch does no request_region too... */
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun * This sequence is needed to properly initialize MC45 attached to OXCF950.
154*4882a593Smuzhiyun * I tried decreasing these msleep()s, but it worked properly (survived
155*4882a593Smuzhiyun * 1000 stop/start operations) with these timeouts (or bigger).
156*4882a593Smuzhiyun */
quirk_wakeup_possio_gcc(struct pcmcia_device * link)157*4882a593Smuzhiyun static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun struct serial_info *info = link->priv;
160*4882a593Smuzhiyun unsigned int ctrl = info->c950ctrl;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun outb(0xA, ctrl + 1);
163*4882a593Smuzhiyun msleep(100);
164*4882a593Smuzhiyun outb(0xE, ctrl + 1);
165*4882a593Smuzhiyun msleep(300);
166*4882a593Smuzhiyun outb(0xC, ctrl + 1);
167*4882a593Smuzhiyun msleep(100);
168*4882a593Smuzhiyun outb(0xE, ctrl + 1);
169*4882a593Smuzhiyun msleep(200);
170*4882a593Smuzhiyun outb(0xF, ctrl + 1);
171*4882a593Smuzhiyun msleep(100);
172*4882a593Smuzhiyun outb(0xE, ctrl + 1);
173*4882a593Smuzhiyun msleep(100);
174*4882a593Smuzhiyun outb(0xC, ctrl + 1);
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * Socket Dual IO: this enables irq's for second port
179*4882a593Smuzhiyun */
quirk_config_socket(struct pcmcia_device * link)180*4882a593Smuzhiyun static void quirk_config_socket(struct pcmcia_device *link)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun struct serial_info *info = link->priv;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (info->multi)
185*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_ESR;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static const struct serial_quirk quirks[] = {
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun .manfid = 0x0160,
191*4882a593Smuzhiyun .prodid = 0x0104,
192*4882a593Smuzhiyun .multi = -1,
193*4882a593Smuzhiyun .setup = quirk_setup_brainboxes_0104,
194*4882a593Smuzhiyun }, {
195*4882a593Smuzhiyun .manfid = 0x015D,
196*4882a593Smuzhiyun .prodid = 0x4C45,
197*4882a593Smuzhiyun .multi = -1,
198*4882a593Smuzhiyun .setup = quirk_setup_brainboxes_0104,
199*4882a593Smuzhiyun }, {
200*4882a593Smuzhiyun .manfid = MANFID_IBM,
201*4882a593Smuzhiyun .prodid = ~0,
202*4882a593Smuzhiyun .multi = -1,
203*4882a593Smuzhiyun .post = quirk_post_ibm,
204*4882a593Smuzhiyun }, {
205*4882a593Smuzhiyun .manfid = MANFID_INTEL,
206*4882a593Smuzhiyun .prodid = PRODID_INTEL_DUAL_RS232,
207*4882a593Smuzhiyun .multi = 2,
208*4882a593Smuzhiyun }, {
209*4882a593Smuzhiyun .manfid = MANFID_NATINST,
210*4882a593Smuzhiyun .prodid = PRODID_NATINST_QUAD_RS232,
211*4882a593Smuzhiyun .multi = 4,
212*4882a593Smuzhiyun }, {
213*4882a593Smuzhiyun .manfid = MANFID_NOKIA,
214*4882a593Smuzhiyun .prodid = ~0,
215*4882a593Smuzhiyun .multi = -1,
216*4882a593Smuzhiyun .config = quirk_config_nokia,
217*4882a593Smuzhiyun }, {
218*4882a593Smuzhiyun .manfid = MANFID_OMEGA,
219*4882a593Smuzhiyun .prodid = PRODID_OMEGA_QSP_100,
220*4882a593Smuzhiyun .multi = 4,
221*4882a593Smuzhiyun }, {
222*4882a593Smuzhiyun .manfid = MANFID_OXSEMI,
223*4882a593Smuzhiyun .prodid = ~0,
224*4882a593Smuzhiyun .multi = -1,
225*4882a593Smuzhiyun .wakeup = quirk_wakeup_oxsemi,
226*4882a593Smuzhiyun }, {
227*4882a593Smuzhiyun .manfid = MANFID_POSSIO,
228*4882a593Smuzhiyun .prodid = PRODID_POSSIO_GCC,
229*4882a593Smuzhiyun .multi = -1,
230*4882a593Smuzhiyun .wakeup = quirk_wakeup_possio_gcc,
231*4882a593Smuzhiyun }, {
232*4882a593Smuzhiyun .manfid = MANFID_QUATECH,
233*4882a593Smuzhiyun .prodid = PRODID_QUATECH_DUAL_RS232,
234*4882a593Smuzhiyun .multi = 2,
235*4882a593Smuzhiyun }, {
236*4882a593Smuzhiyun .manfid = MANFID_QUATECH,
237*4882a593Smuzhiyun .prodid = PRODID_QUATECH_DUAL_RS232_D1,
238*4882a593Smuzhiyun .multi = 2,
239*4882a593Smuzhiyun }, {
240*4882a593Smuzhiyun .manfid = MANFID_QUATECH,
241*4882a593Smuzhiyun .prodid = PRODID_QUATECH_DUAL_RS232_G,
242*4882a593Smuzhiyun .multi = 2,
243*4882a593Smuzhiyun }, {
244*4882a593Smuzhiyun .manfid = MANFID_QUATECH,
245*4882a593Smuzhiyun .prodid = PRODID_QUATECH_QUAD_RS232,
246*4882a593Smuzhiyun .multi = 4,
247*4882a593Smuzhiyun }, {
248*4882a593Smuzhiyun .manfid = MANFID_SOCKET,
249*4882a593Smuzhiyun .prodid = PRODID_SOCKET_DUAL_RS232,
250*4882a593Smuzhiyun .multi = 2,
251*4882a593Smuzhiyun .config = quirk_config_socket,
252*4882a593Smuzhiyun }, {
253*4882a593Smuzhiyun .manfid = MANFID_SOCKET,
254*4882a593Smuzhiyun .prodid = ~0,
255*4882a593Smuzhiyun .multi = -1,
256*4882a593Smuzhiyun .config = quirk_config_socket,
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun };
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun static int serial_config(struct pcmcia_device *link);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun
serial_remove(struct pcmcia_device * link)264*4882a593Smuzhiyun static void serial_remove(struct pcmcia_device *link)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun struct serial_info *info = link->priv;
267*4882a593Smuzhiyun int i;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun dev_dbg(&link->dev, "serial_release\n");
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /*
272*4882a593Smuzhiyun * Recheck to see if the device is still configured.
273*4882a593Smuzhiyun */
274*4882a593Smuzhiyun for (i = 0; i < info->ndev; i++)
275*4882a593Smuzhiyun serial8250_unregister_port(info->line[i]);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (!info->slave)
278*4882a593Smuzhiyun pcmcia_disable_device(link);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
serial_suspend(struct pcmcia_device * link)281*4882a593Smuzhiyun static int serial_suspend(struct pcmcia_device *link)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun struct serial_info *info = link->priv;
284*4882a593Smuzhiyun int i;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun for (i = 0; i < info->ndev; i++)
287*4882a593Smuzhiyun serial8250_suspend_port(info->line[i]);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
serial_resume(struct pcmcia_device * link)292*4882a593Smuzhiyun static int serial_resume(struct pcmcia_device *link)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct serial_info *info = link->priv;
295*4882a593Smuzhiyun int i;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun for (i = 0; i < info->ndev; i++)
298*4882a593Smuzhiyun serial8250_resume_port(info->line[i]);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (info->quirk && info->quirk->wakeup)
301*4882a593Smuzhiyun info->quirk->wakeup(link);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun return 0;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
serial_probe(struct pcmcia_device * link)306*4882a593Smuzhiyun static int serial_probe(struct pcmcia_device *link)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct serial_info *info;
309*4882a593Smuzhiyun int ret;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun dev_dbg(&link->dev, "serial_attach()\n");
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /* Create new serial device */
314*4882a593Smuzhiyun info = kzalloc(sizeof(*info), GFP_KERNEL);
315*4882a593Smuzhiyun if (!info)
316*4882a593Smuzhiyun return -ENOMEM;
317*4882a593Smuzhiyun info->p_dev = link;
318*4882a593Smuzhiyun link->priv = info;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
321*4882a593Smuzhiyun if (do_sound)
322*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_SPKR;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun ret = serial_config(link);
325*4882a593Smuzhiyun if (ret)
326*4882a593Smuzhiyun goto free_info;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun return 0;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun free_info:
331*4882a593Smuzhiyun kfree(info);
332*4882a593Smuzhiyun return ret;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
serial_detach(struct pcmcia_device * link)335*4882a593Smuzhiyun static void serial_detach(struct pcmcia_device *link)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun struct serial_info *info = link->priv;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun dev_dbg(&link->dev, "serial_detach\n");
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /*
342*4882a593Smuzhiyun * Ensure that the ports have been released.
343*4882a593Smuzhiyun */
344*4882a593Smuzhiyun serial_remove(link);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* free bits */
347*4882a593Smuzhiyun kfree(info);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /*====================================================================*/
351*4882a593Smuzhiyun
setup_serial(struct pcmcia_device * handle,struct serial_info * info,unsigned int iobase,int irq)352*4882a593Smuzhiyun static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
353*4882a593Smuzhiyun unsigned int iobase, int irq)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct uart_8250_port uart;
356*4882a593Smuzhiyun int line;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun memset(&uart, 0, sizeof(uart));
359*4882a593Smuzhiyun uart.port.iobase = iobase;
360*4882a593Smuzhiyun uart.port.irq = irq;
361*4882a593Smuzhiyun uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
362*4882a593Smuzhiyun uart.port.uartclk = 1843200;
363*4882a593Smuzhiyun uart.port.dev = &handle->dev;
364*4882a593Smuzhiyun if (buggy_uart)
365*4882a593Smuzhiyun uart.port.flags |= UPF_BUGGY_UART;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun if (info->quirk && info->quirk->setup)
368*4882a593Smuzhiyun info->quirk->setup(handle, &uart);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun line = serial8250_register_8250_port(&uart);
371*4882a593Smuzhiyun if (line < 0) {
372*4882a593Smuzhiyun pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
373*4882a593Smuzhiyun (unsigned long)iobase, irq);
374*4882a593Smuzhiyun return -EINVAL;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun info->line[info->ndev] = line;
378*4882a593Smuzhiyun info->ndev++;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun return 0;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /*====================================================================*/
384*4882a593Smuzhiyun
pfc_config(struct pcmcia_device * p_dev)385*4882a593Smuzhiyun static int pfc_config(struct pcmcia_device *p_dev)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun unsigned int port = 0;
388*4882a593Smuzhiyun struct serial_info *info = p_dev->priv;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if ((p_dev->resource[1]->end != 0) &&
391*4882a593Smuzhiyun (resource_size(p_dev->resource[1]) == 8)) {
392*4882a593Smuzhiyun port = p_dev->resource[1]->start;
393*4882a593Smuzhiyun info->slave = 1;
394*4882a593Smuzhiyun } else if ((info->manfid == MANFID_OSITECH) &&
395*4882a593Smuzhiyun (resource_size(p_dev->resource[0]) == 0x40)) {
396*4882a593Smuzhiyun port = p_dev->resource[0]->start + 0x28;
397*4882a593Smuzhiyun info->slave = 1;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun if (info->slave)
400*4882a593Smuzhiyun return setup_serial(p_dev, info, port, p_dev->irq);
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
403*4882a593Smuzhiyun return -ENODEV;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
simple_config_check(struct pcmcia_device * p_dev,void * priv_data)406*4882a593Smuzhiyun static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun static const int size_table[2] = { 8, 16 };
409*4882a593Smuzhiyun int *try = priv_data;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (p_dev->resource[0]->start == 0)
412*4882a593Smuzhiyun return -ENODEV;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if ((*try & 0x1) == 0)
415*4882a593Smuzhiyun p_dev->io_lines = 16;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (p_dev->resource[0]->end != size_table[(*try >> 1)])
418*4882a593Smuzhiyun return -ENODEV;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun p_dev->resource[0]->end = 8;
421*4882a593Smuzhiyun p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
422*4882a593Smuzhiyun p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun return pcmcia_request_io(p_dev);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
simple_config_check_notpicky(struct pcmcia_device * p_dev,void * priv_data)427*4882a593Smuzhiyun static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
428*4882a593Smuzhiyun void *priv_data)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
431*4882a593Smuzhiyun int j;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun if (p_dev->io_lines > 3)
434*4882a593Smuzhiyun return -ENODEV;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
437*4882a593Smuzhiyun p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
438*4882a593Smuzhiyun p_dev->resource[0]->end = 8;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun for (j = 0; j < 5; j++) {
441*4882a593Smuzhiyun p_dev->resource[0]->start = base[j];
442*4882a593Smuzhiyun p_dev->io_lines = base[j] ? 16 : 3;
443*4882a593Smuzhiyun if (!pcmcia_request_io(p_dev))
444*4882a593Smuzhiyun return 0;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun return -ENODEV;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
simple_config(struct pcmcia_device * link)449*4882a593Smuzhiyun static int simple_config(struct pcmcia_device *link)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun struct serial_info *info = link->priv;
452*4882a593Smuzhiyun int ret, try;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * First pass: look for a config entry that looks normal.
456*4882a593Smuzhiyun * Two tries: without IO aliases, then with aliases.
457*4882a593Smuzhiyun */
458*4882a593Smuzhiyun link->config_flags |= CONF_AUTO_SET_VPP;
459*4882a593Smuzhiyun for (try = 0; try < 4; try++)
460*4882a593Smuzhiyun if (!pcmcia_loop_config(link, simple_config_check, &try))
461*4882a593Smuzhiyun goto found_port;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /*
464*4882a593Smuzhiyun * Second pass: try to find an entry that isn't picky about
465*4882a593Smuzhiyun * its base address, then try to grab any standard serial port
466*4882a593Smuzhiyun * address, and finally try to get any free port.
467*4882a593Smuzhiyun */
468*4882a593Smuzhiyun if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
469*4882a593Smuzhiyun goto found_port;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun dev_warn(&link->dev, "no usable port range found, giving up\n");
472*4882a593Smuzhiyun return -1;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun found_port:
475*4882a593Smuzhiyun if (info->multi && (info->manfid == MANFID_3COM))
476*4882a593Smuzhiyun link->config_index &= ~(0x08);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * Apply any configuration quirks.
480*4882a593Smuzhiyun */
481*4882a593Smuzhiyun if (info->quirk && info->quirk->config)
482*4882a593Smuzhiyun info->quirk->config(link);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun ret = pcmcia_enable_device(link);
485*4882a593Smuzhiyun if (ret != 0)
486*4882a593Smuzhiyun return -1;
487*4882a593Smuzhiyun return setup_serial(link, info, link->resource[0]->start, link->irq);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
multi_config_check(struct pcmcia_device * p_dev,void * priv_data)490*4882a593Smuzhiyun static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun int *multi = priv_data;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (p_dev->resource[1]->end)
495*4882a593Smuzhiyun return -EINVAL;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /*
498*4882a593Smuzhiyun * The quad port cards have bad CIS's, so just look for a
499*4882a593Smuzhiyun * window larger than 8 ports and assume it will be right.
500*4882a593Smuzhiyun */
501*4882a593Smuzhiyun if (p_dev->resource[0]->end <= 8)
502*4882a593Smuzhiyun return -EINVAL;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
505*4882a593Smuzhiyun p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
506*4882a593Smuzhiyun p_dev->resource[0]->end = *multi * 8;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun if (pcmcia_request_io(p_dev))
509*4882a593Smuzhiyun return -ENODEV;
510*4882a593Smuzhiyun return 0;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
multi_config_check_notpicky(struct pcmcia_device * p_dev,void * priv_data)513*4882a593Smuzhiyun static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
514*4882a593Smuzhiyun void *priv_data)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun int *base2 = priv_data;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (!p_dev->resource[0]->end || !p_dev->resource[1]->end ||
519*4882a593Smuzhiyun p_dev->resource[0]->start + 8 != p_dev->resource[1]->start)
520*4882a593Smuzhiyun return -ENODEV;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
523*4882a593Smuzhiyun p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
524*4882a593Smuzhiyun p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun if (pcmcia_request_io(p_dev))
527*4882a593Smuzhiyun return -ENODEV;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun *base2 = p_dev->resource[0]->start + 8;
530*4882a593Smuzhiyun return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
multi_config(struct pcmcia_device * link)533*4882a593Smuzhiyun static int multi_config(struct pcmcia_device *link)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun struct serial_info *info = link->priv;
536*4882a593Smuzhiyun int i, base2 = 0;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /* First, look for a generic full-sized window */
539*4882a593Smuzhiyun if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
540*4882a593Smuzhiyun base2 = link->resource[0]->start + 8;
541*4882a593Smuzhiyun else {
542*4882a593Smuzhiyun /* If that didn't work, look for two windows */
543*4882a593Smuzhiyun info->multi = 2;
544*4882a593Smuzhiyun if (pcmcia_loop_config(link, multi_config_check_notpicky,
545*4882a593Smuzhiyun &base2)) {
546*4882a593Smuzhiyun dev_warn(&link->dev,
547*4882a593Smuzhiyun "no usable port range found, giving up\n");
548*4882a593Smuzhiyun return -ENODEV;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if (!link->irq)
553*4882a593Smuzhiyun dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /*
556*4882a593Smuzhiyun * Apply any configuration quirks.
557*4882a593Smuzhiyun */
558*4882a593Smuzhiyun if (info->quirk && info->quirk->config)
559*4882a593Smuzhiyun info->quirk->config(link);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun i = pcmcia_enable_device(link);
562*4882a593Smuzhiyun if (i != 0)
563*4882a593Smuzhiyun return -ENODEV;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
566*4882a593Smuzhiyun * 8 registers are for the UART, the others are extra registers.
567*4882a593Smuzhiyun * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
568*4882a593Smuzhiyun */
569*4882a593Smuzhiyun if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
570*4882a593Smuzhiyun info->prodid == PRODID_POSSIO_GCC)) {
571*4882a593Smuzhiyun int err;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (link->config_index == 1 ||
574*4882a593Smuzhiyun link->config_index == 3) {
575*4882a593Smuzhiyun err = setup_serial(link, info, base2,
576*4882a593Smuzhiyun link->irq);
577*4882a593Smuzhiyun base2 = link->resource[0]->start;
578*4882a593Smuzhiyun } else {
579*4882a593Smuzhiyun err = setup_serial(link, info, link->resource[0]->start,
580*4882a593Smuzhiyun link->irq);
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun info->c950ctrl = base2;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /*
585*4882a593Smuzhiyun * FIXME: We really should wake up the port prior to
586*4882a593Smuzhiyun * handing it over to the serial layer.
587*4882a593Smuzhiyun */
588*4882a593Smuzhiyun if (info->quirk && info->quirk->wakeup)
589*4882a593Smuzhiyun info->quirk->wakeup(link);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun return 0;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun setup_serial(link, info, link->resource[0]->start, link->irq);
595*4882a593Smuzhiyun for (i = 0; i < info->multi - 1; i++)
596*4882a593Smuzhiyun setup_serial(link, info, base2 + (8 * i),
597*4882a593Smuzhiyun link->irq);
598*4882a593Smuzhiyun return 0;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
serial_check_for_multi(struct pcmcia_device * p_dev,void * priv_data)601*4882a593Smuzhiyun static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun struct serial_info *info = p_dev->priv;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun if (!p_dev->resource[0]->end)
606*4882a593Smuzhiyun return -EINVAL;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
609*4882a593Smuzhiyun info->multi = p_dev->resource[0]->end >> 3;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
612*4882a593Smuzhiyun && (p_dev->resource[1]->end == 8))
613*4882a593Smuzhiyun info->multi = 2;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun return 0; /* break */
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun
serial_config(struct pcmcia_device * link)619*4882a593Smuzhiyun static int serial_config(struct pcmcia_device *link)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun struct serial_info *info = link->priv;
622*4882a593Smuzhiyun int i;
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun dev_dbg(&link->dev, "serial_config\n");
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /* Is this a compliant multifunction card? */
627*4882a593Smuzhiyun info->multi = (link->socket->functions > 1);
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun /* Is this a multiport card? */
630*4882a593Smuzhiyun info->manfid = link->manf_id;
631*4882a593Smuzhiyun info->prodid = link->card_id;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(quirks); i++)
634*4882a593Smuzhiyun if ((quirks[i].manfid == ~0 ||
635*4882a593Smuzhiyun quirks[i].manfid == info->manfid) &&
636*4882a593Smuzhiyun (quirks[i].prodid == ~0 ||
637*4882a593Smuzhiyun quirks[i].prodid == info->prodid)) {
638*4882a593Smuzhiyun info->quirk = &quirks[i];
639*4882a593Smuzhiyun break;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun /*
643*4882a593Smuzhiyun * Another check for dual-serial cards: look for either serial or
644*4882a593Smuzhiyun * multifunction cards that ask for appropriate IO port ranges.
645*4882a593Smuzhiyun */
646*4882a593Smuzhiyun if ((info->multi == 0) &&
647*4882a593Smuzhiyun (link->has_func_id) &&
648*4882a593Smuzhiyun (link->socket->pcmcia_pfc == 0) &&
649*4882a593Smuzhiyun ((link->func_id == CISTPL_FUNCID_MULTI) ||
650*4882a593Smuzhiyun (link->func_id == CISTPL_FUNCID_SERIAL))) {
651*4882a593Smuzhiyun if (pcmcia_loop_config(link, serial_check_for_multi, info))
652*4882a593Smuzhiyun goto failed;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun /*
656*4882a593Smuzhiyun * Apply any multi-port quirk.
657*4882a593Smuzhiyun */
658*4882a593Smuzhiyun if (info->quirk && info->quirk->multi != -1)
659*4882a593Smuzhiyun info->multi = info->quirk->multi;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun dev_info(&link->dev,
662*4882a593Smuzhiyun "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
663*4882a593Smuzhiyun link->manf_id, link->card_id,
664*4882a593Smuzhiyun link->socket->pcmcia_pfc, info->multi, info->quirk);
665*4882a593Smuzhiyun if (link->socket->pcmcia_pfc)
666*4882a593Smuzhiyun i = pfc_config(link);
667*4882a593Smuzhiyun else if (info->multi > 1)
668*4882a593Smuzhiyun i = multi_config(link);
669*4882a593Smuzhiyun else
670*4882a593Smuzhiyun i = simple_config(link);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (i || info->ndev == 0)
673*4882a593Smuzhiyun goto failed;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /*
676*4882a593Smuzhiyun * Apply any post-init quirk. FIXME: This should really happen
677*4882a593Smuzhiyun * before we register the port, since it might already be in use.
678*4882a593Smuzhiyun */
679*4882a593Smuzhiyun if (info->quirk && info->quirk->post)
680*4882a593Smuzhiyun if (info->quirk->post(link))
681*4882a593Smuzhiyun goto failed;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun return 0;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun failed:
686*4882a593Smuzhiyun dev_warn(&link->dev, "failed to initialize\n");
687*4882a593Smuzhiyun serial_remove(link);
688*4882a593Smuzhiyun return -ENODEV;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun static const struct pcmcia_device_id serial_ids[] = {
692*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
693*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
694*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
695*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
696*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
697*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
698*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
699*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
700*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
701*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
702*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
703*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
704*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
705*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
706*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
707*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
708*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
709*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
710*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
711*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
712*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
713*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
714*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
715*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
716*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
717*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
718*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
719*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
720*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
721*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
722*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
723*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
724*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
725*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
726*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
727*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
728*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
729*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
730*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
731*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
732*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
733*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0b05),
734*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
735*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
736*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
737*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
738*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
739*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
740*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
741*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
742*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
743*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
744*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
745*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
746*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
747*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
748*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
749*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
750*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
751*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
752*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
753*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
754*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
755*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
756*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
757*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
758*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
759*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
760*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
761*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
762*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
763*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
764*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
765*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
766*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
767*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
768*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
769*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
770*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
771*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
772*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
773*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
774*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
775*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
776*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
777*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
778*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
779*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
780*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
781*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
782*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
783*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
784*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
785*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
786*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
787*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
788*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
789*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
790*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
791*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
792*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Option International", "GSM-Ready 56K/ISDN", 0x9d7cd6f5, 0xb23844aa),
793*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
794*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
795*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
796*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
797*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
798*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
799*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
800*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
801*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
802*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
803*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
804*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
805*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
806*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
807*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
808*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
809*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
810*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
811*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */
812*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
813*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
814*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
815*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
816*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
817*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
818*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
819*4882a593Smuzhiyun PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
820*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
821*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
822*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
823*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
824*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
825*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
826*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
827*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
828*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
829*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
830*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
831*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
832*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
833*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
834*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
835*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
836*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
837*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
838*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
839*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
840*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
841*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
842*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
843*4882a593Smuzhiyun PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
844*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
845*4882a593Smuzhiyun /* too generic */
846*4882a593Smuzhiyun /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
847*4882a593Smuzhiyun /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
848*4882a593Smuzhiyun PCMCIA_DEVICE_FUNC_ID(2),
849*4882a593Smuzhiyun PCMCIA_DEVICE_NULL,
850*4882a593Smuzhiyun };
851*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, serial_ids);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun MODULE_FIRMWARE("cis/PCMLM28.cis");
854*4882a593Smuzhiyun MODULE_FIRMWARE("cis/DP83903.cis");
855*4882a593Smuzhiyun MODULE_FIRMWARE("cis/3CCFEM556.cis");
856*4882a593Smuzhiyun MODULE_FIRMWARE("cis/3CXEM556.cis");
857*4882a593Smuzhiyun MODULE_FIRMWARE("cis/SW_8xx_SER.cis");
858*4882a593Smuzhiyun MODULE_FIRMWARE("cis/SW_7xx_SER.cis");
859*4882a593Smuzhiyun MODULE_FIRMWARE("cis/SW_555_SER.cis");
860*4882a593Smuzhiyun MODULE_FIRMWARE("cis/MT5634ZLX.cis");
861*4882a593Smuzhiyun MODULE_FIRMWARE("cis/COMpad2.cis");
862*4882a593Smuzhiyun MODULE_FIRMWARE("cis/COMpad4.cis");
863*4882a593Smuzhiyun MODULE_FIRMWARE("cis/RS-COM-2P.cis");
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun static struct pcmcia_driver serial_cs_driver = {
866*4882a593Smuzhiyun .owner = THIS_MODULE,
867*4882a593Smuzhiyun .name = "serial_cs",
868*4882a593Smuzhiyun .probe = serial_probe,
869*4882a593Smuzhiyun .remove = serial_detach,
870*4882a593Smuzhiyun .id_table = serial_ids,
871*4882a593Smuzhiyun .suspend = serial_suspend,
872*4882a593Smuzhiyun .resume = serial_resume,
873*4882a593Smuzhiyun };
874*4882a593Smuzhiyun module_pcmcia_driver(serial_cs_driver);
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun MODULE_LICENSE("GPL");
877