diff options
Diffstat (limited to 'drivers/pcmcia')
61 files changed, 24437 insertions, 0 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig new file mode 100644 index 000000000000..6375ebc85020 --- /dev/null +++ b/drivers/pcmcia/Kconfig | |||
@@ -0,0 +1,203 @@ | |||
1 | # | ||
2 | # PCMCIA bus subsystem configuration | ||
3 | # | ||
4 | # Right now the non-CardBus choices are not supported | ||
5 | # by the integrated kernel driver. | ||
6 | # | ||
7 | |||
8 | menu "PCCARD (PCMCIA/CardBus) support" | ||
9 | |||
10 | config PCCARD | ||
11 | tristate "PCCard (PCMCIA/CardBus) support" | ||
12 | select HOTPLUG | ||
13 | ---help--- | ||
14 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux | ||
15 | computer. These are credit-card size devices such as network cards, | ||
16 | modems or hard drives often used with laptops computers. There are | ||
17 | actually two varieties of these cards: the older 16 bit PCMCIA cards | ||
18 | and the newer 32 bit CardBus cards. | ||
19 | |||
20 | To compile this driver as modules, choose M here: the | ||
21 | module will be called pcmcia_core. | ||
22 | |||
23 | if PCCARD | ||
24 | |||
25 | config PCMCIA_DEBUG | ||
26 | bool "Enable PCCARD debugging" | ||
27 | help | ||
28 | Say Y here to enable PCMCIA subsystem debugging. You | ||
29 | will need to choose the debugging level either via the | ||
30 | kernel command line, or module options depending whether | ||
31 | you build the PCMCIA as modules. | ||
32 | |||
33 | The kernel command line options are: | ||
34 | pcmcia_core.pc_debug=N | ||
35 | ds.pc_debug=N | ||
36 | sa11xx_core.pc_debug=N | ||
37 | |||
38 | The module option is called pc_debug=N | ||
39 | |||
40 | In all the above examples, N is the debugging verbosity | ||
41 | level. | ||
42 | |||
43 | config PCMCIA | ||
44 | tristate "16-bit PCMCIA support" | ||
45 | default y | ||
46 | ---help--- | ||
47 | This option enables support for 16-bit PCMCIA cards. Most older | ||
48 | PC-cards are such 16-bit PCMCIA cards, so unless you know you're | ||
49 | only using 32-bit CardBus cards, say Y or M here. | ||
50 | |||
51 | To use 16-bit PCMCIA cards, you will need supporting software from | ||
52 | David Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
53 | for location). Please also read the PCMCIA-HOWTO, available from | ||
54 | <http://www.tldp.org/docs.html#howto>. | ||
55 | |||
56 | To compile this driver as modules, choose M here: the | ||
57 | module will be called pcmcia. | ||
58 | |||
59 | If unsure, say Y. | ||
60 | |||
61 | config CARDBUS | ||
62 | bool "32-bit CardBus support" | ||
63 | depends on PCI | ||
64 | default y | ||
65 | ---help--- | ||
66 | CardBus is a bus mastering architecture for PC-cards, which allows | ||
67 | for 32 bit PC-cards (the original PCMCIA standard specifies only | ||
68 | a 16 bit wide bus). Many newer PC-cards are actually CardBus cards. | ||
69 | |||
70 | To use 32 bit PC-cards, you also need a CardBus compatible host | ||
71 | bridge. Virtually all modern PCMCIA bridges do this, and most of | ||
72 | them are "yenta-compatible", so say Y or M there, too. | ||
73 | |||
74 | If unsure, say Y. | ||
75 | |||
76 | comment "PC-card bridges" | ||
77 | |||
78 | config YENTA | ||
79 | tristate "CardBus yenta-compatible bridge support" | ||
80 | depends on PCI | ||
81 | #fixme: remove dependendcy on CARDBUS | ||
82 | depends on CARDBUS | ||
83 | select PCCARD_NONSTATIC | ||
84 | ---help--- | ||
85 | This option enables support for CardBus host bridges. Virtually | ||
86 | all modern PCMCIA bridges are CardBus compatible. A "bridge" is | ||
87 | the hardware inside your computer that PCMCIA cards are plugged | ||
88 | into. | ||
89 | |||
90 | To compile this driver as modules, choose M here: the | ||
91 | module will be called yenta_socket. | ||
92 | |||
93 | If unsure, say Y. | ||
94 | |||
95 | config PD6729 | ||
96 | tristate "Cirrus PD6729 compatible bridge support" | ||
97 | depends on PCMCIA && PCI | ||
98 | select PCCARD_NONSTATIC | ||
99 | help | ||
100 | This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge | ||
101 | device, found in some older laptops and PCMCIA card readers. | ||
102 | |||
103 | config I82092 | ||
104 | tristate "i82092 compatible bridge support" | ||
105 | depends on PCMCIA && PCI | ||
106 | select PCCARD_NONSTATIC | ||
107 | help | ||
108 | This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device, | ||
109 | found in some older laptops and more commonly in evaluation boards for the | ||
110 | chip. | ||
111 | |||
112 | config I82365 | ||
113 | tristate "i82365 compatible bridge support" | ||
114 | depends on PCMCIA && ISA | ||
115 | select PCCARD_NONSTATIC | ||
116 | help | ||
117 | Say Y here to include support for ISA-bus PCMCIA host bridges that | ||
118 | are register compatible with the Intel i82365. These are found on | ||
119 | older laptops and ISA-bus card readers for desktop systems. A | ||
120 | "bridge" is the hardware inside your computer that PCMCIA cards are | ||
121 | plugged into. If unsure, say N. | ||
122 | |||
123 | config TCIC | ||
124 | tristate "Databook TCIC host bridge support" | ||
125 | depends on PCMCIA | ||
126 | select PCCARD_NONSTATIC | ||
127 | help | ||
128 | Say Y here to include support for the Databook TCIC family of PCMCIA | ||
129 | host bridges. These are only found on a handful of old systems. | ||
130 | "Bridge" is the name used for the hardware inside your computer that | ||
131 | PCMCIA cards are plugged into. If unsure, say N. | ||
132 | |||
133 | config HD64465_PCMCIA | ||
134 | tristate "HD64465 host bridge support" | ||
135 | depends on HD64465 && PCMCIA | ||
136 | |||
137 | config PCMCIA_AU1X00 | ||
138 | tristate "Au1x00 pcmcia support" | ||
139 | depends on SOC_AU1X00 && PCMCIA | ||
140 | |||
141 | config PCMCIA_SA1100 | ||
142 | tristate "SA1100 support" | ||
143 | depends on ARM && ARCH_SA1100 && PCMCIA | ||
144 | help | ||
145 | Say Y here to include support for SA11x0-based PCMCIA or CF | ||
146 | sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ | ||
147 | Xscale(R) embedded machines. | ||
148 | |||
149 | This driver is also available as a module called sa1100_cs. | ||
150 | |||
151 | config PCMCIA_SA1111 | ||
152 | tristate "SA1111 support" | ||
153 | depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA | ||
154 | help | ||
155 | Say Y here to include support for SA1111-based PCMCIA or CF | ||
156 | sockets, found on the Jornada 720, Graphicsmaster and other | ||
157 | StrongARM(R)/Xscale(R) embedded machines. | ||
158 | |||
159 | This driver is also available as a module called sa1111_cs. | ||
160 | |||
161 | config PCMCIA_PXA2XX | ||
162 | tristate "PXA2xx support" | ||
163 | depends on ARM && ARCH_PXA && PCMCIA | ||
164 | help | ||
165 | Say Y here to include support for the PXA2xx PCMCIA controller | ||
166 | |||
167 | config PCMCIA_PROBE | ||
168 | bool | ||
169 | default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X | ||
170 | |||
171 | config M32R_PCC | ||
172 | bool "M32R PCMCIA I/F" | ||
173 | depends on M32R && CHIP_M32700 && PCMCIA | ||
174 | help | ||
175 | Say Y here to use the M32R PCMCIA controller. | ||
176 | |||
177 | config M32R_CFC | ||
178 | bool "M32R CF I/F Controller" | ||
179 | depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT) | ||
180 | help | ||
181 | Say Y here to use the M32R CompactFlash controller. | ||
182 | |||
183 | config M32R_CFC_NUM | ||
184 | int "M32R CF I/F number" | ||
185 | depends on M32R_CFC | ||
186 | default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT | ||
187 | help | ||
188 | Set the number of M32R CF slots. | ||
189 | |||
190 | config PCMCIA_VRC4171 | ||
191 | tristate "NEC VRC4171 Card Controllers support" | ||
192 | depends on VRC4171 && PCMCIA | ||
193 | |||
194 | config PCMCIA_VRC4173 | ||
195 | tristate "NEC VRC4173 CARDU support" | ||
196 | depends on CPU_VR41XX && PCI && PCMCIA | ||
197 | |||
198 | config PCCARD_NONSTATIC | ||
199 | tristate | ||
200 | |||
201 | endif # PCCARD | ||
202 | |||
203 | endmenu | ||
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile new file mode 100644 index 000000000000..50c29361bc5f --- /dev/null +++ b/drivers/pcmcia/Makefile | |||
@@ -0,0 +1,65 @@ | |||
1 | # | ||
2 | # Makefile for the kernel pcmcia subsystem (c/o David Hinds) | ||
3 | # | ||
4 | |||
5 | ifeq ($(CONFIG_PCMCIA_DEBUG),y) | ||
6 | EXTRA_CFLAGS += -DDEBUG | ||
7 | endif | ||
8 | |||
9 | pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o | ||
10 | pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o | ||
11 | obj-$(CONFIG_PCCARD) += pcmcia_core.o | ||
12 | |||
13 | pcmcia-y += ds.o pcmcia_compat.o | ||
14 | obj-$(CONFIG_PCMCIA) += pcmcia.o | ||
15 | |||
16 | obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o | ||
17 | |||
18 | |||
19 | # socket drivers | ||
20 | |||
21 | obj-$(CONFIG_YENTA) += yenta_socket.o | ||
22 | |||
23 | obj-$(CONFIG_PD6729) += pd6729.o | ||
24 | obj-$(CONFIG_I82365) += i82365.o | ||
25 | obj-$(CONFIG_I82092) += i82092.o | ||
26 | obj-$(CONFIG_TCIC) += tcic.o | ||
27 | obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o | ||
28 | obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o | ||
29 | obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o | ||
30 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o pxa2xx_cs.o | ||
31 | obj-$(CONFIG_M32R_PCC) += m32r_pcc.o | ||
32 | obj-$(CONFIG_M32R_CFC) += m32r_cfc.o | ||
33 | obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o | ||
34 | obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o | ||
35 | obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o | ||
36 | |||
37 | sa11xx_core-y += soc_common.o sa11xx_base.o | ||
38 | pxa2xx_core-y += soc_common.o pxa2xx_base.o | ||
39 | |||
40 | au1x00_ss-y += au1000_generic.o | ||
41 | au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o | ||
42 | au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o | ||
43 | au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o | ||
44 | au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o | ||
45 | au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o | ||
46 | au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o | ||
47 | au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o | ||
48 | au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o | ||
49 | |||
50 | sa1111_cs-y += sa1111_generic.o | ||
51 | sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o | ||
52 | sa1111_cs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o | ||
53 | sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o | ||
54 | |||
55 | sa1100_cs-y += sa1100_generic.o | ||
56 | sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o | ||
57 | sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o | ||
58 | sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o | ||
59 | sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o | ||
60 | sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o | ||
61 | |||
62 | pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o | ||
63 | pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o | ||
64 | pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o | ||
65 | |||
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c new file mode 100644 index 000000000000..42cf8bfbcc98 --- /dev/null +++ b/drivers/pcmcia/au1000_db1x00.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Alchemy Semi Db1x00 boards specific pcmcia routines. | ||
4 | * | ||
5 | * Copyright 2002 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * Copyright 2004 Pete Popov, updated the driver to 2.6. | ||
10 | * Followed the sa11xx API and largely copied many of the hardware | ||
11 | * independent functions. | ||
12 | * | ||
13 | * ######################################################################## | ||
14 | * | ||
15 | * This program is free software; you can distribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License (Version 2) as | ||
17 | * published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
20 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
22 | * for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
27 | * | ||
28 | * ######################################################################## | ||
29 | * | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/errno.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/device.h> | ||
38 | #include <linux/init.h> | ||
39 | |||
40 | #include <asm/irq.h> | ||
41 | #include <asm/signal.h> | ||
42 | #include <asm/mach-au1x00/au1000.h> | ||
43 | #include <asm/mach-db1x00/db1x00.h> | ||
44 | |||
45 | #include "au1000_generic.h" | ||
46 | |||
47 | #if 0 | ||
48 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) | ||
49 | #else | ||
50 | #define debug(x,args...) | ||
51 | #endif | ||
52 | |||
53 | static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; | ||
54 | |||
55 | struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS]; | ||
56 | extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int); | ||
57 | |||
58 | static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt) | ||
59 | { | ||
60 | #ifdef CONFIG_MIPS_DB1550 | ||
61 | skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3; | ||
62 | #else | ||
63 | skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2; | ||
64 | #endif | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt) | ||
69 | { | ||
70 | bcsr->pcmcia = 0; /* turn off power */ | ||
71 | au_sync_delay(2); | ||
72 | } | ||
73 | |||
74 | static void | ||
75 | db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state) | ||
76 | { | ||
77 | u32 inserted; | ||
78 | unsigned char vs; | ||
79 | |||
80 | state->ready = 0; | ||
81 | state->vs_Xv = 0; | ||
82 | state->vs_3v = 0; | ||
83 | state->detect = 0; | ||
84 | |||
85 | switch (skt->nr) { | ||
86 | case 0: | ||
87 | vs = bcsr->status & 0x3; | ||
88 | inserted = !(bcsr->status & (1<<4)); | ||
89 | break; | ||
90 | case 1: | ||
91 | vs = (bcsr->status & 0xC)>>2; | ||
92 | inserted = !(bcsr->status & (1<<5)); | ||
93 | break; | ||
94 | default:/* should never happen */ | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | if (inserted) | ||
99 | debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n", | ||
100 | skt->nr, inserted, vs, bcsr->pcmcia); | ||
101 | |||
102 | if (inserted) { | ||
103 | switch (vs) { | ||
104 | case 0: | ||
105 | case 2: | ||
106 | state->vs_3v=1; | ||
107 | break; | ||
108 | case 3: /* 5V */ | ||
109 | break; | ||
110 | default: | ||
111 | /* return without setting 'detect' */ | ||
112 | printk(KERN_ERR "db1x00 bad VS (%d)\n", | ||
113 | vs); | ||
114 | } | ||
115 | state->detect = 1; | ||
116 | state->ready = 1; | ||
117 | } | ||
118 | else { | ||
119 | /* if the card was previously inserted and then ejected, | ||
120 | * we should turn off power to it | ||
121 | */ | ||
122 | if ((skt->nr == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) { | ||
123 | bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST | | ||
124 | BCSR_PCMCIA_PC0DRVEN | | ||
125 | BCSR_PCMCIA_PC0VPP | | ||
126 | BCSR_PCMCIA_PC0VCC); | ||
127 | au_sync_delay(10); | ||
128 | } | ||
129 | else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) { | ||
130 | bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST | | ||
131 | BCSR_PCMCIA_PC1DRVEN | | ||
132 | BCSR_PCMCIA_PC1VPP | | ||
133 | BCSR_PCMCIA_PC1VCC); | ||
134 | au_sync_delay(10); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | state->bvd1=1; | ||
139 | state->bvd2=1; | ||
140 | state->wrprot=0; | ||
141 | } | ||
142 | |||
143 | static int | ||
144 | db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state) | ||
145 | { | ||
146 | u16 pwr; | ||
147 | int sock = skt->nr; | ||
148 | |||
149 | debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n", | ||
150 | sock, state->Vcc, state->Vpp, | ||
151 | state->flags & SS_RESET); | ||
152 | |||
153 | /* pcmcia reg was set to zero at init time. Be careful when | ||
154 | * initializing a socket not to wipe out the settings of the | ||
155 | * other socket. | ||
156 | */ | ||
157 | pwr = bcsr->pcmcia; | ||
158 | pwr &= ~(0xf << sock*8); /* clear voltage settings */ | ||
159 | |||
160 | state->Vpp = 0; | ||
161 | switch(state->Vcc){ | ||
162 | case 0: /* Vcc 0 */ | ||
163 | pwr |= SET_VCC_VPP(0,0,sock); | ||
164 | break; | ||
165 | case 50: /* Vcc 5V */ | ||
166 | switch(state->Vpp) { | ||
167 | case 0: | ||
168 | pwr |= SET_VCC_VPP(2,0,sock); | ||
169 | break; | ||
170 | case 50: | ||
171 | pwr |= SET_VCC_VPP(2,1,sock); | ||
172 | break; | ||
173 | case 12: | ||
174 | pwr |= SET_VCC_VPP(2,2,sock); | ||
175 | break; | ||
176 | case 33: | ||
177 | default: | ||
178 | pwr |= SET_VCC_VPP(0,0,sock); | ||
179 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
180 | __FUNCTION__, | ||
181 | state->Vcc, | ||
182 | state->Vpp); | ||
183 | break; | ||
184 | } | ||
185 | break; | ||
186 | case 33: /* Vcc 3.3V */ | ||
187 | switch(state->Vpp) { | ||
188 | case 0: | ||
189 | pwr |= SET_VCC_VPP(1,0,sock); | ||
190 | break; | ||
191 | case 12: | ||
192 | pwr |= SET_VCC_VPP(1,2,sock); | ||
193 | break; | ||
194 | case 33: | ||
195 | pwr |= SET_VCC_VPP(1,1,sock); | ||
196 | break; | ||
197 | case 50: | ||
198 | default: | ||
199 | pwr |= SET_VCC_VPP(0,0,sock); | ||
200 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
201 | __FUNCTION__, | ||
202 | state->Vcc, | ||
203 | state->Vpp); | ||
204 | break; | ||
205 | } | ||
206 | break; | ||
207 | default: /* what's this ? */ | ||
208 | pwr |= SET_VCC_VPP(0,0,sock); | ||
209 | printk(KERN_ERR "%s: bad Vcc %d\n", | ||
210 | __FUNCTION__, state->Vcc); | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | bcsr->pcmcia = pwr; | ||
215 | au_sync_delay(300); | ||
216 | |||
217 | if (sock == 0) { | ||
218 | if (!(state->flags & SS_RESET)) { | ||
219 | pwr |= BCSR_PCMCIA_PC0DRVEN; | ||
220 | bcsr->pcmcia = pwr; | ||
221 | au_sync_delay(300); | ||
222 | pwr |= BCSR_PCMCIA_PC0RST; | ||
223 | bcsr->pcmcia = pwr; | ||
224 | au_sync_delay(100); | ||
225 | } | ||
226 | else { | ||
227 | pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN); | ||
228 | bcsr->pcmcia = pwr; | ||
229 | au_sync_delay(100); | ||
230 | } | ||
231 | } | ||
232 | else { | ||
233 | if (!(state->flags & SS_RESET)) { | ||
234 | pwr |= BCSR_PCMCIA_PC1DRVEN; | ||
235 | bcsr->pcmcia = pwr; | ||
236 | au_sync_delay(300); | ||
237 | pwr |= BCSR_PCMCIA_PC1RST; | ||
238 | bcsr->pcmcia = pwr; | ||
239 | au_sync_delay(100); | ||
240 | } | ||
241 | else { | ||
242 | pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN); | ||
243 | bcsr->pcmcia = pwr; | ||
244 | au_sync_delay(100); | ||
245 | } | ||
246 | } | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Enable card status IRQs on (re-)initialisation. This can | ||
252 | * be called at initialisation, power management event, or | ||
253 | * pcmcia event. | ||
254 | */ | ||
255 | void db1x00_socket_init(struct au1000_pcmcia_socket *skt) | ||
256 | { | ||
257 | /* nothing to do for now */ | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Disable card status IRQs and PCMCIA bus on suspend. | ||
262 | */ | ||
263 | void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt) | ||
264 | { | ||
265 | /* nothing to do for now */ | ||
266 | } | ||
267 | |||
268 | struct pcmcia_low_level db1x00_pcmcia_ops = { | ||
269 | .owner = THIS_MODULE, | ||
270 | |||
271 | .hw_init = db1x00_pcmcia_hw_init, | ||
272 | .hw_shutdown = db1x00_pcmcia_shutdown, | ||
273 | |||
274 | .socket_state = db1x00_pcmcia_socket_state, | ||
275 | .configure_socket = db1x00_pcmcia_configure_socket, | ||
276 | |||
277 | .socket_init = db1x00_socket_init, | ||
278 | .socket_suspend = db1x00_socket_suspend | ||
279 | }; | ||
280 | |||
281 | int __init au1x_board_init(struct device *dev) | ||
282 | { | ||
283 | int ret = -ENODEV; | ||
284 | bcsr->pcmcia = 0; /* turn off power, if it's not already off */ | ||
285 | au_sync_delay(2); | ||
286 | ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2); | ||
287 | return ret; | ||
288 | } | ||
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c new file mode 100644 index 000000000000..9fa7f15d89e5 --- /dev/null +++ b/drivers/pcmcia/au1000_generic.c | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Alchemy Semi Au1000 pcmcia driver | ||
4 | * | ||
5 | * Copyright 2001-2003 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@embeddedalley.com or source@mvista.com | ||
8 | * | ||
9 | * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc. | ||
10 | * Updated the driver to 2.6. Followed the sa11xx API and largely | ||
11 | * copied many of the hardware independent functions. | ||
12 | * | ||
13 | * ######################################################################## | ||
14 | * | ||
15 | * This program is free software; you can distribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License (Version 2) as | ||
17 | * published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
20 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
22 | * for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
27 | * | ||
28 | * ######################################################################## | ||
29 | * | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/cpufreq.h> | ||
38 | #include <linux/ioport.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/mm.h> | ||
42 | #include <linux/notifier.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | #include <linux/spinlock.h> | ||
45 | #include <linux/device.h> | ||
46 | |||
47 | #include <asm/io.h> | ||
48 | #include <asm/irq.h> | ||
49 | #include <asm/system.h> | ||
50 | |||
51 | #include <asm/mach-au1x00/au1000.h> | ||
52 | #include "au1000_generic.h" | ||
53 | |||
54 | MODULE_LICENSE("GPL"); | ||
55 | MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>"); | ||
56 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); | ||
57 | |||
58 | #if 0 | ||
59 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) | ||
60 | #else | ||
61 | #define debug(x,args...) | ||
62 | #endif | ||
63 | |||
64 | #define MAP_SIZE 0x100000 | ||
65 | extern struct au1000_pcmcia_socket au1000_pcmcia_socket[]; | ||
66 | #define PCMCIA_SOCKET(x) (au1000_pcmcia_socket + (x)) | ||
67 | #define to_au1000_socket(x) container_of(x, struct au1000_pcmcia_socket, socket) | ||
68 | |||
69 | /* Some boards like to support CF cards as IDE root devices, so they | ||
70 | * grab pcmcia sockets directly. | ||
71 | */ | ||
72 | u32 *pcmcia_base_vaddrs[2]; | ||
73 | extern const unsigned long mips_io_port_base; | ||
74 | |||
75 | DECLARE_MUTEX(pcmcia_sockets_lock); | ||
76 | |||
77 | static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = { | ||
78 | au1x_board_init, | ||
79 | }; | ||
80 | |||
81 | static int | ||
82 | au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt) | ||
83 | { | ||
84 | struct pcmcia_state state; | ||
85 | unsigned int stat; | ||
86 | |||
87 | memset(&state, 0, sizeof(struct pcmcia_state)); | ||
88 | |||
89 | skt->ops->socket_state(skt, &state); | ||
90 | |||
91 | stat = state.detect ? SS_DETECT : 0; | ||
92 | stat |= state.ready ? SS_READY : 0; | ||
93 | stat |= state.wrprot ? SS_WRPROT : 0; | ||
94 | stat |= state.vs_3v ? SS_3VCARD : 0; | ||
95 | stat |= state.vs_Xv ? SS_XVCARD : 0; | ||
96 | stat |= skt->cs_state.Vcc ? SS_POWERON : 0; | ||
97 | |||
98 | if (skt->cs_state.flags & SS_IOCARD) | ||
99 | stat |= state.bvd1 ? SS_STSCHG : 0; | ||
100 | else { | ||
101 | if (state.bvd1 == 0) | ||
102 | stat |= SS_BATDEAD; | ||
103 | else if (state.bvd2 == 0) | ||
104 | stat |= SS_BATWARN; | ||
105 | } | ||
106 | return stat; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * au100_pcmcia_config_skt | ||
111 | * | ||
112 | * Convert PCMCIA socket state to our socket configure structure. | ||
113 | */ | ||
114 | static int | ||
115 | au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state) | ||
116 | { | ||
117 | int ret; | ||
118 | |||
119 | ret = skt->ops->configure_socket(skt, state); | ||
120 | if (ret == 0) { | ||
121 | skt->cs_state = *state; | ||
122 | } | ||
123 | |||
124 | if (ret < 0) | ||
125 | debug("unable to configure socket %d\n", skt->nr); | ||
126 | |||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | /* au1x00_pcmcia_sock_init() | ||
131 | * | ||
132 | * (Re-)Initialise the socket, turning on status interrupts | ||
133 | * and PCMCIA bus. This must wait for power to stabilise | ||
134 | * so that the card status signals report correctly. | ||
135 | * | ||
136 | * Returns: 0 | ||
137 | */ | ||
138 | static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock) | ||
139 | { | ||
140 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
141 | |||
142 | debug("initializing socket %u\n", skt->nr); | ||
143 | |||
144 | skt->ops->socket_init(skt); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * au1x00_pcmcia_suspend() | ||
150 | * | ||
151 | * Remove power on the socket, disable IRQs from the card. | ||
152 | * Turn off status interrupts, and disable the PCMCIA bus. | ||
153 | * | ||
154 | * Returns: 0 | ||
155 | */ | ||
156 | static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock) | ||
157 | { | ||
158 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
159 | |||
160 | debug("suspending socket %u\n", skt->nr); | ||
161 | |||
162 | skt->ops->socket_suspend(skt); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static DEFINE_SPINLOCK(status_lock); | ||
168 | |||
169 | /* | ||
170 | * au1x00_check_status() | ||
171 | */ | ||
172 | static void au1x00_check_status(struct au1000_pcmcia_socket *skt) | ||
173 | { | ||
174 | unsigned int events; | ||
175 | |||
176 | debug("entering PCMCIA monitoring thread\n"); | ||
177 | |||
178 | do { | ||
179 | unsigned int status; | ||
180 | unsigned long flags; | ||
181 | |||
182 | status = au1x00_pcmcia_skt_state(skt); | ||
183 | |||
184 | spin_lock_irqsave(&status_lock, flags); | ||
185 | events = (status ^ skt->status) & skt->cs_state.csc_mask; | ||
186 | skt->status = status; | ||
187 | spin_unlock_irqrestore(&status_lock, flags); | ||
188 | |||
189 | debug("events: %s%s%s%s%s%s\n", | ||
190 | events == 0 ? "<NONE>" : "", | ||
191 | events & SS_DETECT ? "DETECT " : "", | ||
192 | events & SS_READY ? "READY " : "", | ||
193 | events & SS_BATDEAD ? "BATDEAD " : "", | ||
194 | events & SS_BATWARN ? "BATWARN " : "", | ||
195 | events & SS_STSCHG ? "STSCHG " : ""); | ||
196 | |||
197 | if (events) | ||
198 | pcmcia_parse_events(&skt->socket, events); | ||
199 | } while (events); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * au1x00_pcmcia_poll_event() | ||
204 | * Let's poll for events in addition to IRQs since IRQ only is unreliable... | ||
205 | */ | ||
206 | static void au1x00_pcmcia_poll_event(unsigned long dummy) | ||
207 | { | ||
208 | struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy; | ||
209 | debug("polling for events\n"); | ||
210 | |||
211 | mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD); | ||
212 | |||
213 | au1x00_check_status(skt); | ||
214 | } | ||
215 | |||
216 | /* au1x00_pcmcia_get_status() | ||
217 | * | ||
218 | * From the sa11xx_core.c: | ||
219 | * Implements the get_status() operation for the in-kernel PCMCIA | ||
220 | * service (formerly SS_GetStatus in Card Services). Essentially just | ||
221 | * fills in bits in `status' according to internal driver state or | ||
222 | * the value of the voltage detect chipselect register. | ||
223 | * | ||
224 | * As a debugging note, during card startup, the PCMCIA core issues | ||
225 | * three set_socket() commands in a row the first with RESET deasserted, | ||
226 | * the second with RESET asserted, and the last with RESET deasserted | ||
227 | * again. Following the third set_socket(), a get_status() command will | ||
228 | * be issued. The kernel is looking for the SS_READY flag (see | ||
229 | * setup_socket(), reset_socket(), and unreset_socket() in cs.c). | ||
230 | * | ||
231 | * Returns: 0 | ||
232 | */ | ||
233 | static int | ||
234 | au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | ||
235 | { | ||
236 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
237 | |||
238 | skt->status = au1x00_pcmcia_skt_state(skt); | ||
239 | *status = skt->status; | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | /* au1x00_pcmcia_get_socket() | ||
245 | * Implements the get_socket() operation for the in-kernel PCMCIA | ||
246 | * service (formerly SS_GetSocket in Card Services). Not a very | ||
247 | * exciting routine. | ||
248 | * | ||
249 | * Returns: 0 | ||
250 | */ | ||
251 | static int | ||
252 | au1x00_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
253 | { | ||
254 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
255 | |||
256 | debug("for sock %u\n", skt->nr); | ||
257 | *state = skt->cs_state; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* au1x00_pcmcia_set_socket() | ||
262 | * Implements the set_socket() operation for the in-kernel PCMCIA | ||
263 | * service (formerly SS_SetSocket in Card Services). We more or | ||
264 | * less punt all of this work and let the kernel handle the details | ||
265 | * of power configuration, reset, &c. We also record the value of | ||
266 | * `state' in order to regurgitate it to the PCMCIA core later. | ||
267 | * | ||
268 | * Returns: 0 | ||
269 | */ | ||
270 | static int | ||
271 | au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
272 | { | ||
273 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
274 | |||
275 | debug("for sock %u\n", skt->nr); | ||
276 | |||
277 | debug("\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", | ||
278 | (state->csc_mask==0)?"<NONE>":"", | ||
279 | (state->csc_mask&SS_DETECT)?"DETECT ":"", | ||
280 | (state->csc_mask&SS_READY)?"READY ":"", | ||
281 | (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", | ||
282 | (state->csc_mask&SS_BATWARN)?"BATWARN ":"", | ||
283 | (state->csc_mask&SS_STSCHG)?"STSCHG ":"", | ||
284 | (state->flags==0)?"<NONE>":"", | ||
285 | (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", | ||
286 | (state->flags&SS_IOCARD)?"IOCARD ":"", | ||
287 | (state->flags&SS_RESET)?"RESET ":"", | ||
288 | (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", | ||
289 | (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); | ||
290 | debug("\tVcc %d Vpp %d irq %d\n", | ||
291 | state->Vcc, state->Vpp, state->io_irq); | ||
292 | |||
293 | return au1x00_pcmcia_config_skt(skt, state); | ||
294 | } | ||
295 | |||
296 | int | ||
297 | au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) | ||
298 | { | ||
299 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
300 | unsigned int speed; | ||
301 | |||
302 | if(map->map>=MAX_IO_WIN){ | ||
303 | debug("map (%d) out of range\n", map->map); | ||
304 | return -1; | ||
305 | } | ||
306 | |||
307 | if(map->flags&MAP_ACTIVE){ | ||
308 | speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; | ||
309 | skt->spd_io[map->map] = speed; | ||
310 | } | ||
311 | |||
312 | map->start=(ioaddr_t)(u32)skt->virt_io; | ||
313 | map->stop=map->start+MAP_SIZE; | ||
314 | return 0; | ||
315 | |||
316 | } /* au1x00_pcmcia_set_io_map() */ | ||
317 | |||
318 | |||
319 | static int | ||
320 | au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) | ||
321 | { | ||
322 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
323 | unsigned short speed = map->speed; | ||
324 | |||
325 | if(map->map>=MAX_WIN){ | ||
326 | debug("map (%d) out of range\n", map->map); | ||
327 | return -1; | ||
328 | } | ||
329 | |||
330 | if (map->flags & MAP_ATTRIB) { | ||
331 | skt->spd_attr[map->map] = speed; | ||
332 | skt->spd_mem[map->map] = 0; | ||
333 | } else { | ||
334 | skt->spd_attr[map->map] = 0; | ||
335 | skt->spd_mem[map->map] = speed; | ||
336 | } | ||
337 | |||
338 | if (map->flags & MAP_ATTRIB) { | ||
339 | map->static_start = skt->phys_attr + map->card_start; | ||
340 | } | ||
341 | else { | ||
342 | map->static_start = skt->phys_mem + map->card_start; | ||
343 | } | ||
344 | |||
345 | debug("set_mem_map %d start %08lx card_start %08x\n", | ||
346 | map->map, map->static_start, map->card_start); | ||
347 | return 0; | ||
348 | |||
349 | } /* au1x00_pcmcia_set_mem_map() */ | ||
350 | |||
351 | static struct pccard_operations au1x00_pcmcia_operations = { | ||
352 | .init = au1x00_pcmcia_sock_init, | ||
353 | .suspend = au1x00_pcmcia_suspend, | ||
354 | .get_status = au1x00_pcmcia_get_status, | ||
355 | .get_socket = au1x00_pcmcia_get_socket, | ||
356 | .set_socket = au1x00_pcmcia_set_socket, | ||
357 | .set_io_map = au1x00_pcmcia_set_io_map, | ||
358 | .set_mem_map = au1x00_pcmcia_set_mem_map, | ||
359 | }; | ||
360 | |||
361 | static const char *skt_names[] = { | ||
362 | "PCMCIA socket 0", | ||
363 | "PCMCIA socket 1", | ||
364 | }; | ||
365 | |||
366 | struct skt_dev_info { | ||
367 | int nskt; | ||
368 | }; | ||
369 | |||
370 | int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) | ||
371 | { | ||
372 | struct skt_dev_info *sinfo; | ||
373 | int ret, i; | ||
374 | |||
375 | sinfo = kmalloc(sizeof(struct skt_dev_info), GFP_KERNEL); | ||
376 | if (!sinfo) { | ||
377 | ret = -ENOMEM; | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | memset(sinfo, 0, sizeof(struct skt_dev_info)); | ||
382 | sinfo->nskt = nr; | ||
383 | |||
384 | /* | ||
385 | * Initialise the per-socket structure. | ||
386 | */ | ||
387 | for (i = 0; i < nr; i++) { | ||
388 | struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); | ||
389 | memset(skt, 0, sizeof(*skt)); | ||
390 | |||
391 | skt->socket.ops = &au1x00_pcmcia_operations; | ||
392 | skt->socket.owner = ops->owner; | ||
393 | skt->socket.dev.dev = dev; | ||
394 | |||
395 | init_timer(&skt->poll_timer); | ||
396 | skt->poll_timer.function = au1x00_pcmcia_poll_event; | ||
397 | skt->poll_timer.data = (unsigned long)skt; | ||
398 | skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; | ||
399 | |||
400 | skt->nr = first + i; | ||
401 | skt->irq = 255; | ||
402 | skt->dev = dev; | ||
403 | skt->ops = ops; | ||
404 | |||
405 | skt->res_skt.name = skt_names[skt->nr]; | ||
406 | skt->res_io.name = "io"; | ||
407 | skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
408 | skt->res_mem.name = "memory"; | ||
409 | skt->res_mem.flags = IORESOURCE_MEM; | ||
410 | skt->res_attr.name = "attribute"; | ||
411 | skt->res_attr.flags = IORESOURCE_MEM; | ||
412 | |||
413 | /* | ||
414 | * PCMCIA client drivers use the inb/outb macros to access the | ||
415 | * IO registers. Since mips_io_port_base is added to the | ||
416 | * access address of the mips implementation of inb/outb, | ||
417 | * we need to subtract it here because we want to access the | ||
418 | * I/O or MEM address directly, without going through this | ||
419 | * "mips_io_port_base" mechanism. | ||
420 | */ | ||
421 | if (i == 0) { | ||
422 | skt->virt_io = (void *) | ||
423 | (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) - | ||
424 | (u32)mips_io_port_base); | ||
425 | skt->phys_attr = AU1X_SOCK0_PSEUDO_PHYS_ATTR; | ||
426 | skt->phys_mem = AU1X_SOCK0_PSEUDO_PHYS_MEM; | ||
427 | } | ||
428 | #ifndef CONFIG_MIPS_XXS1500 | ||
429 | else { | ||
430 | skt->virt_io = (void *) | ||
431 | (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) - | ||
432 | (u32)mips_io_port_base); | ||
433 | skt->phys_attr = AU1X_SOCK1_PSEUDO_PHYS_ATTR; | ||
434 | skt->phys_mem = AU1X_SOCK1_PSEUDO_PHYS_MEM; | ||
435 | } | ||
436 | #endif | ||
437 | pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io; | ||
438 | ret = ops->hw_init(skt); | ||
439 | |||
440 | skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; | ||
441 | skt->socket.irq_mask = 0; | ||
442 | skt->socket.map_size = MAP_SIZE; | ||
443 | skt->socket.pci_irq = skt->irq; | ||
444 | skt->socket.io_offset = (unsigned long)skt->virt_io; | ||
445 | |||
446 | skt->status = au1x00_pcmcia_skt_state(skt); | ||
447 | |||
448 | ret = pcmcia_register_socket(&skt->socket); | ||
449 | if (ret) | ||
450 | goto out_err; | ||
451 | |||
452 | WARN_ON(skt->socket.sock != i); | ||
453 | |||
454 | add_timer(&skt->poll_timer); | ||
455 | } | ||
456 | |||
457 | dev_set_drvdata(dev, sinfo); | ||
458 | return 0; | ||
459 | |||
460 | do { | ||
461 | struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); | ||
462 | |||
463 | del_timer_sync(&skt->poll_timer); | ||
464 | pcmcia_unregister_socket(&skt->socket); | ||
465 | out_err: | ||
466 | flush_scheduled_work(); | ||
467 | ops->hw_shutdown(skt); | ||
468 | |||
469 | i--; | ||
470 | } while (i > 0); | ||
471 | kfree(sinfo); | ||
472 | out: | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | int au1x00_drv_pcmcia_remove(struct device *dev) | ||
477 | { | ||
478 | struct skt_dev_info *sinfo = dev_get_drvdata(dev); | ||
479 | int i; | ||
480 | |||
481 | down(&pcmcia_sockets_lock); | ||
482 | dev_set_drvdata(dev, NULL); | ||
483 | |||
484 | for (i = 0; i < sinfo->nskt; i++) { | ||
485 | struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); | ||
486 | |||
487 | del_timer_sync(&skt->poll_timer); | ||
488 | pcmcia_unregister_socket(&skt->socket); | ||
489 | flush_scheduled_work(); | ||
490 | skt->ops->hw_shutdown(skt); | ||
491 | au1x00_pcmcia_config_skt(skt, &dead_socket); | ||
492 | iounmap(skt->virt_io); | ||
493 | skt->virt_io = NULL; | ||
494 | } | ||
495 | |||
496 | kfree(sinfo); | ||
497 | up(&pcmcia_sockets_lock); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | |||
502 | /* | ||
503 | * PCMCIA "Driver" API | ||
504 | */ | ||
505 | |||
506 | static int au1x00_drv_pcmcia_probe(struct device *dev) | ||
507 | { | ||
508 | int i, ret = -ENODEV; | ||
509 | |||
510 | down(&pcmcia_sockets_lock); | ||
511 | for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) { | ||
512 | ret = au1x00_pcmcia_hw_init[i](dev); | ||
513 | if (ret == 0) | ||
514 | break; | ||
515 | } | ||
516 | up(&pcmcia_sockets_lock); | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | |||
521 | static int au1x00_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level) | ||
522 | { | ||
523 | int ret = 0; | ||
524 | if (level == SUSPEND_SAVE_STATE) | ||
525 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static int au1x00_drv_pcmcia_resume(struct device *dev, u32 level) | ||
530 | { | ||
531 | int ret = 0; | ||
532 | if (level == RESUME_RESTORE_STATE) | ||
533 | ret = pcmcia_socket_dev_resume(dev); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | |||
538 | static struct device_driver au1x00_pcmcia_driver = { | ||
539 | .probe = au1x00_drv_pcmcia_probe, | ||
540 | .remove = au1x00_drv_pcmcia_remove, | ||
541 | .name = "au1x00-pcmcia", | ||
542 | .bus = &platform_bus_type, | ||
543 | .suspend = au1x00_drv_pcmcia_suspend, | ||
544 | .resume = au1x00_drv_pcmcia_resume | ||
545 | }; | ||
546 | |||
547 | static struct platform_device au1x00_device = { | ||
548 | .name = "au1x00-pcmcia", | ||
549 | .id = 0, | ||
550 | }; | ||
551 | |||
552 | /* au1x00_pcmcia_init() | ||
553 | * | ||
554 | * This routine performs low-level PCMCIA initialization and then | ||
555 | * registers this socket driver with Card Services. | ||
556 | * | ||
557 | * Returns: 0 on success, -ve error code on failure | ||
558 | */ | ||
559 | static int __init au1x00_pcmcia_init(void) | ||
560 | { | ||
561 | int error = 0; | ||
562 | if ((error = driver_register(&au1x00_pcmcia_driver))) | ||
563 | return error; | ||
564 | platform_device_register(&au1x00_device); | ||
565 | return error; | ||
566 | } | ||
567 | |||
568 | /* au1x00_pcmcia_exit() | ||
569 | * Invokes the low-level kernel service to free IRQs associated with this | ||
570 | * socket controller and reset GPIO edge detection. | ||
571 | */ | ||
572 | static void __exit au1x00_pcmcia_exit(void) | ||
573 | { | ||
574 | driver_unregister(&au1x00_pcmcia_driver); | ||
575 | platform_device_unregister(&au1x00_device); | ||
576 | } | ||
577 | |||
578 | module_init(au1x00_pcmcia_init); | ||
579 | module_exit(au1x00_pcmcia_exit); | ||
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h new file mode 100644 index 000000000000..417bc1500bad --- /dev/null +++ b/drivers/pcmcia/au1000_generic.h | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Alchemy Semi Au1000 pcmcia driver include file | ||
3 | * | ||
4 | * Copyright 2001 MontaVista Software Inc. | ||
5 | * Author: MontaVista Software, Inc. | ||
6 | * ppopov@mvista.com or source@mvista.com | ||
7 | * | ||
8 | * This program is free software; you can distribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License (Version 2) as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __ASM_AU1000_PCMCIA_H | ||
22 | #define __ASM_AU1000_PCMCIA_H | ||
23 | |||
24 | /* include the world */ | ||
25 | #include <pcmcia/version.h> | ||
26 | #include <pcmcia/cs_types.h> | ||
27 | #include <pcmcia/cs.h> | ||
28 | #include <pcmcia/ss.h> | ||
29 | #include <pcmcia/bulkmem.h> | ||
30 | #include <pcmcia/cistpl.h> | ||
31 | #include "cs_internal.h" | ||
32 | |||
33 | #define AU1000_PCMCIA_POLL_PERIOD (2*HZ) | ||
34 | #define AU1000_PCMCIA_IO_SPEED (255) | ||
35 | #define AU1000_PCMCIA_MEM_SPEED (300) | ||
36 | |||
37 | #define AU1X_SOCK0_IO 0xF00000000 | ||
38 | #define AU1X_SOCK0_PHYS_ATTR 0xF40000000 | ||
39 | #define AU1X_SOCK0_PHYS_MEM 0xF80000000 | ||
40 | /* pseudo 32 bit phys addresses, which get fixed up to the | ||
41 | * real 36 bit address in fixup_bigphys_addr() */ | ||
42 | #define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000 | ||
43 | #define AU1X_SOCK0_PSEUDO_PHYS_MEM 0xF8000000 | ||
44 | |||
45 | /* pcmcia socket 1 needs external glue logic so the memory map | ||
46 | * differs from board to board. | ||
47 | */ | ||
48 | #if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) | ||
49 | #define AU1X_SOCK1_IO 0xF08000000 | ||
50 | #define AU1X_SOCK1_PHYS_ATTR 0xF48000000 | ||
51 | #define AU1X_SOCK1_PHYS_MEM 0xF88000000 | ||
52 | #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000 | ||
53 | #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000 | ||
54 | #elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) | ||
55 | #define AU1X_SOCK1_IO 0xF04000000 | ||
56 | #define AU1X_SOCK1_PHYS_ATTR 0xF44000000 | ||
57 | #define AU1X_SOCK1_PHYS_MEM 0xF84000000 | ||
58 | #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000 | ||
59 | #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8400000 | ||
60 | #endif | ||
61 | |||
62 | struct pcmcia_state { | ||
63 | unsigned detect: 1, | ||
64 | ready: 1, | ||
65 | wrprot: 1, | ||
66 | bvd1: 1, | ||
67 | bvd2: 1, | ||
68 | vs_3v: 1, | ||
69 | vs_Xv: 1; | ||
70 | }; | ||
71 | |||
72 | struct pcmcia_configure { | ||
73 | unsigned sock: 8, | ||
74 | vcc: 8, | ||
75 | vpp: 8, | ||
76 | output: 1, | ||
77 | speaker: 1, | ||
78 | reset: 1; | ||
79 | }; | ||
80 | |||
81 | struct pcmcia_irqs { | ||
82 | int sock; | ||
83 | int irq; | ||
84 | const char *str; | ||
85 | }; | ||
86 | |||
87 | |||
88 | struct au1000_pcmcia_socket { | ||
89 | struct pcmcia_socket socket; | ||
90 | |||
91 | /* | ||
92 | * Info from low level handler | ||
93 | */ | ||
94 | struct device *dev; | ||
95 | unsigned int nr; | ||
96 | unsigned int irq; | ||
97 | |||
98 | /* | ||
99 | * Core PCMCIA state | ||
100 | */ | ||
101 | struct pcmcia_low_level *ops; | ||
102 | |||
103 | unsigned int status; | ||
104 | socket_state_t cs_state; | ||
105 | |||
106 | unsigned short spd_io[MAX_IO_WIN]; | ||
107 | unsigned short spd_mem[MAX_WIN]; | ||
108 | unsigned short spd_attr[MAX_WIN]; | ||
109 | |||
110 | struct resource res_skt; | ||
111 | struct resource res_io; | ||
112 | struct resource res_mem; | ||
113 | struct resource res_attr; | ||
114 | |||
115 | void * virt_io; | ||
116 | ioaddr_t phys_io; | ||
117 | unsigned int phys_attr; | ||
118 | unsigned int phys_mem; | ||
119 | unsigned short speed_io, speed_attr, speed_mem; | ||
120 | |||
121 | unsigned int irq_state; | ||
122 | |||
123 | struct timer_list poll_timer; | ||
124 | }; | ||
125 | |||
126 | struct pcmcia_low_level { | ||
127 | struct module *owner; | ||
128 | |||
129 | int (*hw_init)(struct au1000_pcmcia_socket *); | ||
130 | void (*hw_shutdown)(struct au1000_pcmcia_socket *); | ||
131 | |||
132 | void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *); | ||
133 | int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *); | ||
134 | |||
135 | /* | ||
136 | * Enable card status IRQs on (re-)initialisation. This can | ||
137 | * be called at initialisation, power management event, or | ||
138 | * pcmcia event. | ||
139 | */ | ||
140 | void (*socket_init)(struct au1000_pcmcia_socket *); | ||
141 | |||
142 | /* | ||
143 | * Disable card status IRQs and PCMCIA bus on suspend. | ||
144 | */ | ||
145 | void (*socket_suspend)(struct au1000_pcmcia_socket *); | ||
146 | }; | ||
147 | |||
148 | extern int au1x_board_init(struct device *dev); | ||
149 | |||
150 | #endif /* __ASM_AU1000_PCMCIA_H */ | ||
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c new file mode 100644 index 000000000000..df19ce1ea4f3 --- /dev/null +++ b/drivers/pcmcia/au1000_pb1x00.c | |||
@@ -0,0 +1,419 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Alchemy Semi Pb1x00 boards specific pcmcia routines. | ||
4 | * | ||
5 | * Copyright 2002 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License (Version 2) as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
18 | * for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/tqueue.h> | ||
30 | #include <linux/timer.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/proc_fs.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/types.h> | ||
35 | |||
36 | #include <pcmcia/version.h> | ||
37 | #include <pcmcia/cs_types.h> | ||
38 | #include <pcmcia/cs.h> | ||
39 | #include <pcmcia/ss.h> | ||
40 | #include <pcmcia/bulkmem.h> | ||
41 | #include <pcmcia/cistpl.h> | ||
42 | #include <pcmcia/bus_ops.h> | ||
43 | #include "cs_internal.h" | ||
44 | |||
45 | #include <asm/io.h> | ||
46 | #include <asm/irq.h> | ||
47 | #include <asm/system.h> | ||
48 | |||
49 | #include <asm/au1000.h> | ||
50 | #include <asm/au1000_pcmcia.h> | ||
51 | |||
52 | #define debug(fmt, arg...) do { } while (0) | ||
53 | |||
54 | #ifdef CONFIG_MIPS_PB1000 | ||
55 | #include <asm/pb1000.h> | ||
56 | #define PCMCIA_IRQ AU1000_GPIO_15 | ||
57 | #elif defined (CONFIG_MIPS_PB1500) | ||
58 | #include <asm/pb1500.h> | ||
59 | #define PCMCIA_IRQ AU1500_GPIO_203 | ||
60 | #elif defined (CONFIG_MIPS_PB1100) | ||
61 | #include <asm/pb1100.h> | ||
62 | #define PCMCIA_IRQ AU1000_GPIO_11 | ||
63 | #endif | ||
64 | |||
65 | static int pb1x00_pcmcia_init(struct pcmcia_init *init) | ||
66 | { | ||
67 | #ifdef CONFIG_MIPS_PB1000 | ||
68 | u16 pcr; | ||
69 | pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; | ||
70 | |||
71 | au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ | ||
72 | au_sync_delay(100); | ||
73 | au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ | ||
74 | au_sync(); | ||
75 | |||
76 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); | ||
77 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); | ||
78 | au_writel(pcr, PB1000_PCR); | ||
79 | au_sync_delay(20); | ||
80 | |||
81 | return PCMCIA_NUM_SOCKS; | ||
82 | |||
83 | #else /* fixme -- take care of the Pb1500 at some point */ | ||
84 | |||
85 | u16 pcr; | ||
86 | pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */ | ||
87 | pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN); | ||
88 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
89 | au_sync_delay(500); | ||
90 | return PCMCIA_NUM_SOCKS; | ||
91 | #endif | ||
92 | } | ||
93 | |||
94 | static int pb1x00_pcmcia_shutdown(void) | ||
95 | { | ||
96 | #ifdef CONFIG_MIPS_PB1000 | ||
97 | u16 pcr; | ||
98 | pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; | ||
99 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); | ||
100 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); | ||
101 | au_writel(pcr, PB1000_PCR); | ||
102 | au_sync_delay(20); | ||
103 | return 0; | ||
104 | #else | ||
105 | u16 pcr; | ||
106 | pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */ | ||
107 | pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN); | ||
108 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
109 | au_sync_delay(2); | ||
110 | return 0; | ||
111 | #endif | ||
112 | } | ||
113 | |||
114 | static int | ||
115 | pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) | ||
116 | { | ||
117 | u32 inserted0, inserted1; | ||
118 | u16 vs0, vs1; | ||
119 | |||
120 | #ifdef CONFIG_MIPS_PB1000 | ||
121 | vs0 = vs1 = (u16)au_readl(PB1000_ACR1); | ||
122 | inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2)); | ||
123 | inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2)); | ||
124 | vs0 = (vs0 >> 4) & 0x3; | ||
125 | vs1 = (vs1 >> 12) & 0x3; | ||
126 | #else | ||
127 | vs0 = (au_readw(BOARD_STATUS_REG) >> 4) & 0x3; | ||
128 | #ifdef CONFIG_MIPS_PB1500 | ||
129 | inserted0 = !((au_readl(GPIO2_PINSTATE) >> 1) & 0x1); /* gpio 201 */ | ||
130 | #else /* Pb1100 */ | ||
131 | inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */ | ||
132 | #endif | ||
133 | inserted1 = 0; | ||
134 | #endif | ||
135 | |||
136 | state->ready = 0; | ||
137 | state->vs_Xv = 0; | ||
138 | state->vs_3v = 0; | ||
139 | state->detect = 0; | ||
140 | |||
141 | if (sock == 0) { | ||
142 | if (inserted0) { | ||
143 | switch (vs0) { | ||
144 | case 0: | ||
145 | case 2: | ||
146 | state->vs_3v=1; | ||
147 | break; | ||
148 | case 3: /* 5V */ | ||
149 | break; | ||
150 | default: | ||
151 | /* return without setting 'detect' */ | ||
152 | printk(KERN_ERR "pb1x00 bad VS (%d)\n", | ||
153 | vs0); | ||
154 | return 0; | ||
155 | } | ||
156 | state->detect = 1; | ||
157 | } | ||
158 | } | ||
159 | else { | ||
160 | if (inserted1) { | ||
161 | switch (vs1) { | ||
162 | case 0: | ||
163 | case 2: | ||
164 | state->vs_3v=1; | ||
165 | break; | ||
166 | case 3: /* 5V */ | ||
167 | break; | ||
168 | default: | ||
169 | /* return without setting 'detect' */ | ||
170 | printk(KERN_ERR "pb1x00 bad VS (%d)\n", | ||
171 | vs1); | ||
172 | return 0; | ||
173 | } | ||
174 | state->detect = 1; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | if (state->detect) { | ||
179 | state->ready = 1; | ||
180 | } | ||
181 | |||
182 | state->bvd1=1; | ||
183 | state->bvd2=1; | ||
184 | state->wrprot=0; | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | |||
189 | static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info) | ||
190 | { | ||
191 | |||
192 | if(info->sock > PCMCIA_MAX_SOCK) return -1; | ||
193 | |||
194 | /* | ||
195 | * Even in the case of the Pb1000, both sockets are connected | ||
196 | * to the same irq line. | ||
197 | */ | ||
198 | info->irq = PCMCIA_IRQ; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | |||
204 | static int | ||
205 | pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) | ||
206 | { | ||
207 | u16 pcr; | ||
208 | |||
209 | if(configure->sock > PCMCIA_MAX_SOCK) return -1; | ||
210 | |||
211 | #ifdef CONFIG_MIPS_PB1000 | ||
212 | pcr = au_readl(PB1000_PCR); | ||
213 | |||
214 | if (configure->sock == 0) { | ||
215 | pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | | ||
216 | PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); | ||
217 | } | ||
218 | else { | ||
219 | pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | | ||
220 | PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); | ||
221 | } | ||
222 | |||
223 | pcr &= ~PCR_SLOT_0_RST; | ||
224 | debug("Vcc %dV Vpp %dV, pcr %x\n", | ||
225 | configure->vcc, configure->vpp, pcr); | ||
226 | switch(configure->vcc){ | ||
227 | case 0: /* Vcc 0 */ | ||
228 | switch(configure->vpp) { | ||
229 | case 0: | ||
230 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, | ||
231 | configure->sock); | ||
232 | break; | ||
233 | case 12: | ||
234 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, | ||
235 | configure->sock); | ||
236 | break; | ||
237 | case 50: | ||
238 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, | ||
239 | configure->sock); | ||
240 | break; | ||
241 | case 33: | ||
242 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, | ||
243 | configure->sock); | ||
244 | break; | ||
245 | default: | ||
246 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
247 | configure->sock); | ||
248 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
249 | __FUNCTION__, | ||
250 | configure->vcc, | ||
251 | configure->vpp); | ||
252 | break; | ||
253 | } | ||
254 | break; | ||
255 | case 50: /* Vcc 5V */ | ||
256 | switch(configure->vpp) { | ||
257 | case 0: | ||
258 | pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, | ||
259 | configure->sock); | ||
260 | break; | ||
261 | case 50: | ||
262 | pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, | ||
263 | configure->sock); | ||
264 | break; | ||
265 | case 12: | ||
266 | pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, | ||
267 | configure->sock); | ||
268 | break; | ||
269 | case 33: | ||
270 | pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, | ||
271 | configure->sock); | ||
272 | break; | ||
273 | default: | ||
274 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
275 | configure->sock); | ||
276 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
277 | __FUNCTION__, | ||
278 | configure->vcc, | ||
279 | configure->vpp); | ||
280 | break; | ||
281 | } | ||
282 | break; | ||
283 | case 33: /* Vcc 3.3V */ | ||
284 | switch(configure->vpp) { | ||
285 | case 0: | ||
286 | pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, | ||
287 | configure->sock); | ||
288 | break; | ||
289 | case 50: | ||
290 | pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, | ||
291 | configure->sock); | ||
292 | break; | ||
293 | case 12: | ||
294 | pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, | ||
295 | configure->sock); | ||
296 | break; | ||
297 | case 33: | ||
298 | pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, | ||
299 | configure->sock); | ||
300 | break; | ||
301 | default: | ||
302 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
303 | configure->sock); | ||
304 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
305 | __FUNCTION__, | ||
306 | configure->vcc, | ||
307 | configure->vpp); | ||
308 | break; | ||
309 | } | ||
310 | break; | ||
311 | default: /* what's this ? */ | ||
312 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); | ||
313 | printk(KERN_ERR "%s: bad Vcc %d\n", | ||
314 | __FUNCTION__, configure->vcc); | ||
315 | break; | ||
316 | } | ||
317 | |||
318 | if (configure->sock == 0) { | ||
319 | pcr &= ~(PCR_SLOT_0_RST); | ||
320 | if (configure->reset) | ||
321 | pcr |= PCR_SLOT_0_RST; | ||
322 | } | ||
323 | else { | ||
324 | pcr &= ~(PCR_SLOT_1_RST); | ||
325 | if (configure->reset) | ||
326 | pcr |= PCR_SLOT_1_RST; | ||
327 | } | ||
328 | au_writel(pcr, PB1000_PCR); | ||
329 | au_sync_delay(300); | ||
330 | |||
331 | #else | ||
332 | |||
333 | pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; | ||
334 | |||
335 | debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n", | ||
336 | configure->vcc, configure->vpp, pcr, configure->reset); | ||
337 | |||
338 | |||
339 | switch(configure->vcc){ | ||
340 | case 0: /* Vcc 0 */ | ||
341 | pcr |= SET_VCC_VPP(0,0); | ||
342 | break; | ||
343 | case 50: /* Vcc 5V */ | ||
344 | switch(configure->vpp) { | ||
345 | case 0: | ||
346 | pcr |= SET_VCC_VPP(2,0); | ||
347 | break; | ||
348 | case 50: | ||
349 | pcr |= SET_VCC_VPP(2,1); | ||
350 | break; | ||
351 | case 12: | ||
352 | pcr |= SET_VCC_VPP(2,2); | ||
353 | break; | ||
354 | case 33: | ||
355 | default: | ||
356 | pcr |= SET_VCC_VPP(0,0); | ||
357 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
358 | __FUNCTION__, | ||
359 | configure->vcc, | ||
360 | configure->vpp); | ||
361 | break; | ||
362 | } | ||
363 | break; | ||
364 | case 33: /* Vcc 3.3V */ | ||
365 | switch(configure->vpp) { | ||
366 | case 0: | ||
367 | pcr |= SET_VCC_VPP(1,0); | ||
368 | break; | ||
369 | case 12: | ||
370 | pcr |= SET_VCC_VPP(1,2); | ||
371 | break; | ||
372 | case 33: | ||
373 | pcr |= SET_VCC_VPP(1,1); | ||
374 | break; | ||
375 | case 50: | ||
376 | default: | ||
377 | pcr |= SET_VCC_VPP(0,0); | ||
378 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
379 | __FUNCTION__, | ||
380 | configure->vcc, | ||
381 | configure->vpp); | ||
382 | break; | ||
383 | } | ||
384 | break; | ||
385 | default: /* what's this ? */ | ||
386 | pcr |= SET_VCC_VPP(0,0); | ||
387 | printk(KERN_ERR "%s: bad Vcc %d\n", | ||
388 | __FUNCTION__, configure->vcc); | ||
389 | break; | ||
390 | } | ||
391 | |||
392 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
393 | au_sync_delay(300); | ||
394 | |||
395 | if (!configure->reset) { | ||
396 | pcr |= PC_DRV_EN; | ||
397 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
398 | au_sync_delay(100); | ||
399 | pcr |= PC_DEASSERT_RST; | ||
400 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
401 | au_sync_delay(100); | ||
402 | } | ||
403 | else { | ||
404 | pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN); | ||
405 | au_writew(pcr, PCMCIA_BOARD_REG); | ||
406 | au_sync_delay(100); | ||
407 | } | ||
408 | #endif | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | |||
413 | struct pcmcia_low_level pb1x00_pcmcia_ops = { | ||
414 | pb1x00_pcmcia_init, | ||
415 | pb1x00_pcmcia_shutdown, | ||
416 | pb1x00_pcmcia_socket_state, | ||
417 | pb1x00_pcmcia_get_irq_info, | ||
418 | pb1x00_pcmcia_configure_socket | ||
419 | }; | ||
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c new file mode 100644 index 000000000000..1dfc77653660 --- /dev/null +++ b/drivers/pcmcia/au1000_xxs1500.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * | ||
3 | * MyCable board specific pcmcia routines. | ||
4 | * | ||
5 | * Copyright 2003 MontaVista Software Inc. | ||
6 | * Author: Pete Popov, MontaVista Software, Inc. | ||
7 | * ppopov@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License (Version 2) as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
18 | * for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
23 | * | ||
24 | * ######################################################################## | ||
25 | * | ||
26 | * | ||
27 | */ | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/config.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/ioport.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/tqueue.h> | ||
35 | #include <linux/timer.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/proc_fs.h> | ||
38 | #include <linux/version.h> | ||
39 | #include <linux/types.h> | ||
40 | |||
41 | #include <pcmcia/version.h> | ||
42 | #include <pcmcia/cs_types.h> | ||
43 | #include <pcmcia/cs.h> | ||
44 | #include <pcmcia/ss.h> | ||
45 | #include <pcmcia/bulkmem.h> | ||
46 | #include <pcmcia/cistpl.h> | ||
47 | #include <pcmcia/bus_ops.h> | ||
48 | #include "cs_internal.h" | ||
49 | |||
50 | #include <asm/io.h> | ||
51 | #include <asm/irq.h> | ||
52 | #include <asm/system.h> | ||
53 | |||
54 | #include <asm/au1000.h> | ||
55 | #include <asm/au1000_pcmcia.h> | ||
56 | #include <asm/xxs1500.h> | ||
57 | |||
58 | #if 0 | ||
59 | #define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) | ||
60 | #else | ||
61 | #define DEBUG(x,args...) | ||
62 | #endif | ||
63 | |||
64 | static int xxs1500_pcmcia_init(struct pcmcia_init *init) | ||
65 | { | ||
66 | return PCMCIA_NUM_SOCKS; | ||
67 | } | ||
68 | |||
69 | static int xxs1500_pcmcia_shutdown(void) | ||
70 | { | ||
71 | /* turn off power */ | ||
72 | au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30), | ||
73 | GPIO2_OUTPUT); | ||
74 | au_sync_delay(100); | ||
75 | |||
76 | /* assert reset */ | ||
77 | au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20), | ||
78 | GPIO2_OUTPUT); | ||
79 | au_sync_delay(100); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | |||
84 | static int | ||
85 | xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) | ||
86 | { | ||
87 | u32 inserted; u32 vs; | ||
88 | unsigned long gpio, gpio2; | ||
89 | |||
90 | if(sock > PCMCIA_MAX_SOCK) return -1; | ||
91 | |||
92 | gpio = au_readl(SYS_PINSTATERD); | ||
93 | gpio2 = au_readl(GPIO2_PINSTATE); | ||
94 | |||
95 | vs = gpio2 & ((1<<8) | (1<<9)); | ||
96 | inserted = (!(gpio & 0x1) && !(gpio & 0x2)); | ||
97 | |||
98 | state->ready = 0; | ||
99 | state->vs_Xv = 0; | ||
100 | state->vs_3v = 0; | ||
101 | state->detect = 0; | ||
102 | |||
103 | if (inserted) { | ||
104 | switch (vs) { | ||
105 | case 0: | ||
106 | case 1: | ||
107 | case 2: | ||
108 | state->vs_3v=1; | ||
109 | break; | ||
110 | case 3: /* 5V */ | ||
111 | default: | ||
112 | /* return without setting 'detect' */ | ||
113 | printk(KERN_ERR "au1x00_cs: unsupported VS\n", | ||
114 | vs); | ||
115 | return; | ||
116 | } | ||
117 | state->detect = 1; | ||
118 | } | ||
119 | |||
120 | if (state->detect) { | ||
121 | state->ready = 1; | ||
122 | } | ||
123 | |||
124 | state->bvd1= gpio2 & (1<<10); | ||
125 | state->bvd2 = gpio2 & (1<<11); | ||
126 | state->wrprot=0; | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | |||
131 | static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info) | ||
132 | { | ||
133 | |||
134 | if(info->sock > PCMCIA_MAX_SOCK) return -1; | ||
135 | info->irq = PCMCIA_IRQ; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int | ||
141 | xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure) | ||
142 | { | ||
143 | |||
144 | if(configure->sock > PCMCIA_MAX_SOCK) return -1; | ||
145 | |||
146 | DEBUG("Vcc %dV Vpp %dV, reset %d\n", | ||
147 | configure->vcc, configure->vpp, configure->reset); | ||
148 | |||
149 | switch(configure->vcc){ | ||
150 | case 33: /* Vcc 3.3V */ | ||
151 | /* turn on power */ | ||
152 | DEBUG("turn on power\n"); | ||
153 | au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30), | ||
154 | GPIO2_OUTPUT); | ||
155 | au_sync_delay(100); | ||
156 | break; | ||
157 | case 50: /* Vcc 5V */ | ||
158 | default: /* what's this ? */ | ||
159 | printk(KERN_ERR "au1x00_cs: unsupported VCC\n"); | ||
160 | case 0: /* Vcc 0 */ | ||
161 | /* turn off power */ | ||
162 | au_sync_delay(100); | ||
163 | au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30), | ||
164 | GPIO2_OUTPUT); | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | if (!configure->reset) { | ||
169 | DEBUG("deassert reset\n"); | ||
170 | au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20), | ||
171 | GPIO2_OUTPUT); | ||
172 | au_sync_delay(100); | ||
173 | au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21), | ||
174 | GPIO2_OUTPUT); | ||
175 | } | ||
176 | else { | ||
177 | DEBUG("assert reset\n"); | ||
178 | au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20), | ||
179 | GPIO2_OUTPUT); | ||
180 | } | ||
181 | au_sync_delay(100); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | struct pcmcia_low_level xxs1500_pcmcia_ops = { | ||
186 | xxs1500_pcmcia_init, | ||
187 | xxs1500_pcmcia_shutdown, | ||
188 | xxs1500_pcmcia_socket_state, | ||
189 | xxs1500_pcmcia_get_irq_info, | ||
190 | xxs1500_pcmcia_configure_socket | ||
191 | }; | ||
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c new file mode 100644 index 000000000000..3ccb5247ec50 --- /dev/null +++ b/drivers/pcmcia/cardbus.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * cardbus.c -- 16-bit PCMCIA core support | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Cardbus handling has been re-written to be more of a PCI bridge thing, | ||
17 | * and the PCI code basically does all the resource handling. | ||
18 | * | ||
19 | * Linus, Jan 2000 | ||
20 | */ | ||
21 | |||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | #define IN_CARD_SERVICES | ||
34 | #include <pcmcia/version.h> | ||
35 | #include <pcmcia/cs_types.h> | ||
36 | #include <pcmcia/ss.h> | ||
37 | #include <pcmcia/cs.h> | ||
38 | #include <pcmcia/bulkmem.h> | ||
39 | #include <pcmcia/cistpl.h> | ||
40 | #include "cs_internal.h" | ||
41 | |||
42 | /*====================================================================*/ | ||
43 | |||
44 | #define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) | ||
45 | |||
46 | /* Offsets in the Expansion ROM Image Header */ | ||
47 | #define ROM_SIGNATURE 0x0000 /* 2 bytes */ | ||
48 | #define ROM_DATA_PTR 0x0018 /* 2 bytes */ | ||
49 | |||
50 | /* Offsets in the CardBus PC Card Data Structure */ | ||
51 | #define PCDATA_SIGNATURE 0x0000 /* 4 bytes */ | ||
52 | #define PCDATA_VPD_PTR 0x0008 /* 2 bytes */ | ||
53 | #define PCDATA_LENGTH 0x000a /* 2 bytes */ | ||
54 | #define PCDATA_REVISION 0x000c | ||
55 | #define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */ | ||
56 | #define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */ | ||
57 | #define PCDATA_CODE_TYPE 0x0014 | ||
58 | #define PCDATA_INDICATOR 0x0015 | ||
59 | |||
60 | /*===================================================================== | ||
61 | |||
62 | Expansion ROM's have a special layout, and pointers specify an | ||
63 | image number and an offset within that image. xlate_rom_addr() | ||
64 | converts an image/offset address to an absolute offset from the | ||
65 | ROM's base address. | ||
66 | |||
67 | =====================================================================*/ | ||
68 | |||
69 | static u_int xlate_rom_addr(void __iomem *b, u_int addr) | ||
70 | { | ||
71 | u_int img = 0, ofs = 0, sz; | ||
72 | u_short data; | ||
73 | while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { | ||
74 | if (img == (addr >> 28)) | ||
75 | return (addr & 0x0fffffff) + ofs; | ||
76 | data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); | ||
77 | sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + | ||
78 | (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); | ||
79 | if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) | ||
80 | break; | ||
81 | b += sz; | ||
82 | ofs += sz; | ||
83 | img++; | ||
84 | } | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /*===================================================================== | ||
89 | |||
90 | These are similar to setup_cis_mem and release_cis_mem for 16-bit | ||
91 | cards. The "result" that is used externally is the cb_cis_virt | ||
92 | pointer in the struct pcmcia_socket structure. | ||
93 | |||
94 | =====================================================================*/ | ||
95 | |||
96 | static void cb_release_cis_mem(struct pcmcia_socket * s) | ||
97 | { | ||
98 | if (s->cb_cis_virt) { | ||
99 | cs_dbg(s, 1, "cb_release_cis_mem()\n"); | ||
100 | iounmap(s->cb_cis_virt); | ||
101 | s->cb_cis_virt = NULL; | ||
102 | s->cb_cis_res = NULL; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static int cb_setup_cis_mem(struct pcmcia_socket * s, struct resource *res) | ||
107 | { | ||
108 | unsigned int start, size; | ||
109 | |||
110 | if (res == s->cb_cis_res) | ||
111 | return 0; | ||
112 | |||
113 | if (s->cb_cis_res) | ||
114 | cb_release_cis_mem(s); | ||
115 | |||
116 | start = res->start; | ||
117 | size = res->end - start + 1; | ||
118 | s->cb_cis_virt = ioremap(start, size); | ||
119 | |||
120 | if (!s->cb_cis_virt) | ||
121 | return -1; | ||
122 | |||
123 | s->cb_cis_res = res; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | /*===================================================================== | ||
129 | |||
130 | This is used by the CIS processing code to read CIS information | ||
131 | from a CardBus device. | ||
132 | |||
133 | =====================================================================*/ | ||
134 | |||
135 | int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void *ptr) | ||
136 | { | ||
137 | struct pci_dev *dev; | ||
138 | struct resource *res; | ||
139 | |||
140 | cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); | ||
141 | |||
142 | dev = pci_find_slot(s->cb_dev->subordinate->number, 0); | ||
143 | if (!dev) | ||
144 | goto fail; | ||
145 | |||
146 | /* Config space? */ | ||
147 | if (space == 0) { | ||
148 | if (addr + len > 0x100) | ||
149 | goto fail; | ||
150 | for (; len; addr++, ptr++, len--) | ||
151 | pci_read_config_byte(dev, addr, ptr); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | res = dev->resource + space - 1; | ||
156 | if (!res->flags) | ||
157 | goto fail; | ||
158 | |||
159 | if (cb_setup_cis_mem(s, res) != 0) | ||
160 | goto fail; | ||
161 | |||
162 | if (space == 7) { | ||
163 | addr = xlate_rom_addr(s->cb_cis_virt, addr); | ||
164 | if (addr == 0) | ||
165 | goto fail; | ||
166 | } | ||
167 | |||
168 | if (addr + len > res->end - res->start) | ||
169 | goto fail; | ||
170 | |||
171 | memcpy_fromio(ptr, s->cb_cis_virt + addr, len); | ||
172 | return 0; | ||
173 | |||
174 | fail: | ||
175 | memset(ptr, 0xff, len); | ||
176 | return -1; | ||
177 | } | ||
178 | |||
179 | /*===================================================================== | ||
180 | |||
181 | cb_alloc() and cb_free() allocate and free the kernel data | ||
182 | structures for a Cardbus device, and handle the lowest level PCI | ||
183 | device setup issues. | ||
184 | |||
185 | =====================================================================*/ | ||
186 | |||
187 | /* | ||
188 | * Since there is only one interrupt available to CardBus | ||
189 | * devices, all devices downstream of this device must | ||
190 | * be using this IRQ. | ||
191 | */ | ||
192 | static void cardbus_assign_irqs(struct pci_bus *bus, int irq) | ||
193 | { | ||
194 | struct pci_dev *dev; | ||
195 | |||
196 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
197 | u8 irq_pin; | ||
198 | |||
199 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); | ||
200 | if (irq_pin) { | ||
201 | dev->irq = irq; | ||
202 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
203 | } | ||
204 | |||
205 | if (dev->subordinate) | ||
206 | cardbus_assign_irqs(dev->subordinate, irq); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | int cb_alloc(struct pcmcia_socket * s) | ||
211 | { | ||
212 | struct pci_bus *bus = s->cb_dev->subordinate; | ||
213 | struct pci_dev *dev; | ||
214 | unsigned int max, pass; | ||
215 | |||
216 | s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); | ||
217 | // pcibios_fixup_bus(bus); | ||
218 | |||
219 | max = bus->secondary; | ||
220 | for (pass = 0; pass < 2; pass++) | ||
221 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
222 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
223 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
224 | max = pci_scan_bridge(bus, dev, max, pass); | ||
225 | |||
226 | /* | ||
227 | * Size all resources below the CardBus controller. | ||
228 | */ | ||
229 | pci_bus_size_bridges(bus); | ||
230 | pci_bus_assign_resources(bus); | ||
231 | cardbus_assign_irqs(bus, s->pci_irq); | ||
232 | pci_enable_bridges(bus); | ||
233 | pci_bus_add_devices(bus); | ||
234 | |||
235 | s->irq.AssignedIRQ = s->pci_irq; | ||
236 | return CS_SUCCESS; | ||
237 | } | ||
238 | |||
239 | void cb_free(struct pcmcia_socket * s) | ||
240 | { | ||
241 | struct pci_dev *bridge = s->cb_dev; | ||
242 | |||
243 | cb_release_cis_mem(s); | ||
244 | |||
245 | if (bridge) | ||
246 | pci_remove_behind_bridge(bridge); | ||
247 | } | ||
diff --git a/drivers/pcmcia/cirrus.h b/drivers/pcmcia/cirrus.h new file mode 100644 index 000000000000..ecd4fc7f666f --- /dev/null +++ b/drivers/pcmcia/cirrus.h | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * cirrus.h 1.4 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_CIRRUS_H | ||
31 | #define _LINUX_CIRRUS_H | ||
32 | |||
33 | #ifndef PCI_VENDOR_ID_CIRRUS | ||
34 | #define PCI_VENDOR_ID_CIRRUS 0x1013 | ||
35 | #endif | ||
36 | #ifndef PCI_DEVICE_ID_CIRRUS_6729 | ||
37 | #define PCI_DEVICE_ID_CIRRUS_6729 0x1100 | ||
38 | #endif | ||
39 | #ifndef PCI_DEVICE_ID_CIRRUS_6832 | ||
40 | #define PCI_DEVICE_ID_CIRRUS_6832 0x1110 | ||
41 | #endif | ||
42 | |||
43 | #define PD67_MISC_CTL_1 0x16 /* Misc control 1 */ | ||
44 | #define PD67_FIFO_CTL 0x17 /* FIFO control */ | ||
45 | #define PD67_MISC_CTL_2 0x1E /* Misc control 2 */ | ||
46 | #define PD67_CHIP_INFO 0x1f /* Chip information */ | ||
47 | #define PD67_ATA_CTL 0x026 /* 6730: ATA control */ | ||
48 | #define PD67_EXT_INDEX 0x2e /* Extension index */ | ||
49 | #define PD67_EXT_DATA 0x2f /* Extension data */ | ||
50 | |||
51 | /* PD6722 extension registers -- indexed in PD67_EXT_INDEX */ | ||
52 | #define PD67_DATA_MASK0 0x01 /* Data mask 0 */ | ||
53 | #define PD67_DATA_MASK1 0x02 /* Data mask 1 */ | ||
54 | #define PD67_DMA_CTL 0x03 /* DMA control */ | ||
55 | |||
56 | /* PD6730 extension registers -- indexed in PD67_EXT_INDEX */ | ||
57 | #define PD67_EXT_CTL_1 0x03 /* Extension control 1 */ | ||
58 | #define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */ | ||
59 | #define PD67_EXTERN_DATA 0x0a | ||
60 | #define PD67_MISC_CTL_3 0x25 | ||
61 | #define PD67_SMB_PWR_CTL 0x26 | ||
62 | |||
63 | /* I/O window address offset */ | ||
64 | #define PD67_IO_OFF(w) (0x36+((w)<<1)) | ||
65 | |||
66 | /* Timing register sets */ | ||
67 | #define PD67_TIME_SETUP(n) (0x3a + 3*(n)) | ||
68 | #define PD67_TIME_CMD(n) (0x3b + 3*(n)) | ||
69 | #define PD67_TIME_RECOV(n) (0x3c + 3*(n)) | ||
70 | |||
71 | /* Flags for PD67_MISC_CTL_1 */ | ||
72 | #define PD67_MC1_5V_DET 0x01 /* 5v detect */ | ||
73 | #define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */ | ||
74 | #define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */ | ||
75 | #define PD67_MC1_PULSE_MGMT 0x04 | ||
76 | #define PD67_MC1_PULSE_IRQ 0x08 | ||
77 | #define PD67_MC1_SPKR_ENA 0x10 | ||
78 | #define PD67_MC1_INPACK_ENA 0x80 | ||
79 | |||
80 | /* Flags for PD67_FIFO_CTL */ | ||
81 | #define PD67_FIFO_EMPTY 0x80 | ||
82 | |||
83 | /* Flags for PD67_MISC_CTL_2 */ | ||
84 | #define PD67_MC2_FREQ_BYPASS 0x01 | ||
85 | #define PD67_MC2_DYNAMIC_MODE 0x02 | ||
86 | #define PD67_MC2_SUSPEND 0x04 | ||
87 | #define PD67_MC2_5V_CORE 0x08 | ||
88 | #define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */ | ||
89 | #define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus > 25 MHz */ | ||
90 | #define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */ | ||
91 | #define PD67_MC2_DMA_MODE 0x40 | ||
92 | #define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */ | ||
93 | |||
94 | /* Flags for PD67_CHIP_INFO */ | ||
95 | #define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */ | ||
96 | #define PD67_INFO_CHIP_ID 0xc0 | ||
97 | #define PD67_INFO_REV 0x1c | ||
98 | |||
99 | /* Fields in PD67_TIME_* registers */ | ||
100 | #define PD67_TIME_SCALE 0xc0 | ||
101 | #define PD67_TIME_SCALE_1 0x00 | ||
102 | #define PD67_TIME_SCALE_16 0x40 | ||
103 | #define PD67_TIME_SCALE_256 0x80 | ||
104 | #define PD67_TIME_SCALE_4096 0xc0 | ||
105 | #define PD67_TIME_MULT 0x3f | ||
106 | |||
107 | /* Fields in PD67_DMA_CTL */ | ||
108 | #define PD67_DMA_MODE 0xc0 | ||
109 | #define PD67_DMA_OFF 0x00 | ||
110 | #define PD67_DMA_DREQ_INPACK 0x40 | ||
111 | #define PD67_DMA_DREQ_WP 0x80 | ||
112 | #define PD67_DMA_DREQ_BVD2 0xc0 | ||
113 | #define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */ | ||
114 | |||
115 | /* Fields in PD67_EXT_CTL_1 */ | ||
116 | #define PD67_EC1_VCC_PWR_LOCK 0x01 | ||
117 | #define PD67_EC1_AUTO_PWR_CLEAR 0x02 | ||
118 | #define PD67_EC1_LED_ENA 0x04 | ||
119 | #define PD67_EC1_INV_CARD_IRQ 0x08 | ||
120 | #define PD67_EC1_INV_MGMT_IRQ 0x10 | ||
121 | #define PD67_EC1_PULLUP_CTL 0x20 | ||
122 | |||
123 | /* Fields in PD67_MISC_CTL_3 */ | ||
124 | #define PD67_MC3_IRQ_MASK 0x03 | ||
125 | #define PD67_MC3_IRQ_PCPCI 0x00 | ||
126 | #define PD67_MC3_IRQ_EXTERN 0x01 | ||
127 | #define PD67_MC3_IRQ_PCIWAY 0x02 | ||
128 | #define PD67_MC3_IRQ_PCI 0x03 | ||
129 | #define PD67_MC3_PWR_MASK 0x0c | ||
130 | #define PD67_MC3_PWR_SERIAL 0x00 | ||
131 | #define PD67_MC3_PWR_TI2202 0x08 | ||
132 | #define PD67_MC3_PWR_SMB 0x0c | ||
133 | |||
134 | /* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */ | ||
135 | |||
136 | /* PD6832 extension registers -- indexed in PD67_EXT_INDEX */ | ||
137 | #define PD68_EXT_CTL_2 0x0b | ||
138 | #define PD68_PCI_SPACE 0x22 | ||
139 | #define PD68_PCCARD_SPACE 0x23 | ||
140 | #define PD68_WINDOW_TYPE 0x24 | ||
141 | #define PD68_EXT_CSC 0x2e | ||
142 | #define PD68_MISC_CTL_4 0x2f | ||
143 | #define PD68_MISC_CTL_5 0x30 | ||
144 | #define PD68_MISC_CTL_6 0x31 | ||
145 | |||
146 | /* Extra flags in PD67_MISC_CTL_3 */ | ||
147 | #define PD68_MC3_HW_SUSP 0x10 | ||
148 | #define PD68_MC3_MM_EXPAND 0x40 | ||
149 | #define PD68_MC3_MM_ARM 0x80 | ||
150 | |||
151 | /* Bridge Control Register */ | ||
152 | #define PD6832_BCR_MGMT_IRQ_ENA 0x0800 | ||
153 | |||
154 | /* Socket Number Register */ | ||
155 | #define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */ | ||
156 | |||
157 | #endif /* _LINUX_CIRRUS_H */ | ||
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c new file mode 100644 index 000000000000..e29a6ddf2fd7 --- /dev/null +++ b/drivers/pcmcia/cistpl.c | |||
@@ -0,0 +1,1490 @@ | |||
1 | /* | ||
2 | * cistpl.c -- 16-bit PCMCIA Card Information Structure parser | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/major.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/byteorder.h> | ||
30 | |||
31 | #include <pcmcia/cs_types.h> | ||
32 | #include <pcmcia/ss.h> | ||
33 | #include <pcmcia/cs.h> | ||
34 | #include <pcmcia/bulkmem.h> | ||
35 | #include <pcmcia/cisreg.h> | ||
36 | #include <pcmcia/cistpl.h> | ||
37 | #include "cs_internal.h" | ||
38 | |||
39 | static const u_char mantissa[] = { | ||
40 | 10, 12, 13, 15, 20, 25, 30, 35, | ||
41 | 40, 45, 50, 55, 60, 70, 80, 90 | ||
42 | }; | ||
43 | |||
44 | static const u_int exponent[] = { | ||
45 | 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 | ||
46 | }; | ||
47 | |||
48 | /* Convert an extended speed byte to a time in nanoseconds */ | ||
49 | #define SPEED_CVT(v) \ | ||
50 | (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10) | ||
51 | /* Convert a power byte to a current in 0.1 microamps */ | ||
52 | #define POWER_CVT(v) \ | ||
53 | (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10) | ||
54 | #define POWER_SCALE(v) (exponent[(v)&7]) | ||
55 | |||
56 | /* Upper limit on reasonable # of tuples */ | ||
57 | #define MAX_TUPLES 200 | ||
58 | |||
59 | /*====================================================================*/ | ||
60 | |||
61 | /* Parameters that can be set with 'insmod' */ | ||
62 | |||
63 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) | ||
64 | |||
65 | INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ | ||
66 | |||
67 | void release_cis_mem(struct pcmcia_socket *s) | ||
68 | { | ||
69 | if (s->cis_mem.flags & MAP_ACTIVE) { | ||
70 | s->cis_mem.flags &= ~MAP_ACTIVE; | ||
71 | s->ops->set_mem_map(s, &s->cis_mem); | ||
72 | if (s->cis_mem.res) { | ||
73 | release_resource(s->cis_mem.res); | ||
74 | kfree(s->cis_mem.res); | ||
75 | s->cis_mem.res = NULL; | ||
76 | } | ||
77 | iounmap(s->cis_virt); | ||
78 | s->cis_virt = NULL; | ||
79 | } | ||
80 | } | ||
81 | EXPORT_SYMBOL(release_cis_mem); | ||
82 | |||
83 | /* | ||
84 | * Map the card memory at "card_offset" into virtual space. | ||
85 | * If flags & MAP_ATTRIB, map the attribute space, otherwise | ||
86 | * map the memory space. | ||
87 | */ | ||
88 | static void __iomem * | ||
89 | set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) | ||
90 | { | ||
91 | pccard_mem_map *mem = &s->cis_mem; | ||
92 | if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) { | ||
93 | mem->res = find_mem_region(0, s->map_size, s->map_size, 0, s); | ||
94 | if (mem->res == NULL) { | ||
95 | printk(KERN_NOTICE "cs: unable to map card memory!\n"); | ||
96 | return NULL; | ||
97 | } | ||
98 | s->cis_virt = ioremap(mem->res->start, s->map_size); | ||
99 | } | ||
100 | mem->card_start = card_offset; | ||
101 | mem->flags = flags; | ||
102 | s->ops->set_mem_map(s, mem); | ||
103 | if (s->features & SS_CAP_STATIC_MAP) { | ||
104 | if (s->cis_virt) | ||
105 | iounmap(s->cis_virt); | ||
106 | s->cis_virt = ioremap(mem->static_start, s->map_size); | ||
107 | } | ||
108 | return s->cis_virt; | ||
109 | } | ||
110 | |||
111 | /*====================================================================== | ||
112 | |||
113 | Low-level functions to read and write CIS memory. I think the | ||
114 | write routine is only useful for writing one-byte registers. | ||
115 | |||
116 | ======================================================================*/ | ||
117 | |||
118 | /* Bits in attr field */ | ||
119 | #define IS_ATTR 1 | ||
120 | #define IS_INDIRECT 8 | ||
121 | |||
122 | int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | ||
123 | u_int len, void *ptr) | ||
124 | { | ||
125 | void __iomem *sys, *end; | ||
126 | unsigned char *buf = ptr; | ||
127 | |||
128 | cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len); | ||
129 | |||
130 | if (attr & IS_INDIRECT) { | ||
131 | /* Indirect accesses use a bunch of special registers at fixed | ||
132 | locations in common memory */ | ||
133 | u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; | ||
134 | if (attr & IS_ATTR) { | ||
135 | addr *= 2; | ||
136 | flags = ICTRL0_AUTOINC; | ||
137 | } | ||
138 | |||
139 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); | ||
140 | if (!sys) { | ||
141 | memset(ptr, 0xff, len); | ||
142 | return -1; | ||
143 | } | ||
144 | |||
145 | writeb(flags, sys+CISREG_ICTRL0); | ||
146 | writeb(addr & 0xff, sys+CISREG_IADDR0); | ||
147 | writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); | ||
148 | writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); | ||
149 | writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); | ||
150 | for ( ; len > 0; len--, buf++) | ||
151 | *buf = readb(sys+CISREG_IDATA0); | ||
152 | } else { | ||
153 | u_int inc = 1, card_offset, flags; | ||
154 | |||
155 | flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); | ||
156 | if (attr) { | ||
157 | flags |= MAP_ATTRIB; | ||
158 | inc++; | ||
159 | addr *= 2; | ||
160 | } | ||
161 | |||
162 | card_offset = addr & ~(s->map_size-1); | ||
163 | while (len) { | ||
164 | sys = set_cis_map(s, card_offset, flags); | ||
165 | if (!sys) { | ||
166 | memset(ptr, 0xff, len); | ||
167 | return -1; | ||
168 | } | ||
169 | end = sys + s->map_size; | ||
170 | sys = sys + (addr & (s->map_size-1)); | ||
171 | for ( ; len > 0; len--, buf++, sys += inc) { | ||
172 | if (sys == end) | ||
173 | break; | ||
174 | *buf = readb(sys); | ||
175 | } | ||
176 | card_offset += s->map_size; | ||
177 | addr = 0; | ||
178 | } | ||
179 | } | ||
180 | cs_dbg(s, 3, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", | ||
181 | *(u_char *)(ptr+0), *(u_char *)(ptr+1), | ||
182 | *(u_char *)(ptr+2), *(u_char *)(ptr+3)); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | ||
187 | u_int len, void *ptr) | ||
188 | { | ||
189 | void __iomem *sys, *end; | ||
190 | unsigned char *buf = ptr; | ||
191 | |||
192 | cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len); | ||
193 | |||
194 | if (attr & IS_INDIRECT) { | ||
195 | /* Indirect accesses use a bunch of special registers at fixed | ||
196 | locations in common memory */ | ||
197 | u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; | ||
198 | if (attr & IS_ATTR) { | ||
199 | addr *= 2; | ||
200 | flags = ICTRL0_AUTOINC; | ||
201 | } | ||
202 | |||
203 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); | ||
204 | if (!sys) | ||
205 | return; /* FIXME: Error */ | ||
206 | |||
207 | writeb(flags, sys+CISREG_ICTRL0); | ||
208 | writeb(addr & 0xff, sys+CISREG_IADDR0); | ||
209 | writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); | ||
210 | writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); | ||
211 | writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); | ||
212 | for ( ; len > 0; len--, buf++) | ||
213 | writeb(*buf, sys+CISREG_IDATA0); | ||
214 | } else { | ||
215 | u_int inc = 1, card_offset, flags; | ||
216 | |||
217 | flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); | ||
218 | if (attr & IS_ATTR) { | ||
219 | flags |= MAP_ATTRIB; | ||
220 | inc++; | ||
221 | addr *= 2; | ||
222 | } | ||
223 | |||
224 | card_offset = addr & ~(s->map_size-1); | ||
225 | while (len) { | ||
226 | sys = set_cis_map(s, card_offset, flags); | ||
227 | if (!sys) | ||
228 | return; /* FIXME: error */ | ||
229 | |||
230 | end = sys + s->map_size; | ||
231 | sys = sys + (addr & (s->map_size-1)); | ||
232 | for ( ; len > 0; len--, buf++, sys += inc) { | ||
233 | if (sys == end) | ||
234 | break; | ||
235 | writeb(*buf, sys); | ||
236 | } | ||
237 | card_offset += s->map_size; | ||
238 | addr = 0; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /*====================================================================== | ||
244 | |||
245 | This is a wrapper around read_cis_mem, with the same interface, | ||
246 | but which caches information, for cards whose CIS may not be | ||
247 | readable all the time. | ||
248 | |||
249 | ======================================================================*/ | ||
250 | |||
251 | static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, | ||
252 | u_int len, void *ptr) | ||
253 | { | ||
254 | struct cis_cache_entry *cis; | ||
255 | int ret; | ||
256 | |||
257 | if (s->fake_cis) { | ||
258 | if (s->fake_cis_len > addr+len) | ||
259 | memcpy(ptr, s->fake_cis+addr, len); | ||
260 | else | ||
261 | memset(ptr, 0xff, len); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | list_for_each_entry(cis, &s->cis_cache, node) { | ||
266 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { | ||
267 | memcpy(ptr, cis->cache, len); | ||
268 | return; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | #ifdef CONFIG_CARDBUS | ||
273 | if (s->state & SOCKET_CARDBUS) | ||
274 | ret = read_cb_mem(s, attr, addr, len, ptr); | ||
275 | else | ||
276 | #endif | ||
277 | ret = read_cis_mem(s, attr, addr, len, ptr); | ||
278 | |||
279 | if (ret == 0) { | ||
280 | /* Copy data into the cache */ | ||
281 | cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL); | ||
282 | if (cis) { | ||
283 | cis->addr = addr; | ||
284 | cis->len = len; | ||
285 | cis->attr = attr; | ||
286 | memcpy(cis->cache, ptr, len); | ||
287 | list_add(&cis->node, &s->cis_cache); | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | |||
292 | static void | ||
293 | remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) | ||
294 | { | ||
295 | struct cis_cache_entry *cis; | ||
296 | |||
297 | list_for_each_entry(cis, &s->cis_cache, node) | ||
298 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { | ||
299 | list_del(&cis->node); | ||
300 | kfree(cis); | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | void destroy_cis_cache(struct pcmcia_socket *s) | ||
306 | { | ||
307 | struct list_head *l, *n; | ||
308 | |||
309 | list_for_each_safe(l, n, &s->cis_cache) { | ||
310 | struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node); | ||
311 | |||
312 | list_del(&cis->node); | ||
313 | kfree(cis); | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * If there was a fake CIS, destroy that as well. | ||
318 | */ | ||
319 | if (s->fake_cis) { | ||
320 | kfree(s->fake_cis); | ||
321 | s->fake_cis = NULL; | ||
322 | } | ||
323 | } | ||
324 | EXPORT_SYMBOL(destroy_cis_cache); | ||
325 | |||
326 | /*====================================================================== | ||
327 | |||
328 | This verifies if the CIS of a card matches what is in the CIS | ||
329 | cache. | ||
330 | |||
331 | ======================================================================*/ | ||
332 | |||
333 | int verify_cis_cache(struct pcmcia_socket *s) | ||
334 | { | ||
335 | struct cis_cache_entry *cis; | ||
336 | char *buf; | ||
337 | |||
338 | buf = kmalloc(256, GFP_KERNEL); | ||
339 | if (buf == NULL) | ||
340 | return -1; | ||
341 | list_for_each_entry(cis, &s->cis_cache, node) { | ||
342 | int len = cis->len; | ||
343 | |||
344 | if (len > 256) | ||
345 | len = 256; | ||
346 | #ifdef CONFIG_CARDBUS | ||
347 | if (s->state & SOCKET_CARDBUS) | ||
348 | read_cb_mem(s, cis->attr, cis->addr, len, buf); | ||
349 | else | ||
350 | #endif | ||
351 | read_cis_mem(s, cis->attr, cis->addr, len, buf); | ||
352 | |||
353 | if (memcmp(buf, cis->cache, len) != 0) { | ||
354 | kfree(buf); | ||
355 | return -1; | ||
356 | } | ||
357 | } | ||
358 | kfree(buf); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | /*====================================================================== | ||
363 | |||
364 | For really bad cards, we provide a facility for uploading a | ||
365 | replacement CIS. | ||
366 | |||
367 | ======================================================================*/ | ||
368 | |||
369 | int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis) | ||
370 | { | ||
371 | if (s->fake_cis != NULL) { | ||
372 | kfree(s->fake_cis); | ||
373 | s->fake_cis = NULL; | ||
374 | } | ||
375 | if (cis->Length > CISTPL_MAX_CIS_SIZE) | ||
376 | return CS_BAD_SIZE; | ||
377 | s->fake_cis = kmalloc(cis->Length, GFP_KERNEL); | ||
378 | if (s->fake_cis == NULL) | ||
379 | return CS_OUT_OF_RESOURCE; | ||
380 | s->fake_cis_len = cis->Length; | ||
381 | memcpy(s->fake_cis, cis->Data, cis->Length); | ||
382 | return CS_SUCCESS; | ||
383 | } | ||
384 | |||
385 | /*====================================================================== | ||
386 | |||
387 | The high-level CIS tuple services | ||
388 | |||
389 | ======================================================================*/ | ||
390 | |||
391 | typedef struct tuple_flags { | ||
392 | u_int link_space:4; | ||
393 | u_int has_link:1; | ||
394 | u_int mfc_fn:3; | ||
395 | u_int space:4; | ||
396 | } tuple_flags; | ||
397 | |||
398 | #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) | ||
399 | #define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link) | ||
400 | #define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) | ||
401 | #define SPACE(f) (((tuple_flags *)(&(f)))->space) | ||
402 | |||
403 | int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple); | ||
404 | |||
405 | int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) | ||
406 | { | ||
407 | if (!s) | ||
408 | return CS_BAD_HANDLE; | ||
409 | if (!(s->state & SOCKET_PRESENT)) | ||
410 | return CS_NO_CARD; | ||
411 | tuple->TupleLink = tuple->Flags = 0; | ||
412 | #ifdef CONFIG_CARDBUS | ||
413 | if (s->state & SOCKET_CARDBUS) { | ||
414 | struct pci_dev *dev = s->cb_dev; | ||
415 | u_int ptr; | ||
416 | pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr); | ||
417 | tuple->CISOffset = ptr & ~7; | ||
418 | SPACE(tuple->Flags) = (ptr & 7); | ||
419 | } else | ||
420 | #endif | ||
421 | { | ||
422 | /* Assume presence of a LONGLINK_C to address 0 */ | ||
423 | tuple->CISOffset = tuple->LinkOffset = 0; | ||
424 | SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; | ||
425 | } | ||
426 | if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && | ||
427 | !(tuple->Attributes & TUPLE_RETURN_COMMON)) { | ||
428 | cisdata_t req = tuple->DesiredTuple; | ||
429 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; | ||
430 | if (pccard_get_next_tuple(s, function, tuple) == CS_SUCCESS) { | ||
431 | tuple->DesiredTuple = CISTPL_LINKTARGET; | ||
432 | if (pccard_get_next_tuple(s, function, tuple) != CS_SUCCESS) | ||
433 | return CS_NO_MORE_ITEMS; | ||
434 | } else | ||
435 | tuple->CISOffset = tuple->TupleLink = 0; | ||
436 | tuple->DesiredTuple = req; | ||
437 | } | ||
438 | return pccard_get_next_tuple(s, function, tuple); | ||
439 | } | ||
440 | EXPORT_SYMBOL(pccard_get_first_tuple); | ||
441 | |||
442 | static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | ||
443 | { | ||
444 | u_char link[5]; | ||
445 | u_int ofs; | ||
446 | |||
447 | if (MFC_FN(tuple->Flags)) { | ||
448 | /* Get indirect link from the MFC tuple */ | ||
449 | read_cis_cache(s, LINK_SPACE(tuple->Flags), | ||
450 | tuple->LinkOffset, 5, link); | ||
451 | ofs = le32_to_cpu(*(u_int *)(link+1)); | ||
452 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); | ||
453 | /* Move to the next indirect link */ | ||
454 | tuple->LinkOffset += 5; | ||
455 | MFC_FN(tuple->Flags)--; | ||
456 | } else if (HAS_LINK(tuple->Flags)) { | ||
457 | ofs = tuple->LinkOffset; | ||
458 | SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); | ||
459 | HAS_LINK(tuple->Flags) = 0; | ||
460 | } else { | ||
461 | return -1; | ||
462 | } | ||
463 | if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { | ||
464 | /* This is ugly, but a common CIS error is to code the long | ||
465 | link offset incorrectly, so we check the right spot... */ | ||
466 | read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); | ||
467 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | ||
468 | (strncmp(link+2, "CIS", 3) == 0)) | ||
469 | return ofs; | ||
470 | remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); | ||
471 | /* Then, we try the wrong spot... */ | ||
472 | ofs = ofs >> 1; | ||
473 | } | ||
474 | read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); | ||
475 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | ||
476 | (strncmp(link+2, "CIS", 3) == 0)) | ||
477 | return ofs; | ||
478 | remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); | ||
479 | return -1; | ||
480 | } | ||
481 | |||
482 | int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) | ||
483 | { | ||
484 | u_char link[2], tmp; | ||
485 | int ofs, i, attr; | ||
486 | |||
487 | if (!s) | ||
488 | return CS_BAD_HANDLE; | ||
489 | if (!(s->state & SOCKET_PRESENT)) | ||
490 | return CS_NO_CARD; | ||
491 | |||
492 | link[1] = tuple->TupleLink; | ||
493 | ofs = tuple->CISOffset + tuple->TupleLink; | ||
494 | attr = SPACE(tuple->Flags); | ||
495 | |||
496 | for (i = 0; i < MAX_TUPLES; i++) { | ||
497 | if (link[1] == 0xff) { | ||
498 | link[0] = CISTPL_END; | ||
499 | } else { | ||
500 | read_cis_cache(s, attr, ofs, 2, link); | ||
501 | if (link[0] == CISTPL_NULL) { | ||
502 | ofs++; continue; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | /* End of chain? Follow long link if possible */ | ||
507 | if (link[0] == CISTPL_END) { | ||
508 | if ((ofs = follow_link(s, tuple)) < 0) | ||
509 | return CS_NO_MORE_ITEMS; | ||
510 | attr = SPACE(tuple->Flags); | ||
511 | read_cis_cache(s, attr, ofs, 2, link); | ||
512 | } | ||
513 | |||
514 | /* Is this a link tuple? Make a note of it */ | ||
515 | if ((link[0] == CISTPL_LONGLINK_A) || | ||
516 | (link[0] == CISTPL_LONGLINK_C) || | ||
517 | (link[0] == CISTPL_LONGLINK_MFC) || | ||
518 | (link[0] == CISTPL_LINKTARGET) || | ||
519 | (link[0] == CISTPL_INDIRECT) || | ||
520 | (link[0] == CISTPL_NO_LINK)) { | ||
521 | switch (link[0]) { | ||
522 | case CISTPL_LONGLINK_A: | ||
523 | HAS_LINK(tuple->Flags) = 1; | ||
524 | LINK_SPACE(tuple->Flags) = attr | IS_ATTR; | ||
525 | read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); | ||
526 | break; | ||
527 | case CISTPL_LONGLINK_C: | ||
528 | HAS_LINK(tuple->Flags) = 1; | ||
529 | LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; | ||
530 | read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); | ||
531 | break; | ||
532 | case CISTPL_INDIRECT: | ||
533 | HAS_LINK(tuple->Flags) = 1; | ||
534 | LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT; | ||
535 | tuple->LinkOffset = 0; | ||
536 | break; | ||
537 | case CISTPL_LONGLINK_MFC: | ||
538 | tuple->LinkOffset = ofs + 3; | ||
539 | LINK_SPACE(tuple->Flags) = attr; | ||
540 | if (function == BIND_FN_ALL) { | ||
541 | /* Follow all the MFC links */ | ||
542 | read_cis_cache(s, attr, ofs+2, 1, &tmp); | ||
543 | MFC_FN(tuple->Flags) = tmp; | ||
544 | } else { | ||
545 | /* Follow exactly one of the links */ | ||
546 | MFC_FN(tuple->Flags) = 1; | ||
547 | tuple->LinkOffset += function * 5; | ||
548 | } | ||
549 | break; | ||
550 | case CISTPL_NO_LINK: | ||
551 | HAS_LINK(tuple->Flags) = 0; | ||
552 | break; | ||
553 | } | ||
554 | if ((tuple->Attributes & TUPLE_RETURN_LINK) && | ||
555 | (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) | ||
556 | break; | ||
557 | } else | ||
558 | if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) | ||
559 | break; | ||
560 | |||
561 | if (link[0] == tuple->DesiredTuple) | ||
562 | break; | ||
563 | ofs += link[1] + 2; | ||
564 | } | ||
565 | if (i == MAX_TUPLES) { | ||
566 | cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n"); | ||
567 | return CS_NO_MORE_ITEMS; | ||
568 | } | ||
569 | |||
570 | tuple->TupleCode = link[0]; | ||
571 | tuple->TupleLink = link[1]; | ||
572 | tuple->CISOffset = ofs + 2; | ||
573 | return CS_SUCCESS; | ||
574 | } | ||
575 | EXPORT_SYMBOL(pccard_get_next_tuple); | ||
576 | |||
577 | /*====================================================================*/ | ||
578 | |||
579 | #define _MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
580 | |||
581 | int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) | ||
582 | { | ||
583 | u_int len; | ||
584 | |||
585 | if (!s) | ||
586 | return CS_BAD_HANDLE; | ||
587 | |||
588 | if (tuple->TupleLink < tuple->TupleOffset) | ||
589 | return CS_NO_MORE_ITEMS; | ||
590 | len = tuple->TupleLink - tuple->TupleOffset; | ||
591 | tuple->TupleDataLen = tuple->TupleLink; | ||
592 | if (len == 0) | ||
593 | return CS_SUCCESS; | ||
594 | read_cis_cache(s, SPACE(tuple->Flags), | ||
595 | tuple->CISOffset + tuple->TupleOffset, | ||
596 | _MIN(len, tuple->TupleDataMax), tuple->TupleData); | ||
597 | return CS_SUCCESS; | ||
598 | } | ||
599 | EXPORT_SYMBOL(pccard_get_tuple_data); | ||
600 | |||
601 | |||
602 | /*====================================================================== | ||
603 | |||
604 | Parsing routines for individual tuples | ||
605 | |||
606 | ======================================================================*/ | ||
607 | |||
608 | static int parse_device(tuple_t *tuple, cistpl_device_t *device) | ||
609 | { | ||
610 | int i; | ||
611 | u_char scale; | ||
612 | u_char *p, *q; | ||
613 | |||
614 | p = (u_char *)tuple->TupleData; | ||
615 | q = p + tuple->TupleDataLen; | ||
616 | |||
617 | device->ndev = 0; | ||
618 | for (i = 0; i < CISTPL_MAX_DEVICES; i++) { | ||
619 | |||
620 | if (*p == 0xff) break; | ||
621 | device->dev[i].type = (*p >> 4); | ||
622 | device->dev[i].wp = (*p & 0x08) ? 1 : 0; | ||
623 | switch (*p & 0x07) { | ||
624 | case 0: device->dev[i].speed = 0; break; | ||
625 | case 1: device->dev[i].speed = 250; break; | ||
626 | case 2: device->dev[i].speed = 200; break; | ||
627 | case 3: device->dev[i].speed = 150; break; | ||
628 | case 4: device->dev[i].speed = 100; break; | ||
629 | case 7: | ||
630 | if (++p == q) return CS_BAD_TUPLE; | ||
631 | device->dev[i].speed = SPEED_CVT(*p); | ||
632 | while (*p & 0x80) | ||
633 | if (++p == q) return CS_BAD_TUPLE; | ||
634 | break; | ||
635 | default: | ||
636 | return CS_BAD_TUPLE; | ||
637 | } | ||
638 | |||
639 | if (++p == q) return CS_BAD_TUPLE; | ||
640 | if (*p == 0xff) break; | ||
641 | scale = *p & 7; | ||
642 | if (scale == 7) return CS_BAD_TUPLE; | ||
643 | device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); | ||
644 | device->ndev++; | ||
645 | if (++p == q) break; | ||
646 | } | ||
647 | |||
648 | return CS_SUCCESS; | ||
649 | } | ||
650 | |||
651 | /*====================================================================*/ | ||
652 | |||
653 | static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) | ||
654 | { | ||
655 | u_char *p; | ||
656 | if (tuple->TupleDataLen < 5) | ||
657 | return CS_BAD_TUPLE; | ||
658 | p = (u_char *)tuple->TupleData; | ||
659 | csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2; | ||
660 | csum->len = le16_to_cpu(*(u_short *)(p + 2)); | ||
661 | csum->sum = *(p+4); | ||
662 | return CS_SUCCESS; | ||
663 | } | ||
664 | |||
665 | /*====================================================================*/ | ||
666 | |||
667 | static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) | ||
668 | { | ||
669 | if (tuple->TupleDataLen < 4) | ||
670 | return CS_BAD_TUPLE; | ||
671 | link->addr = le32_to_cpu(*(u_int *)tuple->TupleData); | ||
672 | return CS_SUCCESS; | ||
673 | } | ||
674 | |||
675 | /*====================================================================*/ | ||
676 | |||
677 | static int parse_longlink_mfc(tuple_t *tuple, | ||
678 | cistpl_longlink_mfc_t *link) | ||
679 | { | ||
680 | u_char *p; | ||
681 | int i; | ||
682 | |||
683 | p = (u_char *)tuple->TupleData; | ||
684 | |||
685 | link->nfn = *p; p++; | ||
686 | if (tuple->TupleDataLen <= link->nfn*5) | ||
687 | return CS_BAD_TUPLE; | ||
688 | for (i = 0; i < link->nfn; i++) { | ||
689 | link->fn[i].space = *p; p++; | ||
690 | link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4; | ||
691 | } | ||
692 | return CS_SUCCESS; | ||
693 | } | ||
694 | |||
695 | /*====================================================================*/ | ||
696 | |||
697 | static int parse_strings(u_char *p, u_char *q, int max, | ||
698 | char *s, u_char *ofs, u_char *found) | ||
699 | { | ||
700 | int i, j, ns; | ||
701 | |||
702 | if (p == q) return CS_BAD_TUPLE; | ||
703 | ns = 0; j = 0; | ||
704 | for (i = 0; i < max; i++) { | ||
705 | if (*p == 0xff) break; | ||
706 | ofs[i] = j; | ||
707 | ns++; | ||
708 | for (;;) { | ||
709 | s[j++] = (*p == 0xff) ? '\0' : *p; | ||
710 | if ((*p == '\0') || (*p == 0xff)) break; | ||
711 | if (++p == q) return CS_BAD_TUPLE; | ||
712 | } | ||
713 | if ((*p == 0xff) || (++p == q)) break; | ||
714 | } | ||
715 | if (found) { | ||
716 | *found = ns; | ||
717 | return CS_SUCCESS; | ||
718 | } else { | ||
719 | return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | /*====================================================================*/ | ||
724 | |||
725 | static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) | ||
726 | { | ||
727 | u_char *p, *q; | ||
728 | |||
729 | p = (u_char *)tuple->TupleData; | ||
730 | q = p + tuple->TupleDataLen; | ||
731 | |||
732 | vers_1->major = *p; p++; | ||
733 | vers_1->minor = *p; p++; | ||
734 | if (p >= q) return CS_BAD_TUPLE; | ||
735 | |||
736 | return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, | ||
737 | vers_1->str, vers_1->ofs, &vers_1->ns); | ||
738 | } | ||
739 | |||
740 | /*====================================================================*/ | ||
741 | |||
742 | static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) | ||
743 | { | ||
744 | u_char *p, *q; | ||
745 | |||
746 | p = (u_char *)tuple->TupleData; | ||
747 | q = p + tuple->TupleDataLen; | ||
748 | |||
749 | return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, | ||
750 | altstr->str, altstr->ofs, &altstr->ns); | ||
751 | } | ||
752 | |||
753 | /*====================================================================*/ | ||
754 | |||
755 | static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) | ||
756 | { | ||
757 | u_char *p, *q; | ||
758 | int nid; | ||
759 | |||
760 | p = (u_char *)tuple->TupleData; | ||
761 | q = p + tuple->TupleDataLen; | ||
762 | |||
763 | for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { | ||
764 | if (p > q-2) break; | ||
765 | jedec->id[nid].mfr = p[0]; | ||
766 | jedec->id[nid].info = p[1]; | ||
767 | p += 2; | ||
768 | } | ||
769 | jedec->nid = nid; | ||
770 | return CS_SUCCESS; | ||
771 | } | ||
772 | |||
773 | /*====================================================================*/ | ||
774 | |||
775 | static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) | ||
776 | { | ||
777 | u_short *p; | ||
778 | if (tuple->TupleDataLen < 4) | ||
779 | return CS_BAD_TUPLE; | ||
780 | p = (u_short *)tuple->TupleData; | ||
781 | m->manf = le16_to_cpu(p[0]); | ||
782 | m->card = le16_to_cpu(p[1]); | ||
783 | return CS_SUCCESS; | ||
784 | } | ||
785 | |||
786 | /*====================================================================*/ | ||
787 | |||
788 | static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) | ||
789 | { | ||
790 | u_char *p; | ||
791 | if (tuple->TupleDataLen < 2) | ||
792 | return CS_BAD_TUPLE; | ||
793 | p = (u_char *)tuple->TupleData; | ||
794 | f->func = p[0]; | ||
795 | f->sysinit = p[1]; | ||
796 | return CS_SUCCESS; | ||
797 | } | ||
798 | |||
799 | /*====================================================================*/ | ||
800 | |||
801 | static int parse_funce(tuple_t *tuple, cistpl_funce_t *f) | ||
802 | { | ||
803 | u_char *p; | ||
804 | int i; | ||
805 | if (tuple->TupleDataLen < 1) | ||
806 | return CS_BAD_TUPLE; | ||
807 | p = (u_char *)tuple->TupleData; | ||
808 | f->type = p[0]; | ||
809 | for (i = 1; i < tuple->TupleDataLen; i++) | ||
810 | f->data[i-1] = p[i]; | ||
811 | return CS_SUCCESS; | ||
812 | } | ||
813 | |||
814 | /*====================================================================*/ | ||
815 | |||
816 | static int parse_config(tuple_t *tuple, cistpl_config_t *config) | ||
817 | { | ||
818 | int rasz, rmsz, i; | ||
819 | u_char *p; | ||
820 | |||
821 | p = (u_char *)tuple->TupleData; | ||
822 | rasz = *p & 0x03; | ||
823 | rmsz = (*p & 0x3c) >> 2; | ||
824 | if (tuple->TupleDataLen < rasz+rmsz+4) | ||
825 | return CS_BAD_TUPLE; | ||
826 | config->last_idx = *(++p); | ||
827 | p++; | ||
828 | config->base = 0; | ||
829 | for (i = 0; i <= rasz; i++) | ||
830 | config->base += p[i] << (8*i); | ||
831 | p += rasz+1; | ||
832 | for (i = 0; i < 4; i++) | ||
833 | config->rmask[i] = 0; | ||
834 | for (i = 0; i <= rmsz; i++) | ||
835 | config->rmask[i>>2] += p[i] << (8*(i%4)); | ||
836 | config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); | ||
837 | return CS_SUCCESS; | ||
838 | } | ||
839 | |||
840 | /*====================================================================== | ||
841 | |||
842 | The following routines are all used to parse the nightmarish | ||
843 | config table entries. | ||
844 | |||
845 | ======================================================================*/ | ||
846 | |||
847 | static u_char *parse_power(u_char *p, u_char *q, | ||
848 | cistpl_power_t *pwr) | ||
849 | { | ||
850 | int i; | ||
851 | u_int scale; | ||
852 | |||
853 | if (p == q) return NULL; | ||
854 | pwr->present = *p; | ||
855 | pwr->flags = 0; | ||
856 | p++; | ||
857 | for (i = 0; i < 7; i++) | ||
858 | if (pwr->present & (1<<i)) { | ||
859 | if (p == q) return NULL; | ||
860 | pwr->param[i] = POWER_CVT(*p); | ||
861 | scale = POWER_SCALE(*p); | ||
862 | while (*p & 0x80) { | ||
863 | if (++p == q) return NULL; | ||
864 | if ((*p & 0x7f) < 100) | ||
865 | pwr->param[i] += (*p & 0x7f) * scale / 100; | ||
866 | else if (*p == 0x7d) | ||
867 | pwr->flags |= CISTPL_POWER_HIGHZ_OK; | ||
868 | else if (*p == 0x7e) | ||
869 | pwr->param[i] = 0; | ||
870 | else if (*p == 0x7f) | ||
871 | pwr->flags |= CISTPL_POWER_HIGHZ_REQ; | ||
872 | else | ||
873 | return NULL; | ||
874 | } | ||
875 | p++; | ||
876 | } | ||
877 | return p; | ||
878 | } | ||
879 | |||
880 | /*====================================================================*/ | ||
881 | |||
882 | static u_char *parse_timing(u_char *p, u_char *q, | ||
883 | cistpl_timing_t *timing) | ||
884 | { | ||
885 | u_char scale; | ||
886 | |||
887 | if (p == q) return NULL; | ||
888 | scale = *p; | ||
889 | if ((scale & 3) != 3) { | ||
890 | if (++p == q) return NULL; | ||
891 | timing->wait = SPEED_CVT(*p); | ||
892 | timing->waitscale = exponent[scale & 3]; | ||
893 | } else | ||
894 | timing->wait = 0; | ||
895 | scale >>= 2; | ||
896 | if ((scale & 7) != 7) { | ||
897 | if (++p == q) return NULL; | ||
898 | timing->ready = SPEED_CVT(*p); | ||
899 | timing->rdyscale = exponent[scale & 7]; | ||
900 | } else | ||
901 | timing->ready = 0; | ||
902 | scale >>= 3; | ||
903 | if (scale != 7) { | ||
904 | if (++p == q) return NULL; | ||
905 | timing->reserved = SPEED_CVT(*p); | ||
906 | timing->rsvscale = exponent[scale]; | ||
907 | } else | ||
908 | timing->reserved = 0; | ||
909 | p++; | ||
910 | return p; | ||
911 | } | ||
912 | |||
913 | /*====================================================================*/ | ||
914 | |||
915 | static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) | ||
916 | { | ||
917 | int i, j, bsz, lsz; | ||
918 | |||
919 | if (p == q) return NULL; | ||
920 | io->flags = *p; | ||
921 | |||
922 | if (!(*p & 0x80)) { | ||
923 | io->nwin = 1; | ||
924 | io->win[0].base = 0; | ||
925 | io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); | ||
926 | return p+1; | ||
927 | } | ||
928 | |||
929 | if (++p == q) return NULL; | ||
930 | io->nwin = (*p & 0x0f) + 1; | ||
931 | bsz = (*p & 0x30) >> 4; | ||
932 | if (bsz == 3) bsz++; | ||
933 | lsz = (*p & 0xc0) >> 6; | ||
934 | if (lsz == 3) lsz++; | ||
935 | p++; | ||
936 | |||
937 | for (i = 0; i < io->nwin; i++) { | ||
938 | io->win[i].base = 0; | ||
939 | io->win[i].len = 1; | ||
940 | for (j = 0; j < bsz; j++, p++) { | ||
941 | if (p == q) return NULL; | ||
942 | io->win[i].base += *p << (j*8); | ||
943 | } | ||
944 | for (j = 0; j < lsz; j++, p++) { | ||
945 | if (p == q) return NULL; | ||
946 | io->win[i].len += *p << (j*8); | ||
947 | } | ||
948 | } | ||
949 | return p; | ||
950 | } | ||
951 | |||
952 | /*====================================================================*/ | ||
953 | |||
954 | static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) | ||
955 | { | ||
956 | int i, j, asz, lsz, has_ha; | ||
957 | u_int len, ca, ha; | ||
958 | |||
959 | if (p == q) return NULL; | ||
960 | |||
961 | mem->nwin = (*p & 0x07) + 1; | ||
962 | lsz = (*p & 0x18) >> 3; | ||
963 | asz = (*p & 0x60) >> 5; | ||
964 | has_ha = (*p & 0x80); | ||
965 | if (++p == q) return NULL; | ||
966 | |||
967 | for (i = 0; i < mem->nwin; i++) { | ||
968 | len = ca = ha = 0; | ||
969 | for (j = 0; j < lsz; j++, p++) { | ||
970 | if (p == q) return NULL; | ||
971 | len += *p << (j*8); | ||
972 | } | ||
973 | for (j = 0; j < asz; j++, p++) { | ||
974 | if (p == q) return NULL; | ||
975 | ca += *p << (j*8); | ||
976 | } | ||
977 | if (has_ha) | ||
978 | for (j = 0; j < asz; j++, p++) { | ||
979 | if (p == q) return NULL; | ||
980 | ha += *p << (j*8); | ||
981 | } | ||
982 | mem->win[i].len = len << 8; | ||
983 | mem->win[i].card_addr = ca << 8; | ||
984 | mem->win[i].host_addr = ha << 8; | ||
985 | } | ||
986 | return p; | ||
987 | } | ||
988 | |||
989 | /*====================================================================*/ | ||
990 | |||
991 | static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) | ||
992 | { | ||
993 | if (p == q) return NULL; | ||
994 | irq->IRQInfo1 = *p; p++; | ||
995 | if (irq->IRQInfo1 & IRQ_INFO2_VALID) { | ||
996 | if (p+2 > q) return NULL; | ||
997 | irq->IRQInfo2 = (p[1]<<8) + p[0]; | ||
998 | p += 2; | ||
999 | } | ||
1000 | return p; | ||
1001 | } | ||
1002 | |||
1003 | /*====================================================================*/ | ||
1004 | |||
1005 | static int parse_cftable_entry(tuple_t *tuple, | ||
1006 | cistpl_cftable_entry_t *entry) | ||
1007 | { | ||
1008 | u_char *p, *q, features; | ||
1009 | |||
1010 | p = tuple->TupleData; | ||
1011 | q = p + tuple->TupleDataLen; | ||
1012 | entry->index = *p & 0x3f; | ||
1013 | entry->flags = 0; | ||
1014 | if (*p & 0x40) | ||
1015 | entry->flags |= CISTPL_CFTABLE_DEFAULT; | ||
1016 | if (*p & 0x80) { | ||
1017 | if (++p == q) return CS_BAD_TUPLE; | ||
1018 | if (*p & 0x10) | ||
1019 | entry->flags |= CISTPL_CFTABLE_BVDS; | ||
1020 | if (*p & 0x20) | ||
1021 | entry->flags |= CISTPL_CFTABLE_WP; | ||
1022 | if (*p & 0x40) | ||
1023 | entry->flags |= CISTPL_CFTABLE_RDYBSY; | ||
1024 | if (*p & 0x80) | ||
1025 | entry->flags |= CISTPL_CFTABLE_MWAIT; | ||
1026 | entry->interface = *p & 0x0f; | ||
1027 | } else | ||
1028 | entry->interface = 0; | ||
1029 | |||
1030 | /* Process optional features */ | ||
1031 | if (++p == q) return CS_BAD_TUPLE; | ||
1032 | features = *p; p++; | ||
1033 | |||
1034 | /* Power options */ | ||
1035 | if ((features & 3) > 0) { | ||
1036 | p = parse_power(p, q, &entry->vcc); | ||
1037 | if (p == NULL) return CS_BAD_TUPLE; | ||
1038 | } else | ||
1039 | entry->vcc.present = 0; | ||
1040 | if ((features & 3) > 1) { | ||
1041 | p = parse_power(p, q, &entry->vpp1); | ||
1042 | if (p == NULL) return CS_BAD_TUPLE; | ||
1043 | } else | ||
1044 | entry->vpp1.present = 0; | ||
1045 | if ((features & 3) > 2) { | ||
1046 | p = parse_power(p, q, &entry->vpp2); | ||
1047 | if (p == NULL) return CS_BAD_TUPLE; | ||
1048 | } else | ||
1049 | entry->vpp2.present = 0; | ||
1050 | |||
1051 | /* Timing options */ | ||
1052 | if (features & 0x04) { | ||
1053 | p = parse_timing(p, q, &entry->timing); | ||
1054 | if (p == NULL) return CS_BAD_TUPLE; | ||
1055 | } else { | ||
1056 | entry->timing.wait = 0; | ||
1057 | entry->timing.ready = 0; | ||
1058 | entry->timing.reserved = 0; | ||
1059 | } | ||
1060 | |||
1061 | /* I/O window options */ | ||
1062 | if (features & 0x08) { | ||
1063 | p = parse_io(p, q, &entry->io); | ||
1064 | if (p == NULL) return CS_BAD_TUPLE; | ||
1065 | } else | ||
1066 | entry->io.nwin = 0; | ||
1067 | |||
1068 | /* Interrupt options */ | ||
1069 | if (features & 0x10) { | ||
1070 | p = parse_irq(p, q, &entry->irq); | ||
1071 | if (p == NULL) return CS_BAD_TUPLE; | ||
1072 | } else | ||
1073 | entry->irq.IRQInfo1 = 0; | ||
1074 | |||
1075 | switch (features & 0x60) { | ||
1076 | case 0x00: | ||
1077 | entry->mem.nwin = 0; | ||
1078 | break; | ||
1079 | case 0x20: | ||
1080 | entry->mem.nwin = 1; | ||
1081 | entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; | ||
1082 | entry->mem.win[0].card_addr = 0; | ||
1083 | entry->mem.win[0].host_addr = 0; | ||
1084 | p += 2; | ||
1085 | if (p > q) return CS_BAD_TUPLE; | ||
1086 | break; | ||
1087 | case 0x40: | ||
1088 | entry->mem.nwin = 1; | ||
1089 | entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; | ||
1090 | entry->mem.win[0].card_addr = | ||
1091 | le16_to_cpu(*(u_short *)(p+2)) << 8; | ||
1092 | entry->mem.win[0].host_addr = 0; | ||
1093 | p += 4; | ||
1094 | if (p > q) return CS_BAD_TUPLE; | ||
1095 | break; | ||
1096 | case 0x60: | ||
1097 | p = parse_mem(p, q, &entry->mem); | ||
1098 | if (p == NULL) return CS_BAD_TUPLE; | ||
1099 | break; | ||
1100 | } | ||
1101 | |||
1102 | /* Misc features */ | ||
1103 | if (features & 0x80) { | ||
1104 | if (p == q) return CS_BAD_TUPLE; | ||
1105 | entry->flags |= (*p << 8); | ||
1106 | while (*p & 0x80) | ||
1107 | if (++p == q) return CS_BAD_TUPLE; | ||
1108 | p++; | ||
1109 | } | ||
1110 | |||
1111 | entry->subtuples = q-p; | ||
1112 | |||
1113 | return CS_SUCCESS; | ||
1114 | } | ||
1115 | |||
1116 | /*====================================================================*/ | ||
1117 | |||
1118 | #ifdef CONFIG_CARDBUS | ||
1119 | |||
1120 | static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) | ||
1121 | { | ||
1122 | u_char *p; | ||
1123 | if (tuple->TupleDataLen < 6) | ||
1124 | return CS_BAD_TUPLE; | ||
1125 | p = (u_char *)tuple->TupleData; | ||
1126 | bar->attr = *p; | ||
1127 | p += 2; | ||
1128 | bar->size = le32_to_cpu(*(u_int *)p); | ||
1129 | return CS_SUCCESS; | ||
1130 | } | ||
1131 | |||
1132 | static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) | ||
1133 | { | ||
1134 | u_char *p; | ||
1135 | |||
1136 | p = (u_char *)tuple->TupleData; | ||
1137 | if ((*p != 3) || (tuple->TupleDataLen < 6)) | ||
1138 | return CS_BAD_TUPLE; | ||
1139 | config->last_idx = *(++p); | ||
1140 | p++; | ||
1141 | config->base = le32_to_cpu(*(u_int *)p); | ||
1142 | config->subtuples = tuple->TupleDataLen - 6; | ||
1143 | return CS_SUCCESS; | ||
1144 | } | ||
1145 | |||
1146 | static int parse_cftable_entry_cb(tuple_t *tuple, | ||
1147 | cistpl_cftable_entry_cb_t *entry) | ||
1148 | { | ||
1149 | u_char *p, *q, features; | ||
1150 | |||
1151 | p = tuple->TupleData; | ||
1152 | q = p + tuple->TupleDataLen; | ||
1153 | entry->index = *p & 0x3f; | ||
1154 | entry->flags = 0; | ||
1155 | if (*p & 0x40) | ||
1156 | entry->flags |= CISTPL_CFTABLE_DEFAULT; | ||
1157 | |||
1158 | /* Process optional features */ | ||
1159 | if (++p == q) return CS_BAD_TUPLE; | ||
1160 | features = *p; p++; | ||
1161 | |||
1162 | /* Power options */ | ||
1163 | if ((features & 3) > 0) { | ||
1164 | p = parse_power(p, q, &entry->vcc); | ||
1165 | if (p == NULL) return CS_BAD_TUPLE; | ||
1166 | } else | ||
1167 | entry->vcc.present = 0; | ||
1168 | if ((features & 3) > 1) { | ||
1169 | p = parse_power(p, q, &entry->vpp1); | ||
1170 | if (p == NULL) return CS_BAD_TUPLE; | ||
1171 | } else | ||
1172 | entry->vpp1.present = 0; | ||
1173 | if ((features & 3) > 2) { | ||
1174 | p = parse_power(p, q, &entry->vpp2); | ||
1175 | if (p == NULL) return CS_BAD_TUPLE; | ||
1176 | } else | ||
1177 | entry->vpp2.present = 0; | ||
1178 | |||
1179 | /* I/O window options */ | ||
1180 | if (features & 0x08) { | ||
1181 | if (p == q) return CS_BAD_TUPLE; | ||
1182 | entry->io = *p; p++; | ||
1183 | } else | ||
1184 | entry->io = 0; | ||
1185 | |||
1186 | /* Interrupt options */ | ||
1187 | if (features & 0x10) { | ||
1188 | p = parse_irq(p, q, &entry->irq); | ||
1189 | if (p == NULL) return CS_BAD_TUPLE; | ||
1190 | } else | ||
1191 | entry->irq.IRQInfo1 = 0; | ||
1192 | |||
1193 | if (features & 0x20) { | ||
1194 | if (p == q) return CS_BAD_TUPLE; | ||
1195 | entry->mem = *p; p++; | ||
1196 | } else | ||
1197 | entry->mem = 0; | ||
1198 | |||
1199 | /* Misc features */ | ||
1200 | if (features & 0x80) { | ||
1201 | if (p == q) return CS_BAD_TUPLE; | ||
1202 | entry->flags |= (*p << 8); | ||
1203 | if (*p & 0x80) { | ||
1204 | if (++p == q) return CS_BAD_TUPLE; | ||
1205 | entry->flags |= (*p << 16); | ||
1206 | } | ||
1207 | while (*p & 0x80) | ||
1208 | if (++p == q) return CS_BAD_TUPLE; | ||
1209 | p++; | ||
1210 | } | ||
1211 | |||
1212 | entry->subtuples = q-p; | ||
1213 | |||
1214 | return CS_SUCCESS; | ||
1215 | } | ||
1216 | |||
1217 | #endif | ||
1218 | |||
1219 | /*====================================================================*/ | ||
1220 | |||
1221 | static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) | ||
1222 | { | ||
1223 | u_char *p, *q; | ||
1224 | int n; | ||
1225 | |||
1226 | p = (u_char *)tuple->TupleData; | ||
1227 | q = p + tuple->TupleDataLen; | ||
1228 | |||
1229 | for (n = 0; n < CISTPL_MAX_DEVICES; n++) { | ||
1230 | if (p > q-6) break; | ||
1231 | geo->geo[n].buswidth = p[0]; | ||
1232 | geo->geo[n].erase_block = 1 << (p[1]-1); | ||
1233 | geo->geo[n].read_block = 1 << (p[2]-1); | ||
1234 | geo->geo[n].write_block = 1 << (p[3]-1); | ||
1235 | geo->geo[n].partition = 1 << (p[4]-1); | ||
1236 | geo->geo[n].interleave = 1 << (p[5]-1); | ||
1237 | p += 6; | ||
1238 | } | ||
1239 | geo->ngeo = n; | ||
1240 | return CS_SUCCESS; | ||
1241 | } | ||
1242 | |||
1243 | /*====================================================================*/ | ||
1244 | |||
1245 | static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) | ||
1246 | { | ||
1247 | u_char *p, *q; | ||
1248 | |||
1249 | if (tuple->TupleDataLen < 10) | ||
1250 | return CS_BAD_TUPLE; | ||
1251 | |||
1252 | p = tuple->TupleData; | ||
1253 | q = p + tuple->TupleDataLen; | ||
1254 | |||
1255 | v2->vers = p[0]; | ||
1256 | v2->comply = p[1]; | ||
1257 | v2->dindex = le16_to_cpu(*(u_short *)(p+2)); | ||
1258 | v2->vspec8 = p[6]; | ||
1259 | v2->vspec9 = p[7]; | ||
1260 | v2->nhdr = p[8]; | ||
1261 | p += 9; | ||
1262 | return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); | ||
1263 | } | ||
1264 | |||
1265 | /*====================================================================*/ | ||
1266 | |||
1267 | static int parse_org(tuple_t *tuple, cistpl_org_t *org) | ||
1268 | { | ||
1269 | u_char *p, *q; | ||
1270 | int i; | ||
1271 | |||
1272 | p = tuple->TupleData; | ||
1273 | q = p + tuple->TupleDataLen; | ||
1274 | if (p == q) return CS_BAD_TUPLE; | ||
1275 | org->data_org = *p; | ||
1276 | if (++p == q) return CS_BAD_TUPLE; | ||
1277 | for (i = 0; i < 30; i++) { | ||
1278 | org->desc[i] = *p; | ||
1279 | if (*p == '\0') break; | ||
1280 | if (++p == q) return CS_BAD_TUPLE; | ||
1281 | } | ||
1282 | return CS_SUCCESS; | ||
1283 | } | ||
1284 | |||
1285 | /*====================================================================*/ | ||
1286 | |||
1287 | static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) | ||
1288 | { | ||
1289 | u_char *p; | ||
1290 | |||
1291 | if (tuple->TupleDataLen < 10) | ||
1292 | return CS_BAD_TUPLE; | ||
1293 | |||
1294 | p = tuple->TupleData; | ||
1295 | |||
1296 | fmt->type = p[0]; | ||
1297 | fmt->edc = p[1]; | ||
1298 | fmt->offset = le32_to_cpu(*(u_int *)(p+2)); | ||
1299 | fmt->length = le32_to_cpu(*(u_int *)(p+6)); | ||
1300 | |||
1301 | return CS_SUCCESS; | ||
1302 | } | ||
1303 | |||
1304 | /*====================================================================*/ | ||
1305 | |||
1306 | int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse) | ||
1307 | { | ||
1308 | int ret = CS_SUCCESS; | ||
1309 | |||
1310 | if (tuple->TupleDataLen > tuple->TupleDataMax) | ||
1311 | return CS_BAD_TUPLE; | ||
1312 | switch (tuple->TupleCode) { | ||
1313 | case CISTPL_DEVICE: | ||
1314 | case CISTPL_DEVICE_A: | ||
1315 | ret = parse_device(tuple, &parse->device); | ||
1316 | break; | ||
1317 | #ifdef CONFIG_CARDBUS | ||
1318 | case CISTPL_BAR: | ||
1319 | ret = parse_bar(tuple, &parse->bar); | ||
1320 | break; | ||
1321 | case CISTPL_CONFIG_CB: | ||
1322 | ret = parse_config_cb(tuple, &parse->config); | ||
1323 | break; | ||
1324 | case CISTPL_CFTABLE_ENTRY_CB: | ||
1325 | ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); | ||
1326 | break; | ||
1327 | #endif | ||
1328 | case CISTPL_CHECKSUM: | ||
1329 | ret = parse_checksum(tuple, &parse->checksum); | ||
1330 | break; | ||
1331 | case CISTPL_LONGLINK_A: | ||
1332 | case CISTPL_LONGLINK_C: | ||
1333 | ret = parse_longlink(tuple, &parse->longlink); | ||
1334 | break; | ||
1335 | case CISTPL_LONGLINK_MFC: | ||
1336 | ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); | ||
1337 | break; | ||
1338 | case CISTPL_VERS_1: | ||
1339 | ret = parse_vers_1(tuple, &parse->version_1); | ||
1340 | break; | ||
1341 | case CISTPL_ALTSTR: | ||
1342 | ret = parse_altstr(tuple, &parse->altstr); | ||
1343 | break; | ||
1344 | case CISTPL_JEDEC_A: | ||
1345 | case CISTPL_JEDEC_C: | ||
1346 | ret = parse_jedec(tuple, &parse->jedec); | ||
1347 | break; | ||
1348 | case CISTPL_MANFID: | ||
1349 | ret = parse_manfid(tuple, &parse->manfid); | ||
1350 | break; | ||
1351 | case CISTPL_FUNCID: | ||
1352 | ret = parse_funcid(tuple, &parse->funcid); | ||
1353 | break; | ||
1354 | case CISTPL_FUNCE: | ||
1355 | ret = parse_funce(tuple, &parse->funce); | ||
1356 | break; | ||
1357 | case CISTPL_CONFIG: | ||
1358 | ret = parse_config(tuple, &parse->config); | ||
1359 | break; | ||
1360 | case CISTPL_CFTABLE_ENTRY: | ||
1361 | ret = parse_cftable_entry(tuple, &parse->cftable_entry); | ||
1362 | break; | ||
1363 | case CISTPL_DEVICE_GEO: | ||
1364 | case CISTPL_DEVICE_GEO_A: | ||
1365 | ret = parse_device_geo(tuple, &parse->device_geo); | ||
1366 | break; | ||
1367 | case CISTPL_VERS_2: | ||
1368 | ret = parse_vers_2(tuple, &parse->vers_2); | ||
1369 | break; | ||
1370 | case CISTPL_ORG: | ||
1371 | ret = parse_org(tuple, &parse->org); | ||
1372 | break; | ||
1373 | case CISTPL_FORMAT: | ||
1374 | case CISTPL_FORMAT_A: | ||
1375 | ret = parse_format(tuple, &parse->format); | ||
1376 | break; | ||
1377 | case CISTPL_NO_LINK: | ||
1378 | case CISTPL_LINKTARGET: | ||
1379 | ret = CS_SUCCESS; | ||
1380 | break; | ||
1381 | default: | ||
1382 | ret = CS_UNSUPPORTED_FUNCTION; | ||
1383 | break; | ||
1384 | } | ||
1385 | return ret; | ||
1386 | } | ||
1387 | EXPORT_SYMBOL(pccard_parse_tuple); | ||
1388 | |||
1389 | /*====================================================================== | ||
1390 | |||
1391 | This is used internally by Card Services to look up CIS stuff. | ||
1392 | |||
1393 | ======================================================================*/ | ||
1394 | |||
1395 | int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse) | ||
1396 | { | ||
1397 | tuple_t tuple; | ||
1398 | cisdata_t *buf; | ||
1399 | int ret; | ||
1400 | |||
1401 | buf = kmalloc(256, GFP_KERNEL); | ||
1402 | if (buf == NULL) | ||
1403 | return CS_OUT_OF_RESOURCE; | ||
1404 | tuple.DesiredTuple = code; | ||
1405 | tuple.Attributes = TUPLE_RETURN_COMMON; | ||
1406 | ret = pccard_get_first_tuple(s, function, &tuple); | ||
1407 | if (ret != CS_SUCCESS) goto done; | ||
1408 | tuple.TupleData = buf; | ||
1409 | tuple.TupleOffset = 0; | ||
1410 | tuple.TupleDataMax = 255; | ||
1411 | ret = pccard_get_tuple_data(s, &tuple); | ||
1412 | if (ret != CS_SUCCESS) goto done; | ||
1413 | ret = pccard_parse_tuple(&tuple, parse); | ||
1414 | done: | ||
1415 | kfree(buf); | ||
1416 | return ret; | ||
1417 | } | ||
1418 | EXPORT_SYMBOL(pccard_read_tuple); | ||
1419 | |||
1420 | /*====================================================================== | ||
1421 | |||
1422 | This tries to determine if a card has a sensible CIS. It returns | ||
1423 | the number of tuples in the CIS, or 0 if the CIS looks bad. The | ||
1424 | checks include making sure several critical tuples are present and | ||
1425 | valid; seeing if the total number of tuples is reasonable; and | ||
1426 | looking for tuples that use reserved codes. | ||
1427 | |||
1428 | ======================================================================*/ | ||
1429 | |||
1430 | int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info) | ||
1431 | { | ||
1432 | tuple_t *tuple; | ||
1433 | cisparse_t *p; | ||
1434 | int ret, reserved, dev_ok = 0, ident_ok = 0; | ||
1435 | |||
1436 | if (!s) | ||
1437 | return CS_BAD_HANDLE; | ||
1438 | |||
1439 | tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); | ||
1440 | if (tuple == NULL) | ||
1441 | return CS_OUT_OF_RESOURCE; | ||
1442 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
1443 | if (p == NULL) { | ||
1444 | kfree(tuple); | ||
1445 | return CS_OUT_OF_RESOURCE; | ||
1446 | } | ||
1447 | |||
1448 | info->Chains = reserved = 0; | ||
1449 | tuple->DesiredTuple = RETURN_FIRST_TUPLE; | ||
1450 | tuple->Attributes = TUPLE_RETURN_COMMON; | ||
1451 | ret = pccard_get_first_tuple(s, function, tuple); | ||
1452 | if (ret != CS_SUCCESS) | ||
1453 | goto done; | ||
1454 | |||
1455 | /* First tuple should be DEVICE; we should really have either that | ||
1456 | or a CFTABLE_ENTRY of some sort */ | ||
1457 | if ((tuple->TupleCode == CISTPL_DEVICE) || | ||
1458 | (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) || | ||
1459 | (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS)) | ||
1460 | dev_ok++; | ||
1461 | |||
1462 | /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 | ||
1463 | tuple, for card identification. Certain old D-Link and Linksys | ||
1464 | cards have only a broken VERS_2 tuple; hence the bogus test. */ | ||
1465 | if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == CS_SUCCESS) || | ||
1466 | (pccard_read_tuple(s, function, CISTPL_VERS_1, p) == CS_SUCCESS) || | ||
1467 | (pccard_read_tuple(s, function, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS)) | ||
1468 | ident_ok++; | ||
1469 | |||
1470 | if (!dev_ok && !ident_ok) | ||
1471 | goto done; | ||
1472 | |||
1473 | for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { | ||
1474 | ret = pccard_get_next_tuple(s, function, tuple); | ||
1475 | if (ret != CS_SUCCESS) break; | ||
1476 | if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || | ||
1477 | ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || | ||
1478 | ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) | ||
1479 | reserved++; | ||
1480 | } | ||
1481 | if ((info->Chains == MAX_TUPLES) || (reserved > 5) || | ||
1482 | ((!dev_ok || !ident_ok) && (info->Chains > 10))) | ||
1483 | info->Chains = 0; | ||
1484 | |||
1485 | done: | ||
1486 | kfree(tuple); | ||
1487 | kfree(p); | ||
1488 | return CS_SUCCESS; | ||
1489 | } | ||
1490 | EXPORT_SYMBOL(pccard_validate_cis); | ||
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c new file mode 100644 index 000000000000..03fc885db1c5 --- /dev/null +++ b/drivers/pcmcia/cs.c | |||
@@ -0,0 +1,1917 @@ | |||
1 | /* | ||
2 | * cs.c -- Kernel Card Services - core services | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/config.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/timer.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/pm.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/irq.h> | ||
34 | |||
35 | #define IN_CARD_SERVICES | ||
36 | #include <pcmcia/version.h> | ||
37 | #include <pcmcia/cs_types.h> | ||
38 | #include <pcmcia/ss.h> | ||
39 | #include <pcmcia/cs.h> | ||
40 | #include <pcmcia/bulkmem.h> | ||
41 | #include <pcmcia/cistpl.h> | ||
42 | #include <pcmcia/cisreg.h> | ||
43 | #include <pcmcia/ds.h> | ||
44 | #include "cs_internal.h" | ||
45 | |||
46 | #ifdef CONFIG_PCI | ||
47 | #define PCI_OPT " [pci]" | ||
48 | #else | ||
49 | #define PCI_OPT "" | ||
50 | #endif | ||
51 | #ifdef CONFIG_CARDBUS | ||
52 | #define CB_OPT " [cardbus]" | ||
53 | #else | ||
54 | #define CB_OPT "" | ||
55 | #endif | ||
56 | #ifdef CONFIG_PM | ||
57 | #define PM_OPT " [pm]" | ||
58 | #else | ||
59 | #define PM_OPT "" | ||
60 | #endif | ||
61 | #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM) | ||
62 | #define OPTIONS " none" | ||
63 | #else | ||
64 | #define OPTIONS PCI_OPT CB_OPT PM_OPT | ||
65 | #endif | ||
66 | |||
67 | static const char *release = "Linux Kernel Card Services"; | ||
68 | static const char *options = "options: " OPTIONS; | ||
69 | |||
70 | /*====================================================================*/ | ||
71 | |||
72 | /* Module parameters */ | ||
73 | |||
74 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | ||
75 | MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS); | ||
76 | MODULE_LICENSE("GPL"); | ||
77 | |||
78 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) | ||
79 | |||
80 | INT_MODULE_PARM(setup_delay, 10); /* centiseconds */ | ||
81 | INT_MODULE_PARM(resume_delay, 20); /* centiseconds */ | ||
82 | INT_MODULE_PARM(shutdown_delay, 3); /* centiseconds */ | ||
83 | INT_MODULE_PARM(vcc_settle, 40); /* centiseconds */ | ||
84 | INT_MODULE_PARM(reset_time, 10); /* usecs */ | ||
85 | INT_MODULE_PARM(unreset_delay, 10); /* centiseconds */ | ||
86 | INT_MODULE_PARM(unreset_check, 10); /* centiseconds */ | ||
87 | INT_MODULE_PARM(unreset_limit, 30); /* unreset_check's */ | ||
88 | |||
89 | /* Access speed for attribute memory windows */ | ||
90 | INT_MODULE_PARM(cis_speed, 300); /* ns */ | ||
91 | |||
92 | /* Access speed for IO windows */ | ||
93 | INT_MODULE_PARM(io_speed, 0); /* ns */ | ||
94 | |||
95 | #ifdef DEBUG | ||
96 | static int pc_debug; | ||
97 | |||
98 | module_param(pc_debug, int, 0644); | ||
99 | |||
100 | int cs_debug_level(int level) | ||
101 | { | ||
102 | return pc_debug > level; | ||
103 | } | ||
104 | #endif | ||
105 | |||
106 | /*====================================================================*/ | ||
107 | |||
108 | socket_state_t dead_socket = { | ||
109 | .csc_mask = SS_DETECT, | ||
110 | }; | ||
111 | |||
112 | |||
113 | /* List of all sockets, protected by a rwsem */ | ||
114 | LIST_HEAD(pcmcia_socket_list); | ||
115 | DECLARE_RWSEM(pcmcia_socket_list_rwsem); | ||
116 | EXPORT_SYMBOL(pcmcia_socket_list); | ||
117 | EXPORT_SYMBOL(pcmcia_socket_list_rwsem); | ||
118 | |||
119 | |||
120 | #ifdef CONFIG_PCMCIA_PROBE | ||
121 | /* mask ofIRQs already reserved by other cards, we should avoid using them */ | ||
122 | static u8 pcmcia_used_irq[NR_IRQS]; | ||
123 | #endif | ||
124 | |||
125 | /*==================================================================== | ||
126 | |||
127 | Low-level PC Card interface drivers need to register with Card | ||
128 | Services using these calls. | ||
129 | |||
130 | ======================================================================*/ | ||
131 | |||
132 | /** | ||
133 | * socket drivers are expected to use the following callbacks in their | ||
134 | * .drv struct: | ||
135 | * - pcmcia_socket_dev_suspend | ||
136 | * - pcmcia_socket_dev_resume | ||
137 | * These functions check for the appropriate struct pcmcia_soket arrays, | ||
138 | * and pass them to the low-level functions pcmcia_{suspend,resume}_socket | ||
139 | */ | ||
140 | static int socket_resume(struct pcmcia_socket *skt); | ||
141 | static int socket_suspend(struct pcmcia_socket *skt); | ||
142 | |||
143 | int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state) | ||
144 | { | ||
145 | struct pcmcia_socket *socket; | ||
146 | |||
147 | down_read(&pcmcia_socket_list_rwsem); | ||
148 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { | ||
149 | if (socket->dev.dev != dev) | ||
150 | continue; | ||
151 | down(&socket->skt_sem); | ||
152 | socket_suspend(socket); | ||
153 | up(&socket->skt_sem); | ||
154 | } | ||
155 | up_read(&pcmcia_socket_list_rwsem); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | EXPORT_SYMBOL(pcmcia_socket_dev_suspend); | ||
160 | |||
161 | int pcmcia_socket_dev_resume(struct device *dev) | ||
162 | { | ||
163 | struct pcmcia_socket *socket; | ||
164 | |||
165 | down_read(&pcmcia_socket_list_rwsem); | ||
166 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { | ||
167 | if (socket->dev.dev != dev) | ||
168 | continue; | ||
169 | down(&socket->skt_sem); | ||
170 | socket_resume(socket); | ||
171 | up(&socket->skt_sem); | ||
172 | } | ||
173 | up_read(&pcmcia_socket_list_rwsem); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | EXPORT_SYMBOL(pcmcia_socket_dev_resume); | ||
178 | |||
179 | |||
180 | struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt) | ||
181 | { | ||
182 | struct class_device *cl_dev = class_device_get(&skt->dev); | ||
183 | if (!cl_dev) | ||
184 | return NULL; | ||
185 | skt = class_get_devdata(cl_dev); | ||
186 | if (!try_module_get(skt->owner)) { | ||
187 | class_device_put(&skt->dev); | ||
188 | return NULL; | ||
189 | } | ||
190 | return (skt); | ||
191 | } | ||
192 | EXPORT_SYMBOL(pcmcia_get_socket); | ||
193 | |||
194 | |||
195 | void pcmcia_put_socket(struct pcmcia_socket *skt) | ||
196 | { | ||
197 | module_put(skt->owner); | ||
198 | class_device_put(&skt->dev); | ||
199 | } | ||
200 | EXPORT_SYMBOL(pcmcia_put_socket); | ||
201 | |||
202 | |||
203 | static void pcmcia_release_socket(struct class_device *class_dev) | ||
204 | { | ||
205 | struct pcmcia_socket *socket = class_get_devdata(class_dev); | ||
206 | |||
207 | complete(&socket->socket_released); | ||
208 | } | ||
209 | |||
210 | static int pccardd(void *__skt); | ||
211 | |||
212 | /** | ||
213 | * pcmcia_register_socket - add a new pcmcia socket device | ||
214 | */ | ||
215 | int pcmcia_register_socket(struct pcmcia_socket *socket) | ||
216 | { | ||
217 | int ret; | ||
218 | |||
219 | if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) | ||
220 | return -EINVAL; | ||
221 | |||
222 | cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); | ||
223 | |||
224 | spin_lock_init(&socket->lock); | ||
225 | |||
226 | if (socket->resource_ops->init) { | ||
227 | ret = socket->resource_ops->init(socket); | ||
228 | if (ret) | ||
229 | return (ret); | ||
230 | } | ||
231 | |||
232 | /* try to obtain a socket number [yes, it gets ugly if we | ||
233 | * register more than 2^sizeof(unsigned int) pcmcia | ||
234 | * sockets... but the socket number is deprecated | ||
235 | * anyways, so I don't care] */ | ||
236 | down_write(&pcmcia_socket_list_rwsem); | ||
237 | if (list_empty(&pcmcia_socket_list)) | ||
238 | socket->sock = 0; | ||
239 | else { | ||
240 | unsigned int found, i = 1; | ||
241 | struct pcmcia_socket *tmp; | ||
242 | do { | ||
243 | found = 1; | ||
244 | list_for_each_entry(tmp, &pcmcia_socket_list, socket_list) { | ||
245 | if (tmp->sock == i) | ||
246 | found = 0; | ||
247 | } | ||
248 | i++; | ||
249 | } while (!found); | ||
250 | socket->sock = i - 1; | ||
251 | } | ||
252 | list_add_tail(&socket->socket_list, &pcmcia_socket_list); | ||
253 | up_write(&pcmcia_socket_list_rwsem); | ||
254 | |||
255 | |||
256 | /* set proper values in socket->dev */ | ||
257 | socket->dev.class_data = socket; | ||
258 | socket->dev.class = &pcmcia_socket_class; | ||
259 | snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); | ||
260 | |||
261 | /* base address = 0, map = 0 */ | ||
262 | socket->cis_mem.flags = 0; | ||
263 | socket->cis_mem.speed = cis_speed; | ||
264 | |||
265 | INIT_LIST_HEAD(&socket->cis_cache); | ||
266 | |||
267 | init_completion(&socket->socket_released); | ||
268 | init_completion(&socket->thread_done); | ||
269 | init_waitqueue_head(&socket->thread_wait); | ||
270 | init_MUTEX(&socket->skt_sem); | ||
271 | spin_lock_init(&socket->thread_lock); | ||
272 | |||
273 | ret = kernel_thread(pccardd, socket, CLONE_KERNEL); | ||
274 | if (ret < 0) | ||
275 | goto err; | ||
276 | |||
277 | wait_for_completion(&socket->thread_done); | ||
278 | if(!socket->thread) { | ||
279 | printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket); | ||
280 | return -EIO; | ||
281 | } | ||
282 | pcmcia_parse_events(socket, SS_DETECT); | ||
283 | |||
284 | return 0; | ||
285 | |||
286 | err: | ||
287 | down_write(&pcmcia_socket_list_rwsem); | ||
288 | list_del(&socket->socket_list); | ||
289 | up_write(&pcmcia_socket_list_rwsem); | ||
290 | return ret; | ||
291 | } /* pcmcia_register_socket */ | ||
292 | EXPORT_SYMBOL(pcmcia_register_socket); | ||
293 | |||
294 | |||
295 | /** | ||
296 | * pcmcia_unregister_socket - remove a pcmcia socket device | ||
297 | */ | ||
298 | void pcmcia_unregister_socket(struct pcmcia_socket *socket) | ||
299 | { | ||
300 | if (!socket) | ||
301 | return; | ||
302 | |||
303 | cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); | ||
304 | |||
305 | if (socket->thread) { | ||
306 | init_completion(&socket->thread_done); | ||
307 | socket->thread = NULL; | ||
308 | wake_up(&socket->thread_wait); | ||
309 | wait_for_completion(&socket->thread_done); | ||
310 | } | ||
311 | release_cis_mem(socket); | ||
312 | |||
313 | /* remove from our own list */ | ||
314 | down_write(&pcmcia_socket_list_rwsem); | ||
315 | list_del(&socket->socket_list); | ||
316 | up_write(&pcmcia_socket_list_rwsem); | ||
317 | |||
318 | /* wait for sysfs to drop all references */ | ||
319 | release_resource_db(socket); | ||
320 | wait_for_completion(&socket->socket_released); | ||
321 | } /* pcmcia_unregister_socket */ | ||
322 | EXPORT_SYMBOL(pcmcia_unregister_socket); | ||
323 | |||
324 | |||
325 | struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr) | ||
326 | { | ||
327 | struct pcmcia_socket *s; | ||
328 | |||
329 | down_read(&pcmcia_socket_list_rwsem); | ||
330 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) | ||
331 | if (s->sock == nr) { | ||
332 | up_read(&pcmcia_socket_list_rwsem); | ||
333 | return s; | ||
334 | } | ||
335 | up_read(&pcmcia_socket_list_rwsem); | ||
336 | |||
337 | return NULL; | ||
338 | |||
339 | } | ||
340 | EXPORT_SYMBOL(pcmcia_get_socket_by_nr); | ||
341 | |||
342 | |||
343 | /*====================================================================== | ||
344 | |||
345 | socket_setup() and shutdown_socket() are called by the main event | ||
346 | handler when card insertion and removal events are received. | ||
347 | socket_setup() turns on socket power and resets the socket, in two stages. | ||
348 | shutdown_socket() unconfigures a socket and turns off socket power. | ||
349 | |||
350 | ======================================================================*/ | ||
351 | |||
352 | static void shutdown_socket(struct pcmcia_socket *s) | ||
353 | { | ||
354 | cs_dbg(s, 1, "shutdown_socket\n"); | ||
355 | |||
356 | /* Blank out the socket state */ | ||
357 | s->socket = dead_socket; | ||
358 | s->ops->init(s); | ||
359 | s->ops->set_socket(s, &s->socket); | ||
360 | s->irq.AssignedIRQ = s->irq.Config = 0; | ||
361 | s->lock_count = 0; | ||
362 | destroy_cis_cache(s); | ||
363 | #ifdef CONFIG_CARDBUS | ||
364 | cb_free(s); | ||
365 | #endif | ||
366 | s->functions = 0; | ||
367 | if (s->config) { | ||
368 | kfree(s->config); | ||
369 | s->config = NULL; | ||
370 | } | ||
371 | |||
372 | { | ||
373 | int status; | ||
374 | s->ops->get_status(s, &status); | ||
375 | if (status & SS_POWERON) { | ||
376 | printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s); | ||
377 | } | ||
378 | } | ||
379 | } /* shutdown_socket */ | ||
380 | |||
381 | /*====================================================================== | ||
382 | |||
383 | The central event handler. Send_event() sends an event to the | ||
384 | 16-bit subsystem, which then calls the relevant device drivers. | ||
385 | Parse_events() interprets the event bits from | ||
386 | a card status change report. Do_shutdown() handles the high | ||
387 | priority stuff associated with a card removal. | ||
388 | |||
389 | ======================================================================*/ | ||
390 | |||
391 | |||
392 | /* NOTE: send_event needs to be called with skt->sem held. */ | ||
393 | |||
394 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | ||
395 | { | ||
396 | int ret; | ||
397 | |||
398 | if (s->state & SOCKET_CARDBUS) | ||
399 | return 0; | ||
400 | |||
401 | cs_dbg(s, 1, "send_event(event %d, pri %d, callback 0x%p)\n", | ||
402 | event, priority, s->callback); | ||
403 | |||
404 | if (!s->callback) | ||
405 | return 0; | ||
406 | if (!try_module_get(s->callback->owner)) | ||
407 | return 0; | ||
408 | |||
409 | ret = s->callback->event(s, event, priority); | ||
410 | |||
411 | module_put(s->callback->owner); | ||
412 | |||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | static void socket_remove_drivers(struct pcmcia_socket *skt) | ||
417 | { | ||
418 | cs_dbg(skt, 4, "remove_drivers\n"); | ||
419 | |||
420 | send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); | ||
421 | } | ||
422 | |||
423 | static void socket_shutdown(struct pcmcia_socket *skt) | ||
424 | { | ||
425 | cs_dbg(skt, 4, "shutdown\n"); | ||
426 | |||
427 | socket_remove_drivers(skt); | ||
428 | skt->state &= SOCKET_INUSE|SOCKET_PRESENT; | ||
429 | msleep(shutdown_delay * 10); | ||
430 | skt->state &= SOCKET_INUSE; | ||
431 | shutdown_socket(skt); | ||
432 | } | ||
433 | |||
434 | static int socket_reset(struct pcmcia_socket *skt) | ||
435 | { | ||
436 | int status, i; | ||
437 | |||
438 | cs_dbg(skt, 4, "reset\n"); | ||
439 | |||
440 | skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET; | ||
441 | skt->ops->set_socket(skt, &skt->socket); | ||
442 | udelay((long)reset_time); | ||
443 | |||
444 | skt->socket.flags &= ~SS_RESET; | ||
445 | skt->ops->set_socket(skt, &skt->socket); | ||
446 | |||
447 | msleep(unreset_delay * 10); | ||
448 | for (i = 0; i < unreset_limit; i++) { | ||
449 | skt->ops->get_status(skt, &status); | ||
450 | |||
451 | if (!(status & SS_DETECT)) | ||
452 | return CS_NO_CARD; | ||
453 | |||
454 | if (status & SS_READY) | ||
455 | return CS_SUCCESS; | ||
456 | |||
457 | msleep(unreset_check * 10); | ||
458 | } | ||
459 | |||
460 | cs_err(skt, "time out after reset.\n"); | ||
461 | return CS_GENERAL_FAILURE; | ||
462 | } | ||
463 | |||
464 | static int socket_setup(struct pcmcia_socket *skt, int initial_delay) | ||
465 | { | ||
466 | int status, i; | ||
467 | |||
468 | cs_dbg(skt, 4, "setup\n"); | ||
469 | |||
470 | skt->ops->get_status(skt, &status); | ||
471 | if (!(status & SS_DETECT)) | ||
472 | return CS_NO_CARD; | ||
473 | |||
474 | msleep(initial_delay * 10); | ||
475 | |||
476 | for (i = 0; i < 100; i++) { | ||
477 | skt->ops->get_status(skt, &status); | ||
478 | if (!(status & SS_DETECT)) | ||
479 | return CS_NO_CARD; | ||
480 | |||
481 | if (!(status & SS_PENDING)) | ||
482 | break; | ||
483 | |||
484 | msleep(100); | ||
485 | } | ||
486 | |||
487 | if (status & SS_PENDING) { | ||
488 | cs_err(skt, "voltage interrogation timed out.\n"); | ||
489 | return CS_GENERAL_FAILURE; | ||
490 | } | ||
491 | |||
492 | if (status & SS_CARDBUS) { | ||
493 | skt->state |= SOCKET_CARDBUS; | ||
494 | #ifndef CONFIG_CARDBUS | ||
495 | cs_err(skt, "cardbus cards are not supported.\n"); | ||
496 | return CS_BAD_TYPE; | ||
497 | #endif | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * Decode the card voltage requirements, and apply power to the card. | ||
502 | */ | ||
503 | if (status & SS_3VCARD) | ||
504 | skt->socket.Vcc = skt->socket.Vpp = 33; | ||
505 | else if (!(status & SS_XVCARD)) | ||
506 | skt->socket.Vcc = skt->socket.Vpp = 50; | ||
507 | else { | ||
508 | cs_err(skt, "unsupported voltage key.\n"); | ||
509 | return CS_BAD_TYPE; | ||
510 | } | ||
511 | skt->socket.flags = 0; | ||
512 | skt->ops->set_socket(skt, &skt->socket); | ||
513 | |||
514 | /* | ||
515 | * Wait "vcc_settle" for the supply to stabilise. | ||
516 | */ | ||
517 | msleep(vcc_settle * 10); | ||
518 | |||
519 | skt->ops->get_status(skt, &status); | ||
520 | if (!(status & SS_POWERON)) { | ||
521 | cs_err(skt, "unable to apply power.\n"); | ||
522 | return CS_BAD_TYPE; | ||
523 | } | ||
524 | |||
525 | return socket_reset(skt); | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Handle card insertion. Setup the socket, reset the card, | ||
530 | * and then tell the rest of PCMCIA that a card is present. | ||
531 | */ | ||
532 | static int socket_insert(struct pcmcia_socket *skt) | ||
533 | { | ||
534 | int ret; | ||
535 | |||
536 | cs_dbg(skt, 4, "insert\n"); | ||
537 | |||
538 | if (!cs_socket_get(skt)) | ||
539 | return CS_NO_CARD; | ||
540 | |||
541 | ret = socket_setup(skt, setup_delay); | ||
542 | if (ret == CS_SUCCESS) { | ||
543 | skt->state |= SOCKET_PRESENT; | ||
544 | #ifdef CONFIG_CARDBUS | ||
545 | if (skt->state & SOCKET_CARDBUS) { | ||
546 | cb_alloc(skt); | ||
547 | skt->state |= SOCKET_CARDBUS_CONFIG; | ||
548 | } | ||
549 | #endif | ||
550 | cs_dbg(skt, 4, "insert done\n"); | ||
551 | |||
552 | send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); | ||
553 | } else { | ||
554 | socket_shutdown(skt); | ||
555 | cs_socket_put(skt); | ||
556 | } | ||
557 | |||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | static int socket_suspend(struct pcmcia_socket *skt) | ||
562 | { | ||
563 | if (skt->state & SOCKET_SUSPEND) | ||
564 | return CS_IN_USE; | ||
565 | |||
566 | send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); | ||
567 | skt->socket = dead_socket; | ||
568 | skt->ops->set_socket(skt, &skt->socket); | ||
569 | if (skt->ops->suspend) | ||
570 | skt->ops->suspend(skt); | ||
571 | skt->state |= SOCKET_SUSPEND; | ||
572 | |||
573 | return CS_SUCCESS; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * Resume a socket. If a card is present, verify its CIS against | ||
578 | * our cached copy. If they are different, the card has been | ||
579 | * replaced, and we need to tell the drivers. | ||
580 | */ | ||
581 | static int socket_resume(struct pcmcia_socket *skt) | ||
582 | { | ||
583 | int ret; | ||
584 | |||
585 | if (!(skt->state & SOCKET_SUSPEND)) | ||
586 | return CS_IN_USE; | ||
587 | |||
588 | skt->socket = dead_socket; | ||
589 | skt->ops->init(skt); | ||
590 | skt->ops->set_socket(skt, &skt->socket); | ||
591 | |||
592 | if (!(skt->state & SOCKET_PRESENT)) { | ||
593 | skt->state &= ~SOCKET_SUSPEND; | ||
594 | return socket_insert(skt); | ||
595 | } | ||
596 | |||
597 | ret = socket_setup(skt, resume_delay); | ||
598 | if (ret == CS_SUCCESS) { | ||
599 | /* | ||
600 | * FIXME: need a better check here for cardbus cards. | ||
601 | */ | ||
602 | if (verify_cis_cache(skt) != 0) { | ||
603 | cs_dbg(skt, 4, "cis mismatch - different card\n"); | ||
604 | socket_remove_drivers(skt); | ||
605 | destroy_cis_cache(skt); | ||
606 | /* | ||
607 | * Workaround: give DS time to schedule removal. | ||
608 | * Remove me once the 100ms delay is eliminated | ||
609 | * in ds.c | ||
610 | */ | ||
611 | msleep(200); | ||
612 | send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); | ||
613 | } else { | ||
614 | cs_dbg(skt, 4, "cis matches cache\n"); | ||
615 | send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); | ||
616 | } | ||
617 | } else { | ||
618 | socket_shutdown(skt); | ||
619 | cs_socket_put(skt); | ||
620 | } | ||
621 | |||
622 | skt->state &= ~SOCKET_SUSPEND; | ||
623 | |||
624 | return CS_SUCCESS; | ||
625 | } | ||
626 | |||
627 | static void socket_remove(struct pcmcia_socket *skt) | ||
628 | { | ||
629 | socket_shutdown(skt); | ||
630 | cs_socket_put(skt); | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * Process a socket card detect status change. | ||
635 | * | ||
636 | * If we don't have a card already present, delay the detect event for | ||
637 | * about 20ms (to be on the safe side) before reading the socket status. | ||
638 | * | ||
639 | * Some i82365-based systems send multiple SS_DETECT events during card | ||
640 | * insertion, and the "card present" status bit seems to bounce. This | ||
641 | * will probably be true with GPIO-based card detection systems after | ||
642 | * the product has aged. | ||
643 | */ | ||
644 | static void socket_detect_change(struct pcmcia_socket *skt) | ||
645 | { | ||
646 | if (!(skt->state & SOCKET_SUSPEND)) { | ||
647 | int status; | ||
648 | |||
649 | if (!(skt->state & SOCKET_PRESENT)) | ||
650 | msleep(20); | ||
651 | |||
652 | skt->ops->get_status(skt, &status); | ||
653 | if ((skt->state & SOCKET_PRESENT) && | ||
654 | !(status & SS_DETECT)) | ||
655 | socket_remove(skt); | ||
656 | if (!(skt->state & SOCKET_PRESENT) && | ||
657 | (status & SS_DETECT)) | ||
658 | socket_insert(skt); | ||
659 | } | ||
660 | } | ||
661 | |||
662 | static int pccardd(void *__skt) | ||
663 | { | ||
664 | struct pcmcia_socket *skt = __skt; | ||
665 | DECLARE_WAITQUEUE(wait, current); | ||
666 | int ret; | ||
667 | |||
668 | daemonize("pccardd"); | ||
669 | |||
670 | skt->thread = current; | ||
671 | skt->socket = dead_socket; | ||
672 | skt->ops->init(skt); | ||
673 | skt->ops->set_socket(skt, &skt->socket); | ||
674 | |||
675 | /* register with the device core */ | ||
676 | ret = class_device_register(&skt->dev); | ||
677 | if (ret) { | ||
678 | printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", | ||
679 | skt); | ||
680 | skt->thread = NULL; | ||
681 | complete_and_exit(&skt->thread_done, 0); | ||
682 | } | ||
683 | complete(&skt->thread_done); | ||
684 | |||
685 | add_wait_queue(&skt->thread_wait, &wait); | ||
686 | for (;;) { | ||
687 | unsigned long flags; | ||
688 | unsigned int events; | ||
689 | |||
690 | set_current_state(TASK_INTERRUPTIBLE); | ||
691 | |||
692 | spin_lock_irqsave(&skt->thread_lock, flags); | ||
693 | events = skt->thread_events; | ||
694 | skt->thread_events = 0; | ||
695 | spin_unlock_irqrestore(&skt->thread_lock, flags); | ||
696 | |||
697 | if (events) { | ||
698 | down(&skt->skt_sem); | ||
699 | if (events & SS_DETECT) | ||
700 | socket_detect_change(skt); | ||
701 | if (events & SS_BATDEAD) | ||
702 | send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW); | ||
703 | if (events & SS_BATWARN) | ||
704 | send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW); | ||
705 | if (events & SS_READY) | ||
706 | send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW); | ||
707 | up(&skt->skt_sem); | ||
708 | continue; | ||
709 | } | ||
710 | |||
711 | schedule(); | ||
712 | try_to_freeze(PF_FREEZE); | ||
713 | |||
714 | if (!skt->thread) | ||
715 | break; | ||
716 | } | ||
717 | remove_wait_queue(&skt->thread_wait, &wait); | ||
718 | |||
719 | /* remove from the device core */ | ||
720 | class_device_unregister(&skt->dev); | ||
721 | |||
722 | complete_and_exit(&skt->thread_done, 0); | ||
723 | } | ||
724 | |||
725 | /* | ||
726 | * Yenta (at least) probes interrupts before registering the socket and | ||
727 | * starting the handler thread. | ||
728 | */ | ||
729 | void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) | ||
730 | { | ||
731 | cs_dbg(s, 4, "parse_events: events %08x\n", events); | ||
732 | if (s->thread) { | ||
733 | spin_lock(&s->thread_lock); | ||
734 | s->thread_events |= events; | ||
735 | spin_unlock(&s->thread_lock); | ||
736 | |||
737 | wake_up(&s->thread_wait); | ||
738 | } | ||
739 | } /* pcmcia_parse_events */ | ||
740 | |||
741 | |||
742 | /*====================================================================== | ||
743 | |||
744 | Special stuff for managing IO windows, because they are scarce. | ||
745 | |||
746 | ======================================================================*/ | ||
747 | |||
748 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, | ||
749 | ioaddr_t num, u_int lines) | ||
750 | { | ||
751 | int i; | ||
752 | kio_addr_t try, align; | ||
753 | |||
754 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | ||
755 | if (align && (align < num)) { | ||
756 | if (*base) { | ||
757 | cs_dbg(s, 0, "odd IO request: num %#x align %#lx\n", | ||
758 | num, align); | ||
759 | align = 0; | ||
760 | } else | ||
761 | while (align && (align < num)) align <<= 1; | ||
762 | } | ||
763 | if (*base & ~(align-1)) { | ||
764 | cs_dbg(s, 0, "odd IO request: base %#x align %#lx\n", | ||
765 | *base, align); | ||
766 | align = 0; | ||
767 | } | ||
768 | if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { | ||
769 | *base = s->io_offset | (*base & 0x0fff); | ||
770 | return 0; | ||
771 | } | ||
772 | /* Check for an already-allocated window that must conflict with | ||
773 | what was asked for. It is a hack because it does not catch all | ||
774 | potential conflicts, just the most obvious ones. */ | ||
775 | for (i = 0; i < MAX_IO_WIN; i++) | ||
776 | if ((s->io[i].NumPorts != 0) && | ||
777 | ((s->io[i].BasePort & (align-1)) == *base)) | ||
778 | return 1; | ||
779 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
780 | if (s->io[i].NumPorts == 0) { | ||
781 | s->io[i].res = find_io_region(*base, num, align, s); | ||
782 | if (s->io[i].res) { | ||
783 | s->io[i].Attributes = attr; | ||
784 | s->io[i].BasePort = *base = s->io[i].res->start; | ||
785 | s->io[i].NumPorts = s->io[i].InUse = num; | ||
786 | break; | ||
787 | } else | ||
788 | return 1; | ||
789 | } else if (s->io[i].Attributes != attr) | ||
790 | continue; | ||
791 | /* Try to extend top of window */ | ||
792 | try = s->io[i].BasePort + s->io[i].NumPorts; | ||
793 | if ((*base == 0) || (*base == try)) | ||
794 | if (adjust_io_region(s->io[i].res, s->io[i].res->start, | ||
795 | s->io[i].res->end + num, s) == 0) { | ||
796 | *base = try; | ||
797 | s->io[i].NumPorts += num; | ||
798 | s->io[i].InUse += num; | ||
799 | break; | ||
800 | } | ||
801 | /* Try to extend bottom of window */ | ||
802 | try = s->io[i].BasePort - num; | ||
803 | if ((*base == 0) || (*base == try)) | ||
804 | if (adjust_io_region(s->io[i].res, s->io[i].res->start - num, | ||
805 | s->io[i].res->end, s) == 0) { | ||
806 | s->io[i].BasePort = *base = try; | ||
807 | s->io[i].NumPorts += num; | ||
808 | s->io[i].InUse += num; | ||
809 | break; | ||
810 | } | ||
811 | } | ||
812 | return (i == MAX_IO_WIN); | ||
813 | } /* alloc_io_space */ | ||
814 | |||
815 | static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, | ||
816 | ioaddr_t num) | ||
817 | { | ||
818 | int i; | ||
819 | |||
820 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
821 | if ((s->io[i].BasePort <= base) && | ||
822 | (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { | ||
823 | s->io[i].InUse -= num; | ||
824 | /* Free the window if no one else is using it */ | ||
825 | if (s->io[i].InUse == 0) { | ||
826 | s->io[i].NumPorts = 0; | ||
827 | release_resource(s->io[i].res); | ||
828 | kfree(s->io[i].res); | ||
829 | s->io[i].res = NULL; | ||
830 | } | ||
831 | } | ||
832 | } | ||
833 | } | ||
834 | |||
835 | /*====================================================================== | ||
836 | |||
837 | Access_configuration_register() reads and writes configuration | ||
838 | registers in attribute memory. Memory window 0 is reserved for | ||
839 | this and the tuple reading services. | ||
840 | |||
841 | ======================================================================*/ | ||
842 | |||
843 | int pccard_access_configuration_register(struct pcmcia_socket *s, | ||
844 | unsigned int function, | ||
845 | conf_reg_t *reg) | ||
846 | { | ||
847 | config_t *c; | ||
848 | int addr; | ||
849 | u_char val; | ||
850 | |||
851 | if (!s || !s->config) | ||
852 | return CS_NO_CARD; | ||
853 | |||
854 | c = &s->config[function]; | ||
855 | |||
856 | if (c == NULL) | ||
857 | return CS_NO_CARD; | ||
858 | |||
859 | if (!(c->state & CONFIG_LOCKED)) | ||
860 | return CS_CONFIGURATION_LOCKED; | ||
861 | |||
862 | addr = (c->ConfigBase + reg->Offset) >> 1; | ||
863 | |||
864 | switch (reg->Action) { | ||
865 | case CS_READ: | ||
866 | read_cis_mem(s, 1, addr, 1, &val); | ||
867 | reg->Value = val; | ||
868 | break; | ||
869 | case CS_WRITE: | ||
870 | val = reg->Value; | ||
871 | write_cis_mem(s, 1, addr, 1, &val); | ||
872 | break; | ||
873 | default: | ||
874 | return CS_BAD_ARGS; | ||
875 | break; | ||
876 | } | ||
877 | return CS_SUCCESS; | ||
878 | } /* access_configuration_register */ | ||
879 | EXPORT_SYMBOL(pccard_access_configuration_register); | ||
880 | |||
881 | |||
882 | /*====================================================================*/ | ||
883 | |||
884 | int pccard_get_configuration_info(struct pcmcia_socket *s, | ||
885 | unsigned int function, | ||
886 | config_info_t *config) | ||
887 | { | ||
888 | config_t *c; | ||
889 | |||
890 | if (!(s->state & SOCKET_PRESENT)) | ||
891 | return CS_NO_CARD; | ||
892 | |||
893 | config->Function = function; | ||
894 | |||
895 | #ifdef CONFIG_CARDBUS | ||
896 | if (s->state & SOCKET_CARDBUS) { | ||
897 | memset(config, 0, sizeof(config_info_t)); | ||
898 | config->Vcc = s->socket.Vcc; | ||
899 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
900 | config->Option = s->cb_dev->subordinate->number; | ||
901 | if (s->state & SOCKET_CARDBUS_CONFIG) { | ||
902 | config->Attributes = CONF_VALID_CLIENT; | ||
903 | config->IntType = INT_CARDBUS; | ||
904 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
905 | if (config->AssignedIRQ) | ||
906 | config->Attributes |= CONF_ENABLE_IRQ; | ||
907 | config->BasePort1 = s->io[0].BasePort; | ||
908 | config->NumPorts1 = s->io[0].NumPorts; | ||
909 | } | ||
910 | return CS_SUCCESS; | ||
911 | } | ||
912 | #endif | ||
913 | |||
914 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
915 | |||
916 | if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { | ||
917 | config->Attributes = 0; | ||
918 | config->Vcc = s->socket.Vcc; | ||
919 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
920 | return CS_SUCCESS; | ||
921 | } | ||
922 | |||
923 | /* !!! This is a hack !!! */ | ||
924 | memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); | ||
925 | config->Attributes |= CONF_VALID_CLIENT; | ||
926 | config->CardValues = c->CardValues; | ||
927 | config->IRQAttributes = c->irq.Attributes; | ||
928 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
929 | config->BasePort1 = c->io.BasePort1; | ||
930 | config->NumPorts1 = c->io.NumPorts1; | ||
931 | config->Attributes1 = c->io.Attributes1; | ||
932 | config->BasePort2 = c->io.BasePort2; | ||
933 | config->NumPorts2 = c->io.NumPorts2; | ||
934 | config->Attributes2 = c->io.Attributes2; | ||
935 | config->IOAddrLines = c->io.IOAddrLines; | ||
936 | |||
937 | return CS_SUCCESS; | ||
938 | } /* get_configuration_info */ | ||
939 | EXPORT_SYMBOL(pccard_get_configuration_info); | ||
940 | |||
941 | /*====================================================================== | ||
942 | |||
943 | Return information about this version of Card Services. | ||
944 | |||
945 | ======================================================================*/ | ||
946 | |||
947 | int pcmcia_get_card_services_info(servinfo_t *info) | ||
948 | { | ||
949 | unsigned int socket_count = 0; | ||
950 | struct list_head *tmp; | ||
951 | info->Signature[0] = 'C'; | ||
952 | info->Signature[1] = 'S'; | ||
953 | down_read(&pcmcia_socket_list_rwsem); | ||
954 | list_for_each(tmp, &pcmcia_socket_list) | ||
955 | socket_count++; | ||
956 | up_read(&pcmcia_socket_list_rwsem); | ||
957 | info->Count = socket_count; | ||
958 | info->Revision = CS_RELEASE_CODE; | ||
959 | info->CSLevel = 0x0210; | ||
960 | info->VendorString = (char *)release; | ||
961 | return CS_SUCCESS; | ||
962 | } /* get_card_services_info */ | ||
963 | |||
964 | |||
965 | /*====================================================================*/ | ||
966 | |||
967 | int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req) | ||
968 | { | ||
969 | window_t *win; | ||
970 | int w; | ||
971 | |||
972 | if (!s || !(s->state & SOCKET_PRESENT)) | ||
973 | return CS_NO_CARD; | ||
974 | for (w = idx; w < MAX_WIN; w++) | ||
975 | if (s->state & SOCKET_WIN_REQ(w)) break; | ||
976 | if (w == MAX_WIN) | ||
977 | return CS_NO_MORE_ITEMS; | ||
978 | win = &s->win[w]; | ||
979 | req->Base = win->ctl.res->start; | ||
980 | req->Size = win->ctl.res->end - win->ctl.res->start + 1; | ||
981 | req->AccessSpeed = win->ctl.speed; | ||
982 | req->Attributes = 0; | ||
983 | if (win->ctl.flags & MAP_ATTRIB) | ||
984 | req->Attributes |= WIN_MEMORY_TYPE_AM; | ||
985 | if (win->ctl.flags & MAP_ACTIVE) | ||
986 | req->Attributes |= WIN_ENABLE; | ||
987 | if (win->ctl.flags & MAP_16BIT) | ||
988 | req->Attributes |= WIN_DATA_WIDTH_16; | ||
989 | if (win->ctl.flags & MAP_USE_WAIT) | ||
990 | req->Attributes |= WIN_USE_WAIT; | ||
991 | *handle = win; | ||
992 | return CS_SUCCESS; | ||
993 | } /* get_window */ | ||
994 | EXPORT_SYMBOL(pcmcia_get_window); | ||
995 | |||
996 | /*===================================================================== | ||
997 | |||
998 | Return the PCI device associated with a card.. | ||
999 | |||
1000 | ======================================================================*/ | ||
1001 | |||
1002 | #ifdef CONFIG_CARDBUS | ||
1003 | |||
1004 | struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s) | ||
1005 | { | ||
1006 | if (!s || !(s->state & SOCKET_CARDBUS)) | ||
1007 | return NULL; | ||
1008 | |||
1009 | return s->cb_dev->subordinate; | ||
1010 | } | ||
1011 | |||
1012 | EXPORT_SYMBOL(pcmcia_lookup_bus); | ||
1013 | |||
1014 | #endif | ||
1015 | |||
1016 | /*====================================================================== | ||
1017 | |||
1018 | Get the current socket state bits. We don't support the latched | ||
1019 | SocketState yet: I haven't seen any point for it. | ||
1020 | |||
1021 | ======================================================================*/ | ||
1022 | |||
1023 | int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status) | ||
1024 | { | ||
1025 | config_t *c; | ||
1026 | int val; | ||
1027 | |||
1028 | s->ops->get_status(s, &val); | ||
1029 | status->CardState = status->SocketState = 0; | ||
1030 | status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; | ||
1031 | status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; | ||
1032 | status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; | ||
1033 | status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; | ||
1034 | if (s->state & SOCKET_SUSPEND) | ||
1035 | status->CardState |= CS_EVENT_PM_SUSPEND; | ||
1036 | if (!(s->state & SOCKET_PRESENT)) | ||
1037 | return CS_NO_CARD; | ||
1038 | |||
1039 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
1040 | if ((c != NULL) && (c->state & CONFIG_LOCKED) && | ||
1041 | (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { | ||
1042 | u_char reg; | ||
1043 | if (c->Present & PRESENT_PIN_REPLACE) { | ||
1044 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); | ||
1045 | status->CardState |= | ||
1046 | (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; | ||
1047 | status->CardState |= | ||
1048 | (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; | ||
1049 | status->CardState |= | ||
1050 | (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; | ||
1051 | status->CardState |= | ||
1052 | (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; | ||
1053 | } else { | ||
1054 | /* No PRR? Then assume we're always ready */ | ||
1055 | status->CardState |= CS_EVENT_READY_CHANGE; | ||
1056 | } | ||
1057 | if (c->Present & PRESENT_EXT_STATUS) { | ||
1058 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); | ||
1059 | status->CardState |= | ||
1060 | (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; | ||
1061 | } | ||
1062 | return CS_SUCCESS; | ||
1063 | } | ||
1064 | status->CardState |= | ||
1065 | (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; | ||
1066 | status->CardState |= | ||
1067 | (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; | ||
1068 | status->CardState |= | ||
1069 | (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; | ||
1070 | status->CardState |= | ||
1071 | (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; | ||
1072 | return CS_SUCCESS; | ||
1073 | } /* get_status */ | ||
1074 | EXPORT_SYMBOL(pccard_get_status); | ||
1075 | |||
1076 | /*====================================================================== | ||
1077 | |||
1078 | Change the card address of an already open memory window. | ||
1079 | |||
1080 | ======================================================================*/ | ||
1081 | |||
1082 | int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) | ||
1083 | { | ||
1084 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1085 | return CS_BAD_HANDLE; | ||
1086 | req->Page = 0; | ||
1087 | req->CardOffset = win->ctl.card_start; | ||
1088 | return CS_SUCCESS; | ||
1089 | } /* get_mem_page */ | ||
1090 | |||
1091 | int pcmcia_map_mem_page(window_handle_t win, memreq_t *req) | ||
1092 | { | ||
1093 | struct pcmcia_socket *s; | ||
1094 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1095 | return CS_BAD_HANDLE; | ||
1096 | if (req->Page != 0) | ||
1097 | return CS_BAD_PAGE; | ||
1098 | s = win->sock; | ||
1099 | win->ctl.card_start = req->CardOffset; | ||
1100 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
1101 | return CS_BAD_OFFSET; | ||
1102 | return CS_SUCCESS; | ||
1103 | } /* map_mem_page */ | ||
1104 | |||
1105 | /*====================================================================== | ||
1106 | |||
1107 | Modify a locked socket configuration | ||
1108 | |||
1109 | ======================================================================*/ | ||
1110 | |||
1111 | int pcmcia_modify_configuration(client_handle_t handle, | ||
1112 | modconf_t *mod) | ||
1113 | { | ||
1114 | struct pcmcia_socket *s; | ||
1115 | config_t *c; | ||
1116 | |||
1117 | if (CHECK_HANDLE(handle)) | ||
1118 | return CS_BAD_HANDLE; | ||
1119 | s = SOCKET(handle); c = CONFIG(handle); | ||
1120 | if (!(s->state & SOCKET_PRESENT)) | ||
1121 | return CS_NO_CARD; | ||
1122 | if (!(c->state & CONFIG_LOCKED)) | ||
1123 | return CS_CONFIGURATION_LOCKED; | ||
1124 | |||
1125 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { | ||
1126 | if (mod->Attributes & CONF_ENABLE_IRQ) { | ||
1127 | c->Attributes |= CONF_ENABLE_IRQ; | ||
1128 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
1129 | } else { | ||
1130 | c->Attributes &= ~CONF_ENABLE_IRQ; | ||
1131 | s->socket.io_irq = 0; | ||
1132 | } | ||
1133 | s->ops->set_socket(s, &s->socket); | ||
1134 | } | ||
1135 | |||
1136 | if (mod->Attributes & CONF_VCC_CHANGE_VALID) | ||
1137 | return CS_BAD_VCC; | ||
1138 | |||
1139 | /* We only allow changing Vpp1 and Vpp2 to the same value */ | ||
1140 | if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && | ||
1141 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { | ||
1142 | if (mod->Vpp1 != mod->Vpp2) | ||
1143 | return CS_BAD_VPP; | ||
1144 | c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; | ||
1145 | if (s->ops->set_socket(s, &s->socket)) | ||
1146 | return CS_BAD_VPP; | ||
1147 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || | ||
1148 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) | ||
1149 | return CS_BAD_VPP; | ||
1150 | |||
1151 | return CS_SUCCESS; | ||
1152 | } /* modify_configuration */ | ||
1153 | |||
1154 | /* register pcmcia_callback */ | ||
1155 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) | ||
1156 | { | ||
1157 | int ret = 0; | ||
1158 | |||
1159 | /* s->skt_sem also protects s->callback */ | ||
1160 | down(&s->skt_sem); | ||
1161 | |||
1162 | if (c) { | ||
1163 | /* registration */ | ||
1164 | if (s->callback) { | ||
1165 | ret = -EBUSY; | ||
1166 | goto err; | ||
1167 | } | ||
1168 | |||
1169 | s->callback = c; | ||
1170 | |||
1171 | if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) | ||
1172 | send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); | ||
1173 | } else | ||
1174 | s->callback = NULL; | ||
1175 | err: | ||
1176 | up(&s->skt_sem); | ||
1177 | |||
1178 | return ret; | ||
1179 | } | ||
1180 | EXPORT_SYMBOL(pccard_register_pcmcia); | ||
1181 | |||
1182 | /*====================================================================*/ | ||
1183 | |||
1184 | int pcmcia_release_configuration(client_handle_t handle) | ||
1185 | { | ||
1186 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
1187 | struct pcmcia_socket *s; | ||
1188 | int i; | ||
1189 | |||
1190 | if (CHECK_HANDLE(handle) || | ||
1191 | !(handle->state & CLIENT_CONFIG_LOCKED)) | ||
1192 | return CS_BAD_HANDLE; | ||
1193 | handle->state &= ~CLIENT_CONFIG_LOCKED; | ||
1194 | s = SOCKET(handle); | ||
1195 | |||
1196 | #ifdef CONFIG_CARDBUS | ||
1197 | if (handle->state & CLIENT_CARDBUS) | ||
1198 | return CS_SUCCESS; | ||
1199 | #endif | ||
1200 | |||
1201 | if (!(handle->state & CLIENT_STALE)) { | ||
1202 | config_t *c = CONFIG(handle); | ||
1203 | if (--(s->lock_count) == 0) { | ||
1204 | s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ | ||
1205 | s->socket.Vpp = 0; | ||
1206 | s->socket.io_irq = 0; | ||
1207 | s->ops->set_socket(s, &s->socket); | ||
1208 | } | ||
1209 | if (c->state & CONFIG_IO_REQ) | ||
1210 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
1211 | if (s->io[i].NumPorts == 0) | ||
1212 | continue; | ||
1213 | s->io[i].Config--; | ||
1214 | if (s->io[i].Config != 0) | ||
1215 | continue; | ||
1216 | io.map = i; | ||
1217 | s->ops->set_io_map(s, &io); | ||
1218 | } | ||
1219 | c->state &= ~CONFIG_LOCKED; | ||
1220 | } | ||
1221 | |||
1222 | return CS_SUCCESS; | ||
1223 | } /* release_configuration */ | ||
1224 | |||
1225 | /*====================================================================== | ||
1226 | |||
1227 | Release_io() releases the I/O ranges allocated by a client. This | ||
1228 | may be invoked some time after a card ejection has already dumped | ||
1229 | the actual socket configuration, so if the client is "stale", we | ||
1230 | don't bother checking the port ranges against the current socket | ||
1231 | values. | ||
1232 | |||
1233 | ======================================================================*/ | ||
1234 | |||
1235 | int pcmcia_release_io(client_handle_t handle, io_req_t *req) | ||
1236 | { | ||
1237 | struct pcmcia_socket *s; | ||
1238 | |||
1239 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) | ||
1240 | return CS_BAD_HANDLE; | ||
1241 | handle->state &= ~CLIENT_IO_REQ; | ||
1242 | s = SOCKET(handle); | ||
1243 | |||
1244 | #ifdef CONFIG_CARDBUS | ||
1245 | if (handle->state & CLIENT_CARDBUS) | ||
1246 | return CS_SUCCESS; | ||
1247 | #endif | ||
1248 | |||
1249 | if (!(handle->state & CLIENT_STALE)) { | ||
1250 | config_t *c = CONFIG(handle); | ||
1251 | if (c->state & CONFIG_LOCKED) | ||
1252 | return CS_CONFIGURATION_LOCKED; | ||
1253 | if ((c->io.BasePort1 != req->BasePort1) || | ||
1254 | (c->io.NumPorts1 != req->NumPorts1) || | ||
1255 | (c->io.BasePort2 != req->BasePort2) || | ||
1256 | (c->io.NumPorts2 != req->NumPorts2)) | ||
1257 | return CS_BAD_ARGS; | ||
1258 | c->state &= ~CONFIG_IO_REQ; | ||
1259 | } | ||
1260 | |||
1261 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
1262 | if (req->NumPorts2) | ||
1263 | release_io_space(s, req->BasePort2, req->NumPorts2); | ||
1264 | |||
1265 | return CS_SUCCESS; | ||
1266 | } /* release_io */ | ||
1267 | |||
1268 | /*====================================================================*/ | ||
1269 | |||
1270 | int pcmcia_release_irq(client_handle_t handle, irq_req_t *req) | ||
1271 | { | ||
1272 | struct pcmcia_socket *s; | ||
1273 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ)) | ||
1274 | return CS_BAD_HANDLE; | ||
1275 | handle->state &= ~CLIENT_IRQ_REQ; | ||
1276 | s = SOCKET(handle); | ||
1277 | |||
1278 | if (!(handle->state & CLIENT_STALE)) { | ||
1279 | config_t *c = CONFIG(handle); | ||
1280 | if (c->state & CONFIG_LOCKED) | ||
1281 | return CS_CONFIGURATION_LOCKED; | ||
1282 | if (c->irq.Attributes != req->Attributes) | ||
1283 | return CS_BAD_ATTRIBUTE; | ||
1284 | if (s->irq.AssignedIRQ != req->AssignedIRQ) | ||
1285 | return CS_BAD_IRQ; | ||
1286 | if (--s->irq.Config == 0) { | ||
1287 | c->state &= ~CONFIG_IRQ_REQ; | ||
1288 | s->irq.AssignedIRQ = 0; | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | if (req->Attributes & IRQ_HANDLE_PRESENT) { | ||
1293 | free_irq(req->AssignedIRQ, req->Instance); | ||
1294 | } | ||
1295 | |||
1296 | #ifdef CONFIG_PCMCIA_PROBE | ||
1297 | pcmcia_used_irq[req->AssignedIRQ]--; | ||
1298 | #endif | ||
1299 | |||
1300 | return CS_SUCCESS; | ||
1301 | } /* cs_release_irq */ | ||
1302 | |||
1303 | /*====================================================================*/ | ||
1304 | |||
1305 | int pcmcia_release_window(window_handle_t win) | ||
1306 | { | ||
1307 | struct pcmcia_socket *s; | ||
1308 | |||
1309 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1310 | return CS_BAD_HANDLE; | ||
1311 | s = win->sock; | ||
1312 | if (!(win->handle->state & CLIENT_WIN_REQ(win->index))) | ||
1313 | return CS_BAD_HANDLE; | ||
1314 | |||
1315 | /* Shut down memory window */ | ||
1316 | win->ctl.flags &= ~MAP_ACTIVE; | ||
1317 | s->ops->set_mem_map(s, &win->ctl); | ||
1318 | s->state &= ~SOCKET_WIN_REQ(win->index); | ||
1319 | |||
1320 | /* Release system memory */ | ||
1321 | if (win->ctl.res) { | ||
1322 | release_resource(win->ctl.res); | ||
1323 | kfree(win->ctl.res); | ||
1324 | win->ctl.res = NULL; | ||
1325 | } | ||
1326 | win->handle->state &= ~CLIENT_WIN_REQ(win->index); | ||
1327 | |||
1328 | win->magic = 0; | ||
1329 | |||
1330 | return CS_SUCCESS; | ||
1331 | } /* release_window */ | ||
1332 | |||
1333 | /*====================================================================*/ | ||
1334 | |||
1335 | int pcmcia_request_configuration(client_handle_t handle, | ||
1336 | config_req_t *req) | ||
1337 | { | ||
1338 | int i; | ||
1339 | u_int base; | ||
1340 | struct pcmcia_socket *s; | ||
1341 | config_t *c; | ||
1342 | pccard_io_map iomap; | ||
1343 | |||
1344 | if (CHECK_HANDLE(handle)) | ||
1345 | return CS_BAD_HANDLE; | ||
1346 | s = SOCKET(handle); | ||
1347 | if (!(s->state & SOCKET_PRESENT)) | ||
1348 | return CS_NO_CARD; | ||
1349 | |||
1350 | #ifdef CONFIG_CARDBUS | ||
1351 | if (handle->state & CLIENT_CARDBUS) | ||
1352 | return CS_UNSUPPORTED_MODE; | ||
1353 | #endif | ||
1354 | |||
1355 | if (req->IntType & INT_CARDBUS) | ||
1356 | return CS_UNSUPPORTED_MODE; | ||
1357 | c = CONFIG(handle); | ||
1358 | if (c->state & CONFIG_LOCKED) | ||
1359 | return CS_CONFIGURATION_LOCKED; | ||
1360 | |||
1361 | /* Do power control. We don't allow changes in Vcc. */ | ||
1362 | if (s->socket.Vcc != req->Vcc) | ||
1363 | return CS_BAD_VCC; | ||
1364 | if (req->Vpp1 != req->Vpp2) | ||
1365 | return CS_BAD_VPP; | ||
1366 | s->socket.Vpp = req->Vpp1; | ||
1367 | if (s->ops->set_socket(s, &s->socket)) | ||
1368 | return CS_BAD_VPP; | ||
1369 | |||
1370 | c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; | ||
1371 | |||
1372 | /* Pick memory or I/O card, DMA mode, interrupt */ | ||
1373 | c->IntType = req->IntType; | ||
1374 | c->Attributes = req->Attributes; | ||
1375 | if (req->IntType & INT_MEMORY_AND_IO) | ||
1376 | s->socket.flags |= SS_IOCARD; | ||
1377 | if (req->IntType & INT_ZOOMED_VIDEO) | ||
1378 | s->socket.flags |= SS_ZVCARD | SS_IOCARD; | ||
1379 | if (req->Attributes & CONF_ENABLE_DMA) | ||
1380 | s->socket.flags |= SS_DMA_MODE; | ||
1381 | if (req->Attributes & CONF_ENABLE_SPKR) | ||
1382 | s->socket.flags |= SS_SPKR_ENA; | ||
1383 | if (req->Attributes & CONF_ENABLE_IRQ) | ||
1384 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
1385 | else | ||
1386 | s->socket.io_irq = 0; | ||
1387 | s->ops->set_socket(s, &s->socket); | ||
1388 | s->lock_count++; | ||
1389 | |||
1390 | /* Set up CIS configuration registers */ | ||
1391 | base = c->ConfigBase = req->ConfigBase; | ||
1392 | c->Present = c->CardValues = req->Present; | ||
1393 | if (req->Present & PRESENT_COPY) { | ||
1394 | c->Copy = req->Copy; | ||
1395 | write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); | ||
1396 | } | ||
1397 | if (req->Present & PRESENT_OPTION) { | ||
1398 | if (s->functions == 1) { | ||
1399 | c->Option = req->ConfigIndex & COR_CONFIG_MASK; | ||
1400 | } else { | ||
1401 | c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; | ||
1402 | c->Option |= COR_FUNC_ENA|COR_IREQ_ENA; | ||
1403 | if (req->Present & PRESENT_IOBASE_0) | ||
1404 | c->Option |= COR_ADDR_DECODE; | ||
1405 | } | ||
1406 | if (c->state & CONFIG_IRQ_REQ) | ||
1407 | if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) | ||
1408 | c->Option |= COR_LEVEL_REQ; | ||
1409 | write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); | ||
1410 | mdelay(40); | ||
1411 | } | ||
1412 | if (req->Present & PRESENT_STATUS) { | ||
1413 | c->Status = req->Status; | ||
1414 | write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status); | ||
1415 | } | ||
1416 | if (req->Present & PRESENT_PIN_REPLACE) { | ||
1417 | c->Pin = req->Pin; | ||
1418 | write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin); | ||
1419 | } | ||
1420 | if (req->Present & PRESENT_EXT_STATUS) { | ||
1421 | c->ExtStatus = req->ExtStatus; | ||
1422 | write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); | ||
1423 | } | ||
1424 | if (req->Present & PRESENT_IOBASE_0) { | ||
1425 | u_char b = c->io.BasePort1 & 0xff; | ||
1426 | write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); | ||
1427 | b = (c->io.BasePort1 >> 8) & 0xff; | ||
1428 | write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); | ||
1429 | } | ||
1430 | if (req->Present & PRESENT_IOSIZE) { | ||
1431 | u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; | ||
1432 | write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); | ||
1433 | } | ||
1434 | |||
1435 | /* Configure I/O windows */ | ||
1436 | if (c->state & CONFIG_IO_REQ) { | ||
1437 | iomap.speed = io_speed; | ||
1438 | for (i = 0; i < MAX_IO_WIN; i++) | ||
1439 | if (s->io[i].NumPorts != 0) { | ||
1440 | iomap.map = i; | ||
1441 | iomap.flags = MAP_ACTIVE; | ||
1442 | switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) { | ||
1443 | case IO_DATA_PATH_WIDTH_16: | ||
1444 | iomap.flags |= MAP_16BIT; break; | ||
1445 | case IO_DATA_PATH_WIDTH_AUTO: | ||
1446 | iomap.flags |= MAP_AUTOSZ; break; | ||
1447 | default: | ||
1448 | break; | ||
1449 | } | ||
1450 | iomap.start = s->io[i].BasePort; | ||
1451 | iomap.stop = iomap.start + s->io[i].NumPorts - 1; | ||
1452 | s->ops->set_io_map(s, &iomap); | ||
1453 | s->io[i].Config++; | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | c->state |= CONFIG_LOCKED; | ||
1458 | handle->state |= CLIENT_CONFIG_LOCKED; | ||
1459 | return CS_SUCCESS; | ||
1460 | } /* request_configuration */ | ||
1461 | |||
1462 | /*====================================================================== | ||
1463 | |||
1464 | Request_io() reserves ranges of port addresses for a socket. | ||
1465 | I have not implemented range sharing or alias addressing. | ||
1466 | |||
1467 | ======================================================================*/ | ||
1468 | |||
1469 | int pcmcia_request_io(client_handle_t handle, io_req_t *req) | ||
1470 | { | ||
1471 | struct pcmcia_socket *s; | ||
1472 | config_t *c; | ||
1473 | |||
1474 | if (CHECK_HANDLE(handle)) | ||
1475 | return CS_BAD_HANDLE; | ||
1476 | s = SOCKET(handle); | ||
1477 | if (!(s->state & SOCKET_PRESENT)) | ||
1478 | return CS_NO_CARD; | ||
1479 | |||
1480 | if (handle->state & CLIENT_CARDBUS) { | ||
1481 | #ifdef CONFIG_CARDBUS | ||
1482 | handle->state |= CLIENT_IO_REQ; | ||
1483 | return CS_SUCCESS; | ||
1484 | #else | ||
1485 | return CS_UNSUPPORTED_FUNCTION; | ||
1486 | #endif | ||
1487 | } | ||
1488 | |||
1489 | if (!req) | ||
1490 | return CS_UNSUPPORTED_MODE; | ||
1491 | c = CONFIG(handle); | ||
1492 | if (c->state & CONFIG_LOCKED) | ||
1493 | return CS_CONFIGURATION_LOCKED; | ||
1494 | if (c->state & CONFIG_IO_REQ) | ||
1495 | return CS_IN_USE; | ||
1496 | if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) | ||
1497 | return CS_BAD_ATTRIBUTE; | ||
1498 | if ((req->NumPorts2 > 0) && | ||
1499 | (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) | ||
1500 | return CS_BAD_ATTRIBUTE; | ||
1501 | |||
1502 | if (alloc_io_space(s, req->Attributes1, &req->BasePort1, | ||
1503 | req->NumPorts1, req->IOAddrLines)) | ||
1504 | return CS_IN_USE; | ||
1505 | |||
1506 | if (req->NumPorts2) { | ||
1507 | if (alloc_io_space(s, req->Attributes2, &req->BasePort2, | ||
1508 | req->NumPorts2, req->IOAddrLines)) { | ||
1509 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
1510 | return CS_IN_USE; | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1514 | c->io = *req; | ||
1515 | c->state |= CONFIG_IO_REQ; | ||
1516 | handle->state |= CLIENT_IO_REQ; | ||
1517 | return CS_SUCCESS; | ||
1518 | } /* request_io */ | ||
1519 | |||
1520 | /*====================================================================== | ||
1521 | |||
1522 | Request_irq() reserves an irq for this client. | ||
1523 | |||
1524 | Also, since Linux only reserves irq's when they are actually | ||
1525 | hooked, we don't guarantee that an irq will still be available | ||
1526 | when the configuration is locked. Now that I think about it, | ||
1527 | there might be a way to fix this using a dummy handler. | ||
1528 | |||
1529 | ======================================================================*/ | ||
1530 | |||
1531 | #ifdef CONFIG_PCMCIA_PROBE | ||
1532 | static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
1533 | { | ||
1534 | return IRQ_NONE; | ||
1535 | } | ||
1536 | #endif | ||
1537 | |||
1538 | int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) | ||
1539 | { | ||
1540 | struct pcmcia_socket *s; | ||
1541 | config_t *c; | ||
1542 | int ret = CS_IN_USE, irq = 0; | ||
1543 | struct pcmcia_device *p_dev = handle_to_pdev(handle); | ||
1544 | |||
1545 | if (CHECK_HANDLE(handle)) | ||
1546 | return CS_BAD_HANDLE; | ||
1547 | s = SOCKET(handle); | ||
1548 | if (!(s->state & SOCKET_PRESENT)) | ||
1549 | return CS_NO_CARD; | ||
1550 | c = CONFIG(handle); | ||
1551 | if (c->state & CONFIG_LOCKED) | ||
1552 | return CS_CONFIGURATION_LOCKED; | ||
1553 | if (c->state & CONFIG_IRQ_REQ) | ||
1554 | return CS_IN_USE; | ||
1555 | |||
1556 | #ifdef CONFIG_PCMCIA_PROBE | ||
1557 | if (s->irq.AssignedIRQ != 0) { | ||
1558 | /* If the interrupt is already assigned, it must be the same */ | ||
1559 | irq = s->irq.AssignedIRQ; | ||
1560 | } else { | ||
1561 | int try; | ||
1562 | u32 mask = s->irq_mask; | ||
1563 | void *data = NULL; | ||
1564 | |||
1565 | for (try = 0; try < 64; try++) { | ||
1566 | irq = try % 32; | ||
1567 | |||
1568 | /* marked as available by driver, and not blocked by userspace? */ | ||
1569 | if (!((mask >> irq) & 1)) | ||
1570 | continue; | ||
1571 | |||
1572 | /* avoid an IRQ which is already used by a PCMCIA card */ | ||
1573 | if ((try < 32) && pcmcia_used_irq[irq]) | ||
1574 | continue; | ||
1575 | |||
1576 | /* register the correct driver, if possible, of check whether | ||
1577 | * registering a dummy handle works, i.e. if the IRQ isn't | ||
1578 | * marked as used by the kernel resource management core */ | ||
1579 | ret = request_irq(irq, | ||
1580 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, | ||
1581 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
1582 | (s->functions > 1) || | ||
1583 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
1584 | p_dev->dev.bus_id, | ||
1585 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); | ||
1586 | if (!ret) { | ||
1587 | if (!(req->Attributes & IRQ_HANDLE_PRESENT)) | ||
1588 | free_irq(irq, data); | ||
1589 | break; | ||
1590 | } | ||
1591 | } | ||
1592 | } | ||
1593 | #endif | ||
1594 | if (ret) { | ||
1595 | if (!s->pci_irq) | ||
1596 | return ret; | ||
1597 | irq = s->pci_irq; | ||
1598 | } | ||
1599 | |||
1600 | if (ret && req->Attributes & IRQ_HANDLE_PRESENT) { | ||
1601 | if (request_irq(irq, req->Handler, | ||
1602 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
1603 | (s->functions > 1) || | ||
1604 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
1605 | p_dev->dev.bus_id, req->Instance)) | ||
1606 | return CS_IN_USE; | ||
1607 | } | ||
1608 | |||
1609 | c->irq.Attributes = req->Attributes; | ||
1610 | s->irq.AssignedIRQ = req->AssignedIRQ = irq; | ||
1611 | s->irq.Config++; | ||
1612 | |||
1613 | c->state |= CONFIG_IRQ_REQ; | ||
1614 | handle->state |= CLIENT_IRQ_REQ; | ||
1615 | |||
1616 | #ifdef CONFIG_PCMCIA_PROBE | ||
1617 | pcmcia_used_irq[irq]++; | ||
1618 | #endif | ||
1619 | |||
1620 | return CS_SUCCESS; | ||
1621 | } /* pcmcia_request_irq */ | ||
1622 | |||
1623 | /*====================================================================== | ||
1624 | |||
1625 | Request_window() establishes a mapping between card memory space | ||
1626 | and system memory space. | ||
1627 | |||
1628 | ======================================================================*/ | ||
1629 | |||
1630 | int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh) | ||
1631 | { | ||
1632 | struct pcmcia_socket *s; | ||
1633 | window_t *win; | ||
1634 | u_long align; | ||
1635 | int w; | ||
1636 | |||
1637 | if (CHECK_HANDLE(*handle)) | ||
1638 | return CS_BAD_HANDLE; | ||
1639 | s = (*handle)->Socket; | ||
1640 | if (!(s->state & SOCKET_PRESENT)) | ||
1641 | return CS_NO_CARD; | ||
1642 | if (req->Attributes & (WIN_PAGED | WIN_SHARED)) | ||
1643 | return CS_BAD_ATTRIBUTE; | ||
1644 | |||
1645 | /* Window size defaults to smallest available */ | ||
1646 | if (req->Size == 0) | ||
1647 | req->Size = s->map_size; | ||
1648 | align = (((s->features & SS_CAP_MEM_ALIGN) || | ||
1649 | (req->Attributes & WIN_STRICT_ALIGN)) ? | ||
1650 | req->Size : s->map_size); | ||
1651 | if (req->Size & (s->map_size-1)) | ||
1652 | return CS_BAD_SIZE; | ||
1653 | if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || | ||
1654 | (req->Base & (align-1))) | ||
1655 | return CS_BAD_BASE; | ||
1656 | if (req->Base) | ||
1657 | align = 0; | ||
1658 | |||
1659 | /* Allocate system memory window */ | ||
1660 | for (w = 0; w < MAX_WIN; w++) | ||
1661 | if (!(s->state & SOCKET_WIN_REQ(w))) break; | ||
1662 | if (w == MAX_WIN) | ||
1663 | return CS_OUT_OF_RESOURCE; | ||
1664 | |||
1665 | win = &s->win[w]; | ||
1666 | win->magic = WINDOW_MAGIC; | ||
1667 | win->index = w; | ||
1668 | win->handle = *handle; | ||
1669 | win->sock = s; | ||
1670 | |||
1671 | if (!(s->features & SS_CAP_STATIC_MAP)) { | ||
1672 | win->ctl.res = find_mem_region(req->Base, req->Size, align, | ||
1673 | (req->Attributes & WIN_MAP_BELOW_1MB), s); | ||
1674 | if (!win->ctl.res) | ||
1675 | return CS_IN_USE; | ||
1676 | } | ||
1677 | (*handle)->state |= CLIENT_WIN_REQ(w); | ||
1678 | |||
1679 | /* Configure the socket controller */ | ||
1680 | win->ctl.map = w+1; | ||
1681 | win->ctl.flags = 0; | ||
1682 | win->ctl.speed = req->AccessSpeed; | ||
1683 | if (req->Attributes & WIN_MEMORY_TYPE) | ||
1684 | win->ctl.flags |= MAP_ATTRIB; | ||
1685 | if (req->Attributes & WIN_ENABLE) | ||
1686 | win->ctl.flags |= MAP_ACTIVE; | ||
1687 | if (req->Attributes & WIN_DATA_WIDTH_16) | ||
1688 | win->ctl.flags |= MAP_16BIT; | ||
1689 | if (req->Attributes & WIN_USE_WAIT) | ||
1690 | win->ctl.flags |= MAP_USE_WAIT; | ||
1691 | win->ctl.card_start = 0; | ||
1692 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
1693 | return CS_BAD_ARGS; | ||
1694 | s->state |= SOCKET_WIN_REQ(w); | ||
1695 | |||
1696 | /* Return window handle */ | ||
1697 | if (s->features & SS_CAP_STATIC_MAP) { | ||
1698 | req->Base = win->ctl.static_start; | ||
1699 | } else { | ||
1700 | req->Base = win->ctl.res->start; | ||
1701 | } | ||
1702 | *wh = win; | ||
1703 | |||
1704 | return CS_SUCCESS; | ||
1705 | } /* request_window */ | ||
1706 | |||
1707 | /*====================================================================== | ||
1708 | |||
1709 | I'm not sure which "reset" function this is supposed to use, | ||
1710 | but for now, it uses the low-level interface's reset, not the | ||
1711 | CIS register. | ||
1712 | |||
1713 | ======================================================================*/ | ||
1714 | |||
1715 | int pccard_reset_card(struct pcmcia_socket *skt) | ||
1716 | { | ||
1717 | int ret; | ||
1718 | |||
1719 | cs_dbg(skt, 1, "resetting socket\n"); | ||
1720 | |||
1721 | down(&skt->skt_sem); | ||
1722 | do { | ||
1723 | if (!(skt->state & SOCKET_PRESENT)) { | ||
1724 | ret = CS_NO_CARD; | ||
1725 | break; | ||
1726 | } | ||
1727 | if (skt->state & SOCKET_SUSPEND) { | ||
1728 | ret = CS_IN_USE; | ||
1729 | break; | ||
1730 | } | ||
1731 | if (skt->state & SOCKET_CARDBUS) { | ||
1732 | ret = CS_UNSUPPORTED_FUNCTION; | ||
1733 | break; | ||
1734 | } | ||
1735 | |||
1736 | ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW); | ||
1737 | if (ret == 0) { | ||
1738 | send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW); | ||
1739 | if (socket_reset(skt) == CS_SUCCESS) | ||
1740 | send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); | ||
1741 | } | ||
1742 | |||
1743 | ret = CS_SUCCESS; | ||
1744 | } while (0); | ||
1745 | up(&skt->skt_sem); | ||
1746 | |||
1747 | return ret; | ||
1748 | } /* reset_card */ | ||
1749 | EXPORT_SYMBOL(pccard_reset_card); | ||
1750 | |||
1751 | /*====================================================================== | ||
1752 | |||
1753 | These shut down or wake up a socket. They are sort of user | ||
1754 | initiated versions of the APM suspend and resume actions. | ||
1755 | |||
1756 | ======================================================================*/ | ||
1757 | |||
1758 | int pcmcia_suspend_card(struct pcmcia_socket *skt) | ||
1759 | { | ||
1760 | int ret; | ||
1761 | |||
1762 | cs_dbg(skt, 1, "suspending socket\n"); | ||
1763 | |||
1764 | down(&skt->skt_sem); | ||
1765 | do { | ||
1766 | if (!(skt->state & SOCKET_PRESENT)) { | ||
1767 | ret = CS_NO_CARD; | ||
1768 | break; | ||
1769 | } | ||
1770 | if (skt->state & SOCKET_CARDBUS) { | ||
1771 | ret = CS_UNSUPPORTED_FUNCTION; | ||
1772 | break; | ||
1773 | } | ||
1774 | ret = socket_suspend(skt); | ||
1775 | } while (0); | ||
1776 | up(&skt->skt_sem); | ||
1777 | |||
1778 | return ret; | ||
1779 | } /* suspend_card */ | ||
1780 | |||
1781 | int pcmcia_resume_card(struct pcmcia_socket *skt) | ||
1782 | { | ||
1783 | int ret; | ||
1784 | |||
1785 | cs_dbg(skt, 1, "waking up socket\n"); | ||
1786 | |||
1787 | down(&skt->skt_sem); | ||
1788 | do { | ||
1789 | if (!(skt->state & SOCKET_PRESENT)) { | ||
1790 | ret = CS_NO_CARD; | ||
1791 | break; | ||
1792 | } | ||
1793 | if (skt->state & SOCKET_CARDBUS) { | ||
1794 | ret = CS_UNSUPPORTED_FUNCTION; | ||
1795 | break; | ||
1796 | } | ||
1797 | ret = socket_resume(skt); | ||
1798 | } while (0); | ||
1799 | up(&skt->skt_sem); | ||
1800 | |||
1801 | return ret; | ||
1802 | } /* resume_card */ | ||
1803 | |||
1804 | /*====================================================================== | ||
1805 | |||
1806 | These handle user requests to eject or insert a card. | ||
1807 | |||
1808 | ======================================================================*/ | ||
1809 | |||
1810 | int pcmcia_eject_card(struct pcmcia_socket *skt) | ||
1811 | { | ||
1812 | int ret; | ||
1813 | |||
1814 | cs_dbg(skt, 1, "user eject request\n"); | ||
1815 | |||
1816 | down(&skt->skt_sem); | ||
1817 | do { | ||
1818 | if (!(skt->state & SOCKET_PRESENT)) { | ||
1819 | ret = -ENODEV; | ||
1820 | break; | ||
1821 | } | ||
1822 | |||
1823 | ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW); | ||
1824 | if (ret != 0) { | ||
1825 | ret = -EINVAL; | ||
1826 | break; | ||
1827 | } | ||
1828 | |||
1829 | socket_remove(skt); | ||
1830 | ret = 0; | ||
1831 | } while (0); | ||
1832 | up(&skt->skt_sem); | ||
1833 | |||
1834 | return ret; | ||
1835 | } /* eject_card */ | ||
1836 | |||
1837 | int pcmcia_insert_card(struct pcmcia_socket *skt) | ||
1838 | { | ||
1839 | int ret; | ||
1840 | |||
1841 | cs_dbg(skt, 1, "user insert request\n"); | ||
1842 | |||
1843 | down(&skt->skt_sem); | ||
1844 | do { | ||
1845 | if (skt->state & SOCKET_PRESENT) { | ||
1846 | ret = -EBUSY; | ||
1847 | break; | ||
1848 | } | ||
1849 | if (socket_insert(skt) == CS_NO_CARD) { | ||
1850 | ret = -ENODEV; | ||
1851 | break; | ||
1852 | } | ||
1853 | ret = 0; | ||
1854 | } while (0); | ||
1855 | up(&skt->skt_sem); | ||
1856 | |||
1857 | return ret; | ||
1858 | } /* insert_card */ | ||
1859 | |||
1860 | /*====================================================================== | ||
1861 | |||
1862 | OS-specific module glue goes here | ||
1863 | |||
1864 | ======================================================================*/ | ||
1865 | /* in alpha order */ | ||
1866 | EXPORT_SYMBOL(pcmcia_eject_card); | ||
1867 | EXPORT_SYMBOL(pcmcia_get_card_services_info); | ||
1868 | EXPORT_SYMBOL(pcmcia_get_mem_page); | ||
1869 | EXPORT_SYMBOL(pcmcia_insert_card); | ||
1870 | EXPORT_SYMBOL(pcmcia_map_mem_page); | ||
1871 | EXPORT_SYMBOL(pcmcia_modify_configuration); | ||
1872 | EXPORT_SYMBOL(pcmcia_release_configuration); | ||
1873 | EXPORT_SYMBOL(pcmcia_release_io); | ||
1874 | EXPORT_SYMBOL(pcmcia_release_irq); | ||
1875 | EXPORT_SYMBOL(pcmcia_release_window); | ||
1876 | EXPORT_SYMBOL(pcmcia_replace_cis); | ||
1877 | EXPORT_SYMBOL(pcmcia_request_configuration); | ||
1878 | EXPORT_SYMBOL(pcmcia_request_io); | ||
1879 | EXPORT_SYMBOL(pcmcia_request_irq); | ||
1880 | EXPORT_SYMBOL(pcmcia_request_window); | ||
1881 | EXPORT_SYMBOL(pcmcia_resume_card); | ||
1882 | EXPORT_SYMBOL(pcmcia_suspend_card); | ||
1883 | |||
1884 | EXPORT_SYMBOL(dead_socket); | ||
1885 | EXPORT_SYMBOL(pcmcia_parse_events); | ||
1886 | |||
1887 | struct class pcmcia_socket_class = { | ||
1888 | .name = "pcmcia_socket", | ||
1889 | .release = pcmcia_release_socket, | ||
1890 | }; | ||
1891 | EXPORT_SYMBOL(pcmcia_socket_class); | ||
1892 | |||
1893 | |||
1894 | static int __init init_pcmcia_cs(void) | ||
1895 | { | ||
1896 | int ret; | ||
1897 | printk(KERN_INFO "%s\n", release); | ||
1898 | printk(KERN_INFO " %s\n", options); | ||
1899 | |||
1900 | ret = class_register(&pcmcia_socket_class); | ||
1901 | if (ret) | ||
1902 | return (ret); | ||
1903 | return class_interface_register(&pccard_sysfs_interface); | ||
1904 | } | ||
1905 | |||
1906 | static void __exit exit_pcmcia_cs(void) | ||
1907 | { | ||
1908 | printk(KERN_INFO "unloading Kernel Card Services\n"); | ||
1909 | class_interface_unregister(&pccard_sysfs_interface); | ||
1910 | class_unregister(&pcmcia_socket_class); | ||
1911 | } | ||
1912 | |||
1913 | subsys_initcall(init_pcmcia_cs); | ||
1914 | module_exit(exit_pcmcia_cs); | ||
1915 | |||
1916 | /*====================================================================*/ | ||
1917 | |||
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h new file mode 100644 index 000000000000..7933a7db49d3 --- /dev/null +++ b/drivers/pcmcia/cs_internal.h | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * cs_internal.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | #ifndef _LINUX_CS_INTERNAL_H | ||
16 | #define _LINUX_CS_INTERNAL_H | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | |||
20 | #define CLIENT_MAGIC 0x51E6 | ||
21 | typedef struct client_t client_t; | ||
22 | |||
23 | /* Flags in client state */ | ||
24 | #define CLIENT_CONFIG_LOCKED 0x0001 | ||
25 | #define CLIENT_IRQ_REQ 0x0002 | ||
26 | #define CLIENT_IO_REQ 0x0004 | ||
27 | #define CLIENT_UNBOUND 0x0008 | ||
28 | #define CLIENT_STALE 0x0010 | ||
29 | #define CLIENT_WIN_REQ(i) (0x20<<(i)) | ||
30 | #define CLIENT_CARDBUS 0x8000 | ||
31 | |||
32 | #define REGION_MAGIC 0xE3C9 | ||
33 | typedef struct region_t { | ||
34 | u_short region_magic; | ||
35 | u_short state; | ||
36 | dev_info_t dev_info; | ||
37 | client_handle_t mtd; | ||
38 | u_int MediaID; | ||
39 | region_info_t info; | ||
40 | } region_t; | ||
41 | |||
42 | #define REGION_STALE 0x01 | ||
43 | |||
44 | /* Each card function gets one of these guys */ | ||
45 | typedef struct config_t { | ||
46 | u_int state; | ||
47 | u_int Attributes; | ||
48 | u_int Vcc, Vpp1, Vpp2; | ||
49 | u_int IntType; | ||
50 | u_int ConfigBase; | ||
51 | u_char Status, Pin, Copy, Option, ExtStatus; | ||
52 | u_int Present; | ||
53 | u_int CardValues; | ||
54 | io_req_t io; | ||
55 | struct { | ||
56 | u_int Attributes; | ||
57 | } irq; | ||
58 | } config_t; | ||
59 | |||
60 | struct cis_cache_entry { | ||
61 | struct list_head node; | ||
62 | unsigned int addr; | ||
63 | unsigned int len; | ||
64 | unsigned int attr; | ||
65 | unsigned char cache[0]; | ||
66 | }; | ||
67 | |||
68 | /* Flags in config state */ | ||
69 | #define CONFIG_LOCKED 0x01 | ||
70 | #define CONFIG_IRQ_REQ 0x02 | ||
71 | #define CONFIG_IO_REQ 0x04 | ||
72 | |||
73 | /* Flags in socket state */ | ||
74 | #define SOCKET_PRESENT 0x0008 | ||
75 | #define SOCKET_INUSE 0x0010 | ||
76 | #define SOCKET_SUSPEND 0x0080 | ||
77 | #define SOCKET_WIN_REQ(i) (0x0100<<(i)) | ||
78 | #define SOCKET_REGION_INFO 0x4000 | ||
79 | #define SOCKET_CARDBUS 0x8000 | ||
80 | #define SOCKET_CARDBUS_CONFIG 0x10000 | ||
81 | |||
82 | static inline int cs_socket_get(struct pcmcia_socket *skt) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | WARN_ON(skt->state & SOCKET_INUSE); | ||
87 | |||
88 | ret = try_module_get(skt->owner); | ||
89 | if (ret) | ||
90 | skt->state |= SOCKET_INUSE; | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static inline void cs_socket_put(struct pcmcia_socket *skt) | ||
95 | { | ||
96 | if (skt->state & SOCKET_INUSE) { | ||
97 | skt->state &= ~SOCKET_INUSE; | ||
98 | module_put(skt->owner); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | #define CHECK_HANDLE(h) \ | ||
103 | (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC)) | ||
104 | |||
105 | #define CHECK_SOCKET(s) \ | ||
106 | (((s) >= sockets) || (socket_table[s]->ops == NULL)) | ||
107 | |||
108 | #define SOCKET(h) (h->Socket) | ||
109 | #define CONFIG(h) (&SOCKET(h)->config[(h)->Function]) | ||
110 | |||
111 | #define CHECK_REGION(r) \ | ||
112 | (((r) == NULL) || ((r)->region_magic != REGION_MAGIC)) | ||
113 | |||
114 | #define CHECK_ERASEQ(q) \ | ||
115 | (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC)) | ||
116 | |||
117 | #define EVENT(h, e, p) \ | ||
118 | ((h)->event_handler((e), (p), &(h)->event_callback_args)) | ||
119 | |||
120 | /* In cardbus.c */ | ||
121 | int cb_alloc(struct pcmcia_socket *s); | ||
122 | void cb_free(struct pcmcia_socket *s); | ||
123 | int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr); | ||
124 | |||
125 | /* In cistpl.c */ | ||
126 | int read_cis_mem(struct pcmcia_socket *s, int attr, | ||
127 | u_int addr, u_int len, void *ptr); | ||
128 | void write_cis_mem(struct pcmcia_socket *s, int attr, | ||
129 | u_int addr, u_int len, void *ptr); | ||
130 | void release_cis_mem(struct pcmcia_socket *s); | ||
131 | void destroy_cis_cache(struct pcmcia_socket *s); | ||
132 | int verify_cis_cache(struct pcmcia_socket *s); | ||
133 | int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse); | ||
134 | |||
135 | /* In rsrc_mgr */ | ||
136 | void pcmcia_validate_mem(struct pcmcia_socket *s); | ||
137 | struct resource *find_io_region(unsigned long base, int num, unsigned long align, | ||
138 | struct pcmcia_socket *s); | ||
139 | int adjust_io_region(struct resource *res, unsigned long r_start, | ||
140 | unsigned long r_end, struct pcmcia_socket *s); | ||
141 | struct resource *find_mem_region(u_long base, u_long num, u_long align, | ||
142 | int low, struct pcmcia_socket *s); | ||
143 | int adjust_resource_info(client_handle_t handle, adjust_t *adj); | ||
144 | void release_resource_db(struct pcmcia_socket *s); | ||
145 | |||
146 | /* In socket_sysfs.c */ | ||
147 | extern struct class_interface pccard_sysfs_interface; | ||
148 | |||
149 | /* In cs.c */ | ||
150 | extern struct rw_semaphore pcmcia_socket_list_rwsem; | ||
151 | extern struct list_head pcmcia_socket_list; | ||
152 | int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req); | ||
153 | int pccard_get_configuration_info(struct pcmcia_socket *s, unsigned int function, config_info_t *config); | ||
154 | int pccard_reset_card(struct pcmcia_socket *skt); | ||
155 | int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status); | ||
156 | int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg); | ||
157 | |||
158 | |||
159 | struct pcmcia_callback{ | ||
160 | struct module *owner; | ||
161 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); | ||
162 | int (*resources_done) (struct pcmcia_socket *s); | ||
163 | }; | ||
164 | |||
165 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); | ||
166 | |||
167 | #define cs_socket_name(skt) ((skt)->dev.class_id) | ||
168 | |||
169 | #ifdef DEBUG | ||
170 | extern int cs_debug_level(int); | ||
171 | |||
172 | #define cs_dbg(skt, lvl, fmt, arg...) do { \ | ||
173 | if (cs_debug_level(lvl)) \ | ||
174 | printk(KERN_DEBUG "cs: %s: " fmt, \ | ||
175 | cs_socket_name(skt) , ## arg); \ | ||
176 | } while (0) | ||
177 | |||
178 | #else | ||
179 | #define cs_dbg(skt, lvl, fmt, arg...) do { } while (0) | ||
180 | #endif | ||
181 | |||
182 | #define cs_err(skt, fmt, arg...) \ | ||
183 | printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg) | ||
184 | |||
185 | #endif /* _LINUX_CS_INTERNAL_H */ | ||
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c new file mode 100644 index 000000000000..66150d08b5c7 --- /dev/null +++ b/drivers/pcmcia/ds.c | |||
@@ -0,0 +1,1659 @@ | |||
1 | /* | ||
2 | * ds.c -- 16-bit PCMCIA core support | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | * (C) 2003 - 2004 Dominik Brodowski | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/fcntl.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/timer.h> | ||
30 | #include <linux/ioctl.h> | ||
31 | #include <linux/proc_fs.h> | ||
32 | #include <linux/poll.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/kref.h> | ||
37 | #include <linux/workqueue.h> | ||
38 | |||
39 | #include <asm/atomic.h> | ||
40 | |||
41 | #define IN_CARD_SERVICES | ||
42 | #include <pcmcia/version.h> | ||
43 | #include <pcmcia/cs_types.h> | ||
44 | #include <pcmcia/cs.h> | ||
45 | #include <pcmcia/bulkmem.h> | ||
46 | #include <pcmcia/cistpl.h> | ||
47 | #include <pcmcia/ds.h> | ||
48 | #include <pcmcia/ss.h> | ||
49 | |||
50 | #include "cs_internal.h" | ||
51 | |||
52 | /*====================================================================*/ | ||
53 | |||
54 | /* Module parameters */ | ||
55 | |||
56 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | ||
57 | MODULE_DESCRIPTION("PCMCIA Driver Services"); | ||
58 | MODULE_LICENSE("GPL"); | ||
59 | |||
60 | #ifdef DEBUG | ||
61 | int ds_pc_debug; | ||
62 | |||
63 | module_param_named(pc_debug, ds_pc_debug, int, 0644); | ||
64 | |||
65 | #define ds_dbg(lvl, fmt, arg...) do { \ | ||
66 | if (ds_pc_debug > (lvl)) \ | ||
67 | printk(KERN_DEBUG "ds: " fmt , ## arg); \ | ||
68 | } while (0) | ||
69 | #else | ||
70 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) | ||
71 | #endif | ||
72 | |||
73 | /*====================================================================*/ | ||
74 | |||
75 | /* Device user information */ | ||
76 | #define MAX_EVENTS 32 | ||
77 | #define USER_MAGIC 0x7ea4 | ||
78 | #define CHECK_USER(u) \ | ||
79 | (((u) == NULL) || ((u)->user_magic != USER_MAGIC)) | ||
80 | typedef struct user_info_t { | ||
81 | u_int user_magic; | ||
82 | int event_head, event_tail; | ||
83 | event_t event[MAX_EVENTS]; | ||
84 | struct user_info_t *next; | ||
85 | struct pcmcia_bus_socket *socket; | ||
86 | } user_info_t; | ||
87 | |||
88 | /* Socket state information */ | ||
89 | struct pcmcia_bus_socket { | ||
90 | struct kref refcount; | ||
91 | struct pcmcia_callback callback; | ||
92 | int state; | ||
93 | user_info_t *user; | ||
94 | wait_queue_head_t queue; | ||
95 | struct pcmcia_socket *parent; | ||
96 | |||
97 | /* the PCMCIA devices connected to this socket (normally one, more | ||
98 | * for multifunction devices: */ | ||
99 | struct list_head devices_list; | ||
100 | u8 device_count; /* the number of devices, used | ||
101 | * only internally and subject | ||
102 | * to incorrectness and change */ | ||
103 | }; | ||
104 | static spinlock_t pcmcia_dev_list_lock; | ||
105 | |||
106 | #define DS_SOCKET_PRESENT 0x01 | ||
107 | #define DS_SOCKET_BUSY 0x02 | ||
108 | #define DS_SOCKET_REMOVAL_PENDING 0x10 | ||
109 | #define DS_SOCKET_DEAD 0x80 | ||
110 | |||
111 | /*====================================================================*/ | ||
112 | |||
113 | static int major_dev = -1; | ||
114 | |||
115 | static int unbind_request(struct pcmcia_bus_socket *s); | ||
116 | |||
117 | /*====================================================================*/ | ||
118 | |||
119 | /* code which was in cs.c before */ | ||
120 | |||
121 | /* String tables for error messages */ | ||
122 | |||
123 | typedef struct lookup_t { | ||
124 | int key; | ||
125 | char *msg; | ||
126 | } lookup_t; | ||
127 | |||
128 | static const lookup_t error_table[] = { | ||
129 | { CS_SUCCESS, "Operation succeeded" }, | ||
130 | { CS_BAD_ADAPTER, "Bad adapter" }, | ||
131 | { CS_BAD_ATTRIBUTE, "Bad attribute", }, | ||
132 | { CS_BAD_BASE, "Bad base address" }, | ||
133 | { CS_BAD_EDC, "Bad EDC" }, | ||
134 | { CS_BAD_IRQ, "Bad IRQ" }, | ||
135 | { CS_BAD_OFFSET, "Bad offset" }, | ||
136 | { CS_BAD_PAGE, "Bad page number" }, | ||
137 | { CS_READ_FAILURE, "Read failure" }, | ||
138 | { CS_BAD_SIZE, "Bad size" }, | ||
139 | { CS_BAD_SOCKET, "Bad socket" }, | ||
140 | { CS_BAD_TYPE, "Bad type" }, | ||
141 | { CS_BAD_VCC, "Bad Vcc" }, | ||
142 | { CS_BAD_VPP, "Bad Vpp" }, | ||
143 | { CS_BAD_WINDOW, "Bad window" }, | ||
144 | { CS_WRITE_FAILURE, "Write failure" }, | ||
145 | { CS_NO_CARD, "No card present" }, | ||
146 | { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, | ||
147 | { CS_UNSUPPORTED_MODE, "Unsupported mode" }, | ||
148 | { CS_BAD_SPEED, "Bad speed" }, | ||
149 | { CS_BUSY, "Resource busy" }, | ||
150 | { CS_GENERAL_FAILURE, "General failure" }, | ||
151 | { CS_WRITE_PROTECTED, "Write protected" }, | ||
152 | { CS_BAD_ARG_LENGTH, "Bad argument length" }, | ||
153 | { CS_BAD_ARGS, "Bad arguments" }, | ||
154 | { CS_CONFIGURATION_LOCKED, "Configuration locked" }, | ||
155 | { CS_IN_USE, "Resource in use" }, | ||
156 | { CS_NO_MORE_ITEMS, "No more items" }, | ||
157 | { CS_OUT_OF_RESOURCE, "Out of resource" }, | ||
158 | { CS_BAD_HANDLE, "Bad handle" }, | ||
159 | { CS_BAD_TUPLE, "Bad CIS tuple" } | ||
160 | }; | ||
161 | |||
162 | |||
163 | static const lookup_t service_table[] = { | ||
164 | { AccessConfigurationRegister, "AccessConfigurationRegister" }, | ||
165 | { AddSocketServices, "AddSocketServices" }, | ||
166 | { AdjustResourceInfo, "AdjustResourceInfo" }, | ||
167 | { CheckEraseQueue, "CheckEraseQueue" }, | ||
168 | { CloseMemory, "CloseMemory" }, | ||
169 | { DeregisterClient, "DeregisterClient" }, | ||
170 | { DeregisterEraseQueue, "DeregisterEraseQueue" }, | ||
171 | { GetCardServicesInfo, "GetCardServicesInfo" }, | ||
172 | { GetClientInfo, "GetClientInfo" }, | ||
173 | { GetConfigurationInfo, "GetConfigurationInfo" }, | ||
174 | { GetEventMask, "GetEventMask" }, | ||
175 | { GetFirstClient, "GetFirstClient" }, | ||
176 | { GetFirstRegion, "GetFirstRegion" }, | ||
177 | { GetFirstTuple, "GetFirstTuple" }, | ||
178 | { GetNextClient, "GetNextClient" }, | ||
179 | { GetNextRegion, "GetNextRegion" }, | ||
180 | { GetNextTuple, "GetNextTuple" }, | ||
181 | { GetStatus, "GetStatus" }, | ||
182 | { GetTupleData, "GetTupleData" }, | ||
183 | { MapMemPage, "MapMemPage" }, | ||
184 | { ModifyConfiguration, "ModifyConfiguration" }, | ||
185 | { ModifyWindow, "ModifyWindow" }, | ||
186 | { OpenMemory, "OpenMemory" }, | ||
187 | { ParseTuple, "ParseTuple" }, | ||
188 | { ReadMemory, "ReadMemory" }, | ||
189 | { RegisterClient, "RegisterClient" }, | ||
190 | { RegisterEraseQueue, "RegisterEraseQueue" }, | ||
191 | { RegisterMTD, "RegisterMTD" }, | ||
192 | { ReleaseConfiguration, "ReleaseConfiguration" }, | ||
193 | { ReleaseIO, "ReleaseIO" }, | ||
194 | { ReleaseIRQ, "ReleaseIRQ" }, | ||
195 | { ReleaseWindow, "ReleaseWindow" }, | ||
196 | { RequestConfiguration, "RequestConfiguration" }, | ||
197 | { RequestIO, "RequestIO" }, | ||
198 | { RequestIRQ, "RequestIRQ" }, | ||
199 | { RequestSocketMask, "RequestSocketMask" }, | ||
200 | { RequestWindow, "RequestWindow" }, | ||
201 | { ResetCard, "ResetCard" }, | ||
202 | { SetEventMask, "SetEventMask" }, | ||
203 | { ValidateCIS, "ValidateCIS" }, | ||
204 | { WriteMemory, "WriteMemory" }, | ||
205 | { BindDevice, "BindDevice" }, | ||
206 | { BindMTD, "BindMTD" }, | ||
207 | { ReportError, "ReportError" }, | ||
208 | { SuspendCard, "SuspendCard" }, | ||
209 | { ResumeCard, "ResumeCard" }, | ||
210 | { EjectCard, "EjectCard" }, | ||
211 | { InsertCard, "InsertCard" }, | ||
212 | { ReplaceCIS, "ReplaceCIS" } | ||
213 | }; | ||
214 | |||
215 | |||
216 | int pcmcia_report_error(client_handle_t handle, error_info_t *err) | ||
217 | { | ||
218 | int i; | ||
219 | char *serv; | ||
220 | |||
221 | if (CHECK_HANDLE(handle)) | ||
222 | printk(KERN_NOTICE); | ||
223 | else { | ||
224 | struct pcmcia_device *p_dev = handle_to_pdev(handle); | ||
225 | printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id); | ||
226 | } | ||
227 | |||
228 | for (i = 0; i < ARRAY_SIZE(service_table); i++) | ||
229 | if (service_table[i].key == err->func) | ||
230 | break; | ||
231 | if (i < ARRAY_SIZE(service_table)) | ||
232 | serv = service_table[i].msg; | ||
233 | else | ||
234 | serv = "Unknown service number"; | ||
235 | |||
236 | for (i = 0; i < ARRAY_SIZE(error_table); i++) | ||
237 | if (error_table[i].key == err->retcode) | ||
238 | break; | ||
239 | if (i < ARRAY_SIZE(error_table)) | ||
240 | printk("%s: %s\n", serv, error_table[i].msg); | ||
241 | else | ||
242 | printk("%s: Unknown error code %#x\n", serv, err->retcode); | ||
243 | |||
244 | return CS_SUCCESS; | ||
245 | } /* report_error */ | ||
246 | EXPORT_SYMBOL(pcmcia_report_error); | ||
247 | |||
248 | /* end of code which was in cs.c before */ | ||
249 | |||
250 | /*======================================================================*/ | ||
251 | |||
252 | void cs_error(client_handle_t handle, int func, int ret) | ||
253 | { | ||
254 | error_info_t err = { func, ret }; | ||
255 | pcmcia_report_error(handle, &err); | ||
256 | } | ||
257 | EXPORT_SYMBOL(cs_error); | ||
258 | |||
259 | /*======================================================================*/ | ||
260 | |||
261 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); | ||
262 | static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr); | ||
263 | |||
264 | static void pcmcia_release_bus_socket(struct kref *refcount) | ||
265 | { | ||
266 | struct pcmcia_bus_socket *s = container_of(refcount, struct pcmcia_bus_socket, refcount); | ||
267 | pcmcia_put_socket(s->parent); | ||
268 | kfree(s); | ||
269 | } | ||
270 | |||
271 | static void pcmcia_put_bus_socket(struct pcmcia_bus_socket *s) | ||
272 | { | ||
273 | kref_put(&s->refcount, pcmcia_release_bus_socket); | ||
274 | } | ||
275 | |||
276 | static struct pcmcia_bus_socket *pcmcia_get_bus_socket(struct pcmcia_bus_socket *s) | ||
277 | { | ||
278 | kref_get(&s->refcount); | ||
279 | return (s); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * pcmcia_register_driver - register a PCMCIA driver with the bus core | ||
284 | * | ||
285 | * Registers a PCMCIA driver with the PCMCIA bus core. | ||
286 | */ | ||
287 | static int pcmcia_device_probe(struct device *dev); | ||
288 | static int pcmcia_device_remove(struct device * dev); | ||
289 | |||
290 | int pcmcia_register_driver(struct pcmcia_driver *driver) | ||
291 | { | ||
292 | if (!driver) | ||
293 | return -EINVAL; | ||
294 | |||
295 | /* initialize common fields */ | ||
296 | driver->drv.bus = &pcmcia_bus_type; | ||
297 | driver->drv.owner = driver->owner; | ||
298 | driver->drv.probe = pcmcia_device_probe; | ||
299 | driver->drv.remove = pcmcia_device_remove; | ||
300 | |||
301 | return driver_register(&driver->drv); | ||
302 | } | ||
303 | EXPORT_SYMBOL(pcmcia_register_driver); | ||
304 | |||
305 | /** | ||
306 | * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core | ||
307 | */ | ||
308 | void pcmcia_unregister_driver(struct pcmcia_driver *driver) | ||
309 | { | ||
310 | driver_unregister(&driver->drv); | ||
311 | } | ||
312 | EXPORT_SYMBOL(pcmcia_unregister_driver); | ||
313 | |||
314 | #ifdef CONFIG_PROC_FS | ||
315 | static struct proc_dir_entry *proc_pccard = NULL; | ||
316 | |||
317 | static int proc_read_drivers_callback(struct device_driver *driver, void *d) | ||
318 | { | ||
319 | char **p = d; | ||
320 | struct pcmcia_driver *p_drv = container_of(driver, | ||
321 | struct pcmcia_driver, drv); | ||
322 | |||
323 | *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name, | ||
324 | #ifdef CONFIG_MODULE_UNLOAD | ||
325 | (p_drv->owner) ? module_refcount(p_drv->owner) : 1 | ||
326 | #else | ||
327 | 1 | ||
328 | #endif | ||
329 | ); | ||
330 | d = (void *) p; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int proc_read_drivers(char *buf, char **start, off_t pos, | ||
336 | int count, int *eof, void *data) | ||
337 | { | ||
338 | char *p = buf; | ||
339 | |||
340 | bus_for_each_drv(&pcmcia_bus_type, NULL, | ||
341 | (void *) &p, proc_read_drivers_callback); | ||
342 | |||
343 | return (p - buf); | ||
344 | } | ||
345 | #endif | ||
346 | |||
347 | /* pcmcia_device handling */ | ||
348 | |||
349 | static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) | ||
350 | { | ||
351 | struct device *tmp_dev; | ||
352 | tmp_dev = get_device(&p_dev->dev); | ||
353 | if (!tmp_dev) | ||
354 | return NULL; | ||
355 | return to_pcmcia_dev(tmp_dev); | ||
356 | } | ||
357 | |||
358 | static void pcmcia_put_dev(struct pcmcia_device *p_dev) | ||
359 | { | ||
360 | if (p_dev) | ||
361 | put_device(&p_dev->dev); | ||
362 | } | ||
363 | |||
364 | static void pcmcia_release_dev(struct device *dev) | ||
365 | { | ||
366 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
367 | ds_dbg(1, "releasing dev %p\n", p_dev); | ||
368 | pcmcia_put_bus_socket(p_dev->socket->pcmcia); | ||
369 | kfree(p_dev); | ||
370 | } | ||
371 | |||
372 | |||
373 | static int pcmcia_device_probe(struct device * dev) | ||
374 | { | ||
375 | struct pcmcia_device *p_dev; | ||
376 | struct pcmcia_driver *p_drv; | ||
377 | int ret = 0; | ||
378 | |||
379 | dev = get_device(dev); | ||
380 | if (!dev) | ||
381 | return -ENODEV; | ||
382 | |||
383 | p_dev = to_pcmcia_dev(dev); | ||
384 | p_drv = to_pcmcia_drv(dev->driver); | ||
385 | |||
386 | if (!try_module_get(p_drv->owner)) { | ||
387 | ret = -EINVAL; | ||
388 | goto put_dev; | ||
389 | } | ||
390 | |||
391 | if (p_drv->attach) { | ||
392 | p_dev->instance = p_drv->attach(); | ||
393 | if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) { | ||
394 | printk(KERN_NOTICE "ds: unable to create instance " | ||
395 | "of '%s'!\n", p_drv->drv.name); | ||
396 | ret = -EINVAL; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | if (ret) | ||
401 | module_put(p_drv->owner); | ||
402 | put_dev: | ||
403 | if ((ret) || !(p_drv->attach)) | ||
404 | put_device(dev); | ||
405 | return (ret); | ||
406 | } | ||
407 | |||
408 | |||
409 | static int pcmcia_device_remove(struct device * dev) | ||
410 | { | ||
411 | struct pcmcia_device *p_dev; | ||
412 | struct pcmcia_driver *p_drv; | ||
413 | |||
414 | /* detach the "instance" */ | ||
415 | p_dev = to_pcmcia_dev(dev); | ||
416 | p_drv = to_pcmcia_drv(dev->driver); | ||
417 | |||
418 | if (p_drv) { | ||
419 | if ((p_drv->detach) && (p_dev->instance)) { | ||
420 | p_drv->detach(p_dev->instance); | ||
421 | /* from pcmcia_probe_device */ | ||
422 | put_device(&p_dev->dev); | ||
423 | } | ||
424 | module_put(p_drv->owner); | ||
425 | } | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | |||
431 | |||
432 | /* | ||
433 | * pcmcia_device_query -- determine information about a pcmcia device | ||
434 | */ | ||
435 | static int pcmcia_device_query(struct pcmcia_device *p_dev) | ||
436 | { | ||
437 | cistpl_manfid_t manf_id; | ||
438 | cistpl_funcid_t func_id; | ||
439 | cistpl_vers_1_t vers1; | ||
440 | unsigned int i; | ||
441 | |||
442 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | ||
443 | CISTPL_MANFID, &manf_id)) { | ||
444 | p_dev->manf_id = manf_id.manf; | ||
445 | p_dev->card_id = manf_id.card; | ||
446 | p_dev->has_manf_id = 1; | ||
447 | p_dev->has_card_id = 1; | ||
448 | } | ||
449 | |||
450 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | ||
451 | CISTPL_FUNCID, &func_id)) { | ||
452 | p_dev->func_id = func_id.func; | ||
453 | p_dev->has_func_id = 1; | ||
454 | } else { | ||
455 | /* rule of thumb: cards with no FUNCID, but with | ||
456 | * common memory device geometry information, are | ||
457 | * probably memory cards (from pcmcia-cs) */ | ||
458 | cistpl_device_geo_t devgeo; | ||
459 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | ||
460 | CISTPL_DEVICE_GEO, &devgeo)) { | ||
461 | ds_dbg(0, "mem device geometry probably means " | ||
462 | "FUNCID_MEMORY\n"); | ||
463 | p_dev->func_id = CISTPL_FUNCID_MEMORY; | ||
464 | p_dev->has_func_id = 1; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, | ||
469 | &vers1)) { | ||
470 | for (i=0; i < vers1.ns; i++) { | ||
471 | char *tmp; | ||
472 | unsigned int length; | ||
473 | |||
474 | tmp = vers1.str + vers1.ofs[i]; | ||
475 | |||
476 | length = strlen(tmp) + 1; | ||
477 | if ((length < 3) || (length > 255)) | ||
478 | continue; | ||
479 | |||
480 | p_dev->prod_id[i] = kmalloc(sizeof(char) * length, | ||
481 | GFP_KERNEL); | ||
482 | if (!p_dev->prod_id[i]) | ||
483 | continue; | ||
484 | |||
485 | p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], | ||
486 | tmp, length); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | |||
494 | /* device_add_lock is needed to avoid double registration by cardmgr and kernel. | ||
495 | * Serializes pcmcia_device_add; will most likely be removed in future. | ||
496 | * | ||
497 | * While it has the caveat that adding new PCMCIA devices inside(!) device_register() | ||
498 | * won't work, this doesn't matter much at the moment: the driver core doesn't | ||
499 | * support it either. | ||
500 | */ | ||
501 | static DECLARE_MUTEX(device_add_lock); | ||
502 | |||
503 | static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function) | ||
504 | { | ||
505 | struct pcmcia_device *p_dev; | ||
506 | unsigned long flags; | ||
507 | |||
508 | s = pcmcia_get_bus_socket(s); | ||
509 | if (!s) | ||
510 | return NULL; | ||
511 | |||
512 | down(&device_add_lock); | ||
513 | |||
514 | p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | ||
515 | if (!p_dev) | ||
516 | goto err_put; | ||
517 | memset(p_dev, 0, sizeof(struct pcmcia_device)); | ||
518 | |||
519 | p_dev->socket = s->parent; | ||
520 | p_dev->device_no = (s->device_count++); | ||
521 | p_dev->func = function; | ||
522 | |||
523 | p_dev->dev.bus = &pcmcia_bus_type; | ||
524 | p_dev->dev.parent = s->parent->dev.dev; | ||
525 | p_dev->dev.release = pcmcia_release_dev; | ||
526 | sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); | ||
527 | |||
528 | /* compat */ | ||
529 | p_dev->client.client_magic = CLIENT_MAGIC; | ||
530 | p_dev->client.Socket = s->parent; | ||
531 | p_dev->client.Function = function; | ||
532 | p_dev->client.state = CLIENT_UNBOUND; | ||
533 | |||
534 | /* Add to the list in pcmcia_bus_socket */ | ||
535 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
536 | list_add_tail(&p_dev->socket_device_list, &s->devices_list); | ||
537 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
538 | |||
539 | if (device_register(&p_dev->dev)) { | ||
540 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
541 | list_del(&p_dev->socket_device_list); | ||
542 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
543 | |||
544 | goto err_free; | ||
545 | } | ||
546 | |||
547 | up(&device_add_lock); | ||
548 | |||
549 | return p_dev; | ||
550 | |||
551 | err_free: | ||
552 | kfree(p_dev); | ||
553 | s->device_count--; | ||
554 | err_put: | ||
555 | up(&device_add_lock); | ||
556 | pcmcia_put_bus_socket(s); | ||
557 | |||
558 | return NULL; | ||
559 | } | ||
560 | |||
561 | |||
562 | static int pcmcia_card_add(struct pcmcia_socket *s) | ||
563 | { | ||
564 | cisinfo_t cisinfo; | ||
565 | cistpl_longlink_mfc_t mfc; | ||
566 | unsigned int no_funcs, i; | ||
567 | int ret = 0; | ||
568 | |||
569 | if (!(s->resource_setup_done)) | ||
570 | return -EAGAIN; /* try again, but later... */ | ||
571 | |||
572 | pcmcia_validate_mem(s); | ||
573 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); | ||
574 | if (ret || !cisinfo.Chains) { | ||
575 | ds_dbg(0, "invalid CIS or invalid resources\n"); | ||
576 | return -ENODEV; | ||
577 | } | ||
578 | |||
579 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) | ||
580 | no_funcs = mfc.nfn; | ||
581 | else | ||
582 | no_funcs = 1; | ||
583 | |||
584 | /* this doesn't handle multifunction devices on one pcmcia function | ||
585 | * yet. */ | ||
586 | for (i=0; i < no_funcs; i++) | ||
587 | pcmcia_device_add(s->pcmcia, i); | ||
588 | |||
589 | return (ret); | ||
590 | } | ||
591 | |||
592 | |||
593 | static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { | ||
594 | struct pcmcia_device * p_dev = to_pcmcia_dev(dev); | ||
595 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); | ||
596 | |||
597 | /* matching by cardmgr */ | ||
598 | if (p_dev->cardmgr == p_drv) | ||
599 | return 1; | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | /************************ per-device sysfs output ***************************/ | ||
605 | |||
606 | #define pcmcia_device_attr(field, test, format) \ | ||
607 | static ssize_t field##_show (struct device *dev, char *buf) \ | ||
608 | { \ | ||
609 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | ||
610 | return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \ | ||
611 | } | ||
612 | |||
613 | #define pcmcia_device_stringattr(name, field) \ | ||
614 | static ssize_t name##_show (struct device *dev, char *buf) \ | ||
615 | { \ | ||
616 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | ||
617 | return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \ | ||
618 | } | ||
619 | |||
620 | pcmcia_device_attr(func, socket, "0x%02x\n"); | ||
621 | pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); | ||
622 | pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); | ||
623 | pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); | ||
624 | pcmcia_device_stringattr(prod_id1, prod_id[0]); | ||
625 | pcmcia_device_stringattr(prod_id2, prod_id[1]); | ||
626 | pcmcia_device_stringattr(prod_id3, prod_id[2]); | ||
627 | pcmcia_device_stringattr(prod_id4, prod_id[3]); | ||
628 | |||
629 | static struct device_attribute pcmcia_dev_attrs[] = { | ||
630 | __ATTR(function, 0444, func_show, NULL), | ||
631 | __ATTR_RO(func_id), | ||
632 | __ATTR_RO(manf_id), | ||
633 | __ATTR_RO(card_id), | ||
634 | __ATTR_RO(prod_id1), | ||
635 | __ATTR_RO(prod_id2), | ||
636 | __ATTR_RO(prod_id3), | ||
637 | __ATTR_RO(prod_id4), | ||
638 | __ATTR_NULL, | ||
639 | }; | ||
640 | |||
641 | |||
642 | /*====================================================================== | ||
643 | |||
644 | These manage a ring buffer of events pending for one user process | ||
645 | |||
646 | ======================================================================*/ | ||
647 | |||
648 | static int queue_empty(user_info_t *user) | ||
649 | { | ||
650 | return (user->event_head == user->event_tail); | ||
651 | } | ||
652 | |||
653 | static event_t get_queued_event(user_info_t *user) | ||
654 | { | ||
655 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
656 | return user->event[user->event_tail]; | ||
657 | } | ||
658 | |||
659 | static void queue_event(user_info_t *user, event_t event) | ||
660 | { | ||
661 | user->event_head = (user->event_head+1) % MAX_EVENTS; | ||
662 | if (user->event_head == user->event_tail) | ||
663 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
664 | user->event[user->event_head] = event; | ||
665 | } | ||
666 | |||
667 | static void handle_event(struct pcmcia_bus_socket *s, event_t event) | ||
668 | { | ||
669 | user_info_t *user; | ||
670 | for (user = s->user; user; user = user->next) | ||
671 | queue_event(user, event); | ||
672 | wake_up_interruptible(&s->queue); | ||
673 | } | ||
674 | |||
675 | |||
676 | /*====================================================================== | ||
677 | |||
678 | The card status event handler. | ||
679 | |||
680 | ======================================================================*/ | ||
681 | |||
682 | struct send_event_data { | ||
683 | struct pcmcia_socket *skt; | ||
684 | event_t event; | ||
685 | int priority; | ||
686 | }; | ||
687 | |||
688 | static int send_event_callback(struct device *dev, void * _data) | ||
689 | { | ||
690 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
691 | struct send_event_data *data = _data; | ||
692 | |||
693 | /* we get called for all sockets, but may only pass the event | ||
694 | * for drivers _on the affected socket_ */ | ||
695 | if (p_dev->socket != data->skt) | ||
696 | return 0; | ||
697 | |||
698 | if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE)) | ||
699 | return 0; | ||
700 | |||
701 | if (p_dev->client.EventMask & data->event) | ||
702 | return EVENT(&p_dev->client, data->event, data->priority); | ||
703 | |||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | ||
708 | { | ||
709 | int ret = 0; | ||
710 | struct send_event_data private; | ||
711 | struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia); | ||
712 | |||
713 | if (!skt) | ||
714 | return 0; | ||
715 | |||
716 | private.skt = s; | ||
717 | private.event = event; | ||
718 | private.priority = priority; | ||
719 | |||
720 | ret = bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); | ||
721 | |||
722 | pcmcia_put_bus_socket(skt); | ||
723 | return ret; | ||
724 | } /* send_event */ | ||
725 | |||
726 | |||
727 | /* Normally, the event is passed to individual drivers after | ||
728 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this | ||
729 | * is inversed to maintain historic compatibility. | ||
730 | */ | ||
731 | |||
732 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | ||
733 | { | ||
734 | struct pcmcia_bus_socket *s = skt->pcmcia; | ||
735 | int ret = 0; | ||
736 | |||
737 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | ||
738 | event, priority, s); | ||
739 | |||
740 | switch (event) { | ||
741 | |||
742 | case CS_EVENT_CARD_REMOVAL: | ||
743 | s->state &= ~DS_SOCKET_PRESENT; | ||
744 | send_event(skt, event, priority); | ||
745 | unbind_request(s); | ||
746 | handle_event(s, event); | ||
747 | break; | ||
748 | |||
749 | case CS_EVENT_CARD_INSERTION: | ||
750 | s->state |= DS_SOCKET_PRESENT; | ||
751 | pcmcia_card_add(skt); | ||
752 | handle_event(s, event); | ||
753 | break; | ||
754 | |||
755 | case CS_EVENT_EJECTION_REQUEST: | ||
756 | ret = send_event(skt, event, priority); | ||
757 | break; | ||
758 | |||
759 | default: | ||
760 | handle_event(s, event); | ||
761 | send_event(skt, event, priority); | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } /* ds_event */ | ||
767 | |||
768 | |||
769 | /*====================================================================== | ||
770 | |||
771 | bind_request() and bind_device() are merged by now. Register_client() | ||
772 | is called right at the end of bind_request(), during the driver's | ||
773 | ->attach() call. Individual descriptions: | ||
774 | |||
775 | bind_request() connects a socket to a particular client driver. | ||
776 | It looks up the specified device ID in the list of registered | ||
777 | drivers, binds it to the socket, and tries to create an instance | ||
778 | of the device. unbind_request() deletes a driver instance. | ||
779 | |||
780 | Bind_device() associates a device driver with a particular socket. | ||
781 | It is normally called by Driver Services after it has identified | ||
782 | a newly inserted card. An instance of that driver will then be | ||
783 | eligible to register as a client of this socket. | ||
784 | |||
785 | Register_client() uses the dev_info_t handle to match the | ||
786 | caller with a socket. The driver must have already been bound | ||
787 | to a socket with bind_device() -- in fact, bind_device() | ||
788 | allocates the client structure that will be used. | ||
789 | |||
790 | ======================================================================*/ | ||
791 | |||
792 | static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) | ||
793 | { | ||
794 | struct pcmcia_driver *p_drv; | ||
795 | struct pcmcia_device *p_dev; | ||
796 | int ret = 0; | ||
797 | unsigned long flags; | ||
798 | |||
799 | s = pcmcia_get_bus_socket(s); | ||
800 | if (!s) | ||
801 | return -EINVAL; | ||
802 | |||
803 | ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, | ||
804 | (char *)bind_info->dev_info); | ||
805 | |||
806 | p_drv = get_pcmcia_driver(&bind_info->dev_info); | ||
807 | if (!p_drv) { | ||
808 | ret = -EINVAL; | ||
809 | goto err_put; | ||
810 | } | ||
811 | |||
812 | if (!try_module_get(p_drv->owner)) { | ||
813 | ret = -EINVAL; | ||
814 | goto err_put_driver; | ||
815 | } | ||
816 | |||
817 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
818 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
819 | if (p_dev->func == bind_info->function) { | ||
820 | if ((p_dev->dev.driver == &p_drv->drv)) { | ||
821 | if (p_dev->cardmgr) { | ||
822 | /* if there's already a device | ||
823 | * registered, and it was registered | ||
824 | * by userspace before, we need to | ||
825 | * return the "instance". */ | ||
826 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
827 | bind_info->instance = p_dev->instance; | ||
828 | ret = -EBUSY; | ||
829 | goto err_put_module; | ||
830 | } else { | ||
831 | /* the correct driver managed to bind | ||
832 | * itself magically to the correct | ||
833 | * device. */ | ||
834 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
835 | p_dev->cardmgr = p_drv; | ||
836 | ret = 0; | ||
837 | goto err_put_module; | ||
838 | } | ||
839 | } else if (!p_dev->dev.driver) { | ||
840 | /* there's already a device available where | ||
841 | * no device has been bound to yet. So we don't | ||
842 | * need to register a device! */ | ||
843 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
844 | goto rescan; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
849 | |||
850 | p_dev = pcmcia_device_add(s, bind_info->function); | ||
851 | if (!p_dev) { | ||
852 | ret = -EIO; | ||
853 | goto err_put_module; | ||
854 | } | ||
855 | |||
856 | rescan: | ||
857 | p_dev->cardmgr = p_drv; | ||
858 | |||
859 | pcmcia_device_query(p_dev); | ||
860 | |||
861 | /* | ||
862 | * Prevent this racing with a card insertion. | ||
863 | */ | ||
864 | down(&s->parent->skt_sem); | ||
865 | bus_rescan_devices(&pcmcia_bus_type); | ||
866 | up(&s->parent->skt_sem); | ||
867 | |||
868 | /* check whether the driver indeed matched. I don't care if this | ||
869 | * is racy or not, because it can only happen on cardmgr access | ||
870 | * paths... | ||
871 | */ | ||
872 | if (!(p_dev->dev.driver == &p_drv->drv)) | ||
873 | p_dev->cardmgr = NULL; | ||
874 | |||
875 | err_put_module: | ||
876 | module_put(p_drv->owner); | ||
877 | err_put_driver: | ||
878 | put_driver(&p_drv->drv); | ||
879 | err_put: | ||
880 | pcmcia_put_bus_socket(s); | ||
881 | |||
882 | return (ret); | ||
883 | } /* bind_request */ | ||
884 | |||
885 | |||
886 | int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) | ||
887 | { | ||
888 | client_t *client = NULL; | ||
889 | struct pcmcia_socket *s; | ||
890 | struct pcmcia_bus_socket *skt = NULL; | ||
891 | struct pcmcia_device *p_dev = NULL; | ||
892 | |||
893 | /* Look for unbound client with matching dev_info */ | ||
894 | down_read(&pcmcia_socket_list_rwsem); | ||
895 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
896 | unsigned long flags; | ||
897 | |||
898 | if (s->state & SOCKET_CARDBUS) | ||
899 | continue; | ||
900 | |||
901 | skt = s->pcmcia; | ||
902 | if (!skt) | ||
903 | continue; | ||
904 | skt = pcmcia_get_bus_socket(skt); | ||
905 | if (!skt) | ||
906 | continue; | ||
907 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
908 | list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) { | ||
909 | struct pcmcia_driver *p_drv; | ||
910 | p_dev = pcmcia_get_dev(p_dev); | ||
911 | if (!p_dev) | ||
912 | continue; | ||
913 | if (!(p_dev->client.state & CLIENT_UNBOUND) || | ||
914 | (!p_dev->dev.driver)) { | ||
915 | pcmcia_put_dev(p_dev); | ||
916 | continue; | ||
917 | } | ||
918 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | ||
919 | if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { | ||
920 | client = &p_dev->client; | ||
921 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
922 | goto found; | ||
923 | } | ||
924 | pcmcia_put_dev(p_dev); | ||
925 | } | ||
926 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
927 | pcmcia_put_bus_socket(skt); | ||
928 | } | ||
929 | found: | ||
930 | up_read(&pcmcia_socket_list_rwsem); | ||
931 | if (!p_dev || !client) | ||
932 | return -ENODEV; | ||
933 | |||
934 | pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */ | ||
935 | |||
936 | *handle = client; | ||
937 | client->state &= ~CLIENT_UNBOUND; | ||
938 | client->Socket = s; | ||
939 | client->EventMask = req->EventMask; | ||
940 | client->event_handler = req->event_handler; | ||
941 | client->event_callback_args = req->event_callback_args; | ||
942 | client->event_callback_args.client_handle = client; | ||
943 | |||
944 | if (s->state & SOCKET_CARDBUS) | ||
945 | client->state |= CLIENT_CARDBUS; | ||
946 | |||
947 | if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) && | ||
948 | (client->Function != BIND_FN_ALL)) { | ||
949 | cistpl_longlink_mfc_t mfc; | ||
950 | if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc) | ||
951 | == CS_SUCCESS) | ||
952 | s->functions = mfc.nfn; | ||
953 | else | ||
954 | s->functions = 1; | ||
955 | s->config = kmalloc(sizeof(config_t) * s->functions, | ||
956 | GFP_KERNEL); | ||
957 | if (!s->config) | ||
958 | goto out_no_resource; | ||
959 | memset(s->config, 0, sizeof(config_t) * s->functions); | ||
960 | } | ||
961 | |||
962 | ds_dbg(1, "register_client(): client 0x%p, dev %s\n", | ||
963 | client, p_dev->dev.bus_id); | ||
964 | if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) | ||
965 | EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); | ||
966 | |||
967 | if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { | ||
968 | if (client->EventMask & CS_EVENT_CARD_INSERTION) | ||
969 | EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); | ||
970 | } | ||
971 | |||
972 | return CS_SUCCESS; | ||
973 | |||
974 | out_no_resource: | ||
975 | pcmcia_put_dev(p_dev); | ||
976 | return CS_OUT_OF_RESOURCE; | ||
977 | } /* register_client */ | ||
978 | EXPORT_SYMBOL(pcmcia_register_client); | ||
979 | |||
980 | |||
981 | /*====================================================================*/ | ||
982 | |||
983 | extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s); | ||
984 | |||
985 | static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first) | ||
986 | { | ||
987 | dev_node_t *node; | ||
988 | struct pcmcia_device *p_dev; | ||
989 | unsigned long flags; | ||
990 | int ret = 0; | ||
991 | |||
992 | #ifdef CONFIG_CARDBUS | ||
993 | /* | ||
994 | * Some unbelievably ugly code to associate the PCI cardbus | ||
995 | * device and its driver with the PCMCIA "bind" information. | ||
996 | */ | ||
997 | { | ||
998 | struct pci_bus *bus; | ||
999 | |||
1000 | bus = pcmcia_lookup_bus(s->parent); | ||
1001 | if (bus) { | ||
1002 | struct list_head *list; | ||
1003 | struct pci_dev *dev = NULL; | ||
1004 | |||
1005 | list = bus->devices.next; | ||
1006 | while (list != &bus->devices) { | ||
1007 | struct pci_dev *pdev = pci_dev_b(list); | ||
1008 | list = list->next; | ||
1009 | |||
1010 | if (first) { | ||
1011 | dev = pdev; | ||
1012 | break; | ||
1013 | } | ||
1014 | |||
1015 | /* Try to handle "next" here some way? */ | ||
1016 | } | ||
1017 | if (dev && dev->driver) { | ||
1018 | strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); | ||
1019 | bind_info->major = 0; | ||
1020 | bind_info->minor = 0; | ||
1021 | bind_info->next = NULL; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | #endif | ||
1027 | |||
1028 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1029 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
1030 | if (p_dev->func == bind_info->function) { | ||
1031 | p_dev = pcmcia_get_dev(p_dev); | ||
1032 | if (!p_dev) | ||
1033 | continue; | ||
1034 | goto found; | ||
1035 | } | ||
1036 | } | ||
1037 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1038 | return -ENODEV; | ||
1039 | |||
1040 | found: | ||
1041 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1042 | |||
1043 | if ((!p_dev->instance) || | ||
1044 | (p_dev->instance->state & DEV_CONFIG_PENDING)) { | ||
1045 | ret = -EAGAIN; | ||
1046 | goto err_put; | ||
1047 | } | ||
1048 | |||
1049 | if (first) | ||
1050 | node = p_dev->instance->dev; | ||
1051 | else | ||
1052 | for (node = p_dev->instance->dev; node; node = node->next) | ||
1053 | if (node == bind_info->next) | ||
1054 | break; | ||
1055 | if (!node) { | ||
1056 | ret = -ENODEV; | ||
1057 | goto err_put; | ||
1058 | } | ||
1059 | |||
1060 | strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); | ||
1061 | bind_info->major = node->major; | ||
1062 | bind_info->minor = node->minor; | ||
1063 | bind_info->next = node->next; | ||
1064 | |||
1065 | err_put: | ||
1066 | pcmcia_put_dev(p_dev); | ||
1067 | return (ret); | ||
1068 | } /* get_device_info */ | ||
1069 | |||
1070 | /*====================================================================*/ | ||
1071 | |||
1072 | /* unbind _all_ devices attached to a given pcmcia_bus_socket. The | ||
1073 | * drivers have been called with EVENT_CARD_REMOVAL before. | ||
1074 | */ | ||
1075 | static int unbind_request(struct pcmcia_bus_socket *s) | ||
1076 | { | ||
1077 | struct pcmcia_device *p_dev; | ||
1078 | unsigned long flags; | ||
1079 | |||
1080 | ds_dbg(2, "unbind_request(%d)\n", s->parent->sock); | ||
1081 | |||
1082 | s->device_count = 0; | ||
1083 | |||
1084 | for (;;) { | ||
1085 | /* unregister all pcmcia_devices registered with this socket*/ | ||
1086 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1087 | if (list_empty(&s->devices_list)) { | ||
1088 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1089 | return 0; | ||
1090 | } | ||
1091 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
1092 | list_del(&p_dev->socket_device_list); | ||
1093 | p_dev->client.state |= CLIENT_STALE; | ||
1094 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1095 | |||
1096 | device_unregister(&p_dev->dev); | ||
1097 | } | ||
1098 | |||
1099 | return 0; | ||
1100 | } /* unbind_request */ | ||
1101 | |||
1102 | int pcmcia_deregister_client(client_handle_t handle) | ||
1103 | { | ||
1104 | struct pcmcia_socket *s; | ||
1105 | int i; | ||
1106 | struct pcmcia_device *p_dev = handle_to_pdev(handle); | ||
1107 | |||
1108 | if (CHECK_HANDLE(handle)) | ||
1109 | return CS_BAD_HANDLE; | ||
1110 | |||
1111 | s = SOCKET(handle); | ||
1112 | ds_dbg(1, "deregister_client(%p)\n", handle); | ||
1113 | |||
1114 | if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) | ||
1115 | goto warn_out; | ||
1116 | for (i = 0; i < MAX_WIN; i++) | ||
1117 | if (handle->state & CLIENT_WIN_REQ(i)) | ||
1118 | goto warn_out; | ||
1119 | |||
1120 | if (handle->state & CLIENT_STALE) { | ||
1121 | handle->client_magic = 0; | ||
1122 | handle->state &= ~CLIENT_STALE; | ||
1123 | pcmcia_put_dev(p_dev); | ||
1124 | } else { | ||
1125 | handle->state = CLIENT_UNBOUND; | ||
1126 | handle->event_handler = NULL; | ||
1127 | } | ||
1128 | |||
1129 | return CS_SUCCESS; | ||
1130 | warn_out: | ||
1131 | printk(KERN_WARNING "ds: deregister_client was called too early.\n"); | ||
1132 | return CS_IN_USE; | ||
1133 | } /* deregister_client */ | ||
1134 | EXPORT_SYMBOL(pcmcia_deregister_client); | ||
1135 | |||
1136 | |||
1137 | /*====================================================================== | ||
1138 | |||
1139 | The user-mode PC Card device interface | ||
1140 | |||
1141 | ======================================================================*/ | ||
1142 | |||
1143 | static int ds_open(struct inode *inode, struct file *file) | ||
1144 | { | ||
1145 | socket_t i = iminor(inode); | ||
1146 | struct pcmcia_bus_socket *s; | ||
1147 | user_info_t *user; | ||
1148 | |||
1149 | ds_dbg(0, "ds_open(socket %d)\n", i); | ||
1150 | |||
1151 | s = get_socket_info_by_nr(i); | ||
1152 | if (!s) | ||
1153 | return -ENODEV; | ||
1154 | s = pcmcia_get_bus_socket(s); | ||
1155 | if (!s) | ||
1156 | return -ENODEV; | ||
1157 | |||
1158 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1159 | if (s->state & DS_SOCKET_BUSY) { | ||
1160 | pcmcia_put_bus_socket(s); | ||
1161 | return -EBUSY; | ||
1162 | } | ||
1163 | else | ||
1164 | s->state |= DS_SOCKET_BUSY; | ||
1165 | } | ||
1166 | |||
1167 | user = kmalloc(sizeof(user_info_t), GFP_KERNEL); | ||
1168 | if (!user) { | ||
1169 | pcmcia_put_bus_socket(s); | ||
1170 | return -ENOMEM; | ||
1171 | } | ||
1172 | user->event_tail = user->event_head = 0; | ||
1173 | user->next = s->user; | ||
1174 | user->user_magic = USER_MAGIC; | ||
1175 | user->socket = s; | ||
1176 | s->user = user; | ||
1177 | file->private_data = user; | ||
1178 | |||
1179 | if (s->state & DS_SOCKET_PRESENT) | ||
1180 | queue_event(user, CS_EVENT_CARD_INSERTION); | ||
1181 | return 0; | ||
1182 | } /* ds_open */ | ||
1183 | |||
1184 | /*====================================================================*/ | ||
1185 | |||
1186 | static int ds_release(struct inode *inode, struct file *file) | ||
1187 | { | ||
1188 | struct pcmcia_bus_socket *s; | ||
1189 | user_info_t *user, **link; | ||
1190 | |||
1191 | ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); | ||
1192 | |||
1193 | user = file->private_data; | ||
1194 | if (CHECK_USER(user)) | ||
1195 | goto out; | ||
1196 | |||
1197 | s = user->socket; | ||
1198 | |||
1199 | /* Unlink user data structure */ | ||
1200 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1201 | s->state &= ~DS_SOCKET_BUSY; | ||
1202 | } | ||
1203 | file->private_data = NULL; | ||
1204 | for (link = &s->user; *link; link = &(*link)->next) | ||
1205 | if (*link == user) break; | ||
1206 | if (link == NULL) | ||
1207 | goto out; | ||
1208 | *link = user->next; | ||
1209 | user->user_magic = 0; | ||
1210 | kfree(user); | ||
1211 | pcmcia_put_bus_socket(s); | ||
1212 | out: | ||
1213 | return 0; | ||
1214 | } /* ds_release */ | ||
1215 | |||
1216 | /*====================================================================*/ | ||
1217 | |||
1218 | static ssize_t ds_read(struct file *file, char __user *buf, | ||
1219 | size_t count, loff_t *ppos) | ||
1220 | { | ||
1221 | struct pcmcia_bus_socket *s; | ||
1222 | user_info_t *user; | ||
1223 | int ret; | ||
1224 | |||
1225 | ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1226 | |||
1227 | if (count < 4) | ||
1228 | return -EINVAL; | ||
1229 | |||
1230 | user = file->private_data; | ||
1231 | if (CHECK_USER(user)) | ||
1232 | return -EIO; | ||
1233 | |||
1234 | s = user->socket; | ||
1235 | if (s->state & DS_SOCKET_DEAD) | ||
1236 | return -EIO; | ||
1237 | |||
1238 | ret = wait_event_interruptible(s->queue, !queue_empty(user)); | ||
1239 | if (ret == 0) | ||
1240 | ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4; | ||
1241 | |||
1242 | return ret; | ||
1243 | } /* ds_read */ | ||
1244 | |||
1245 | /*====================================================================*/ | ||
1246 | |||
1247 | static ssize_t ds_write(struct file *file, const char __user *buf, | ||
1248 | size_t count, loff_t *ppos) | ||
1249 | { | ||
1250 | ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1251 | |||
1252 | if (count != 4) | ||
1253 | return -EINVAL; | ||
1254 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) | ||
1255 | return -EBADF; | ||
1256 | |||
1257 | return -EIO; | ||
1258 | } /* ds_write */ | ||
1259 | |||
1260 | /*====================================================================*/ | ||
1261 | |||
1262 | /* No kernel lock - fine */ | ||
1263 | static u_int ds_poll(struct file *file, poll_table *wait) | ||
1264 | { | ||
1265 | struct pcmcia_bus_socket *s; | ||
1266 | user_info_t *user; | ||
1267 | |||
1268 | ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1269 | |||
1270 | user = file->private_data; | ||
1271 | if (CHECK_USER(user)) | ||
1272 | return POLLERR; | ||
1273 | s = user->socket; | ||
1274 | /* | ||
1275 | * We don't check for a dead socket here since that | ||
1276 | * will send cardmgr into an endless spin. | ||
1277 | */ | ||
1278 | poll_wait(file, &s->queue, wait); | ||
1279 | if (!queue_empty(user)) | ||
1280 | return POLLIN | POLLRDNORM; | ||
1281 | return 0; | ||
1282 | } /* ds_poll */ | ||
1283 | |||
1284 | /*====================================================================*/ | ||
1285 | |||
1286 | extern int pcmcia_adjust_resource_info(adjust_t *adj); | ||
1287 | |||
1288 | static int ds_ioctl(struct inode * inode, struct file * file, | ||
1289 | u_int cmd, u_long arg) | ||
1290 | { | ||
1291 | struct pcmcia_bus_socket *s; | ||
1292 | void __user *uarg = (char __user *)arg; | ||
1293 | u_int size; | ||
1294 | int ret, err; | ||
1295 | ds_ioctl_arg_t *buf; | ||
1296 | user_info_t *user; | ||
1297 | |||
1298 | ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); | ||
1299 | |||
1300 | user = file->private_data; | ||
1301 | if (CHECK_USER(user)) | ||
1302 | return -EIO; | ||
1303 | |||
1304 | s = user->socket; | ||
1305 | if (s->state & DS_SOCKET_DEAD) | ||
1306 | return -EIO; | ||
1307 | |||
1308 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; | ||
1309 | if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; | ||
1310 | |||
1311 | /* Permission check */ | ||
1312 | if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) | ||
1313 | return -EPERM; | ||
1314 | |||
1315 | if (cmd & IOC_IN) { | ||
1316 | if (!access_ok(VERIFY_READ, uarg, size)) { | ||
1317 | ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT); | ||
1318 | return -EFAULT; | ||
1319 | } | ||
1320 | } | ||
1321 | if (cmd & IOC_OUT) { | ||
1322 | if (!access_ok(VERIFY_WRITE, uarg, size)) { | ||
1323 | ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT); | ||
1324 | return -EFAULT; | ||
1325 | } | ||
1326 | } | ||
1327 | buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL); | ||
1328 | if (!buf) | ||
1329 | return -ENOMEM; | ||
1330 | |||
1331 | err = ret = 0; | ||
1332 | |||
1333 | if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size); | ||
1334 | |||
1335 | switch (cmd) { | ||
1336 | case DS_ADJUST_RESOURCE_INFO: | ||
1337 | ret = pcmcia_adjust_resource_info(&buf->adjust); | ||
1338 | break; | ||
1339 | case DS_GET_CARD_SERVICES_INFO: | ||
1340 | ret = pcmcia_get_card_services_info(&buf->servinfo); | ||
1341 | break; | ||
1342 | case DS_GET_CONFIGURATION_INFO: | ||
1343 | if (buf->config.Function && | ||
1344 | (buf->config.Function >= s->parent->functions)) | ||
1345 | ret = CS_BAD_ARGS; | ||
1346 | else | ||
1347 | ret = pccard_get_configuration_info(s->parent, | ||
1348 | buf->config.Function, &buf->config); | ||
1349 | break; | ||
1350 | case DS_GET_FIRST_TUPLE: | ||
1351 | down(&s->parent->skt_sem); | ||
1352 | pcmcia_validate_mem(s->parent); | ||
1353 | up(&s->parent->skt_sem); | ||
1354 | ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple); | ||
1355 | break; | ||
1356 | case DS_GET_NEXT_TUPLE: | ||
1357 | ret = pccard_get_next_tuple(s->parent, BIND_FN_ALL, &buf->tuple); | ||
1358 | break; | ||
1359 | case DS_GET_TUPLE_DATA: | ||
1360 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
1361 | buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data); | ||
1362 | ret = pccard_get_tuple_data(s->parent, &buf->tuple); | ||
1363 | break; | ||
1364 | case DS_PARSE_TUPLE: | ||
1365 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
1366 | ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse); | ||
1367 | break; | ||
1368 | case DS_RESET_CARD: | ||
1369 | ret = pccard_reset_card(s->parent); | ||
1370 | break; | ||
1371 | case DS_GET_STATUS: | ||
1372 | if (buf->status.Function && | ||
1373 | (buf->status.Function >= s->parent->functions)) | ||
1374 | ret = CS_BAD_ARGS; | ||
1375 | else | ||
1376 | ret = pccard_get_status(s->parent, buf->status.Function, &buf->status); | ||
1377 | break; | ||
1378 | case DS_VALIDATE_CIS: | ||
1379 | down(&s->parent->skt_sem); | ||
1380 | pcmcia_validate_mem(s->parent); | ||
1381 | up(&s->parent->skt_sem); | ||
1382 | ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo); | ||
1383 | break; | ||
1384 | case DS_SUSPEND_CARD: | ||
1385 | ret = pcmcia_suspend_card(s->parent); | ||
1386 | break; | ||
1387 | case DS_RESUME_CARD: | ||
1388 | ret = pcmcia_resume_card(s->parent); | ||
1389 | break; | ||
1390 | case DS_EJECT_CARD: | ||
1391 | err = pcmcia_eject_card(s->parent); | ||
1392 | break; | ||
1393 | case DS_INSERT_CARD: | ||
1394 | err = pcmcia_insert_card(s->parent); | ||
1395 | break; | ||
1396 | case DS_ACCESS_CONFIGURATION_REGISTER: | ||
1397 | if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) { | ||
1398 | err = -EPERM; | ||
1399 | goto free_out; | ||
1400 | } | ||
1401 | if (buf->conf_reg.Function && | ||
1402 | (buf->conf_reg.Function >= s->parent->functions)) | ||
1403 | ret = CS_BAD_ARGS; | ||
1404 | else | ||
1405 | ret = pccard_access_configuration_register(s->parent, | ||
1406 | buf->conf_reg.Function, &buf->conf_reg); | ||
1407 | break; | ||
1408 | case DS_GET_FIRST_REGION: | ||
1409 | case DS_GET_NEXT_REGION: | ||
1410 | case DS_BIND_MTD: | ||
1411 | if (!capable(CAP_SYS_ADMIN)) { | ||
1412 | err = -EPERM; | ||
1413 | goto free_out; | ||
1414 | } else { | ||
1415 | static int printed = 0; | ||
1416 | if (!printed) { | ||
1417 | printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); | ||
1418 | printk(KERN_WARNING "MTD handling any more.\n"); | ||
1419 | printed++; | ||
1420 | } | ||
1421 | } | ||
1422 | err = -EINVAL; | ||
1423 | goto free_out; | ||
1424 | break; | ||
1425 | case DS_GET_FIRST_WINDOW: | ||
1426 | ret = pcmcia_get_window(s->parent, &buf->win_info.handle, 0, | ||
1427 | &buf->win_info.window); | ||
1428 | break; | ||
1429 | case DS_GET_NEXT_WINDOW: | ||
1430 | ret = pcmcia_get_window(s->parent, &buf->win_info.handle, | ||
1431 | buf->win_info.handle->index + 1, &buf->win_info.window); | ||
1432 | break; | ||
1433 | case DS_GET_MEM_PAGE: | ||
1434 | ret = pcmcia_get_mem_page(buf->win_info.handle, | ||
1435 | &buf->win_info.map); | ||
1436 | break; | ||
1437 | case DS_REPLACE_CIS: | ||
1438 | ret = pcmcia_replace_cis(s->parent, &buf->cisdump); | ||
1439 | break; | ||
1440 | case DS_BIND_REQUEST: | ||
1441 | if (!capable(CAP_SYS_ADMIN)) { | ||
1442 | err = -EPERM; | ||
1443 | goto free_out; | ||
1444 | } | ||
1445 | err = bind_request(s, &buf->bind_info); | ||
1446 | break; | ||
1447 | case DS_GET_DEVICE_INFO: | ||
1448 | err = get_device_info(s, &buf->bind_info, 1); | ||
1449 | break; | ||
1450 | case DS_GET_NEXT_DEVICE: | ||
1451 | err = get_device_info(s, &buf->bind_info, 0); | ||
1452 | break; | ||
1453 | case DS_UNBIND_REQUEST: | ||
1454 | err = 0; | ||
1455 | break; | ||
1456 | default: | ||
1457 | err = -EINVAL; | ||
1458 | } | ||
1459 | |||
1460 | if ((err == 0) && (ret != CS_SUCCESS)) { | ||
1461 | ds_dbg(2, "ds_ioctl: ret = %d\n", ret); | ||
1462 | switch (ret) { | ||
1463 | case CS_BAD_SOCKET: case CS_NO_CARD: | ||
1464 | err = -ENODEV; break; | ||
1465 | case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: | ||
1466 | case CS_BAD_TUPLE: | ||
1467 | err = -EINVAL; break; | ||
1468 | case CS_IN_USE: | ||
1469 | err = -EBUSY; break; | ||
1470 | case CS_OUT_OF_RESOURCE: | ||
1471 | err = -ENOSPC; break; | ||
1472 | case CS_NO_MORE_ITEMS: | ||
1473 | err = -ENODATA; break; | ||
1474 | case CS_UNSUPPORTED_FUNCTION: | ||
1475 | err = -ENOSYS; break; | ||
1476 | default: | ||
1477 | err = -EIO; break; | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | if (cmd & IOC_OUT) { | ||
1482 | if (__copy_to_user(uarg, (char *)buf, size)) | ||
1483 | err = -EFAULT; | ||
1484 | } | ||
1485 | |||
1486 | free_out: | ||
1487 | kfree(buf); | ||
1488 | return err; | ||
1489 | } /* ds_ioctl */ | ||
1490 | |||
1491 | /*====================================================================*/ | ||
1492 | |||
1493 | static struct file_operations ds_fops = { | ||
1494 | .owner = THIS_MODULE, | ||
1495 | .open = ds_open, | ||
1496 | .release = ds_release, | ||
1497 | .ioctl = ds_ioctl, | ||
1498 | .read = ds_read, | ||
1499 | .write = ds_write, | ||
1500 | .poll = ds_poll, | ||
1501 | }; | ||
1502 | |||
1503 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) | ||
1504 | { | ||
1505 | struct pcmcia_socket *socket = class_get_devdata(class_dev); | ||
1506 | struct pcmcia_bus_socket *s; | ||
1507 | int ret; | ||
1508 | |||
1509 | s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL); | ||
1510 | if(!s) | ||
1511 | return -ENOMEM; | ||
1512 | memset(s, 0, sizeof(struct pcmcia_bus_socket)); | ||
1513 | |||
1514 | /* get reference to parent socket */ | ||
1515 | s->parent = pcmcia_get_socket(socket); | ||
1516 | if (!s->parent) { | ||
1517 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket); | ||
1518 | kfree (s); | ||
1519 | return -ENODEV; | ||
1520 | } | ||
1521 | |||
1522 | kref_init(&s->refcount); | ||
1523 | |||
1524 | /* | ||
1525 | * Ugly. But we want to wait for the socket threads to have started up. | ||
1526 | * We really should let the drivers themselves drive some of this.. | ||
1527 | */ | ||
1528 | msleep(250); | ||
1529 | |||
1530 | init_waitqueue_head(&s->queue); | ||
1531 | INIT_LIST_HEAD(&s->devices_list); | ||
1532 | |||
1533 | /* Set up hotline to Card Services */ | ||
1534 | s->callback.owner = THIS_MODULE; | ||
1535 | s->callback.event = &ds_event; | ||
1536 | s->callback.resources_done = &pcmcia_card_add; | ||
1537 | socket->pcmcia = s; | ||
1538 | |||
1539 | ret = pccard_register_pcmcia(socket, &s->callback); | ||
1540 | if (ret) { | ||
1541 | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); | ||
1542 | pcmcia_put_bus_socket(s); | ||
1543 | socket->pcmcia = NULL; | ||
1544 | return (ret); | ||
1545 | } | ||
1546 | |||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | |||
1551 | static void pcmcia_bus_remove_socket(struct class_device *class_dev) | ||
1552 | { | ||
1553 | struct pcmcia_socket *socket = class_get_devdata(class_dev); | ||
1554 | |||
1555 | if (!socket || !socket->pcmcia) | ||
1556 | return; | ||
1557 | |||
1558 | pccard_register_pcmcia(socket, NULL); | ||
1559 | |||
1560 | socket->pcmcia->state |= DS_SOCKET_DEAD; | ||
1561 | pcmcia_put_bus_socket(socket->pcmcia); | ||
1562 | socket->pcmcia = NULL; | ||
1563 | |||
1564 | return; | ||
1565 | } | ||
1566 | |||
1567 | |||
1568 | /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ | ||
1569 | static struct class_interface pcmcia_bus_interface = { | ||
1570 | .class = &pcmcia_socket_class, | ||
1571 | .add = &pcmcia_bus_add_socket, | ||
1572 | .remove = &pcmcia_bus_remove_socket, | ||
1573 | }; | ||
1574 | |||
1575 | |||
1576 | struct bus_type pcmcia_bus_type = { | ||
1577 | .name = "pcmcia", | ||
1578 | .match = pcmcia_bus_match, | ||
1579 | .dev_attrs = pcmcia_dev_attrs, | ||
1580 | }; | ||
1581 | EXPORT_SYMBOL(pcmcia_bus_type); | ||
1582 | |||
1583 | |||
1584 | static int __init init_pcmcia_bus(void) | ||
1585 | { | ||
1586 | int i; | ||
1587 | |||
1588 | spin_lock_init(&pcmcia_dev_list_lock); | ||
1589 | |||
1590 | bus_register(&pcmcia_bus_type); | ||
1591 | class_interface_register(&pcmcia_bus_interface); | ||
1592 | |||
1593 | /* Set up character device for user mode clients */ | ||
1594 | i = register_chrdev(0, "pcmcia", &ds_fops); | ||
1595 | if (i == -EBUSY) | ||
1596 | printk(KERN_NOTICE "unable to find a free device # for " | ||
1597 | "Driver Services\n"); | ||
1598 | else | ||
1599 | major_dev = i; | ||
1600 | |||
1601 | #ifdef CONFIG_PROC_FS | ||
1602 | proc_pccard = proc_mkdir("pccard", proc_bus); | ||
1603 | if (proc_pccard) | ||
1604 | create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); | ||
1605 | #endif | ||
1606 | |||
1607 | return 0; | ||
1608 | } | ||
1609 | fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that | ||
1610 | * pcmcia_socket_class is already registered */ | ||
1611 | |||
1612 | |||
1613 | static void __exit exit_pcmcia_bus(void) | ||
1614 | { | ||
1615 | class_interface_unregister(&pcmcia_bus_interface); | ||
1616 | |||
1617 | #ifdef CONFIG_PROC_FS | ||
1618 | if (proc_pccard) { | ||
1619 | remove_proc_entry("drivers", proc_pccard); | ||
1620 | remove_proc_entry("pccard", proc_bus); | ||
1621 | } | ||
1622 | #endif | ||
1623 | if (major_dev != -1) | ||
1624 | unregister_chrdev(major_dev, "pcmcia"); | ||
1625 | |||
1626 | bus_unregister(&pcmcia_bus_type); | ||
1627 | } | ||
1628 | module_exit(exit_pcmcia_bus); | ||
1629 | |||
1630 | |||
1631 | |||
1632 | /* helpers for backwards-compatible functions */ | ||
1633 | |||
1634 | static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr) | ||
1635 | { | ||
1636 | struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr); | ||
1637 | if (s && s->pcmcia) | ||
1638 | return s->pcmcia; | ||
1639 | else | ||
1640 | return NULL; | ||
1641 | } | ||
1642 | |||
1643 | /* backwards-compatible accessing of driver --- by name! */ | ||
1644 | |||
1645 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info) | ||
1646 | { | ||
1647 | struct device_driver *drv; | ||
1648 | struct pcmcia_driver *p_drv; | ||
1649 | |||
1650 | drv = driver_find((char *) dev_info, &pcmcia_bus_type); | ||
1651 | if (!drv) | ||
1652 | return NULL; | ||
1653 | |||
1654 | p_drv = container_of(drv, struct pcmcia_driver, drv); | ||
1655 | |||
1656 | return (p_drv); | ||
1657 | } | ||
1658 | |||
1659 | MODULE_ALIAS("ds"); | ||
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c new file mode 100644 index 000000000000..5e6c4ba7d995 --- /dev/null +++ b/drivers/pcmcia/hd64465_ss.c | |||
@@ -0,0 +1,968 @@ | |||
1 | /* | ||
2 | * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $ | ||
3 | * | ||
4 | * Device driver for the PCMCIA controller module of the | ||
5 | * Hitachi HD64465 handheld companion chip. | ||
6 | * | ||
7 | * Note that the HD64465 provides a very thin PCMCIA host bridge | ||
8 | * layer, requiring a lot of the work of supporting cards to be | ||
9 | * performed by the processor. For example: mapping of card | ||
10 | * interrupts to processor IRQs is done by IRQ demuxing software; | ||
11 | * IO and memory mappings are fixed; setting voltages according | ||
12 | * to card Voltage Select pins etc is done in software. | ||
13 | * | ||
14 | * Note also that this driver uses only the simple, fixed, | ||
15 | * 16MB, 16-bit wide mappings to PCMCIA spaces defined by the | ||
16 | * HD64465. Larger mappings, smaller mappings, or mappings of | ||
17 | * different width to the same socket, are all possible only by | ||
18 | * involving the SH7750's MMU, which is considered unnecessary here. | ||
19 | * The downside is that it may be possible for some drivers to | ||
20 | * break because they need or expect 8-bit mappings. | ||
21 | * | ||
22 | * This driver currently supports only the following configuration: | ||
23 | * SH7750 CPU, HD64465, TPS2206 voltage control chip. | ||
24 | * | ||
25 | * by Greg Banks <gbanks@pocketpenguins.com> | ||
26 | * (c) 2000 PocketPenguins Inc | ||
27 | */ | ||
28 | |||
29 | #include <linux/types.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/vmalloc.h> | ||
37 | #include <asm/errno.h> | ||
38 | #include <linux/irq.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/device.h> | ||
41 | |||
42 | #include <asm/io.h> | ||
43 | #include <asm/hd64465/hd64465.h> | ||
44 | #include <asm/hd64465/io.h> | ||
45 | |||
46 | #include <pcmcia/version.h> | ||
47 | #include <pcmcia/cs_types.h> | ||
48 | #include <pcmcia/cs.h> | ||
49 | #include <pcmcia/cistpl.h> | ||
50 | #include <pcmcia/ds.h> | ||
51 | #include <pcmcia/ss.h> | ||
52 | #include <pcmcia/bulkmem.h> | ||
53 | #include "cs_internal.h" | ||
54 | |||
55 | #define MODNAME "hd64465_ss" | ||
56 | |||
57 | /* #define HD64465_DEBUG 1 */ | ||
58 | |||
59 | #if HD64465_DEBUG | ||
60 | #define DPRINTK(args...) printk(MODNAME ": " args) | ||
61 | #else | ||
62 | #define DPRINTK(args...) | ||
63 | #endif | ||
64 | |||
65 | extern int hd64465_io_debug; | ||
66 | extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); | ||
67 | extern void p3_iounmap(void *addr); | ||
68 | |||
69 | /*============================================================*/ | ||
70 | |||
71 | #define HS_IO_MAP_SIZE (64*1024) | ||
72 | |||
73 | typedef struct hs_socket_t | ||
74 | { | ||
75 | unsigned int number; | ||
76 | u_int irq; | ||
77 | u_long mem_base; | ||
78 | void *io_base; | ||
79 | u_long mem_length; | ||
80 | u_int ctrl_base; | ||
81 | socket_state_t state; | ||
82 | pccard_io_map io_maps[MAX_IO_WIN]; | ||
83 | pccard_mem_map mem_maps[MAX_WIN]; | ||
84 | struct pcmcia_socket socket; | ||
85 | } hs_socket_t; | ||
86 | |||
87 | |||
88 | |||
89 | #define HS_MAX_SOCKETS 2 | ||
90 | static hs_socket_t hs_sockets[HS_MAX_SOCKETS]; | ||
91 | |||
92 | #define hs_in(sp, r) inb((sp)->ctrl_base + (r)) | ||
93 | #define hs_out(sp, v, r) outb(v, (sp)->ctrl_base + (r)) | ||
94 | |||
95 | |||
96 | /* translate a boolean value to a bit in a register */ | ||
97 | #define bool_to_regbit(sp, r, bi, bo) \ | ||
98 | do { \ | ||
99 | unsigned short v = hs_in(sp, r); \ | ||
100 | if (bo) \ | ||
101 | v |= (bi); \ | ||
102 | else \ | ||
103 | v &= ~(bi); \ | ||
104 | hs_out(sp, v, r); \ | ||
105 | } while(0) | ||
106 | |||
107 | /* register offsets from HD64465_REG_PCC[01]ISR */ | ||
108 | #define ISR 0x0 | ||
109 | #define GCR 0x2 | ||
110 | #define CSCR 0x4 | ||
111 | #define CSCIER 0x6 | ||
112 | #define SCR 0x8 | ||
113 | |||
114 | |||
115 | /* Mask and values for CSCIER register */ | ||
116 | #define IER_MASK 0x80 | ||
117 | #define IER_ON 0x3f /* interrupts on */ | ||
118 | #define IER_OFF 0x00 /* interrupts off */ | ||
119 | |||
120 | /*============================================================*/ | ||
121 | |||
122 | #if HD64465_DEBUG > 10 | ||
123 | |||
124 | static void cis_hex_dump(const unsigned char *x, int len) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | for (i=0 ; i<len ; i++) | ||
129 | { | ||
130 | if (!(i & 0xf)) | ||
131 | printk("\n%08x", (unsigned)(x + i)); | ||
132 | printk(" %02x", *(volatile unsigned short*)x); | ||
133 | x += 2; | ||
134 | } | ||
135 | printk("\n"); | ||
136 | } | ||
137 | |||
138 | #endif | ||
139 | /*============================================================*/ | ||
140 | |||
141 | /* | ||
142 | * This code helps create the illusion that the IREQ line from | ||
143 | * the PC card is mapped to one of the CPU's IRQ lines by the | ||
144 | * host bridge hardware (which is how every host bridge *except* | ||
145 | * the HD64465 works). In particular, it supports enabling | ||
146 | * and disabling the IREQ line by code which knows nothing | ||
147 | * about the host bridge (e.g. device drivers, IDE code) using | ||
148 | * the request_irq(), free_irq(), probe_irq_on() and probe_irq_off() | ||
149 | * functions. Also, it supports sharing the mapped IRQ with | ||
150 | * real hardware IRQs from the -IRL0-3 lines. | ||
151 | */ | ||
152 | |||
153 | #define HS_NUM_MAPPED_IRQS 16 /* Limitation of the PCMCIA code */ | ||
154 | static struct | ||
155 | { | ||
156 | /* index is mapped irq number */ | ||
157 | hs_socket_t *sock; | ||
158 | hw_irq_controller *old_handler; | ||
159 | } hs_mapped_irq[HS_NUM_MAPPED_IRQS]; | ||
160 | |||
161 | static void hs_socket_enable_ireq(hs_socket_t *sp) | ||
162 | { | ||
163 | unsigned short cscier; | ||
164 | |||
165 | DPRINTK("hs_socket_enable_ireq(sock=%d)\n", sp->number); | ||
166 | |||
167 | cscier = hs_in(sp, CSCIER); | ||
168 | cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; | ||
169 | cscier |= HD64465_PCCCSCIER_PIREQE_LEVEL; | ||
170 | hs_out(sp, cscier, CSCIER); | ||
171 | } | ||
172 | |||
173 | static void hs_socket_disable_ireq(hs_socket_t *sp) | ||
174 | { | ||
175 | unsigned short cscier; | ||
176 | |||
177 | DPRINTK("hs_socket_disable_ireq(sock=%d)\n", sp->number); | ||
178 | |||
179 | cscier = hs_in(sp, CSCIER); | ||
180 | cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; | ||
181 | hs_out(sp, cscier, CSCIER); | ||
182 | } | ||
183 | |||
184 | static unsigned int hs_startup_irq(unsigned int irq) | ||
185 | { | ||
186 | hs_socket_enable_ireq(hs_mapped_irq[irq].sock); | ||
187 | hs_mapped_irq[irq].old_handler->startup(irq); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void hs_shutdown_irq(unsigned int irq) | ||
192 | { | ||
193 | hs_socket_disable_ireq(hs_mapped_irq[irq].sock); | ||
194 | hs_mapped_irq[irq].old_handler->shutdown(irq); | ||
195 | } | ||
196 | |||
197 | static void hs_enable_irq(unsigned int irq) | ||
198 | { | ||
199 | hs_socket_enable_ireq(hs_mapped_irq[irq].sock); | ||
200 | hs_mapped_irq[irq].old_handler->enable(irq); | ||
201 | } | ||
202 | |||
203 | static void hs_disable_irq(unsigned int irq) | ||
204 | { | ||
205 | hs_socket_disable_ireq(hs_mapped_irq[irq].sock); | ||
206 | hs_mapped_irq[irq].old_handler->disable(irq); | ||
207 | } | ||
208 | |||
209 | extern struct hw_interrupt_type no_irq_type; | ||
210 | |||
211 | static void hs_mask_and_ack_irq(unsigned int irq) | ||
212 | { | ||
213 | hs_socket_disable_ireq(hs_mapped_irq[irq].sock); | ||
214 | /* ack_none() spuriously complains about an unexpected IRQ */ | ||
215 | if (hs_mapped_irq[irq].old_handler != &no_irq_type) | ||
216 | hs_mapped_irq[irq].old_handler->ack(irq); | ||
217 | } | ||
218 | |||
219 | static void hs_end_irq(unsigned int irq) | ||
220 | { | ||
221 | hs_socket_enable_ireq(hs_mapped_irq[irq].sock); | ||
222 | hs_mapped_irq[irq].old_handler->end(irq); | ||
223 | } | ||
224 | |||
225 | |||
226 | static struct hw_interrupt_type hd64465_ss_irq_type = { | ||
227 | .typename = "PCMCIA-IRQ", | ||
228 | .startup = hs_startup_irq, | ||
229 | .shutdown = hs_shutdown_irq, | ||
230 | .enable = hs_enable_irq, | ||
231 | .disable = hs_disable_irq, | ||
232 | .ack = hs_mask_and_ack_irq, | ||
233 | .end = hs_end_irq | ||
234 | }; | ||
235 | |||
236 | /* | ||
237 | * This function should only ever be called with interrupts disabled. | ||
238 | */ | ||
239 | static void hs_map_irq(hs_socket_t *sp, unsigned int irq) | ||
240 | { | ||
241 | DPRINTK("hs_map_irq(sock=%d irq=%d)\n", sp->number, irq); | ||
242 | |||
243 | if (irq >= HS_NUM_MAPPED_IRQS) | ||
244 | return; | ||
245 | |||
246 | hs_mapped_irq[irq].sock = sp; | ||
247 | /* insert ourselves as the irq controller */ | ||
248 | hs_mapped_irq[irq].old_handler = irq_desc[irq].handler; | ||
249 | irq_desc[irq].handler = &hd64465_ss_irq_type; | ||
250 | } | ||
251 | |||
252 | |||
253 | /* | ||
254 | * This function should only ever be called with interrupts disabled. | ||
255 | */ | ||
256 | static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq) | ||
257 | { | ||
258 | DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", sp->number, irq); | ||
259 | |||
260 | if (irq >= HS_NUM_MAPPED_IRQS) | ||
261 | return; | ||
262 | |||
263 | /* restore the original irq controller */ | ||
264 | irq_desc[irq].handler = hs_mapped_irq[irq].old_handler; | ||
265 | } | ||
266 | |||
267 | /*============================================================*/ | ||
268 | |||
269 | |||
270 | /* | ||
271 | * Set Vpp and Vcc (in tenths of a Volt). Does not | ||
272 | * support the hi-Z state. | ||
273 | * | ||
274 | * Note, this assumes the board uses a TPS2206 chip to control | ||
275 | * the Vcc and Vpp voltages to the hs_sockets. If your board | ||
276 | * uses the MIC2563 (also supported by the HD64465) then you | ||
277 | * will have to modify this function. | ||
278 | */ | ||
279 | /* 0V 3.3V 5.5V */ | ||
280 | static const u_char hs_tps2206_avcc[3] = { 0x00, 0x04, 0x08 }; | ||
281 | static const u_char hs_tps2206_bvcc[3] = { 0x00, 0x80, 0x40 }; | ||
282 | |||
283 | static int hs_set_voltages(hs_socket_t *sp, int Vcc, int Vpp) | ||
284 | { | ||
285 | u_int psr; | ||
286 | u_int vcci = 0; | ||
287 | u_int sock = sp->number; | ||
288 | |||
289 | DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp); | ||
290 | |||
291 | switch (Vcc) | ||
292 | { | ||
293 | case 0: vcci = 0; break; | ||
294 | case 33: vcci = 1; break; | ||
295 | case 50: vcci = 2; break; | ||
296 | default: return 0; | ||
297 | } | ||
298 | |||
299 | /* Note: Vpp = 120 not supported -- Greg Banks */ | ||
300 | if (Vpp != 0 && Vpp != Vcc) | ||
301 | return 0; | ||
302 | |||
303 | /* The PSR register holds 8 of the 9 bits which control | ||
304 | * the TPS2206 via its serial interface. | ||
305 | */ | ||
306 | psr = inw(HD64465_REG_PCCPSR); | ||
307 | switch (sock) | ||
308 | { | ||
309 | case 0: | ||
310 | psr &= 0x0f; | ||
311 | psr |= hs_tps2206_avcc[vcci]; | ||
312 | psr |= (Vpp == 0 ? 0x00 : 0x02); | ||
313 | break; | ||
314 | case 1: | ||
315 | psr &= 0xf0; | ||
316 | psr |= hs_tps2206_bvcc[vcci]; | ||
317 | psr |= (Vpp == 0 ? 0x00 : 0x20); | ||
318 | break; | ||
319 | }; | ||
320 | outw(psr, HD64465_REG_PCCPSR); | ||
321 | |||
322 | return 1; | ||
323 | } | ||
324 | |||
325 | |||
326 | /*============================================================*/ | ||
327 | |||
328 | /* | ||
329 | * Drive the RESET line to the card. | ||
330 | */ | ||
331 | static void hs_reset_socket(hs_socket_t *sp, int on) | ||
332 | { | ||
333 | unsigned short v; | ||
334 | |||
335 | v = hs_in(sp, GCR); | ||
336 | if (on) | ||
337 | v |= HD64465_PCCGCR_PCCR; | ||
338 | else | ||
339 | v &= ~HD64465_PCCGCR_PCCR; | ||
340 | hs_out(sp, v, GCR); | ||
341 | } | ||
342 | |||
343 | /*============================================================*/ | ||
344 | |||
345 | static int hs_init(struct pcmcia_socket *s) | ||
346 | { | ||
347 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
348 | |||
349 | DPRINTK("hs_init(%d)\n", sp->number); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /*============================================================*/ | ||
355 | |||
356 | |||
357 | static int hs_get_status(struct pcmcia_socket *s, u_int *value) | ||
358 | { | ||
359 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
360 | unsigned int isr; | ||
361 | u_int status = 0; | ||
362 | |||
363 | |||
364 | isr = hs_in(sp, ISR); | ||
365 | |||
366 | /* Card is seated and powered when *both* CD pins are low */ | ||
367 | if ((isr & HD64465_PCCISR_PCD_MASK) == 0) | ||
368 | { | ||
369 | status |= SS_DETECT; /* card present */ | ||
370 | |||
371 | switch (isr & HD64465_PCCISR_PBVD_MASK) | ||
372 | { | ||
373 | case HD64465_PCCISR_PBVD_BATGOOD: | ||
374 | break; | ||
375 | case HD64465_PCCISR_PBVD_BATWARN: | ||
376 | status |= SS_BATWARN; | ||
377 | break; | ||
378 | default: | ||
379 | status |= SS_BATDEAD; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | if (isr & HD64465_PCCISR_PREADY) | ||
384 | status |= SS_READY; | ||
385 | |||
386 | if (isr & HD64465_PCCISR_PMWP) | ||
387 | status |= SS_WRPROT; | ||
388 | |||
389 | /* Voltage Select pins interpreted as per Table 4-5 of the std. | ||
390 | * Assuming we have the TPS2206, the socket is a "Low Voltage | ||
391 | * key, 3.3V and 5V available, no X.XV available". | ||
392 | */ | ||
393 | switch (isr & (HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1)) | ||
394 | { | ||
395 | case HD64465_PCCISR_PVS1: | ||
396 | printk(KERN_NOTICE MODNAME ": cannot handle X.XV card, ignored\n"); | ||
397 | status = 0; | ||
398 | break; | ||
399 | case 0: | ||
400 | case HD64465_PCCISR_PVS2: | ||
401 | /* 3.3V */ | ||
402 | status |= SS_3VCARD; | ||
403 | break; | ||
404 | case HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1: | ||
405 | /* 5V */ | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | /* TODO: SS_POWERON */ | ||
410 | /* TODO: SS_STSCHG */ | ||
411 | } | ||
412 | |||
413 | DPRINTK("hs_get_status(%d) = %x\n", sock, status); | ||
414 | |||
415 | *value = status; | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /*============================================================*/ | ||
420 | |||
421 | static int hs_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
422 | { | ||
423 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
424 | |||
425 | DPRINTK("hs_get_socket(%d)\n", sock); | ||
426 | |||
427 | *state = sp->state; | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | /*============================================================*/ | ||
432 | |||
433 | static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
434 | { | ||
435 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
436 | u_long flags; | ||
437 | u_int changed; | ||
438 | unsigned short cscier; | ||
439 | |||
440 | DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n", | ||
441 | sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq); | ||
442 | |||
443 | local_irq_save(flags); /* Don't want interrupts happening here */ | ||
444 | |||
445 | if (state->Vpp != sp->state.Vpp || | ||
446 | state->Vcc != sp->state.Vcc) { | ||
447 | if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) { | ||
448 | local_irq_restore(flags); | ||
449 | return -EINVAL; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | /* hd64465_io_debug = 1; */ | ||
454 | /* | ||
455 | * Handle changes in the Card Status Change mask, | ||
456 | * by propagating to the CSCR register | ||
457 | */ | ||
458 | changed = sp->state.csc_mask ^ state->csc_mask; | ||
459 | cscier = hs_in(sp, CSCIER); | ||
460 | |||
461 | if (changed & SS_DETECT) { | ||
462 | if (state->csc_mask & SS_DETECT) | ||
463 | cscier |= HD64465_PCCCSCIER_PCDE; | ||
464 | else | ||
465 | cscier &= ~HD64465_PCCCSCIER_PCDE; | ||
466 | } | ||
467 | |||
468 | if (changed & SS_READY) { | ||
469 | if (state->csc_mask & SS_READY) | ||
470 | cscier |= HD64465_PCCCSCIER_PRE; | ||
471 | else | ||
472 | cscier &= ~HD64465_PCCCSCIER_PRE; | ||
473 | } | ||
474 | |||
475 | if (changed & SS_BATDEAD) { | ||
476 | if (state->csc_mask & SS_BATDEAD) | ||
477 | cscier |= HD64465_PCCCSCIER_PBDE; | ||
478 | else | ||
479 | cscier &= ~HD64465_PCCCSCIER_PBDE; | ||
480 | } | ||
481 | |||
482 | if (changed & SS_BATWARN) { | ||
483 | if (state->csc_mask & SS_BATWARN) | ||
484 | cscier |= HD64465_PCCCSCIER_PBWE; | ||
485 | else | ||
486 | cscier &= ~HD64465_PCCCSCIER_PBWE; | ||
487 | } | ||
488 | |||
489 | if (changed & SS_STSCHG) { | ||
490 | if (state->csc_mask & SS_STSCHG) | ||
491 | cscier |= HD64465_PCCCSCIER_PSCE; | ||
492 | else | ||
493 | cscier &= ~HD64465_PCCCSCIER_PSCE; | ||
494 | } | ||
495 | |||
496 | hs_out(sp, cscier, CSCIER); | ||
497 | |||
498 | if (sp->state.io_irq && !state->io_irq) | ||
499 | hs_unmap_irq(sp, sp->state.io_irq); | ||
500 | else if (!sp->state.io_irq && state->io_irq) | ||
501 | hs_map_irq(sp, state->io_irq); | ||
502 | |||
503 | |||
504 | /* | ||
505 | * Handle changes in the flags field, | ||
506 | * by propagating to config registers. | ||
507 | */ | ||
508 | changed = sp->state.flags ^ state->flags; | ||
509 | |||
510 | if (changed & SS_IOCARD) { | ||
511 | DPRINTK("card type: %s\n", | ||
512 | (state->flags & SS_IOCARD ? "i/o" : "memory" )); | ||
513 | bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCT, | ||
514 | state->flags & SS_IOCARD); | ||
515 | } | ||
516 | |||
517 | if (changed & SS_RESET) { | ||
518 | DPRINTK("%s reset card\n", | ||
519 | (state->flags & SS_RESET ? "start" : "stop")); | ||
520 | bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCR, | ||
521 | state->flags & SS_RESET); | ||
522 | } | ||
523 | |||
524 | if (changed & SS_OUTPUT_ENA) { | ||
525 | DPRINTK("%sabling card output\n", | ||
526 | (state->flags & SS_OUTPUT_ENA ? "en" : "dis")); | ||
527 | bool_to_regbit(sp, GCR, HD64465_PCCGCR_PDRV, | ||
528 | state->flags & SS_OUTPUT_ENA); | ||
529 | } | ||
530 | |||
531 | /* TODO: SS_SPKR_ENA */ | ||
532 | |||
533 | /* hd64465_io_debug = 0; */ | ||
534 | sp->state = *state; | ||
535 | |||
536 | local_irq_restore(flags); | ||
537 | |||
538 | #if HD64465_DEBUG > 10 | ||
539 | if (state->flags & SS_OUTPUT_ENA) | ||
540 | cis_hex_dump((const unsigned char*)sp->mem_base, 0x100); | ||
541 | #endif | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | /*============================================================*/ | ||
546 | |||
547 | static int hs_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) | ||
548 | { | ||
549 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
550 | int map = io->map; | ||
551 | int sock = sp->number; | ||
552 | struct pccard_io_map *sio; | ||
553 | pgprot_t prot; | ||
554 | |||
555 | DPRINTK("hs_set_io_map(sock=%d, map=%d, flags=0x%x, speed=%dns, start=%#lx, stop=%#lx)\n", | ||
556 | sock, map, io->flags, io->speed, io->start, io->stop); | ||
557 | if (map >= MAX_IO_WIN) | ||
558 | return -EINVAL; | ||
559 | sio = &sp->io_maps[map]; | ||
560 | |||
561 | /* check for null changes */ | ||
562 | if (io->flags == sio->flags && | ||
563 | io->start == sio->start && | ||
564 | io->stop == sio->stop) | ||
565 | return 0; | ||
566 | |||
567 | if (io->flags & MAP_AUTOSZ) | ||
568 | prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IODYN); | ||
569 | else if (io->flags & MAP_16BIT) | ||
570 | prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO16); | ||
571 | else | ||
572 | prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO8); | ||
573 | |||
574 | /* TODO: handle MAP_USE_WAIT */ | ||
575 | if (io->flags & MAP_USE_WAIT) | ||
576 | printk(KERN_INFO MODNAME ": MAP_USE_WAIT unimplemented\n"); | ||
577 | /* TODO: handle MAP_PREFETCH */ | ||
578 | if (io->flags & MAP_PREFETCH) | ||
579 | printk(KERN_INFO MODNAME ": MAP_PREFETCH unimplemented\n"); | ||
580 | /* TODO: handle MAP_WRPROT */ | ||
581 | if (io->flags & MAP_WRPROT) | ||
582 | printk(KERN_INFO MODNAME ": MAP_WRPROT unimplemented\n"); | ||
583 | /* TODO: handle MAP_0WS */ | ||
584 | if (io->flags & MAP_0WS) | ||
585 | printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n"); | ||
586 | |||
587 | if (io->flags & MAP_ACTIVE) { | ||
588 | unsigned long pstart, psize, paddrbase; | ||
589 | |||
590 | paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW)); | ||
591 | pstart = io->start & PAGE_MASK; | ||
592 | psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart; | ||
593 | |||
594 | /* | ||
595 | * Change PTEs in only that portion of the mapping requested | ||
596 | * by the caller. This means that most of the time, most of | ||
597 | * the PTEs in the io_vma will be unmapped and only the bottom | ||
598 | * page will be mapped. But the code allows for weird cards | ||
599 | * that might want IO ports > 4K. | ||
600 | */ | ||
601 | sp->io_base = p3_ioremap(paddrbase + pstart, psize, pgprot_val(prot)); | ||
602 | |||
603 | /* | ||
604 | * Change the mapping used by inb() outb() etc | ||
605 | */ | ||
606 | hd64465_port_map(io->start, | ||
607 | io->stop - io->start + 1, | ||
608 | (unsigned long)sp->io_base + io->start, 0); | ||
609 | } else { | ||
610 | hd64465_port_unmap(sio->start, sio->stop - sio->start + 1); | ||
611 | p3_iounmap(sp->io_base); | ||
612 | } | ||
613 | |||
614 | *sio = *io; | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | /*============================================================*/ | ||
619 | |||
620 | static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) | ||
621 | { | ||
622 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
623 | struct pccard_mem_map *smem; | ||
624 | int map = mem->map; | ||
625 | unsigned long paddr; | ||
626 | |||
627 | #if 0 | ||
628 | DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, card_start=0x%08x)\n", | ||
629 | sock, map, mem->flags, mem->card_start); | ||
630 | #endif | ||
631 | |||
632 | if (map >= MAX_WIN) | ||
633 | return -EINVAL; | ||
634 | smem = &sp->mem_maps[map]; | ||
635 | |||
636 | paddr = sp->mem_base; /* base of Attribute mapping */ | ||
637 | if (!(mem->flags & MAP_ATTRIB)) | ||
638 | paddr += HD64465_PCC_WINDOW; /* base of Common mapping */ | ||
639 | paddr += mem->card_start; | ||
640 | |||
641 | /* Because we specified SS_CAP_STATIC_MAP, we are obliged | ||
642 | * at this time to report the system address corresponding | ||
643 | * to the card address requested. This is how Socket Services | ||
644 | * queries our fixed mapping. I wish this fact had been | ||
645 | * documented - Greg Banks. | ||
646 | */ | ||
647 | mem->static_start = paddr; | ||
648 | |||
649 | *smem = *mem; | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | /* TODO: do we need to use the MMU to access Common memory ??? */ | ||
655 | |||
656 | /*============================================================*/ | ||
657 | |||
658 | /* | ||
659 | * This function is registered with the HD64465 glue code to do a | ||
660 | * secondary demux step on the PCMCIA interrupts. It handles | ||
661 | * mapping the IREQ request from the card to a standard Linux | ||
662 | * IRQ, as requested by SocketServices. | ||
663 | */ | ||
664 | static int hs_irq_demux(int irq, void *dev) | ||
665 | { | ||
666 | hs_socket_t *sp = (hs_socket_t *)dev; | ||
667 | u_int cscr; | ||
668 | |||
669 | DPRINTK("hs_irq_demux(irq=%d)\n", irq); | ||
670 | |||
671 | if (sp->state.io_irq && | ||
672 | (cscr = hs_in(sp, CSCR)) & HD64465_PCCCSCR_PIREQ) { | ||
673 | cscr &= ~HD64465_PCCCSCR_PIREQ; | ||
674 | hs_out(sp, cscr, CSCR); | ||
675 | return sp->state.io_irq; | ||
676 | } | ||
677 | |||
678 | return irq; | ||
679 | } | ||
680 | |||
681 | /*============================================================*/ | ||
682 | |||
683 | /* | ||
684 | * Interrupt handling routine. | ||
685 | */ | ||
686 | |||
687 | static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
688 | { | ||
689 | hs_socket_t *sp = (hs_socket_t *)dev; | ||
690 | u_int events = 0; | ||
691 | u_int cscr; | ||
692 | |||
693 | |||
694 | cscr = hs_in(sp, CSCR); | ||
695 | |||
696 | DPRINTK("hs_interrupt, cscr=%04x\n", cscr); | ||
697 | |||
698 | /* check for bus-related changes to be reported to Socket Services */ | ||
699 | if (cscr & HD64465_PCCCSCR_PCDC) { | ||
700 | /* double-check for a 16-bit card, as we don't support CardBus */ | ||
701 | if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) { | ||
702 | printk(KERN_NOTICE MODNAME | ||
703 | ": socket %d, card not a supported card type or not inserted correctly\n", | ||
704 | sp->number); | ||
705 | /* Don't do the rest unless a card is present */ | ||
706 | cscr &= ~(HD64465_PCCCSCR_PCDC| | ||
707 | HD64465_PCCCSCR_PRC| | ||
708 | HD64465_PCCCSCR_PBW| | ||
709 | HD64465_PCCCSCR_PBD| | ||
710 | HD64465_PCCCSCR_PSC); | ||
711 | } else { | ||
712 | cscr &= ~HD64465_PCCCSCR_PCDC; | ||
713 | events |= SS_DETECT; /* card insertion or removal */ | ||
714 | } | ||
715 | } | ||
716 | if (cscr & HD64465_PCCCSCR_PRC) { | ||
717 | cscr &= ~HD64465_PCCCSCR_PRC; | ||
718 | events |= SS_READY; /* ready signal changed */ | ||
719 | } | ||
720 | if (cscr & HD64465_PCCCSCR_PBW) { | ||
721 | cscr &= ~HD64465_PCCCSCR_PSC; | ||
722 | events |= SS_BATWARN; /* battery warning */ | ||
723 | } | ||
724 | if (cscr & HD64465_PCCCSCR_PBD) { | ||
725 | cscr &= ~HD64465_PCCCSCR_PSC; | ||
726 | events |= SS_BATDEAD; /* battery dead */ | ||
727 | } | ||
728 | if (cscr & HD64465_PCCCSCR_PSC) { | ||
729 | cscr &= ~HD64465_PCCCSCR_PSC; | ||
730 | events |= SS_STSCHG; /* STSCHG (status changed) signal */ | ||
731 | } | ||
732 | |||
733 | if (cscr & HD64465_PCCCSCR_PIREQ) { | ||
734 | cscr &= ~HD64465_PCCCSCR_PIREQ; | ||
735 | |||
736 | /* This should have been dealt with during irq demux */ | ||
737 | printk(KERN_NOTICE MODNAME ": unexpected IREQ from card\n"); | ||
738 | } | ||
739 | |||
740 | hs_out(sp, cscr, CSCR); | ||
741 | |||
742 | if (events) | ||
743 | pcmcia_parse_events(&sp->socket, events); | ||
744 | |||
745 | return IRQ_HANDLED; | ||
746 | } | ||
747 | |||
748 | /*============================================================*/ | ||
749 | |||
750 | static struct pccard_operations hs_operations = { | ||
751 | .init = hs_init, | ||
752 | .get_status = hs_get_status, | ||
753 | .get_socket = hs_get_socket, | ||
754 | .set_socket = hs_set_socket, | ||
755 | .set_io_map = hs_set_io_map, | ||
756 | .set_mem_map = hs_set_mem_map, | ||
757 | }; | ||
758 | |||
759 | static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base, | ||
760 | unsigned int ctrl_base) | ||
761 | { | ||
762 | unsigned short v; | ||
763 | int i, err; | ||
764 | |||
765 | memset(sp, 0, sizeof(*sp)); | ||
766 | sp->irq = irq; | ||
767 | sp->mem_base = mem_base; | ||
768 | sp->mem_length = 4*HD64465_PCC_WINDOW; /* 16MB */ | ||
769 | sp->ctrl_base = ctrl_base; | ||
770 | |||
771 | for (i=0 ; i<MAX_IO_WIN ; i++) | ||
772 | sp->io_maps[i].map = i; | ||
773 | for (i=0 ; i<MAX_WIN ; i++) | ||
774 | sp->mem_maps[i].map = i; | ||
775 | |||
776 | hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp); | ||
777 | |||
778 | if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0) | ||
779 | return err; | ||
780 | if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) { | ||
781 | sp->mem_base = 0; | ||
782 | return -ENOMEM; | ||
783 | } | ||
784 | |||
785 | |||
786 | /* According to section 3.2 of the PCMCIA standard, low-voltage | ||
787 | * capable cards must implement cold insertion, i.e. Vpp and | ||
788 | * Vcc set to 0 before card is inserted. | ||
789 | */ | ||
790 | /*hs_set_voltages(sp, 0, 0);*/ | ||
791 | |||
792 | /* hi-Z the outputs to the card and set 16MB map mode */ | ||
793 | v = hs_in(sp, GCR); | ||
794 | v &= ~HD64465_PCCGCR_PCCT; /* memory-only card */ | ||
795 | hs_out(sp, v, GCR); | ||
796 | |||
797 | v = hs_in(sp, GCR); | ||
798 | v |= HD64465_PCCGCR_PDRV; /* enable outputs to card */ | ||
799 | hs_out(sp, v, GCR); | ||
800 | |||
801 | v = hs_in(sp, GCR); | ||
802 | v |= HD64465_PCCGCR_PMMOD; /* 16MB mapping mode */ | ||
803 | hs_out(sp, v, GCR); | ||
804 | |||
805 | v = hs_in(sp, GCR); | ||
806 | /* lowest 16MB of Common */ | ||
807 | v &= ~(HD64465_PCCGCR_PPA25|HD64465_PCCGCR_PPA24); | ||
808 | hs_out(sp, v, GCR); | ||
809 | |||
810 | hs_reset_socket(sp, 1); | ||
811 | |||
812 | printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d\n", | ||
813 | i, sp->mem_base, sp->irq); | ||
814 | |||
815 | return 0; | ||
816 | } | ||
817 | |||
818 | static void hs_exit_socket(hs_socket_t *sp) | ||
819 | { | ||
820 | unsigned short cscier, gcr; | ||
821 | unsigned long flags; | ||
822 | |||
823 | local_irq_save(flags); | ||
824 | |||
825 | /* turn off interrupts in hardware */ | ||
826 | cscier = hs_in(sp, CSCIER); | ||
827 | cscier = (cscier & IER_MASK) | IER_OFF; | ||
828 | hs_out(sp, cscier, CSCIER); | ||
829 | |||
830 | /* hi-Z the outputs to the card */ | ||
831 | gcr = hs_in(sp, GCR); | ||
832 | gcr &= HD64465_PCCGCR_PDRV; | ||
833 | hs_out(sp, gcr, GCR); | ||
834 | |||
835 | /* power the card down */ | ||
836 | hs_set_voltages(sp, 0, 0); | ||
837 | |||
838 | if (sp->mem_base != 0) | ||
839 | release_mem_region(sp->mem_base, sp->mem_length); | ||
840 | if (sp->irq != 0) { | ||
841 | free_irq(sp->irq, hs_interrupt); | ||
842 | hd64465_unregister_irq_demux(sp->irq); | ||
843 | } | ||
844 | |||
845 | local_irq_restore(flags); | ||
846 | } | ||
847 | |||
848 | static int hd64465_suspend(struct device *dev, u32 state, u32 level) | ||
849 | { | ||
850 | int ret = 0; | ||
851 | if (level == SUSPEND_SAVE_STATE) | ||
852 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
853 | return ret; | ||
854 | } | ||
855 | |||
856 | static int hd64465_resume(struct device *dev, u32 level) | ||
857 | { | ||
858 | int ret = 0; | ||
859 | if (level == RESUME_RESTORE_STATE) | ||
860 | ret = pcmcia_socket_dev_resume(dev); | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | static struct device_driver hd64465_driver = { | ||
865 | .name = "hd64465-pcmcia", | ||
866 | .bus = &platform_bus_type, | ||
867 | .suspend = hd64465_suspend, | ||
868 | .resume = hd64465_resume, | ||
869 | }; | ||
870 | |||
871 | static struct platform_device hd64465_device = { | ||
872 | .name = "hd64465-pcmcia", | ||
873 | .id = 0, | ||
874 | }; | ||
875 | |||
876 | static int __init init_hs(void) | ||
877 | { | ||
878 | int i; | ||
879 | unsigned short v; | ||
880 | |||
881 | /* hd64465_io_debug = 1; */ | ||
882 | if (driver_register(&hd64465_driver)) | ||
883 | return -EINVAL; | ||
884 | |||
885 | /* Wake both sockets out of STANDBY mode */ | ||
886 | /* TODO: wait 15ms */ | ||
887 | v = inw(HD64465_REG_SMSCR); | ||
888 | v &= ~(HD64465_SMSCR_PC0ST|HD64465_SMSCR_PC1ST); | ||
889 | outw(v, HD64465_REG_SMSCR); | ||
890 | |||
891 | /* keep power controller out of shutdown mode */ | ||
892 | v = inb(HD64465_REG_PCC0SCR); | ||
893 | v |= HD64465_PCCSCR_SHDN; | ||
894 | outb(v, HD64465_REG_PCC0SCR); | ||
895 | |||
896 | /* use serial (TPS2206) power controller */ | ||
897 | v = inb(HD64465_REG_PCC0CSCR); | ||
898 | v |= HD64465_PCCCSCR_PSWSEL; | ||
899 | outb(v, HD64465_REG_PCC0CSCR); | ||
900 | |||
901 | /* | ||
902 | * Setup hs_sockets[] structures and request system resources. | ||
903 | * TODO: on memory allocation failure, power down the socket | ||
904 | * before quitting. | ||
905 | */ | ||
906 | for (i=0; i<HS_MAX_SOCKETS; i++) { | ||
907 | hs_set_voltages(&hs_sockets[i], 0, 0); | ||
908 | |||
909 | hs_sockets[i].socket.features |= SS_CAP_PCCARD | SS_CAP_STATIC_MAP; /* mappings are fixed in host memory */ | ||
910 | hs_sockets[i].socket.resource_ops = &pccard_static_ops; | ||
911 | hs_sockets[i].socket.irq_mask = 0xffde;/*0xffff*/ /* IRQs mapped in s/w so can do any, really */ | ||
912 | hs_sockets[i].socket.map_size = HD64465_PCC_WINDOW; /* 16MB fixed window size */ | ||
913 | |||
914 | hs_sockets[i].socket.owner = THIS_MODULE; | ||
915 | hs_sockets[i].socket.ss_entry = &hs_operations; | ||
916 | } | ||
917 | |||
918 | i = hs_init_socket(&hs_sockets[0], | ||
919 | HD64465_IRQ_PCMCIA0, | ||
920 | HD64465_PCC0_BASE, | ||
921 | HD64465_REG_PCC0ISR); | ||
922 | if (i < 0) { | ||
923 | unregister_driver(&hd64465_driver); | ||
924 | return i; | ||
925 | } | ||
926 | i = hs_init_socket(&hs_sockets[1], | ||
927 | HD64465_IRQ_PCMCIA1, | ||
928 | HD64465_PCC1_BASE, | ||
929 | HD64465_REG_PCC1ISR); | ||
930 | if (i < 0) { | ||
931 | unregister_driver(&hd64465_driver); | ||
932 | return i; | ||
933 | } | ||
934 | |||
935 | /* hd64465_io_debug = 0; */ | ||
936 | |||
937 | platform_device_register(&hd64465_device); | ||
938 | |||
939 | for (i=0; i<HS_MAX_SOCKETS; i++) { | ||
940 | unsigned int ret; | ||
941 | hs_sockets[i].socket.dev.dev = &hd64465_device.dev; | ||
942 | hs_sockets[i].number = i; | ||
943 | ret = pcmcia_register_socket(&hs_sockets[i].socket); | ||
944 | if (ret && i) | ||
945 | pcmcia_unregister_socket(&hs_sockets[0].socket); | ||
946 | } | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static void __exit exit_hs(void) | ||
952 | { | ||
953 | int i; | ||
954 | |||
955 | for (i=0 ; i<HS_MAX_SOCKETS ; i++) { | ||
956 | pcmcia_unregister_socket(&hs_sockets[i].socket); | ||
957 | hs_exit_socket(&hs_sockets[i]); | ||
958 | } | ||
959 | |||
960 | platform_device_unregister(&hd64465_device); | ||
961 | unregister_driver(&hd64465_driver); | ||
962 | } | ||
963 | |||
964 | module_init(init_hs); | ||
965 | module_exit(exit_hs); | ||
966 | |||
967 | /*============================================================*/ | ||
968 | /*END*/ | ||
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c new file mode 100644 index 000000000000..f3fdc748659d --- /dev/null +++ b/drivers/pcmcia/i82092.c | |||
@@ -0,0 +1,799 @@ | |||
1 | /* | ||
2 | * Driver for Intel I82092AA PCI-PCMCIA bridge. | ||
3 | * | ||
4 | * (C) 2001 Red Hat, Inc. | ||
5 | * | ||
6 | * Author: Arjan Van De Ven <arjanv@redhat.com> | ||
7 | * Loosly based on i82365.c from the pcmcia-cs package | ||
8 | * | ||
9 | * $Id: i82092aa.c,v 1.2 2001/10/23 14:43:34 arjanv Exp $ | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/device.h> | ||
20 | |||
21 | #include <pcmcia/cs_types.h> | ||
22 | #include <pcmcia/ss.h> | ||
23 | #include <pcmcia/cs.h> | ||
24 | |||
25 | #include <asm/system.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "i82092aa.h" | ||
29 | #include "i82365.h" | ||
30 | |||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* PCI core routines */ | ||
34 | static struct pci_device_id i82092aa_pci_ids[] = { | ||
35 | { | ||
36 | .vendor = PCI_VENDOR_ID_INTEL, | ||
37 | .device = PCI_DEVICE_ID_INTEL_82092AA_0, | ||
38 | .subvendor = PCI_ANY_ID, | ||
39 | .subdevice = PCI_ANY_ID, | ||
40 | }, | ||
41 | {} | ||
42 | }; | ||
43 | MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); | ||
44 | |||
45 | static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state) | ||
46 | { | ||
47 | return pcmcia_socket_dev_suspend(&dev->dev, state); | ||
48 | } | ||
49 | |||
50 | static int i82092aa_socket_resume (struct pci_dev *dev) | ||
51 | { | ||
52 | return pcmcia_socket_dev_resume(&dev->dev); | ||
53 | } | ||
54 | |||
55 | static struct pci_driver i82092aa_pci_drv = { | ||
56 | .name = "i82092aa", | ||
57 | .id_table = i82092aa_pci_ids, | ||
58 | .probe = i82092aa_pci_probe, | ||
59 | .remove = __devexit_p(i82092aa_pci_remove), | ||
60 | .suspend = i82092aa_socket_suspend, | ||
61 | .resume = i82092aa_socket_resume, | ||
62 | }; | ||
63 | |||
64 | |||
65 | /* the pccard structure and its functions */ | ||
66 | static struct pccard_operations i82092aa_operations = { | ||
67 | .init = i82092aa_init, | ||
68 | .get_status = i82092aa_get_status, | ||
69 | .get_socket = i82092aa_get_socket, | ||
70 | .set_socket = i82092aa_set_socket, | ||
71 | .set_io_map = i82092aa_set_io_map, | ||
72 | .set_mem_map = i82092aa_set_mem_map, | ||
73 | }; | ||
74 | |||
75 | /* The card can do upto 4 sockets, allocate a structure for each of them */ | ||
76 | |||
77 | struct socket_info { | ||
78 | int number; | ||
79 | int card_state; /* 0 = no socket, | ||
80 | 1 = empty socket, | ||
81 | 2 = card but not initialized, | ||
82 | 3 = operational card */ | ||
83 | kio_addr_t io_base; /* base io address of the socket */ | ||
84 | |||
85 | struct pcmcia_socket socket; | ||
86 | struct pci_dev *dev; /* The PCI device for the socket */ | ||
87 | }; | ||
88 | |||
89 | #define MAX_SOCKETS 4 | ||
90 | static struct socket_info sockets[MAX_SOCKETS]; | ||
91 | static int socket_count; /* shortcut */ | ||
92 | |||
93 | |||
94 | static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
95 | { | ||
96 | unsigned char configbyte; | ||
97 | int i, ret; | ||
98 | |||
99 | enter("i82092aa_pci_probe"); | ||
100 | |||
101 | if ((ret = pci_enable_device(dev))) | ||
102 | return ret; | ||
103 | |||
104 | pci_read_config_byte(dev, 0x40, &configbyte); /* PCI Configuration Control */ | ||
105 | switch(configbyte&6) { | ||
106 | case 0: | ||
107 | socket_count = 2; | ||
108 | break; | ||
109 | case 2: | ||
110 | socket_count = 1; | ||
111 | break; | ||
112 | case 4: | ||
113 | case 6: | ||
114 | socket_count = 4; | ||
115 | break; | ||
116 | |||
117 | default: | ||
118 | printk(KERN_ERR "i82092aa: Oops, you did something we didn't think of.\n"); | ||
119 | ret = -EIO; | ||
120 | goto err_out_disable; | ||
121 | } | ||
122 | printk(KERN_INFO "i82092aa: configured as a %d socket device.\n", socket_count); | ||
123 | |||
124 | if (!request_region(pci_resource_start(dev, 0), 2, "i82092aa")) { | ||
125 | ret = -EBUSY; | ||
126 | goto err_out_disable; | ||
127 | } | ||
128 | |||
129 | for (i = 0;i<socket_count;i++) { | ||
130 | sockets[i].card_state = 1; /* 1 = present but empty */ | ||
131 | sockets[i].io_base = pci_resource_start(dev, 0); | ||
132 | sockets[i].socket.features |= SS_CAP_PCCARD; | ||
133 | sockets[i].socket.map_size = 0x1000; | ||
134 | sockets[i].socket.irq_mask = 0; | ||
135 | sockets[i].socket.pci_irq = dev->irq; | ||
136 | sockets[i].socket.owner = THIS_MODULE; | ||
137 | |||
138 | sockets[i].number = i; | ||
139 | |||
140 | if (card_present(i)) { | ||
141 | sockets[i].card_state = 3; | ||
142 | dprintk(KERN_DEBUG "i82092aa: slot %i is occupied\n",i); | ||
143 | } else { | ||
144 | dprintk(KERN_DEBUG "i82092aa: slot %i is vacant\n",i); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /* Now, specifiy that all interrupts are to be done as PCI interrupts */ | ||
149 | configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */ | ||
150 | pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */ | ||
151 | |||
152 | /* Register the interrupt handler */ | ||
153 | dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq); | ||
154 | if ((ret = request_irq(dev->irq, i82092aa_interrupt, SA_SHIRQ, "i82092aa", i82092aa_interrupt))) { | ||
155 | printk(KERN_ERR "i82092aa: Failed to register IRQ %d, aborting\n", dev->irq); | ||
156 | goto err_out_free_res; | ||
157 | } | ||
158 | |||
159 | pci_set_drvdata(dev, &sockets[i].socket); | ||
160 | |||
161 | for (i = 0; i<socket_count; i++) { | ||
162 | sockets[i].socket.dev.dev = &dev->dev; | ||
163 | sockets[i].socket.ops = &i82092aa_operations; | ||
164 | sockets[i].socket.resource_ops = &pccard_nonstatic_ops; | ||
165 | ret = pcmcia_register_socket(&sockets[i].socket); | ||
166 | if (ret) { | ||
167 | goto err_out_free_sockets; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | leave("i82092aa_pci_probe"); | ||
172 | return 0; | ||
173 | |||
174 | err_out_free_sockets: | ||
175 | if (i) { | ||
176 | for (i--;i>=0;i--) { | ||
177 | pcmcia_unregister_socket(&sockets[i].socket); | ||
178 | } | ||
179 | } | ||
180 | free_irq(dev->irq, i82092aa_interrupt); | ||
181 | err_out_free_res: | ||
182 | release_region(pci_resource_start(dev, 0), 2); | ||
183 | err_out_disable: | ||
184 | pci_disable_device(dev); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static void __devexit i82092aa_pci_remove(struct pci_dev *dev) | ||
189 | { | ||
190 | struct pcmcia_socket *socket = pci_get_drvdata(dev); | ||
191 | |||
192 | enter("i82092aa_pci_remove"); | ||
193 | |||
194 | free_irq(dev->irq, i82092aa_interrupt); | ||
195 | |||
196 | if (socket) | ||
197 | pcmcia_unregister_socket(socket); | ||
198 | |||
199 | leave("i82092aa_pci_remove"); | ||
200 | } | ||
201 | |||
202 | static DEFINE_SPINLOCK(port_lock); | ||
203 | |||
204 | /* basic value read/write functions */ | ||
205 | |||
206 | static unsigned char indirect_read(int socket, unsigned short reg) | ||
207 | { | ||
208 | unsigned short int port; | ||
209 | unsigned char val; | ||
210 | unsigned long flags; | ||
211 | spin_lock_irqsave(&port_lock,flags); | ||
212 | reg += socket * 0x40; | ||
213 | port = sockets[socket].io_base; | ||
214 | outb(reg,port); | ||
215 | val = inb(port+1); | ||
216 | spin_unlock_irqrestore(&port_lock,flags); | ||
217 | return val; | ||
218 | } | ||
219 | |||
220 | #if 0 | ||
221 | static unsigned short indirect_read16(int socket, unsigned short reg) | ||
222 | { | ||
223 | unsigned short int port; | ||
224 | unsigned short tmp; | ||
225 | unsigned long flags; | ||
226 | spin_lock_irqsave(&port_lock,flags); | ||
227 | reg = reg + socket * 0x40; | ||
228 | port = sockets[socket].io_base; | ||
229 | outb(reg,port); | ||
230 | tmp = inb(port+1); | ||
231 | reg++; | ||
232 | outb(reg,port); | ||
233 | tmp = tmp | (inb(port+1)<<8); | ||
234 | spin_unlock_irqrestore(&port_lock,flags); | ||
235 | return tmp; | ||
236 | } | ||
237 | #endif | ||
238 | |||
239 | static void indirect_write(int socket, unsigned short reg, unsigned char value) | ||
240 | { | ||
241 | unsigned short int port; | ||
242 | unsigned long flags; | ||
243 | spin_lock_irqsave(&port_lock,flags); | ||
244 | reg = reg + socket * 0x40; | ||
245 | port = sockets[socket].io_base; | ||
246 | outb(reg,port); | ||
247 | outb(value,port+1); | ||
248 | spin_unlock_irqrestore(&port_lock,flags); | ||
249 | } | ||
250 | |||
251 | static void indirect_setbit(int socket, unsigned short reg, unsigned char mask) | ||
252 | { | ||
253 | unsigned short int port; | ||
254 | unsigned char val; | ||
255 | unsigned long flags; | ||
256 | spin_lock_irqsave(&port_lock,flags); | ||
257 | reg = reg + socket * 0x40; | ||
258 | port = sockets[socket].io_base; | ||
259 | outb(reg,port); | ||
260 | val = inb(port+1); | ||
261 | val |= mask; | ||
262 | outb(reg,port); | ||
263 | outb(val,port+1); | ||
264 | spin_unlock_irqrestore(&port_lock,flags); | ||
265 | } | ||
266 | |||
267 | |||
268 | static void indirect_resetbit(int socket, unsigned short reg, unsigned char mask) | ||
269 | { | ||
270 | unsigned short int port; | ||
271 | unsigned char val; | ||
272 | unsigned long flags; | ||
273 | spin_lock_irqsave(&port_lock,flags); | ||
274 | reg = reg + socket * 0x40; | ||
275 | port = sockets[socket].io_base; | ||
276 | outb(reg,port); | ||
277 | val = inb(port+1); | ||
278 | val &= ~mask; | ||
279 | outb(reg,port); | ||
280 | outb(val,port+1); | ||
281 | spin_unlock_irqrestore(&port_lock,flags); | ||
282 | } | ||
283 | |||
284 | static void indirect_write16(int socket, unsigned short reg, unsigned short value) | ||
285 | { | ||
286 | unsigned short int port; | ||
287 | unsigned char val; | ||
288 | unsigned long flags; | ||
289 | spin_lock_irqsave(&port_lock,flags); | ||
290 | reg = reg + socket * 0x40; | ||
291 | port = sockets[socket].io_base; | ||
292 | |||
293 | outb(reg,port); | ||
294 | val = value & 255; | ||
295 | outb(val,port+1); | ||
296 | |||
297 | reg++; | ||
298 | |||
299 | outb(reg,port); | ||
300 | val = value>>8; | ||
301 | outb(val,port+1); | ||
302 | spin_unlock_irqrestore(&port_lock,flags); | ||
303 | } | ||
304 | |||
305 | /* simple helper functions */ | ||
306 | /* External clock time, in nanoseconds. 120 ns = 8.33 MHz */ | ||
307 | static int cycle_time = 120; | ||
308 | |||
309 | static int to_cycles(int ns) | ||
310 | { | ||
311 | if (cycle_time!=0) | ||
312 | return ns/cycle_time; | ||
313 | else | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
318 | /* Interrupt handler functionality */ | ||
319 | |||
320 | static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
321 | { | ||
322 | int i; | ||
323 | int loopcount = 0; | ||
324 | int handled = 0; | ||
325 | |||
326 | unsigned int events, active=0; | ||
327 | |||
328 | /* enter("i82092aa_interrupt");*/ | ||
329 | |||
330 | while (1) { | ||
331 | loopcount++; | ||
332 | if (loopcount>20) { | ||
333 | printk(KERN_ERR "i82092aa: infinite eventloop in interrupt \n"); | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | active = 0; | ||
338 | |||
339 | for (i=0;i<socket_count;i++) { | ||
340 | int csc; | ||
341 | if (sockets[i].card_state==0) /* Inactive socket, should not happen */ | ||
342 | continue; | ||
343 | |||
344 | csc = indirect_read(i,I365_CSC); /* card status change register */ | ||
345 | |||
346 | if (csc==0) /* no events on this socket */ | ||
347 | continue; | ||
348 | handled = 1; | ||
349 | events = 0; | ||
350 | |||
351 | if (csc & I365_CSC_DETECT) { | ||
352 | events |= SS_DETECT; | ||
353 | printk("Card detected in socket %i!\n",i); | ||
354 | } | ||
355 | |||
356 | if (indirect_read(i,I365_INTCTL) & I365_PC_IOCARD) { | ||
357 | /* For IO/CARDS, bit 0 means "read the card" */ | ||
358 | events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
359 | } else { | ||
360 | /* Check for battery/ready events */ | ||
361 | events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
362 | events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
363 | events |= (csc & I365_CSC_READY) ? SS_READY : 0; | ||
364 | } | ||
365 | |||
366 | if (events) { | ||
367 | pcmcia_parse_events(&sockets[i].socket, events); | ||
368 | } | ||
369 | active |= events; | ||
370 | } | ||
371 | |||
372 | if (active==0) /* no more events to handle */ | ||
373 | break; | ||
374 | |||
375 | } | ||
376 | return IRQ_RETVAL(handled); | ||
377 | /* leave("i82092aa_interrupt");*/ | ||
378 | } | ||
379 | |||
380 | |||
381 | |||
382 | /* socket functions */ | ||
383 | |||
384 | static int card_present(int socketno) | ||
385 | { | ||
386 | unsigned int val; | ||
387 | enter("card_present"); | ||
388 | |||
389 | if ((socketno<0) || (socketno >= MAX_SOCKETS)) | ||
390 | return 0; | ||
391 | if (sockets[socketno].io_base == 0) | ||
392 | return 0; | ||
393 | |||
394 | |||
395 | val = indirect_read(socketno, 1); /* Interface status register */ | ||
396 | if ((val&12)==12) { | ||
397 | leave("card_present 1"); | ||
398 | return 1; | ||
399 | } | ||
400 | |||
401 | leave("card_present 0"); | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static void set_bridge_state(int sock) | ||
406 | { | ||
407 | enter("set_bridge_state"); | ||
408 | indirect_write(sock, I365_GBLCTL,0x00); | ||
409 | indirect_write(sock, I365_GENCTL,0x00); | ||
410 | |||
411 | indirect_setbit(sock, I365_INTCTL,0x08); | ||
412 | leave("set_bridge_state"); | ||
413 | } | ||
414 | |||
415 | |||
416 | |||
417 | |||
418 | |||
419 | |||
420 | static int i82092aa_init(struct pcmcia_socket *sock) | ||
421 | { | ||
422 | int i; | ||
423 | struct resource res = { .start = 0, .end = 0x0fff }; | ||
424 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
425 | pccard_mem_map mem = { .res = &res, }; | ||
426 | |||
427 | enter("i82092aa_init"); | ||
428 | |||
429 | for (i = 0; i < 2; i++) { | ||
430 | io.map = i; | ||
431 | i82092aa_set_io_map(sock, &io); | ||
432 | } | ||
433 | for (i = 0; i < 5; i++) { | ||
434 | mem.map = i; | ||
435 | i82092aa_set_mem_map(sock, &mem); | ||
436 | } | ||
437 | |||
438 | leave("i82092aa_init"); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value) | ||
443 | { | ||
444 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | ||
445 | unsigned int status; | ||
446 | |||
447 | enter("i82092aa_get_status"); | ||
448 | |||
449 | status = indirect_read(sock,I365_STATUS); /* Interface Status Register */ | ||
450 | *value = 0; | ||
451 | |||
452 | if ((status & I365_CS_DETECT) == I365_CS_DETECT) { | ||
453 | *value |= SS_DETECT; | ||
454 | } | ||
455 | |||
456 | /* IO cards have a different meaning of bits 0,1 */ | ||
457 | /* Also notice the inverse-logic on the bits */ | ||
458 | if (indirect_read(sock, I365_INTCTL) & I365_PC_IOCARD) { | ||
459 | /* IO card */ | ||
460 | if (!(status & I365_CS_STSCHG)) | ||
461 | *value |= SS_STSCHG; | ||
462 | } else { /* non I/O card */ | ||
463 | if (!(status & I365_CS_BVD1)) | ||
464 | *value |= SS_BATDEAD; | ||
465 | if (!(status & I365_CS_BVD2)) | ||
466 | *value |= SS_BATWARN; | ||
467 | |||
468 | } | ||
469 | |||
470 | if (status & I365_CS_WRPROT) | ||
471 | (*value) |= SS_WRPROT; /* card is write protected */ | ||
472 | |||
473 | if (status & I365_CS_READY) | ||
474 | (*value) |= SS_READY; /* card is not busy */ | ||
475 | |||
476 | if (status & I365_CS_POWERON) | ||
477 | (*value) |= SS_POWERON; /* power is applied to the card */ | ||
478 | |||
479 | |||
480 | leave("i82092aa_get_status"); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | |||
485 | static int i82092aa_get_socket(struct pcmcia_socket *socket, socket_state_t *state) | ||
486 | { | ||
487 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | ||
488 | unsigned char reg,vcc,vpp; | ||
489 | |||
490 | enter("i82092aa_get_socket"); | ||
491 | state->flags = 0; | ||
492 | state->Vcc = 0; | ||
493 | state->Vpp = 0; | ||
494 | state->io_irq = 0; | ||
495 | state->csc_mask = 0; | ||
496 | |||
497 | /* First the power status of the socket */ | ||
498 | reg = indirect_read(sock,I365_POWER); /* PCTRL - Power Control Register */ | ||
499 | |||
500 | if (reg & I365_PWR_AUTO) | ||
501 | state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */ | ||
502 | |||
503 | if (reg & I365_PWR_OUT) | ||
504 | state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */ | ||
505 | |||
506 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
507 | |||
508 | if (reg & I365_VCC_5V) { /* Can still be 3.3V, in this case the Vcc value will be overwritten later */ | ||
509 | state->Vcc = 50; | ||
510 | |||
511 | if (vpp == I365_VPP1_5V) | ||
512 | state->Vpp = 50; | ||
513 | if (vpp == I365_VPP1_12V) | ||
514 | state->Vpp = 120; | ||
515 | |||
516 | } | ||
517 | |||
518 | if ((reg & I365_VCC_3V)==I365_VCC_3V) | ||
519 | state->Vcc = 33; | ||
520 | |||
521 | |||
522 | /* Now the IO card, RESET flags and IO interrupt */ | ||
523 | |||
524 | reg = indirect_read(sock, I365_INTCTL); /* IGENC, Interrupt and General Control */ | ||
525 | |||
526 | if ((reg & I365_PC_RESET)==0) | ||
527 | state->flags |= SS_RESET; | ||
528 | if (reg & I365_PC_IOCARD) | ||
529 | state->flags |= SS_IOCARD; /* This is an IO card */ | ||
530 | |||
531 | /* Set the IRQ number */ | ||
532 | if (sockets[sock].dev!=NULL) | ||
533 | state->io_irq = sockets[sock].dev->irq; | ||
534 | |||
535 | /* Card status change */ | ||
536 | reg = indirect_read(sock, I365_CSCINT); /* CSCICR, Card Status Change Interrupt Configuration */ | ||
537 | |||
538 | if (reg & I365_CSC_DETECT) | ||
539 | state->csc_mask |= SS_DETECT; /* Card detect is enabled */ | ||
540 | |||
541 | if (state->flags & SS_IOCARD) {/* IO Cards behave different */ | ||
542 | if (reg & I365_CSC_STSCHG) | ||
543 | state->csc_mask |= SS_STSCHG; | ||
544 | } else { | ||
545 | if (reg & I365_CSC_BVD1) | ||
546 | state->csc_mask |= SS_BATDEAD; | ||
547 | if (reg & I365_CSC_BVD2) | ||
548 | state->csc_mask |= SS_BATWARN; | ||
549 | if (reg & I365_CSC_READY) | ||
550 | state->csc_mask |= SS_READY; | ||
551 | } | ||
552 | |||
553 | leave("i82092aa_get_socket"); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state) | ||
558 | { | ||
559 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | ||
560 | unsigned char reg; | ||
561 | |||
562 | enter("i82092aa_set_socket"); | ||
563 | |||
564 | /* First, set the global controller options */ | ||
565 | |||
566 | set_bridge_state(sock); | ||
567 | |||
568 | /* Values for the IGENC register */ | ||
569 | |||
570 | reg = 0; | ||
571 | if (!(state->flags & SS_RESET)) /* The reset bit has "inverse" logic */ | ||
572 | reg = reg | I365_PC_RESET; | ||
573 | if (state->flags & SS_IOCARD) | ||
574 | reg = reg | I365_PC_IOCARD; | ||
575 | |||
576 | indirect_write(sock,I365_INTCTL,reg); /* IGENC, Interrupt and General Control Register */ | ||
577 | |||
578 | /* Power registers */ | ||
579 | |||
580 | reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */ | ||
581 | |||
582 | if (state->flags & SS_PWR_AUTO) { | ||
583 | printk("Auto power\n"); | ||
584 | reg |= I365_PWR_AUTO; /* automatic power mngmnt */ | ||
585 | } | ||
586 | if (state->flags & SS_OUTPUT_ENA) { | ||
587 | printk("Power Enabled \n"); | ||
588 | reg |= I365_PWR_OUT; /* enable power */ | ||
589 | } | ||
590 | |||
591 | switch (state->Vcc) { | ||
592 | case 0: | ||
593 | break; | ||
594 | case 50: | ||
595 | printk("setting voltage to Vcc to 5V on socket %i\n",sock); | ||
596 | reg |= I365_VCC_5V; | ||
597 | break; | ||
598 | default: | ||
599 | printk("i82092aa: i82092aa_set_socket called with invalid VCC power value: %i ", state->Vcc); | ||
600 | leave("i82092aa_set_socket"); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | |||
604 | |||
605 | switch (state->Vpp) { | ||
606 | case 0: | ||
607 | printk("not setting Vpp on socket %i\n",sock); | ||
608 | break; | ||
609 | case 50: | ||
610 | printk("setting Vpp to 5.0 for socket %i\n",sock); | ||
611 | reg |= I365_VPP1_5V | I365_VPP2_5V; | ||
612 | break; | ||
613 | case 120: | ||
614 | printk("setting Vpp to 12.0\n"); | ||
615 | reg |= I365_VPP1_12V | I365_VPP2_12V; | ||
616 | break; | ||
617 | default: | ||
618 | printk("i82092aa: i82092aa_set_socket called with invalid VPP power value: %i ", state->Vcc); | ||
619 | leave("i82092aa_set_socket"); | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | if (reg != indirect_read(sock,I365_POWER)) /* only write if changed */ | ||
624 | indirect_write(sock,I365_POWER,reg); | ||
625 | |||
626 | /* Enable specific interrupt events */ | ||
627 | |||
628 | reg = 0x00; | ||
629 | if (state->csc_mask & SS_DETECT) { | ||
630 | reg |= I365_CSC_DETECT; | ||
631 | } | ||
632 | if (state->flags & SS_IOCARD) { | ||
633 | if (state->csc_mask & SS_STSCHG) | ||
634 | reg |= I365_CSC_STSCHG; | ||
635 | } else { | ||
636 | if (state->csc_mask & SS_BATDEAD) | ||
637 | reg |= I365_CSC_BVD1; | ||
638 | if (state->csc_mask & SS_BATWARN) | ||
639 | reg |= I365_CSC_BVD2; | ||
640 | if (state->csc_mask & SS_READY) | ||
641 | reg |= I365_CSC_READY; | ||
642 | |||
643 | } | ||
644 | |||
645 | /* now write the value and clear the (probably bogus) pending stuff by doing a dummy read*/ | ||
646 | |||
647 | indirect_write(sock,I365_CSCINT,reg); | ||
648 | (void)indirect_read(sock,I365_CSC); | ||
649 | |||
650 | leave("i82092aa_set_socket"); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io) | ||
655 | { | ||
656 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | ||
657 | unsigned char map, ioctl; | ||
658 | |||
659 | enter("i82092aa_set_io_map"); | ||
660 | |||
661 | map = io->map; | ||
662 | |||
663 | /* Check error conditions */ | ||
664 | if (map > 1) { | ||
665 | leave("i82092aa_set_io_map with invalid map"); | ||
666 | return -EINVAL; | ||
667 | } | ||
668 | if ((io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)){ | ||
669 | leave("i82092aa_set_io_map with invalid io"); | ||
670 | return -EINVAL; | ||
671 | } | ||
672 | |||
673 | /* Turn off the window before changing anything */ | ||
674 | if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_IO(map)) | ||
675 | indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_IO(map)); | ||
676 | |||
677 | /* printk("set_io_map: Setting range to %x - %x \n",io->start,io->stop); */ | ||
678 | |||
679 | /* write the new values */ | ||
680 | indirect_write16(sock,I365_IO(map)+I365_W_START,io->start); | ||
681 | indirect_write16(sock,I365_IO(map)+I365_W_STOP,io->stop); | ||
682 | |||
683 | ioctl = indirect_read(sock,I365_IOCTL) & ~I365_IOCTL_MASK(map); | ||
684 | |||
685 | if (io->flags & (MAP_16BIT|MAP_AUTOSZ)) | ||
686 | ioctl |= I365_IOCTL_16BIT(map); | ||
687 | |||
688 | indirect_write(sock,I365_IOCTL,ioctl); | ||
689 | |||
690 | /* Turn the window back on if needed */ | ||
691 | if (io->flags & MAP_ACTIVE) | ||
692 | indirect_setbit(sock,I365_ADDRWIN,I365_ENA_IO(map)); | ||
693 | |||
694 | leave("i82092aa_set_io_map"); | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem) | ||
699 | { | ||
700 | struct socket_info *sock_info = container_of(socket, struct socket_info, socket); | ||
701 | unsigned int sock = sock_info->number; | ||
702 | struct pci_bus_region region; | ||
703 | unsigned short base, i; | ||
704 | unsigned char map; | ||
705 | |||
706 | enter("i82092aa_set_mem_map"); | ||
707 | |||
708 | pcibios_resource_to_bus(sock_info->dev, ®ion, mem->res); | ||
709 | |||
710 | map = mem->map; | ||
711 | if (map > 4) { | ||
712 | leave("i82092aa_set_mem_map: invalid map"); | ||
713 | return -EINVAL; | ||
714 | } | ||
715 | |||
716 | |||
717 | if ( (mem->card_start > 0x3ffffff) || (region.start > region.end) || | ||
718 | (mem->speed > 1000) ) { | ||
719 | leave("i82092aa_set_mem_map: invalid address / speed"); | ||
720 | printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,region.start, region.end, mem->card_start); | ||
721 | return -EINVAL; | ||
722 | } | ||
723 | |||
724 | /* Turn off the window before changing anything */ | ||
725 | if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) | ||
726 | indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
727 | |||
728 | |||
729 | /* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, region.start,region.end,sock,mem->speed,mem->flags & MAP_ACTIVE); */ | ||
730 | |||
731 | /* write the start address */ | ||
732 | base = I365_MEM(map); | ||
733 | i = (region.start >> 12) & 0x0fff; | ||
734 | if (mem->flags & MAP_16BIT) | ||
735 | i |= I365_MEM_16BIT; | ||
736 | if (mem->flags & MAP_0WS) | ||
737 | i |= I365_MEM_0WS; | ||
738 | indirect_write16(sock,base+I365_W_START,i); | ||
739 | |||
740 | /* write the stop address */ | ||
741 | |||
742 | i= (region.end >> 12) & 0x0fff; | ||
743 | switch (to_cycles(mem->speed)) { | ||
744 | case 0: | ||
745 | break; | ||
746 | case 1: | ||
747 | i |= I365_MEM_WS0; | ||
748 | break; | ||
749 | case 2: | ||
750 | i |= I365_MEM_WS1; | ||
751 | break; | ||
752 | default: | ||
753 | i |= I365_MEM_WS1 | I365_MEM_WS0; | ||
754 | break; | ||
755 | } | ||
756 | |||
757 | indirect_write16(sock,base+I365_W_STOP,i); | ||
758 | |||
759 | /* card start */ | ||
760 | |||
761 | i = ((mem->card_start - region.start) >> 12) & 0x3fff; | ||
762 | if (mem->flags & MAP_WRPROT) | ||
763 | i |= I365_MEM_WRPROT; | ||
764 | if (mem->flags & MAP_ATTRIB) { | ||
765 | /* printk("requesting attribute memory for socket %i\n",sock);*/ | ||
766 | i |= I365_MEM_REG; | ||
767 | } else { | ||
768 | /* printk("requesting normal memory for socket %i\n",sock);*/ | ||
769 | } | ||
770 | indirect_write16(sock,base+I365_W_OFF,i); | ||
771 | |||
772 | /* Enable the window if necessary */ | ||
773 | if (mem->flags & MAP_ACTIVE) | ||
774 | indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
775 | |||
776 | leave("i82092aa_set_mem_map"); | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static int i82092aa_module_init(void) | ||
781 | { | ||
782 | enter("i82092aa_module_init"); | ||
783 | pci_register_driver(&i82092aa_pci_drv); | ||
784 | leave("i82092aa_module_init"); | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static void i82092aa_module_exit(void) | ||
789 | { | ||
790 | enter("i82092aa_module_exit"); | ||
791 | pci_unregister_driver(&i82092aa_pci_drv); | ||
792 | if (sockets[0].io_base>0) | ||
793 | release_region(sockets[0].io_base, 2); | ||
794 | leave("i82092aa_module_exit"); | ||
795 | } | ||
796 | |||
797 | module_init(i82092aa_module_init); | ||
798 | module_exit(i82092aa_module_exit); | ||
799 | |||
diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h new file mode 100644 index 000000000000..b98cac7bda9f --- /dev/null +++ b/drivers/pcmcia/i82092aa.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef _INCLUDE_GUARD_i82092aa_H_ | ||
2 | #define _INCLUDE_GUARD_i82092aa_H_ | ||
3 | |||
4 | #include <linux/interrupt.h> | ||
5 | |||
6 | /* $Id: i82092aa.h,v 1.1.1.1 2001/09/19 14:53:15 dwmw2 Exp $ */ | ||
7 | |||
8 | /* Debuging defines */ | ||
9 | #ifdef NOTRACE | ||
10 | #define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) | ||
11 | #define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__) | ||
12 | #define dprintk(fmt, args...) printk(fmt , ## args) | ||
13 | #else | ||
14 | #define enter(x) do {} while (0) | ||
15 | #define leave(x) do {} while (0) | ||
16 | #define dprintk(fmt, args...) do {} while (0) | ||
17 | #endif | ||
18 | |||
19 | |||
20 | |||
21 | /* prototypes */ | ||
22 | |||
23 | static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); | ||
24 | static void i82092aa_pci_remove(struct pci_dev *dev); | ||
25 | static int card_present(int socketno); | ||
26 | static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs); | ||
27 | |||
28 | |||
29 | |||
30 | |||
31 | static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value); | ||
32 | static int i82092aa_get_socket(struct pcmcia_socket *socket, socket_state_t *state); | ||
33 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state); | ||
34 | static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io); | ||
35 | static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem); | ||
36 | static int i82092aa_init(struct pcmcia_socket *socket); | ||
37 | |||
38 | #endif | ||
39 | |||
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c new file mode 100644 index 000000000000..90a335a5d9fa --- /dev/null +++ b/drivers/pcmcia/i82365.c | |||
@@ -0,0 +1,1454 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for Intel 82365 and compatible PC Card controllers. | ||
4 | |||
5 | i82365.c 1.265 1999/11/10 18:36:21 | ||
6 | |||
7 | The contents of this file are subject to the Mozilla Public | ||
8 | License Version 1.1 (the "License"); you may not use this file | ||
9 | except in compliance with the License. You may obtain a copy of | ||
10 | the License at http://www.mozilla.org/MPL/ | ||
11 | |||
12 | Software distributed under the License is distributed on an "AS | ||
13 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
14 | implied. See the License for the specific language governing | ||
15 | rights and limitations under the License. | ||
16 | |||
17 | The initial developer of the original code is David A. Hinds | ||
18 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
19 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
20 | |||
21 | Alternatively, the contents of this file may be used under the | ||
22 | terms of the GNU General Public License version 2 (the "GPL"), in which | ||
23 | case the provisions of the GPL are applicable instead of the | ||
24 | above. If you wish to allow the use of your version of this file | ||
25 | only under the terms of the GPL and not to allow others to use | ||
26 | your version of this file under the MPL, indicate your decision | ||
27 | by deleting the provisions above and replace them with the notice | ||
28 | and other provisions required by the GPL. If you do not delete | ||
29 | the provisions above, a recipient may use your version of this | ||
30 | file under either the MPL or the GPL. | ||
31 | |||
32 | ======================================================================*/ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/config.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/fcntl.h> | ||
40 | #include <linux/string.h> | ||
41 | #include <linux/kernel.h> | ||
42 | #include <linux/errno.h> | ||
43 | #include <linux/timer.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/ioport.h> | ||
47 | #include <linux/delay.h> | ||
48 | #include <linux/workqueue.h> | ||
49 | #include <linux/interrupt.h> | ||
50 | #include <linux/device.h> | ||
51 | #include <linux/bitops.h> | ||
52 | #include <asm/irq.h> | ||
53 | #include <asm/io.h> | ||
54 | #include <asm/system.h> | ||
55 | |||
56 | #include <pcmcia/version.h> | ||
57 | #include <pcmcia/cs_types.h> | ||
58 | #include <pcmcia/ss.h> | ||
59 | #include <pcmcia/cs.h> | ||
60 | |||
61 | #include <linux/isapnp.h> | ||
62 | |||
63 | /* ISA-bus controllers */ | ||
64 | #include "i82365.h" | ||
65 | #include "cirrus.h" | ||
66 | #include "vg468.h" | ||
67 | #include "ricoh.h" | ||
68 | |||
69 | #ifdef DEBUG | ||
70 | static const char version[] = | ||
71 | "i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)"; | ||
72 | |||
73 | static int pc_debug; | ||
74 | |||
75 | module_param(pc_debug, int, 0644); | ||
76 | |||
77 | #define debug(lvl, fmt, arg...) do { \ | ||
78 | if (pc_debug > (lvl)) \ | ||
79 | printk(KERN_DEBUG "i82365: " fmt , ## arg); \ | ||
80 | } while (0) | ||
81 | #else | ||
82 | #define debug(lvl, fmt, arg...) do { } while (0) | ||
83 | #endif | ||
84 | |||
85 | static irqreturn_t i365_count_irq(int, void *, struct pt_regs *); | ||
86 | static inline int _check_irq(int irq, int flags) | ||
87 | { | ||
88 | if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0) | ||
89 | return -1; | ||
90 | free_irq(irq, i365_count_irq); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /*====================================================================*/ | ||
95 | |||
96 | /* Parameters that can be set with 'insmod' */ | ||
97 | |||
98 | /* Default base address for i82365sl and other ISA chips */ | ||
99 | static unsigned long i365_base = 0x3e0; | ||
100 | /* Should we probe at 0x3e2 for an extra ISA controller? */ | ||
101 | static int extra_sockets = 0; | ||
102 | /* Specify a socket number to ignore */ | ||
103 | static int ignore = -1; | ||
104 | /* Bit map or list of interrupts to choose from */ | ||
105 | static u_int irq_mask = 0xffff; | ||
106 | static int irq_list[16]; | ||
107 | static int irq_list_count; | ||
108 | /* The card status change interrupt -- 0 means autoselect */ | ||
109 | static int cs_irq = 0; | ||
110 | |||
111 | /* Probe for safe interrupts? */ | ||
112 | static int do_scan = 1; | ||
113 | /* Poll status interval -- 0 means default to interrupt */ | ||
114 | static int poll_interval = 0; | ||
115 | /* External clock time, in nanoseconds. 120 ns = 8.33 MHz */ | ||
116 | static int cycle_time = 120; | ||
117 | |||
118 | /* Cirrus options */ | ||
119 | static int has_dma = -1; | ||
120 | static int has_led = -1; | ||
121 | static int has_ring = -1; | ||
122 | static int dynamic_mode = 0; | ||
123 | static int freq_bypass = -1; | ||
124 | static int setup_time = -1; | ||
125 | static int cmd_time = -1; | ||
126 | static int recov_time = -1; | ||
127 | |||
128 | /* Vadem options */ | ||
129 | static int async_clock = -1; | ||
130 | static int cable_mode = -1; | ||
131 | static int wakeup = 0; | ||
132 | |||
133 | module_param(i365_base, ulong, 0444); | ||
134 | module_param(ignore, int, 0444); | ||
135 | module_param(extra_sockets, int, 0444); | ||
136 | module_param(irq_mask, int, 0444); | ||
137 | module_param_array(irq_list, int, &irq_list_count, 0444); | ||
138 | module_param(cs_irq, int, 0444); | ||
139 | module_param(async_clock, int, 0444); | ||
140 | module_param(cable_mode, int, 0444); | ||
141 | module_param(wakeup, int, 0444); | ||
142 | |||
143 | module_param(do_scan, int, 0444); | ||
144 | module_param(poll_interval, int, 0444); | ||
145 | module_param(cycle_time, int, 0444); | ||
146 | module_param(has_dma, int, 0444); | ||
147 | module_param(has_led, int, 0444); | ||
148 | module_param(has_ring, int, 0444); | ||
149 | module_param(dynamic_mode, int, 0444); | ||
150 | module_param(freq_bypass, int, 0444); | ||
151 | module_param(setup_time, int, 0444); | ||
152 | module_param(cmd_time, int, 0444); | ||
153 | module_param(recov_time, int, 0444); | ||
154 | |||
155 | /*====================================================================*/ | ||
156 | |||
157 | typedef struct cirrus_state_t { | ||
158 | u_char misc1, misc2; | ||
159 | u_char timer[6]; | ||
160 | } cirrus_state_t; | ||
161 | |||
162 | typedef struct vg46x_state_t { | ||
163 | u_char ctl, ema; | ||
164 | } vg46x_state_t; | ||
165 | |||
166 | struct i82365_socket { | ||
167 | u_short type, flags; | ||
168 | struct pcmcia_socket socket; | ||
169 | unsigned int number; | ||
170 | kio_addr_t ioaddr; | ||
171 | u_short psock; | ||
172 | u_char cs_irq, intr; | ||
173 | union { | ||
174 | cirrus_state_t cirrus; | ||
175 | vg46x_state_t vg46x; | ||
176 | } state; | ||
177 | }; | ||
178 | |||
179 | /* Where we keep track of our sockets... */ | ||
180 | static int sockets = 0; | ||
181 | static struct i82365_socket socket[8] = { | ||
182 | { 0, }, /* ... */ | ||
183 | }; | ||
184 | |||
185 | /* Default ISA interrupt mask */ | ||
186 | #define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ | ||
187 | |||
188 | static int grab_irq; | ||
189 | static DEFINE_SPINLOCK(isa_lock); | ||
190 | #define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f) | ||
191 | #define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f) | ||
192 | |||
193 | static struct timer_list poll_timer; | ||
194 | |||
195 | /*====================================================================*/ | ||
196 | |||
197 | /* These definitions must match the pcic table! */ | ||
198 | typedef enum pcic_id { | ||
199 | IS_I82365A, IS_I82365B, IS_I82365DF, | ||
200 | IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, | ||
201 | IS_PD6710, IS_PD672X, IS_VT83C469, | ||
202 | } pcic_id; | ||
203 | |||
204 | /* Flags for classifying groups of controllers */ | ||
205 | #define IS_VADEM 0x0001 | ||
206 | #define IS_CIRRUS 0x0002 | ||
207 | #define IS_VIA 0x0010 | ||
208 | #define IS_UNKNOWN 0x0400 | ||
209 | #define IS_VG_PWR 0x0800 | ||
210 | #define IS_DF_PWR 0x1000 | ||
211 | #define IS_REGISTERED 0x2000 | ||
212 | #define IS_ALIVE 0x8000 | ||
213 | |||
214 | typedef struct pcic_t { | ||
215 | char *name; | ||
216 | u_short flags; | ||
217 | } pcic_t; | ||
218 | |||
219 | static pcic_t pcic[] = { | ||
220 | { "Intel i82365sl A step", 0 }, | ||
221 | { "Intel i82365sl B step", 0 }, | ||
222 | { "Intel i82365sl DF", IS_DF_PWR }, | ||
223 | { "IBM Clone", 0 }, | ||
224 | { "Ricoh RF5C296/396", 0 }, | ||
225 | { "VLSI 82C146", 0 }, | ||
226 | { "Vadem VG-468", IS_VADEM }, | ||
227 | { "Vadem VG-469", IS_VADEM|IS_VG_PWR }, | ||
228 | { "Cirrus PD6710", IS_CIRRUS }, | ||
229 | { "Cirrus PD672x", IS_CIRRUS }, | ||
230 | { "VIA VT83C469", IS_CIRRUS|IS_VIA }, | ||
231 | }; | ||
232 | |||
233 | #define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) | ||
234 | |||
235 | /*====================================================================*/ | ||
236 | |||
237 | static DEFINE_SPINLOCK(bus_lock); | ||
238 | |||
239 | static u_char i365_get(u_short sock, u_short reg) | ||
240 | { | ||
241 | unsigned long flags; | ||
242 | spin_lock_irqsave(&bus_lock,flags); | ||
243 | { | ||
244 | kio_addr_t port = socket[sock].ioaddr; | ||
245 | u_char val; | ||
246 | reg = I365_REG(socket[sock].psock, reg); | ||
247 | outb(reg, port); val = inb(port+1); | ||
248 | spin_unlock_irqrestore(&bus_lock,flags); | ||
249 | return val; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void i365_set(u_short sock, u_short reg, u_char data) | ||
254 | { | ||
255 | unsigned long flags; | ||
256 | spin_lock_irqsave(&bus_lock,flags); | ||
257 | { | ||
258 | kio_addr_t port = socket[sock].ioaddr; | ||
259 | u_char val = I365_REG(socket[sock].psock, reg); | ||
260 | outb(val, port); outb(data, port+1); | ||
261 | spin_unlock_irqrestore(&bus_lock,flags); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static void i365_bset(u_short sock, u_short reg, u_char mask) | ||
266 | { | ||
267 | u_char d = i365_get(sock, reg); | ||
268 | d |= mask; | ||
269 | i365_set(sock, reg, d); | ||
270 | } | ||
271 | |||
272 | static void i365_bclr(u_short sock, u_short reg, u_char mask) | ||
273 | { | ||
274 | u_char d = i365_get(sock, reg); | ||
275 | d &= ~mask; | ||
276 | i365_set(sock, reg, d); | ||
277 | } | ||
278 | |||
279 | static void i365_bflip(u_short sock, u_short reg, u_char mask, int b) | ||
280 | { | ||
281 | u_char d = i365_get(sock, reg); | ||
282 | if (b) | ||
283 | d |= mask; | ||
284 | else | ||
285 | d &= ~mask; | ||
286 | i365_set(sock, reg, d); | ||
287 | } | ||
288 | |||
289 | static u_short i365_get_pair(u_short sock, u_short reg) | ||
290 | { | ||
291 | u_short a, b; | ||
292 | a = i365_get(sock, reg); | ||
293 | b = i365_get(sock, reg+1); | ||
294 | return (a + (b<<8)); | ||
295 | } | ||
296 | |||
297 | static void i365_set_pair(u_short sock, u_short reg, u_short data) | ||
298 | { | ||
299 | i365_set(sock, reg, data & 0xff); | ||
300 | i365_set(sock, reg+1, data >> 8); | ||
301 | } | ||
302 | |||
303 | /*====================================================================== | ||
304 | |||
305 | Code to save and restore global state information for Cirrus | ||
306 | PD67xx controllers, and to set and report global configuration | ||
307 | options. | ||
308 | |||
309 | The VIA controllers also use these routines, as they are mostly | ||
310 | Cirrus lookalikes, without the timing registers. | ||
311 | |||
312 | ======================================================================*/ | ||
313 | |||
314 | #define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b)))) | ||
315 | |||
316 | static void cirrus_get_state(u_short s) | ||
317 | { | ||
318 | int i; | ||
319 | cirrus_state_t *p = &socket[s].state.cirrus; | ||
320 | p->misc1 = i365_get(s, PD67_MISC_CTL_1); | ||
321 | p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); | ||
322 | p->misc2 = i365_get(s, PD67_MISC_CTL_2); | ||
323 | for (i = 0; i < 6; i++) | ||
324 | p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i); | ||
325 | } | ||
326 | |||
327 | static void cirrus_set_state(u_short s) | ||
328 | { | ||
329 | int i; | ||
330 | u_char misc; | ||
331 | cirrus_state_t *p = &socket[s].state.cirrus; | ||
332 | |||
333 | misc = i365_get(s, PD67_MISC_CTL_2); | ||
334 | i365_set(s, PD67_MISC_CTL_2, p->misc2); | ||
335 | if (misc & PD67_MC2_SUSPEND) mdelay(50); | ||
336 | misc = i365_get(s, PD67_MISC_CTL_1); | ||
337 | misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); | ||
338 | i365_set(s, PD67_MISC_CTL_1, misc | p->misc1); | ||
339 | for (i = 0; i < 6; i++) | ||
340 | i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]); | ||
341 | } | ||
342 | |||
343 | static u_int __init cirrus_set_opts(u_short s, char *buf) | ||
344 | { | ||
345 | struct i82365_socket *t = &socket[s]; | ||
346 | cirrus_state_t *p = &socket[s].state.cirrus; | ||
347 | u_int mask = 0xffff; | ||
348 | |||
349 | if (has_ring == -1) has_ring = 1; | ||
350 | flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring); | ||
351 | flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode); | ||
352 | flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass); | ||
353 | if (p->misc2 & PD67_MC2_IRQ15_RI) | ||
354 | strcat(buf, " [ring]"); | ||
355 | if (p->misc2 & PD67_MC2_DYNAMIC_MODE) | ||
356 | strcat(buf, " [dyn mode]"); | ||
357 | if (p->misc2 & PD67_MC2_FREQ_BYPASS) | ||
358 | strcat(buf, " [freq bypass]"); | ||
359 | if (p->misc1 & PD67_MC1_INPACK_ENA) | ||
360 | strcat(buf, " [inpack]"); | ||
361 | if (p->misc2 & PD67_MC2_IRQ15_RI) | ||
362 | mask &= ~0x8000; | ||
363 | if (has_led > 0) { | ||
364 | strcat(buf, " [led]"); | ||
365 | mask &= ~0x1000; | ||
366 | } | ||
367 | if (has_dma > 0) { | ||
368 | strcat(buf, " [dma]"); | ||
369 | mask &= ~0x0600; | ||
370 | } | ||
371 | if (!(t->flags & IS_VIA)) { | ||
372 | if (setup_time >= 0) | ||
373 | p->timer[0] = p->timer[3] = setup_time; | ||
374 | if (cmd_time > 0) { | ||
375 | p->timer[1] = cmd_time; | ||
376 | p->timer[4] = cmd_time*2+4; | ||
377 | } | ||
378 | if (p->timer[1] == 0) { | ||
379 | p->timer[1] = 6; p->timer[4] = 16; | ||
380 | if (p->timer[0] == 0) | ||
381 | p->timer[0] = p->timer[3] = 1; | ||
382 | } | ||
383 | if (recov_time >= 0) | ||
384 | p->timer[2] = p->timer[5] = recov_time; | ||
385 | buf += strlen(buf); | ||
386 | sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1], | ||
387 | p->timer[2], p->timer[3], p->timer[4], p->timer[5]); | ||
388 | } | ||
389 | return mask; | ||
390 | } | ||
391 | |||
392 | /*====================================================================== | ||
393 | |||
394 | Code to save and restore global state information for Vadem VG468 | ||
395 | and VG469 controllers, and to set and report global configuration | ||
396 | options. | ||
397 | |||
398 | ======================================================================*/ | ||
399 | |||
400 | static void vg46x_get_state(u_short s) | ||
401 | { | ||
402 | vg46x_state_t *p = &socket[s].state.vg46x; | ||
403 | p->ctl = i365_get(s, VG468_CTL); | ||
404 | if (socket[s].type == IS_VG469) | ||
405 | p->ema = i365_get(s, VG469_EXT_MODE); | ||
406 | } | ||
407 | |||
408 | static void vg46x_set_state(u_short s) | ||
409 | { | ||
410 | vg46x_state_t *p = &socket[s].state.vg46x; | ||
411 | i365_set(s, VG468_CTL, p->ctl); | ||
412 | if (socket[s].type == IS_VG469) | ||
413 | i365_set(s, VG469_EXT_MODE, p->ema); | ||
414 | } | ||
415 | |||
416 | static u_int __init vg46x_set_opts(u_short s, char *buf) | ||
417 | { | ||
418 | vg46x_state_t *p = &socket[s].state.vg46x; | ||
419 | |||
420 | flip(p->ctl, VG468_CTL_ASYNC, async_clock); | ||
421 | flip(p->ema, VG469_MODE_CABLE, cable_mode); | ||
422 | if (p->ctl & VG468_CTL_ASYNC) | ||
423 | strcat(buf, " [async]"); | ||
424 | if (p->ctl & VG468_CTL_INPACK) | ||
425 | strcat(buf, " [inpack]"); | ||
426 | if (socket[s].type == IS_VG469) { | ||
427 | u_char vsel = i365_get(s, VG469_VSELECT); | ||
428 | if (vsel & VG469_VSEL_EXT_STAT) { | ||
429 | strcat(buf, " [ext mode]"); | ||
430 | if (vsel & VG469_VSEL_EXT_BUS) | ||
431 | strcat(buf, " [isa buf]"); | ||
432 | } | ||
433 | if (p->ema & VG469_MODE_CABLE) | ||
434 | strcat(buf, " [cable]"); | ||
435 | if (p->ema & VG469_MODE_COMPAT) | ||
436 | strcat(buf, " [c step]"); | ||
437 | } | ||
438 | return 0xffff; | ||
439 | } | ||
440 | |||
441 | /*====================================================================== | ||
442 | |||
443 | Generic routines to get and set controller options | ||
444 | |||
445 | ======================================================================*/ | ||
446 | |||
447 | static void get_bridge_state(u_short s) | ||
448 | { | ||
449 | struct i82365_socket *t = &socket[s]; | ||
450 | if (t->flags & IS_CIRRUS) | ||
451 | cirrus_get_state(s); | ||
452 | else if (t->flags & IS_VADEM) | ||
453 | vg46x_get_state(s); | ||
454 | } | ||
455 | |||
456 | static void set_bridge_state(u_short s) | ||
457 | { | ||
458 | struct i82365_socket *t = &socket[s]; | ||
459 | if (t->flags & IS_CIRRUS) | ||
460 | cirrus_set_state(s); | ||
461 | else { | ||
462 | i365_set(s, I365_GBLCTL, 0x00); | ||
463 | i365_set(s, I365_GENCTL, 0x00); | ||
464 | } | ||
465 | i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr); | ||
466 | if (t->flags & IS_VADEM) | ||
467 | vg46x_set_state(s); | ||
468 | } | ||
469 | |||
470 | static u_int __init set_bridge_opts(u_short s, u_short ns) | ||
471 | { | ||
472 | u_short i; | ||
473 | u_int m = 0xffff; | ||
474 | char buf[128]; | ||
475 | |||
476 | for (i = s; i < s+ns; i++) { | ||
477 | if (socket[i].flags & IS_ALIVE) { | ||
478 | printk(KERN_INFO " host opts [%d]: already alive!\n", i); | ||
479 | continue; | ||
480 | } | ||
481 | buf[0] = '\0'; | ||
482 | get_bridge_state(i); | ||
483 | if (socket[i].flags & IS_CIRRUS) | ||
484 | m = cirrus_set_opts(i, buf); | ||
485 | else if (socket[i].flags & IS_VADEM) | ||
486 | m = vg46x_set_opts(i, buf); | ||
487 | set_bridge_state(i); | ||
488 | printk(KERN_INFO " host opts [%d]:%s\n", i, | ||
489 | (*buf) ? buf : " none"); | ||
490 | } | ||
491 | return m; | ||
492 | } | ||
493 | |||
494 | /*====================================================================== | ||
495 | |||
496 | Interrupt testing code, for ISA and PCI interrupts | ||
497 | |||
498 | ======================================================================*/ | ||
499 | |||
500 | static volatile u_int irq_hits; | ||
501 | static u_short irq_sock; | ||
502 | |||
503 | static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs) | ||
504 | { | ||
505 | i365_get(irq_sock, I365_CSC); | ||
506 | irq_hits++; | ||
507 | debug(2, "-> hit on irq %d\n", irq); | ||
508 | return IRQ_HANDLED; | ||
509 | } | ||
510 | |||
511 | static u_int __init test_irq(u_short sock, int irq) | ||
512 | { | ||
513 | debug(2, " testing ISA irq %d\n", irq); | ||
514 | if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0) | ||
515 | return 1; | ||
516 | irq_hits = 0; irq_sock = sock; | ||
517 | msleep(10); | ||
518 | if (irq_hits) { | ||
519 | free_irq(irq, i365_count_irq); | ||
520 | debug(2, " spurious hit!\n"); | ||
521 | return 1; | ||
522 | } | ||
523 | |||
524 | /* Generate one interrupt */ | ||
525 | i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4)); | ||
526 | i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); | ||
527 | udelay(1000); | ||
528 | |||
529 | free_irq(irq, i365_count_irq); | ||
530 | |||
531 | /* mask all interrupts */ | ||
532 | i365_set(sock, I365_CSCINT, 0); | ||
533 | debug(2, " hits = %d\n", irq_hits); | ||
534 | |||
535 | return (irq_hits != 1); | ||
536 | } | ||
537 | |||
538 | static u_int __init isa_scan(u_short sock, u_int mask0) | ||
539 | { | ||
540 | u_int mask1 = 0; | ||
541 | int i; | ||
542 | |||
543 | #ifdef __alpha__ | ||
544 | #define PIC 0x4d0 | ||
545 | /* Don't probe level-triggered interrupts -- reserved for PCI */ | ||
546 | mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); | ||
547 | #endif | ||
548 | |||
549 | if (do_scan) { | ||
550 | set_bridge_state(sock); | ||
551 | i365_set(sock, I365_CSCINT, 0); | ||
552 | for (i = 0; i < 16; i++) | ||
553 | if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0)) | ||
554 | mask1 |= (1 << i); | ||
555 | for (i = 0; i < 16; i++) | ||
556 | if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0)) | ||
557 | mask1 ^= (1 << i); | ||
558 | } | ||
559 | |||
560 | printk(KERN_INFO " ISA irqs ("); | ||
561 | if (mask1) { | ||
562 | printk("scanned"); | ||
563 | } else { | ||
564 | /* Fallback: just find interrupts that aren't in use */ | ||
565 | for (i = 0; i < 16; i++) | ||
566 | if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0)) | ||
567 | mask1 |= (1 << i); | ||
568 | printk("default"); | ||
569 | /* If scan failed, default to polled status */ | ||
570 | if (!cs_irq && (poll_interval == 0)) poll_interval = HZ; | ||
571 | } | ||
572 | printk(") = "); | ||
573 | |||
574 | for (i = 0; i < 16; i++) | ||
575 | if (mask1 & (1<<i)) | ||
576 | printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i); | ||
577 | if (mask1 == 0) printk("none!"); | ||
578 | |||
579 | return mask1; | ||
580 | } | ||
581 | |||
582 | /*====================================================================*/ | ||
583 | |||
584 | /* Time conversion functions */ | ||
585 | |||
586 | static int to_cycles(int ns) | ||
587 | { | ||
588 | return ns/cycle_time; | ||
589 | } | ||
590 | |||
591 | /*====================================================================*/ | ||
592 | |||
593 | static int __init identify(kio_addr_t port, u_short sock) | ||
594 | { | ||
595 | u_char val; | ||
596 | int type = -1; | ||
597 | |||
598 | /* Use the next free entry in the socket table */ | ||
599 | socket[sockets].ioaddr = port; | ||
600 | socket[sockets].psock = sock; | ||
601 | |||
602 | /* Wake up a sleepy Cirrus controller */ | ||
603 | if (wakeup) { | ||
604 | i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND); | ||
605 | /* Pause at least 50 ms */ | ||
606 | mdelay(50); | ||
607 | } | ||
608 | |||
609 | if ((val = i365_get(sockets, I365_IDENT)) & 0x70) | ||
610 | return -1; | ||
611 | switch (val) { | ||
612 | case 0x82: | ||
613 | type = IS_I82365A; break; | ||
614 | case 0x83: | ||
615 | type = IS_I82365B; break; | ||
616 | case 0x84: | ||
617 | type = IS_I82365DF; break; | ||
618 | case 0x88: case 0x89: case 0x8a: | ||
619 | type = IS_IBM; break; | ||
620 | } | ||
621 | |||
622 | /* Check for Vadem VG-468 chips */ | ||
623 | outb(0x0e, port); | ||
624 | outb(0x37, port); | ||
625 | i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV); | ||
626 | val = i365_get(sockets, I365_IDENT); | ||
627 | if (val & I365_IDENT_VADEM) { | ||
628 | i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV); | ||
629 | type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468; | ||
630 | } | ||
631 | |||
632 | /* Check for Ricoh chips */ | ||
633 | val = i365_get(sockets, RF5C_CHIP_ID); | ||
634 | if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) | ||
635 | type = IS_RF5Cx96; | ||
636 | |||
637 | /* Check for Cirrus CL-PD67xx chips */ | ||
638 | i365_set(sockets, PD67_CHIP_INFO, 0); | ||
639 | val = i365_get(sockets, PD67_CHIP_INFO); | ||
640 | if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { | ||
641 | val = i365_get(sockets, PD67_CHIP_INFO); | ||
642 | if ((val & PD67_INFO_CHIP_ID) == 0) { | ||
643 | type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710; | ||
644 | i365_set(sockets, PD67_EXT_INDEX, 0xe5); | ||
645 | if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5) | ||
646 | type = IS_VT83C469; | ||
647 | } | ||
648 | } | ||
649 | return type; | ||
650 | } /* identify */ | ||
651 | |||
652 | /*====================================================================== | ||
653 | |||
654 | See if a card is present, powered up, in IO mode, and already | ||
655 | bound to a (non PC Card) Linux driver. We leave these alone. | ||
656 | |||
657 | We make an exception for cards that seem to be serial devices. | ||
658 | |||
659 | ======================================================================*/ | ||
660 | |||
661 | static int __init is_alive(u_short sock) | ||
662 | { | ||
663 | u_char stat; | ||
664 | kio_addr_t start, stop; | ||
665 | |||
666 | stat = i365_get(sock, I365_STATUS); | ||
667 | start = i365_get_pair(sock, I365_IO(0)+I365_W_START); | ||
668 | stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP); | ||
669 | if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && | ||
670 | (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && | ||
671 | (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && | ||
672 | (check_region(start, stop-start+1) != 0) && | ||
673 | ((start & 0xfeef) != 0x02e8)) | ||
674 | return 1; | ||
675 | else | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /*====================================================================*/ | ||
680 | |||
681 | static void __init add_socket(kio_addr_t port, int psock, int type) | ||
682 | { | ||
683 | socket[sockets].ioaddr = port; | ||
684 | socket[sockets].psock = psock; | ||
685 | socket[sockets].type = type; | ||
686 | socket[sockets].flags = pcic[type].flags; | ||
687 | if (is_alive(sockets)) | ||
688 | socket[sockets].flags |= IS_ALIVE; | ||
689 | sockets++; | ||
690 | } | ||
691 | |||
692 | static void __init add_pcic(int ns, int type) | ||
693 | { | ||
694 | u_int mask = 0, i, base; | ||
695 | int isa_irq = 0; | ||
696 | struct i82365_socket *t = &socket[sockets-ns]; | ||
697 | |||
698 | base = sockets-ns; | ||
699 | if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365"); | ||
700 | |||
701 | if (base == 0) printk("\n"); | ||
702 | printk(KERN_INFO " %s", pcic[type].name); | ||
703 | printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x", | ||
704 | t->ioaddr, t->psock*0x40); | ||
705 | printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); | ||
706 | |||
707 | /* Set host options, build basic interrupt mask */ | ||
708 | if (irq_list_count == 0) | ||
709 | mask = irq_mask; | ||
710 | else | ||
711 | for (i = mask = 0; i < irq_list_count; i++) | ||
712 | mask |= (1<<irq_list[i]); | ||
713 | mask &= I365_MASK & set_bridge_opts(base, ns); | ||
714 | /* Scan for ISA interrupts */ | ||
715 | mask = isa_scan(base, mask); | ||
716 | |||
717 | /* Poll if only two interrupts available */ | ||
718 | if (!poll_interval) { | ||
719 | u_int tmp = (mask & 0xff20); | ||
720 | tmp = tmp & (tmp-1); | ||
721 | if ((tmp & (tmp-1)) == 0) | ||
722 | poll_interval = HZ; | ||
723 | } | ||
724 | /* Only try an ISA cs_irq if this is the first controller */ | ||
725 | if (!grab_irq && (cs_irq || !poll_interval)) { | ||
726 | /* Avoid irq 12 unless it is explicitly requested */ | ||
727 | u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); | ||
728 | for (cs_irq = 15; cs_irq > 0; cs_irq--) | ||
729 | if ((cs_mask & (1 << cs_irq)) && | ||
730 | (_check_irq(cs_irq, 0) == 0)) | ||
731 | break; | ||
732 | if (cs_irq) { | ||
733 | grab_irq = 1; | ||
734 | isa_irq = cs_irq; | ||
735 | printk(" status change on irq %d\n", cs_irq); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | if (!isa_irq) { | ||
740 | if (poll_interval == 0) | ||
741 | poll_interval = HZ; | ||
742 | printk(" polling interval = %d ms\n", | ||
743 | poll_interval * 1000 / HZ); | ||
744 | |||
745 | } | ||
746 | |||
747 | /* Update socket interrupt information, capabilities */ | ||
748 | for (i = 0; i < ns; i++) { | ||
749 | t[i].socket.features |= SS_CAP_PCCARD; | ||
750 | t[i].socket.map_size = 0x1000; | ||
751 | t[i].socket.irq_mask = mask; | ||
752 | t[i].cs_irq = isa_irq; | ||
753 | } | ||
754 | |||
755 | } /* add_pcic */ | ||
756 | |||
757 | /*====================================================================*/ | ||
758 | |||
759 | #ifdef CONFIG_PNP | ||
760 | static struct isapnp_device_id id_table[] __initdata = { | ||
761 | { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), | ||
762 | ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" }, | ||
763 | { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), | ||
764 | ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" }, | ||
765 | { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), | ||
766 | ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" }, | ||
767 | { 0 } | ||
768 | }; | ||
769 | MODULE_DEVICE_TABLE(isapnp, id_table); | ||
770 | |||
771 | static struct pnp_dev *i82365_pnpdev; | ||
772 | #endif | ||
773 | |||
774 | static void __init isa_probe(void) | ||
775 | { | ||
776 | int i, j, sock, k, ns, id; | ||
777 | kio_addr_t port; | ||
778 | #ifdef CONFIG_PNP | ||
779 | struct isapnp_device_id *devid; | ||
780 | struct pnp_dev *dev; | ||
781 | |||
782 | for (devid = id_table; devid->vendor; devid++) { | ||
783 | if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) { | ||
784 | |||
785 | if (pnp_device_attach(dev) < 0) | ||
786 | continue; | ||
787 | |||
788 | if (pnp_activate_dev(dev) < 0) { | ||
789 | printk("activate failed\n"); | ||
790 | pnp_device_detach(dev); | ||
791 | break; | ||
792 | } | ||
793 | |||
794 | if (!pnp_port_valid(dev, 0)) { | ||
795 | printk("invalid resources ?\n"); | ||
796 | pnp_device_detach(dev); | ||
797 | break; | ||
798 | } | ||
799 | i365_base = pnp_port_start(dev, 0); | ||
800 | i82365_pnpdev = dev; | ||
801 | break; | ||
802 | } | ||
803 | } | ||
804 | #endif | ||
805 | |||
806 | if (check_region(i365_base, 2) != 0) { | ||
807 | if (sockets == 0) | ||
808 | printk("port conflict at %#lx\n", i365_base); | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | id = identify(i365_base, 0); | ||
813 | if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) { | ||
814 | for (i = 0; i < 4; i++) { | ||
815 | if (i == ignore) continue; | ||
816 | port = i365_base + ((i & 1) << 2) + ((i & 2) << 1); | ||
817 | sock = (i & 1) << 1; | ||
818 | if (identify(port, sock) == IS_I82365DF) { | ||
819 | add_socket(port, sock, IS_VLSI); | ||
820 | add_pcic(1, IS_VLSI); | ||
821 | } | ||
822 | } | ||
823 | } else { | ||
824 | for (i = 0; i < 8; i += 2) { | ||
825 | if (sockets && !extra_sockets && (i == 4)) | ||
826 | break; | ||
827 | port = i365_base + 2*(i>>2); | ||
828 | sock = (i & 3); | ||
829 | id = identify(port, sock); | ||
830 | if (id < 0) continue; | ||
831 | |||
832 | for (j = ns = 0; j < 2; j++) { | ||
833 | /* Does the socket exist? */ | ||
834 | if ((ignore == i+j) || (identify(port, sock+j) < 0)) | ||
835 | continue; | ||
836 | /* Check for bad socket decode */ | ||
837 | for (k = 0; k <= sockets; k++) | ||
838 | i365_set(k, I365_MEM(0)+I365_W_OFF, k); | ||
839 | for (k = 0; k <= sockets; k++) | ||
840 | if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k) | ||
841 | break; | ||
842 | if (k <= sockets) break; | ||
843 | add_socket(port, sock+j, id); ns++; | ||
844 | } | ||
845 | if (ns != 0) add_pcic(ns, id); | ||
846 | } | ||
847 | } | ||
848 | } | ||
849 | |||
850 | /*====================================================================*/ | ||
851 | |||
852 | static irqreturn_t pcic_interrupt(int irq, void *dev, | ||
853 | struct pt_regs *regs) | ||
854 | { | ||
855 | int i, j, csc; | ||
856 | u_int events, active; | ||
857 | u_long flags = 0; | ||
858 | int handled = 0; | ||
859 | |||
860 | debug(4, "pcic_interrupt(%d)\n", irq); | ||
861 | |||
862 | for (j = 0; j < 20; j++) { | ||
863 | active = 0; | ||
864 | for (i = 0; i < sockets; i++) { | ||
865 | if (socket[i].cs_irq != irq) | ||
866 | continue; | ||
867 | handled = 1; | ||
868 | ISA_LOCK(i, flags); | ||
869 | csc = i365_get(i, I365_CSC); | ||
870 | if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) { | ||
871 | ISA_UNLOCK(i, flags); | ||
872 | continue; | ||
873 | } | ||
874 | events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
875 | |||
876 | if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) | ||
877 | events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
878 | else { | ||
879 | events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
880 | events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
881 | events |= (csc & I365_CSC_READY) ? SS_READY : 0; | ||
882 | } | ||
883 | ISA_UNLOCK(i, flags); | ||
884 | debug(2, "socket %d event 0x%02x\n", i, events); | ||
885 | |||
886 | if (events) | ||
887 | pcmcia_parse_events(&socket[i].socket, events); | ||
888 | |||
889 | active |= events; | ||
890 | } | ||
891 | if (!active) break; | ||
892 | } | ||
893 | if (j == 20) | ||
894 | printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n"); | ||
895 | |||
896 | debug(4, "interrupt done\n"); | ||
897 | return IRQ_RETVAL(handled); | ||
898 | } /* pcic_interrupt */ | ||
899 | |||
900 | static void pcic_interrupt_wrapper(u_long data) | ||
901 | { | ||
902 | pcic_interrupt(0, NULL, NULL); | ||
903 | poll_timer.expires = jiffies + poll_interval; | ||
904 | add_timer(&poll_timer); | ||
905 | } | ||
906 | |||
907 | /*====================================================================*/ | ||
908 | |||
909 | static int i365_get_status(u_short sock, u_int *value) | ||
910 | { | ||
911 | u_int status; | ||
912 | |||
913 | status = i365_get(sock, I365_STATUS); | ||
914 | *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) | ||
915 | ? SS_DETECT : 0; | ||
916 | |||
917 | if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) | ||
918 | *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; | ||
919 | else { | ||
920 | *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; | ||
921 | *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; | ||
922 | } | ||
923 | *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; | ||
924 | *value |= (status & I365_CS_READY) ? SS_READY : 0; | ||
925 | *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; | ||
926 | |||
927 | if (socket[sock].type == IS_VG469) { | ||
928 | status = i365_get(sock, VG469_VSENSE); | ||
929 | if (socket[sock].psock & 1) { | ||
930 | *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD; | ||
931 | *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD; | ||
932 | } else { | ||
933 | *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD; | ||
934 | *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value); | ||
939 | return 0; | ||
940 | } /* i365_get_status */ | ||
941 | |||
942 | /*====================================================================*/ | ||
943 | |||
944 | static int i365_get_socket(u_short sock, socket_state_t *state) | ||
945 | { | ||
946 | struct i82365_socket *t = &socket[sock]; | ||
947 | u_char reg, vcc, vpp; | ||
948 | |||
949 | reg = i365_get(sock, I365_POWER); | ||
950 | state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; | ||
951 | state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; | ||
952 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
953 | state->Vcc = state->Vpp = 0; | ||
954 | if (t->flags & IS_CIRRUS) { | ||
955 | if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { | ||
956 | if (reg & I365_VCC_5V) state->Vcc = 33; | ||
957 | if (vpp == I365_VPP1_5V) state->Vpp = 33; | ||
958 | } else { | ||
959 | if (reg & I365_VCC_5V) state->Vcc = 50; | ||
960 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
961 | } | ||
962 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
963 | } else if (t->flags & IS_VG_PWR) { | ||
964 | if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) { | ||
965 | if (reg & I365_VCC_5V) state->Vcc = 33; | ||
966 | if (vpp == I365_VPP1_5V) state->Vpp = 33; | ||
967 | } else { | ||
968 | if (reg & I365_VCC_5V) state->Vcc = 50; | ||
969 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
970 | } | ||
971 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
972 | } else if (t->flags & IS_DF_PWR) { | ||
973 | if (vcc == I365_VCC_3V) state->Vcc = 33; | ||
974 | if (vcc == I365_VCC_5V) state->Vcc = 50; | ||
975 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
976 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
977 | } else { | ||
978 | if (reg & I365_VCC_5V) { | ||
979 | state->Vcc = 50; | ||
980 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
981 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | /* IO card, RESET flags, IO interrupt */ | ||
986 | reg = i365_get(sock, I365_INTCTL); | ||
987 | state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; | ||
988 | if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; | ||
989 | state->io_irq = reg & I365_IRQ_MASK; | ||
990 | |||
991 | /* speaker control */ | ||
992 | if (t->flags & IS_CIRRUS) { | ||
993 | if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA) | ||
994 | state->flags |= SS_SPKR_ENA; | ||
995 | } | ||
996 | |||
997 | /* Card status change mask */ | ||
998 | reg = i365_get(sock, I365_CSCINT); | ||
999 | state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
1000 | if (state->flags & SS_IOCARD) | ||
1001 | state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
1002 | else { | ||
1003 | state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
1004 | state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
1005 | state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; | ||
1006 | } | ||
1007 | |||
1008 | debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
1009 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
1010 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
1011 | return 0; | ||
1012 | } /* i365_get_socket */ | ||
1013 | |||
1014 | /*====================================================================*/ | ||
1015 | |||
1016 | static int i365_set_socket(u_short sock, socket_state_t *state) | ||
1017 | { | ||
1018 | struct i82365_socket *t = &socket[sock]; | ||
1019 | u_char reg; | ||
1020 | |||
1021 | debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | ||
1022 | "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, | ||
1023 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
1024 | |||
1025 | /* First set global controller options */ | ||
1026 | set_bridge_state(sock); | ||
1027 | |||
1028 | /* IO card, RESET flag, IO interrupt */ | ||
1029 | reg = t->intr; | ||
1030 | reg |= state->io_irq; | ||
1031 | reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; | ||
1032 | reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; | ||
1033 | i365_set(sock, I365_INTCTL, reg); | ||
1034 | |||
1035 | reg = I365_PWR_NORESET; | ||
1036 | if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; | ||
1037 | if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; | ||
1038 | |||
1039 | if (t->flags & IS_CIRRUS) { | ||
1040 | if (state->Vpp != 0) { | ||
1041 | if (state->Vpp == 120) | ||
1042 | reg |= I365_VPP1_12V; | ||
1043 | else if (state->Vpp == state->Vcc) | ||
1044 | reg |= I365_VPP1_5V; | ||
1045 | else return -EINVAL; | ||
1046 | } | ||
1047 | if (state->Vcc != 0) { | ||
1048 | reg |= I365_VCC_5V; | ||
1049 | if (state->Vcc == 33) | ||
1050 | i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
1051 | else if (state->Vcc == 50) | ||
1052 | i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
1053 | else return -EINVAL; | ||
1054 | } | ||
1055 | } else if (t->flags & IS_VG_PWR) { | ||
1056 | if (state->Vpp != 0) { | ||
1057 | if (state->Vpp == 120) | ||
1058 | reg |= I365_VPP1_12V; | ||
1059 | else if (state->Vpp == state->Vcc) | ||
1060 | reg |= I365_VPP1_5V; | ||
1061 | else return -EINVAL; | ||
1062 | } | ||
1063 | if (state->Vcc != 0) { | ||
1064 | reg |= I365_VCC_5V; | ||
1065 | if (state->Vcc == 33) | ||
1066 | i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC); | ||
1067 | else if (state->Vcc == 50) | ||
1068 | i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC); | ||
1069 | else return -EINVAL; | ||
1070 | } | ||
1071 | } else if (t->flags & IS_DF_PWR) { | ||
1072 | switch (state->Vcc) { | ||
1073 | case 0: break; | ||
1074 | case 33: reg |= I365_VCC_3V; break; | ||
1075 | case 50: reg |= I365_VCC_5V; break; | ||
1076 | default: return -EINVAL; | ||
1077 | } | ||
1078 | switch (state->Vpp) { | ||
1079 | case 0: break; | ||
1080 | case 50: reg |= I365_VPP1_5V; break; | ||
1081 | case 120: reg |= I365_VPP1_12V; break; | ||
1082 | default: return -EINVAL; | ||
1083 | } | ||
1084 | } else { | ||
1085 | switch (state->Vcc) { | ||
1086 | case 0: break; | ||
1087 | case 50: reg |= I365_VCC_5V; break; | ||
1088 | default: return -EINVAL; | ||
1089 | } | ||
1090 | switch (state->Vpp) { | ||
1091 | case 0: break; | ||
1092 | case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break; | ||
1093 | case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break; | ||
1094 | default: return -EINVAL; | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | if (reg != i365_get(sock, I365_POWER)) | ||
1099 | i365_set(sock, I365_POWER, reg); | ||
1100 | |||
1101 | /* Chipset-specific functions */ | ||
1102 | if (t->flags & IS_CIRRUS) { | ||
1103 | /* Speaker control */ | ||
1104 | i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA, | ||
1105 | state->flags & SS_SPKR_ENA); | ||
1106 | } | ||
1107 | |||
1108 | /* Card status change interrupt mask */ | ||
1109 | reg = t->cs_irq << 4; | ||
1110 | if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; | ||
1111 | if (state->flags & SS_IOCARD) { | ||
1112 | if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; | ||
1113 | } else { | ||
1114 | if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; | ||
1115 | if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; | ||
1116 | if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; | ||
1117 | } | ||
1118 | i365_set(sock, I365_CSCINT, reg); | ||
1119 | i365_get(sock, I365_CSC); | ||
1120 | |||
1121 | return 0; | ||
1122 | } /* i365_set_socket */ | ||
1123 | |||
1124 | /*====================================================================*/ | ||
1125 | |||
1126 | static int i365_set_io_map(u_short sock, struct pccard_io_map *io) | ||
1127 | { | ||
1128 | u_char map, ioctl; | ||
1129 | |||
1130 | debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " | ||
1131 | "%#lx-%#lx)\n", sock, io->map, io->flags, | ||
1132 | io->speed, io->start, io->stop); | ||
1133 | map = io->map; | ||
1134 | if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || | ||
1135 | (io->stop < io->start)) return -EINVAL; | ||
1136 | /* Turn off the window before changing anything */ | ||
1137 | if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map)) | ||
1138 | i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map)); | ||
1139 | i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start); | ||
1140 | i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop); | ||
1141 | ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map); | ||
1142 | if (io->speed) ioctl |= I365_IOCTL_WAIT(map); | ||
1143 | if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); | ||
1144 | if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); | ||
1145 | if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); | ||
1146 | i365_set(sock, I365_IOCTL, ioctl); | ||
1147 | /* Turn on the window if necessary */ | ||
1148 | if (io->flags & MAP_ACTIVE) | ||
1149 | i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map)); | ||
1150 | return 0; | ||
1151 | } /* i365_set_io_map */ | ||
1152 | |||
1153 | /*====================================================================*/ | ||
1154 | |||
1155 | static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) | ||
1156 | { | ||
1157 | u_short base, i; | ||
1158 | u_char map; | ||
1159 | |||
1160 | debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#lx-%#lx, " | ||
1161 | "%#x)\n", sock, mem->map, mem->flags, mem->speed, | ||
1162 | mem->res->start, mem->res->end, mem->card_start); | ||
1163 | |||
1164 | map = mem->map; | ||
1165 | if ((map > 4) || (mem->card_start > 0x3ffffff) || | ||
1166 | (mem->res->start > mem->res->end) || (mem->speed > 1000)) | ||
1167 | return -EINVAL; | ||
1168 | if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff)) | ||
1169 | return -EINVAL; | ||
1170 | |||
1171 | /* Turn off the window before changing anything */ | ||
1172 | if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) | ||
1173 | i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
1174 | |||
1175 | base = I365_MEM(map); | ||
1176 | i = (mem->res->start >> 12) & 0x0fff; | ||
1177 | if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; | ||
1178 | if (mem->flags & MAP_0WS) i |= I365_MEM_0WS; | ||
1179 | i365_set_pair(sock, base+I365_W_START, i); | ||
1180 | |||
1181 | i = (mem->res->end >> 12) & 0x0fff; | ||
1182 | switch (to_cycles(mem->speed)) { | ||
1183 | case 0: break; | ||
1184 | case 1: i |= I365_MEM_WS0; break; | ||
1185 | case 2: i |= I365_MEM_WS1; break; | ||
1186 | default: i |= I365_MEM_WS1 | I365_MEM_WS0; break; | ||
1187 | } | ||
1188 | i365_set_pair(sock, base+I365_W_STOP, i); | ||
1189 | |||
1190 | i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; | ||
1191 | if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; | ||
1192 | if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; | ||
1193 | i365_set_pair(sock, base+I365_W_OFF, i); | ||
1194 | |||
1195 | /* Turn on the window if necessary */ | ||
1196 | if (mem->flags & MAP_ACTIVE) | ||
1197 | i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
1198 | return 0; | ||
1199 | } /* i365_set_mem_map */ | ||
1200 | |||
1201 | #if 0 /* driver model ordering issue */ | ||
1202 | /*====================================================================== | ||
1203 | |||
1204 | Routines for accessing socket information and register dumps via | ||
1205 | /sys/class/pcmcia_socket/... | ||
1206 | |||
1207 | ======================================================================*/ | ||
1208 | |||
1209 | static ssize_t show_info(struct class_device *class_dev, char *buf) | ||
1210 | { | ||
1211 | struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); | ||
1212 | return sprintf(buf, "type: %s\npsock: %d\n", | ||
1213 | pcic[s->type].name, s->psock); | ||
1214 | } | ||
1215 | |||
1216 | static ssize_t show_exca(struct class_device *class_dev, char *buf) | ||
1217 | { | ||
1218 | struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); | ||
1219 | unsigned short sock; | ||
1220 | int i; | ||
1221 | ssize_t ret = 0; | ||
1222 | unsigned long flags = 0; | ||
1223 | |||
1224 | sock = s->number; | ||
1225 | |||
1226 | ISA_LOCK(sock, flags); | ||
1227 | for (i = 0; i < 0x40; i += 4) { | ||
1228 | ret += sprintf(buf, "%02x %02x %02x %02x%s", | ||
1229 | i365_get(sock,i), i365_get(sock,i+1), | ||
1230 | i365_get(sock,i+2), i365_get(sock,i+3), | ||
1231 | ((i % 16) == 12) ? "\n" : " "); | ||
1232 | buf += ret; | ||
1233 | } | ||
1234 | ISA_UNLOCK(sock, flags); | ||
1235 | |||
1236 | return ret; | ||
1237 | } | ||
1238 | |||
1239 | static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL); | ||
1240 | static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL); | ||
1241 | #endif | ||
1242 | |||
1243 | /*====================================================================*/ | ||
1244 | |||
1245 | /* this is horribly ugly... proper locking needs to be done here at | ||
1246 | * some time... */ | ||
1247 | #define LOCKED(x) do { \ | ||
1248 | int retval; \ | ||
1249 | unsigned long flags; \ | ||
1250 | spin_lock_irqsave(&isa_lock, flags); \ | ||
1251 | retval = x; \ | ||
1252 | spin_unlock_irqrestore(&isa_lock, flags); \ | ||
1253 | return retval; \ | ||
1254 | } while (0) | ||
1255 | |||
1256 | |||
1257 | static int pcic_get_status(struct pcmcia_socket *s, u_int *value) | ||
1258 | { | ||
1259 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1260 | |||
1261 | if (socket[sock].flags & IS_ALIVE) { | ||
1262 | *value = 0; | ||
1263 | return -EINVAL; | ||
1264 | } | ||
1265 | |||
1266 | LOCKED(i365_get_status(sock, value)); | ||
1267 | } | ||
1268 | |||
1269 | static int pcic_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
1270 | { | ||
1271 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1272 | |||
1273 | if (socket[sock].flags & IS_ALIVE) | ||
1274 | return -EINVAL; | ||
1275 | |||
1276 | LOCKED(i365_get_socket(sock, state)); | ||
1277 | } | ||
1278 | |||
1279 | static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
1280 | { | ||
1281 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1282 | |||
1283 | if (socket[sock].flags & IS_ALIVE) | ||
1284 | return -EINVAL; | ||
1285 | |||
1286 | LOCKED(i365_set_socket(sock, state)); | ||
1287 | } | ||
1288 | |||
1289 | static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) | ||
1290 | { | ||
1291 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1292 | if (socket[sock].flags & IS_ALIVE) | ||
1293 | return -EINVAL; | ||
1294 | |||
1295 | LOCKED(i365_set_io_map(sock, io)); | ||
1296 | } | ||
1297 | |||
1298 | static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) | ||
1299 | { | ||
1300 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1301 | if (socket[sock].flags & IS_ALIVE) | ||
1302 | return -EINVAL; | ||
1303 | |||
1304 | LOCKED(i365_set_mem_map(sock, mem)); | ||
1305 | } | ||
1306 | |||
1307 | static int pcic_init(struct pcmcia_socket *s) | ||
1308 | { | ||
1309 | int i; | ||
1310 | struct resource res = { .start = 0, .end = 0x1000 }; | ||
1311 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
1312 | pccard_mem_map mem = { .res = &res, }; | ||
1313 | |||
1314 | for (i = 0; i < 2; i++) { | ||
1315 | io.map = i; | ||
1316 | pcic_set_io_map(s, &io); | ||
1317 | } | ||
1318 | for (i = 0; i < 5; i++) { | ||
1319 | mem.map = i; | ||
1320 | pcic_set_mem_map(s, &mem); | ||
1321 | } | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | static struct pccard_operations pcic_operations = { | ||
1326 | .init = pcic_init, | ||
1327 | .get_status = pcic_get_status, | ||
1328 | .get_socket = pcic_get_socket, | ||
1329 | .set_socket = pcic_set_socket, | ||
1330 | .set_io_map = pcic_set_io_map, | ||
1331 | .set_mem_map = pcic_set_mem_map, | ||
1332 | }; | ||
1333 | |||
1334 | /*====================================================================*/ | ||
1335 | |||
1336 | static int i82365_suspend(struct device *dev, pm_message_t state, u32 level) | ||
1337 | { | ||
1338 | int ret = 0; | ||
1339 | if (level == SUSPEND_SAVE_STATE) | ||
1340 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
1341 | return ret; | ||
1342 | } | ||
1343 | |||
1344 | static int i82365_resume(struct device *dev, u32 level) | ||
1345 | { | ||
1346 | int ret = 0; | ||
1347 | if (level == RESUME_RESTORE_STATE) | ||
1348 | ret = pcmcia_socket_dev_resume(dev); | ||
1349 | return ret; | ||
1350 | } | ||
1351 | |||
1352 | static struct device_driver i82365_driver = { | ||
1353 | .name = "i82365", | ||
1354 | .bus = &platform_bus_type, | ||
1355 | .suspend = i82365_suspend, | ||
1356 | .resume = i82365_resume, | ||
1357 | }; | ||
1358 | |||
1359 | static struct platform_device i82365_device = { | ||
1360 | .name = "i82365", | ||
1361 | .id = 0, | ||
1362 | }; | ||
1363 | |||
1364 | static int __init init_i82365(void) | ||
1365 | { | ||
1366 | int i, ret; | ||
1367 | |||
1368 | ret = driver_register(&i82365_driver); | ||
1369 | if (ret) | ||
1370 | return ret; | ||
1371 | |||
1372 | ret = platform_device_register(&i82365_device); | ||
1373 | if (ret) { | ||
1374 | driver_unregister(&i82365_driver); | ||
1375 | return ret; | ||
1376 | } | ||
1377 | |||
1378 | printk(KERN_INFO "Intel ISA PCIC probe: "); | ||
1379 | sockets = 0; | ||
1380 | |||
1381 | isa_probe(); | ||
1382 | |||
1383 | if (sockets == 0) { | ||
1384 | printk("not found.\n"); | ||
1385 | platform_device_unregister(&i82365_device); | ||
1386 | driver_unregister(&i82365_driver); | ||
1387 | return -ENODEV; | ||
1388 | } | ||
1389 | |||
1390 | /* Set up interrupt handler(s) */ | ||
1391 | if (grab_irq != 0) | ||
1392 | request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); | ||
1393 | |||
1394 | /* register sockets with the pcmcia core */ | ||
1395 | for (i = 0; i < sockets; i++) { | ||
1396 | socket[i].socket.dev.dev = &i82365_device.dev; | ||
1397 | socket[i].socket.ops = &pcic_operations; | ||
1398 | socket[i].socket.resource_ops = &pccard_nonstatic_ops; | ||
1399 | socket[i].socket.owner = THIS_MODULE; | ||
1400 | socket[i].number = i; | ||
1401 | ret = pcmcia_register_socket(&socket[i].socket); | ||
1402 | if (!ret) | ||
1403 | socket[i].flags |= IS_REGISTERED; | ||
1404 | |||
1405 | #if 0 /* driver model ordering issue */ | ||
1406 | class_device_create_file(&socket[i].socket.dev, | ||
1407 | &class_device_attr_info); | ||
1408 | class_device_create_file(&socket[i].socket.dev, | ||
1409 | &class_device_attr_exca); | ||
1410 | #endif | ||
1411 | } | ||
1412 | |||
1413 | /* Finally, schedule a polling interrupt */ | ||
1414 | if (poll_interval != 0) { | ||
1415 | poll_timer.function = pcic_interrupt_wrapper; | ||
1416 | poll_timer.data = 0; | ||
1417 | init_timer(&poll_timer); | ||
1418 | poll_timer.expires = jiffies + poll_interval; | ||
1419 | add_timer(&poll_timer); | ||
1420 | } | ||
1421 | |||
1422 | return 0; | ||
1423 | |||
1424 | } /* init_i82365 */ | ||
1425 | |||
1426 | static void __exit exit_i82365(void) | ||
1427 | { | ||
1428 | int i; | ||
1429 | |||
1430 | for (i = 0; i < sockets; i++) { | ||
1431 | if (socket[i].flags & IS_REGISTERED) | ||
1432 | pcmcia_unregister_socket(&socket[i].socket); | ||
1433 | } | ||
1434 | platform_device_unregister(&i82365_device); | ||
1435 | if (poll_interval != 0) | ||
1436 | del_timer_sync(&poll_timer); | ||
1437 | if (grab_irq != 0) | ||
1438 | free_irq(cs_irq, pcic_interrupt); | ||
1439 | for (i = 0; i < sockets; i++) { | ||
1440 | /* Turn off all interrupt sources! */ | ||
1441 | i365_set(i, I365_CSCINT, 0); | ||
1442 | release_region(socket[i].ioaddr, 2); | ||
1443 | } | ||
1444 | #ifdef CONFIG_PNP | ||
1445 | if (i82365_pnpdev) | ||
1446 | pnp_disable_dev(i82365_pnpdev); | ||
1447 | #endif | ||
1448 | driver_unregister(&i82365_driver); | ||
1449 | } /* exit_i82365 */ | ||
1450 | |||
1451 | module_init(init_i82365); | ||
1452 | module_exit(exit_i82365); | ||
1453 | MODULE_LICENSE("Dual MPL/GPL"); | ||
1454 | /*====================================================================*/ | ||
diff --git a/drivers/pcmcia/i82365.h b/drivers/pcmcia/i82365.h new file mode 100644 index 000000000000..622860c689d9 --- /dev/null +++ b/drivers/pcmcia/i82365.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * i82365.h 1.15 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_I82365_H | ||
31 | #define _LINUX_I82365_H | ||
32 | |||
33 | /* register definitions for the Intel 82365SL PCMCIA controller */ | ||
34 | |||
35 | /* Offsets for PCIC registers */ | ||
36 | #define I365_IDENT 0x00 /* Identification and revision */ | ||
37 | #define I365_STATUS 0x01 /* Interface status */ | ||
38 | #define I365_POWER 0x02 /* Power and RESETDRV control */ | ||
39 | #define I365_INTCTL 0x03 /* Interrupt and general control */ | ||
40 | #define I365_CSC 0x04 /* Card status change */ | ||
41 | #define I365_CSCINT 0x05 /* Card status change interrupt control */ | ||
42 | #define I365_ADDRWIN 0x06 /* Address window enable */ | ||
43 | #define I365_IOCTL 0x07 /* I/O control */ | ||
44 | #define I365_GENCTL 0x16 /* Card detect and general control */ | ||
45 | #define I365_GBLCTL 0x1E /* Global control register */ | ||
46 | |||
47 | /* Offsets for I/O and memory window registers */ | ||
48 | #define I365_IO(map) (0x08+((map)<<2)) | ||
49 | #define I365_MEM(map) (0x10+((map)<<3)) | ||
50 | #define I365_W_START 0 | ||
51 | #define I365_W_STOP 2 | ||
52 | #define I365_W_OFF 4 | ||
53 | |||
54 | /* Flags for I365_STATUS */ | ||
55 | #define I365_CS_BVD1 0x01 | ||
56 | #define I365_CS_STSCHG 0x01 | ||
57 | #define I365_CS_BVD2 0x02 | ||
58 | #define I365_CS_SPKR 0x02 | ||
59 | #define I365_CS_DETECT 0x0C | ||
60 | #define I365_CS_WRPROT 0x10 | ||
61 | #define I365_CS_READY 0x20 /* Inverted */ | ||
62 | #define I365_CS_POWERON 0x40 | ||
63 | #define I365_CS_GPI 0x80 | ||
64 | |||
65 | /* Flags for I365_POWER */ | ||
66 | #define I365_PWR_OFF 0x00 /* Turn off the socket */ | ||
67 | #define I365_PWR_OUT 0x80 /* Output enable */ | ||
68 | #define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */ | ||
69 | #define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */ | ||
70 | #define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */ | ||
71 | /* There are different layouts for B-step and DF-step chips: the B | ||
72 | step has independent Vpp1/Vpp2 control, and the DF step has only | ||
73 | Vpp1 control, plus 3V control */ | ||
74 | #define I365_VCC_5V 0x10 /* Vcc = 5.0v */ | ||
75 | #define I365_VCC_3V 0x18 /* Vcc = 3.3v */ | ||
76 | #define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */ | ||
77 | #define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */ | ||
78 | #define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */ | ||
79 | #define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */ | ||
80 | #define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */ | ||
81 | #define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */ | ||
82 | |||
83 | /* Flags for I365_INTCTL */ | ||
84 | #define I365_RING_ENA 0x80 | ||
85 | #define I365_PC_RESET 0x40 | ||
86 | #define I365_PC_IOCARD 0x20 | ||
87 | #define I365_INTR_ENA 0x10 | ||
88 | #define I365_IRQ_MASK 0x0F | ||
89 | |||
90 | /* Flags for I365_CSC and I365_CSCINT*/ | ||
91 | #define I365_CSC_BVD1 0x01 | ||
92 | #define I365_CSC_STSCHG 0x01 | ||
93 | #define I365_CSC_BVD2 0x02 | ||
94 | #define I365_CSC_READY 0x04 | ||
95 | #define I365_CSC_DETECT 0x08 | ||
96 | #define I365_CSC_ANY 0x0F | ||
97 | #define I365_CSC_GPI 0x10 | ||
98 | |||
99 | /* Flags for I365_ADDRWIN */ | ||
100 | #define I365_ENA_IO(map) (0x40 << (map)) | ||
101 | #define I365_ENA_MEM(map) (0x01 << (map)) | ||
102 | |||
103 | /* Flags for I365_IOCTL */ | ||
104 | #define I365_IOCTL_MASK(map) (0x0F << (map<<2)) | ||
105 | #define I365_IOCTL_WAIT(map) (0x08 << (map<<2)) | ||
106 | #define I365_IOCTL_0WS(map) (0x04 << (map<<2)) | ||
107 | #define I365_IOCTL_IOCS16(map) (0x02 << (map<<2)) | ||
108 | #define I365_IOCTL_16BIT(map) (0x01 << (map<<2)) | ||
109 | |||
110 | /* Flags for I365_GENCTL */ | ||
111 | #define I365_CTL_16DELAY 0x01 | ||
112 | #define I365_CTL_RESET 0x02 | ||
113 | #define I365_CTL_GPI_ENA 0x04 | ||
114 | #define I365_CTL_GPI_CTL 0x08 | ||
115 | #define I365_CTL_RESUME 0x10 | ||
116 | #define I365_CTL_SW_IRQ 0x20 | ||
117 | |||
118 | /* Flags for I365_GBLCTL */ | ||
119 | #define I365_GBL_PWRDOWN 0x01 | ||
120 | #define I365_GBL_CSC_LEV 0x02 | ||
121 | #define I365_GBL_WRBACK 0x04 | ||
122 | #define I365_GBL_IRQ_0_LEV 0x08 | ||
123 | #define I365_GBL_IRQ_1_LEV 0x10 | ||
124 | |||
125 | /* Flags for memory window registers */ | ||
126 | #define I365_MEM_16BIT 0x8000 /* In memory start high byte */ | ||
127 | #define I365_MEM_0WS 0x4000 | ||
128 | #define I365_MEM_WS1 0x8000 /* In memory stop high byte */ | ||
129 | #define I365_MEM_WS0 0x4000 | ||
130 | #define I365_MEM_WRPROT 0x8000 /* In offset high byte */ | ||
131 | #define I365_MEM_REG 0x4000 | ||
132 | |||
133 | #define I365_REG(slot, reg) (((slot) << 6) + reg) | ||
134 | |||
135 | #endif /* _LINUX_I82365_H */ | ||
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c new file mode 100644 index 000000000000..b0b7a7a41120 --- /dev/null +++ b/drivers/pcmcia/m32r_cfc.c | |||
@@ -0,0 +1,873 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/m32r_cfc.c | ||
3 | * | ||
4 | * Device driver for the CFC functionality of M32R. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002, 2003, 2004 | ||
7 | * Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/fcntl.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/bitops.h> | ||
30 | #include <asm/system.h> | ||
31 | |||
32 | #include <pcmcia/version.h> | ||
33 | #include <pcmcia/cs_types.h> | ||
34 | #include <pcmcia/ss.h> | ||
35 | #include <pcmcia/cs.h> | ||
36 | |||
37 | #undef MAX_IO_WIN /* FIXME */ | ||
38 | #define MAX_IO_WIN 1 | ||
39 | #undef MAX_WIN /* FIXME */ | ||
40 | #define MAX_WIN 1 | ||
41 | |||
42 | #include "m32r_cfc.h" | ||
43 | |||
44 | #ifdef DEBUG | ||
45 | static int m32r_cfc_debug; | ||
46 | module_param(m32r_cfc_debug, int, 0644); | ||
47 | #define debug(lvl, fmt, arg...) do { \ | ||
48 | if (m32r_cfc_debug > (lvl)) \ | ||
49 | printk(KERN_DEBUG "m32r_cfc: " fmt , ## arg); \ | ||
50 | } while (0) | ||
51 | #else | ||
52 | #define debug(n, args...) do { } while (0) | ||
53 | #endif | ||
54 | |||
55 | /* Poll status interval -- 0 means default to interrupt */ | ||
56 | static int poll_interval = 0; | ||
57 | |||
58 | typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t; | ||
59 | |||
60 | typedef struct pcc_socket { | ||
61 | u_short type, flags; | ||
62 | struct pcmcia_socket socket; | ||
63 | unsigned int number; | ||
64 | kio_addr_t ioaddr; | ||
65 | u_long mapaddr; | ||
66 | u_long base; /* PCC register base */ | ||
67 | u_char cs_irq1, cs_irq2, intr; | ||
68 | pccard_io_map io_map[MAX_IO_WIN]; | ||
69 | pccard_mem_map mem_map[MAX_WIN]; | ||
70 | u_char io_win; | ||
71 | u_char mem_win; | ||
72 | pcc_as_t current_space; | ||
73 | u_char last_iodbex; | ||
74 | #ifdef CONFIG_PROC_FS | ||
75 | struct proc_dir_entry *proc; | ||
76 | #endif | ||
77 | } pcc_socket_t; | ||
78 | |||
79 | static int pcc_sockets = 0; | ||
80 | static pcc_socket_t socket[M32R_MAX_PCC] = { | ||
81 | { 0, }, /* ... */ | ||
82 | }; | ||
83 | |||
84 | /*====================================================================*/ | ||
85 | |||
86 | static unsigned int pcc_get(u_short, unsigned int); | ||
87 | static void pcc_set(u_short, unsigned int , unsigned int ); | ||
88 | |||
89 | static DEFINE_SPINLOCK(pcc_lock); | ||
90 | |||
91 | #if !defined(CONFIG_PLAT_USRV) | ||
92 | static inline u_long pcc_port2addr(unsigned long port, int size) { | ||
93 | u_long addr = 0; | ||
94 | u_long odd; | ||
95 | |||
96 | if (size == 1) { /* byte access */ | ||
97 | odd = (port&1) << 11; | ||
98 | port -= port & 1; | ||
99 | addr = CFC_IO_MAPBASE_BYTE - CFC_IOPORT_BASE + odd + port; | ||
100 | } else if (size == 2) | ||
101 | addr = CFC_IO_MAPBASE_WORD - CFC_IOPORT_BASE + port; | ||
102 | |||
103 | return addr; | ||
104 | } | ||
105 | #else /* CONFIG_PLAT_USRV */ | ||
106 | static inline u_long pcc_port2addr(unsigned long port, int size) { | ||
107 | u_long odd; | ||
108 | u_long addr = ((port - CFC_IOPORT_BASE) & 0xf000) << 8; | ||
109 | |||
110 | if (size == 1) { /* byte access */ | ||
111 | odd = port & 1; | ||
112 | port -= odd; | ||
113 | odd <<= 11; | ||
114 | addr = (addr | CFC_IO_MAPBASE_BYTE) + odd + (port & 0xfff); | ||
115 | } else if (size == 2) /* word access */ | ||
116 | addr = (addr | CFC_IO_MAPBASE_WORD) + (port & 0xfff); | ||
117 | |||
118 | return addr; | ||
119 | } | ||
120 | #endif /* CONFIG_PLAT_USRV */ | ||
121 | |||
122 | void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size, | ||
123 | size_t nmemb, int flag) | ||
124 | { | ||
125 | u_long addr; | ||
126 | unsigned char *bp = (unsigned char *)buf; | ||
127 | unsigned long flags; | ||
128 | |||
129 | debug(3, "m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, " | ||
130 | "size=%u, nmemb=%d, flag=%d\n", | ||
131 | sock, port, buf, size, nmemb, flag); | ||
132 | |||
133 | addr = pcc_port2addr(port, 1); | ||
134 | if (!addr) { | ||
135 | printk("m32r_cfc:ioread_byte null port :%#lx\n",port); | ||
136 | return; | ||
137 | } | ||
138 | debug(3, "m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr); | ||
139 | |||
140 | spin_lock_irqsave(&pcc_lock, flags); | ||
141 | /* read Byte */ | ||
142 | while (nmemb--) | ||
143 | *bp++ = readb(addr); | ||
144 | spin_unlock_irqrestore(&pcc_lock, flags); | ||
145 | } | ||
146 | |||
147 | void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size, | ||
148 | size_t nmemb, int flag) | ||
149 | { | ||
150 | u_long addr; | ||
151 | unsigned short *bp = (unsigned short *)buf; | ||
152 | unsigned long flags; | ||
153 | |||
154 | debug(3, "m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, " | ||
155 | "buf=%p, size=%u, nmemb=%d, flag=%d\n", | ||
156 | sock, port, buf, size, nmemb, flag); | ||
157 | |||
158 | if (size != 2) | ||
159 | printk("m32r_cfc: ioread_word :illigal size %u : %#lx\n", size, | ||
160 | port); | ||
161 | if (size == 9) | ||
162 | printk("m32r_cfc: ioread_word :insw \n"); | ||
163 | |||
164 | addr = pcc_port2addr(port, 2); | ||
165 | if (!addr) { | ||
166 | printk("m32r_cfc:ioread_word null port :%#lx\n",port); | ||
167 | return; | ||
168 | } | ||
169 | debug(3, "m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr); | ||
170 | |||
171 | spin_lock_irqsave(&pcc_lock, flags); | ||
172 | /* read Word */ | ||
173 | while (nmemb--) | ||
174 | *bp++ = readw(addr); | ||
175 | spin_unlock_irqrestore(&pcc_lock, flags); | ||
176 | } | ||
177 | |||
178 | void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size, | ||
179 | size_t nmemb, int flag) | ||
180 | { | ||
181 | u_long addr; | ||
182 | unsigned char *bp = (unsigned char *)buf; | ||
183 | unsigned long flags; | ||
184 | |||
185 | debug(3, "m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, " | ||
186 | "buf=%p, size=%u, nmemb=%d, flag=%d\n", | ||
187 | sock, port, buf, size, nmemb, flag); | ||
188 | |||
189 | /* write Byte */ | ||
190 | addr = pcc_port2addr(port, 1); | ||
191 | if (!addr) { | ||
192 | printk("m32r_cfc:iowrite_byte null port:%#lx\n",port); | ||
193 | return; | ||
194 | } | ||
195 | debug(3, "m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr); | ||
196 | |||
197 | spin_lock_irqsave(&pcc_lock, flags); | ||
198 | while (nmemb--) | ||
199 | writeb(*bp++, addr); | ||
200 | spin_unlock_irqrestore(&pcc_lock, flags); | ||
201 | } | ||
202 | |||
203 | void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size, | ||
204 | size_t nmemb, int flag) | ||
205 | { | ||
206 | u_long addr; | ||
207 | unsigned short *bp = (unsigned short *)buf; | ||
208 | unsigned long flags; | ||
209 | |||
210 | debug(3, "m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, " | ||
211 | "buf=%p, size=%u, nmemb=%d, flag=%d\n", | ||
212 | sock, port, buf, size, nmemb, flag); | ||
213 | |||
214 | if(size != 2) | ||
215 | printk("m32r_cfc: iowrite_word :illigal size %u : %#lx\n", | ||
216 | size, port); | ||
217 | if(size == 9) | ||
218 | printk("m32r_cfc: iowrite_word :outsw \n"); | ||
219 | |||
220 | addr = pcc_port2addr(port, 2); | ||
221 | if (!addr) { | ||
222 | printk("m32r_cfc:iowrite_word null addr :%#lx\n",port); | ||
223 | return; | ||
224 | } | ||
225 | #if 1 | ||
226 | if (addr & 1) { | ||
227 | printk("m32r_cfc:iowrite_word port addr (%#lx):%#lx\n", port, | ||
228 | addr); | ||
229 | return; | ||
230 | } | ||
231 | #endif | ||
232 | debug(3, "m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr); | ||
233 | |||
234 | spin_lock_irqsave(&pcc_lock, flags); | ||
235 | while (nmemb--) | ||
236 | writew(*bp++, addr); | ||
237 | spin_unlock_irqrestore(&pcc_lock, flags); | ||
238 | } | ||
239 | |||
240 | /*====================================================================*/ | ||
241 | |||
242 | #define IS_REGISTERED 0x2000 | ||
243 | #define IS_ALIVE 0x8000 | ||
244 | |||
245 | typedef struct pcc_t { | ||
246 | char *name; | ||
247 | u_short flags; | ||
248 | } pcc_t; | ||
249 | |||
250 | static pcc_t pcc[] = { | ||
251 | #if !defined(CONFIG_PLAT_USRV) | ||
252 | { "m32r_cfc", 0 }, { "", 0 }, | ||
253 | #else /* CONFIG_PLAT_USRV */ | ||
254 | { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, | ||
255 | { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "", 0 }, | ||
256 | #endif /* CONFIG_PLAT_USRV */ | ||
257 | }; | ||
258 | |||
259 | static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *); | ||
260 | |||
261 | /*====================================================================*/ | ||
262 | |||
263 | static struct timer_list poll_timer; | ||
264 | |||
265 | static unsigned int pcc_get(u_short sock, unsigned int reg) | ||
266 | { | ||
267 | unsigned int val = inw(reg); | ||
268 | debug(3, "m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val); | ||
269 | return val; | ||
270 | } | ||
271 | |||
272 | |||
273 | static void pcc_set(u_short sock, unsigned int reg, unsigned int data) | ||
274 | { | ||
275 | outw(data, reg); | ||
276 | debug(3, "m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data); | ||
277 | } | ||
278 | |||
279 | /*====================================================================== | ||
280 | |||
281 | See if a card is present, powered up, in IO mode, and already | ||
282 | bound to a (non PC Card) Linux driver. We leave these alone. | ||
283 | |||
284 | We make an exception for cards that seem to be serial devices. | ||
285 | |||
286 | ======================================================================*/ | ||
287 | |||
288 | static int __init is_alive(u_short sock) | ||
289 | { | ||
290 | unsigned int stat; | ||
291 | |||
292 | debug(3, "m32r_cfc: is_alive:\n"); | ||
293 | |||
294 | printk("CF: "); | ||
295 | stat = pcc_get(sock, (unsigned int)PLD_CFSTS); | ||
296 | if (!stat) | ||
297 | printk("No "); | ||
298 | printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat); | ||
299 | debug(3, "m32r_cfc: is_alive: sock stat is 0x%04x\n", stat); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr) | ||
305 | { | ||
306 | pcc_socket_t *t = &socket[pcc_sockets]; | ||
307 | |||
308 | debug(3, "m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, " | ||
309 | "mapaddr=%#lx, ioaddr=%08x\n", | ||
310 | base, irq, mapaddr, ioaddr); | ||
311 | |||
312 | /* add sockets */ | ||
313 | t->ioaddr = ioaddr; | ||
314 | t->mapaddr = mapaddr; | ||
315 | #if !defined(CONFIG_PLAT_USRV) | ||
316 | t->base = 0; | ||
317 | t->flags = 0; | ||
318 | t->cs_irq1 = irq; // insert irq | ||
319 | t->cs_irq2 = irq + 1; // eject irq | ||
320 | #else /* CONFIG_PLAT_USRV */ | ||
321 | t->base = base; | ||
322 | t->flags = 0; | ||
323 | t->cs_irq1 = 0; // insert irq | ||
324 | t->cs_irq2 = 0; // eject irq | ||
325 | #endif /* CONFIG_PLAT_USRV */ | ||
326 | |||
327 | if (is_alive(pcc_sockets)) | ||
328 | t->flags |= IS_ALIVE; | ||
329 | |||
330 | /* add pcc */ | ||
331 | #if !defined(CONFIG_PLAT_USRV) | ||
332 | request_region((unsigned int)PLD_CFRSTCR, 0x20, "m32r_cfc"); | ||
333 | #else /* CONFIG_PLAT_USRV */ | ||
334 | { | ||
335 | unsigned int reg_base; | ||
336 | |||
337 | reg_base = (unsigned int)PLD_CFRSTCR; | ||
338 | reg_base |= pcc_sockets << 8; | ||
339 | request_region(reg_base, 0x20, "m32r_cfc"); | ||
340 | } | ||
341 | #endif /* CONFIG_PLAT_USRV */ | ||
342 | printk(KERN_INFO " %s ", pcc[pcc_sockets].name); | ||
343 | printk("pcc at 0x%08lx\n", t->base); | ||
344 | |||
345 | /* Update socket interrupt information, capabilities */ | ||
346 | t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP); | ||
347 | t->socket.map_size = M32R_PCC_MAPSIZE; | ||
348 | t->socket.io_offset = ioaddr; /* use for io access offset */ | ||
349 | t->socket.irq_mask = 0; | ||
350 | #if !defined(CONFIG_PLAT_USRV) | ||
351 | t->socket.pci_irq = PLD_IRQ_CFIREQ ; /* card interrupt */ | ||
352 | #else /* CONFIG_PLAT_USRV */ | ||
353 | t->socket.pci_irq = PLD_IRQ_CF0 + pcc_sockets; | ||
354 | #endif /* CONFIG_PLAT_USRV */ | ||
355 | |||
356 | #ifndef CONFIG_PLAT_USRV | ||
357 | /* insert interrupt */ | ||
358 | request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt); | ||
359 | /* eject interrupt */ | ||
360 | request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt); | ||
361 | |||
362 | debug(3, "m32r_cfc: enable CFMSK, RDYSEL\n"); | ||
363 | pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01); | ||
364 | #endif /* CONFIG_PLAT_USRV */ | ||
365 | #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) | ||
366 | pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200); | ||
367 | #endif | ||
368 | pcc_sockets++; | ||
369 | |||
370 | return; | ||
371 | } | ||
372 | |||
373 | |||
374 | /*====================================================================*/ | ||
375 | |||
376 | static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
377 | { | ||
378 | int i; | ||
379 | u_int events = 0; | ||
380 | int handled = 0; | ||
381 | |||
382 | debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n", | ||
383 | irq, dev, regs); | ||
384 | for (i = 0; i < pcc_sockets; i++) { | ||
385 | if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq) | ||
386 | continue; | ||
387 | |||
388 | handled = 1; | ||
389 | debug(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ", | ||
390 | i, irq); | ||
391 | events |= SS_DETECT; /* insert or eject */ | ||
392 | if (events) | ||
393 | pcmcia_parse_events(&socket[i].socket, events); | ||
394 | } | ||
395 | debug(3, "m32r_cfc: pcc_interrupt: done\n"); | ||
396 | |||
397 | return IRQ_RETVAL(handled); | ||
398 | } /* pcc_interrupt */ | ||
399 | |||
400 | static void pcc_interrupt_wrapper(u_long data) | ||
401 | { | ||
402 | debug(3, "m32r_cfc: pcc_interrupt_wrapper:\n"); | ||
403 | pcc_interrupt(0, NULL, NULL); | ||
404 | init_timer(&poll_timer); | ||
405 | poll_timer.expires = jiffies + poll_interval; | ||
406 | add_timer(&poll_timer); | ||
407 | } | ||
408 | |||
409 | /*====================================================================*/ | ||
410 | |||
411 | static int _pcc_get_status(u_short sock, u_int *value) | ||
412 | { | ||
413 | u_int status; | ||
414 | |||
415 | debug(3, "m32r_cfc: _pcc_get_status:\n"); | ||
416 | status = pcc_get(sock, (unsigned int)PLD_CFSTS); | ||
417 | *value = (status) ? SS_DETECT : 0; | ||
418 | debug(3, "m32r_cfc: _pcc_get_status: status=0x%08x\n", status); | ||
419 | |||
420 | #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) | ||
421 | if ( status ) { | ||
422 | /* enable CF power */ | ||
423 | status = inw((unsigned int)PLD_CPCR); | ||
424 | if (!(status & PLD_CPCR_CF)) { | ||
425 | debug(3, "m32r_cfc: _pcc_get_status: " | ||
426 | "power on (CPCR=0x%08x)\n", status); | ||
427 | status |= PLD_CPCR_CF; | ||
428 | outw(status, (unsigned int)PLD_CPCR); | ||
429 | udelay(100); | ||
430 | } | ||
431 | *value |= SS_POWERON; | ||
432 | |||
433 | pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);/* enable buffer */ | ||
434 | udelay(100); | ||
435 | |||
436 | *value |= SS_READY; /* always ready */ | ||
437 | *value |= SS_3VCARD; | ||
438 | } else { | ||
439 | /* disable CF power */ | ||
440 | status = inw((unsigned int)PLD_CPCR); | ||
441 | status &= ~PLD_CPCR_CF; | ||
442 | outw(status, (unsigned int)PLD_CPCR); | ||
443 | udelay(100); | ||
444 | debug(3, "m32r_cfc: _pcc_get_status: " | ||
445 | "power off (CPCR=0x%08x)\n", status); | ||
446 | } | ||
447 | #elif defined(CONFIG_PLAT_MAPPI2) | ||
448 | if ( status ) { | ||
449 | status = pcc_get(sock, (unsigned int)PLD_CPCR); | ||
450 | if (status == 0) { /* power off */ | ||
451 | pcc_set(sock, (unsigned int)PLD_CPCR, 1); | ||
452 | pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */ | ||
453 | udelay(50); | ||
454 | } | ||
455 | status = pcc_get(sock, (unsigned int)PLD_CFBUFCR); | ||
456 | if (status != 0) { /* buffer off */ | ||
457 | pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); | ||
458 | udelay(50); | ||
459 | pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101); | ||
460 | udelay(25); /* for IDE reset */ | ||
461 | pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100); | ||
462 | mdelay(2); /* for IDE reset */ | ||
463 | } else { | ||
464 | *value |= SS_POWERON; | ||
465 | *value |= SS_READY; | ||
466 | } | ||
467 | } | ||
468 | #else | ||
469 | #error no platform configuration | ||
470 | #endif | ||
471 | debug(3, "m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n", | ||
472 | sock, *value); | ||
473 | return 0; | ||
474 | } /* _get_status */ | ||
475 | |||
476 | /*====================================================================*/ | ||
477 | |||
478 | static int _pcc_get_socket(u_short sock, socket_state_t *state) | ||
479 | { | ||
480 | // pcc_socket_t *t = &socket[sock]; | ||
481 | |||
482 | #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) | ||
483 | state->flags = 0; | ||
484 | state->csc_mask = SS_DETECT; | ||
485 | state->csc_mask |= SS_READY; | ||
486 | state->io_irq = 0; | ||
487 | state->Vcc = 33; /* 3.3V fixed */ | ||
488 | state->Vpp = 33; | ||
489 | #endif | ||
490 | debug(3, "m32r_cfc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
491 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
492 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
493 | return 0; | ||
494 | } /* _get_socket */ | ||
495 | |||
496 | /*====================================================================*/ | ||
497 | |||
498 | static int _pcc_set_socket(u_short sock, socket_state_t *state) | ||
499 | { | ||
500 | #if defined(CONFIG_PLAT_MAPPI2) | ||
501 | u_long reg = 0; | ||
502 | #endif | ||
503 | debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | ||
504 | "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, | ||
505 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
506 | |||
507 | #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) | ||
508 | if (state->Vcc) { | ||
509 | if ((state->Vcc != 50) && (state->Vcc != 33)) | ||
510 | return -EINVAL; | ||
511 | /* accept 5V and 3.3V */ | ||
512 | } | ||
513 | #elif defined(CONFIG_PLAT_MAPPI2) | ||
514 | if (state->Vcc) { | ||
515 | /* | ||
516 | * 5V only | ||
517 | */ | ||
518 | if (state->Vcc == 50) { | ||
519 | reg |= PCCSIGCR_VEN; | ||
520 | } else { | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | } | ||
524 | #endif | ||
525 | |||
526 | if (state->flags & SS_RESET) { | ||
527 | debug(3, ":RESET\n"); | ||
528 | pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101); | ||
529 | }else{ | ||
530 | pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x100); | ||
531 | } | ||
532 | if (state->flags & SS_OUTPUT_ENA){ | ||
533 | debug(3, ":OUTPUT_ENA\n"); | ||
534 | /* bit clear */ | ||
535 | pcc_set(sock,(unsigned int)PLD_CFBUFCR,0); | ||
536 | } else { | ||
537 | pcc_set(sock,(unsigned int)PLD_CFBUFCR,1); | ||
538 | } | ||
539 | |||
540 | #ifdef DEBUG | ||
541 | if(state->flags & SS_IOCARD){ | ||
542 | debug(3, ":IOCARD"); | ||
543 | } | ||
544 | if (state->flags & SS_PWR_AUTO) { | ||
545 | debug(3, ":PWR_AUTO"); | ||
546 | } | ||
547 | if (state->csc_mask & SS_DETECT) | ||
548 | debug(3, ":csc-SS_DETECT"); | ||
549 | if (state->flags & SS_IOCARD) { | ||
550 | if (state->csc_mask & SS_STSCHG) | ||
551 | debug(3, ":STSCHG"); | ||
552 | } else { | ||
553 | if (state->csc_mask & SS_BATDEAD) | ||
554 | debug(3, ":BATDEAD"); | ||
555 | if (state->csc_mask & SS_BATWARN) | ||
556 | debug(3, ":BATWARN"); | ||
557 | if (state->csc_mask & SS_READY) | ||
558 | debug(3, ":READY"); | ||
559 | } | ||
560 | debug(3, "\n"); | ||
561 | #endif | ||
562 | return 0; | ||
563 | } /* _set_socket */ | ||
564 | |||
565 | /*====================================================================*/ | ||
566 | |||
567 | static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io) | ||
568 | { | ||
569 | u_char map; | ||
570 | |||
571 | debug(3, "m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, " | ||
572 | "%#lx-%#lx)\n", sock, io->map, io->flags, | ||
573 | io->speed, io->start, io->stop); | ||
574 | map = io->map; | ||
575 | |||
576 | return 0; | ||
577 | } /* _set_io_map */ | ||
578 | |||
579 | /*====================================================================*/ | ||
580 | |||
581 | static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem) | ||
582 | { | ||
583 | |||
584 | u_char map = mem->map; | ||
585 | u_long addr; | ||
586 | pcc_socket_t *t = &socket[sock]; | ||
587 | |||
588 | debug(3, "m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, " | ||
589 | "%#lx, %#x)\n", sock, map, mem->flags, | ||
590 | mem->speed, mem->static_start, mem->card_start); | ||
591 | |||
592 | /* | ||
593 | * sanity check | ||
594 | */ | ||
595 | if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){ | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | /* | ||
600 | * de-activate | ||
601 | */ | ||
602 | if ((mem->flags & MAP_ACTIVE) == 0) { | ||
603 | t->current_space = as_none; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Set mode | ||
609 | */ | ||
610 | if (mem->flags & MAP_ATTRIB) { | ||
611 | t->current_space = as_attr; | ||
612 | } else { | ||
613 | t->current_space = as_comm; | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Set address | ||
618 | */ | ||
619 | addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK); | ||
620 | mem->static_start = addr + mem->card_start; | ||
621 | |||
622 | return 0; | ||
623 | |||
624 | } /* _set_mem_map */ | ||
625 | |||
626 | #if 0 /* driver model ordering issue */ | ||
627 | /*====================================================================== | ||
628 | |||
629 | Routines for accessing socket information and register dumps via | ||
630 | /proc/bus/pccard/... | ||
631 | |||
632 | ======================================================================*/ | ||
633 | |||
634 | static ssize_t show_info(struct class_device *class_dev, char *buf) | ||
635 | { | ||
636 | pcc_socket_t *s = container_of(class_dev, struct pcc_socket, | ||
637 | socket.dev); | ||
638 | |||
639 | return sprintf(buf, "type: %s\nbase addr: 0x%08lx\n", | ||
640 | pcc[s->type].name, s->base); | ||
641 | } | ||
642 | |||
643 | static ssize_t show_exca(struct class_device *class_dev, char *buf) | ||
644 | { | ||
645 | /* FIXME */ | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL); | ||
651 | static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL); | ||
652 | #endif | ||
653 | |||
654 | /*====================================================================*/ | ||
655 | |||
656 | /* this is horribly ugly... proper locking needs to be done here at | ||
657 | * some time... */ | ||
658 | #define LOCKED(x) do { \ | ||
659 | int retval; \ | ||
660 | unsigned long flags; \ | ||
661 | spin_lock_irqsave(&pcc_lock, flags); \ | ||
662 | retval = x; \ | ||
663 | spin_unlock_irqrestore(&pcc_lock, flags); \ | ||
664 | return retval; \ | ||
665 | } while (0) | ||
666 | |||
667 | |||
668 | static int pcc_get_status(struct pcmcia_socket *s, u_int *value) | ||
669 | { | ||
670 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
671 | |||
672 | if (socket[sock].flags & IS_ALIVE) { | ||
673 | debug(3, "m32r_cfc: pcc_get_status: sock(%d) -EINVAL\n", sock); | ||
674 | *value = 0; | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | debug(3, "m32r_cfc: pcc_get_status: sock(%d)\n", sock); | ||
678 | LOCKED(_pcc_get_status(sock, value)); | ||
679 | } | ||
680 | |||
681 | static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
682 | { | ||
683 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
684 | |||
685 | if (socket[sock].flags & IS_ALIVE) { | ||
686 | debug(3, "m32r_cfc: pcc_get_socket: sock(%d) -EINVAL\n", sock); | ||
687 | return -EINVAL; | ||
688 | } | ||
689 | debug(3, "m32r_cfc: pcc_get_socket: sock(%d)\n", sock); | ||
690 | LOCKED(_pcc_get_socket(sock, state)); | ||
691 | } | ||
692 | |||
693 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
694 | { | ||
695 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
696 | |||
697 | if (socket[sock].flags & IS_ALIVE) { | ||
698 | debug(3, "m32r_cfc: pcc_set_socket: sock(%d) -EINVAL\n", sock); | ||
699 | return -EINVAL; | ||
700 | } | ||
701 | debug(3, "m32r_cfc: pcc_set_socket: sock(%d)\n", sock); | ||
702 | LOCKED(_pcc_set_socket(sock, state)); | ||
703 | } | ||
704 | |||
705 | static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) | ||
706 | { | ||
707 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
708 | |||
709 | if (socket[sock].flags & IS_ALIVE) { | ||
710 | debug(3, "m32r_cfc: pcc_set_io_map: sock(%d) -EINVAL\n", sock); | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | debug(3, "m32r_cfc: pcc_set_io_map: sock(%d)\n", sock); | ||
714 | LOCKED(_pcc_set_io_map(sock, io)); | ||
715 | } | ||
716 | |||
717 | static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) | ||
718 | { | ||
719 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
720 | |||
721 | if (socket[sock].flags & IS_ALIVE) { | ||
722 | debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d) -EINVAL\n", sock); | ||
723 | return -EINVAL; | ||
724 | } | ||
725 | debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d)\n", sock); | ||
726 | LOCKED(_pcc_set_mem_map(sock, mem)); | ||
727 | } | ||
728 | |||
729 | static int pcc_init(struct pcmcia_socket *s) | ||
730 | { | ||
731 | debug(3, "m32r_cfc: pcc_init()\n"); | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static struct pccard_operations pcc_operations = { | ||
736 | .init = pcc_init, | ||
737 | .get_status = pcc_get_status, | ||
738 | .get_socket = pcc_get_socket, | ||
739 | .set_socket = pcc_set_socket, | ||
740 | .set_io_map = pcc_set_io_map, | ||
741 | .set_mem_map = pcc_set_mem_map, | ||
742 | }; | ||
743 | |||
744 | /*====================================================================*/ | ||
745 | |||
746 | static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level) | ||
747 | { | ||
748 | int ret = 0; | ||
749 | if (level == SUSPEND_SAVE_STATE) | ||
750 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
751 | return ret; | ||
752 | } | ||
753 | |||
754 | static int m32r_pcc_resume(struct device *dev, u32 level) | ||
755 | { | ||
756 | int ret = 0; | ||
757 | if (level == RESUME_RESTORE_STATE) | ||
758 | ret = pcmcia_socket_dev_resume(dev); | ||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | |||
763 | static struct device_driver pcc_driver = { | ||
764 | .name = "cfc", | ||
765 | .bus = &platform_bus_type, | ||
766 | .suspend = m32r_pcc_suspend, | ||
767 | .resume = m32r_pcc_resume, | ||
768 | }; | ||
769 | |||
770 | static struct platform_device pcc_device = { | ||
771 | .name = "cfc", | ||
772 | .id = 0, | ||
773 | }; | ||
774 | |||
775 | /*====================================================================*/ | ||
776 | |||
777 | static int __init init_m32r_pcc(void) | ||
778 | { | ||
779 | int i, ret; | ||
780 | |||
781 | ret = driver_register(&pcc_driver); | ||
782 | if (ret) | ||
783 | return ret; | ||
784 | |||
785 | ret = platform_device_register(&pcc_device); | ||
786 | if (ret){ | ||
787 | driver_unregister(&pcc_driver); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | #if defined(CONFIG_PLAT_MAPPI2) | ||
792 | pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f); | ||
793 | pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200); | ||
794 | #endif | ||
795 | |||
796 | pcc_sockets = 0; | ||
797 | |||
798 | #if !defined(CONFIG_PLAT_USRV) | ||
799 | add_pcc_socket(M32R_PCC0_BASE, PLD_IRQ_CFC_INSERT, CFC_ATTR_MAPBASE, | ||
800 | CFC_IOPORT_BASE); | ||
801 | #else /* CONFIG_PLAT_USRV */ | ||
802 | { | ||
803 | ulong base, mapaddr; | ||
804 | kio_addr_t ioaddr; | ||
805 | |||
806 | for (i = 0 ; i < M32R_MAX_PCC ; i++) { | ||
807 | base = (ulong)PLD_CFRSTCR; | ||
808 | base = base | (i << 8); | ||
809 | ioaddr = (i + 1) << 12; | ||
810 | mapaddr = CFC_ATTR_MAPBASE | (i << 20); | ||
811 | add_pcc_socket(base, 0, mapaddr, ioaddr); | ||
812 | } | ||
813 | } | ||
814 | #endif /* CONFIG_PLAT_USRV */ | ||
815 | |||
816 | if (pcc_sockets == 0) { | ||
817 | printk("socket is not found.\n"); | ||
818 | platform_device_unregister(&pcc_device); | ||
819 | driver_unregister(&pcc_driver); | ||
820 | return -ENODEV; | ||
821 | } | ||
822 | |||
823 | /* Set up interrupt handler(s) */ | ||
824 | |||
825 | for (i = 0 ; i < pcc_sockets ; i++) { | ||
826 | socket[i].socket.dev.dev = &pcc_device.dev; | ||
827 | socket[i].socket.ops = &pcc_operations; | ||
828 | socket[i].socket.resource_ops = &pccard_static_ops; | ||
829 | socket[i].socket.owner = THIS_MODULE; | ||
830 | socket[i].number = i; | ||
831 | ret = pcmcia_register_socket(&socket[i].socket); | ||
832 | if (!ret) | ||
833 | socket[i].flags |= IS_REGISTERED; | ||
834 | |||
835 | #if 0 /* driver model ordering issue */ | ||
836 | class_device_create_file(&socket[i].socket.dev, | ||
837 | &class_device_attr_info); | ||
838 | class_device_create_file(&socket[i].socket.dev, | ||
839 | &class_device_attr_exca); | ||
840 | #endif | ||
841 | } | ||
842 | |||
843 | /* Finally, schedule a polling interrupt */ | ||
844 | if (poll_interval != 0) { | ||
845 | poll_timer.function = pcc_interrupt_wrapper; | ||
846 | poll_timer.data = 0; | ||
847 | init_timer(&poll_timer); | ||
848 | poll_timer.expires = jiffies + poll_interval; | ||
849 | add_timer(&poll_timer); | ||
850 | } | ||
851 | |||
852 | return 0; | ||
853 | } /* init_m32r_pcc */ | ||
854 | |||
855 | static void __exit exit_m32r_pcc(void) | ||
856 | { | ||
857 | int i; | ||
858 | |||
859 | for (i = 0; i < pcc_sockets; i++) | ||
860 | if (socket[i].flags & IS_REGISTERED) | ||
861 | pcmcia_unregister_socket(&socket[i].socket); | ||
862 | |||
863 | platform_device_unregister(&pcc_device); | ||
864 | if (poll_interval != 0) | ||
865 | del_timer_sync(&poll_timer); | ||
866 | |||
867 | driver_unregister(&pcc_driver); | ||
868 | } /* exit_m32r_pcc */ | ||
869 | |||
870 | module_init(init_m32r_pcc); | ||
871 | module_exit(exit_m32r_pcc); | ||
872 | MODULE_LICENSE("Dual MPL/GPL"); | ||
873 | /*====================================================================*/ | ||
diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h new file mode 100644 index 000000000000..17c1db7ae155 --- /dev/null +++ b/drivers/pcmcia/m32r_cfc.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 by Hiroyuki Kondo | ||
3 | */ | ||
4 | |||
5 | #if !defined(CONFIG_M32R_CFC_NUM) | ||
6 | #define M32R_MAX_PCC 2 | ||
7 | #else | ||
8 | #define M32R_MAX_PCC CONFIG_M32R_CFC_NUM | ||
9 | #endif | ||
10 | |||
11 | /* | ||
12 | * M32R PC Card Controler | ||
13 | */ | ||
14 | #define M32R_PCC0_BASE 0x00ef7000 | ||
15 | #define M32R_PCC1_BASE 0x00ef7020 | ||
16 | |||
17 | /* | ||
18 | * Register offsets | ||
19 | */ | ||
20 | #define PCCR 0x00 | ||
21 | #define PCADR 0x04 | ||
22 | #define PCMOD 0x08 | ||
23 | #define PCIRC 0x0c | ||
24 | #define PCCSIGCR 0x10 | ||
25 | #define PCATCR 0x14 | ||
26 | |||
27 | /* | ||
28 | * PCCR | ||
29 | */ | ||
30 | #define PCCR_PCEN (1UL<<(31-31)) | ||
31 | |||
32 | /* | ||
33 | * PCIRC | ||
34 | */ | ||
35 | #define PCIRC_BWERR (1UL<<(31-7)) | ||
36 | #define PCIRC_CDIN1 (1UL<<(31-14)) | ||
37 | #define PCIRC_CDIN2 (1UL<<(31-15)) | ||
38 | #define PCIRC_BEIEN (1UL<<(31-23)) | ||
39 | #define PCIRC_CIIEN (1UL<<(31-30)) | ||
40 | #define PCIRC_COIEN (1UL<<(31-31)) | ||
41 | |||
42 | /* | ||
43 | * PCCSIGCR | ||
44 | */ | ||
45 | #define PCCSIGCR_SEN (1UL<<(31-3)) | ||
46 | #define PCCSIGCR_VEN (1UL<<(31-7)) | ||
47 | #define PCCSIGCR_CRST (1UL<<(31-15)) | ||
48 | #define PCCSIGCR_COCR (1UL<<(31-31)) | ||
49 | |||
50 | /* | ||
51 | * | ||
52 | */ | ||
53 | #define PCMOD_AS_ATTRIB (1UL<<(31-19)) | ||
54 | #define PCMOD_AS_IO (1UL<<(31-18)) | ||
55 | |||
56 | #define PCMOD_CBSZ (1UL<<(31-23)) /* set for 8bit */ | ||
57 | |||
58 | #define PCMOD_DBEX (1UL<<(31-31)) /* set for excahnge */ | ||
59 | |||
60 | /* | ||
61 | * M32R PCC Map addr | ||
62 | */ | ||
63 | |||
64 | #define M32R_PCC0_MAPBASE 0x14000000 | ||
65 | #define M32R_PCC1_MAPBASE 0x16000000 | ||
66 | |||
67 | #define M32R_PCC_MAPMAX 0x02000000 | ||
68 | |||
69 | #define M32R_PCC_MAPSIZE 0x00001000 /* XXX */ | ||
70 | #define M32R_PCC_MAPMASK (~(M32R_PCC_MAPMAX-1)) | ||
71 | |||
72 | #define CFC_IOPORT_BASE 0x1000 | ||
73 | |||
74 | #if !defined(CONFIG_PLAT_USRV) | ||
75 | #define CFC_ATTR_MAPBASE 0x0c014000 | ||
76 | #define CFC_IO_MAPBASE_BYTE 0xac012000 | ||
77 | #define CFC_IO_MAPBASE_WORD 0xac002000 | ||
78 | #else /* CONFIG_PLAT_USRV */ | ||
79 | #define CFC_ATTR_MAPBASE 0x04014000 | ||
80 | #define CFC_IO_MAPBASE_BYTE 0xa4012000 | ||
81 | #define CFC_IO_MAPBASE_WORD 0xa4002000 | ||
82 | #endif /* CONFIG_PLAT_USRV */ | ||
83 | |||
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c new file mode 100644 index 000000000000..cafba6f45dfa --- /dev/null +++ b/drivers/pcmcia/m32r_pcc.c | |||
@@ -0,0 +1,811 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/m32r_pcc.c | ||
3 | * | ||
4 | * Device driver for the PCMCIA functionality of M32R. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002, 2003, 2004 | ||
7 | * Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/fcntl.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/bitops.h> | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/addrspace.h> | ||
32 | |||
33 | #include <pcmcia/version.h> | ||
34 | #include <pcmcia/cs_types.h> | ||
35 | #include <pcmcia/ss.h> | ||
36 | #include <pcmcia/cs.h> | ||
37 | |||
38 | /* XXX: should be moved into asm/irq.h */ | ||
39 | #define PCC0_IRQ 24 | ||
40 | #define PCC1_IRQ 25 | ||
41 | |||
42 | #include "m32r_pcc.h" | ||
43 | |||
44 | #define CHAOS_PCC_DEBUG | ||
45 | #ifdef CHAOS_PCC_DEBUG | ||
46 | static volatile u_short dummy_readbuf; | ||
47 | #endif | ||
48 | |||
49 | #define PCC_DEBUG_DBEX | ||
50 | |||
51 | #ifdef DEBUG | ||
52 | static int m32r_pcc_debug; | ||
53 | module_param(m32r_pcc_debug, int, 0644); | ||
54 | #define debug(lvl, fmt, arg...) do { \ | ||
55 | if (m32r_pcc_debug > (lvl)) \ | ||
56 | printk(KERN_DEBUG "m32r_pcc: " fmt , ## arg); \ | ||
57 | } while (0) | ||
58 | #else | ||
59 | #define debug(n, args...) do { } while (0) | ||
60 | #endif | ||
61 | |||
62 | /* Poll status interval -- 0 means default to interrupt */ | ||
63 | static int poll_interval = 0; | ||
64 | |||
65 | typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t; | ||
66 | |||
67 | typedef struct pcc_socket { | ||
68 | u_short type, flags; | ||
69 | struct pcmcia_socket socket; | ||
70 | unsigned int number; | ||
71 | kio_addr_t ioaddr; | ||
72 | u_long mapaddr; | ||
73 | u_long base; /* PCC register base */ | ||
74 | u_char cs_irq, intr; | ||
75 | pccard_io_map io_map[MAX_IO_WIN]; | ||
76 | pccard_mem_map mem_map[MAX_WIN]; | ||
77 | u_char io_win; | ||
78 | u_char mem_win; | ||
79 | pcc_as_t current_space; | ||
80 | u_char last_iodbex; | ||
81 | #ifdef CHAOS_PCC_DEBUG | ||
82 | u_char last_iosize; | ||
83 | #endif | ||
84 | #ifdef CONFIG_PROC_FS | ||
85 | struct proc_dir_entry *proc; | ||
86 | #endif | ||
87 | } pcc_socket_t; | ||
88 | |||
89 | static int pcc_sockets = 0; | ||
90 | static pcc_socket_t socket[M32R_MAX_PCC] = { | ||
91 | { 0, }, /* ... */ | ||
92 | }; | ||
93 | |||
94 | /*====================================================================*/ | ||
95 | |||
96 | static unsigned int pcc_get(u_short, unsigned int); | ||
97 | static void pcc_set(u_short, unsigned int , unsigned int ); | ||
98 | |||
99 | static DEFINE_SPINLOCK(pcc_lock); | ||
100 | |||
101 | void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag) | ||
102 | { | ||
103 | u_long addr; | ||
104 | u_long flags; | ||
105 | int need_ex; | ||
106 | #ifdef PCC_DEBUG_DBEX | ||
107 | int _dbex; | ||
108 | #endif | ||
109 | pcc_socket_t *t = &socket[sock]; | ||
110 | #ifdef CHAOS_PCC_DEBUG | ||
111 | int map_changed = 0; | ||
112 | #endif | ||
113 | |||
114 | /* Need lock ? */ | ||
115 | spin_lock_irqsave(&pcc_lock, flags); | ||
116 | |||
117 | /* | ||
118 | * Check if need dbex | ||
119 | */ | ||
120 | need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0; | ||
121 | #ifdef PCC_DEBUG_DBEX | ||
122 | _dbex = need_ex; | ||
123 | need_ex = 0; | ||
124 | #endif | ||
125 | |||
126 | /* | ||
127 | * calculate access address | ||
128 | */ | ||
129 | addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */ | ||
130 | |||
131 | /* | ||
132 | * Check current mapping | ||
133 | */ | ||
134 | if (t->current_space != as_io || t->last_iodbex != need_ex) { | ||
135 | |||
136 | u_long cbsz; | ||
137 | |||
138 | /* | ||
139 | * Disable first | ||
140 | */ | ||
141 | pcc_set(sock, PCCR, 0); | ||
142 | |||
143 | /* | ||
144 | * Set mode and io address | ||
145 | */ | ||
146 | cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ; | ||
147 | pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex); | ||
148 | pcc_set(sock, PCADR, addr & 0x1ff00000); | ||
149 | |||
150 | /* | ||
151 | * Enable and read it | ||
152 | */ | ||
153 | pcc_set(sock, PCCR, 1); | ||
154 | |||
155 | #ifdef CHAOS_PCC_DEBUG | ||
156 | #if 0 | ||
157 | map_changed = (t->current_space == as_attr && size == 2); /* XXX */ | ||
158 | #else | ||
159 | map_changed = 1; | ||
160 | #endif | ||
161 | #endif | ||
162 | t->current_space = as_io; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * access to IO space | ||
167 | */ | ||
168 | if (size == 1) { | ||
169 | /* Byte */ | ||
170 | unsigned char *bp = (unsigned char *)buf; | ||
171 | |||
172 | #ifdef CHAOS_DEBUG | ||
173 | if (map_changed) { | ||
174 | dummy_readbuf = readb(addr); | ||
175 | } | ||
176 | #endif | ||
177 | if (wr) { | ||
178 | /* write Byte */ | ||
179 | while (nmemb--) { | ||
180 | writeb(*bp++, addr); | ||
181 | } | ||
182 | } else { | ||
183 | /* read Byte */ | ||
184 | while (nmemb--) { | ||
185 | *bp++ = readb(addr); | ||
186 | } | ||
187 | } | ||
188 | } else { | ||
189 | /* Word */ | ||
190 | unsigned short *bp = (unsigned short *)buf; | ||
191 | |||
192 | #ifdef CHAOS_PCC_DEBUG | ||
193 | if (map_changed) { | ||
194 | dummy_readbuf = readw(addr); | ||
195 | } | ||
196 | #endif | ||
197 | if (wr) { | ||
198 | /* write Word */ | ||
199 | while (nmemb--) { | ||
200 | #ifdef PCC_DEBUG_DBEX | ||
201 | if (_dbex) { | ||
202 | unsigned char *cp = (unsigned char *)bp; | ||
203 | unsigned short tmp; | ||
204 | tmp = cp[1] << 8 | cp[0]; | ||
205 | writew(tmp, addr); | ||
206 | bp++; | ||
207 | } else | ||
208 | #endif | ||
209 | writew(*bp++, addr); | ||
210 | } | ||
211 | } else { | ||
212 | /* read Word */ | ||
213 | while (nmemb--) { | ||
214 | #ifdef PCC_DEBUG_DBEX | ||
215 | if (_dbex) { | ||
216 | unsigned char *cp = (unsigned char *)bp; | ||
217 | unsigned short tmp; | ||
218 | tmp = readw(addr); | ||
219 | cp[0] = tmp & 0xff; | ||
220 | cp[1] = (tmp >> 8) & 0xff; | ||
221 | bp++; | ||
222 | } else | ||
223 | #endif | ||
224 | *bp++ = readw(addr); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | #if 1 | ||
230 | /* addr is no longer used */ | ||
231 | if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) { | ||
232 | printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n", | ||
233 | port, size * 8); | ||
234 | pcc_set(sock, PCIRC, addr); | ||
235 | } | ||
236 | #endif | ||
237 | /* | ||
238 | * save state | ||
239 | */ | ||
240 | t->last_iosize = size; | ||
241 | t->last_iodbex = need_ex; | ||
242 | |||
243 | /* Need lock ? */ | ||
244 | |||
245 | spin_unlock_irqrestore(&pcc_lock,flags); | ||
246 | |||
247 | return; | ||
248 | } | ||
249 | |||
250 | void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) { | ||
251 | pcc_iorw(sock, port, buf, size, nmemb, 0, flag); | ||
252 | } | ||
253 | |||
254 | void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) { | ||
255 | pcc_iorw(sock, port, buf, size, nmemb, 1, flag); | ||
256 | } | ||
257 | |||
258 | /*====================================================================*/ | ||
259 | |||
260 | #define IS_REGISTERED 0x2000 | ||
261 | #define IS_ALIVE 0x8000 | ||
262 | |||
263 | typedef struct pcc_t { | ||
264 | char *name; | ||
265 | u_short flags; | ||
266 | } pcc_t; | ||
267 | |||
268 | static pcc_t pcc[] = { | ||
269 | { "xnux2", 0 }, { "xnux2", 0 }, | ||
270 | }; | ||
271 | |||
272 | static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *); | ||
273 | |||
274 | /*====================================================================*/ | ||
275 | |||
276 | static struct timer_list poll_timer; | ||
277 | |||
278 | static unsigned int pcc_get(u_short sock, unsigned int reg) | ||
279 | { | ||
280 | return inl(socket[sock].base + reg); | ||
281 | } | ||
282 | |||
283 | |||
284 | static void pcc_set(u_short sock, unsigned int reg, unsigned int data) | ||
285 | { | ||
286 | outl(data, socket[sock].base + reg); | ||
287 | } | ||
288 | |||
289 | /*====================================================================== | ||
290 | |||
291 | See if a card is present, powered up, in IO mode, and already | ||
292 | bound to a (non PC Card) Linux driver. We leave these alone. | ||
293 | |||
294 | We make an exception for cards that seem to be serial devices. | ||
295 | |||
296 | ======================================================================*/ | ||
297 | |||
298 | static int __init is_alive(u_short sock) | ||
299 | { | ||
300 | unsigned int stat; | ||
301 | unsigned int f; | ||
302 | |||
303 | stat = pcc_get(sock, PCIRC); | ||
304 | f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16; | ||
305 | if(!f){ | ||
306 | printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock); | ||
307 | return 0; | ||
308 | } | ||
309 | if(f!=3) | ||
310 | printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock); | ||
311 | else | ||
312 | printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,stat); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr) | ||
317 | { | ||
318 | pcc_socket_t *t = &socket[pcc_sockets]; | ||
319 | |||
320 | /* add sockets */ | ||
321 | t->ioaddr = ioaddr; | ||
322 | t->mapaddr = mapaddr; | ||
323 | t->base = base; | ||
324 | #ifdef CHAOS_PCC_DEBUG | ||
325 | t->flags = MAP_16BIT; | ||
326 | #else | ||
327 | t->flags = 0; | ||
328 | #endif | ||
329 | if (is_alive(pcc_sockets)) | ||
330 | t->flags |= IS_ALIVE; | ||
331 | |||
332 | /* add pcc */ | ||
333 | if (t->base > 0) { | ||
334 | request_region(t->base, 0x20, "m32r-pcc"); | ||
335 | } | ||
336 | |||
337 | printk(KERN_INFO " %s ", pcc[pcc_sockets].name); | ||
338 | printk("pcc at 0x%08lx\n", t->base); | ||
339 | |||
340 | /* Update socket interrupt information, capabilities */ | ||
341 | t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP); | ||
342 | t->socket.map_size = M32R_PCC_MAPSIZE; | ||
343 | t->socket.io_offset = ioaddr; /* use for io access offset */ | ||
344 | t->socket.irq_mask = 0; | ||
345 | t->socket.pci_irq = 2 + pcc_sockets; /* XXX */ | ||
346 | |||
347 | request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt); | ||
348 | |||
349 | pcc_sockets++; | ||
350 | |||
351 | return; | ||
352 | } | ||
353 | |||
354 | |||
355 | /*====================================================================*/ | ||
356 | |||
357 | static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
358 | { | ||
359 | int i, j, irc; | ||
360 | u_int events, active; | ||
361 | int handled = 0; | ||
362 | |||
363 | debug(4, "m32r: pcc_interrupt(%d)\n", irq); | ||
364 | |||
365 | for (j = 0; j < 20; j++) { | ||
366 | active = 0; | ||
367 | for (i = 0; i < pcc_sockets; i++) { | ||
368 | if ((socket[i].cs_irq != irq) && | ||
369 | (socket[i].socket.pci_irq != irq)) | ||
370 | continue; | ||
371 | handled = 1; | ||
372 | irc = pcc_get(i, PCIRC); | ||
373 | irc >>=16; | ||
374 | debug(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc); | ||
375 | if (!irc) | ||
376 | continue; | ||
377 | |||
378 | events = (irc) ? SS_DETECT : 0; | ||
379 | events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0; | ||
380 | debug(2, " event 0x%02x\n", events); | ||
381 | |||
382 | if (events) | ||
383 | pcmcia_parse_events(&socket[i].socket, events); | ||
384 | |||
385 | active |= events; | ||
386 | active = 0; | ||
387 | } | ||
388 | if (!active) break; | ||
389 | } | ||
390 | if (j == 20) | ||
391 | printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n"); | ||
392 | |||
393 | debug(4, "m32r-pcc: interrupt done\n"); | ||
394 | |||
395 | return IRQ_RETVAL(handled); | ||
396 | } /* pcc_interrupt */ | ||
397 | |||
398 | static void pcc_interrupt_wrapper(u_long data) | ||
399 | { | ||
400 | pcc_interrupt(0, NULL, NULL); | ||
401 | init_timer(&poll_timer); | ||
402 | poll_timer.expires = jiffies + poll_interval; | ||
403 | add_timer(&poll_timer); | ||
404 | } | ||
405 | |||
406 | /*====================================================================*/ | ||
407 | |||
408 | static int _pcc_get_status(u_short sock, u_int *value) | ||
409 | { | ||
410 | u_int status; | ||
411 | |||
412 | status = pcc_get(sock,PCIRC); | ||
413 | *value = ((status & PCIRC_CDIN1) && (status & PCIRC_CDIN2)) | ||
414 | ? SS_DETECT : 0; | ||
415 | |||
416 | status = pcc_get(sock,PCCR); | ||
417 | |||
418 | #if 0 | ||
419 | *value |= (status & PCCR_PCEN) ? SS_READY : 0; | ||
420 | #else | ||
421 | *value |= SS_READY; /* XXX: always */ | ||
422 | #endif | ||
423 | |||
424 | status = pcc_get(sock,PCCSIGCR); | ||
425 | *value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0; | ||
426 | |||
427 | debug(3, "m32r-pcc: GetStatus(%d) = %#4.4x\n", sock, *value); | ||
428 | return 0; | ||
429 | } /* _get_status */ | ||
430 | |||
431 | /*====================================================================*/ | ||
432 | |||
433 | static int _pcc_get_socket(u_short sock, socket_state_t *state) | ||
434 | { | ||
435 | debug(3, "m32r-pcc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
436 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
437 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
438 | return 0; | ||
439 | } /* _get_socket */ | ||
440 | |||
441 | /*====================================================================*/ | ||
442 | |||
443 | static int _pcc_set_socket(u_short sock, socket_state_t *state) | ||
444 | { | ||
445 | u_long reg = 0; | ||
446 | |||
447 | debug(3, "m32r-pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | ||
448 | "io_irq %d, csc_mask %#2.2x)", sock, state->flags, | ||
449 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
450 | |||
451 | if (state->Vcc) { | ||
452 | /* | ||
453 | * 5V only | ||
454 | */ | ||
455 | if (state->Vcc == 50) { | ||
456 | reg |= PCCSIGCR_VEN; | ||
457 | } else { | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | if (state->flags & SS_RESET) { | ||
463 | debug(3, ":RESET\n"); | ||
464 | reg |= PCCSIGCR_CRST; | ||
465 | } | ||
466 | if (state->flags & SS_OUTPUT_ENA){ | ||
467 | debug(3, ":OUTPUT_ENA\n"); | ||
468 | /* bit clear */ | ||
469 | } else { | ||
470 | reg |= PCCSIGCR_SEN; | ||
471 | } | ||
472 | |||
473 | pcc_set(sock,PCCSIGCR,reg); | ||
474 | |||
475 | #ifdef DEBUG | ||
476 | if(state->flags & SS_IOCARD){ | ||
477 | debug(3, ":IOCARD"); | ||
478 | } | ||
479 | if (state->flags & SS_PWR_AUTO) { | ||
480 | debug(3, ":PWR_AUTO"); | ||
481 | } | ||
482 | if (state->csc_mask & SS_DETECT) | ||
483 | debug(3, ":csc-SS_DETECT"); | ||
484 | if (state->flags & SS_IOCARD) { | ||
485 | if (state->csc_mask & SS_STSCHG) | ||
486 | debug(3, ":STSCHG"); | ||
487 | } else { | ||
488 | if (state->csc_mask & SS_BATDEAD) | ||
489 | debug(3, ":BATDEAD"); | ||
490 | if (state->csc_mask & SS_BATWARN) | ||
491 | debug(3, ":BATWARN"); | ||
492 | if (state->csc_mask & SS_READY) | ||
493 | debug(3, ":READY"); | ||
494 | } | ||
495 | debug(3, "\n"); | ||
496 | #endif | ||
497 | return 0; | ||
498 | } /* _set_socket */ | ||
499 | |||
500 | /*====================================================================*/ | ||
501 | |||
502 | static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io) | ||
503 | { | ||
504 | u_char map; | ||
505 | |||
506 | debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, " | ||
507 | "%#lx-%#lx)\n", sock, io->map, io->flags, | ||
508 | io->speed, io->start, io->stop); | ||
509 | map = io->map; | ||
510 | |||
511 | return 0; | ||
512 | } /* _set_io_map */ | ||
513 | |||
514 | /*====================================================================*/ | ||
515 | |||
516 | static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem) | ||
517 | { | ||
518 | |||
519 | u_char map = mem->map; | ||
520 | u_long mode; | ||
521 | u_long addr; | ||
522 | pcc_socket_t *t = &socket[sock]; | ||
523 | #ifdef CHAOS_PCC_DEBUG | ||
524 | #if 0 | ||
525 | pcc_as_t last = t->current_space; | ||
526 | #endif | ||
527 | #endif | ||
528 | |||
529 | debug(3, "m32r-pcc: SetMemMap(%d, %d, %#2.2x, %d ns, " | ||
530 | "%#lx, %#x)\n", sock, map, mem->flags, | ||
531 | mem->speed, mem->static_start, mem->card_start); | ||
532 | |||
533 | /* | ||
534 | * sanity check | ||
535 | */ | ||
536 | if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){ | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * de-activate | ||
542 | */ | ||
543 | if ((mem->flags & MAP_ACTIVE) == 0) { | ||
544 | t->current_space = as_none; | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * Disable first | ||
550 | */ | ||
551 | pcc_set(sock, PCCR, 0); | ||
552 | |||
553 | /* | ||
554 | * Set mode | ||
555 | */ | ||
556 | if (mem->flags & MAP_ATTRIB) { | ||
557 | mode = PCMOD_AS_ATTRIB | PCMOD_CBSZ; | ||
558 | t->current_space = as_attr; | ||
559 | } else { | ||
560 | mode = 0; /* common memory */ | ||
561 | t->current_space = as_comm; | ||
562 | } | ||
563 | pcc_set(sock, PCMOD, mode); | ||
564 | |||
565 | /* | ||
566 | * Set address | ||
567 | */ | ||
568 | addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK); | ||
569 | pcc_set(sock, PCADR, addr); | ||
570 | |||
571 | mem->static_start = addr + mem->card_start; | ||
572 | |||
573 | /* | ||
574 | * Enable again | ||
575 | */ | ||
576 | pcc_set(sock, PCCR, 1); | ||
577 | |||
578 | #ifdef CHAOS_PCC_DEBUG | ||
579 | #if 0 | ||
580 | if (last != as_attr) { | ||
581 | #else | ||
582 | if (1) { | ||
583 | #endif | ||
584 | dummy_readbuf = *(u_char *)(addr + KSEG1); | ||
585 | } | ||
586 | #endif | ||
587 | |||
588 | return 0; | ||
589 | |||
590 | } /* _set_mem_map */ | ||
591 | |||
592 | #if 0 /* driver model ordering issue */ | ||
593 | /*====================================================================== | ||
594 | |||
595 | Routines for accessing socket information and register dumps via | ||
596 | /proc/bus/pccard/... | ||
597 | |||
598 | ======================================================================*/ | ||
599 | |||
600 | static ssize_t show_info(struct class_device *class_dev, char *buf) | ||
601 | { | ||
602 | pcc_socket_t *s = container_of(class_dev, struct pcc_socket, | ||
603 | socket.dev); | ||
604 | |||
605 | return sprintf(buf, "type: %s\nbase addr: 0x%08lx\n", | ||
606 | pcc[s->type].name, s->base); | ||
607 | } | ||
608 | |||
609 | static ssize_t show_exca(struct class_device *class_dev, char *buf) | ||
610 | { | ||
611 | /* FIXME */ | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL); | ||
617 | static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL); | ||
618 | #endif | ||
619 | |||
620 | /*====================================================================*/ | ||
621 | |||
622 | /* this is horribly ugly... proper locking needs to be done here at | ||
623 | * some time... */ | ||
624 | #define LOCKED(x) do { \ | ||
625 | int retval; \ | ||
626 | unsigned long flags; \ | ||
627 | spin_lock_irqsave(&pcc_lock, flags); \ | ||
628 | retval = x; \ | ||
629 | spin_unlock_irqrestore(&pcc_lock, flags); \ | ||
630 | return retval; \ | ||
631 | } while (0) | ||
632 | |||
633 | |||
634 | static int pcc_get_status(struct pcmcia_socket *s, u_int *value) | ||
635 | { | ||
636 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
637 | |||
638 | if (socket[sock].flags & IS_ALIVE) { | ||
639 | *value = 0; | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | LOCKED(_pcc_get_status(sock, value)); | ||
643 | } | ||
644 | |||
645 | static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
646 | { | ||
647 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
648 | |||
649 | if (socket[sock].flags & IS_ALIVE) | ||
650 | return -EINVAL; | ||
651 | LOCKED(_pcc_get_socket(sock, state)); | ||
652 | } | ||
653 | |||
654 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
655 | { | ||
656 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
657 | |||
658 | if (socket[sock].flags & IS_ALIVE) | ||
659 | return -EINVAL; | ||
660 | |||
661 | LOCKED(_pcc_set_socket(sock, state)); | ||
662 | } | ||
663 | |||
664 | static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) | ||
665 | { | ||
666 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
667 | |||
668 | if (socket[sock].flags & IS_ALIVE) | ||
669 | return -EINVAL; | ||
670 | LOCKED(_pcc_set_io_map(sock, io)); | ||
671 | } | ||
672 | |||
673 | static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) | ||
674 | { | ||
675 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
676 | |||
677 | if (socket[sock].flags & IS_ALIVE) | ||
678 | return -EINVAL; | ||
679 | LOCKED(_pcc_set_mem_map(sock, mem)); | ||
680 | } | ||
681 | |||
682 | static int pcc_init(struct pcmcia_socket *s) | ||
683 | { | ||
684 | debug(4, "m32r-pcc: init call\n"); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static struct pccard_operations pcc_operations = { | ||
689 | .init = pcc_init, | ||
690 | .get_status = pcc_get_status, | ||
691 | .get_socket = pcc_get_socket, | ||
692 | .set_socket = pcc_set_socket, | ||
693 | .set_io_map = pcc_set_io_map, | ||
694 | .set_mem_map = pcc_set_mem_map, | ||
695 | }; | ||
696 | |||
697 | /*====================================================================*/ | ||
698 | |||
699 | static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level) | ||
700 | { | ||
701 | int ret = 0; | ||
702 | if (level == SUSPEND_SAVE_STATE) | ||
703 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | static int m32r_pcc_resume(struct device *dev, u32 level) | ||
708 | { | ||
709 | int ret = 0; | ||
710 | if (level == RESUME_RESTORE_STATE) | ||
711 | ret = pcmcia_socket_dev_resume(dev); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | |||
716 | static struct device_driver pcc_driver = { | ||
717 | .name = "pcc", | ||
718 | .bus = &platform_bus_type, | ||
719 | .suspend = m32r_pcc_suspend, | ||
720 | .resume = m32r_pcc_resume, | ||
721 | }; | ||
722 | |||
723 | static struct platform_device pcc_device = { | ||
724 | .name = "pcc", | ||
725 | .id = 0, | ||
726 | }; | ||
727 | |||
728 | /*====================================================================*/ | ||
729 | |||
730 | static int __init init_m32r_pcc(void) | ||
731 | { | ||
732 | int i, ret; | ||
733 | |||
734 | ret = driver_register(&pcc_driver); | ||
735 | if (ret) | ||
736 | return ret; | ||
737 | |||
738 | ret = platform_device_register(&pcc_device); | ||
739 | if (ret){ | ||
740 | driver_unregister(&pcc_driver); | ||
741 | return ret; | ||
742 | } | ||
743 | |||
744 | printk(KERN_INFO "m32r PCC probe:\n"); | ||
745 | |||
746 | pcc_sockets = 0; | ||
747 | |||
748 | add_pcc_socket(M32R_PCC0_BASE, PCC0_IRQ, M32R_PCC0_MAPBASE, 0x1000); | ||
749 | |||
750 | #ifdef CONFIG_M32RPCC_SLOT2 | ||
751 | add_pcc_socket(M32R_PCC1_BASE, PCC1_IRQ, M32R_PCC1_MAPBASE, 0x2000); | ||
752 | #endif | ||
753 | |||
754 | if (pcc_sockets == 0) { | ||
755 | printk("socket is not found.\n"); | ||
756 | platform_device_unregister(&pcc_device); | ||
757 | driver_unregister(&pcc_driver); | ||
758 | return -ENODEV; | ||
759 | } | ||
760 | |||
761 | /* Set up interrupt handler(s) */ | ||
762 | |||
763 | for (i = 0 ; i < pcc_sockets ; i++) { | ||
764 | socket[i].socket.dev.dev = &pcc_device.dev; | ||
765 | socket[i].socket.ops = &pcc_operations; | ||
766 | socket[i].socket.resource_ops = &pccard_static_ops; | ||
767 | socket[i].socket.owner = THIS_MODULE; | ||
768 | socket[i].number = i; | ||
769 | ret = pcmcia_register_socket(&socket[i].socket); | ||
770 | if (!ret) | ||
771 | socket[i].flags |= IS_REGISTERED; | ||
772 | |||
773 | #if 0 /* driver model ordering issue */ | ||
774 | class_device_create_file(&socket[i].socket.dev, | ||
775 | &class_device_attr_info); | ||
776 | class_device_create_file(&socket[i].socket.dev, | ||
777 | &class_device_attr_exca); | ||
778 | #endif | ||
779 | } | ||
780 | |||
781 | /* Finally, schedule a polling interrupt */ | ||
782 | if (poll_interval != 0) { | ||
783 | poll_timer.function = pcc_interrupt_wrapper; | ||
784 | poll_timer.data = 0; | ||
785 | init_timer(&poll_timer); | ||
786 | poll_timer.expires = jiffies + poll_interval; | ||
787 | add_timer(&poll_timer); | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } /* init_m32r_pcc */ | ||
792 | |||
793 | static void __exit exit_m32r_pcc(void) | ||
794 | { | ||
795 | int i; | ||
796 | |||
797 | for (i = 0; i < pcc_sockets; i++) | ||
798 | if (socket[i].flags & IS_REGISTERED) | ||
799 | pcmcia_unregister_socket(&socket[i].socket); | ||
800 | |||
801 | platform_device_unregister(&pcc_device); | ||
802 | if (poll_interval != 0) | ||
803 | del_timer_sync(&poll_timer); | ||
804 | |||
805 | driver_unregister(&pcc_driver); | ||
806 | } /* exit_m32r_pcc */ | ||
807 | |||
808 | module_init(init_m32r_pcc); | ||
809 | module_exit(exit_m32r_pcc); | ||
810 | MODULE_LICENSE("Dual MPL/GPL"); | ||
811 | /*====================================================================*/ | ||
diff --git a/drivers/pcmcia/m32r_pcc.h b/drivers/pcmcia/m32r_pcc.h new file mode 100644 index 000000000000..e4fffe417ba9 --- /dev/null +++ b/drivers/pcmcia/m32r_pcc.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 by Hiroyuki Kondo | ||
3 | */ | ||
4 | |||
5 | #define M32R_MAX_PCC 2 | ||
6 | |||
7 | /* | ||
8 | * M32R PC Card Controler | ||
9 | */ | ||
10 | #define M32R_PCC0_BASE 0x00ef7000 | ||
11 | #define M32R_PCC1_BASE 0x00ef7020 | ||
12 | |||
13 | /* | ||
14 | * Register offsets | ||
15 | */ | ||
16 | #define PCCR 0x00 | ||
17 | #define PCADR 0x04 | ||
18 | #define PCMOD 0x08 | ||
19 | #define PCIRC 0x0c | ||
20 | #define PCCSIGCR 0x10 | ||
21 | #define PCATCR 0x14 | ||
22 | |||
23 | /* | ||
24 | * PCCR | ||
25 | */ | ||
26 | #define PCCR_PCEN (1UL<<(31-31)) | ||
27 | |||
28 | /* | ||
29 | * PCIRC | ||
30 | */ | ||
31 | #define PCIRC_BWERR (1UL<<(31-7)) | ||
32 | #define PCIRC_CDIN1 (1UL<<(31-14)) | ||
33 | #define PCIRC_CDIN2 (1UL<<(31-15)) | ||
34 | #define PCIRC_BEIEN (1UL<<(31-23)) | ||
35 | #define PCIRC_CIIEN (1UL<<(31-30)) | ||
36 | #define PCIRC_COIEN (1UL<<(31-31)) | ||
37 | |||
38 | /* | ||
39 | * PCCSIGCR | ||
40 | */ | ||
41 | #define PCCSIGCR_SEN (1UL<<(31-3)) | ||
42 | #define PCCSIGCR_VEN (1UL<<(31-7)) | ||
43 | #define PCCSIGCR_CRST (1UL<<(31-15)) | ||
44 | #define PCCSIGCR_COCR (1UL<<(31-31)) | ||
45 | |||
46 | /* | ||
47 | * | ||
48 | */ | ||
49 | #define PCMOD_AS_ATTRIB (1UL<<(31-19)) | ||
50 | #define PCMOD_AS_IO (1UL<<(31-18)) | ||
51 | |||
52 | #define PCMOD_CBSZ (1UL<<(31-23)) /* set for 8bit */ | ||
53 | |||
54 | #define PCMOD_DBEX (1UL<<(31-31)) /* set for excahnge */ | ||
55 | |||
56 | /* | ||
57 | * M32R PCC Map addr | ||
58 | */ | ||
59 | #define M32R_PCC0_MAPBASE 0x14000000 | ||
60 | #define M32R_PCC1_MAPBASE 0x16000000 | ||
61 | |||
62 | #define M32R_PCC_MAPMAX 0x02000000 | ||
63 | |||
64 | #define M32R_PCC_MAPSIZE 0x00001000 /* XXX */ | ||
65 | #define M32R_PCC_MAPMASK (~(M32R_PCC_MAPMAX-1)) | ||
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h new file mode 100644 index 000000000000..b1f6e3d9ee06 --- /dev/null +++ b/drivers/pcmcia/o2micro.h | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * o2micro.h 1.13 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_O2MICRO_H | ||
31 | #define _LINUX_O2MICRO_H | ||
32 | |||
33 | #ifndef PCI_VENDOR_ID_O2 | ||
34 | #define PCI_VENDOR_ID_O2 0x1217 | ||
35 | #endif | ||
36 | #ifndef PCI_DEVICE_ID_O2_6729 | ||
37 | #define PCI_DEVICE_ID_O2_6729 0x6729 | ||
38 | #endif | ||
39 | #ifndef PCI_DEVICE_ID_O2_6730 | ||
40 | #define PCI_DEVICE_ID_O2_6730 0x673a | ||
41 | #endif | ||
42 | #ifndef PCI_DEVICE_ID_O2_6832 | ||
43 | #define PCI_DEVICE_ID_O2_6832 0x6832 | ||
44 | #endif | ||
45 | #ifndef PCI_DEVICE_ID_O2_6836 | ||
46 | #define PCI_DEVICE_ID_O2_6836 0x6836 | ||
47 | #endif | ||
48 | #ifndef PCI_DEVICE_ID_O2_6812 | ||
49 | #define PCI_DEVICE_ID_O2_6812 0x6872 | ||
50 | #endif | ||
51 | |||
52 | /* Additional PCI configuration registers */ | ||
53 | |||
54 | #define O2_MUX_CONTROL 0x90 /* 32 bit */ | ||
55 | #define O2_MUX_RING_OUT 0x0000000f | ||
56 | #define O2_MUX_SKTB_ACTV 0x000000f0 | ||
57 | #define O2_MUX_SCTA_ACTV_ENA 0x00000100 | ||
58 | #define O2_MUX_SCTB_ACTV_ENA 0x00000200 | ||
59 | #define O2_MUX_SER_IRQ_ROUTE 0x0000e000 | ||
60 | #define O2_MUX_SER_PCI 0x00010000 | ||
61 | |||
62 | #define O2_MUX_SKTA_TURBO 0x000c0000 /* for 6833, 6860 */ | ||
63 | #define O2_MUX_SKTB_TURBO 0x00300000 | ||
64 | #define O2_MUX_AUX_VCC_3V 0x00400000 | ||
65 | #define O2_MUX_PCI_VCC_5V 0x00800000 | ||
66 | #define O2_MUX_PME_MUX 0x0f000000 | ||
67 | |||
68 | /* Additional ExCA registers */ | ||
69 | |||
70 | #define O2_MODE_A 0x38 | ||
71 | #define O2_MODE_A_2 0x26 /* for 6833B, 6860C */ | ||
72 | #define O2_MODE_A_CD_PULSE 0x04 | ||
73 | #define O2_MODE_A_SUSP_EDGE 0x08 | ||
74 | #define O2_MODE_A_HOST_SUSP 0x10 | ||
75 | #define O2_MODE_A_PWR_MASK 0x60 | ||
76 | #define O2_MODE_A_QUIET 0x80 | ||
77 | |||
78 | #define O2_MODE_B 0x39 | ||
79 | #define O2_MODE_B_2 0x2e /* for 6833B, 6860C */ | ||
80 | #define O2_MODE_B_IDENT 0x03 | ||
81 | #define O2_MODE_B_ID_BSTEP 0x00 | ||
82 | #define O2_MODE_B_ID_CSTEP 0x01 | ||
83 | #define O2_MODE_B_ID_O2 0x02 | ||
84 | #define O2_MODE_B_VS1 0x04 | ||
85 | #define O2_MODE_B_VS2 0x08 | ||
86 | #define O2_MODE_B_IRQ15_RI 0x80 | ||
87 | |||
88 | #define O2_MODE_C 0x3a | ||
89 | #define O2_MODE_C_DREQ_MASK 0x03 | ||
90 | #define O2_MODE_C_DREQ_INPACK 0x01 | ||
91 | #define O2_MODE_C_DREQ_WP 0x02 | ||
92 | #define O2_MODE_C_DREQ_BVD2 0x03 | ||
93 | #define O2_MODE_C_ZVIDEO 0x08 | ||
94 | #define O2_MODE_C_IREQ_SEL 0x30 | ||
95 | #define O2_MODE_C_MGMT_SEL 0xc0 | ||
96 | |||
97 | #define O2_MODE_D 0x3b | ||
98 | #define O2_MODE_D_IRQ_MODE 0x03 | ||
99 | #define O2_MODE_D_PCI_CLKRUN 0x04 | ||
100 | #define O2_MODE_D_CB_CLKRUN 0x08 | ||
101 | #define O2_MODE_D_SKT_ACTV 0x20 | ||
102 | #define O2_MODE_D_PCI_FIFO 0x40 /* for OZ6729, OZ6730 */ | ||
103 | #define O2_MODE_D_W97_IRQ 0x40 | ||
104 | #define O2_MODE_D_ISA_IRQ 0x80 | ||
105 | |||
106 | #define O2_MHPG_DMA 0x3c | ||
107 | #define O2_MHPG_CHANNEL 0x07 | ||
108 | #define O2_MHPG_CINT_ENA 0x08 | ||
109 | #define O2_MHPG_CSC_ENA 0x10 | ||
110 | |||
111 | #define O2_FIFO_ENA 0x3d | ||
112 | #define O2_FIFO_ZVIDEO_3 0x08 | ||
113 | #define O2_FIFO_PCI_FIFO 0x10 | ||
114 | #define O2_FIFO_POSTWR 0x40 | ||
115 | #define O2_FIFO_BUFFER 0x80 | ||
116 | |||
117 | #define O2_MODE_E 0x3e | ||
118 | #define O2_MODE_E_MHPG_DMA 0x01 | ||
119 | #define O2_MODE_E_SPKR_OUT 0x02 | ||
120 | #define O2_MODE_E_LED_OUT 0x08 | ||
121 | #define O2_MODE_E_SKTA_ACTV 0x10 | ||
122 | |||
123 | static int o2micro_override(struct yenta_socket *socket) | ||
124 | { | ||
125 | /* | ||
126 | * 'reserved' register at 0x94/D4. chaning it to 0xCA (8 bit) enables | ||
127 | * read prefetching which for example makes the RME Hammerfall DSP | ||
128 | * working. for some bridges it is at 0x94, for others at 0xD4. it's | ||
129 | * ok to write to both registers on all O2 bridges. | ||
130 | * from Eric Still, 02Micro. | ||
131 | */ | ||
132 | u8 a, b; | ||
133 | |||
134 | if (PCI_FUNC(socket->dev->devfn) == 0) { | ||
135 | a = config_readb(socket, 0x94); | ||
136 | b = config_readb(socket, 0xD4); | ||
137 | |||
138 | printk(KERN_INFO "Yenta O2: res at 0x94/0xD4: %02x/%02x\n", a, b); | ||
139 | |||
140 | switch (socket->dev->device) { | ||
141 | case PCI_DEVICE_ID_O2_6832: | ||
142 | printk(KERN_INFO "Yenta O2: old bridge, not enabling read prefetch / write burst\n"); | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | printk(KERN_INFO "Yenta O2: enabling read prefetch/write burst\n"); | ||
147 | config_writeb(socket, 0x94, a | 0x0a); | ||
148 | config_writeb(socket, 0xD4, b | 0x0a); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void o2micro_restore_state(struct yenta_socket *socket) | ||
156 | { | ||
157 | /* | ||
158 | * as long as read prefetch is the only thing in | ||
159 | * o2micro_override, it's safe to call it from here | ||
160 | */ | ||
161 | o2micro_override(socket); | ||
162 | } | ||
163 | |||
164 | #endif /* _LINUX_O2MICRO_H */ | ||
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c new file mode 100644 index 000000000000..68b80084f83f --- /dev/null +++ b/drivers/pcmcia/pcmcia_compat.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * PCMCIA 16-bit compatibility functions | ||
3 | * | ||
4 | * The initial developer of the original code is David A. Hinds | ||
5 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
6 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
7 | * | ||
8 | * Copyright (C) 2004 Dominik Brodowski | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | |||
20 | #define IN_CARD_SERVICES | ||
21 | #include <pcmcia/version.h> | ||
22 | #include <pcmcia/cs_types.h> | ||
23 | #include <pcmcia/cs.h> | ||
24 | #include <pcmcia/bulkmem.h> | ||
25 | #include <pcmcia/cistpl.h> | ||
26 | #include <pcmcia/ds.h> | ||
27 | #include <pcmcia/ss.h> | ||
28 | |||
29 | #include "cs_internal.h" | ||
30 | |||
31 | int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple) | ||
32 | { | ||
33 | struct pcmcia_socket *s; | ||
34 | if (CHECK_HANDLE(handle)) | ||
35 | return CS_BAD_HANDLE; | ||
36 | s = SOCKET(handle); | ||
37 | return pccard_get_first_tuple(s, handle->Function, tuple); | ||
38 | } | ||
39 | EXPORT_SYMBOL(pcmcia_get_first_tuple); | ||
40 | |||
41 | int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple) | ||
42 | { | ||
43 | struct pcmcia_socket *s; | ||
44 | if (CHECK_HANDLE(handle)) | ||
45 | return CS_BAD_HANDLE; | ||
46 | s = SOCKET(handle); | ||
47 | return pccard_get_next_tuple(s, handle->Function, tuple); | ||
48 | } | ||
49 | EXPORT_SYMBOL(pcmcia_get_next_tuple); | ||
50 | |||
51 | int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple) | ||
52 | { | ||
53 | struct pcmcia_socket *s; | ||
54 | if (CHECK_HANDLE(handle)) | ||
55 | return CS_BAD_HANDLE; | ||
56 | s = SOCKET(handle); | ||
57 | return pccard_get_tuple_data(s, tuple); | ||
58 | } | ||
59 | EXPORT_SYMBOL(pcmcia_get_tuple_data); | ||
60 | |||
61 | int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
62 | { | ||
63 | return pccard_parse_tuple(tuple, parse); | ||
64 | } | ||
65 | EXPORT_SYMBOL(pcmcia_parse_tuple); | ||
66 | |||
67 | int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info) | ||
68 | { | ||
69 | struct pcmcia_socket *s; | ||
70 | if (CHECK_HANDLE(handle)) | ||
71 | return CS_BAD_HANDLE; | ||
72 | s = SOCKET(handle); | ||
73 | return pccard_validate_cis(s, handle->Function, info); | ||
74 | } | ||
75 | EXPORT_SYMBOL(pcmcia_validate_cis); | ||
76 | |||
77 | int pcmcia_get_configuration_info(client_handle_t handle, | ||
78 | config_info_t *config) | ||
79 | { | ||
80 | struct pcmcia_socket *s; | ||
81 | |||
82 | if ((CHECK_HANDLE(handle)) || !config) | ||
83 | return CS_BAD_HANDLE; | ||
84 | s = SOCKET(handle); | ||
85 | if (!s) | ||
86 | return CS_BAD_HANDLE; | ||
87 | return pccard_get_configuration_info(s, handle->Function, config); | ||
88 | } | ||
89 | EXPORT_SYMBOL(pcmcia_get_configuration_info); | ||
90 | |||
91 | int pcmcia_reset_card(client_handle_t handle, client_req_t *req) | ||
92 | { | ||
93 | struct pcmcia_socket *skt; | ||
94 | |||
95 | if (CHECK_HANDLE(handle)) | ||
96 | return CS_BAD_HANDLE; | ||
97 | skt = SOCKET(handle); | ||
98 | if (!skt) | ||
99 | return CS_BAD_HANDLE; | ||
100 | |||
101 | return pccard_reset_card(skt); | ||
102 | } | ||
103 | EXPORT_SYMBOL(pcmcia_reset_card); | ||
104 | |||
105 | int pcmcia_get_status(client_handle_t handle, cs_status_t *status) | ||
106 | { | ||
107 | struct pcmcia_socket *s; | ||
108 | if (CHECK_HANDLE(handle)) | ||
109 | return CS_BAD_HANDLE; | ||
110 | s = SOCKET(handle); | ||
111 | return pccard_get_status(s, handle->Function, status); | ||
112 | } | ||
113 | EXPORT_SYMBOL(pcmcia_get_status); | ||
114 | |||
115 | int pcmcia_access_configuration_register(client_handle_t handle, | ||
116 | conf_reg_t *reg) | ||
117 | { | ||
118 | struct pcmcia_socket *s; | ||
119 | if (CHECK_HANDLE(handle)) | ||
120 | return CS_BAD_HANDLE; | ||
121 | s = SOCKET(handle); | ||
122 | return pccard_access_configuration_register(s, handle->Function, reg); | ||
123 | } | ||
124 | EXPORT_SYMBOL(pcmcia_access_configuration_register); | ||
125 | |||
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c new file mode 100644 index 000000000000..3f4364341d8d --- /dev/null +++ b/drivers/pcmcia/pd6729.c | |||
@@ -0,0 +1,871 @@ | |||
1 | /* | ||
2 | * Driver for the Cirrus PD6729 PCI-PCMCIA bridge. | ||
3 | * | ||
4 | * Based on the i82092.c driver. | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms of | ||
7 | * the GNU General Public License, incorporated herein by reference. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/workqueue.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/device.h> | ||
18 | |||
19 | #include <pcmcia/cs_types.h> | ||
20 | #include <pcmcia/ss.h> | ||
21 | #include <pcmcia/cs.h> | ||
22 | |||
23 | #include <asm/system.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #include "pd6729.h" | ||
27 | #include "i82365.h" | ||
28 | #include "cirrus.h" | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge"); | ||
32 | MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>"); | ||
33 | |||
34 | #define MAX_SOCKETS 2 | ||
35 | |||
36 | /* | ||
37 | * simple helper functions | ||
38 | * External clock time, in nanoseconds. 120 ns = 8.33 MHz | ||
39 | */ | ||
40 | #define to_cycles(ns) ((ns)/120) | ||
41 | |||
42 | #ifndef NO_IRQ | ||
43 | #define NO_IRQ ((unsigned int)(0)) | ||
44 | #endif | ||
45 | |||
46 | /* | ||
47 | * PARAMETERS | ||
48 | * irq_mode=n | ||
49 | * Specifies the interrupt delivery mode. The default (1) is to use PCI | ||
50 | * interrupts; a value of 0 selects ISA interrupts. This must be set for | ||
51 | * correct operation of PCI card readers. | ||
52 | * | ||
53 | * irq_list=i,j,... | ||
54 | * This list limits the set of interrupts that can be used by PCMCIA | ||
55 | * cards. | ||
56 | * The default list is 3,4,5,7,9,10,11. | ||
57 | * (irq_list parameter is not used, if irq_mode = 1) | ||
58 | */ | ||
59 | |||
60 | static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */ | ||
61 | static int irq_list[16]; | ||
62 | static int irq_list_count = 0; | ||
63 | |||
64 | module_param(irq_mode, int, 0444); | ||
65 | module_param_array(irq_list, int, &irq_list_count, 0444); | ||
66 | MODULE_PARM_DESC(irq_mode, | ||
67 | "interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1"); | ||
68 | MODULE_PARM_DESC(irq_list, "interrupts that can be used by PCMCIA cards"); | ||
69 | |||
70 | static DEFINE_SPINLOCK(port_lock); | ||
71 | |||
72 | /* basic value read/write functions */ | ||
73 | |||
74 | static unsigned char indirect_read(struct pd6729_socket *socket, | ||
75 | unsigned short reg) | ||
76 | { | ||
77 | unsigned long port; | ||
78 | unsigned char val; | ||
79 | unsigned long flags; | ||
80 | |||
81 | spin_lock_irqsave(&port_lock, flags); | ||
82 | reg += socket->number * 0x40; | ||
83 | port = socket->io_base; | ||
84 | outb(reg, port); | ||
85 | val = inb(port + 1); | ||
86 | spin_unlock_irqrestore(&port_lock, flags); | ||
87 | |||
88 | return val; | ||
89 | } | ||
90 | |||
91 | static unsigned short indirect_read16(struct pd6729_socket *socket, | ||
92 | unsigned short reg) | ||
93 | { | ||
94 | unsigned long port; | ||
95 | unsigned short tmp; | ||
96 | unsigned long flags; | ||
97 | |||
98 | spin_lock_irqsave(&port_lock, flags); | ||
99 | reg = reg + socket->number * 0x40; | ||
100 | port = socket->io_base; | ||
101 | outb(reg, port); | ||
102 | tmp = inb(port + 1); | ||
103 | reg++; | ||
104 | outb(reg, port); | ||
105 | tmp = tmp | (inb(port + 1) << 8); | ||
106 | spin_unlock_irqrestore(&port_lock, flags); | ||
107 | |||
108 | return tmp; | ||
109 | } | ||
110 | |||
111 | static void indirect_write(struct pd6729_socket *socket, unsigned short reg, | ||
112 | unsigned char value) | ||
113 | { | ||
114 | unsigned long port; | ||
115 | unsigned long flags; | ||
116 | |||
117 | spin_lock_irqsave(&port_lock, flags); | ||
118 | reg = reg + socket->number * 0x40; | ||
119 | port = socket->io_base; | ||
120 | outb(reg, port); | ||
121 | outb(value, port + 1); | ||
122 | spin_unlock_irqrestore(&port_lock, flags); | ||
123 | } | ||
124 | |||
125 | static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg, | ||
126 | unsigned char mask) | ||
127 | { | ||
128 | unsigned long port; | ||
129 | unsigned char val; | ||
130 | unsigned long flags; | ||
131 | |||
132 | spin_lock_irqsave(&port_lock, flags); | ||
133 | reg = reg + socket->number * 0x40; | ||
134 | port = socket->io_base; | ||
135 | outb(reg, port); | ||
136 | val = inb(port + 1); | ||
137 | val |= mask; | ||
138 | outb(reg, port); | ||
139 | outb(val, port + 1); | ||
140 | spin_unlock_irqrestore(&port_lock, flags); | ||
141 | } | ||
142 | |||
143 | static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg, | ||
144 | unsigned char mask) | ||
145 | { | ||
146 | unsigned long port; | ||
147 | unsigned char val; | ||
148 | unsigned long flags; | ||
149 | |||
150 | spin_lock_irqsave(&port_lock, flags); | ||
151 | reg = reg + socket->number * 0x40; | ||
152 | port = socket->io_base; | ||
153 | outb(reg, port); | ||
154 | val = inb(port + 1); | ||
155 | val &= ~mask; | ||
156 | outb(reg, port); | ||
157 | outb(val, port + 1); | ||
158 | spin_unlock_irqrestore(&port_lock, flags); | ||
159 | } | ||
160 | |||
161 | static void indirect_write16(struct pd6729_socket *socket, unsigned short reg, | ||
162 | unsigned short value) | ||
163 | { | ||
164 | unsigned long port; | ||
165 | unsigned char val; | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&port_lock, flags); | ||
169 | reg = reg + socket->number * 0x40; | ||
170 | port = socket->io_base; | ||
171 | |||
172 | outb(reg, port); | ||
173 | val = value & 255; | ||
174 | outb(val, port + 1); | ||
175 | |||
176 | reg++; | ||
177 | |||
178 | outb(reg, port); | ||
179 | val = value >> 8; | ||
180 | outb(val, port + 1); | ||
181 | spin_unlock_irqrestore(&port_lock, flags); | ||
182 | } | ||
183 | |||
184 | /* Interrupt handler functionality */ | ||
185 | |||
186 | static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
187 | { | ||
188 | struct pd6729_socket *socket = (struct pd6729_socket *)dev; | ||
189 | int i; | ||
190 | int loopcount = 0; | ||
191 | int handled = 0; | ||
192 | unsigned int events, active = 0; | ||
193 | |||
194 | while (1) { | ||
195 | loopcount++; | ||
196 | if (loopcount > 20) { | ||
197 | printk(KERN_ERR "pd6729: infinite eventloop " | ||
198 | "in interrupt\n"); | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | active = 0; | ||
203 | |||
204 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
205 | unsigned int csc; | ||
206 | |||
207 | /* card status change register */ | ||
208 | csc = indirect_read(&socket[i], I365_CSC); | ||
209 | if (csc == 0) /* no events on this socket */ | ||
210 | continue; | ||
211 | |||
212 | handled = 1; | ||
213 | events = 0; | ||
214 | |||
215 | if (csc & I365_CSC_DETECT) { | ||
216 | events |= SS_DETECT; | ||
217 | dprintk("Card detected in socket %i!\n", i); | ||
218 | } | ||
219 | |||
220 | if (indirect_read(&socket[i], I365_INTCTL) | ||
221 | & I365_PC_IOCARD) { | ||
222 | /* For IO/CARDS, bit 0 means "read the card" */ | ||
223 | events |= (csc & I365_CSC_STSCHG) | ||
224 | ? SS_STSCHG : 0; | ||
225 | } else { | ||
226 | /* Check for battery/ready events */ | ||
227 | events |= (csc & I365_CSC_BVD1) | ||
228 | ? SS_BATDEAD : 0; | ||
229 | events |= (csc & I365_CSC_BVD2) | ||
230 | ? SS_BATWARN : 0; | ||
231 | events |= (csc & I365_CSC_READY) | ||
232 | ? SS_READY : 0; | ||
233 | } | ||
234 | |||
235 | if (events) { | ||
236 | pcmcia_parse_events(&socket[i].socket, events); | ||
237 | } | ||
238 | active |= events; | ||
239 | } | ||
240 | |||
241 | if (active == 0) /* no more events to handle */ | ||
242 | break; | ||
243 | } | ||
244 | return IRQ_RETVAL(handled); | ||
245 | } | ||
246 | |||
247 | /* socket functions */ | ||
248 | |||
249 | static void pd6729_interrupt_wrapper(unsigned long data) | ||
250 | { | ||
251 | struct pd6729_socket *socket = (struct pd6729_socket *) data; | ||
252 | |||
253 | pd6729_interrupt(0, (void *)socket, NULL); | ||
254 | mod_timer(&socket->poll_timer, jiffies + HZ); | ||
255 | } | ||
256 | |||
257 | static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) | ||
258 | { | ||
259 | struct pd6729_socket *socket | ||
260 | = container_of(sock, struct pd6729_socket, socket); | ||
261 | unsigned int status; | ||
262 | unsigned int data; | ||
263 | struct pd6729_socket *t; | ||
264 | |||
265 | /* Interface Status Register */ | ||
266 | status = indirect_read(socket, I365_STATUS); | ||
267 | *value = 0; | ||
268 | |||
269 | if ((status & I365_CS_DETECT) == I365_CS_DETECT) { | ||
270 | *value |= SS_DETECT; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * IO cards have a different meaning of bits 0,1 | ||
275 | * Also notice the inverse-logic on the bits | ||
276 | */ | ||
277 | if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) { | ||
278 | /* IO card */ | ||
279 | if (!(status & I365_CS_STSCHG)) | ||
280 | *value |= SS_STSCHG; | ||
281 | } else { | ||
282 | /* non I/O card */ | ||
283 | if (!(status & I365_CS_BVD1)) | ||
284 | *value |= SS_BATDEAD; | ||
285 | if (!(status & I365_CS_BVD2)) | ||
286 | *value |= SS_BATWARN; | ||
287 | } | ||
288 | |||
289 | if (status & I365_CS_WRPROT) | ||
290 | *value |= SS_WRPROT; /* card is write protected */ | ||
291 | |||
292 | if (status & I365_CS_READY) | ||
293 | *value |= SS_READY; /* card is not busy */ | ||
294 | |||
295 | if (status & I365_CS_POWERON) | ||
296 | *value |= SS_POWERON; /* power is applied to the card */ | ||
297 | |||
298 | t = (socket->number) ? socket : socket + 1; | ||
299 | indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA); | ||
300 | data = indirect_read16(t, PD67_EXT_DATA); | ||
301 | *value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | static int pd6729_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
308 | { | ||
309 | struct pd6729_socket *socket | ||
310 | = container_of(sock, struct pd6729_socket, socket); | ||
311 | unsigned char reg, vcc, vpp; | ||
312 | |||
313 | state->flags = 0; | ||
314 | state->Vcc = 0; | ||
315 | state->Vpp = 0; | ||
316 | state->io_irq = 0; | ||
317 | state->csc_mask = 0; | ||
318 | |||
319 | /* First the power status of the socket */ | ||
320 | reg = indirect_read(socket, I365_POWER); | ||
321 | |||
322 | if (reg & I365_PWR_AUTO) | ||
323 | state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */ | ||
324 | |||
325 | if (reg & I365_PWR_OUT) | ||
326 | state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */ | ||
327 | |||
328 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
329 | |||
330 | if (reg & I365_VCC_5V) { | ||
331 | state->Vcc = (indirect_read(socket, PD67_MISC_CTL_1) & | ||
332 | PD67_MC1_VCC_3V) ? 33 : 50; | ||
333 | |||
334 | if (vpp == I365_VPP1_5V) { | ||
335 | if (state->Vcc == 50) | ||
336 | state->Vpp = 50; | ||
337 | else | ||
338 | state->Vpp = 33; | ||
339 | } | ||
340 | if (vpp == I365_VPP1_12V) | ||
341 | state->Vpp = 120; | ||
342 | } | ||
343 | |||
344 | /* Now the IO card, RESET flags and IO interrupt */ | ||
345 | reg = indirect_read(socket, I365_INTCTL); | ||
346 | |||
347 | if ((reg & I365_PC_RESET) == 0) | ||
348 | state->flags |= SS_RESET; | ||
349 | if (reg & I365_PC_IOCARD) | ||
350 | state->flags |= SS_IOCARD; /* This is an IO card */ | ||
351 | |||
352 | /* Set the IRQ number */ | ||
353 | state->io_irq = socket->card_irq; | ||
354 | |||
355 | /* Card status change */ | ||
356 | reg = indirect_read(socket, I365_CSCINT); | ||
357 | |||
358 | if (reg & I365_CSC_DETECT) | ||
359 | state->csc_mask |= SS_DETECT; /* Card detect is enabled */ | ||
360 | |||
361 | if (state->flags & SS_IOCARD) {/* IO Cards behave different */ | ||
362 | if (reg & I365_CSC_STSCHG) | ||
363 | state->csc_mask |= SS_STSCHG; | ||
364 | } else { | ||
365 | if (reg & I365_CSC_BVD1) | ||
366 | state->csc_mask |= SS_BATDEAD; | ||
367 | if (reg & I365_CSC_BVD2) | ||
368 | state->csc_mask |= SS_BATWARN; | ||
369 | if (reg & I365_CSC_READY) | ||
370 | state->csc_mask |= SS_READY; | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
377 | { | ||
378 | struct pd6729_socket *socket | ||
379 | = container_of(sock, struct pd6729_socket, socket); | ||
380 | unsigned char reg, data; | ||
381 | |||
382 | /* First, set the global controller options */ | ||
383 | indirect_write(socket, I365_GBLCTL, 0x00); | ||
384 | indirect_write(socket, I365_GENCTL, 0x00); | ||
385 | |||
386 | /* Values for the IGENC register */ | ||
387 | socket->card_irq = state->io_irq; | ||
388 | |||
389 | reg = 0; | ||
390 | /* The reset bit has "inverse" logic */ | ||
391 | if (!(state->flags & SS_RESET)) | ||
392 | reg |= I365_PC_RESET; | ||
393 | if (state->flags & SS_IOCARD) | ||
394 | reg |= I365_PC_IOCARD; | ||
395 | |||
396 | /* IGENC, Interrupt and General Control Register */ | ||
397 | indirect_write(socket, I365_INTCTL, reg); | ||
398 | |||
399 | /* Power registers */ | ||
400 | |||
401 | reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */ | ||
402 | |||
403 | if (state->flags & SS_PWR_AUTO) { | ||
404 | dprintk("Auto power\n"); | ||
405 | reg |= I365_PWR_AUTO; /* automatic power mngmnt */ | ||
406 | } | ||
407 | if (state->flags & SS_OUTPUT_ENA) { | ||
408 | dprintk("Power Enabled\n"); | ||
409 | reg |= I365_PWR_OUT; /* enable power */ | ||
410 | } | ||
411 | |||
412 | switch (state->Vcc) { | ||
413 | case 0: | ||
414 | break; | ||
415 | case 33: | ||
416 | dprintk("setting voltage to Vcc to 3.3V on socket %i\n", | ||
417 | socket->number); | ||
418 | reg |= I365_VCC_5V; | ||
419 | indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
420 | break; | ||
421 | case 50: | ||
422 | dprintk("setting voltage to Vcc to 5V on socket %i\n", | ||
423 | socket->number); | ||
424 | reg |= I365_VCC_5V; | ||
425 | indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
426 | break; | ||
427 | default: | ||
428 | dprintk("pd6729: pd6729_set_socket called with " | ||
429 | "invalid VCC power value: %i\n", | ||
430 | state->Vcc); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | switch (state->Vpp) { | ||
435 | case 0: | ||
436 | dprintk("not setting Vpp on socket %i\n", socket->number); | ||
437 | break; | ||
438 | case 33: | ||
439 | case 50: | ||
440 | dprintk("setting Vpp to Vcc for socket %i\n", socket->number); | ||
441 | reg |= I365_VPP1_5V; | ||
442 | break; | ||
443 | case 120: | ||
444 | dprintk("setting Vpp to 12.0\n"); | ||
445 | reg |= I365_VPP1_12V; | ||
446 | break; | ||
447 | default: | ||
448 | dprintk("pd6729: pd6729_set_socket called with invalid VPP power value: %i\n", | ||
449 | state->Vpp); | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | /* only write if changed */ | ||
454 | if (reg != indirect_read(socket, I365_POWER)) | ||
455 | indirect_write(socket, I365_POWER, reg); | ||
456 | |||
457 | if (irq_mode == 1) { | ||
458 | /* all interrupts are to be done as PCI interrupts */ | ||
459 | data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ; | ||
460 | } else | ||
461 | data = 0; | ||
462 | |||
463 | indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1); | ||
464 | indirect_write(socket, PD67_EXT_DATA, data); | ||
465 | |||
466 | /* Enable specific interrupt events */ | ||
467 | |||
468 | reg = 0x00; | ||
469 | if (state->csc_mask & SS_DETECT) { | ||
470 | reg |= I365_CSC_DETECT; | ||
471 | } | ||
472 | if (state->flags & SS_IOCARD) { | ||
473 | if (state->csc_mask & SS_STSCHG) | ||
474 | reg |= I365_CSC_STSCHG; | ||
475 | } else { | ||
476 | if (state->csc_mask & SS_BATDEAD) | ||
477 | reg |= I365_CSC_BVD1; | ||
478 | if (state->csc_mask & SS_BATWARN) | ||
479 | reg |= I365_CSC_BVD2; | ||
480 | if (state->csc_mask & SS_READY) | ||
481 | reg |= I365_CSC_READY; | ||
482 | } | ||
483 | if (irq_mode == 1) | ||
484 | reg |= 0x30; /* management IRQ: PCI INTA# = "irq 3" */ | ||
485 | indirect_write(socket, I365_CSCINT, reg); | ||
486 | |||
487 | reg = indirect_read(socket, I365_INTCTL); | ||
488 | if (irq_mode == 1) | ||
489 | reg |= 0x03; /* card IRQ: PCI INTA# = "irq 3" */ | ||
490 | else | ||
491 | reg |= socket->card_irq; | ||
492 | indirect_write(socket, I365_INTCTL, reg); | ||
493 | |||
494 | /* now clear the (probably bogus) pending stuff by doing a dummy read */ | ||
495 | (void)indirect_read(socket, I365_CSC); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int pd6729_set_io_map(struct pcmcia_socket *sock, | ||
501 | struct pccard_io_map *io) | ||
502 | { | ||
503 | struct pd6729_socket *socket | ||
504 | = container_of(sock, struct pd6729_socket, socket); | ||
505 | unsigned char map, ioctl; | ||
506 | |||
507 | map = io->map; | ||
508 | |||
509 | /* Check error conditions */ | ||
510 | if (map > 1) { | ||
511 | dprintk("pd6729_set_io_map with invalid map"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | /* Turn off the window before changing anything */ | ||
516 | if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map)) | ||
517 | indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); | ||
518 | |||
519 | /* dprintk("set_io_map: Setting range to %x - %x\n", | ||
520 | io->start, io->stop);*/ | ||
521 | |||
522 | /* write the new values */ | ||
523 | indirect_write16(socket, I365_IO(map)+I365_W_START, io->start); | ||
524 | indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop); | ||
525 | |||
526 | ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); | ||
527 | |||
528 | if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); | ||
529 | if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); | ||
530 | if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); | ||
531 | |||
532 | indirect_write(socket, I365_IOCTL, ioctl); | ||
533 | |||
534 | /* Turn the window back on if needed */ | ||
535 | if (io->flags & MAP_ACTIVE) | ||
536 | indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int pd6729_set_mem_map(struct pcmcia_socket *sock, | ||
542 | struct pccard_mem_map *mem) | ||
543 | { | ||
544 | struct pd6729_socket *socket | ||
545 | = container_of(sock, struct pd6729_socket, socket); | ||
546 | unsigned short base, i; | ||
547 | unsigned char map; | ||
548 | |||
549 | map = mem->map; | ||
550 | if (map > 4) { | ||
551 | printk("pd6729_set_mem_map: invalid map"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | |||
555 | if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) { | ||
556 | printk("pd6729_set_mem_map: invalid address / speed"); | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | /* Turn off the window before changing anything */ | ||
561 | if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map)) | ||
562 | indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
563 | |||
564 | /* write the start address */ | ||
565 | base = I365_MEM(map); | ||
566 | i = (mem->res->start >> 12) & 0x0fff; | ||
567 | if (mem->flags & MAP_16BIT) | ||
568 | i |= I365_MEM_16BIT; | ||
569 | if (mem->flags & MAP_0WS) | ||
570 | i |= I365_MEM_0WS; | ||
571 | indirect_write16(socket, base + I365_W_START, i); | ||
572 | |||
573 | /* write the stop address */ | ||
574 | |||
575 | i= (mem->res->end >> 12) & 0x0fff; | ||
576 | switch (to_cycles(mem->speed)) { | ||
577 | case 0: | ||
578 | break; | ||
579 | case 1: | ||
580 | i |= I365_MEM_WS0; | ||
581 | break; | ||
582 | case 2: | ||
583 | i |= I365_MEM_WS1; | ||
584 | break; | ||
585 | default: | ||
586 | i |= I365_MEM_WS1 | I365_MEM_WS0; | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | indirect_write16(socket, base + I365_W_STOP, i); | ||
591 | |||
592 | /* Take care of high byte */ | ||
593 | indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); | ||
594 | indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24); | ||
595 | |||
596 | /* card start */ | ||
597 | |||
598 | i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; | ||
599 | if (mem->flags & MAP_WRPROT) | ||
600 | i |= I365_MEM_WRPROT; | ||
601 | if (mem->flags & MAP_ATTRIB) { | ||
602 | /* dprintk("requesting attribute memory for socket %i\n", | ||
603 | socket->number);*/ | ||
604 | i |= I365_MEM_REG; | ||
605 | } else { | ||
606 | /* dprintk("requesting normal memory for socket %i\n", | ||
607 | socket->number);*/ | ||
608 | } | ||
609 | indirect_write16(socket, base + I365_W_OFF, i); | ||
610 | |||
611 | /* Enable the window if necessary */ | ||
612 | if (mem->flags & MAP_ACTIVE) | ||
613 | indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int pd6729_init(struct pcmcia_socket *sock) | ||
619 | { | ||
620 | int i; | ||
621 | struct resource res = { .end = 0x0fff }; | ||
622 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
623 | pccard_mem_map mem = { .res = &res, }; | ||
624 | |||
625 | pd6729_set_socket(sock, &dead_socket); | ||
626 | for (i = 0; i < 2; i++) { | ||
627 | io.map = i; | ||
628 | pd6729_set_io_map(sock, &io); | ||
629 | } | ||
630 | for (i = 0; i < 5; i++) { | ||
631 | mem.map = i; | ||
632 | pd6729_set_mem_map(sock, &mem); | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | |||
639 | /* the pccard structure and its functions */ | ||
640 | static struct pccard_operations pd6729_operations = { | ||
641 | .init = pd6729_init, | ||
642 | .get_status = pd6729_get_status, | ||
643 | .get_socket = pd6729_get_socket, | ||
644 | .set_socket = pd6729_set_socket, | ||
645 | .set_io_map = pd6729_set_io_map, | ||
646 | .set_mem_map = pd6729_set_mem_map, | ||
647 | }; | ||
648 | |||
649 | static irqreturn_t pd6729_test(int irq, void *dev, struct pt_regs *regs) | ||
650 | { | ||
651 | dprintk("-> hit on irq %d\n", irq); | ||
652 | return IRQ_HANDLED; | ||
653 | } | ||
654 | |||
655 | static int pd6729_check_irq(int irq, int flags) | ||
656 | { | ||
657 | if (request_irq(irq, pd6729_test, flags, "x", pd6729_test) != 0) | ||
658 | return -1; | ||
659 | free_irq(irq, pd6729_test); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static u_int __init pd6729_isa_scan(void) | ||
664 | { | ||
665 | u_int mask0, mask = 0; | ||
666 | int i; | ||
667 | |||
668 | if (irq_mode == 1) { | ||
669 | printk(KERN_INFO "pd6729: PCI card interrupts, " | ||
670 | "PCI status changes\n"); | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | if (irq_list_count == 0) | ||
675 | mask0 = 0xffff; | ||
676 | else | ||
677 | for (i = mask0 = 0; i < irq_list_count; i++) | ||
678 | mask0 |= (1<<irq_list[i]); | ||
679 | |||
680 | mask0 &= PD67_MASK; | ||
681 | |||
682 | /* just find interrupts that aren't in use */ | ||
683 | for (i = 0; i < 16; i++) | ||
684 | if ((mask0 & (1 << i)) && (pd6729_check_irq(i, 0) == 0)) | ||
685 | mask |= (1 << i); | ||
686 | |||
687 | printk(KERN_INFO "pd6729: ISA irqs = "); | ||
688 | for (i = 0; i < 16; i++) | ||
689 | if (mask & (1<<i)) | ||
690 | printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i); | ||
691 | |||
692 | if (mask == 0) printk("none!"); | ||
693 | |||
694 | printk(" polling status changes.\n"); | ||
695 | |||
696 | return mask; | ||
697 | } | ||
698 | |||
699 | static int __devinit pd6729_pci_probe(struct pci_dev *dev, | ||
700 | const struct pci_device_id *id) | ||
701 | { | ||
702 | int i, j, ret; | ||
703 | u_int mask; | ||
704 | char configbyte; | ||
705 | struct pd6729_socket *socket; | ||
706 | |||
707 | socket = kmalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, | ||
708 | GFP_KERNEL); | ||
709 | if (!socket) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | memset(socket, 0, sizeof(struct pd6729_socket) * MAX_SOCKETS); | ||
713 | |||
714 | if ((ret = pci_enable_device(dev))) | ||
715 | goto err_out_free_mem; | ||
716 | |||
717 | printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge " | ||
718 | "at 0x%lx on irq %d\n", pci_resource_start(dev, 0), dev->irq); | ||
719 | /* | ||
720 | * Since we have no memory BARs some firmware may not | ||
721 | * have had PCI_COMMAND_MEMORY enabled, yet the device needs it. | ||
722 | */ | ||
723 | pci_read_config_byte(dev, PCI_COMMAND, &configbyte); | ||
724 | if (!(configbyte & PCI_COMMAND_MEMORY)) { | ||
725 | printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n"); | ||
726 | configbyte |= PCI_COMMAND_MEMORY; | ||
727 | pci_write_config_byte(dev, PCI_COMMAND, configbyte); | ||
728 | } | ||
729 | |||
730 | ret = pci_request_regions(dev, "pd6729"); | ||
731 | if (ret) { | ||
732 | printk(KERN_INFO "pd6729: pci request region failed.\n"); | ||
733 | goto err_out_disable; | ||
734 | } | ||
735 | |||
736 | if (dev->irq == NO_IRQ) | ||
737 | irq_mode = 0; /* fall back to ISA interrupt mode */ | ||
738 | |||
739 | mask = pd6729_isa_scan(); | ||
740 | if (irq_mode == 0 && mask == 0) { | ||
741 | printk(KERN_INFO "pd6729: no ISA interrupt is available.\n"); | ||
742 | goto err_out_free_res; | ||
743 | } | ||
744 | |||
745 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
746 | socket[i].io_base = pci_resource_start(dev, 0); | ||
747 | socket[i].socket.features |= SS_CAP_PCCARD; | ||
748 | socket[i].socket.map_size = 0x1000; | ||
749 | socket[i].socket.irq_mask = mask; | ||
750 | socket[i].socket.pci_irq = dev->irq; | ||
751 | socket[i].socket.owner = THIS_MODULE; | ||
752 | |||
753 | socket[i].number = i; | ||
754 | |||
755 | socket[i].socket.ops = &pd6729_operations; | ||
756 | socket[i].socket.resource_ops = &pccard_nonstatic_ops; | ||
757 | socket[i].socket.dev.dev = &dev->dev; | ||
758 | socket[i].socket.driver_data = &socket[i]; | ||
759 | } | ||
760 | |||
761 | pci_set_drvdata(dev, socket); | ||
762 | if (irq_mode == 1) { | ||
763 | /* Register the interrupt handler */ | ||
764 | if ((ret = request_irq(dev->irq, pd6729_interrupt, SA_SHIRQ, | ||
765 | "pd6729", socket))) { | ||
766 | printk(KERN_ERR "pd6729: Failed to register irq %d, " | ||
767 | "aborting\n", dev->irq); | ||
768 | goto err_out_free_res; | ||
769 | } | ||
770 | } else { | ||
771 | /* poll Card status change */ | ||
772 | init_timer(&socket->poll_timer); | ||
773 | socket->poll_timer.function = pd6729_interrupt_wrapper; | ||
774 | socket->poll_timer.data = (unsigned long)socket; | ||
775 | socket->poll_timer.expires = jiffies + HZ; | ||
776 | add_timer(&socket->poll_timer); | ||
777 | } | ||
778 | |||
779 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
780 | ret = pcmcia_register_socket(&socket[i].socket); | ||
781 | if (ret) { | ||
782 | printk(KERN_INFO "pd6729: pcmcia_register_socket " | ||
783 | "failed.\n"); | ||
784 | for (j = 0; j < i ; j++) | ||
785 | pcmcia_unregister_socket(&socket[j].socket); | ||
786 | goto err_out_free_res2; | ||
787 | } | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | |||
792 | err_out_free_res2: | ||
793 | if (irq_mode == 1) | ||
794 | free_irq(dev->irq, socket); | ||
795 | else | ||
796 | del_timer_sync(&socket->poll_timer); | ||
797 | err_out_free_res: | ||
798 | pci_release_regions(dev); | ||
799 | err_out_disable: | ||
800 | pci_disable_device(dev); | ||
801 | |||
802 | err_out_free_mem: | ||
803 | kfree(socket); | ||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | static void __devexit pd6729_pci_remove(struct pci_dev *dev) | ||
808 | { | ||
809 | int i; | ||
810 | struct pd6729_socket *socket = pci_get_drvdata(dev); | ||
811 | |||
812 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
813 | /* Turn off all interrupt sources */ | ||
814 | indirect_write(&socket[i], I365_CSCINT, 0); | ||
815 | indirect_write(&socket[i], I365_INTCTL, 0); | ||
816 | |||
817 | pcmcia_unregister_socket(&socket[i].socket); | ||
818 | } | ||
819 | |||
820 | if (irq_mode == 1) | ||
821 | free_irq(dev->irq, socket); | ||
822 | else | ||
823 | del_timer_sync(&socket->poll_timer); | ||
824 | pci_release_regions(dev); | ||
825 | pci_disable_device(dev); | ||
826 | |||
827 | kfree(socket); | ||
828 | } | ||
829 | |||
830 | static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state) | ||
831 | { | ||
832 | return pcmcia_socket_dev_suspend(&dev->dev, state); | ||
833 | } | ||
834 | |||
835 | static int pd6729_socket_resume(struct pci_dev *dev) | ||
836 | { | ||
837 | return pcmcia_socket_dev_resume(&dev->dev); | ||
838 | } | ||
839 | |||
840 | static struct pci_device_id pd6729_pci_ids[] = { | ||
841 | { | ||
842 | .vendor = PCI_VENDOR_ID_CIRRUS, | ||
843 | .device = PCI_DEVICE_ID_CIRRUS_6729, | ||
844 | .subvendor = PCI_ANY_ID, | ||
845 | .subdevice = PCI_ANY_ID, | ||
846 | }, | ||
847 | { } | ||
848 | }; | ||
849 | MODULE_DEVICE_TABLE(pci, pd6729_pci_ids); | ||
850 | |||
851 | static struct pci_driver pd6729_pci_drv = { | ||
852 | .name = "pd6729", | ||
853 | .id_table = pd6729_pci_ids, | ||
854 | .probe = pd6729_pci_probe, | ||
855 | .remove = __devexit_p(pd6729_pci_remove), | ||
856 | .suspend = pd6729_socket_suspend, | ||
857 | .resume = pd6729_socket_resume, | ||
858 | }; | ||
859 | |||
860 | static int pd6729_module_init(void) | ||
861 | { | ||
862 | return pci_register_driver(&pd6729_pci_drv); | ||
863 | } | ||
864 | |||
865 | static void pd6729_module_exit(void) | ||
866 | { | ||
867 | pci_unregister_driver(&pd6729_pci_drv); | ||
868 | } | ||
869 | |||
870 | module_init(pd6729_module_init); | ||
871 | module_exit(pd6729_module_exit); | ||
diff --git a/drivers/pcmcia/pd6729.h b/drivers/pcmcia/pd6729.h new file mode 100644 index 000000000000..f392e458cdfd --- /dev/null +++ b/drivers/pcmcia/pd6729.h | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifndef _INCLUDE_GUARD_PD6729_H_ | ||
2 | #define _INCLUDE_GUARD_PD6729_H_ | ||
3 | |||
4 | /* Debuging defines */ | ||
5 | #ifdef NOTRACE | ||
6 | #define dprintk(fmt, args...) printk(fmt , ## args) | ||
7 | #else | ||
8 | #define dprintk(fmt, args...) do {} while (0) | ||
9 | #endif | ||
10 | |||
11 | /* Flags for I365_GENCTL */ | ||
12 | #define I365_DF_VS1 0x40 /* DF-step Voltage Sense */ | ||
13 | #define I365_DF_VS2 0x80 | ||
14 | |||
15 | /* Fields in PD67_EXTERN_DATA */ | ||
16 | #define PD67_EXD_VS1(s) (0x01 << ((s) << 1)) | ||
17 | #define PD67_EXD_VS2(s) (0x02 << ((s) << 1)) | ||
18 | |||
19 | /* Default ISA interrupt mask */ | ||
20 | #define PD67_MASK 0x0eb8 /* irq 11,10,9,7,5,4,3 */ | ||
21 | |||
22 | struct pd6729_socket { | ||
23 | int number; | ||
24 | int card_irq; | ||
25 | unsigned long io_base; /* base io address of the socket */ | ||
26 | struct pcmcia_socket socket; | ||
27 | struct timer_list poll_timer; | ||
28 | }; | ||
29 | |||
30 | #endif | ||
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c new file mode 100644 index 000000000000..a6936a75a87e --- /dev/null +++ b/drivers/pcmcia/pxa2xx_base.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for the PCMCIA control functionality of PXA2xx | ||
4 | microprocessors. | ||
5 | |||
6 | The contents of this file may be used under the | ||
7 | terms of the GNU Public License version 2 (the "GPL") | ||
8 | |||
9 | (c) Ian Molton (spyro@f2s.com) 2003 | ||
10 | (c) Stefan Eletzhofer (stefan.eletzhofer@inquant.de) 2003,4 | ||
11 | |||
12 | derived from sa11xx_base.c | ||
13 | |||
14 | Portions created by John G. Dorsey are | ||
15 | Copyright (C) 1999 John G. Dorsey. | ||
16 | |||
17 | ======================================================================*/ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/cpufreq.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/arch/pxa-regs.h> | ||
32 | |||
33 | #include <pcmcia/cs_types.h> | ||
34 | #include <pcmcia/ss.h> | ||
35 | #include <pcmcia/bulkmem.h> | ||
36 | #include <pcmcia/cistpl.h> | ||
37 | |||
38 | #include "cs_internal.h" | ||
39 | #include "soc_common.h" | ||
40 | #include "pxa2xx_base.h" | ||
41 | |||
42 | |||
43 | #define MCXX_SETUP_MASK (0x7f) | ||
44 | #define MCXX_ASST_MASK (0x1f) | ||
45 | #define MCXX_HOLD_MASK (0x3f) | ||
46 | #define MCXX_SETUP_SHIFT (0) | ||
47 | #define MCXX_ASST_SHIFT (7) | ||
48 | #define MCXX_HOLD_SHIFT (14) | ||
49 | |||
50 | static inline u_int pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns, | ||
51 | u_int mem_clk_10khz) | ||
52 | { | ||
53 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | ||
54 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; | ||
55 | } | ||
56 | |||
57 | static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns, | ||
58 | u_int mem_clk_10khz) | ||
59 | { | ||
60 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | ||
61 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; | ||
62 | } | ||
63 | |||
64 | static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, | ||
65 | u_int mem_clk_10khz) | ||
66 | { | ||
67 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | ||
68 | return (code / 100000) + ((code % 100000) ? 1 : 0) - 1; | ||
69 | } | ||
70 | |||
71 | /* This function returns the (approximate) command assertion period, in | ||
72 | * nanoseconds, for a given CPU clock frequency and MCXX_ASST value: | ||
73 | */ | ||
74 | static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz, | ||
75 | u_int pcmcia_mcxx_asst) | ||
76 | { | ||
77 | return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz); | ||
78 | } | ||
79 | |||
80 | static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock ) | ||
81 | { | ||
82 | MCMEM(sock) = ((pxa2xx_mcxx_setup(speed, clock) | ||
83 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | ||
84 | | ((pxa2xx_mcxx_asst(speed, clock) | ||
85 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | ||
86 | | ((pxa2xx_mcxx_hold(speed, clock) | ||
87 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock ) | ||
93 | { | ||
94 | MCIO(sock) = ((pxa2xx_mcxx_setup(speed, clock) | ||
95 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | ||
96 | | ((pxa2xx_mcxx_asst(speed, clock) | ||
97 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | ||
98 | | ((pxa2xx_mcxx_hold(speed, clock) | ||
99 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) | ||
105 | { | ||
106 | MCATT(sock) = ((pxa2xx_mcxx_setup(speed, clock) | ||
107 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | ||
108 | | ((pxa2xx_mcxx_asst(speed, clock) | ||
109 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | ||
110 | | ((pxa2xx_mcxx_hold(speed, clock) | ||
111 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int clk) | ||
117 | { | ||
118 | struct soc_pcmcia_timing timing; | ||
119 | int sock = skt->nr; | ||
120 | |||
121 | soc_common_pcmcia_get_timing(skt, &timing); | ||
122 | |||
123 | pxa2xx_pcmcia_set_mcmem(sock, timing.mem, clk); | ||
124 | pxa2xx_pcmcia_set_mcatt(sock, timing.attr, clk); | ||
125 | pxa2xx_pcmcia_set_mcio(sock, timing.io, clk); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) | ||
131 | { | ||
132 | unsigned int clk = get_memclk_frequency_10khz(); | ||
133 | return pxa2xx_pcmcia_set_mcxx(skt, clk); | ||
134 | } | ||
135 | |||
136 | #ifdef CONFIG_CPU_FREQ | ||
137 | |||
138 | static int | ||
139 | pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | ||
140 | unsigned long val, | ||
141 | struct cpufreq_freqs *freqs) | ||
142 | { | ||
143 | #warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" | ||
144 | switch (val) { | ||
145 | case CPUFREQ_PRECHANGE: | ||
146 | if (freqs->new > freqs->old) { | ||
147 | debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, " | ||
148 | "pre-updating\n", | ||
149 | freqs->new / 1000, (freqs->new / 100) % 10, | ||
150 | freqs->old / 1000, (freqs->old / 100) % 10); | ||
151 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); | ||
152 | } | ||
153 | break; | ||
154 | |||
155 | case CPUFREQ_POSTCHANGE: | ||
156 | if (freqs->new < freqs->old) { | ||
157 | debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, " | ||
158 | "post-updating\n", | ||
159 | freqs->new / 1000, (freqs->new / 100) % 10, | ||
160 | freqs->old / 1000, (freqs->old / 100) % 10); | ||
161 | pxa2xx_pcmcia_set_mcxx(skt, freqs->new); | ||
162 | } | ||
163 | break; | ||
164 | } | ||
165 | return 0; | ||
166 | } | ||
167 | #endif | ||
168 | |||
169 | int pxa2xx_drv_pcmcia_probe(struct device *dev) | ||
170 | { | ||
171 | int ret; | ||
172 | struct pcmcia_low_level *ops; | ||
173 | int first, nr; | ||
174 | |||
175 | if (!dev || !dev->platform_data) | ||
176 | return -ENODEV; | ||
177 | |||
178 | ops = (struct pcmcia_low_level *)dev->platform_data; | ||
179 | first = ops->first; | ||
180 | nr = ops->nr; | ||
181 | |||
182 | /* Provide our PXA2xx specific timing routines. */ | ||
183 | ops->set_timing = pxa2xx_pcmcia_set_timing; | ||
184 | #ifdef CONFIG_CPU_FREQ | ||
185 | ops->frequency_change = pxa2xx_pcmcia_frequency_change; | ||
186 | #endif | ||
187 | |||
188 | ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); | ||
189 | |||
190 | if (ret == 0) { | ||
191 | /* | ||
192 | * We have at least one socket, so set MECR:CIT | ||
193 | * (Card Is There) | ||
194 | */ | ||
195 | MECR |= MECR_CIT; | ||
196 | |||
197 | /* Set MECR:NOS (Number Of Sockets) */ | ||
198 | if (nr > 1) | ||
199 | MECR |= MECR_NOS; | ||
200 | else | ||
201 | MECR &= ~MECR_NOS; | ||
202 | } | ||
203 | |||
204 | return ret; | ||
205 | } | ||
206 | EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); | ||
207 | |||
208 | static int pxa2xx_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level) | ||
209 | { | ||
210 | int ret = 0; | ||
211 | if (level == SUSPEND_SAVE_STATE) | ||
212 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) | ||
217 | { | ||
218 | int ret = 0; | ||
219 | if (level == RESUME_RESTORE_STATE) | ||
220 | { | ||
221 | struct pcmcia_low_level *ops = dev->platform_data; | ||
222 | int nr = ops ? ops->nr : 0; | ||
223 | |||
224 | MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); | ||
225 | ret = pcmcia_socket_dev_resume(dev); | ||
226 | } | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static struct device_driver pxa2xx_pcmcia_driver = { | ||
231 | .probe = pxa2xx_drv_pcmcia_probe, | ||
232 | .remove = soc_common_drv_pcmcia_remove, | ||
233 | .suspend = pxa2xx_drv_pcmcia_suspend, | ||
234 | .resume = pxa2xx_drv_pcmcia_resume, | ||
235 | .name = "pxa2xx-pcmcia", | ||
236 | .bus = &platform_bus_type, | ||
237 | }; | ||
238 | |||
239 | static int __init pxa2xx_pcmcia_init(void) | ||
240 | { | ||
241 | return driver_register(&pxa2xx_pcmcia_driver); | ||
242 | } | ||
243 | |||
244 | static void __exit pxa2xx_pcmcia_exit(void) | ||
245 | { | ||
246 | driver_unregister(&pxa2xx_pcmcia_driver); | ||
247 | } | ||
248 | |||
249 | module_init(pxa2xx_pcmcia_init); | ||
250 | module_exit(pxa2xx_pcmcia_exit); | ||
251 | |||
252 | MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>"); | ||
253 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA2xx core socket driver"); | ||
254 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/pxa2xx_base.h b/drivers/pcmcia/pxa2xx_base.h new file mode 100644 index 000000000000..e46cff345d47 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_base.h | |||
@@ -0,0 +1,3 @@ | |||
1 | /* temporary measure */ | ||
2 | extern int pxa2xx_drv_pcmcia_probe(struct device *); | ||
3 | |||
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c new file mode 100644 index 000000000000..fd1f691c7c2c --- /dev/null +++ b/drivers/pcmcia/pxa2xx_lubbock.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_lubbock.c | ||
3 | * | ||
4 | * Author: George Davis | ||
5 | * Created: Jan 10, 2002 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c | ||
13 | * | ||
14 | * Lubbock PCMCIA specific routines. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/hardware/sa1111.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | #include <asm/arch/pxa-regs.h> | ||
29 | #include <asm/arch/lubbock.h> | ||
30 | |||
31 | #include "sa1111_generic.h" | ||
32 | |||
33 | static int | ||
34 | lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
35 | { | ||
36 | /* | ||
37 | * Setup default state of GPIO outputs | ||
38 | * before we enable them as outputs. | ||
39 | */ | ||
40 | GPSR(GPIO48_nPOE) = | ||
41 | GPIO_bit(GPIO48_nPOE) | | ||
42 | GPIO_bit(GPIO49_nPWE) | | ||
43 | GPIO_bit(GPIO50_nPIOR) | | ||
44 | GPIO_bit(GPIO51_nPIOW) | | ||
45 | GPIO_bit(GPIO52_nPCE_1) | | ||
46 | GPIO_bit(GPIO53_nPCE_2); | ||
47 | |||
48 | pxa_gpio_mode(GPIO48_nPOE_MD); | ||
49 | pxa_gpio_mode(GPIO49_nPWE_MD); | ||
50 | pxa_gpio_mode(GPIO50_nPIOR_MD); | ||
51 | pxa_gpio_mode(GPIO51_nPIOW_MD); | ||
52 | pxa_gpio_mode(GPIO52_nPCE_1_MD); | ||
53 | pxa_gpio_mode(GPIO53_nPCE_2_MD); | ||
54 | pxa_gpio_mode(GPIO54_pSKTSEL_MD); | ||
55 | pxa_gpio_mode(GPIO55_nPREG_MD); | ||
56 | pxa_gpio_mode(GPIO56_nPWAIT_MD); | ||
57 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | ||
58 | |||
59 | return sa1111_pcmcia_hw_init(skt); | ||
60 | } | ||
61 | |||
62 | static int | ||
63 | lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
64 | const socket_state_t *state) | ||
65 | { | ||
66 | unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; | ||
67 | int ret = 0; | ||
68 | |||
69 | pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0; | ||
70 | |||
71 | /* Lubbock uses the Maxim MAX1602, with the following connections: | ||
72 | * | ||
73 | * Socket 0 (PCMCIA): | ||
74 | * MAX1602 Lubbock Register | ||
75 | * Pin Signal | ||
76 | * ----- ------- ---------------------- | ||
77 | * A0VPP S0_PWR0 SA-1111 GPIO A<0> | ||
78 | * A1VPP S0_PWR1 SA-1111 GPIO A<1> | ||
79 | * A0VCC S0_PWR2 SA-1111 GPIO A<2> | ||
80 | * A1VCC S0_PWR3 SA-1111 GPIO A<3> | ||
81 | * VX VCC | ||
82 | * VY +3.3V | ||
83 | * 12IN +12V | ||
84 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
85 | * | ||
86 | * Socket 1 (CF): | ||
87 | * MAX1602 Lubbock Register | ||
88 | * Pin Signal | ||
89 | * ----- ------- ---------------------- | ||
90 | * A0VPP GND VPP is not connected | ||
91 | * A1VPP GND VPP is not connected | ||
92 | * A0VCC S1_PWR0 MISC_WR<14> | ||
93 | * A1VCC S1_PWR1 MISC_WR<15> | ||
94 | * VX VCC | ||
95 | * VY +3.3V | ||
96 | * 12IN GND VPP is not connected | ||
97 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
98 | * | ||
99 | */ | ||
100 | |||
101 | again: | ||
102 | switch (skt->nr) { | ||
103 | case 0: | ||
104 | pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; | ||
105 | |||
106 | switch (state->Vcc) { | ||
107 | case 0: /* Hi-Z */ | ||
108 | break; | ||
109 | |||
110 | case 33: /* VY */ | ||
111 | pa_dwr_set |= GPIO_A3; | ||
112 | break; | ||
113 | |||
114 | case 50: /* VX */ | ||
115 | pa_dwr_set |= GPIO_A2; | ||
116 | break; | ||
117 | |||
118 | default: | ||
119 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
120 | __FUNCTION__, state->Vcc); | ||
121 | ret = -1; | ||
122 | } | ||
123 | |||
124 | switch (state->Vpp) { | ||
125 | case 0: /* Hi-Z */ | ||
126 | break; | ||
127 | |||
128 | case 120: /* 12IN */ | ||
129 | pa_dwr_set |= GPIO_A1; | ||
130 | break; | ||
131 | |||
132 | default: /* VCC */ | ||
133 | if (state->Vpp == state->Vcc) | ||
134 | pa_dwr_set |= GPIO_A0; | ||
135 | else { | ||
136 | printk(KERN_ERR "%s(): unrecognized Vpp %u\n", | ||
137 | __FUNCTION__, state->Vpp); | ||
138 | ret = -1; | ||
139 | break; | ||
140 | } | ||
141 | } | ||
142 | break; | ||
143 | |||
144 | case 1: | ||
145 | misc_mask = (1 << 15) | (1 << 14); | ||
146 | |||
147 | switch (state->Vcc) { | ||
148 | case 0: /* Hi-Z */ | ||
149 | break; | ||
150 | |||
151 | case 33: /* VY */ | ||
152 | misc_set |= 1 << 15; | ||
153 | break; | ||
154 | |||
155 | case 50: /* VX */ | ||
156 | misc_set |= 1 << 14; | ||
157 | break; | ||
158 | |||
159 | default: | ||
160 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
161 | __FUNCTION__, state->Vcc); | ||
162 | ret = -1; | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
167 | printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", | ||
168 | __FUNCTION__, state->Vpp); | ||
169 | ret = -1; | ||
170 | break; | ||
171 | } | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | ret = -1; | ||
176 | } | ||
177 | |||
178 | if (ret == 0) | ||
179 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
180 | |||
181 | if (ret == 0) { | ||
182 | lubbock_set_misc_wr(misc_mask, misc_set); | ||
183 | sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); | ||
184 | } | ||
185 | |||
186 | #if 1 | ||
187 | if (ret == 0 && state->Vcc == 33) { | ||
188 | struct pcmcia_state new_state; | ||
189 | |||
190 | /* | ||
191 | * HACK ALERT: | ||
192 | * We can't sense the voltage properly on Lubbock before | ||
193 | * actually applying some power to the socket (catch 22). | ||
194 | * Resense the socket Voltage Sense pins after applying | ||
195 | * socket power. | ||
196 | * | ||
197 | * Note: It takes about 2.5ms for the MAX1602 VCC output | ||
198 | * to rise. | ||
199 | */ | ||
200 | mdelay(3); | ||
201 | |||
202 | sa1111_pcmcia_socket_state(skt, &new_state); | ||
203 | |||
204 | if (!new_state.vs_3v && !new_state.vs_Xv) { | ||
205 | /* | ||
206 | * Switch to 5V, Configure socket with 5V voltage | ||
207 | */ | ||
208 | lubbock_set_misc_wr(misc_mask, 0); | ||
209 | sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, 0); | ||
210 | |||
211 | /* | ||
212 | * It takes about 100ms to turn off Vcc. | ||
213 | */ | ||
214 | mdelay(100); | ||
215 | |||
216 | /* | ||
217 | * We need to hack around the const qualifier as | ||
218 | * well to keep this ugly workaround localized and | ||
219 | * not force it to the rest of the code. Barf bags | ||
220 | * avaliable in the seat pocket in front of you! | ||
221 | */ | ||
222 | ((socket_state_t *)state)->Vcc = 50; | ||
223 | ((socket_state_t *)state)->Vpp = 50; | ||
224 | goto again; | ||
225 | } | ||
226 | } | ||
227 | #endif | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static struct pcmcia_low_level lubbock_pcmcia_ops = { | ||
233 | .owner = THIS_MODULE, | ||
234 | .hw_init = lubbock_pcmcia_hw_init, | ||
235 | .hw_shutdown = sa1111_pcmcia_hw_shutdown, | ||
236 | .socket_state = sa1111_pcmcia_socket_state, | ||
237 | .configure_socket = lubbock_pcmcia_configure_socket, | ||
238 | .socket_init = sa1111_pcmcia_socket_init, | ||
239 | .socket_suspend = sa1111_pcmcia_socket_suspend, | ||
240 | .first = 0, | ||
241 | .nr = 2, | ||
242 | }; | ||
243 | |||
244 | #include "pxa2xx_base.h" | ||
245 | |||
246 | int __init pcmcia_lubbock_init(struct sa1111_dev *sadev) | ||
247 | { | ||
248 | int ret = -ENODEV; | ||
249 | |||
250 | if (machine_is_lubbock()) { | ||
251 | /* | ||
252 | * Set GPIO_A<3:0> to be outputs for the MAX1600, | ||
253 | * and switch to standby mode. | ||
254 | */ | ||
255 | sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | ||
256 | sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
257 | sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
258 | |||
259 | /* Set CF Socket 1 power to standby mode. */ | ||
260 | lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); | ||
261 | |||
262 | sadev->dev.platform_data = &lubbock_pcmcia_ops; | ||
263 | ret = pxa2xx_drv_pcmcia_probe(&sadev->dev); | ||
264 | } | ||
265 | |||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c new file mode 100644 index 000000000000..5309734e1687 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_mainstone.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_mainstone.c | ||
3 | * | ||
4 | * Mainstone PCMCIA specific routines. | ||
5 | * | ||
6 | * Created: May 12, 2004 | ||
7 | * Author: Nicolas Pitre | ||
8 | * Copyright: MontaVista Software Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/device.h> | ||
21 | |||
22 | #include <pcmcia/ss.h> | ||
23 | |||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/irq.h> | ||
26 | |||
27 | #include <asm/arch/pxa-regs.h> | ||
28 | #include <asm/arch/mainstone.h> | ||
29 | |||
30 | #include "soc_common.h" | ||
31 | |||
32 | |||
33 | static struct pcmcia_irqs irqs[] = { | ||
34 | { 0, MAINSTONE_S0_CD_IRQ, "PCMCIA0 CD" }, | ||
35 | { 1, MAINSTONE_S1_CD_IRQ, "PCMCIA1 CD" }, | ||
36 | { 0, MAINSTONE_S0_STSCHG_IRQ, "PCMCIA0 STSCHG" }, | ||
37 | { 1, MAINSTONE_S1_STSCHG_IRQ, "PCMCIA1 STSCHG" }, | ||
38 | }; | ||
39 | |||
40 | static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
41 | { | ||
42 | /* | ||
43 | * Setup default state of GPIO outputs | ||
44 | * before we enable them as outputs. | ||
45 | */ | ||
46 | GPSR(GPIO48_nPOE) = | ||
47 | GPIO_bit(GPIO48_nPOE) | | ||
48 | GPIO_bit(GPIO49_nPWE) | | ||
49 | GPIO_bit(GPIO50_nPIOR) | | ||
50 | GPIO_bit(GPIO51_nPIOW) | | ||
51 | GPIO_bit(GPIO85_nPCE_1) | | ||
52 | GPIO_bit(GPIO54_nPCE_2); | ||
53 | |||
54 | pxa_gpio_mode(GPIO48_nPOE_MD); | ||
55 | pxa_gpio_mode(GPIO49_nPWE_MD); | ||
56 | pxa_gpio_mode(GPIO50_nPIOR_MD); | ||
57 | pxa_gpio_mode(GPIO51_nPIOW_MD); | ||
58 | pxa_gpio_mode(GPIO85_nPCE_1_MD); | ||
59 | pxa_gpio_mode(GPIO54_nPCE_2_MD); | ||
60 | pxa_gpio_mode(GPIO79_pSKTSEL_MD); | ||
61 | pxa_gpio_mode(GPIO55_nPREG_MD); | ||
62 | pxa_gpio_mode(GPIO56_nPWAIT_MD); | ||
63 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | ||
64 | |||
65 | skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; | ||
66 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
67 | } | ||
68 | |||
69 | static void mst_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
70 | { | ||
71 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
72 | } | ||
73 | |||
74 | static unsigned long mst_pcmcia_status[2]; | ||
75 | |||
76 | static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
77 | struct pcmcia_state *state) | ||
78 | { | ||
79 | unsigned long status, flip; | ||
80 | |||
81 | status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1; | ||
82 | flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1; | ||
83 | |||
84 | /* | ||
85 | * Workaround for STSCHG which can't be deasserted: | ||
86 | * We therefore disable/enable corresponding IRQs | ||
87 | * as needed to avoid IRQ locks. | ||
88 | */ | ||
89 | if (flip) { | ||
90 | mst_pcmcia_status[skt->nr] = status; | ||
91 | if (status & MST_PCMCIA_nSTSCHG_BVD1) | ||
92 | enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ | ||
93 | : MAINSTONE_S1_STSCHG_IRQ ); | ||
94 | else | ||
95 | disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ | ||
96 | : MAINSTONE_S1_STSCHG_IRQ ); | ||
97 | } | ||
98 | |||
99 | state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1; | ||
100 | state->ready = (status & MST_PCMCIA_nIRQ) ? 1 : 0; | ||
101 | state->bvd1 = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0; | ||
102 | state->bvd2 = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0; | ||
103 | state->vs_3v = (status & MST_PCMCIA_nVS1) ? 0 : 1; | ||
104 | state->vs_Xv = (status & MST_PCMCIA_nVS2) ? 0 : 1; | ||
105 | state->wrprot = 0; /* not available */ | ||
106 | } | ||
107 | |||
108 | static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
109 | const socket_state_t *state) | ||
110 | { | ||
111 | unsigned long power = 0; | ||
112 | int ret = 0; | ||
113 | |||
114 | switch (state->Vcc) { | ||
115 | case 0: power |= MST_PCMCIA_PWR_VCC_0; break; | ||
116 | case 33: power |= MST_PCMCIA_PWR_VCC_33; break; | ||
117 | case 50: power |= MST_PCMCIA_PWR_VCC_50; break; | ||
118 | default: | ||
119 | printk(KERN_ERR "%s(): bad Vcc %u\n", | ||
120 | __FUNCTION__, state->Vcc); | ||
121 | ret = -1; | ||
122 | } | ||
123 | |||
124 | switch (state->Vpp) { | ||
125 | case 0: power |= MST_PCMCIA_PWR_VPP_0; break; | ||
126 | case 120: power |= MST_PCMCIA_PWR_VPP_120; break; | ||
127 | default: | ||
128 | if(state->Vpp == state->Vcc) { | ||
129 | power |= MST_PCMCIA_PWR_VPP_VCC; | ||
130 | } else { | ||
131 | printk(KERN_ERR "%s(): bad Vpp %u\n", | ||
132 | __FUNCTION__, state->Vpp); | ||
133 | ret = -1; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | if (state->flags & SS_RESET) | ||
138 | power |= MST_PCMCIA_RESET; | ||
139 | |||
140 | switch (skt->nr) { | ||
141 | case 0: MST_PCMCIA0 = power; break; | ||
142 | case 1: MST_PCMCIA1 = power; break; | ||
143 | default: ret = -1; | ||
144 | } | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static void mst_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
150 | { | ||
151 | } | ||
152 | |||
153 | static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | static struct pcmcia_low_level mst_pcmcia_ops = { | ||
158 | .owner = THIS_MODULE, | ||
159 | .hw_init = mst_pcmcia_hw_init, | ||
160 | .hw_shutdown = mst_pcmcia_hw_shutdown, | ||
161 | .socket_state = mst_pcmcia_socket_state, | ||
162 | .configure_socket = mst_pcmcia_configure_socket, | ||
163 | .socket_init = mst_pcmcia_socket_init, | ||
164 | .socket_suspend = mst_pcmcia_socket_suspend, | ||
165 | .nr = 2, | ||
166 | }; | ||
167 | |||
168 | static struct platform_device *mst_pcmcia_device; | ||
169 | |||
170 | static int __init mst_pcmcia_init(void) | ||
171 | { | ||
172 | int ret; | ||
173 | |||
174 | mst_pcmcia_device = kmalloc(sizeof(*mst_pcmcia_device), GFP_KERNEL); | ||
175 | if (!mst_pcmcia_device) | ||
176 | return -ENOMEM; | ||
177 | memset(mst_pcmcia_device, 0, sizeof(*mst_pcmcia_device)); | ||
178 | mst_pcmcia_device->name = "pxa2xx-pcmcia"; | ||
179 | mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; | ||
180 | |||
181 | ret = platform_device_register(mst_pcmcia_device); | ||
182 | if (ret) | ||
183 | kfree(mst_pcmcia_device); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static void __exit mst_pcmcia_exit(void) | ||
189 | { | ||
190 | /* | ||
191 | * This call is supposed to free our mst_pcmcia_device. | ||
192 | * Unfortunately platform_device don't have a free method, and | ||
193 | * we can't assume it's free of any reference at this point so we | ||
194 | * can't free it either. | ||
195 | */ | ||
196 | platform_device_unregister(mst_pcmcia_device); | ||
197 | } | ||
198 | |||
199 | module_init(mst_pcmcia_init); | ||
200 | module_exit(mst_pcmcia_exit); | ||
201 | |||
202 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c new file mode 100644 index 000000000000..42efe218867a --- /dev/null +++ b/drivers/pcmcia/pxa2xx_sharpsl.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Sharp SL-C7xx Series PCMCIA routines | ||
3 | * | ||
4 | * Copyright (c) 2004-2005 Richard Purdie | ||
5 | * | ||
6 | * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/device.h> | ||
20 | |||
21 | #include <asm/hardware.h> | ||
22 | #include <asm/irq.h> | ||
23 | |||
24 | #include <asm/hardware/scoop.h> | ||
25 | #include <asm/arch/corgi.h> | ||
26 | #include <asm/arch/pxa-regs.h> | ||
27 | |||
28 | #include "soc_common.h" | ||
29 | |||
30 | #define NO_KEEP_VS 0x0001 | ||
31 | |||
32 | static unsigned char keep_vs; | ||
33 | static unsigned char keep_rd; | ||
34 | |||
35 | static struct pcmcia_irqs irqs[] = { | ||
36 | { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"}, | ||
37 | }; | ||
38 | |||
39 | static void sharpsl_pcmcia_init_reset(void) | ||
40 | { | ||
41 | reset_scoop(&corgiscoop_device.dev); | ||
42 | keep_vs = NO_KEEP_VS; | ||
43 | keep_rd = 0; | ||
44 | } | ||
45 | |||
46 | static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
47 | { | ||
48 | int ret; | ||
49 | |||
50 | /* | ||
51 | * Setup default state of GPIO outputs | ||
52 | * before we enable them as outputs. | ||
53 | */ | ||
54 | GPSR(GPIO48_nPOE) = | ||
55 | GPIO_bit(GPIO48_nPOE) | | ||
56 | GPIO_bit(GPIO49_nPWE) | | ||
57 | GPIO_bit(GPIO50_nPIOR) | | ||
58 | GPIO_bit(GPIO51_nPIOW) | | ||
59 | GPIO_bit(GPIO52_nPCE_1) | | ||
60 | GPIO_bit(GPIO53_nPCE_2); | ||
61 | |||
62 | pxa_gpio_mode(GPIO48_nPOE_MD); | ||
63 | pxa_gpio_mode(GPIO49_nPWE_MD); | ||
64 | pxa_gpio_mode(GPIO50_nPIOR_MD); | ||
65 | pxa_gpio_mode(GPIO51_nPIOW_MD); | ||
66 | pxa_gpio_mode(GPIO52_nPCE_1_MD); | ||
67 | pxa_gpio_mode(GPIO53_nPCE_2_MD); | ||
68 | pxa_gpio_mode(GPIO54_pSKTSEL_MD); | ||
69 | pxa_gpio_mode(GPIO55_nPREG_MD); | ||
70 | pxa_gpio_mode(GPIO56_nPWAIT_MD); | ||
71 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | ||
72 | |||
73 | /* Register interrupts */ | ||
74 | ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
75 | |||
76 | if (ret) { | ||
77 | printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | /* Enable interrupt */ | ||
82 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); | ||
83 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); | ||
84 | keep_vs = NO_KEEP_VS; | ||
85 | |||
86 | skt->irq = CORGI_IRQ_GPIO_CF_IRQ; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
92 | { | ||
93 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
94 | |||
95 | /* CF_BUS_OFF */ | ||
96 | sharpsl_pcmcia_init_reset(); | ||
97 | } | ||
98 | |||
99 | |||
100 | static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
101 | struct pcmcia_state *state) | ||
102 | { | ||
103 | unsigned short cpr, csr; | ||
104 | |||
105 | cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); | ||
106 | |||
107 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); | ||
108 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); | ||
109 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); | ||
110 | csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); | ||
111 | if (csr & 0x0004) { | ||
112 | /* card eject */ | ||
113 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | ||
114 | keep_vs = NO_KEEP_VS; | ||
115 | } | ||
116 | else if (!(keep_vs & NO_KEEP_VS)) { | ||
117 | /* keep vs1,vs2 */ | ||
118 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | ||
119 | csr |= keep_vs; | ||
120 | } | ||
121 | else if (cpr & 0x0003) { | ||
122 | /* power on */ | ||
123 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | ||
124 | keep_vs = (csr & 0x00C0); | ||
125 | } | ||
126 | else { | ||
127 | /* card detect */ | ||
128 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); | ||
129 | } | ||
130 | |||
131 | state->detect = (csr & 0x0004) ? 0 : 1; | ||
132 | state->ready = (csr & 0x0002) ? 1 : 0; | ||
133 | state->bvd1 = (csr & 0x0010) ? 1 : 0; | ||
134 | state->bvd2 = (csr & 0x0020) ? 1 : 0; | ||
135 | state->wrprot = (csr & 0x0008) ? 1 : 0; | ||
136 | state->vs_3v = (csr & 0x0040) ? 0 : 1; | ||
137 | state->vs_Xv = (csr & 0x0080) ? 0 : 1; | ||
138 | |||
139 | if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) { | ||
140 | printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr); | ||
141 | } | ||
142 | |||
143 | } | ||
144 | |||
145 | |||
146 | static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
147 | const socket_state_t *state) | ||
148 | { | ||
149 | unsigned long flags; | ||
150 | |||
151 | unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; | ||
152 | |||
153 | switch (state->Vcc) { | ||
154 | case 0: break; | ||
155 | case 33: break; | ||
156 | case 50: break; | ||
157 | default: | ||
158 | printk(KERN_ERR "sharpsl_pcmcia_configure_socket(): bad Vcc %u\n", state->Vcc); | ||
159 | return -1; | ||
160 | } | ||
161 | |||
162 | if ((state->Vpp!=state->Vcc) && (state->Vpp!=0)) { | ||
163 | printk(KERN_ERR "CF slot cannot support Vpp %u\n", state->Vpp); | ||
164 | return -1; | ||
165 | } | ||
166 | |||
167 | local_irq_save(flags); | ||
168 | |||
169 | nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; | ||
170 | ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; | ||
171 | nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; | ||
172 | nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; | ||
173 | |||
174 | ncpr |= (state->Vcc == 33) ? 0x0001 : | ||
175 | (state->Vcc == 50) ? 0x0002 : 0; | ||
176 | nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0; | ||
177 | ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0; | ||
178 | nccr |= (state->flags&SS_RESET)? 0x0080: 0; | ||
179 | nimr |= ((skt->status&SS_DETECT) ? 0x0004 : 0)| | ||
180 | ((skt->status&SS_READY) ? 0x0002 : 0)| | ||
181 | ((skt->status&SS_BATDEAD)? 0x0010 : 0)| | ||
182 | ((skt->status&SS_BATWARN)? 0x0020 : 0)| | ||
183 | ((skt->status&SS_STSCHG) ? 0x0010 : 0)| | ||
184 | ((skt->status&SS_WRPROT) ? 0x0008 : 0); | ||
185 | |||
186 | if (!(ncpr & 0x0003)) { | ||
187 | keep_rd = 0; | ||
188 | } else if (!keep_rd) { | ||
189 | if (nccr & 0x0080) | ||
190 | keep_rd = 1; | ||
191 | else | ||
192 | nccr |= 0x0080; | ||
193 | } | ||
194 | |||
195 | if (mcr != nmcr) | ||
196 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); | ||
197 | if (cpr != ncpr) | ||
198 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); | ||
199 | if (ccr != nccr) | ||
200 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); | ||
201 | if (imr != nimr) | ||
202 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); | ||
203 | |||
204 | local_irq_restore(flags); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
210 | { | ||
211 | } | ||
212 | |||
213 | static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
214 | { | ||
215 | } | ||
216 | |||
217 | static struct pcmcia_low_level sharpsl_pcmcia_ops = { | ||
218 | .owner = THIS_MODULE, | ||
219 | .hw_init = sharpsl_pcmcia_hw_init, | ||
220 | .hw_shutdown = sharpsl_pcmcia_hw_shutdown, | ||
221 | .socket_state = sharpsl_pcmcia_socket_state, | ||
222 | .configure_socket = sharpsl_pcmcia_configure_socket, | ||
223 | .socket_init = sharpsl_pcmcia_socket_init, | ||
224 | .socket_suspend = sharpsl_pcmcia_socket_suspend, | ||
225 | .first = 0, | ||
226 | .nr = 1, | ||
227 | }; | ||
228 | |||
229 | static struct platform_device *sharpsl_pcmcia_device; | ||
230 | |||
231 | static int __init sharpsl_pcmcia_init(void) | ||
232 | { | ||
233 | int ret; | ||
234 | |||
235 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); | ||
236 | if (!sharpsl_pcmcia_device) | ||
237 | return -ENOMEM; | ||
238 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); | ||
239 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; | ||
240 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; | ||
241 | |||
242 | ret = platform_device_register(sharpsl_pcmcia_device); | ||
243 | if (ret) | ||
244 | kfree(sharpsl_pcmcia_device); | ||
245 | |||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | static void __exit sharpsl_pcmcia_exit(void) | ||
250 | { | ||
251 | /* | ||
252 | * This call is supposed to free our sharpsl_pcmcia_device. | ||
253 | * Unfortunately platform_device don't have a free method, and | ||
254 | * we can't assume it's free of any reference at this point so we | ||
255 | * can't free it either. | ||
256 | */ | ||
257 | platform_device_unregister(sharpsl_pcmcia_device); | ||
258 | } | ||
259 | |||
260 | module_init(sharpsl_pcmcia_init); | ||
261 | module_exit(sharpsl_pcmcia_exit); | ||
262 | |||
263 | MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); | ||
264 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h new file mode 100644 index 000000000000..01098c841f87 --- /dev/null +++ b/drivers/pcmcia/ricoh.h | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * ricoh.h 1.9 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_RICOH_H | ||
31 | #define _LINUX_RICOH_H | ||
32 | |||
33 | |||
34 | #define RF5C_MODE_CTL 0x1f /* Mode control */ | ||
35 | #define RF5C_PWR_CTL 0x2f /* Mixed voltage control */ | ||
36 | #define RF5C_CHIP_ID 0x3a /* Chip identification */ | ||
37 | #define RF5C_MODE_CTL_3 0x3b /* Mode control 3 */ | ||
38 | |||
39 | /* I/O window address offset */ | ||
40 | #define RF5C_IO_OFF(w) (0x36+((w)<<1)) | ||
41 | |||
42 | /* Flags for RF5C_MODE_CTL */ | ||
43 | #define RF5C_MODE_ATA 0x01 /* ATA mode */ | ||
44 | #define RF5C_MODE_LED_ENA 0x02 /* IRQ 12 is LED */ | ||
45 | #define RF5C_MODE_CA21 0x04 | ||
46 | #define RF5C_MODE_CA22 0x08 | ||
47 | #define RF5C_MODE_CA23 0x10 | ||
48 | #define RF5C_MODE_CA24 0x20 | ||
49 | #define RF5C_MODE_CA25 0x40 | ||
50 | #define RF5C_MODE_3STATE_BIT7 0x80 | ||
51 | |||
52 | /* Flags for RF5C_PWR_CTL */ | ||
53 | #define RF5C_PWR_VCC_3V 0x01 | ||
54 | #define RF5C_PWR_IREQ_HIGH 0x02 | ||
55 | #define RF5C_PWR_INPACK_ENA 0x04 | ||
56 | #define RF5C_PWR_5V_DET 0x08 | ||
57 | #define RF5C_PWR_TC_SEL 0x10 /* Terminal Count: irq 11 or 15 */ | ||
58 | #define RF5C_PWR_DREQ_LOW 0x20 | ||
59 | #define RF5C_PWR_DREQ_OFF 0x00 /* DREQ steering control */ | ||
60 | #define RF5C_PWR_DREQ_INPACK 0x40 | ||
61 | #define RF5C_PWR_DREQ_SPKR 0x80 | ||
62 | #define RF5C_PWR_DREQ_IOIS16 0xc0 | ||
63 | |||
64 | /* Values for RF5C_CHIP_ID */ | ||
65 | #define RF5C_CHIP_RF5C296 0x32 | ||
66 | #define RF5C_CHIP_RF5C396 0xb2 | ||
67 | |||
68 | /* Flags for RF5C_MODE_CTL_3 */ | ||
69 | #define RF5C_MCTL3_DISABLE 0x01 /* Disable PCMCIA interface */ | ||
70 | #define RF5C_MCTL3_DMA_ENA 0x02 | ||
71 | |||
72 | /* Register definitions for Ricoh PCI-to-CardBus bridges */ | ||
73 | |||
74 | /* Extra bits in CB_BRIDGE_CONTROL */ | ||
75 | #define RL5C46X_BCR_3E0_ENA 0x0800 | ||
76 | #define RL5C46X_BCR_3E2_ENA 0x1000 | ||
77 | |||
78 | /* Bridge Configuration Register */ | ||
79 | #define RL5C4XX_CONFIG 0x80 /* 16 bit */ | ||
80 | #define RL5C4XX_CONFIG_IO_1_MODE 0x0200 | ||
81 | #define RL5C4XX_CONFIG_IO_0_MODE 0x0100 | ||
82 | #define RL5C4XX_CONFIG_PREFETCH 0x0001 | ||
83 | |||
84 | /* Misc Control Register */ | ||
85 | #define RL5C4XX_MISC 0x0082 /* 16 bit */ | ||
86 | #define RL5C4XX_MISC_HW_SUSPEND_ENA 0x0002 | ||
87 | #define RL5C4XX_MISC_VCCEN_POL 0x0100 | ||
88 | #define RL5C4XX_MISC_VPPEN_POL 0x0200 | ||
89 | #define RL5C46X_MISC_SUSPEND 0x0001 | ||
90 | #define RL5C46X_MISC_PWR_SAVE_2 0x0004 | ||
91 | #define RL5C46X_MISC_IFACE_BUSY 0x0008 | ||
92 | #define RL5C46X_MISC_B_LOCK 0x0010 | ||
93 | #define RL5C46X_MISC_A_LOCK 0x0020 | ||
94 | #define RL5C46X_MISC_PCI_LOCK 0x0040 | ||
95 | #define RL5C47X_MISC_IFACE_BUSY 0x0004 | ||
96 | #define RL5C47X_MISC_PCI_INT_MASK 0x0018 | ||
97 | #define RL5C47X_MISC_PCI_INT_DIS 0x0020 | ||
98 | #define RL5C47X_MISC_SUBSYS_WR 0x0040 | ||
99 | #define RL5C47X_MISC_SRIRQ_ENA 0x0080 | ||
100 | #define RL5C47X_MISC_5V_DISABLE 0x0400 | ||
101 | #define RL5C47X_MISC_LED_POL 0x0800 | ||
102 | |||
103 | /* 16-bit Interface Control Register */ | ||
104 | #define RL5C4XX_16BIT_CTL 0x0084 /* 16 bit */ | ||
105 | #define RL5C4XX_16CTL_IO_TIMING 0x0100 | ||
106 | #define RL5C4XX_16CTL_MEM_TIMING 0x0200 | ||
107 | #define RL5C46X_16CTL_LEVEL_1 0x0010 | ||
108 | #define RL5C46X_16CTL_LEVEL_2 0x0020 | ||
109 | |||
110 | /* 16-bit IO and memory timing registers */ | ||
111 | #define RL5C4XX_16BIT_IO_0 0x0088 /* 16 bit */ | ||
112 | #define RL5C4XX_16BIT_MEM_0 0x008a /* 16 bit */ | ||
113 | #define RL5C4XX_SETUP_MASK 0x0007 | ||
114 | #define RL5C4XX_SETUP_SHIFT 0 | ||
115 | #define RL5C4XX_CMD_MASK 0x01f0 | ||
116 | #define RL5C4XX_CMD_SHIFT 4 | ||
117 | #define RL5C4XX_HOLD_MASK 0x1c00 | ||
118 | #define RL5C4XX_HOLD_SHIFT 10 | ||
119 | #define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */ | ||
120 | #define RL5C4XX_ZV_ENABLE 0x08 | ||
121 | |||
122 | #ifdef __YENTA_H | ||
123 | |||
124 | #define rl_misc(socket) ((socket)->private[0]) | ||
125 | #define rl_ctl(socket) ((socket)->private[1]) | ||
126 | #define rl_io(socket) ((socket)->private[2]) | ||
127 | #define rl_mem(socket) ((socket)->private[3]) | ||
128 | #define rl_config(socket) ((socket)->private[4]) | ||
129 | |||
130 | static void ricoh_zoom_video(struct pcmcia_socket *sock, int onoff) | ||
131 | { | ||
132 | u8 reg; | ||
133 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
134 | |||
135 | reg = config_readb(socket, RL5C4XX_MISC_CONTROL); | ||
136 | if (onoff) | ||
137 | /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ | ||
138 | reg |= RL5C4XX_ZV_ENABLE; | ||
139 | else | ||
140 | reg &= ~RL5C4XX_ZV_ENABLE; | ||
141 | |||
142 | config_writeb(socket, RL5C4XX_MISC_CONTROL, reg); | ||
143 | } | ||
144 | |||
145 | static void ricoh_set_zv(struct yenta_socket *socket) | ||
146 | { | ||
147 | if(socket->dev->vendor == PCI_VENDOR_ID_RICOH) | ||
148 | { | ||
149 | switch(socket->dev->device) | ||
150 | { | ||
151 | /* There may be more .. */ | ||
152 | case PCI_DEVICE_ID_RICOH_RL5C478: | ||
153 | socket->socket.zoom_video = ricoh_zoom_video; | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static void ricoh_save_state(struct yenta_socket *socket) | ||
160 | { | ||
161 | rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); | ||
162 | rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL); | ||
163 | rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); | ||
164 | rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0); | ||
165 | rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG); | ||
166 | } | ||
167 | |||
168 | static void ricoh_restore_state(struct yenta_socket *socket) | ||
169 | { | ||
170 | config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); | ||
171 | config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); | ||
172 | config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); | ||
173 | config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); | ||
174 | config_writew(socket, RL5C4XX_CONFIG, rl_config(socket)); | ||
175 | } | ||
176 | |||
177 | |||
178 | /* | ||
179 | * Magic Ricoh initialization code.. | ||
180 | */ | ||
181 | static int ricoh_override(struct yenta_socket *socket) | ||
182 | { | ||
183 | u16 config, ctl; | ||
184 | |||
185 | config = config_readw(socket, RL5C4XX_CONFIG); | ||
186 | |||
187 | /* Set the default timings, don't trust the original values */ | ||
188 | ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; | ||
189 | |||
190 | if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) { | ||
191 | ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; | ||
192 | } else { | ||
193 | config |= RL5C4XX_CONFIG_PREFETCH; | ||
194 | } | ||
195 | |||
196 | config_writew(socket, RL5C4XX_16BIT_CTL, ctl); | ||
197 | config_writew(socket, RL5C4XX_CONFIG, config); | ||
198 | |||
199 | ricoh_set_zv(socket); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | #endif /* CONFIG_CARDBUS */ | ||
205 | |||
206 | #endif /* _LINUX_RICOH_H */ | ||
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c new file mode 100644 index 000000000000..b6843f8d300d --- /dev/null +++ b/drivers/pcmcia/rsrc_mgr.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * rsrc_mgr.c -- Resource management routines and/or wrappers | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | |||
19 | #include <pcmcia/cs_types.h> | ||
20 | #include <pcmcia/ss.h> | ||
21 | #include <pcmcia/cs.h> | ||
22 | #include "cs_internal.h" | ||
23 | |||
24 | |||
25 | #ifdef CONFIG_PCMCIA_PROBE | ||
26 | |||
27 | static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) | ||
28 | { | ||
29 | int irq; | ||
30 | u32 mask; | ||
31 | |||
32 | irq = adj->resource.irq.IRQ; | ||
33 | if ((irq < 0) || (irq > 15)) | ||
34 | return CS_BAD_IRQ; | ||
35 | |||
36 | if (adj->Action != REMOVE_MANAGED_RESOURCE) | ||
37 | return 0; | ||
38 | |||
39 | mask = 1 << irq; | ||
40 | |||
41 | if (!(s->irq_mask & mask)) | ||
42 | return 0; | ||
43 | |||
44 | s->irq_mask &= ~mask; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | #else | ||
50 | |||
51 | static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { | ||
52 | return CS_SUCCESS; | ||
53 | } | ||
54 | |||
55 | #endif | ||
56 | |||
57 | |||
58 | int pcmcia_adjust_resource_info(adjust_t *adj) | ||
59 | { | ||
60 | struct pcmcia_socket *s; | ||
61 | int ret = CS_UNSUPPORTED_FUNCTION; | ||
62 | unsigned long flags; | ||
63 | |||
64 | down_read(&pcmcia_socket_list_rwsem); | ||
65 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
66 | |||
67 | if (adj->Resource == RES_IRQ) | ||
68 | ret = adjust_irq(s, adj); | ||
69 | |||
70 | else if (s->resource_ops->adjust_resource) { | ||
71 | |||
72 | /* you can't use the old interface if the new | ||
73 | * one was used before */ | ||
74 | spin_lock_irqsave(&s->lock, flags); | ||
75 | if ((s->resource_setup_done) && | ||
76 | !(s->resource_setup_old)) { | ||
77 | spin_unlock_irqrestore(&s->lock, flags); | ||
78 | continue; | ||
79 | } else if (!(s->resource_setup_old)) | ||
80 | s->resource_setup_old = 1; | ||
81 | spin_unlock_irqrestore(&s->lock, flags); | ||
82 | |||
83 | ret = s->resource_ops->adjust_resource(s, adj); | ||
84 | if (!ret) { | ||
85 | /* as there's no way we know this is the | ||
86 | * last call to adjust_resource_info, we | ||
87 | * always need to assume this is the latest | ||
88 | * one... */ | ||
89 | spin_lock_irqsave(&s->lock, flags); | ||
90 | s->resource_setup_done = 1; | ||
91 | spin_unlock_irqrestore(&s->lock, flags); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | up_read(&pcmcia_socket_list_rwsem); | ||
96 | |||
97 | return (ret); | ||
98 | } | ||
99 | EXPORT_SYMBOL(pcmcia_adjust_resource_info); | ||
100 | |||
101 | void pcmcia_validate_mem(struct pcmcia_socket *s) | ||
102 | { | ||
103 | if (s->resource_ops->validate_mem) | ||
104 | s->resource_ops->validate_mem(s); | ||
105 | } | ||
106 | EXPORT_SYMBOL(pcmcia_validate_mem); | ||
107 | |||
108 | int adjust_io_region(struct resource *res, unsigned long r_start, | ||
109 | unsigned long r_end, struct pcmcia_socket *s) | ||
110 | { | ||
111 | if (s->resource_ops->adjust_io_region) | ||
112 | return s->resource_ops->adjust_io_region(res, r_start, r_end, s); | ||
113 | return -ENOMEM; | ||
114 | } | ||
115 | |||
116 | struct resource *find_io_region(unsigned long base, int num, | ||
117 | unsigned long align, struct pcmcia_socket *s) | ||
118 | { | ||
119 | if (s->resource_ops->find_io) | ||
120 | return s->resource_ops->find_io(base, num, align, s); | ||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | struct resource *find_mem_region(u_long base, u_long num, u_long align, | ||
125 | int low, struct pcmcia_socket *s) | ||
126 | { | ||
127 | if (s->resource_ops->find_mem) | ||
128 | return s->resource_ops->find_mem(base, num, align, low, s); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | void release_resource_db(struct pcmcia_socket *s) | ||
133 | { | ||
134 | if (s->resource_ops->exit) | ||
135 | s->resource_ops->exit(s); | ||
136 | } | ||
137 | |||
138 | |||
139 | static int static_init(struct pcmcia_socket *s) | ||
140 | { | ||
141 | unsigned long flags; | ||
142 | |||
143 | /* the good thing about SS_CAP_STATIC_MAP sockets is | ||
144 | * that they don't need a resource database */ | ||
145 | |||
146 | spin_lock_irqsave(&s->lock, flags); | ||
147 | s->resource_setup_done = 1; | ||
148 | spin_unlock_irqrestore(&s->lock, flags); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | struct pccard_resource_ops pccard_static_ops = { | ||
155 | .validate_mem = NULL, | ||
156 | .adjust_io_region = NULL, | ||
157 | .find_io = NULL, | ||
158 | .find_mem = NULL, | ||
159 | .adjust_resource = NULL, | ||
160 | .init = static_init, | ||
161 | .exit = NULL, | ||
162 | }; | ||
163 | EXPORT_SYMBOL(pccard_static_ops); | ||
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c new file mode 100644 index 000000000000..5876bab7c14c --- /dev/null +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -0,0 +1,985 @@ | |||
1 | /* | ||
2 | * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/device.h> | ||
28 | |||
29 | #include <asm/irq.h> | ||
30 | #include <asm/io.h> | ||
31 | |||
32 | #include <pcmcia/cs_types.h> | ||
33 | #include <pcmcia/ss.h> | ||
34 | #include <pcmcia/cs.h> | ||
35 | #include <pcmcia/bulkmem.h> | ||
36 | #include <pcmcia/cistpl.h> | ||
37 | #include "cs_internal.h" | ||
38 | |||
39 | MODULE_AUTHOR("David A. Hinds, Dominik Brodowski"); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | |||
42 | /* Parameters that can be set with 'insmod' */ | ||
43 | |||
44 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) | ||
45 | |||
46 | INT_MODULE_PARM(probe_mem, 1); /* memory probe? */ | ||
47 | #ifdef CONFIG_PCMCIA_PROBE | ||
48 | INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ | ||
49 | INT_MODULE_PARM(mem_limit, 0x10000); | ||
50 | #endif | ||
51 | |||
52 | /* for io_db and mem_db */ | ||
53 | struct resource_map { | ||
54 | u_long base, num; | ||
55 | struct resource_map *next; | ||
56 | }; | ||
57 | |||
58 | struct socket_data { | ||
59 | struct resource_map mem_db; | ||
60 | struct resource_map io_db; | ||
61 | unsigned int rsrc_mem_probe; | ||
62 | }; | ||
63 | |||
64 | static DECLARE_MUTEX(rsrc_sem); | ||
65 | #define MEM_PROBE_LOW (1 << 0) | ||
66 | #define MEM_PROBE_HIGH (1 << 1) | ||
67 | |||
68 | |||
69 | /*====================================================================== | ||
70 | |||
71 | Linux resource management extensions | ||
72 | |||
73 | ======================================================================*/ | ||
74 | |||
75 | static struct resource * | ||
76 | make_resource(unsigned long b, unsigned long n, int flags, char *name) | ||
77 | { | ||
78 | struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); | ||
79 | |||
80 | if (res) { | ||
81 | memset(res, 0, sizeof(*res)); | ||
82 | res->name = name; | ||
83 | res->start = b; | ||
84 | res->end = b + n - 1; | ||
85 | res->flags = flags; | ||
86 | } | ||
87 | return res; | ||
88 | } | ||
89 | |||
90 | static struct resource * | ||
91 | claim_region(struct pcmcia_socket *s, unsigned long base, unsigned long size, | ||
92 | int type, char *name) | ||
93 | { | ||
94 | struct resource *res, *parent; | ||
95 | |||
96 | parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource; | ||
97 | res = make_resource(base, size, type | IORESOURCE_BUSY, name); | ||
98 | |||
99 | if (res) { | ||
100 | #ifdef CONFIG_PCI | ||
101 | if (s && s->cb_dev) | ||
102 | parent = pci_find_parent_resource(s->cb_dev, res); | ||
103 | #endif | ||
104 | if (!parent || request_resource(parent, res)) { | ||
105 | kfree(res); | ||
106 | res = NULL; | ||
107 | } | ||
108 | } | ||
109 | return res; | ||
110 | } | ||
111 | |||
112 | static void free_region(struct resource *res) | ||
113 | { | ||
114 | if (res) { | ||
115 | release_resource(res); | ||
116 | kfree(res); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /*====================================================================== | ||
121 | |||
122 | These manage the internal databases of available resources. | ||
123 | |||
124 | ======================================================================*/ | ||
125 | |||
126 | static int add_interval(struct resource_map *map, u_long base, u_long num) | ||
127 | { | ||
128 | struct resource_map *p, *q; | ||
129 | |||
130 | for (p = map; ; p = p->next) { | ||
131 | if ((p != map) && (p->base+p->num-1 >= base)) | ||
132 | return -1; | ||
133 | if ((p->next == map) || (p->next->base > base+num-1)) | ||
134 | break; | ||
135 | } | ||
136 | q = kmalloc(sizeof(struct resource_map), GFP_KERNEL); | ||
137 | if (!q) return CS_OUT_OF_RESOURCE; | ||
138 | q->base = base; q->num = num; | ||
139 | q->next = p->next; p->next = q; | ||
140 | return CS_SUCCESS; | ||
141 | } | ||
142 | |||
143 | /*====================================================================*/ | ||
144 | |||
145 | static int sub_interval(struct resource_map *map, u_long base, u_long num) | ||
146 | { | ||
147 | struct resource_map *p, *q; | ||
148 | |||
149 | for (p = map; ; p = q) { | ||
150 | q = p->next; | ||
151 | if (q == map) | ||
152 | break; | ||
153 | if ((q->base+q->num > base) && (base+num > q->base)) { | ||
154 | if (q->base >= base) { | ||
155 | if (q->base+q->num <= base+num) { | ||
156 | /* Delete whole block */ | ||
157 | p->next = q->next; | ||
158 | kfree(q); | ||
159 | /* don't advance the pointer yet */ | ||
160 | q = p; | ||
161 | } else { | ||
162 | /* Cut off bit from the front */ | ||
163 | q->num = q->base + q->num - base - num; | ||
164 | q->base = base + num; | ||
165 | } | ||
166 | } else if (q->base+q->num <= base+num) { | ||
167 | /* Cut off bit from the end */ | ||
168 | q->num = base - q->base; | ||
169 | } else { | ||
170 | /* Split the block into two pieces */ | ||
171 | p = kmalloc(sizeof(struct resource_map), GFP_KERNEL); | ||
172 | if (!p) return CS_OUT_OF_RESOURCE; | ||
173 | p->base = base+num; | ||
174 | p->num = q->base+q->num - p->base; | ||
175 | q->num = base - q->base; | ||
176 | p->next = q->next ; q->next = p; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | return CS_SUCCESS; | ||
181 | } | ||
182 | |||
183 | /*====================================================================== | ||
184 | |||
185 | These routines examine a region of IO or memory addresses to | ||
186 | determine what ranges might be genuinely available. | ||
187 | |||
188 | ======================================================================*/ | ||
189 | |||
190 | #ifdef CONFIG_PCMCIA_PROBE | ||
191 | static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num) | ||
192 | { | ||
193 | struct resource *res; | ||
194 | struct socket_data *s_data = s->resource_data; | ||
195 | kio_addr_t i, j, bad; | ||
196 | int any; | ||
197 | u_char *b, hole, most; | ||
198 | |||
199 | printk(KERN_INFO "cs: IO port probe %#lx-%#lx:", | ||
200 | base, base+num-1); | ||
201 | |||
202 | /* First, what does a floating port look like? */ | ||
203 | b = kmalloc(256, GFP_KERNEL); | ||
204 | if (!b) { | ||
205 | printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); | ||
206 | return; | ||
207 | } | ||
208 | memset(b, 0, 256); | ||
209 | for (i = base, most = 0; i < base+num; i += 8) { | ||
210 | res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); | ||
211 | if (!res) | ||
212 | continue; | ||
213 | hole = inb(i); | ||
214 | for (j = 1; j < 8; j++) | ||
215 | if (inb(i+j) != hole) break; | ||
216 | free_region(res); | ||
217 | if ((j == 8) && (++b[hole] > b[most])) | ||
218 | most = hole; | ||
219 | if (b[most] == 127) break; | ||
220 | } | ||
221 | kfree(b); | ||
222 | |||
223 | bad = any = 0; | ||
224 | for (i = base; i < base+num; i += 8) { | ||
225 | res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); | ||
226 | if (!res) | ||
227 | continue; | ||
228 | for (j = 0; j < 8; j++) | ||
229 | if (inb(i+j) != most) break; | ||
230 | free_region(res); | ||
231 | if (j < 8) { | ||
232 | if (!any) | ||
233 | printk(" excluding"); | ||
234 | if (!bad) | ||
235 | bad = any = i; | ||
236 | } else { | ||
237 | if (bad) { | ||
238 | sub_interval(&s_data->io_db, bad, i-bad); | ||
239 | printk(" %#lx-%#lx", bad, i-1); | ||
240 | bad = 0; | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | if (bad) { | ||
245 | if ((num > 16) && (bad == base) && (i == base+num)) { | ||
246 | printk(" nothing: probe failed.\n"); | ||
247 | return; | ||
248 | } else { | ||
249 | sub_interval(&s_data->io_db, bad, i-bad); | ||
250 | printk(" %#lx-%#lx", bad, i-1); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | printk(any ? "\n" : " clean.\n"); | ||
255 | } | ||
256 | #endif | ||
257 | |||
258 | /*====================================================================== | ||
259 | |||
260 | This is tricky... when we set up CIS memory, we try to validate | ||
261 | the memory window space allocations. | ||
262 | |||
263 | ======================================================================*/ | ||
264 | |||
265 | /* Validation function for cards with a valid CIS */ | ||
266 | static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info) | ||
267 | { | ||
268 | int ret = -1; | ||
269 | |||
270 | s->cis_mem.res = res; | ||
271 | s->cis_virt = ioremap(res->start, s->map_size); | ||
272 | if (s->cis_virt) { | ||
273 | ret = pccard_validate_cis(s, BIND_FN_ALL, info); | ||
274 | /* invalidate mapping and CIS cache */ | ||
275 | iounmap(s->cis_virt); | ||
276 | s->cis_virt = NULL; | ||
277 | destroy_cis_cache(s); | ||
278 | } | ||
279 | s->cis_mem.res = NULL; | ||
280 | if ((ret != 0) || (info->Chains == 0)) | ||
281 | return 0; | ||
282 | return 1; | ||
283 | } | ||
284 | |||
285 | /* Validation function for simple memory cards */ | ||
286 | static int checksum(struct pcmcia_socket *s, struct resource *res) | ||
287 | { | ||
288 | pccard_mem_map map; | ||
289 | int i, a = 0, b = -1, d; | ||
290 | void __iomem *virt; | ||
291 | |||
292 | virt = ioremap(res->start, s->map_size); | ||
293 | if (virt) { | ||
294 | map.map = 0; | ||
295 | map.flags = MAP_ACTIVE; | ||
296 | map.speed = 0; | ||
297 | map.res = res; | ||
298 | map.card_start = 0; | ||
299 | s->ops->set_mem_map(s, &map); | ||
300 | |||
301 | /* Don't bother checking every word... */ | ||
302 | for (i = 0; i < s->map_size; i += 44) { | ||
303 | d = readl(virt+i); | ||
304 | a += d; | ||
305 | b &= d; | ||
306 | } | ||
307 | |||
308 | map.flags = 0; | ||
309 | s->ops->set_mem_map(s, &map); | ||
310 | |||
311 | iounmap(virt); | ||
312 | } | ||
313 | |||
314 | return (b == -1) ? -1 : (a>>1); | ||
315 | } | ||
316 | |||
317 | static int | ||
318 | cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) | ||
319 | { | ||
320 | struct resource *res1, *res2; | ||
321 | cisinfo_t info1, info2; | ||
322 | int ret = 0; | ||
323 | |||
324 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe"); | ||
325 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe"); | ||
326 | |||
327 | if (res1 && res2) { | ||
328 | ret = readable(s, res1, &info1); | ||
329 | ret += readable(s, res2, &info2); | ||
330 | } | ||
331 | |||
332 | free_region(res2); | ||
333 | free_region(res1); | ||
334 | |||
335 | return (ret == 2) && (info1.Chains == info2.Chains); | ||
336 | } | ||
337 | |||
338 | static int | ||
339 | checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) | ||
340 | { | ||
341 | struct resource *res1, *res2; | ||
342 | int a = -1, b = -1; | ||
343 | |||
344 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe"); | ||
345 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe"); | ||
346 | |||
347 | if (res1 && res2) { | ||
348 | a = checksum(s, res1); | ||
349 | b = checksum(s, res2); | ||
350 | } | ||
351 | |||
352 | free_region(res2); | ||
353 | free_region(res1); | ||
354 | |||
355 | return (a == b) && (a >= 0); | ||
356 | } | ||
357 | |||
358 | /*====================================================================== | ||
359 | |||
360 | The memory probe. If the memory list includes a 64K-aligned block | ||
361 | below 1MB, we probe in 64K chunks, and as soon as we accumulate at | ||
362 | least mem_limit free space, we quit. | ||
363 | |||
364 | ======================================================================*/ | ||
365 | |||
366 | static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | ||
367 | { | ||
368 | struct socket_data *s_data = s->resource_data; | ||
369 | u_long i, j, bad, fail, step; | ||
370 | |||
371 | printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:", | ||
372 | base, base+num-1); | ||
373 | bad = fail = 0; | ||
374 | step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); | ||
375 | /* cis_readable wants to map 2x map_size */ | ||
376 | if (step < 2 * s->map_size) | ||
377 | step = 2 * s->map_size; | ||
378 | for (i = j = base; i < base+num; i = j + step) { | ||
379 | if (!fail) { | ||
380 | for (j = i; j < base+num; j += step) { | ||
381 | if (cis_readable(s, j, step)) | ||
382 | break; | ||
383 | } | ||
384 | fail = ((i == base) && (j == base+num)); | ||
385 | } | ||
386 | if (fail) { | ||
387 | for (j = i; j < base+num; j += 2*step) | ||
388 | if (checksum_match(s, j, step) && | ||
389 | checksum_match(s, j + step, step)) | ||
390 | break; | ||
391 | } | ||
392 | if (i != j) { | ||
393 | if (!bad) printk(" excluding"); | ||
394 | printk(" %#05lx-%#05lx", i, j-1); | ||
395 | sub_interval(&s_data->mem_db, i, j-i); | ||
396 | bad += j-i; | ||
397 | } | ||
398 | } | ||
399 | printk(bad ? "\n" : " clean.\n"); | ||
400 | return (num - bad); | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_PCMCIA_PROBE | ||
404 | |||
405 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | ||
406 | { | ||
407 | struct socket_data *s_data = s->resource_data; | ||
408 | u_long ok; | ||
409 | if (m == &s_data->mem_db) | ||
410 | return 0; | ||
411 | ok = inv_probe(m->next, s); | ||
412 | if (ok) { | ||
413 | if (m->base >= 0x100000) | ||
414 | sub_interval(&s_data->mem_db, m->base, m->num); | ||
415 | return ok; | ||
416 | } | ||
417 | if (m->base < 0x100000) | ||
418 | return 0; | ||
419 | return do_mem_probe(m->base, m->num, s); | ||
420 | } | ||
421 | |||
422 | static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | ||
423 | { | ||
424 | struct resource_map *m, mm; | ||
425 | static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; | ||
426 | u_long b, i, ok = 0; | ||
427 | struct socket_data *s_data = s->resource_data; | ||
428 | |||
429 | /* We do up to four passes through the list */ | ||
430 | if (probe_mask & MEM_PROBE_HIGH) { | ||
431 | if (inv_probe(s_data->mem_db.next, s) > 0) | ||
432 | return; | ||
433 | printk(KERN_NOTICE "cs: warning: no high memory space " | ||
434 | "available!\n"); | ||
435 | } | ||
436 | if ((probe_mask & MEM_PROBE_LOW) == 0) | ||
437 | return; | ||
438 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | ||
439 | mm = *m; | ||
440 | /* Only probe < 1 MB */ | ||
441 | if (mm.base >= 0x100000) continue; | ||
442 | if ((mm.base | mm.num) & 0xffff) { | ||
443 | ok += do_mem_probe(mm.base, mm.num, s); | ||
444 | continue; | ||
445 | } | ||
446 | /* Special probe for 64K-aligned block */ | ||
447 | for (i = 0; i < 4; i++) { | ||
448 | b = order[i] << 12; | ||
449 | if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { | ||
450 | if (ok >= mem_limit) | ||
451 | sub_interval(&s_data->mem_db, b, 0x10000); | ||
452 | else | ||
453 | ok += do_mem_probe(b, 0x10000, s); | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | |||
459 | #else /* CONFIG_PCMCIA_PROBE */ | ||
460 | |||
461 | static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | ||
462 | { | ||
463 | struct resource_map *m, mm; | ||
464 | struct socket_data *s_data = s->resource_data; | ||
465 | |||
466 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | ||
467 | mm = *m; | ||
468 | if (do_mem_probe(mm.base, mm.num, s)) | ||
469 | break; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | #endif /* CONFIG_PCMCIA_PROBE */ | ||
474 | |||
475 | |||
476 | /* | ||
477 | * Locking note: Must be called with skt_sem held! | ||
478 | */ | ||
479 | static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | ||
480 | { | ||
481 | struct socket_data *s_data = s->resource_data; | ||
482 | if (probe_mem) { | ||
483 | unsigned int probe_mask; | ||
484 | |||
485 | down(&rsrc_sem); | ||
486 | |||
487 | probe_mask = MEM_PROBE_LOW; | ||
488 | if (s->features & SS_CAP_PAGE_REGS) | ||
489 | probe_mask = MEM_PROBE_HIGH; | ||
490 | |||
491 | if (probe_mask & ~s_data->rsrc_mem_probe) { | ||
492 | s_data->rsrc_mem_probe |= probe_mask; | ||
493 | |||
494 | if (s->state & SOCKET_PRESENT) | ||
495 | validate_mem(s, probe_mask); | ||
496 | } | ||
497 | |||
498 | up(&rsrc_sem); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | struct pcmcia_align_data { | ||
503 | unsigned long mask; | ||
504 | unsigned long offset; | ||
505 | struct resource_map *map; | ||
506 | }; | ||
507 | |||
508 | static void | ||
509 | pcmcia_common_align(void *align_data, struct resource *res, | ||
510 | unsigned long size, unsigned long align) | ||
511 | { | ||
512 | struct pcmcia_align_data *data = align_data; | ||
513 | unsigned long start; | ||
514 | /* | ||
515 | * Ensure that we have the correct start address | ||
516 | */ | ||
517 | start = (res->start & ~data->mask) + data->offset; | ||
518 | if (start < res->start) | ||
519 | start += data->mask + 1; | ||
520 | res->start = start; | ||
521 | } | ||
522 | |||
523 | static void | ||
524 | pcmcia_align(void *align_data, struct resource *res, | ||
525 | unsigned long size, unsigned long align) | ||
526 | { | ||
527 | struct pcmcia_align_data *data = align_data; | ||
528 | struct resource_map *m; | ||
529 | |||
530 | pcmcia_common_align(data, res, size, align); | ||
531 | |||
532 | for (m = data->map->next; m != data->map; m = m->next) { | ||
533 | unsigned long start = m->base; | ||
534 | unsigned long end = m->base + m->num - 1; | ||
535 | |||
536 | /* | ||
537 | * If the lower resources are not available, try aligning | ||
538 | * to this entry of the resource database to see if it'll | ||
539 | * fit here. | ||
540 | */ | ||
541 | if (res->start < start) { | ||
542 | res->start = start; | ||
543 | pcmcia_common_align(data, res, size, align); | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * If we're above the area which was passed in, there's | ||
548 | * no point proceeding. | ||
549 | */ | ||
550 | if (res->start >= res->end) | ||
551 | break; | ||
552 | |||
553 | if ((res->start + size - 1) <= end) | ||
554 | break; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * If we failed to find something suitable, ensure we fail. | ||
559 | */ | ||
560 | if (m == data->map) | ||
561 | res->start = res->end; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * Adjust an existing IO region allocation, but making sure that we don't | ||
566 | * encroach outside the resources which the user supplied. | ||
567 | */ | ||
568 | static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start, | ||
569 | unsigned long r_end, struct pcmcia_socket *s) | ||
570 | { | ||
571 | struct resource_map *m; | ||
572 | struct socket_data *s_data = s->resource_data; | ||
573 | int ret = -ENOMEM; | ||
574 | |||
575 | down(&rsrc_sem); | ||
576 | for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) { | ||
577 | unsigned long start = m->base; | ||
578 | unsigned long end = m->base + m->num - 1; | ||
579 | |||
580 | if (start > r_start || r_end > end) | ||
581 | continue; | ||
582 | |||
583 | ret = adjust_resource(res, r_start, r_end - r_start + 1); | ||
584 | break; | ||
585 | } | ||
586 | up(&rsrc_sem); | ||
587 | |||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | /*====================================================================== | ||
592 | |||
593 | These find ranges of I/O ports or memory addresses that are not | ||
594 | currently allocated by other devices. | ||
595 | |||
596 | The 'align' field should reflect the number of bits of address | ||
597 | that need to be preserved from the initial value of *base. It | ||
598 | should be a power of two, greater than or equal to 'num'. A value | ||
599 | of 0 means that all bits of *base are significant. *base should | ||
600 | also be strictly less than 'align'. | ||
601 | |||
602 | ======================================================================*/ | ||
603 | |||
604 | struct resource *nonstatic_find_io_region(unsigned long base, int num, | ||
605 | unsigned long align, struct pcmcia_socket *s) | ||
606 | { | ||
607 | struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); | ||
608 | struct socket_data *s_data = s->resource_data; | ||
609 | struct pcmcia_align_data data; | ||
610 | unsigned long min = base; | ||
611 | int ret; | ||
612 | |||
613 | if (align == 0) | ||
614 | align = 0x10000; | ||
615 | |||
616 | data.mask = align - 1; | ||
617 | data.offset = base & data.mask; | ||
618 | data.map = &s_data->io_db; | ||
619 | |||
620 | down(&rsrc_sem); | ||
621 | #ifdef CONFIG_PCI | ||
622 | if (s->cb_dev) { | ||
623 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, | ||
624 | min, 0, pcmcia_align, &data); | ||
625 | } else | ||
626 | #endif | ||
627 | ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, | ||
628 | 1, pcmcia_align, &data); | ||
629 | up(&rsrc_sem); | ||
630 | |||
631 | if (ret != 0) { | ||
632 | kfree(res); | ||
633 | res = NULL; | ||
634 | } | ||
635 | return res; | ||
636 | } | ||
637 | |||
638 | struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, | ||
639 | int low, struct pcmcia_socket *s) | ||
640 | { | ||
641 | struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); | ||
642 | struct socket_data *s_data = s->resource_data; | ||
643 | struct pcmcia_align_data data; | ||
644 | unsigned long min, max; | ||
645 | int ret, i; | ||
646 | |||
647 | low = low || !(s->features & SS_CAP_PAGE_REGS); | ||
648 | |||
649 | data.mask = align - 1; | ||
650 | data.offset = base & data.mask; | ||
651 | data.map = &s_data->mem_db; | ||
652 | |||
653 | for (i = 0; i < 2; i++) { | ||
654 | if (low) { | ||
655 | max = 0x100000UL; | ||
656 | min = base < max ? base : 0; | ||
657 | } else { | ||
658 | max = ~0UL; | ||
659 | min = 0x100000UL + base; | ||
660 | } | ||
661 | |||
662 | down(&rsrc_sem); | ||
663 | #ifdef CONFIG_PCI | ||
664 | if (s->cb_dev) { | ||
665 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, | ||
666 | 1, min, 0, | ||
667 | pcmcia_align, &data); | ||
668 | } else | ||
669 | #endif | ||
670 | ret = allocate_resource(&iomem_resource, res, num, min, | ||
671 | max, 1, pcmcia_align, &data); | ||
672 | up(&rsrc_sem); | ||
673 | if (ret == 0 || low) | ||
674 | break; | ||
675 | low = 1; | ||
676 | } | ||
677 | |||
678 | if (ret != 0) { | ||
679 | kfree(res); | ||
680 | res = NULL; | ||
681 | } | ||
682 | return res; | ||
683 | } | ||
684 | |||
685 | |||
686 | static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) | ||
687 | { | ||
688 | u_long base, num; | ||
689 | struct socket_data *data = s->resource_data; | ||
690 | int ret; | ||
691 | |||
692 | base = adj->resource.memory.Base; | ||
693 | num = adj->resource.memory.Size; | ||
694 | if ((num == 0) || (base+num-1 < base)) | ||
695 | return CS_BAD_SIZE; | ||
696 | |||
697 | ret = CS_SUCCESS; | ||
698 | |||
699 | down(&rsrc_sem); | ||
700 | switch (adj->Action) { | ||
701 | case ADD_MANAGED_RESOURCE: | ||
702 | ret = add_interval(&data->mem_db, base, num); | ||
703 | break; | ||
704 | case REMOVE_MANAGED_RESOURCE: | ||
705 | ret = sub_interval(&data->mem_db, base, num); | ||
706 | if (ret == CS_SUCCESS) { | ||
707 | struct pcmcia_socket *socket; | ||
708 | down_read(&pcmcia_socket_list_rwsem); | ||
709 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) | ||
710 | release_cis_mem(socket); | ||
711 | up_read(&pcmcia_socket_list_rwsem); | ||
712 | } | ||
713 | break; | ||
714 | default: | ||
715 | ret = CS_UNSUPPORTED_FUNCTION; | ||
716 | } | ||
717 | up(&rsrc_sem); | ||
718 | |||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | |||
723 | static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) | ||
724 | { | ||
725 | struct socket_data *data = s->resource_data; | ||
726 | kio_addr_t base, num; | ||
727 | int ret = CS_SUCCESS; | ||
728 | |||
729 | base = adj->resource.io.BasePort; | ||
730 | num = adj->resource.io.NumPorts; | ||
731 | if ((base < 0) || (base > 0xffff)) | ||
732 | return CS_BAD_BASE; | ||
733 | if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) | ||
734 | return CS_BAD_SIZE; | ||
735 | |||
736 | down(&rsrc_sem); | ||
737 | switch (adj->Action) { | ||
738 | case ADD_MANAGED_RESOURCE: | ||
739 | if (add_interval(&data->io_db, base, num) != 0) { | ||
740 | ret = CS_IN_USE; | ||
741 | break; | ||
742 | } | ||
743 | #ifdef CONFIG_PCMCIA_PROBE | ||
744 | if (probe_io) | ||
745 | do_io_probe(s, base, num); | ||
746 | #endif | ||
747 | break; | ||
748 | case REMOVE_MANAGED_RESOURCE: | ||
749 | sub_interval(&data->io_db, base, num); | ||
750 | break; | ||
751 | default: | ||
752 | ret = CS_UNSUPPORTED_FUNCTION; | ||
753 | break; | ||
754 | } | ||
755 | up(&rsrc_sem); | ||
756 | |||
757 | return ret; | ||
758 | } | ||
759 | |||
760 | |||
761 | static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) | ||
762 | { | ||
763 | switch (adj->Resource) { | ||
764 | case RES_MEMORY_RANGE: | ||
765 | return adjust_memory(s, adj); | ||
766 | case RES_IO_RANGE: | ||
767 | return adjust_io(s, adj); | ||
768 | } | ||
769 | return CS_UNSUPPORTED_FUNCTION; | ||
770 | } | ||
771 | |||
772 | static int nonstatic_init(struct pcmcia_socket *s) | ||
773 | { | ||
774 | struct socket_data *data; | ||
775 | |||
776 | data = kmalloc(sizeof(struct socket_data), GFP_KERNEL); | ||
777 | if (!data) | ||
778 | return -ENOMEM; | ||
779 | memset(data, 0, sizeof(struct socket_data)); | ||
780 | |||
781 | data->mem_db.next = &data->mem_db; | ||
782 | data->io_db.next = &data->io_db; | ||
783 | |||
784 | s->resource_data = (void *) data; | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static void nonstatic_release_resource_db(struct pcmcia_socket *s) | ||
790 | { | ||
791 | struct socket_data *data = s->resource_data; | ||
792 | struct resource_map *p, *q; | ||
793 | |||
794 | down(&rsrc_sem); | ||
795 | for (p = data->mem_db.next; p != &data->mem_db; p = q) { | ||
796 | q = p->next; | ||
797 | kfree(p); | ||
798 | } | ||
799 | for (p = data->io_db.next; p != &data->io_db; p = q) { | ||
800 | q = p->next; | ||
801 | kfree(p); | ||
802 | } | ||
803 | up(&rsrc_sem); | ||
804 | } | ||
805 | |||
806 | |||
807 | struct pccard_resource_ops pccard_nonstatic_ops = { | ||
808 | .validate_mem = pcmcia_nonstatic_validate_mem, | ||
809 | .adjust_io_region = nonstatic_adjust_io_region, | ||
810 | .find_io = nonstatic_find_io_region, | ||
811 | .find_mem = nonstatic_find_mem_region, | ||
812 | .adjust_resource = nonstatic_adjust_resource_info, | ||
813 | .init = nonstatic_init, | ||
814 | .exit = nonstatic_release_resource_db, | ||
815 | }; | ||
816 | EXPORT_SYMBOL(pccard_nonstatic_ops); | ||
817 | |||
818 | |||
819 | /* sysfs interface to the resource database */ | ||
820 | |||
821 | static ssize_t show_io_db(struct class_device *class_dev, char *buf) | ||
822 | { | ||
823 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
824 | struct socket_data *data; | ||
825 | struct resource_map *p; | ||
826 | ssize_t ret = 0; | ||
827 | |||
828 | down(&rsrc_sem); | ||
829 | data = s->resource_data; | ||
830 | |||
831 | for (p = data->io_db.next; p != &data->io_db; p = p->next) { | ||
832 | if (ret > (PAGE_SIZE - 10)) | ||
833 | continue; | ||
834 | ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1), | ||
835 | "0x%08lx - 0x%08lx\n", | ||
836 | ((unsigned long) p->base), | ||
837 | ((unsigned long) p->base + p->num - 1)); | ||
838 | } | ||
839 | |||
840 | up(&rsrc_sem); | ||
841 | return (ret); | ||
842 | } | ||
843 | |||
844 | static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count) | ||
845 | { | ||
846 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
847 | unsigned long start_addr, end_addr; | ||
848 | unsigned int add = 1; | ||
849 | adjust_t adj; | ||
850 | ssize_t ret = 0; | ||
851 | |||
852 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); | ||
853 | if (ret != 2) { | ||
854 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); | ||
855 | add = 0; | ||
856 | if (ret != 2) { | ||
857 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); | ||
858 | add = 1; | ||
859 | if (ret != 2) | ||
860 | return -EINVAL; | ||
861 | } | ||
862 | } | ||
863 | if (end_addr <= start_addr) | ||
864 | return -EINVAL; | ||
865 | |||
866 | adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; | ||
867 | adj.Resource = RES_IO_RANGE; | ||
868 | adj.resource.io.BasePort = start_addr; | ||
869 | adj.resource.io.NumPorts = end_addr - start_addr + 1; | ||
870 | |||
871 | ret = adjust_io(s, &adj); | ||
872 | |||
873 | return ret ? ret : count; | ||
874 | } | ||
875 | static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); | ||
876 | |||
877 | static ssize_t show_mem_db(struct class_device *class_dev, char *buf) | ||
878 | { | ||
879 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
880 | struct socket_data *data; | ||
881 | struct resource_map *p; | ||
882 | ssize_t ret = 0; | ||
883 | |||
884 | down(&rsrc_sem); | ||
885 | data = s->resource_data; | ||
886 | |||
887 | for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { | ||
888 | if (ret > (PAGE_SIZE - 10)) | ||
889 | continue; | ||
890 | ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1), | ||
891 | "0x%08lx - 0x%08lx\n", | ||
892 | ((unsigned long) p->base), | ||
893 | ((unsigned long) p->base + p->num - 1)); | ||
894 | } | ||
895 | |||
896 | up(&rsrc_sem); | ||
897 | return (ret); | ||
898 | } | ||
899 | |||
900 | static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count) | ||
901 | { | ||
902 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
903 | unsigned long start_addr, end_addr; | ||
904 | unsigned int add = 1; | ||
905 | adjust_t adj; | ||
906 | ssize_t ret = 0; | ||
907 | |||
908 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); | ||
909 | if (ret != 2) { | ||
910 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); | ||
911 | add = 0; | ||
912 | if (ret != 2) { | ||
913 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); | ||
914 | add = 1; | ||
915 | if (ret != 2) | ||
916 | return -EINVAL; | ||
917 | } | ||
918 | } | ||
919 | if (end_addr <= start_addr) | ||
920 | return -EINVAL; | ||
921 | |||
922 | adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; | ||
923 | adj.Resource = RES_MEMORY_RANGE; | ||
924 | adj.resource.memory.Base = start_addr; | ||
925 | adj.resource.memory.Size = end_addr - start_addr + 1; | ||
926 | |||
927 | ret = adjust_memory(s, &adj); | ||
928 | |||
929 | return ret ? ret : count; | ||
930 | } | ||
931 | static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); | ||
932 | |||
933 | static struct class_device_attribute *pccard_rsrc_attributes[] = { | ||
934 | &class_device_attr_available_resources_io, | ||
935 | &class_device_attr_available_resources_mem, | ||
936 | NULL, | ||
937 | }; | ||
938 | |||
939 | static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) | ||
940 | { | ||
941 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
942 | struct class_device_attribute **attr; | ||
943 | int ret = 0; | ||
944 | if (s->resource_ops != &pccard_nonstatic_ops) | ||
945 | return 0; | ||
946 | |||
947 | for (attr = pccard_rsrc_attributes; *attr; attr++) { | ||
948 | ret = class_device_create_file(class_dev, *attr); | ||
949 | if (ret) | ||
950 | break; | ||
951 | } | ||
952 | |||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev) | ||
957 | { | ||
958 | struct pcmcia_socket *s = class_get_devdata(class_dev); | ||
959 | struct class_device_attribute **attr; | ||
960 | |||
961 | if (s->resource_ops != &pccard_nonstatic_ops) | ||
962 | return; | ||
963 | |||
964 | for (attr = pccard_rsrc_attributes; *attr; attr++) | ||
965 | class_device_remove_file(class_dev, *attr); | ||
966 | } | ||
967 | |||
968 | static struct class_interface pccard_rsrc_interface = { | ||
969 | .class = &pcmcia_socket_class, | ||
970 | .add = &pccard_sysfs_add_rsrc, | ||
971 | .remove = __devexit_p(&pccard_sysfs_remove_rsrc), | ||
972 | }; | ||
973 | |||
974 | static int __init nonstatic_sysfs_init(void) | ||
975 | { | ||
976 | return class_interface_register(&pccard_rsrc_interface); | ||
977 | } | ||
978 | |||
979 | static void __exit nonstatic_sysfs_exit(void) | ||
980 | { | ||
981 | class_interface_unregister(&pccard_rsrc_interface); | ||
982 | } | ||
983 | |||
984 | module_init(nonstatic_sysfs_init); | ||
985 | module_exit(nonstatic_sysfs_exit); | ||
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c new file mode 100644 index 000000000000..7c57fdd3c8d7 --- /dev/null +++ b/drivers/pcmcia/sa1100_assabet.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_assabet.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for Assabet | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/errno.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/hardware.h> | ||
15 | #include <asm/mach-types.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include <asm/signal.h> | ||
18 | #include <asm/arch/assabet.h> | ||
19 | |||
20 | #include "sa1100_generic.h" | ||
21 | |||
22 | static struct pcmcia_irqs irqs[] = { | ||
23 | { 1, ASSABET_IRQ_GPIO_CF_CD, "CF CD" }, | ||
24 | { 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" }, | ||
25 | { 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" }, | ||
26 | }; | ||
27 | |||
28 | static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
29 | { | ||
30 | skt->irq = ASSABET_IRQ_GPIO_CF_IRQ; | ||
31 | |||
32 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * Release all resources. | ||
37 | */ | ||
38 | static void assabet_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
39 | { | ||
40 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
41 | } | ||
42 | |||
43 | static void | ||
44 | assabet_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | ||
45 | { | ||
46 | unsigned long levels = GPLR; | ||
47 | |||
48 | state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; | ||
49 | state->ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; | ||
50 | state->bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; | ||
51 | state->bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; | ||
52 | state->wrprot = 0; /* Not available on Assabet. */ | ||
53 | state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ | ||
54 | state->vs_Xv = 0; | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
59 | { | ||
60 | unsigned int mask; | ||
61 | |||
62 | switch (state->Vcc) { | ||
63 | case 0: | ||
64 | mask = 0; | ||
65 | break; | ||
66 | |||
67 | case 50: | ||
68 | printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", | ||
69 | __FUNCTION__); | ||
70 | |||
71 | case 33: /* Can only apply 3.3V to the CF slot. */ | ||
72 | mask = ASSABET_BCR_CF_PWR; | ||
73 | break; | ||
74 | |||
75 | default: | ||
76 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, | ||
77 | state->Vcc); | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | /* Silently ignore Vpp, output enable, speaker enable. */ | ||
82 | |||
83 | if (state->flags & SS_RESET) | ||
84 | mask |= ASSABET_BCR_CF_RST; | ||
85 | |||
86 | ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Enable card status IRQs on (re-)initialisation. This can | ||
93 | * be called at initialisation, power management event, or | ||
94 | * pcmcia event. | ||
95 | */ | ||
96 | static void assabet_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
97 | { | ||
98 | /* | ||
99 | * Enable CF bus | ||
100 | */ | ||
101 | ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); | ||
102 | |||
103 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Disable card status IRQs on suspend. | ||
108 | */ | ||
109 | static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
110 | { | ||
111 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
112 | |||
113 | /* | ||
114 | * Tristate the CF bus signals. Also assert CF | ||
115 | * reset as per user guide page 4-11. | ||
116 | */ | ||
117 | ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST); | ||
118 | } | ||
119 | |||
120 | static struct pcmcia_low_level assabet_pcmcia_ops = { | ||
121 | .owner = THIS_MODULE, | ||
122 | |||
123 | .hw_init = assabet_pcmcia_hw_init, | ||
124 | .hw_shutdown = assabet_pcmcia_hw_shutdown, | ||
125 | |||
126 | .socket_state = assabet_pcmcia_socket_state, | ||
127 | .configure_socket = assabet_pcmcia_configure_socket, | ||
128 | |||
129 | .socket_init = assabet_pcmcia_socket_init, | ||
130 | .socket_suspend = assabet_pcmcia_socket_suspend, | ||
131 | }; | ||
132 | |||
133 | int __init pcmcia_assabet_init(struct device *dev) | ||
134 | { | ||
135 | int ret = -ENODEV; | ||
136 | |||
137 | if (machine_is_assabet() && !machine_has_neponset()) | ||
138 | ret = sa11xx_drv_pcmcia_probe(dev, &assabet_pcmcia_ops, 1, 1); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c new file mode 100644 index 000000000000..c6b262b653d3 --- /dev/null +++ b/drivers/pcmcia/sa1100_badge4.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/sa1100_badge4.c | ||
3 | * | ||
4 | * BadgePAD 4 PCMCIA specific routines | ||
5 | * | ||
6 | * Christopher Hoover <ch@hpl.hp.com> | ||
7 | * | ||
8 | * Copyright (C) 2002 Hewlett-Packard Company | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #include <asm/hardware.h> | ||
23 | #include <asm/mach-types.h> | ||
24 | #include <asm/arch/badge4.h> | ||
25 | #include <asm/hardware/sa1111.h> | ||
26 | |||
27 | #include "sa1111_generic.h" | ||
28 | |||
29 | /* | ||
30 | * BadgePAD 4 Details | ||
31 | * | ||
32 | * PCM Vcc: | ||
33 | * | ||
34 | * PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3 | ||
35 | * on JP6) or 5v0 (short pins 3 and 5 on JP6). | ||
36 | * | ||
37 | * PCM Vpp: | ||
38 | * | ||
39 | * PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6 | ||
40 | * on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6). N.B., | ||
41 | * 12v0 operation requires that the power supply actually supply 12v0 | ||
42 | * via pin 7 of JP7. | ||
43 | * | ||
44 | * CF Vcc: | ||
45 | * | ||
46 | * CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1 | ||
47 | * and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10). | ||
48 | * | ||
49 | * Unfortunately there's no way programmatically to determine how a | ||
50 | * given board is jumpered. This code assumes a default jumpering | ||
51 | * as described below. | ||
52 | * | ||
53 | * If the defaults aren't correct, you may override them with a pcmv | ||
54 | * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>. The units are | ||
55 | * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0 | ||
56 | * PCM Vpp, and 5v0 CF Vcc. | ||
57 | * | ||
58 | */ | ||
59 | |||
60 | static int badge4_pcmvcc = 50; /* pins 3 and 5 jumpered on JP6 */ | ||
61 | static int badge4_pcmvpp = 50; /* pins 2 and 4 jumpered on JP6 */ | ||
62 | static int badge4_cfvcc = 33; /* pins 1 and 2 jumpered on JP10 */ | ||
63 | |||
64 | static void complain_about_jumpering(const char *whom, | ||
65 | const char *supply, | ||
66 | int given, int wanted) | ||
67 | { | ||
68 | printk(KERN_ERR | ||
69 | "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation" | ||
70 | "; re-jumper the board and/or use pcmv=xx,xx,xx\n", | ||
71 | whom, supply, | ||
72 | wanted / 10, wanted % 10, | ||
73 | supply, | ||
74 | given / 10, given % 10); | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
79 | { | ||
80 | int ret; | ||
81 | |||
82 | switch (skt->nr) { | ||
83 | case 0: | ||
84 | if ((state->Vcc != 0) && | ||
85 | (state->Vcc != badge4_pcmvcc)) { | ||
86 | complain_about_jumpering(__FUNCTION__, "pcmvcc", | ||
87 | badge4_pcmvcc, state->Vcc); | ||
88 | // Apply power regardless of the jumpering. | ||
89 | // return -1; | ||
90 | } | ||
91 | if ((state->Vpp != 0) && | ||
92 | (state->Vpp != badge4_pcmvpp)) { | ||
93 | complain_about_jumpering(__FUNCTION__, "pcmvpp", | ||
94 | badge4_pcmvpp, state->Vpp); | ||
95 | return -1; | ||
96 | } | ||
97 | break; | ||
98 | |||
99 | case 1: | ||
100 | if ((state->Vcc != 0) && | ||
101 | (state->Vcc != badge4_cfvcc)) { | ||
102 | complain_about_jumpering(__FUNCTION__, "cfvcc", | ||
103 | badge4_cfvcc, state->Vcc); | ||
104 | return -1; | ||
105 | } | ||
106 | break; | ||
107 | |||
108 | default: | ||
109 | return -1; | ||
110 | } | ||
111 | |||
112 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
113 | if (ret == 0) { | ||
114 | unsigned long flags; | ||
115 | int need5V; | ||
116 | |||
117 | local_irq_save(flags); | ||
118 | |||
119 | need5V = ((state->Vcc == 50) || (state->Vpp == 50)); | ||
120 | |||
121 | badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V); | ||
122 | |||
123 | local_irq_restore(flags); | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct pcmcia_low_level badge4_pcmcia_ops = { | ||
130 | .owner = THIS_MODULE, | ||
131 | .init = sa1111_pcmcia_hw_init, | ||
132 | .shutdown = sa1111_pcmcia_hw_shutdown, | ||
133 | .socket_state = sa1111_pcmcia_socket_state, | ||
134 | .configure_socket = badge4_pcmcia_configure_socket, | ||
135 | |||
136 | .socket_init = sa1111_pcmcia_socket_init, | ||
137 | .socket_suspend = sa1111_pcmcia_socket_suspend, | ||
138 | }; | ||
139 | |||
140 | int pcmcia_badge4_init(struct device *dev) | ||
141 | { | ||
142 | int ret = -ENODEV; | ||
143 | |||
144 | if (machine_is_badge4()) { | ||
145 | printk(KERN_INFO | ||
146 | "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", | ||
147 | __FUNCTION__, | ||
148 | badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); | ||
149 | |||
150 | ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2); | ||
151 | } | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | static int __init pcmv_setup(char *s) | ||
157 | { | ||
158 | int v[4]; | ||
159 | |||
160 | s = get_options(s, ARRAY_SIZE(v), v); | ||
161 | |||
162 | if (v[0] >= 1) badge4_pcmvcc = v[1]; | ||
163 | if (v[0] >= 2) badge4_pcmvpp = v[2]; | ||
164 | if (v[0] >= 3) badge4_cfvcc = v[3]; | ||
165 | |||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | __setup("pcmv=", pcmv_setup); | ||
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c new file mode 100644 index 000000000000..2b3c2895b43d --- /dev/null +++ b/drivers/pcmcia/sa1100_cerf.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_cerf.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for CerfBoard | ||
5 | * Based off the Assabet. | ||
6 | * | ||
7 | */ | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/delay.h> | ||
15 | |||
16 | #include <asm/hardware.h> | ||
17 | #include <asm/mach-types.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/arch/cerf.h> | ||
20 | #include "sa1100_generic.h" | ||
21 | |||
22 | #define CERF_SOCKET 1 | ||
23 | |||
24 | static struct pcmcia_irqs irqs[] = { | ||
25 | { CERF_SOCKET, CERF_IRQ_GPIO_CF_CD, "CF_CD" }, | ||
26 | { CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD2, "CF_BVD2" }, | ||
27 | { CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD1, "CF_BVD1" } | ||
28 | }; | ||
29 | |||
30 | static int cerf_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
31 | { | ||
32 | skt->irq = CERF_IRQ_GPIO_CF_IRQ; | ||
33 | |||
34 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
35 | } | ||
36 | |||
37 | static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
38 | { | ||
39 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | cerf_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | ||
44 | { | ||
45 | unsigned long levels = GPLR; | ||
46 | |||
47 | state->detect = (levels & CERF_GPIO_CF_CD) ?0:1; | ||
48 | state->ready = (levels & CERF_GPIO_CF_IRQ) ?1:0; | ||
49 | state->bvd1 = (levels & CERF_GPIO_CF_BVD1)?1:0; | ||
50 | state->bvd2 = (levels & CERF_GPIO_CF_BVD2)?1:0; | ||
51 | state->wrprot = 0; | ||
52 | state->vs_3v = 1; | ||
53 | state->vs_Xv = 0; | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
58 | const socket_state_t *state) | ||
59 | { | ||
60 | switch (state->Vcc) { | ||
61 | case 0: | ||
62 | case 50: | ||
63 | case 33: | ||
64 | break; | ||
65 | |||
66 | default: | ||
67 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
68 | __FUNCTION__, state->Vcc); | ||
69 | return -1; | ||
70 | } | ||
71 | |||
72 | if (state->flags & SS_RESET) { | ||
73 | GPSR = CERF_GPIO_CF_RESET; | ||
74 | } else { | ||
75 | GPCR = CERF_GPIO_CF_RESET; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static void cerf_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
82 | { | ||
83 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
84 | } | ||
85 | |||
86 | static void cerf_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
87 | { | ||
88 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
89 | } | ||
90 | |||
91 | static struct pcmcia_low_level cerf_pcmcia_ops = { | ||
92 | .owner = THIS_MODULE, | ||
93 | .hw_init = cerf_pcmcia_hw_init, | ||
94 | .hw_shutdown = cerf_pcmcia_hw_shutdown, | ||
95 | .socket_state = cerf_pcmcia_socket_state, | ||
96 | .configure_socket = cerf_pcmcia_configure_socket, | ||
97 | |||
98 | .socket_init = cerf_pcmcia_socket_init, | ||
99 | .socket_suspend = cerf_pcmcia_socket_suspend, | ||
100 | }; | ||
101 | |||
102 | int __init pcmcia_cerf_init(struct device *dev) | ||
103 | { | ||
104 | int ret = -ENODEV; | ||
105 | |||
106 | if (machine_is_cerf()) | ||
107 | ret = sa11xx_drv_pcmcia_probe(dev, &cerf_pcmcia_ops, CERF_SOCKET, 1); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c new file mode 100644 index 000000000000..874990ebe147 --- /dev/null +++ b/drivers/pcmcia/sa1100_generic.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for the PCMCIA control functionality of StrongARM | ||
4 | SA-1100 microprocessors. | ||
5 | |||
6 | The contents of this file are subject to the Mozilla Public | ||
7 | License Version 1.1 (the "License"); you may not use this file | ||
8 | except in compliance with the License. You may obtain a copy of | ||
9 | the License at http://www.mozilla.org/MPL/ | ||
10 | |||
11 | Software distributed under the License is distributed on an "AS | ||
12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
13 | implied. See the License for the specific language governing | ||
14 | rights and limitations under the License. | ||
15 | |||
16 | The initial developer of the original code is John G. Dorsey | ||
17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | ||
18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | ||
19 | |||
20 | Alternatively, the contents of this file may be used under the | ||
21 | terms of the GNU Public License version 2 (the "GPL"), in which | ||
22 | case the provisions of the GPL are applicable instead of the | ||
23 | above. If you wish to allow the use of your version of this file | ||
24 | only under the terms of the GPL and not to allow others to use | ||
25 | your version of this file under the MPL, indicate your decision | ||
26 | by deleting the provisions above and replace them with the notice | ||
27 | and other provisions required by the GPL. If you do not delete | ||
28 | the provisions above, a recipient may use your version of this | ||
29 | file under either the MPL or the GPL. | ||
30 | |||
31 | ======================================================================*/ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/config.h> | ||
36 | |||
37 | #include <pcmcia/version.h> | ||
38 | #include <pcmcia/cs_types.h> | ||
39 | #include <pcmcia/cs.h> | ||
40 | #include <pcmcia/ss.h> | ||
41 | |||
42 | #include "sa1100_generic.h" | ||
43 | |||
44 | static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { | ||
45 | #ifdef CONFIG_SA1100_ASSABET | ||
46 | pcmcia_assabet_init, | ||
47 | #endif | ||
48 | #ifdef CONFIG_SA1100_CERF | ||
49 | pcmcia_cerf_init, | ||
50 | #endif | ||
51 | #ifdef CONFIG_SA1100_H3600 | ||
52 | pcmcia_h3600_init, | ||
53 | #endif | ||
54 | #ifdef CONFIG_SA1100_SHANNON | ||
55 | pcmcia_shannon_init, | ||
56 | #endif | ||
57 | #ifdef CONFIG_SA1100_SIMPAD | ||
58 | pcmcia_simpad_init, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
62 | static int sa11x0_drv_pcmcia_probe(struct device *dev) | ||
63 | { | ||
64 | int i, ret = -ENODEV; | ||
65 | |||
66 | /* | ||
67 | * Initialise any "on-board" PCMCIA sockets. | ||
68 | */ | ||
69 | for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { | ||
70 | ret = sa11x0_pcmcia_hw_init[i](dev); | ||
71 | if (ret == 0) | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static int sa11x0_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level) | ||
79 | { | ||
80 | int ret = 0; | ||
81 | if (level == SUSPEND_SAVE_STATE) | ||
82 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) | ||
87 | { | ||
88 | int ret = 0; | ||
89 | if (level == RESUME_RESTORE_STATE) | ||
90 | ret = pcmcia_socket_dev_resume(dev); | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static struct device_driver sa11x0_pcmcia_driver = { | ||
95 | .probe = sa11x0_drv_pcmcia_probe, | ||
96 | .remove = soc_common_drv_pcmcia_remove, | ||
97 | .name = "sa11x0-pcmcia", | ||
98 | .bus = &platform_bus_type, | ||
99 | .suspend = sa11x0_drv_pcmcia_suspend, | ||
100 | .resume = sa11x0_drv_pcmcia_resume, | ||
101 | }; | ||
102 | |||
103 | /* sa11x0_pcmcia_init() | ||
104 | * ^^^^^^^^^^^^^^^^^^^^ | ||
105 | * | ||
106 | * This routine performs low-level PCMCIA initialization and then | ||
107 | * registers this socket driver with Card Services. | ||
108 | * | ||
109 | * Returns: 0 on success, -ve error code on failure | ||
110 | */ | ||
111 | static int __init sa11x0_pcmcia_init(void) | ||
112 | { | ||
113 | return driver_register(&sa11x0_pcmcia_driver); | ||
114 | } | ||
115 | |||
116 | /* sa11x0_pcmcia_exit() | ||
117 | * ^^^^^^^^^^^^^^^^^^^^ | ||
118 | * Invokes the low-level kernel service to free IRQs associated with this | ||
119 | * socket controller and reset GPIO edge detection. | ||
120 | */ | ||
121 | static void __exit sa11x0_pcmcia_exit(void) | ||
122 | { | ||
123 | driver_unregister(&sa11x0_pcmcia_driver); | ||
124 | } | ||
125 | |||
126 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); | ||
127 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); | ||
128 | MODULE_LICENSE("Dual MPL/GPL"); | ||
129 | |||
130 | module_init(sa11x0_pcmcia_init); | ||
131 | module_exit(sa11x0_pcmcia_exit); | ||
diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h new file mode 100644 index 000000000000..794f96a35bba --- /dev/null +++ b/drivers/pcmcia/sa1100_generic.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #include "soc_common.h" | ||
2 | #include "sa11xx_base.h" | ||
3 | |||
4 | /* | ||
5 | * Declaration for all machine specific init/exit functions. | ||
6 | */ | ||
7 | extern int pcmcia_adsbitsy_init(struct device *); | ||
8 | extern int pcmcia_assabet_init(struct device *); | ||
9 | extern int pcmcia_badge4_init(struct device *); | ||
10 | extern int pcmcia_cerf_init(struct device *); | ||
11 | extern int pcmcia_flexanet_init(struct device *); | ||
12 | extern int pcmcia_freebird_init(struct device *); | ||
13 | extern int pcmcia_gcplus_init(struct device *); | ||
14 | extern int pcmcia_graphicsmaster_init(struct device *); | ||
15 | extern int pcmcia_h3600_init(struct device *); | ||
16 | extern int pcmcia_pangolin_init(struct device *); | ||
17 | extern int pcmcia_pfs168_init(struct device *); | ||
18 | extern int pcmcia_shannon_init(struct device *); | ||
19 | extern int pcmcia_simpad_init(struct device *); | ||
20 | extern int pcmcia_stork_init(struct device *); | ||
21 | extern int pcmcia_system3_init(struct device *); | ||
22 | extern int pcmcia_trizeps_init(struct device *); | ||
23 | extern int pcmcia_xp860_init(struct device *); | ||
24 | extern int pcmcia_yopy_init(struct device *); | ||
diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c new file mode 100644 index 000000000000..64fd5e37f2d2 --- /dev/null +++ b/drivers/pcmcia/sa1100_h3600.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_h3600.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for H3600 | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/delay.h> | ||
14 | |||
15 | #include <asm/hardware.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include <asm/mach-types.h> | ||
18 | #include <asm/arch/h3600.h> | ||
19 | |||
20 | #include "sa1100_generic.h" | ||
21 | |||
22 | static struct pcmcia_irqs irqs[] = { | ||
23 | { 0, IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, | ||
24 | { 1, IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } | ||
25 | }; | ||
26 | |||
27 | static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
28 | { | ||
29 | skt->irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1 | ||
30 | : IRQ_GPIO_H3600_PCMCIA_IRQ0; | ||
31 | |||
32 | |||
33 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
34 | } | ||
35 | |||
36 | static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
37 | { | ||
38 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
39 | |||
40 | /* Disable CF bus: */ | ||
41 | clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); | ||
42 | clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); | ||
43 | set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); | ||
44 | } | ||
45 | |||
46 | static void | ||
47 | h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | ||
48 | { | ||
49 | unsigned long levels = GPLR; | ||
50 | |||
51 | switch (skt->nr) { | ||
52 | case 0: | ||
53 | state->detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1; | ||
54 | state->ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0; | ||
55 | state->bvd1 = 0; | ||
56 | state->bvd2 = 0; | ||
57 | state->wrprot = 0; /* Not available on H3600. */ | ||
58 | state->vs_3v = 0; | ||
59 | state->vs_Xv = 0; | ||
60 | break; | ||
61 | |||
62 | case 1: | ||
63 | state->detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1; | ||
64 | state->ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0; | ||
65 | state->bvd1 = 0; | ||
66 | state->bvd2 = 0; | ||
67 | state->wrprot = 0; /* Not available on H3600. */ | ||
68 | state->vs_3v = 0; | ||
69 | state->vs_Xv = 0; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
76 | { | ||
77 | if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) { | ||
78 | printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", | ||
79 | state->Vcc / 10, state->Vcc % 10); | ||
80 | return -1; | ||
81 | } | ||
82 | |||
83 | if (state->flags & SS_RESET) | ||
84 | set_h3600_egpio(IPAQ_EGPIO_CARD_RESET); | ||
85 | else | ||
86 | clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); | ||
87 | |||
88 | /* Silently ignore Vpp, output enable, speaker enable. */ | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
94 | { | ||
95 | /* Enable CF bus: */ | ||
96 | set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); | ||
97 | set_h3600_egpio(IPAQ_EGPIO_OPT_ON); | ||
98 | clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); | ||
99 | |||
100 | msleep(10); | ||
101 | |||
102 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
103 | } | ||
104 | |||
105 | static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
106 | { | ||
107 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
108 | |||
109 | /* | ||
110 | * FIXME: This doesn't fit well. We don't have the mechanism in | ||
111 | * the generic PCMCIA layer to deal with the idea of two sockets | ||
112 | * on one bus. We rely on the cs.c behaviour shutting down | ||
113 | * socket 0 then socket 1. | ||
114 | */ | ||
115 | if (skt->nr == 1) { | ||
116 | clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); | ||
117 | clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); | ||
118 | /* hmm, does this suck power? */ | ||
119 | set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | struct pcmcia_low_level h3600_pcmcia_ops = { | ||
124 | .owner = THIS_MODULE, | ||
125 | .hw_init = h3600_pcmcia_hw_init, | ||
126 | .hw_shutdown = h3600_pcmcia_hw_shutdown, | ||
127 | .socket_state = h3600_pcmcia_socket_state, | ||
128 | .configure_socket = h3600_pcmcia_configure_socket, | ||
129 | |||
130 | .socket_init = h3600_pcmcia_socket_init, | ||
131 | .socket_suspend = h3600_pcmcia_socket_suspend, | ||
132 | }; | ||
133 | |||
134 | int __init pcmcia_h3600_init(struct device *dev) | ||
135 | { | ||
136 | int ret = -ENODEV; | ||
137 | |||
138 | if (machine_is_h3600()) | ||
139 | ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); | ||
140 | |||
141 | return ret; | ||
142 | } | ||
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c new file mode 100644 index 000000000000..0a387106acb0 --- /dev/null +++ b/drivers/pcmcia/sa1100_jornada720.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_jornada720.c | ||
3 | * | ||
4 | * Jornada720 PCMCIA specific routines | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/hardware.h> | ||
15 | #include <asm/hardware/sa1111.h> | ||
16 | #include <asm/mach-types.h> | ||
17 | |||
18 | #include "sa1111_generic.h" | ||
19 | |||
20 | #define SOCKET0_POWER GPIO_GPIO0 | ||
21 | #define SOCKET0_3V GPIO_GPIO2 | ||
22 | #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) | ||
23 | #warning *** Does SOCKET1_3V actually do anything? | ||
24 | #define SOCKET1_3V GPIO_GPIO3 | ||
25 | |||
26 | static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
27 | { | ||
28 | /* | ||
29 | * What is all this crap for? | ||
30 | */ | ||
31 | GRER |= 0x00000002; | ||
32 | /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ | ||
33 | PA_DDR = 0; | ||
34 | PA_DWR = 0; | ||
35 | PA_SDR = 0; | ||
36 | PA_SSR = 0; | ||
37 | |||
38 | PB_DDR = 0; | ||
39 | PB_DWR = 0x01; | ||
40 | PB_SDR = 0; | ||
41 | PB_SSR = 0; | ||
42 | |||
43 | PC_DDR = 0x88; | ||
44 | PC_DWR = 0x20; | ||
45 | PC_SDR = 0; | ||
46 | PC_SSR = 0; | ||
47 | |||
48 | return sa1111_pcmcia_hw_init(skt); | ||
49 | } | ||
50 | |||
51 | static int | ||
52 | jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
53 | { | ||
54 | unsigned int pa_dwr_mask, pa_dwr_set; | ||
55 | int ret; | ||
56 | |||
57 | printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, | ||
58 | skt->nr, state->Vcc, state->Vpp); | ||
59 | |||
60 | switch (skt->nr) { | ||
61 | case 0: | ||
62 | pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; | ||
63 | |||
64 | switch (state->Vcc) { | ||
65 | default: | ||
66 | case 0: pa_dwr_set = 0; break; | ||
67 | case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break; | ||
68 | case 50: pa_dwr_set = SOCKET0_POWER; break; | ||
69 | } | ||
70 | break; | ||
71 | |||
72 | case 1: | ||
73 | pa_dwr_mask = SOCKET1_POWER; | ||
74 | |||
75 | switch (state->Vcc) { | ||
76 | default: | ||
77 | case 0: pa_dwr_set = 0; break; | ||
78 | case 33: pa_dwr_set = SOCKET1_POWER; break; | ||
79 | case 50: pa_dwr_set = SOCKET1_POWER; break; | ||
80 | } | ||
81 | break; | ||
82 | |||
83 | default: | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
88 | printk(KERN_ERR "%s(): slot cannot support VPP %u\n", | ||
89 | __FUNCTION__, state->Vpp); | ||
90 | return -1; | ||
91 | } | ||
92 | |||
93 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
94 | if (ret == 0) { | ||
95 | unsigned long flags; | ||
96 | |||
97 | local_irq_save(flags); | ||
98 | PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; | ||
99 | local_irq_restore(flags); | ||
100 | } | ||
101 | |||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | static struct pcmcia_low_level jornada720_pcmcia_ops = { | ||
106 | .owner = THIS_MODULE, | ||
107 | .hw_init = jornada720_pcmcia_hw_init, | ||
108 | .hw_shutdown = sa1111_pcmcia_hw_shutdown, | ||
109 | .socket_state = sa1111_pcmcia_socket_state, | ||
110 | .configure_socket = jornada720_pcmcia_configure_socket, | ||
111 | |||
112 | .socket_init = sa1111_pcmcia_socket_init, | ||
113 | .socket_suspend = sa1111_pcmcia_socket_suspend, | ||
114 | }; | ||
115 | |||
116 | int __init pcmcia_jornada720_init(struct device *dev) | ||
117 | { | ||
118 | int ret = -ENODEV; | ||
119 | |||
120 | if (machine_is_jornada720()) | ||
121 | ret = sa11xx_drv_pcmcia_probe(dev, &jornada720_pcmcia_ops, 0, 2); | ||
122 | |||
123 | return ret; | ||
124 | } | ||
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c new file mode 100644 index 000000000000..5e34b3e8e5db --- /dev/null +++ b/drivers/pcmcia/sa1100_neponset.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/sa1100_neponset.c | ||
3 | * | ||
4 | * Neponset PCMCIA specific routines | ||
5 | */ | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/sched.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/hardware.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | #include <asm/arch/neponset.h> | ||
16 | #include <asm/hardware/sa1111.h> | ||
17 | |||
18 | #include "sa1111_generic.h" | ||
19 | |||
20 | /* | ||
21 | * Neponset uses the Maxim MAX1600, with the following connections: | ||
22 | * | ||
23 | * MAX1600 Neponset | ||
24 | * | ||
25 | * A0VCC SA-1111 GPIO A<1> | ||
26 | * A1VCC SA-1111 GPIO A<0> | ||
27 | * A0VPP CPLD NCR A0VPP | ||
28 | * A1VPP CPLD NCR A1VPP | ||
29 | * B0VCC SA-1111 GPIO A<2> | ||
30 | * B1VCC SA-1111 GPIO A<3> | ||
31 | * B0VPP ground (slot B is CF) | ||
32 | * B1VPP ground (slot B is CF) | ||
33 | * | ||
34 | * VX VCC (5V) | ||
35 | * VY VCC3_3 (3.3V) | ||
36 | * 12INA 12V | ||
37 | * 12INB ground (slot B is CF) | ||
38 | * | ||
39 | * The MAX1600 CODE pin is tied to ground, placing the device in | ||
40 | * "Standard Intel code" mode. Refer to the Maxim data sheet for | ||
41 | * the corresponding truth table. | ||
42 | */ | ||
43 | |||
44 | static int | ||
45 | neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
46 | { | ||
47 | unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; | ||
48 | int ret; | ||
49 | |||
50 | switch (skt->nr) { | ||
51 | case 0: | ||
52 | pa_dwr_mask = GPIO_A0 | GPIO_A1; | ||
53 | ncr_mask = NCR_A0VPP | NCR_A1VPP; | ||
54 | |||
55 | if (state->Vpp == 0) | ||
56 | ncr_set = 0; | ||
57 | else if (state->Vpp == 120) | ||
58 | ncr_set = NCR_A1VPP; | ||
59 | else if (state->Vpp == state->Vcc) | ||
60 | ncr_set = NCR_A0VPP; | ||
61 | else { | ||
62 | printk(KERN_ERR "%s(): unrecognized VPP %u\n", | ||
63 | __FUNCTION__, state->Vpp); | ||
64 | return -1; | ||
65 | } | ||
66 | break; | ||
67 | |||
68 | case 1: | ||
69 | pa_dwr_mask = GPIO_A2 | GPIO_A3; | ||
70 | ncr_mask = 0; | ||
71 | ncr_set = 0; | ||
72 | |||
73 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
74 | printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", | ||
75 | __FUNCTION__, state->Vpp); | ||
76 | return -1; | ||
77 | } | ||
78 | break; | ||
79 | |||
80 | default: | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * pa_dwr_set is the mask for selecting Vcc on both sockets. | ||
86 | * pa_dwr_mask selects which bits (and therefore socket) we change. | ||
87 | */ | ||
88 | switch (state->Vcc) { | ||
89 | default: | ||
90 | case 0: pa_dwr_set = 0; break; | ||
91 | case 33: pa_dwr_set = GPIO_A1|GPIO_A2; break; | ||
92 | case 50: pa_dwr_set = GPIO_A0|GPIO_A3; break; | ||
93 | } | ||
94 | |||
95 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
96 | if (ret == 0) { | ||
97 | unsigned long flags; | ||
98 | |||
99 | local_irq_save(flags); | ||
100 | NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; | ||
101 | |||
102 | local_irq_restore(flags); | ||
103 | sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void neponset_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
110 | { | ||
111 | if (skt->nr == 0) | ||
112 | NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); | ||
113 | |||
114 | sa1111_pcmcia_socket_init(skt); | ||
115 | } | ||
116 | |||
117 | static struct pcmcia_low_level neponset_pcmcia_ops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .hw_init = sa1111_pcmcia_hw_init, | ||
120 | .hw_shutdown = sa1111_pcmcia_hw_shutdown, | ||
121 | .socket_state = sa1111_pcmcia_socket_state, | ||
122 | .configure_socket = neponset_pcmcia_configure_socket, | ||
123 | .socket_init = neponset_pcmcia_socket_init, | ||
124 | .socket_suspend = sa1111_pcmcia_socket_suspend, | ||
125 | }; | ||
126 | |||
127 | int __init pcmcia_neponset_init(struct sa1111_dev *sadev) | ||
128 | { | ||
129 | int ret = -ENODEV; | ||
130 | |||
131 | if (machine_is_assabet()) { | ||
132 | /* | ||
133 | * Set GPIO_A<3:0> to be outputs for the MAX1600, | ||
134 | * and switch to standby mode. | ||
135 | */ | ||
136 | sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | ||
137 | sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
138 | sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
139 | ret = sa11xx_drv_pcmcia_probe(&sadev->dev, &neponset_pcmcia_ops, 0, 2); | ||
140 | } | ||
141 | |||
142 | return ret; | ||
143 | } | ||
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c new file mode 100644 index 000000000000..7bc9e59c761f --- /dev/null +++ b/drivers/pcmcia/sa1100_shannon.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_shannon.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for Shannon | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/hardware.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | #include <asm/arch/shannon.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include "sa1100_generic.h" | ||
18 | |||
19 | static struct pcmcia_irqs irqs[] = { | ||
20 | { 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" }, | ||
21 | { 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" }, | ||
22 | }; | ||
23 | |||
24 | static int shannon_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
25 | { | ||
26 | /* All those are inputs */ | ||
27 | GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | | ||
28 | SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); | ||
29 | GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | | ||
30 | SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); | ||
31 | |||
32 | skt->irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0; | ||
33 | |||
34 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
35 | } | ||
36 | |||
37 | static void shannon_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
38 | { | ||
39 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | shannon_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
44 | struct pcmcia_state *state) | ||
45 | { | ||
46 | unsigned long levels = GPLR; | ||
47 | |||
48 | switch (skt->nr) { | ||
49 | case 0: | ||
50 | state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; | ||
51 | state->ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0; | ||
52 | state->wrprot = 0; /* Not available on Shannon. */ | ||
53 | state->bvd1 = 1; | ||
54 | state->bvd2 = 1; | ||
55 | state->vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ | ||
56 | state->vs_Xv = 0; | ||
57 | break; | ||
58 | |||
59 | case 1: | ||
60 | state->detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1; | ||
61 | state->ready = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0; | ||
62 | state->wrprot = 0; /* Not available on Shannon. */ | ||
63 | state->bvd1 = 1; | ||
64 | state->bvd2 = 1; | ||
65 | state->vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ | ||
66 | state->vs_Xv = 0; | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
73 | const socket_state_t *state) | ||
74 | { | ||
75 | switch (state->Vcc) { | ||
76 | case 0: /* power off */ | ||
77 | printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__); | ||
78 | break; | ||
79 | case 50: | ||
80 | printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__); | ||
81 | case 33: | ||
82 | break; | ||
83 | default: | ||
84 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
85 | __FUNCTION__, state->Vcc); | ||
86 | return -1; | ||
87 | } | ||
88 | |||
89 | printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__); | ||
90 | |||
91 | /* Silently ignore Vpp, output enable, speaker enable. */ | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void shannon_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
97 | { | ||
98 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
99 | } | ||
100 | |||
101 | static void shannon_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
102 | { | ||
103 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
104 | } | ||
105 | |||
106 | static struct pcmcia_low_level shannon_pcmcia_ops = { | ||
107 | .owner = THIS_MODULE, | ||
108 | .hw_init = shannon_pcmcia_hw_init, | ||
109 | .hw_shutdown = shannon_pcmcia_hw_shutdown, | ||
110 | .socket_state = shannon_pcmcia_socket_state, | ||
111 | .configure_socket = shannon_pcmcia_configure_socket, | ||
112 | |||
113 | .socket_init = shannon_pcmcia_socket_init, | ||
114 | .socket_suspend = shannon_pcmcia_socket_suspend, | ||
115 | }; | ||
116 | |||
117 | int __init pcmcia_shannon_init(struct device *dev) | ||
118 | { | ||
119 | int ret = -ENODEV; | ||
120 | |||
121 | if (machine_is_shannon()) | ||
122 | ret = sa11xx_drv_pcmcia_probe(dev, &shannon_pcmcia_ops, 0, 2); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c new file mode 100644 index 000000000000..c2ecf1185e9e --- /dev/null +++ b/drivers/pcmcia/sa1100_simpad.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_simpad.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for simpad | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/hardware.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | #include <asm/irq.h> | ||
16 | #include <asm/arch/simpad.h> | ||
17 | #include "sa1100_generic.h" | ||
18 | |||
19 | extern long get_cs3_shadow(void); | ||
20 | extern void set_cs3_bit(int value); | ||
21 | extern void clear_cs3_bit(int value); | ||
22 | |||
23 | static struct pcmcia_irqs irqs[] = { | ||
24 | { 1, IRQ_GPIO_CF_CD, "CF_CD" }, | ||
25 | }; | ||
26 | |||
27 | static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
28 | { | ||
29 | |||
30 | clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); | ||
31 | |||
32 | skt->irq = IRQ_GPIO_CF_IRQ; | ||
33 | |||
34 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
35 | } | ||
36 | |||
37 | static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
38 | { | ||
39 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
40 | |||
41 | /* Disable CF bus: */ | ||
42 | //set_cs3_bit(PCMCIA_BUFF_DIS); | ||
43 | clear_cs3_bit(PCMCIA_RESET); | ||
44 | } | ||
45 | |||
46 | static void | ||
47 | simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
48 | struct pcmcia_state *state) | ||
49 | { | ||
50 | unsigned long levels = GPLR; | ||
51 | long cs3reg = get_cs3_shadow(); | ||
52 | |||
53 | state->detect=((levels & GPIO_CF_CD)==0)?1:0; | ||
54 | state->ready=(levels & GPIO_CF_IRQ)?1:0; | ||
55 | state->bvd1=1; /* Not available on Simpad. */ | ||
56 | state->bvd2=1; /* Not available on Simpad. */ | ||
57 | state->wrprot=0; /* Not available on Simpad. */ | ||
58 | |||
59 | if((cs3reg & 0x0c) == 0x0c) { | ||
60 | state->vs_3v=0; | ||
61 | state->vs_Xv=0; | ||
62 | } else { | ||
63 | state->vs_3v=1; | ||
64 | state->vs_Xv=0; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
70 | const socket_state_t *state) | ||
71 | { | ||
72 | unsigned long flags; | ||
73 | |||
74 | local_irq_save(flags); | ||
75 | |||
76 | /* Murphy: see table of MIC2562a-1 */ | ||
77 | switch (state->Vcc) { | ||
78 | case 0: | ||
79 | clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); | ||
80 | break; | ||
81 | |||
82 | case 33: | ||
83 | clear_cs3_bit(VCC_3V_EN|EN1); | ||
84 | set_cs3_bit(VCC_5V_EN|EN0); | ||
85 | break; | ||
86 | |||
87 | case 50: | ||
88 | clear_cs3_bit(VCC_5V_EN|EN1); | ||
89 | set_cs3_bit(VCC_3V_EN|EN0); | ||
90 | break; | ||
91 | |||
92 | default: | ||
93 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
94 | __FUNCTION__, state->Vcc); | ||
95 | clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); | ||
96 | local_irq_restore(flags); | ||
97 | return -1; | ||
98 | } | ||
99 | |||
100 | |||
101 | local_irq_restore(flags); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void simpad_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
107 | { | ||
108 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
109 | } | ||
110 | |||
111 | static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
112 | { | ||
113 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
114 | set_cs3_bit(PCMCIA_RESET); | ||
115 | } | ||
116 | |||
117 | static struct pcmcia_low_level simpad_pcmcia_ops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .hw_init = simpad_pcmcia_hw_init, | ||
120 | .hw_shutdown = simpad_pcmcia_hw_shutdown, | ||
121 | .socket_state = simpad_pcmcia_socket_state, | ||
122 | .configure_socket = simpad_pcmcia_configure_socket, | ||
123 | .socket_init = simpad_pcmcia_socket_init, | ||
124 | .socket_suspend = simpad_pcmcia_socket_suspend, | ||
125 | }; | ||
126 | |||
127 | int __init pcmcia_simpad_init(struct device *dev) | ||
128 | { | ||
129 | int ret = -ENODEV; | ||
130 | |||
131 | if (machine_is_simpad()) | ||
132 | ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1); | ||
133 | |||
134 | return ret; | ||
135 | } | ||
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c new file mode 100644 index 000000000000..bd9d6b2fad68 --- /dev/null +++ b/drivers/pcmcia/sa1111_generic.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/sa1111_generic.c | ||
3 | * | ||
4 | * We implement the generic parts of a SA1111 PCMCIA driver. This | ||
5 | * basically means we handle everything except controlling the | ||
6 | * power. Power is machine specific... | ||
7 | */ | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/ioport.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <pcmcia/ss.h> | ||
17 | |||
18 | #include <asm/hardware.h> | ||
19 | #include <asm/hardware/sa1111.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/irq.h> | ||
22 | |||
23 | #include "sa1111_generic.h" | ||
24 | |||
25 | static struct pcmcia_irqs irqs[] = { | ||
26 | { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, | ||
27 | { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, | ||
28 | { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, | ||
29 | { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, | ||
30 | }; | ||
31 | |||
32 | int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
33 | { | ||
34 | if (skt->irq == NO_IRQ) | ||
35 | skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; | ||
36 | |||
37 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
38 | } | ||
39 | |||
40 | void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
41 | { | ||
42 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
43 | } | ||
44 | |||
45 | void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | ||
46 | { | ||
47 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | ||
48 | unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); | ||
49 | |||
50 | switch (skt->nr) { | ||
51 | case 0: | ||
52 | state->detect = status & PCSR_S0_DETECT ? 0 : 1; | ||
53 | state->ready = status & PCSR_S0_READY ? 1 : 0; | ||
54 | state->bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; | ||
55 | state->bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; | ||
56 | state->wrprot = status & PCSR_S0_WP ? 1 : 0; | ||
57 | state->vs_3v = status & PCSR_S0_VS1 ? 0 : 1; | ||
58 | state->vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; | ||
59 | break; | ||
60 | |||
61 | case 1: | ||
62 | state->detect = status & PCSR_S1_DETECT ? 0 : 1; | ||
63 | state->ready = status & PCSR_S1_READY ? 1 : 0; | ||
64 | state->bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; | ||
65 | state->bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; | ||
66 | state->wrprot = status & PCSR_S1_WP ? 1 : 0; | ||
67 | state->vs_3v = status & PCSR_S1_VS1 ? 0 : 1; | ||
68 | state->vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; | ||
69 | break; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
74 | { | ||
75 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | ||
76 | unsigned int pccr_skt_mask, pccr_set_mask, val; | ||
77 | unsigned long flags; | ||
78 | |||
79 | switch (skt->nr) { | ||
80 | case 0: | ||
81 | pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; | ||
82 | break; | ||
83 | |||
84 | case 1: | ||
85 | pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | return -1; | ||
90 | } | ||
91 | |||
92 | pccr_set_mask = 0; | ||
93 | |||
94 | if (state->Vcc != 0) | ||
95 | pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; | ||
96 | if (state->Vcc == 50) | ||
97 | pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; | ||
98 | if (state->flags & SS_RESET) | ||
99 | pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; | ||
100 | if (state->flags & SS_OUTPUT_ENA) | ||
101 | pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; | ||
102 | |||
103 | local_irq_save(flags); | ||
104 | val = sa1111_readl(sadev->mapbase + SA1111_PCCR); | ||
105 | val &= ~pccr_skt_mask; | ||
106 | val |= pccr_set_mask & pccr_skt_mask; | ||
107 | sa1111_writel(val, sadev->mapbase + SA1111_PCCR); | ||
108 | local_irq_restore(flags); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
114 | { | ||
115 | soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
116 | } | ||
117 | |||
118 | void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
119 | { | ||
120 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
121 | } | ||
122 | |||
123 | static int pcmcia_probe(struct sa1111_dev *dev) | ||
124 | { | ||
125 | char *base; | ||
126 | |||
127 | if (!request_mem_region(dev->res.start, 512, | ||
128 | SA1111_DRIVER_NAME(dev))) | ||
129 | return -EBUSY; | ||
130 | |||
131 | base = dev->mapbase; | ||
132 | |||
133 | /* | ||
134 | * Initialise the suspend state. | ||
135 | */ | ||
136 | sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR); | ||
137 | sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR); | ||
138 | |||
139 | #ifdef CONFIG_SA1100_BADGE4 | ||
140 | pcmcia_badge4_init(&dev->dev); | ||
141 | #endif | ||
142 | #ifdef CONFIG_SA1100_JORNADA720 | ||
143 | pcmcia_jornada720_init(&dev->dev); | ||
144 | #endif | ||
145 | #ifdef CONFIG_ARCH_LUBBOCK | ||
146 | pcmcia_lubbock_init(dev); | ||
147 | #endif | ||
148 | #ifdef CONFIG_ASSABET_NEPONSET | ||
149 | pcmcia_neponset_init(dev); | ||
150 | #endif | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int __devexit pcmcia_remove(struct sa1111_dev *dev) | ||
155 | { | ||
156 | soc_common_drv_pcmcia_remove(&dev->dev); | ||
157 | release_mem_region(dev->res.start, 512); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int pcmcia_suspend(struct sa1111_dev *dev, u32 state) | ||
162 | { | ||
163 | return pcmcia_socket_dev_suspend(&dev->dev, state); | ||
164 | } | ||
165 | |||
166 | static int pcmcia_resume(struct sa1111_dev *dev) | ||
167 | { | ||
168 | return pcmcia_socket_dev_resume(&dev->dev); | ||
169 | } | ||
170 | |||
171 | static struct sa1111_driver pcmcia_driver = { | ||
172 | .drv = { | ||
173 | .name = "sa1111-pcmcia", | ||
174 | }, | ||
175 | .devid = SA1111_DEVID_PCMCIA, | ||
176 | .probe = pcmcia_probe, | ||
177 | .remove = __devexit_p(pcmcia_remove), | ||
178 | .suspend = pcmcia_suspend, | ||
179 | .resume = pcmcia_resume, | ||
180 | }; | ||
181 | |||
182 | static int __init sa1111_drv_pcmcia_init(void) | ||
183 | { | ||
184 | return sa1111_driver_register(&pcmcia_driver); | ||
185 | } | ||
186 | |||
187 | static void __exit sa1111_drv_pcmcia_exit(void) | ||
188 | { | ||
189 | sa1111_driver_unregister(&pcmcia_driver); | ||
190 | } | ||
191 | |||
192 | module_init(sa1111_drv_pcmcia_init); | ||
193 | module_exit(sa1111_drv_pcmcia_exit); | ||
194 | |||
195 | MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); | ||
196 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h new file mode 100644 index 000000000000..10ced4a210d7 --- /dev/null +++ b/drivers/pcmcia/sa1111_generic.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #include "soc_common.h" | ||
2 | #include "sa11xx_base.h" | ||
3 | |||
4 | extern int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *); | ||
5 | extern void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *); | ||
6 | extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *); | ||
7 | extern int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *, const socket_state_t *); | ||
8 | extern void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *); | ||
9 | extern void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *); | ||
10 | |||
11 | extern int pcmcia_badge4_init(struct device *); | ||
12 | extern int pcmcia_jornada720_init(struct device *); | ||
13 | extern int pcmcia_lubbock_init(struct sa1111_dev *); | ||
14 | extern int pcmcia_neponset_init(struct sa1111_dev *); | ||
15 | |||
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c new file mode 100644 index 000000000000..db04ffb6f68c --- /dev/null +++ b/drivers/pcmcia/sa11xx_base.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for the PCMCIA control functionality of StrongARM | ||
4 | SA-1100 microprocessors. | ||
5 | |||
6 | The contents of this file are subject to the Mozilla Public | ||
7 | License Version 1.1 (the "License"); you may not use this file | ||
8 | except in compliance with the License. You may obtain a copy of | ||
9 | the License at http://www.mozilla.org/MPL/ | ||
10 | |||
11 | Software distributed under the License is distributed on an "AS | ||
12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
13 | implied. See the License for the specific language governing | ||
14 | rights and limitations under the License. | ||
15 | |||
16 | The initial developer of the original code is John G. Dorsey | ||
17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | ||
18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | ||
19 | |||
20 | Alternatively, the contents of this file may be used under the | ||
21 | terms of the GNU Public License version 2 (the "GPL"), in which | ||
22 | case the provisions of the GPL are applicable instead of the | ||
23 | above. If you wish to allow the use of your version of this file | ||
24 | only under the terms of the GPL and not to allow others to use | ||
25 | your version of this file under the MPL, indicate your decision | ||
26 | by deleting the provisions above and replace them with the notice | ||
27 | and other provisions required by the GPL. If you do not delete | ||
28 | the provisions above, a recipient may use your version of this | ||
29 | file under either the MPL or the GPL. | ||
30 | |||
31 | ======================================================================*/ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/config.h> | ||
36 | #include <linux/cpufreq.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | |||
41 | #include <asm/hardware.h> | ||
42 | #include <asm/io.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <asm/system.h> | ||
45 | |||
46 | #include "soc_common.h" | ||
47 | #include "sa11xx_base.h" | ||
48 | |||
49 | |||
50 | /* | ||
51 | * sa1100_pcmcia_default_mecr_timing | ||
52 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
53 | * | ||
54 | * Calculate MECR clock wait states for given CPU clock | ||
55 | * speed and command wait state. This function can be over- | ||
56 | * written by a board specific version. | ||
57 | * | ||
58 | * The default is to simply calculate the BS values as specified in | ||
59 | * the INTEL SA1100 development manual | ||
60 | * "Expansion Memory (PCMCIA) Configuration Register (MECR)" | ||
61 | * that's section 10.2.5 in _my_ version of the manual ;) | ||
62 | */ | ||
63 | static unsigned int | ||
64 | sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt, | ||
65 | unsigned int cpu_speed, | ||
66 | unsigned int cmd_time) | ||
67 | { | ||
68 | return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); | ||
69 | } | ||
70 | |||
71 | /* sa1100_pcmcia_set_mecr() | ||
72 | * ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
73 | * | ||
74 | * set MECR value for socket <sock> based on this sockets | ||
75 | * io, mem and attribute space access speed. | ||
76 | * Call board specific BS value calculation to allow boards | ||
77 | * to tweak the BS values. | ||
78 | */ | ||
79 | static int | ||
80 | sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock) | ||
81 | { | ||
82 | struct soc_pcmcia_timing timing; | ||
83 | u32 mecr, old_mecr; | ||
84 | unsigned long flags; | ||
85 | unsigned int bs_io, bs_mem, bs_attr; | ||
86 | |||
87 | soc_common_pcmcia_get_timing(skt, &timing); | ||
88 | |||
89 | bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io); | ||
90 | bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem); | ||
91 | bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr); | ||
92 | |||
93 | local_irq_save(flags); | ||
94 | |||
95 | old_mecr = mecr = MECR; | ||
96 | MECR_FAST_SET(mecr, skt->nr, 0); | ||
97 | MECR_BSIO_SET(mecr, skt->nr, bs_io); | ||
98 | MECR_BSA_SET(mecr, skt->nr, bs_attr); | ||
99 | MECR_BSM_SET(mecr, skt->nr, bs_mem); | ||
100 | if (old_mecr != mecr) | ||
101 | MECR = mecr; | ||
102 | |||
103 | local_irq_restore(flags); | ||
104 | |||
105 | debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n", | ||
106 | MECR_FAST_GET(mecr, skt->nr), | ||
107 | MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), | ||
108 | MECR_BSIO_GET(mecr, skt->nr)); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | #ifdef CONFIG_CPU_FREQ | ||
114 | static int | ||
115 | sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | ||
116 | unsigned long val, | ||
117 | struct cpufreq_freqs *freqs) | ||
118 | { | ||
119 | switch (val) { | ||
120 | case CPUFREQ_PRECHANGE: | ||
121 | if (freqs->new > freqs->old) | ||
122 | sa1100_pcmcia_set_mecr(skt, freqs->new); | ||
123 | break; | ||
124 | |||
125 | case CPUFREQ_POSTCHANGE: | ||
126 | if (freqs->new < freqs->old) | ||
127 | sa1100_pcmcia_set_mecr(skt, freqs->new); | ||
128 | break; | ||
129 | case CPUFREQ_RESUMECHANGE: | ||
130 | sa1100_pcmcia_set_mecr(skt, freqs->new); | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | #endif | ||
138 | |||
139 | static int | ||
140 | sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt) | ||
141 | { | ||
142 | return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); | ||
143 | } | ||
144 | |||
145 | static int | ||
146 | sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf) | ||
147 | { | ||
148 | struct soc_pcmcia_timing timing; | ||
149 | unsigned int clock = cpufreq_get(0); | ||
150 | unsigned long mecr = MECR; | ||
151 | char *p = buf; | ||
152 | |||
153 | soc_common_pcmcia_get_timing(skt, &timing); | ||
154 | |||
155 | p+=sprintf(p, "I/O : %u (%u)\n", timing.io, | ||
156 | sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); | ||
157 | |||
158 | p+=sprintf(p, "attribute: %u (%u)\n", timing.attr, | ||
159 | sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); | ||
160 | |||
161 | p+=sprintf(p, "common : %u (%u)\n", timing.mem, | ||
162 | sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); | ||
163 | |||
164 | return p - buf; | ||
165 | } | ||
166 | |||
167 | int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, | ||
168 | int first, int nr) | ||
169 | { | ||
170 | /* | ||
171 | * set default MECR calculation if the board specific | ||
172 | * code did not specify one... | ||
173 | */ | ||
174 | if (!ops->get_timing) | ||
175 | ops->get_timing = sa1100_pcmcia_default_mecr_timing; | ||
176 | |||
177 | /* Provide our SA11x0 specific timing routines. */ | ||
178 | ops->set_timing = sa1100_pcmcia_set_timing; | ||
179 | ops->show_timing = sa1100_pcmcia_show_timing; | ||
180 | #ifdef CONFIG_CPU_FREQ | ||
181 | ops->frequency_change = sa1100_pcmcia_frequency_change; | ||
182 | #endif | ||
183 | |||
184 | return soc_common_drv_pcmcia_probe(dev, ops, first, nr); | ||
185 | } | ||
186 | EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); | ||
187 | |||
188 | static int __init sa11xx_pcmcia_init(void) | ||
189 | { | ||
190 | return 0; | ||
191 | } | ||
192 | module_init(sa11xx_pcmcia_init); | ||
193 | |||
194 | static void __exit sa11xx_pcmcia_exit(void) {} | ||
195 | |||
196 | module_exit(sa11xx_pcmcia_exit); | ||
197 | |||
198 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); | ||
199 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); | ||
200 | MODULE_LICENSE("Dual MPL/GPL"); | ||
diff --git a/drivers/pcmcia/sa11xx_base.h b/drivers/pcmcia/sa11xx_base.h new file mode 100644 index 000000000000..7bc208280527 --- /dev/null +++ b/drivers/pcmcia/sa11xx_base.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for the PCMCIA control functionality of StrongARM | ||
4 | SA-1100 microprocessors. | ||
5 | |||
6 | The contents of this file are subject to the Mozilla Public | ||
7 | License Version 1.1 (the "License"); you may not use this file | ||
8 | except in compliance with the License. You may obtain a copy of | ||
9 | the License at http://www.mozilla.org/MPL/ | ||
10 | |||
11 | Software distributed under the License is distributed on an "AS | ||
12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
13 | implied. See the License for the specific language governing | ||
14 | rights and limitations under the License. | ||
15 | |||
16 | The initial developer of the original code is John G. Dorsey | ||
17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | ||
18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | ||
19 | |||
20 | Alternatively, the contents of this file may be used under the | ||
21 | terms of the GNU Public License version 2 (the "GPL"), in which | ||
22 | case the provisions of the GPL are applicable instead of the | ||
23 | above. If you wish to allow the use of your version of this file | ||
24 | only under the terms of the GPL and not to allow others to use | ||
25 | your version of this file under the MPL, indicate your decision | ||
26 | by deleting the provisions above and replace them with the notice | ||
27 | and other provisions required by the GPL. If you do not delete | ||
28 | the provisions above, a recipient may use your version of this | ||
29 | file under either the MPL or the GPL. | ||
30 | |||
31 | ======================================================================*/ | ||
32 | |||
33 | #if !defined(_PCMCIA_SA1100_H) | ||
34 | # define _PCMCIA_SA1100_H | ||
35 | |||
36 | /* SA-1100 PCMCIA Memory and I/O timing | ||
37 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
38 | * The SA-1110 Developer's Manual, section 10.2.5, says the following: | ||
39 | * | ||
40 | * "To calculate the recommended BS_xx value for each address space: | ||
41 | * divide the command width time (the greater of twIOWR and twIORD, | ||
42 | * or the greater of twWE and twOE) by processor cycle time; divide | ||
43 | * by 2; divide again by 3 (number of BCLK's per command assertion); | ||
44 | * round up to the next whole number; and subtract 1." | ||
45 | */ | ||
46 | |||
47 | /* MECR: Expansion Memory Configuration Register | ||
48 | * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) | ||
49 | * | ||
50 | * MECR layout is: | ||
51 | * | ||
52 | * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0> | ||
53 | * | ||
54 | * (This layout is actually true only for the SA-1110; the FASTn bits are | ||
55 | * reserved on the SA-1100.) | ||
56 | */ | ||
57 | |||
58 | #define MECR_SOCKET_0_SHIFT (0) | ||
59 | #define MECR_SOCKET_1_SHIFT (16) | ||
60 | |||
61 | #define MECR_BS_MASK (0x1f) | ||
62 | #define MECR_FAST_MODE_MASK (0x01) | ||
63 | |||
64 | #define MECR_BSIO_SHIFT (0) | ||
65 | #define MECR_BSA_SHIFT (5) | ||
66 | #define MECR_BSM_SHIFT (10) | ||
67 | #define MECR_FAST_SHIFT (15) | ||
68 | |||
69 | #define MECR_SET(mecr, sock, shift, mask, bs) \ | ||
70 | ((mecr)=((mecr)&~(((mask)<<(shift))<<\ | ||
71 | ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\ | ||
72 | (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))) | ||
73 | |||
74 | #define MECR_GET(mecr, sock, shift, mask) \ | ||
75 | ((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\ | ||
76 | (shift))&(mask)) | ||
77 | |||
78 | #define MECR_BSIO_SET(mecr, sock, bs) \ | ||
79 | MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs)) | ||
80 | |||
81 | #define MECR_BSIO_GET(mecr, sock) \ | ||
82 | MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK) | ||
83 | |||
84 | #define MECR_BSA_SET(mecr, sock, bs) \ | ||
85 | MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs)) | ||
86 | |||
87 | #define MECR_BSA_GET(mecr, sock) \ | ||
88 | MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK) | ||
89 | |||
90 | #define MECR_BSM_SET(mecr, sock, bs) \ | ||
91 | MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs)) | ||
92 | |||
93 | #define MECR_BSM_GET(mecr, sock) \ | ||
94 | MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK) | ||
95 | |||
96 | #define MECR_FAST_SET(mecr, sock, fast) \ | ||
97 | MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast)) | ||
98 | |||
99 | #define MECR_FAST_GET(mecr, sock) \ | ||
100 | MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK) | ||
101 | |||
102 | |||
103 | /* This function implements the BS value calculation for setting the MECR | ||
104 | * using integer arithmetic: | ||
105 | */ | ||
106 | static inline unsigned int sa1100_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns, | ||
107 | unsigned int cpu_clock_khz){ | ||
108 | unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000; | ||
109 | return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1); | ||
110 | } | ||
111 | |||
112 | /* This function returns the (approximate) command assertion period, in | ||
113 | * nanoseconds, for a given CPU clock frequency and MECR BS value: | ||
114 | */ | ||
115 | static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, | ||
116 | unsigned int pcmcia_mecr_bs){ | ||
117 | return (((10000000 * 2) / cpu_clock_khz) * (3 * (pcmcia_mecr_bs + 1))) / 10; | ||
118 | } | ||
119 | |||
120 | |||
121 | extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); | ||
122 | |||
123 | #endif /* !defined(_PCMCIA_SA1100_H) */ | ||
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c new file mode 100644 index 000000000000..888b70e6a484 --- /dev/null +++ b/drivers/pcmcia/soc_common.c | |||
@@ -0,0 +1,850 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Common support code for the PCMCIA control functionality of | ||
4 | integrated SOCs like the SA-11x0 and PXA2xx microprocessors. | ||
5 | |||
6 | The contents of this file are subject to the Mozilla Public | ||
7 | License Version 1.1 (the "License"); you may not use this file | ||
8 | except in compliance with the License. You may obtain a copy of | ||
9 | the License at http://www.mozilla.org/MPL/ | ||
10 | |||
11 | Software distributed under the License is distributed on an "AS | ||
12 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
13 | implied. See the License for the specific language governing | ||
14 | rights and limitations under the License. | ||
15 | |||
16 | The initial developer of the original code is John G. Dorsey | ||
17 | <john+@cs.cmu.edu>. Portions created by John G. Dorsey are | ||
18 | Copyright (C) 1999 John G. Dorsey. All Rights Reserved. | ||
19 | |||
20 | Alternatively, the contents of this file may be used under the | ||
21 | terms of the GNU Public License version 2 (the "GPL"), in which | ||
22 | case the provisions of the GPL are applicable instead of the | ||
23 | above. If you wish to allow the use of your version of this file | ||
24 | only under the terms of the GPL and not to allow others to use | ||
25 | your version of this file under the MPL, indicate your decision | ||
26 | by deleting the provisions above and replace them with the notice | ||
27 | and other provisions required by the GPL. If you do not delete | ||
28 | the provisions above, a recipient may use your version of this | ||
29 | file under either the MPL or the GPL. | ||
30 | |||
31 | ======================================================================*/ | ||
32 | |||
33 | |||
34 | #include <linux/config.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/timer.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/spinlock.h> | ||
43 | #include <linux/cpufreq.h> | ||
44 | |||
45 | #include <asm/hardware.h> | ||
46 | #include <asm/io.h> | ||
47 | #include <asm/irq.h> | ||
48 | #include <asm/system.h> | ||
49 | |||
50 | #include "soc_common.h" | ||
51 | |||
52 | /* FIXME: platform dependent resource declaration has to move out of this file */ | ||
53 | #ifdef CONFIG_ARCH_PXA | ||
54 | #include <asm/arch/pxa-regs.h> | ||
55 | #endif | ||
56 | |||
57 | #ifdef DEBUG | ||
58 | |||
59 | static int pc_debug; | ||
60 | module_param(pc_debug, int, 0644); | ||
61 | |||
62 | void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, | ||
63 | int lvl, const char *fmt, ...) | ||
64 | { | ||
65 | va_list args; | ||
66 | if (pc_debug > lvl) { | ||
67 | printk(KERN_DEBUG "skt%u: %s: ", skt->nr, func); | ||
68 | va_start(args, fmt); | ||
69 | printk(fmt, args); | ||
70 | va_end(args); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | #endif | ||
75 | |||
76 | #define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket) | ||
77 | |||
78 | static unsigned short | ||
79 | calc_speed(unsigned short *spds, int num, unsigned short dflt) | ||
80 | { | ||
81 | unsigned short speed = 0; | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < num; i++) | ||
85 | if (speed < spds[i]) | ||
86 | speed = spds[i]; | ||
87 | if (speed == 0) | ||
88 | speed = dflt; | ||
89 | |||
90 | return speed; | ||
91 | } | ||
92 | |||
93 | void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing) | ||
94 | { | ||
95 | timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); | ||
96 | timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | ||
97 | timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | ||
98 | } | ||
99 | EXPORT_SYMBOL(soc_common_pcmcia_get_timing); | ||
100 | |||
101 | static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) | ||
102 | { | ||
103 | struct pcmcia_state state; | ||
104 | unsigned int stat; | ||
105 | |||
106 | memset(&state, 0, sizeof(struct pcmcia_state)); | ||
107 | |||
108 | skt->ops->socket_state(skt, &state); | ||
109 | |||
110 | stat = state.detect ? SS_DETECT : 0; | ||
111 | stat |= state.ready ? SS_READY : 0; | ||
112 | stat |= state.wrprot ? SS_WRPROT : 0; | ||
113 | stat |= state.vs_3v ? SS_3VCARD : 0; | ||
114 | stat |= state.vs_Xv ? SS_XVCARD : 0; | ||
115 | |||
116 | /* The power status of individual sockets is not available | ||
117 | * explicitly from the hardware, so we just remember the state | ||
118 | * and regurgitate it upon request: | ||
119 | */ | ||
120 | stat |= skt->cs_state.Vcc ? SS_POWERON : 0; | ||
121 | |||
122 | if (skt->cs_state.flags & SS_IOCARD) | ||
123 | stat |= state.bvd1 ? SS_STSCHG : 0; | ||
124 | else { | ||
125 | if (state.bvd1 == 0) | ||
126 | stat |= SS_BATDEAD; | ||
127 | else if (state.bvd2 == 0) | ||
128 | stat |= SS_BATWARN; | ||
129 | } | ||
130 | return stat; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * soc_common_pcmcia_config_skt | ||
135 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
136 | * | ||
137 | * Convert PCMCIA socket state to our socket configure structure. | ||
138 | */ | ||
139 | static int | ||
140 | soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state) | ||
141 | { | ||
142 | int ret; | ||
143 | |||
144 | ret = skt->ops->configure_socket(skt, state); | ||
145 | if (ret == 0) { | ||
146 | /* | ||
147 | * This really needs a better solution. The IRQ | ||
148 | * may or may not be claimed by the driver. | ||
149 | */ | ||
150 | if (skt->irq_state != 1 && state->io_irq) { | ||
151 | skt->irq_state = 1; | ||
152 | set_irq_type(skt->irq, IRQT_FALLING); | ||
153 | } else if (skt->irq_state == 1 && state->io_irq == 0) { | ||
154 | skt->irq_state = 0; | ||
155 | set_irq_type(skt->irq, IRQT_NOEDGE); | ||
156 | } | ||
157 | |||
158 | skt->cs_state = *state; | ||
159 | } | ||
160 | |||
161 | if (ret < 0) | ||
162 | printk(KERN_ERR "soc_common_pcmcia: unable to configure " | ||
163 | "socket %d\n", skt->nr); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | /* soc_common_pcmcia_sock_init() | ||
169 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
170 | * | ||
171 | * (Re-)Initialise the socket, turning on status interrupts | ||
172 | * and PCMCIA bus. This must wait for power to stabilise | ||
173 | * so that the card status signals report correctly. | ||
174 | * | ||
175 | * Returns: 0 | ||
176 | */ | ||
177 | static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock) | ||
178 | { | ||
179 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
180 | |||
181 | debug(skt, 2, "initializing socket\n"); | ||
182 | |||
183 | skt->ops->socket_init(skt); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | |||
188 | /* | ||
189 | * soc_common_pcmcia_suspend() | ||
190 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
191 | * | ||
192 | * Remove power on the socket, disable IRQs from the card. | ||
193 | * Turn off status interrupts, and disable the PCMCIA bus. | ||
194 | * | ||
195 | * Returns: 0 | ||
196 | */ | ||
197 | static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock) | ||
198 | { | ||
199 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
200 | |||
201 | debug(skt, 2, "suspending socket\n"); | ||
202 | |||
203 | skt->ops->socket_suspend(skt); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static DEFINE_SPINLOCK(status_lock); | ||
209 | |||
210 | static void soc_common_check_status(struct soc_pcmcia_socket *skt) | ||
211 | { | ||
212 | unsigned int events; | ||
213 | |||
214 | debug(skt, 4, "entering PCMCIA monitoring thread\n"); | ||
215 | |||
216 | do { | ||
217 | unsigned int status; | ||
218 | unsigned long flags; | ||
219 | |||
220 | status = soc_common_pcmcia_skt_state(skt); | ||
221 | |||
222 | spin_lock_irqsave(&status_lock, flags); | ||
223 | events = (status ^ skt->status) & skt->cs_state.csc_mask; | ||
224 | skt->status = status; | ||
225 | spin_unlock_irqrestore(&status_lock, flags); | ||
226 | |||
227 | debug(skt, 4, "events: %s%s%s%s%s%s\n", | ||
228 | events == 0 ? "<NONE>" : "", | ||
229 | events & SS_DETECT ? "DETECT " : "", | ||
230 | events & SS_READY ? "READY " : "", | ||
231 | events & SS_BATDEAD ? "BATDEAD " : "", | ||
232 | events & SS_BATWARN ? "BATWARN " : "", | ||
233 | events & SS_STSCHG ? "STSCHG " : ""); | ||
234 | |||
235 | if (events) | ||
236 | pcmcia_parse_events(&skt->socket, events); | ||
237 | } while (events); | ||
238 | } | ||
239 | |||
240 | /* Let's poll for events in addition to IRQs since IRQ only is unreliable... */ | ||
241 | static void soc_common_pcmcia_poll_event(unsigned long dummy) | ||
242 | { | ||
243 | struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy; | ||
244 | debug(skt, 4, "polling for events\n"); | ||
245 | |||
246 | mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD); | ||
247 | |||
248 | soc_common_check_status(skt); | ||
249 | } | ||
250 | |||
251 | |||
252 | /* | ||
253 | * Service routine for socket driver interrupts (requested by the | ||
254 | * low-level PCMCIA init() operation via soc_common_pcmcia_thread()). | ||
255 | * The actual interrupt-servicing work is performed by | ||
256 | * soc_common_pcmcia_thread(), largely because the Card Services event- | ||
257 | * handling code performs scheduling operations which cannot be | ||
258 | * executed from within an interrupt context. | ||
259 | */ | ||
260 | static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
261 | { | ||
262 | struct soc_pcmcia_socket *skt = dev; | ||
263 | |||
264 | debug(skt, 3, "servicing IRQ %d\n", irq); | ||
265 | |||
266 | soc_common_check_status(skt); | ||
267 | |||
268 | return IRQ_HANDLED; | ||
269 | } | ||
270 | |||
271 | |||
272 | /* | ||
273 | * Implements the get_status() operation for the in-kernel PCMCIA | ||
274 | * service (formerly SS_GetStatus in Card Services). Essentially just | ||
275 | * fills in bits in `status' according to internal driver state or | ||
276 | * the value of the voltage detect chipselect register. | ||
277 | * | ||
278 | * As a debugging note, during card startup, the PCMCIA core issues | ||
279 | * three set_socket() commands in a row the first with RESET deasserted, | ||
280 | * the second with RESET asserted, and the last with RESET deasserted | ||
281 | * again. Following the third set_socket(), a get_status() command will | ||
282 | * be issued. The kernel is looking for the SS_READY flag (see | ||
283 | * setup_socket(), reset_socket(), and unreset_socket() in cs.c). | ||
284 | * | ||
285 | * Returns: 0 | ||
286 | */ | ||
287 | static int | ||
288 | soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | ||
289 | { | ||
290 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
291 | |||
292 | skt->status = soc_common_pcmcia_skt_state(skt); | ||
293 | *status = skt->status; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | |||
299 | /* | ||
300 | * Implements the get_socket() operation for the in-kernel PCMCIA | ||
301 | * service (formerly SS_GetSocket in Card Services). Not a very | ||
302 | * exciting routine. | ||
303 | * | ||
304 | * Returns: 0 | ||
305 | */ | ||
306 | static int | ||
307 | soc_common_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
308 | { | ||
309 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
310 | |||
311 | debug(skt, 2, "\n"); | ||
312 | |||
313 | *state = skt->cs_state; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Implements the set_socket() operation for the in-kernel PCMCIA | ||
320 | * service (formerly SS_SetSocket in Card Services). We more or | ||
321 | * less punt all of this work and let the kernel handle the details | ||
322 | * of power configuration, reset, &c. We also record the value of | ||
323 | * `state' in order to regurgitate it to the PCMCIA core later. | ||
324 | * | ||
325 | * Returns: 0 | ||
326 | */ | ||
327 | static int | ||
328 | soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
329 | { | ||
330 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
331 | |||
332 | debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", | ||
333 | (state->csc_mask==0)?"<NONE> ":"", | ||
334 | (state->csc_mask&SS_DETECT)?"DETECT ":"", | ||
335 | (state->csc_mask&SS_READY)?"READY ":"", | ||
336 | (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", | ||
337 | (state->csc_mask&SS_BATWARN)?"BATWARN ":"", | ||
338 | (state->csc_mask&SS_STSCHG)?"STSCHG ":"", | ||
339 | (state->flags==0)?"<NONE> ":"", | ||
340 | (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", | ||
341 | (state->flags&SS_IOCARD)?"IOCARD ":"", | ||
342 | (state->flags&SS_RESET)?"RESET ":"", | ||
343 | (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", | ||
344 | (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", | ||
345 | state->Vcc, state->Vpp, state->io_irq); | ||
346 | |||
347 | return soc_common_pcmcia_config_skt(skt, state); | ||
348 | } | ||
349 | |||
350 | |||
351 | /* | ||
352 | * Implements the set_io_map() operation for the in-kernel PCMCIA | ||
353 | * service (formerly SS_SetIOMap in Card Services). We configure | ||
354 | * the map speed as requested, but override the address ranges | ||
355 | * supplied by Card Services. | ||
356 | * | ||
357 | * Returns: 0 on success, -1 on error | ||
358 | */ | ||
359 | static int | ||
360 | soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) | ||
361 | { | ||
362 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
363 | unsigned short speed = map->speed; | ||
364 | |||
365 | debug(skt, 2, "map %u speed %u start 0x%08x stop 0x%08x\n", | ||
366 | map->map, map->speed, map->start, map->stop); | ||
367 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", | ||
368 | (map->flags==0)?"<NONE>":"", | ||
369 | (map->flags&MAP_ACTIVE)?"ACTIVE ":"", | ||
370 | (map->flags&MAP_16BIT)?"16BIT ":"", | ||
371 | (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", | ||
372 | (map->flags&MAP_0WS)?"0WS ":"", | ||
373 | (map->flags&MAP_WRPROT)?"WRPROT ":"", | ||
374 | (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", | ||
375 | (map->flags&MAP_PREFETCH)?"PREFETCH ":""); | ||
376 | |||
377 | if (map->map >= MAX_IO_WIN) { | ||
378 | printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, | ||
379 | map->map); | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | if (map->flags & MAP_ACTIVE) { | ||
384 | if (speed == 0) | ||
385 | speed = SOC_PCMCIA_IO_ACCESS; | ||
386 | } else { | ||
387 | speed = 0; | ||
388 | } | ||
389 | |||
390 | skt->spd_io[map->map] = speed; | ||
391 | skt->ops->set_timing(skt); | ||
392 | |||
393 | if (map->stop == 1) | ||
394 | map->stop = PAGE_SIZE-1; | ||
395 | |||
396 | map->stop -= map->start; | ||
397 | map->stop += skt->socket.io_offset; | ||
398 | map->start = skt->socket.io_offset; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | |||
404 | /* | ||
405 | * Implements the set_mem_map() operation for the in-kernel PCMCIA | ||
406 | * service (formerly SS_SetMemMap in Card Services). We configure | ||
407 | * the map speed as requested, but override the address ranges | ||
408 | * supplied by Card Services. | ||
409 | * | ||
410 | * Returns: 0 on success, -1 on error | ||
411 | */ | ||
412 | static int | ||
413 | soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) | ||
414 | { | ||
415 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
416 | struct resource *res; | ||
417 | unsigned short speed = map->speed; | ||
418 | |||
419 | debug(skt, 2, "map %u speed %u card_start %08x\n", | ||
420 | map->map, map->speed, map->card_start); | ||
421 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", | ||
422 | (map->flags==0)?"<NONE>":"", | ||
423 | (map->flags&MAP_ACTIVE)?"ACTIVE ":"", | ||
424 | (map->flags&MAP_16BIT)?"16BIT ":"", | ||
425 | (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", | ||
426 | (map->flags&MAP_0WS)?"0WS ":"", | ||
427 | (map->flags&MAP_WRPROT)?"WRPROT ":"", | ||
428 | (map->flags&MAP_ATTRIB)?"ATTRIB ":"", | ||
429 | (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); | ||
430 | |||
431 | if (map->map >= MAX_WIN) | ||
432 | return -EINVAL; | ||
433 | |||
434 | if (map->flags & MAP_ACTIVE) { | ||
435 | if (speed == 0) | ||
436 | speed = 300; | ||
437 | } else { | ||
438 | speed = 0; | ||
439 | } | ||
440 | |||
441 | if (map->flags & MAP_ATTRIB) { | ||
442 | res = &skt->res_attr; | ||
443 | skt->spd_attr[map->map] = speed; | ||
444 | skt->spd_mem[map->map] = 0; | ||
445 | } else { | ||
446 | res = &skt->res_mem; | ||
447 | skt->spd_attr[map->map] = 0; | ||
448 | skt->spd_mem[map->map] = speed; | ||
449 | } | ||
450 | |||
451 | skt->ops->set_timing(skt); | ||
452 | |||
453 | map->static_start = res->start + map->card_start; | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | struct bittbl { | ||
459 | unsigned int mask; | ||
460 | const char *name; | ||
461 | }; | ||
462 | |||
463 | static struct bittbl status_bits[] = { | ||
464 | { SS_WRPROT, "SS_WRPROT" }, | ||
465 | { SS_BATDEAD, "SS_BATDEAD" }, | ||
466 | { SS_BATWARN, "SS_BATWARN" }, | ||
467 | { SS_READY, "SS_READY" }, | ||
468 | { SS_DETECT, "SS_DETECT" }, | ||
469 | { SS_POWERON, "SS_POWERON" }, | ||
470 | { SS_STSCHG, "SS_STSCHG" }, | ||
471 | { SS_3VCARD, "SS_3VCARD" }, | ||
472 | { SS_XVCARD, "SS_XVCARD" }, | ||
473 | }; | ||
474 | |||
475 | static struct bittbl conf_bits[] = { | ||
476 | { SS_PWR_AUTO, "SS_PWR_AUTO" }, | ||
477 | { SS_IOCARD, "SS_IOCARD" }, | ||
478 | { SS_RESET, "SS_RESET" }, | ||
479 | { SS_DMA_MODE, "SS_DMA_MODE" }, | ||
480 | { SS_SPKR_ENA, "SS_SPKR_ENA" }, | ||
481 | { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, | ||
482 | }; | ||
483 | |||
484 | static void | ||
485 | dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) | ||
486 | { | ||
487 | char *b = *p; | ||
488 | int i; | ||
489 | |||
490 | b += sprintf(b, "%-9s:", prefix); | ||
491 | for (i = 0; i < sz; i++) | ||
492 | if (val & bits[i].mask) | ||
493 | b += sprintf(b, " %s", bits[i].name); | ||
494 | *b++ = '\n'; | ||
495 | *p = b; | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | * Implements the /sys/class/pcmcia_socket/??/status file. | ||
500 | * | ||
501 | * Returns: the number of characters added to the buffer | ||
502 | */ | ||
503 | static ssize_t show_status(struct class_device *class_dev, char *buf) | ||
504 | { | ||
505 | struct soc_pcmcia_socket *skt = | ||
506 | container_of(class_dev, struct soc_pcmcia_socket, socket.dev); | ||
507 | char *p = buf; | ||
508 | |||
509 | p+=sprintf(p, "slot : %d\n", skt->nr); | ||
510 | |||
511 | dump_bits(&p, "status", skt->status, | ||
512 | status_bits, ARRAY_SIZE(status_bits)); | ||
513 | dump_bits(&p, "csc_mask", skt->cs_state.csc_mask, | ||
514 | status_bits, ARRAY_SIZE(status_bits)); | ||
515 | dump_bits(&p, "cs_flags", skt->cs_state.flags, | ||
516 | conf_bits, ARRAY_SIZE(conf_bits)); | ||
517 | |||
518 | p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); | ||
519 | p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); | ||
520 | p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq); | ||
521 | if (skt->ops->show_timing) | ||
522 | p+=skt->ops->show_timing(skt, p); | ||
523 | |||
524 | return p-buf; | ||
525 | } | ||
526 | static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | ||
527 | |||
528 | |||
529 | static struct pccard_operations soc_common_pcmcia_operations = { | ||
530 | .init = soc_common_pcmcia_sock_init, | ||
531 | .suspend = soc_common_pcmcia_suspend, | ||
532 | .get_status = soc_common_pcmcia_get_status, | ||
533 | .get_socket = soc_common_pcmcia_get_socket, | ||
534 | .set_socket = soc_common_pcmcia_set_socket, | ||
535 | .set_io_map = soc_common_pcmcia_set_io_map, | ||
536 | .set_mem_map = soc_common_pcmcia_set_mem_map, | ||
537 | }; | ||
538 | |||
539 | |||
540 | int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, | ||
541 | struct pcmcia_irqs *irqs, int nr) | ||
542 | { | ||
543 | int i, res = 0; | ||
544 | |||
545 | for (i = 0; i < nr; i++) { | ||
546 | if (irqs[i].sock != skt->nr) | ||
547 | continue; | ||
548 | res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt, | ||
549 | SA_INTERRUPT, irqs[i].str, skt); | ||
550 | if (res) | ||
551 | break; | ||
552 | set_irq_type(irqs[i].irq, IRQT_NOEDGE); | ||
553 | } | ||
554 | |||
555 | if (res) { | ||
556 | printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n", | ||
557 | irqs[i].irq, res); | ||
558 | |||
559 | while (i--) | ||
560 | if (irqs[i].sock == skt->nr) | ||
561 | free_irq(irqs[i].irq, skt); | ||
562 | } | ||
563 | return res; | ||
564 | } | ||
565 | EXPORT_SYMBOL(soc_pcmcia_request_irqs); | ||
566 | |||
567 | void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, | ||
568 | struct pcmcia_irqs *irqs, int nr) | ||
569 | { | ||
570 | int i; | ||
571 | |||
572 | for (i = 0; i < nr; i++) | ||
573 | if (irqs[i].sock == skt->nr) | ||
574 | free_irq(irqs[i].irq, skt); | ||
575 | } | ||
576 | EXPORT_SYMBOL(soc_pcmcia_free_irqs); | ||
577 | |||
578 | void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, | ||
579 | struct pcmcia_irqs *irqs, int nr) | ||
580 | { | ||
581 | int i; | ||
582 | |||
583 | for (i = 0; i < nr; i++) | ||
584 | if (irqs[i].sock == skt->nr) | ||
585 | set_irq_type(irqs[i].irq, IRQT_NOEDGE); | ||
586 | } | ||
587 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); | ||
588 | |||
589 | void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, | ||
590 | struct pcmcia_irqs *irqs, int nr) | ||
591 | { | ||
592 | int i; | ||
593 | |||
594 | for (i = 0; i < nr; i++) | ||
595 | if (irqs[i].sock == skt->nr) { | ||
596 | set_irq_type(irqs[i].irq, IRQT_RISING); | ||
597 | set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); | ||
598 | } | ||
599 | } | ||
600 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); | ||
601 | |||
602 | |||
603 | LIST_HEAD(soc_pcmcia_sockets); | ||
604 | DECLARE_MUTEX(soc_pcmcia_sockets_lock); | ||
605 | |||
606 | static const char *skt_names[] = { | ||
607 | "PCMCIA socket 0", | ||
608 | "PCMCIA socket 1", | ||
609 | }; | ||
610 | |||
611 | struct skt_dev_info { | ||
612 | int nskt; | ||
613 | struct soc_pcmcia_socket skt[0]; | ||
614 | }; | ||
615 | |||
616 | #define SKT_DEV_INFO_SIZE(n) \ | ||
617 | (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) | ||
618 | |||
619 | #ifdef CONFIG_CPU_FREQ | ||
620 | static int | ||
621 | soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) | ||
622 | { | ||
623 | struct soc_pcmcia_socket *skt; | ||
624 | struct cpufreq_freqs *freqs = data; | ||
625 | int ret = 0; | ||
626 | |||
627 | down(&soc_pcmcia_sockets_lock); | ||
628 | list_for_each_entry(skt, &soc_pcmcia_sockets, node) | ||
629 | if ( skt->ops->frequency_change ) | ||
630 | ret += skt->ops->frequency_change(skt, val, freqs); | ||
631 | up(&soc_pcmcia_sockets_lock); | ||
632 | |||
633 | return ret; | ||
634 | } | ||
635 | |||
636 | static struct notifier_block soc_pcmcia_notifier_block = { | ||
637 | .notifier_call = soc_pcmcia_notifier | ||
638 | }; | ||
639 | |||
640 | static int soc_pcmcia_cpufreq_register(void) | ||
641 | { | ||
642 | int ret; | ||
643 | |||
644 | ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block, | ||
645 | CPUFREQ_TRANSITION_NOTIFIER); | ||
646 | if (ret < 0) | ||
647 | printk(KERN_ERR "Unable to register CPU frequency change " | ||
648 | "notifier for PCMCIA (%d)\n", ret); | ||
649 | return ret; | ||
650 | } | ||
651 | |||
652 | static void soc_pcmcia_cpufreq_unregister(void) | ||
653 | { | ||
654 | cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); | ||
655 | } | ||
656 | |||
657 | #else | ||
658 | #define soc_pcmcia_cpufreq_register() | ||
659 | #define soc_pcmcia_cpufreq_unregister() | ||
660 | #endif | ||
661 | |||
662 | int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) | ||
663 | { | ||
664 | struct skt_dev_info *sinfo; | ||
665 | struct soc_pcmcia_socket *skt; | ||
666 | int ret, i; | ||
667 | |||
668 | down(&soc_pcmcia_sockets_lock); | ||
669 | |||
670 | sinfo = kmalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); | ||
671 | if (!sinfo) { | ||
672 | ret = -ENOMEM; | ||
673 | goto out; | ||
674 | } | ||
675 | |||
676 | memset(sinfo, 0, SKT_DEV_INFO_SIZE(nr)); | ||
677 | sinfo->nskt = nr; | ||
678 | |||
679 | /* | ||
680 | * Initialise the per-socket structure. | ||
681 | */ | ||
682 | for (i = 0; i < nr; i++) { | ||
683 | skt = &sinfo->skt[i]; | ||
684 | |||
685 | skt->socket.ops = &soc_common_pcmcia_operations; | ||
686 | skt->socket.owner = ops->owner; | ||
687 | skt->socket.dev.dev = dev; | ||
688 | |||
689 | init_timer(&skt->poll_timer); | ||
690 | skt->poll_timer.function = soc_common_pcmcia_poll_event; | ||
691 | skt->poll_timer.data = (unsigned long)skt; | ||
692 | skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; | ||
693 | |||
694 | skt->nr = first + i; | ||
695 | skt->irq = NO_IRQ; | ||
696 | skt->dev = dev; | ||
697 | skt->ops = ops; | ||
698 | |||
699 | skt->res_skt.start = _PCMCIA(skt->nr); | ||
700 | skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; | ||
701 | skt->res_skt.name = skt_names[skt->nr]; | ||
702 | skt->res_skt.flags = IORESOURCE_MEM; | ||
703 | |||
704 | ret = request_resource(&iomem_resource, &skt->res_skt); | ||
705 | if (ret) | ||
706 | goto out_err_1; | ||
707 | |||
708 | skt->res_io.start = _PCMCIAIO(skt->nr); | ||
709 | skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; | ||
710 | skt->res_io.name = "io"; | ||
711 | skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
712 | |||
713 | ret = request_resource(&skt->res_skt, &skt->res_io); | ||
714 | if (ret) | ||
715 | goto out_err_2; | ||
716 | |||
717 | skt->res_mem.start = _PCMCIAMem(skt->nr); | ||
718 | skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; | ||
719 | skt->res_mem.name = "memory"; | ||
720 | skt->res_mem.flags = IORESOURCE_MEM; | ||
721 | |||
722 | ret = request_resource(&skt->res_skt, &skt->res_mem); | ||
723 | if (ret) | ||
724 | goto out_err_3; | ||
725 | |||
726 | skt->res_attr.start = _PCMCIAAttr(skt->nr); | ||
727 | skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; | ||
728 | skt->res_attr.name = "attribute"; | ||
729 | skt->res_attr.flags = IORESOURCE_MEM; | ||
730 | |||
731 | ret = request_resource(&skt->res_skt, &skt->res_attr); | ||
732 | if (ret) | ||
733 | goto out_err_4; | ||
734 | |||
735 | skt->virt_io = ioremap(skt->res_io.start, 0x10000); | ||
736 | if (skt->virt_io == NULL) { | ||
737 | ret = -ENOMEM; | ||
738 | goto out_err_5; | ||
739 | } | ||
740 | |||
741 | if ( list_empty(&soc_pcmcia_sockets) ) | ||
742 | soc_pcmcia_cpufreq_register(); | ||
743 | |||
744 | list_add(&skt->node, &soc_pcmcia_sockets); | ||
745 | |||
746 | /* | ||
747 | * We initialize default socket timing here, because | ||
748 | * we are not guaranteed to see a SetIOMap operation at | ||
749 | * runtime. | ||
750 | */ | ||
751 | ops->set_timing(skt); | ||
752 | |||
753 | ret = ops->hw_init(skt); | ||
754 | if (ret) | ||
755 | goto out_err_6; | ||
756 | |||
757 | skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; | ||
758 | skt->socket.resource_ops = &pccard_static_ops; | ||
759 | skt->socket.irq_mask = 0; | ||
760 | skt->socket.map_size = PAGE_SIZE; | ||
761 | skt->socket.pci_irq = skt->irq; | ||
762 | skt->socket.io_offset = (unsigned long)skt->virt_io; | ||
763 | |||
764 | skt->status = soc_common_pcmcia_skt_state(skt); | ||
765 | |||
766 | ret = pcmcia_register_socket(&skt->socket); | ||
767 | if (ret) | ||
768 | goto out_err_7; | ||
769 | |||
770 | WARN_ON(skt->socket.sock != i); | ||
771 | |||
772 | add_timer(&skt->poll_timer); | ||
773 | |||
774 | class_device_create_file(&skt->socket.dev, &class_device_attr_status); | ||
775 | } | ||
776 | |||
777 | dev_set_drvdata(dev, sinfo); | ||
778 | ret = 0; | ||
779 | goto out; | ||
780 | |||
781 | do { | ||
782 | skt = &sinfo->skt[i]; | ||
783 | |||
784 | del_timer_sync(&skt->poll_timer); | ||
785 | pcmcia_unregister_socket(&skt->socket); | ||
786 | |||
787 | out_err_7: | ||
788 | flush_scheduled_work(); | ||
789 | |||
790 | ops->hw_shutdown(skt); | ||
791 | out_err_6: | ||
792 | list_del(&skt->node); | ||
793 | iounmap(skt->virt_io); | ||
794 | out_err_5: | ||
795 | release_resource(&skt->res_attr); | ||
796 | out_err_4: | ||
797 | release_resource(&skt->res_mem); | ||
798 | out_err_3: | ||
799 | release_resource(&skt->res_io); | ||
800 | out_err_2: | ||
801 | release_resource(&skt->res_skt); | ||
802 | out_err_1: | ||
803 | i--; | ||
804 | } while (i > 0); | ||
805 | |||
806 | kfree(sinfo); | ||
807 | |||
808 | out: | ||
809 | up(&soc_pcmcia_sockets_lock); | ||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | int soc_common_drv_pcmcia_remove(struct device *dev) | ||
814 | { | ||
815 | struct skt_dev_info *sinfo = dev_get_drvdata(dev); | ||
816 | int i; | ||
817 | |||
818 | dev_set_drvdata(dev, NULL); | ||
819 | |||
820 | down(&soc_pcmcia_sockets_lock); | ||
821 | for (i = 0; i < sinfo->nskt; i++) { | ||
822 | struct soc_pcmcia_socket *skt = &sinfo->skt[i]; | ||
823 | |||
824 | del_timer_sync(&skt->poll_timer); | ||
825 | |||
826 | pcmcia_unregister_socket(&skt->socket); | ||
827 | |||
828 | flush_scheduled_work(); | ||
829 | |||
830 | skt->ops->hw_shutdown(skt); | ||
831 | |||
832 | soc_common_pcmcia_config_skt(skt, &dead_socket); | ||
833 | |||
834 | list_del(&skt->node); | ||
835 | iounmap(skt->virt_io); | ||
836 | skt->virt_io = NULL; | ||
837 | release_resource(&skt->res_attr); | ||
838 | release_resource(&skt->res_mem); | ||
839 | release_resource(&skt->res_io); | ||
840 | release_resource(&skt->res_skt); | ||
841 | } | ||
842 | if ( list_empty(&soc_pcmcia_sockets) ) | ||
843 | soc_pcmcia_cpufreq_unregister(); | ||
844 | |||
845 | up(&soc_pcmcia_sockets_lock); | ||
846 | |||
847 | kfree(sinfo); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h new file mode 100644 index 000000000000..700a155fbc78 --- /dev/null +++ b/drivers/pcmcia/soc_common.h | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/soc_common.h | ||
3 | * | ||
4 | * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> | ||
5 | * | ||
6 | * This file contains definitions for the PCMCIA support code common to | ||
7 | * integrated SOCs like the SA-11x0 and PXA2xx microprocessors. | ||
8 | */ | ||
9 | #ifndef _ASM_ARCH_PCMCIA | ||
10 | #define _ASM_ARCH_PCMCIA | ||
11 | |||
12 | /* include the world */ | ||
13 | #include <linux/cpufreq.h> | ||
14 | #include <pcmcia/version.h> | ||
15 | #include <pcmcia/cs_types.h> | ||
16 | #include <pcmcia/cs.h> | ||
17 | #include <pcmcia/ss.h> | ||
18 | #include <pcmcia/bulkmem.h> | ||
19 | #include <pcmcia/cistpl.h> | ||
20 | #include "cs_internal.h" | ||
21 | |||
22 | |||
23 | struct device; | ||
24 | struct pcmcia_low_level; | ||
25 | |||
26 | /* | ||
27 | * This structure encapsulates per-socket state which we might need to | ||
28 | * use when responding to a Card Services query of some kind. | ||
29 | */ | ||
30 | struct soc_pcmcia_socket { | ||
31 | struct pcmcia_socket socket; | ||
32 | |||
33 | /* | ||
34 | * Info from low level handler | ||
35 | */ | ||
36 | struct device *dev; | ||
37 | unsigned int nr; | ||
38 | unsigned int irq; | ||
39 | |||
40 | /* | ||
41 | * Core PCMCIA state | ||
42 | */ | ||
43 | struct pcmcia_low_level *ops; | ||
44 | |||
45 | unsigned int status; | ||
46 | socket_state_t cs_state; | ||
47 | |||
48 | unsigned short spd_io[MAX_IO_WIN]; | ||
49 | unsigned short spd_mem[MAX_WIN]; | ||
50 | unsigned short spd_attr[MAX_WIN]; | ||
51 | |||
52 | struct resource res_skt; | ||
53 | struct resource res_io; | ||
54 | struct resource res_mem; | ||
55 | struct resource res_attr; | ||
56 | void __iomem *virt_io; | ||
57 | |||
58 | unsigned int irq_state; | ||
59 | |||
60 | struct timer_list poll_timer; | ||
61 | struct list_head node; | ||
62 | }; | ||
63 | |||
64 | struct pcmcia_state { | ||
65 | unsigned detect: 1, | ||
66 | ready: 1, | ||
67 | bvd1: 1, | ||
68 | bvd2: 1, | ||
69 | wrprot: 1, | ||
70 | vs_3v: 1, | ||
71 | vs_Xv: 1; | ||
72 | }; | ||
73 | |||
74 | struct pcmcia_low_level { | ||
75 | struct module *owner; | ||
76 | |||
77 | /* first socket in system */ | ||
78 | int first; | ||
79 | /* nr of sockets */ | ||
80 | int nr; | ||
81 | |||
82 | int (*hw_init)(struct soc_pcmcia_socket *); | ||
83 | void (*hw_shutdown)(struct soc_pcmcia_socket *); | ||
84 | |||
85 | void (*socket_state)(struct soc_pcmcia_socket *, struct pcmcia_state *); | ||
86 | int (*configure_socket)(struct soc_pcmcia_socket *, const socket_state_t *); | ||
87 | |||
88 | /* | ||
89 | * Enable card status IRQs on (re-)initialisation. This can | ||
90 | * be called at initialisation, power management event, or | ||
91 | * pcmcia event. | ||
92 | */ | ||
93 | void (*socket_init)(struct soc_pcmcia_socket *); | ||
94 | |||
95 | /* | ||
96 | * Disable card status IRQs and PCMCIA bus on suspend. | ||
97 | */ | ||
98 | void (*socket_suspend)(struct soc_pcmcia_socket *); | ||
99 | |||
100 | /* | ||
101 | * Hardware specific timing routines. | ||
102 | * If provided, the get_timing routine overrides the SOC default. | ||
103 | */ | ||
104 | unsigned int (*get_timing)(struct soc_pcmcia_socket *, unsigned int, unsigned int); | ||
105 | int (*set_timing)(struct soc_pcmcia_socket *); | ||
106 | int (*show_timing)(struct soc_pcmcia_socket *, char *); | ||
107 | |||
108 | #ifdef CONFIG_CPU_FREQ | ||
109 | /* | ||
110 | * CPUFREQ support. | ||
111 | */ | ||
112 | int (*frequency_change)(struct soc_pcmcia_socket *, unsigned long, struct cpufreq_freqs *); | ||
113 | #endif | ||
114 | }; | ||
115 | |||
116 | |||
117 | struct pcmcia_irqs { | ||
118 | int sock; | ||
119 | int irq; | ||
120 | const char *str; | ||
121 | }; | ||
122 | |||
123 | struct soc_pcmcia_timing { | ||
124 | unsigned short io; | ||
125 | unsigned short mem; | ||
126 | unsigned short attr; | ||
127 | }; | ||
128 | |||
129 | extern int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); | ||
130 | extern void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); | ||
131 | extern void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); | ||
132 | extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); | ||
133 | extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *); | ||
134 | |||
135 | |||
136 | extern struct list_head soc_pcmcia_sockets; | ||
137 | extern struct semaphore soc_pcmcia_sockets_lock; | ||
138 | |||
139 | extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); | ||
140 | extern int soc_common_drv_pcmcia_remove(struct device *dev); | ||
141 | |||
142 | |||
143 | #ifdef DEBUG | ||
144 | |||
145 | extern void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, | ||
146 | int lvl, const char *fmt, ...); | ||
147 | |||
148 | #define debug(skt, lvl, fmt, arg...) \ | ||
149 | soc_pcmcia_debug(skt, __func__, lvl, fmt , ## arg) | ||
150 | |||
151 | #else | ||
152 | #define debug(skt, lvl, fmt, arg...) do { } while (0) | ||
153 | #endif | ||
154 | |||
155 | |||
156 | /* | ||
157 | * The PC Card Standard, Release 7, section 4.13.4, says that twIORD | ||
158 | * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has | ||
159 | * a minimum value of 165ns, as well. Section 4.7.2 (describing | ||
160 | * common and attribute memory write timing) says that twWE has a | ||
161 | * minimum value of 150ns for a 250ns cycle time (for 5V operation; | ||
162 | * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V | ||
163 | * operation, also section 4.7.4). Section 4.7.3 says that taOE | ||
164 | * has a maximum value of 150ns for a 300ns cycle time (for 5V | ||
165 | * operation), or 300ns for a 600ns cycle time (for 3.3V operation). | ||
166 | * | ||
167 | * When configuring memory maps, Card Services appears to adopt the policy | ||
168 | * that a memory access time of "0" means "use the default." The default | ||
169 | * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute | ||
170 | * and memory command width time is 150ns; the PCMCIA 3.3V attribute and | ||
171 | * memory command width time is 300ns. | ||
172 | */ | ||
173 | #define SOC_PCMCIA_IO_ACCESS (165) | ||
174 | #define SOC_PCMCIA_5V_MEM_ACCESS (150) | ||
175 | #define SOC_PCMCIA_3V_MEM_ACCESS (300) | ||
176 | #define SOC_PCMCIA_ATTR_MEM_ACCESS (300) | ||
177 | |||
178 | /* | ||
179 | * The socket driver actually works nicely in interrupt-driven form, | ||
180 | * so the (relatively infrequent) polling is "just to be sure." | ||
181 | */ | ||
182 | #define SOC_PCMCIA_POLL_PERIOD (2*HZ) | ||
183 | |||
184 | |||
185 | /* I/O pins replacing memory pins | ||
186 | * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) | ||
187 | * | ||
188 | * These signals change meaning when going from memory-only to | ||
189 | * memory-or-I/O interface: | ||
190 | */ | ||
191 | #define iostschg bvd1 | ||
192 | #define iospkr bvd2 | ||
193 | |||
194 | #endif | ||
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c new file mode 100644 index 000000000000..8eed03938214 --- /dev/null +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * socket_sysfs.c -- most of socket-related sysfs output | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * (C) 2003 - 2004 Dominik Brodowski | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/moduleparam.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/config.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/major.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <asm/system.h> | ||
29 | #include <asm/irq.h> | ||
30 | |||
31 | #define IN_CARD_SERVICES | ||
32 | #include <pcmcia/version.h> | ||
33 | #include <pcmcia/cs_types.h> | ||
34 | #include <pcmcia/ss.h> | ||
35 | #include <pcmcia/cs.h> | ||
36 | #include <pcmcia/bulkmem.h> | ||
37 | #include <pcmcia/cistpl.h> | ||
38 | #include <pcmcia/cisreg.h> | ||
39 | #include <pcmcia/ds.h> | ||
40 | #include "cs_internal.h" | ||
41 | |||
42 | #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) | ||
43 | |||
44 | static ssize_t pccard_show_type(struct class_device *dev, char *buf) | ||
45 | { | ||
46 | int val; | ||
47 | struct pcmcia_socket *s = to_socket(dev); | ||
48 | |||
49 | if (!(s->state & SOCKET_PRESENT)) | ||
50 | return -ENODEV; | ||
51 | s->ops->get_status(s, &val); | ||
52 | if (val & SS_CARDBUS) | ||
53 | return sprintf(buf, "32-bit\n"); | ||
54 | if (val & SS_DETECT) | ||
55 | return sprintf(buf, "16-bit\n"); | ||
56 | return sprintf(buf, "invalid\n"); | ||
57 | } | ||
58 | static CLASS_DEVICE_ATTR(card_type, 0400, pccard_show_type, NULL); | ||
59 | |||
60 | static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) | ||
61 | { | ||
62 | int val; | ||
63 | struct pcmcia_socket *s = to_socket(dev); | ||
64 | |||
65 | if (!(s->state & SOCKET_PRESENT)) | ||
66 | return -ENODEV; | ||
67 | s->ops->get_status(s, &val); | ||
68 | if (val & SS_3VCARD) | ||
69 | return sprintf(buf, "3.3V\n"); | ||
70 | if (val & SS_XVCARD) | ||
71 | return sprintf(buf, "X.XV\n"); | ||
72 | return sprintf(buf, "5.0V\n"); | ||
73 | } | ||
74 | static CLASS_DEVICE_ATTR(card_voltage, 0400, pccard_show_voltage, NULL); | ||
75 | |||
76 | static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) | ||
77 | { | ||
78 | struct pcmcia_socket *s = to_socket(dev); | ||
79 | if (!(s->state & SOCKET_PRESENT)) | ||
80 | return -ENODEV; | ||
81 | return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); | ||
82 | } | ||
83 | static CLASS_DEVICE_ATTR(card_vpp, 0400, pccard_show_vpp, NULL); | ||
84 | |||
85 | static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) | ||
86 | { | ||
87 | struct pcmcia_socket *s = to_socket(dev); | ||
88 | if (!(s->state & SOCKET_PRESENT)) | ||
89 | return -ENODEV; | ||
90 | return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); | ||
91 | } | ||
92 | static CLASS_DEVICE_ATTR(card_vcc, 0400, pccard_show_vcc, NULL); | ||
93 | |||
94 | |||
95 | static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) | ||
96 | { | ||
97 | ssize_t ret; | ||
98 | struct pcmcia_socket *s = to_socket(dev); | ||
99 | |||
100 | if (!count) | ||
101 | return -EINVAL; | ||
102 | |||
103 | ret = pcmcia_insert_card(s); | ||
104 | |||
105 | return ret ? ret : count; | ||
106 | } | ||
107 | static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); | ||
108 | |||
109 | static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) | ||
110 | { | ||
111 | ssize_t ret; | ||
112 | struct pcmcia_socket *s = to_socket(dev); | ||
113 | |||
114 | if (!count) | ||
115 | return -EINVAL; | ||
116 | |||
117 | ret = pcmcia_eject_card(s); | ||
118 | |||
119 | return ret ? ret : count; | ||
120 | } | ||
121 | static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); | ||
122 | |||
123 | |||
124 | static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) | ||
125 | { | ||
126 | struct pcmcia_socket *s = to_socket(dev); | ||
127 | return sprintf(buf, "0x%04x\n", s->irq_mask); | ||
128 | } | ||
129 | |||
130 | static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) | ||
131 | { | ||
132 | ssize_t ret; | ||
133 | struct pcmcia_socket *s = to_socket(dev); | ||
134 | u32 mask; | ||
135 | |||
136 | if (!count) | ||
137 | return -EINVAL; | ||
138 | |||
139 | ret = sscanf (buf, "0x%x\n", &mask); | ||
140 | |||
141 | if (ret == 1) { | ||
142 | s->irq_mask &= mask; | ||
143 | ret = 0; | ||
144 | } | ||
145 | |||
146 | return ret ? ret : count; | ||
147 | } | ||
148 | static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); | ||
149 | |||
150 | |||
151 | static ssize_t pccard_show_resource(struct class_device *dev, char *buf) | ||
152 | { | ||
153 | struct pcmcia_socket *s = to_socket(dev); | ||
154 | return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); | ||
155 | } | ||
156 | |||
157 | static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | struct pcmcia_socket *s = to_socket(dev); | ||
161 | |||
162 | if (!count) | ||
163 | return -EINVAL; | ||
164 | |||
165 | spin_lock_irqsave(&s->lock, flags); | ||
166 | if (!s->resource_setup_done) { | ||
167 | s->resource_setup_done = 1; | ||
168 | spin_unlock_irqrestore(&s->lock, flags); | ||
169 | |||
170 | down(&s->skt_sem); | ||
171 | if ((s->callback) && | ||
172 | (s->state & SOCKET_PRESENT) && | ||
173 | !(s->state & SOCKET_CARDBUS)) { | ||
174 | if (try_module_get(s->callback->owner)) { | ||
175 | s->callback->resources_done(s); | ||
176 | module_put(s->callback->owner); | ||
177 | } | ||
178 | } | ||
179 | up(&s->skt_sem); | ||
180 | |||
181 | return count; | ||
182 | } | ||
183 | spin_unlock_irqrestore(&s->lock, flags); | ||
184 | |||
185 | return count; | ||
186 | } | ||
187 | static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
188 | |||
189 | |||
190 | static struct class_device_attribute *pccard_socket_attributes[] = { | ||
191 | &class_device_attr_card_type, | ||
192 | &class_device_attr_card_voltage, | ||
193 | &class_device_attr_card_vpp, | ||
194 | &class_device_attr_card_vcc, | ||
195 | &class_device_attr_card_insert, | ||
196 | &class_device_attr_card_eject, | ||
197 | &class_device_attr_card_irq_mask, | ||
198 | &class_device_attr_available_resources_setup_done, | ||
199 | NULL, | ||
200 | }; | ||
201 | |||
202 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | ||
203 | { | ||
204 | struct class_device_attribute **attr; | ||
205 | int ret = 0; | ||
206 | |||
207 | for (attr = pccard_socket_attributes; *attr; attr++) { | ||
208 | ret = class_device_create_file(class_dev, *attr); | ||
209 | if (ret) | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) | ||
217 | { | ||
218 | struct class_device_attribute **attr; | ||
219 | |||
220 | for (attr = pccard_socket_attributes; *attr; attr++) | ||
221 | class_device_remove_file(class_dev, *attr); | ||
222 | } | ||
223 | |||
224 | struct class_interface pccard_sysfs_interface = { | ||
225 | .class = &pcmcia_socket_class, | ||
226 | .add = &pccard_sysfs_add_socket, | ||
227 | .remove = __devexit_p(&pccard_sysfs_remove_socket), | ||
228 | }; | ||
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c new file mode 100644 index 000000000000..aacbbb5f055d --- /dev/null +++ b/drivers/pcmcia/tcic.c | |||
@@ -0,0 +1,903 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | Device driver for Databook TCIC-2 PCMCIA controller | ||
4 | |||
5 | tcic.c 1.111 2000/02/15 04:13:12 | ||
6 | |||
7 | The contents of this file are subject to the Mozilla Public | ||
8 | License Version 1.1 (the "License"); you may not use this file | ||
9 | except in compliance with the License. You may obtain a copy of | ||
10 | the License at http://www.mozilla.org/MPL/ | ||
11 | |||
12 | Software distributed under the License is distributed on an "AS | ||
13 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
14 | implied. See the License for the specific language governing | ||
15 | rights and limitations under the License. | ||
16 | |||
17 | The initial developer of the original code is David A. Hinds | ||
18 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
19 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
20 | |||
21 | Alternatively, the contents of this file may be used under the | ||
22 | terms of the GNU General Public License version 2 (the "GPL"), in which | ||
23 | case the provisions of the GPL are applicable instead of the | ||
24 | above. If you wish to allow the use of your version of this file | ||
25 | only under the terms of the GPL and not to allow others to use | ||
26 | your version of this file under the MPL, indicate your decision | ||
27 | by deleting the provisions above and replace them with the notice | ||
28 | and other provisions required by the GPL. If you do not delete | ||
29 | the provisions above, a recipient may use your version of this | ||
30 | file under either the MPL or the GPL. | ||
31 | |||
32 | ======================================================================*/ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/types.h> | ||
38 | #include <linux/fcntl.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/errno.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <linux/timer.h> | ||
44 | #include <linux/ioport.h> | ||
45 | #include <linux/delay.h> | ||
46 | #include <linux/workqueue.h> | ||
47 | #include <linux/device.h> | ||
48 | #include <linux/bitops.h> | ||
49 | |||
50 | #include <asm/io.h> | ||
51 | #include <asm/system.h> | ||
52 | |||
53 | #include <pcmcia/version.h> | ||
54 | #include <pcmcia/cs_types.h> | ||
55 | #include <pcmcia/cs.h> | ||
56 | #include <pcmcia/ss.h> | ||
57 | #include "tcic.h" | ||
58 | |||
59 | #ifdef DEBUG | ||
60 | static int pc_debug; | ||
61 | |||
62 | module_param(pc_debug, int, 0644); | ||
63 | static const char version[] = | ||
64 | "tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)"; | ||
65 | |||
66 | #define debug(lvl, fmt, arg...) do { \ | ||
67 | if (pc_debug > (lvl)) \ | ||
68 | printk(KERN_DEBUG "tcic: " fmt , ## arg); \ | ||
69 | } while (0) | ||
70 | #else | ||
71 | #define debug(lvl, fmt, arg...) do { } while (0) | ||
72 | #endif | ||
73 | |||
74 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | ||
75 | MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver"); | ||
76 | MODULE_LICENSE("Dual MPL/GPL"); | ||
77 | |||
78 | /*====================================================================*/ | ||
79 | |||
80 | /* Parameters that can be set with 'insmod' */ | ||
81 | |||
82 | /* The base port address of the TCIC-2 chip */ | ||
83 | static unsigned long tcic_base = TCIC_BASE; | ||
84 | |||
85 | /* Specify a socket number to ignore */ | ||
86 | static int ignore = -1; | ||
87 | |||
88 | /* Probe for safe interrupts? */ | ||
89 | static int do_scan = 1; | ||
90 | |||
91 | /* Bit map of interrupts to choose from */ | ||
92 | static u_int irq_mask = 0xffff; | ||
93 | static int irq_list[16]; | ||
94 | static int irq_list_count; | ||
95 | |||
96 | /* The card status change interrupt -- 0 means autoselect */ | ||
97 | static int cs_irq; | ||
98 | |||
99 | /* Poll status interval -- 0 means default to interrupt */ | ||
100 | static int poll_interval; | ||
101 | |||
102 | /* Delay for card status double-checking */ | ||
103 | static int poll_quick = HZ/20; | ||
104 | |||
105 | /* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */ | ||
106 | static int cycle_time = 70; | ||
107 | |||
108 | module_param(tcic_base, ulong, 0444); | ||
109 | module_param(ignore, int, 0444); | ||
110 | module_param(do_scan, int, 0444); | ||
111 | module_param(irq_mask, int, 0444); | ||
112 | module_param_array(irq_list, int, &irq_list_count, 0444); | ||
113 | module_param(cs_irq, int, 0444); | ||
114 | module_param(poll_interval, int, 0444); | ||
115 | module_param(poll_quick, int, 0444); | ||
116 | module_param(cycle_time, int, 0444); | ||
117 | |||
118 | /*====================================================================*/ | ||
119 | |||
120 | static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs); | ||
121 | static void tcic_timer(u_long data); | ||
122 | static struct pccard_operations tcic_operations; | ||
123 | |||
124 | struct tcic_socket { | ||
125 | u_short psock; | ||
126 | u_char last_sstat; | ||
127 | u_char id; | ||
128 | struct pcmcia_socket socket; | ||
129 | }; | ||
130 | |||
131 | static struct timer_list poll_timer; | ||
132 | static int tcic_timer_pending; | ||
133 | |||
134 | static int sockets; | ||
135 | static struct tcic_socket socket_table[2]; | ||
136 | |||
137 | /*====================================================================*/ | ||
138 | |||
139 | /* Trick when selecting interrupts: the TCIC sktirq pin is supposed | ||
140 | to map to irq 11, but is coded as 0 or 1 in the irq registers. */ | ||
141 | #define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15) | ||
142 | |||
143 | #ifdef DEBUG_X | ||
144 | static u_char tcic_getb(u_char reg) | ||
145 | { | ||
146 | u_char val = inb(tcic_base+reg); | ||
147 | printk(KERN_DEBUG "tcic_getb(%#lx) = %#x\n", tcic_base+reg, val); | ||
148 | return val; | ||
149 | } | ||
150 | |||
151 | static u_short tcic_getw(u_char reg) | ||
152 | { | ||
153 | u_short val = inw(tcic_base+reg); | ||
154 | printk(KERN_DEBUG "tcic_getw(%#lx) = %#x\n", tcic_base+reg, val); | ||
155 | return val; | ||
156 | } | ||
157 | |||
158 | static void tcic_setb(u_char reg, u_char data) | ||
159 | { | ||
160 | printk(KERN_DEBUG "tcic_setb(%#lx, %#x)\n", tcic_base+reg, data); | ||
161 | outb(data, tcic_base+reg); | ||
162 | } | ||
163 | |||
164 | static void tcic_setw(u_char reg, u_short data) | ||
165 | { | ||
166 | printk(KERN_DEBUG "tcic_setw(%#lx, %#x)\n", tcic_base+reg, data); | ||
167 | outw(data, tcic_base+reg); | ||
168 | } | ||
169 | #else | ||
170 | #define tcic_getb(reg) inb(tcic_base+reg) | ||
171 | #define tcic_getw(reg) inw(tcic_base+reg) | ||
172 | #define tcic_setb(reg, data) outb(data, tcic_base+reg) | ||
173 | #define tcic_setw(reg, data) outw(data, tcic_base+reg) | ||
174 | #endif | ||
175 | |||
176 | static void tcic_setl(u_char reg, u_int data) | ||
177 | { | ||
178 | #ifdef DEBUG_X | ||
179 | printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data); | ||
180 | #endif | ||
181 | outw(data & 0xffff, tcic_base+reg); | ||
182 | outw(data >> 16, tcic_base+reg+2); | ||
183 | } | ||
184 | |||
185 | static u_char tcic_aux_getb(u_short reg) | ||
186 | { | ||
187 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | ||
188 | tcic_setb(TCIC_MODE, mode); | ||
189 | return tcic_getb(TCIC_AUX); | ||
190 | } | ||
191 | |||
192 | static void tcic_aux_setb(u_short reg, u_char data) | ||
193 | { | ||
194 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | ||
195 | tcic_setb(TCIC_MODE, mode); | ||
196 | tcic_setb(TCIC_AUX, data); | ||
197 | } | ||
198 | |||
199 | static u_short tcic_aux_getw(u_short reg) | ||
200 | { | ||
201 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | ||
202 | tcic_setb(TCIC_MODE, mode); | ||
203 | return tcic_getw(TCIC_AUX); | ||
204 | } | ||
205 | |||
206 | static void tcic_aux_setw(u_short reg, u_short data) | ||
207 | { | ||
208 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | ||
209 | tcic_setb(TCIC_MODE, mode); | ||
210 | tcic_setw(TCIC_AUX, data); | ||
211 | } | ||
212 | |||
213 | /*====================================================================*/ | ||
214 | |||
215 | /* Time conversion functions */ | ||
216 | |||
217 | static int to_cycles(int ns) | ||
218 | { | ||
219 | if (ns < 14) | ||
220 | return 0; | ||
221 | else | ||
222 | return 2*(ns-14)/cycle_time; | ||
223 | } | ||
224 | |||
225 | /*====================================================================*/ | ||
226 | |||
227 | static volatile u_int irq_hits; | ||
228 | |||
229 | static irqreturn_t __init tcic_irq_count(int irq, void *dev, struct pt_regs *regs) | ||
230 | { | ||
231 | irq_hits++; | ||
232 | return IRQ_HANDLED; | ||
233 | } | ||
234 | |||
235 | static u_int __init try_irq(int irq) | ||
236 | { | ||
237 | u_short cfg; | ||
238 | |||
239 | irq_hits = 0; | ||
240 | if (request_irq(irq, tcic_irq_count, 0, "irq scan", tcic_irq_count) != 0) | ||
241 | return -1; | ||
242 | mdelay(10); | ||
243 | if (irq_hits) { | ||
244 | free_irq(irq, tcic_irq_count); | ||
245 | return -1; | ||
246 | } | ||
247 | |||
248 | /* Generate one interrupt */ | ||
249 | cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00; | ||
250 | tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq)); | ||
251 | tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH); | ||
252 | tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM); | ||
253 | |||
254 | udelay(1000); | ||
255 | free_irq(irq, tcic_irq_count); | ||
256 | |||
257 | /* Turn off interrupts */ | ||
258 | tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF); | ||
259 | while (tcic_getb(TCIC_ICSR)) | ||
260 | tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM); | ||
261 | tcic_aux_setw(TCIC_AUX_SYSCFG, cfg); | ||
262 | |||
263 | return (irq_hits != 1); | ||
264 | } | ||
265 | |||
266 | static u_int __init irq_scan(u_int mask0) | ||
267 | { | ||
268 | u_int mask1; | ||
269 | int i; | ||
270 | |||
271 | #ifdef __alpha__ | ||
272 | #define PIC 0x4d0 | ||
273 | /* Don't probe level-triggered interrupts -- reserved for PCI */ | ||
274 | int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8); | ||
275 | if (level_mask) | ||
276 | mask0 &= ~level_mask; | ||
277 | #endif | ||
278 | |||
279 | mask1 = 0; | ||
280 | if (do_scan) { | ||
281 | for (i = 0; i < 16; i++) | ||
282 | if ((mask0 & (1 << i)) && (try_irq(i) == 0)) | ||
283 | mask1 |= (1 << i); | ||
284 | for (i = 0; i < 16; i++) | ||
285 | if ((mask1 & (1 << i)) && (try_irq(i) != 0)) { | ||
286 | mask1 ^= (1 << i); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | if (mask1) { | ||
291 | printk("scanned"); | ||
292 | } else { | ||
293 | /* Fallback: just find interrupts that aren't in use */ | ||
294 | for (i = 0; i < 16; i++) | ||
295 | if ((mask0 & (1 << i)) && | ||
296 | (request_irq(i, tcic_irq_count, 0, "x", tcic_irq_count) == 0)) { | ||
297 | mask1 |= (1 << i); | ||
298 | free_irq(i, tcic_irq_count); | ||
299 | } | ||
300 | printk("default"); | ||
301 | } | ||
302 | |||
303 | printk(") = "); | ||
304 | for (i = 0; i < 16; i++) | ||
305 | if (mask1 & (1<<i)) | ||
306 | printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i); | ||
307 | printk(" "); | ||
308 | |||
309 | return mask1; | ||
310 | } | ||
311 | |||
312 | /*====================================================================== | ||
313 | |||
314 | See if a card is present, powered up, in IO mode, and already | ||
315 | bound to a (non-PCMCIA) Linux driver. | ||
316 | |||
317 | We make an exception for cards that look like serial devices. | ||
318 | |||
319 | ======================================================================*/ | ||
320 | |||
321 | static int __init is_active(int s) | ||
322 | { | ||
323 | u_short scf1, ioctl, base, num; | ||
324 | u_char pwr, sstat; | ||
325 | u_int addr; | ||
326 | |||
327 | tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT) | ||
328 | | TCIC_ADDR_INDREG | TCIC_SCF1(s)); | ||
329 | scf1 = tcic_getw(TCIC_DATA); | ||
330 | pwr = tcic_getb(TCIC_PWR); | ||
331 | sstat = tcic_getb(TCIC_SSTAT); | ||
332 | addr = TCIC_IWIN(s, 0); | ||
333 | tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); | ||
334 | base = tcic_getw(TCIC_DATA); | ||
335 | tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); | ||
336 | ioctl = tcic_getw(TCIC_DATA); | ||
337 | |||
338 | if (ioctl & TCIC_ICTL_TINY) | ||
339 | num = 1; | ||
340 | else { | ||
341 | num = (base ^ (base-1)); | ||
342 | base = base & (base-1); | ||
343 | } | ||
344 | |||
345 | if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) && | ||
346 | (scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) && | ||
347 | ((base & 0xfeef) != 0x02e8)) { | ||
348 | struct resource *res = request_region(base, num, "tcic-2"); | ||
349 | if (!res) /* region is busy */ | ||
350 | return 1; | ||
351 | release_region(base, num); | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /*====================================================================== | ||
358 | |||
359 | This returns the revision code for the specified socket. | ||
360 | |||
361 | ======================================================================*/ | ||
362 | |||
363 | static int __init get_tcic_id(void) | ||
364 | { | ||
365 | u_short id; | ||
366 | |||
367 | tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG); | ||
368 | id = tcic_aux_getw(TCIC_AUX_ILOCK); | ||
369 | id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH; | ||
370 | tcic_aux_setw(TCIC_AUX_TEST, 0); | ||
371 | return id; | ||
372 | } | ||
373 | |||
374 | /*====================================================================*/ | ||
375 | |||
376 | static int tcic_drv_suspend(struct device *dev, pm_message_t state, u32 level) | ||
377 | { | ||
378 | int ret = 0; | ||
379 | if (level == SUSPEND_SAVE_STATE) | ||
380 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static int tcic_drv_resume(struct device *dev, u32 level) | ||
385 | { | ||
386 | int ret = 0; | ||
387 | if (level == RESUME_RESTORE_STATE) | ||
388 | ret = pcmcia_socket_dev_resume(dev); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static struct device_driver tcic_driver = { | ||
393 | .name = "tcic-pcmcia", | ||
394 | .bus = &platform_bus_type, | ||
395 | .suspend = tcic_drv_suspend, | ||
396 | .resume = tcic_drv_resume, | ||
397 | }; | ||
398 | |||
399 | static struct platform_device tcic_device = { | ||
400 | .name = "tcic-pcmcia", | ||
401 | .id = 0, | ||
402 | }; | ||
403 | |||
404 | |||
405 | static int __init init_tcic(void) | ||
406 | { | ||
407 | int i, sock, ret = 0; | ||
408 | u_int mask, scan; | ||
409 | |||
410 | if (driver_register(&tcic_driver)) | ||
411 | return -1; | ||
412 | |||
413 | printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: "); | ||
414 | sock = 0; | ||
415 | |||
416 | if (!request_region(tcic_base, 16, "tcic-2")) { | ||
417 | printk("could not allocate ports,\n "); | ||
418 | driver_unregister(&tcic_driver); | ||
419 | return -ENODEV; | ||
420 | } | ||
421 | else { | ||
422 | tcic_setw(TCIC_ADDR, 0); | ||
423 | if (tcic_getw(TCIC_ADDR) == 0) { | ||
424 | tcic_setw(TCIC_ADDR, 0xc3a5); | ||
425 | if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2; | ||
426 | } | ||
427 | if (sock == 0) { | ||
428 | /* See if resetting the controller does any good */ | ||
429 | tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET); | ||
430 | tcic_setb(TCIC_SCTRL, 0); | ||
431 | tcic_setw(TCIC_ADDR, 0); | ||
432 | if (tcic_getw(TCIC_ADDR) == 0) { | ||
433 | tcic_setw(TCIC_ADDR, 0xc3a5); | ||
434 | if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2; | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | if (sock == 0) { | ||
439 | printk("not found.\n"); | ||
440 | release_region(tcic_base, 16); | ||
441 | driver_unregister(&tcic_driver); | ||
442 | return -ENODEV; | ||
443 | } | ||
444 | |||
445 | sockets = 0; | ||
446 | for (i = 0; i < sock; i++) { | ||
447 | if ((i == ignore) || is_active(i)) continue; | ||
448 | socket_table[sockets].psock = i; | ||
449 | socket_table[sockets].id = get_tcic_id(); | ||
450 | |||
451 | socket_table[sockets].socket.owner = THIS_MODULE; | ||
452 | /* only 16-bit cards, memory windows must be size-aligned */ | ||
453 | /* No PCI or CardBus support */ | ||
454 | socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN; | ||
455 | /* irq 14, 11, 10, 7, 6, 5, 4, 3 */ | ||
456 | socket_table[sockets].socket.irq_mask = 0x4cf8; | ||
457 | /* 4K minimum window size */ | ||
458 | socket_table[sockets].socket.map_size = 0x1000; | ||
459 | sockets++; | ||
460 | } | ||
461 | |||
462 | switch (socket_table[0].id) { | ||
463 | case TCIC_ID_DB86082: | ||
464 | printk("DB86082"); break; | ||
465 | case TCIC_ID_DB86082A: | ||
466 | printk("DB86082A"); break; | ||
467 | case TCIC_ID_DB86084: | ||
468 | printk("DB86084"); break; | ||
469 | case TCIC_ID_DB86084A: | ||
470 | printk("DB86084A"); break; | ||
471 | case TCIC_ID_DB86072: | ||
472 | printk("DB86072"); break; | ||
473 | case TCIC_ID_DB86184: | ||
474 | printk("DB86184"); break; | ||
475 | case TCIC_ID_DB86082B: | ||
476 | printk("DB86082B"); break; | ||
477 | default: | ||
478 | printk("Unknown ID 0x%02x", socket_table[0].id); | ||
479 | } | ||
480 | |||
481 | /* Set up polling */ | ||
482 | poll_timer.function = &tcic_timer; | ||
483 | poll_timer.data = 0; | ||
484 | init_timer(&poll_timer); | ||
485 | |||
486 | /* Build interrupt mask */ | ||
487 | printk(", %d sockets\n" KERN_INFO " irq list (", sockets); | ||
488 | if (irq_list_count == 0) | ||
489 | mask = irq_mask; | ||
490 | else | ||
491 | for (i = mask = 0; i < irq_list_count; i++) | ||
492 | mask |= (1<<irq_list[i]); | ||
493 | |||
494 | /* irq 14, 11, 10, 7, 6, 5, 4, 3 */ | ||
495 | mask &= 0x4cf8; | ||
496 | /* Scan interrupts */ | ||
497 | mask = irq_scan(mask); | ||
498 | for (i=0;i<sockets;i++) | ||
499 | socket_table[i].socket.irq_mask = mask; | ||
500 | |||
501 | /* Check for only two interrupts available */ | ||
502 | scan = (mask & (mask-1)); | ||
503 | if (((scan & (scan-1)) == 0) && (poll_interval == 0)) | ||
504 | poll_interval = HZ; | ||
505 | |||
506 | if (poll_interval == 0) { | ||
507 | /* Avoid irq 12 unless it is explicitly requested */ | ||
508 | u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); | ||
509 | for (i = 15; i > 0; i--) | ||
510 | if ((cs_mask & (1 << i)) && | ||
511 | (request_irq(i, tcic_interrupt, 0, "tcic", | ||
512 | tcic_interrupt) == 0)) | ||
513 | break; | ||
514 | cs_irq = i; | ||
515 | if (cs_irq == 0) poll_interval = HZ; | ||
516 | } | ||
517 | |||
518 | if (socket_table[0].socket.irq_mask & (1 << 11)) | ||
519 | printk("sktirq is irq 11, "); | ||
520 | if (cs_irq != 0) | ||
521 | printk("status change on irq %d\n", cs_irq); | ||
522 | else | ||
523 | printk("polled status, interval = %d ms\n", | ||
524 | poll_interval * 1000 / HZ); | ||
525 | |||
526 | for (i = 0; i < sockets; i++) { | ||
527 | tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT); | ||
528 | socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT); | ||
529 | } | ||
530 | |||
531 | /* jump start interrupt handler, if needed */ | ||
532 | tcic_interrupt(0, NULL, NULL); | ||
533 | |||
534 | platform_device_register(&tcic_device); | ||
535 | |||
536 | for (i = 0; i < sockets; i++) { | ||
537 | socket_table[i].socket.ops = &tcic_operations; | ||
538 | socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; | ||
539 | socket_table[i].socket.dev.dev = &tcic_device.dev; | ||
540 | ret = pcmcia_register_socket(&socket_table[i].socket); | ||
541 | if (ret && i) | ||
542 | pcmcia_unregister_socket(&socket_table[0].socket); | ||
543 | } | ||
544 | |||
545 | return ret; | ||
546 | |||
547 | return 0; | ||
548 | |||
549 | } /* init_tcic */ | ||
550 | |||
551 | /*====================================================================*/ | ||
552 | |||
553 | static void __exit exit_tcic(void) | ||
554 | { | ||
555 | int i; | ||
556 | |||
557 | del_timer_sync(&poll_timer); | ||
558 | if (cs_irq != 0) { | ||
559 | tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); | ||
560 | free_irq(cs_irq, tcic_interrupt); | ||
561 | } | ||
562 | release_region(tcic_base, 16); | ||
563 | |||
564 | for (i = 0; i < sockets; i++) { | ||
565 | pcmcia_unregister_socket(&socket_table[i].socket); | ||
566 | } | ||
567 | |||
568 | platform_device_unregister(&tcic_device); | ||
569 | driver_unregister(&tcic_driver); | ||
570 | } /* exit_tcic */ | ||
571 | |||
572 | /*====================================================================*/ | ||
573 | |||
574 | static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
575 | { | ||
576 | int i, quick = 0; | ||
577 | u_char latch, sstat; | ||
578 | u_short psock; | ||
579 | u_int events; | ||
580 | static volatile int active = 0; | ||
581 | |||
582 | if (active) { | ||
583 | printk(KERN_NOTICE "tcic: reentered interrupt handler!\n"); | ||
584 | return IRQ_NONE; | ||
585 | } else | ||
586 | active = 1; | ||
587 | |||
588 | debug(2, "tcic_interrupt()\n"); | ||
589 | |||
590 | for (i = 0; i < sockets; i++) { | ||
591 | psock = socket_table[i].psock; | ||
592 | tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | ||
593 | | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); | ||
594 | sstat = tcic_getb(TCIC_SSTAT); | ||
595 | latch = sstat ^ socket_table[psock].last_sstat; | ||
596 | socket_table[i].last_sstat = sstat; | ||
597 | if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) { | ||
598 | tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR); | ||
599 | quick = 1; | ||
600 | } | ||
601 | if (latch == 0) | ||
602 | continue; | ||
603 | events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0; | ||
604 | events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0; | ||
605 | if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { | ||
606 | events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; | ||
607 | } else { | ||
608 | events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0; | ||
609 | events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; | ||
610 | events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; | ||
611 | } | ||
612 | if (events) { | ||
613 | pcmcia_parse_events(&socket_table[i].socket, events); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | /* Schedule next poll, if needed */ | ||
618 | if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) { | ||
619 | poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval); | ||
620 | add_timer(&poll_timer); | ||
621 | tcic_timer_pending = 1; | ||
622 | } | ||
623 | active = 0; | ||
624 | |||
625 | debug(2, "interrupt done\n"); | ||
626 | return IRQ_HANDLED; | ||
627 | } /* tcic_interrupt */ | ||
628 | |||
629 | static void tcic_timer(u_long data) | ||
630 | { | ||
631 | debug(2, "tcic_timer()\n"); | ||
632 | tcic_timer_pending = 0; | ||
633 | tcic_interrupt(0, NULL, NULL); | ||
634 | } /* tcic_timer */ | ||
635 | |||
636 | /*====================================================================*/ | ||
637 | |||
638 | static int tcic_get_status(struct pcmcia_socket *sock, u_int *value) | ||
639 | { | ||
640 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
641 | u_char reg; | ||
642 | |||
643 | tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | ||
644 | | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); | ||
645 | reg = tcic_getb(TCIC_SSTAT); | ||
646 | *value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0; | ||
647 | *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0; | ||
648 | if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { | ||
649 | *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; | ||
650 | } else { | ||
651 | *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0; | ||
652 | *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; | ||
653 | *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; | ||
654 | } | ||
655 | reg = tcic_getb(TCIC_PWR); | ||
656 | if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock))) | ||
657 | *value |= SS_POWERON; | ||
658 | debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value); | ||
659 | return 0; | ||
660 | } /* tcic_get_status */ | ||
661 | |||
662 | /*====================================================================*/ | ||
663 | |||
664 | static int tcic_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
665 | { | ||
666 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
667 | u_char reg; | ||
668 | u_short scf1, scf2; | ||
669 | |||
670 | tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | ||
671 | | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); | ||
672 | scf1 = tcic_getw(TCIC_DATA); | ||
673 | state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0; | ||
674 | state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0; | ||
675 | state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0; | ||
676 | if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA) | ||
677 | state->flags |= SS_OUTPUT_ENA; | ||
678 | state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK; | ||
679 | if (state->io_irq == 1) state->io_irq = 11; | ||
680 | |||
681 | reg = tcic_getb(TCIC_PWR); | ||
682 | state->Vcc = state->Vpp = 0; | ||
683 | if (reg & TCIC_PWR_VCC(psock)) { | ||
684 | if (reg & TCIC_PWR_VPP(psock)) | ||
685 | state->Vcc = 50; | ||
686 | else | ||
687 | state->Vcc = state->Vpp = 50; | ||
688 | } else { | ||
689 | if (reg & TCIC_PWR_VPP(psock)) { | ||
690 | state->Vcc = 50; | ||
691 | state->Vpp = 120; | ||
692 | } | ||
693 | } | ||
694 | reg = tcic_aux_getb(TCIC_AUX_ILOCK); | ||
695 | state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0; | ||
696 | |||
697 | /* Card status change interrupt mask */ | ||
698 | tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); | ||
699 | scf2 = tcic_getw(TCIC_DATA); | ||
700 | state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT; | ||
701 | if (state->flags & SS_IOCARD) { | ||
702 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG; | ||
703 | } else { | ||
704 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD; | ||
705 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN; | ||
706 | state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY; | ||
707 | } | ||
708 | |||
709 | debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
710 | "io_irq %d, csc_mask %#2.2x\n", psock, state->flags, | ||
711 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
712 | return 0; | ||
713 | } /* tcic_get_socket */ | ||
714 | |||
715 | /*====================================================================*/ | ||
716 | |||
717 | static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
718 | { | ||
719 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
720 | u_char reg; | ||
721 | u_short scf1, scf2; | ||
722 | |||
723 | debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | ||
724 | "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags, | ||
725 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
726 | tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG); | ||
727 | |||
728 | reg = tcic_getb(TCIC_PWR); | ||
729 | reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock)); | ||
730 | |||
731 | if (state->Vcc == 50) { | ||
732 | switch (state->Vpp) { | ||
733 | case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break; | ||
734 | case 50: reg |= TCIC_PWR_VCC(psock); break; | ||
735 | case 120: reg |= TCIC_PWR_VPP(psock); break; | ||
736 | default: return -EINVAL; | ||
737 | } | ||
738 | } else if (state->Vcc != 0) | ||
739 | return -EINVAL; | ||
740 | |||
741 | if (reg != tcic_getb(TCIC_PWR)) | ||
742 | tcic_setb(TCIC_PWR, reg); | ||
743 | |||
744 | reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT; | ||
745 | if (state->flags & SS_OUTPUT_ENA) { | ||
746 | tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA); | ||
747 | reg |= TCIC_ILOCK_CRESENA; | ||
748 | } else | ||
749 | tcic_setb(TCIC_SCTRL, 0); | ||
750 | if (state->flags & SS_RESET) | ||
751 | reg |= TCIC_ILOCK_CRESET; | ||
752 | tcic_aux_setb(TCIC_AUX_ILOCK, reg); | ||
753 | |||
754 | tcic_setw(TCIC_ADDR, TCIC_SCF1(psock)); | ||
755 | scf1 = TCIC_SCF1_FINPACK; | ||
756 | scf1 |= TCIC_IRQ(state->io_irq); | ||
757 | if (state->flags & SS_IOCARD) { | ||
758 | scf1 |= TCIC_SCF1_IOSTS; | ||
759 | if (state->flags & SS_SPKR_ENA) | ||
760 | scf1 |= TCIC_SCF1_SPKR; | ||
761 | if (state->flags & SS_DMA_MODE) | ||
762 | scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT; | ||
763 | } | ||
764 | tcic_setw(TCIC_DATA, scf1); | ||
765 | |||
766 | /* Some general setup stuff, and configure status interrupt */ | ||
767 | reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250); | ||
768 | tcic_aux_setb(TCIC_AUX_WCTL, reg); | ||
769 | tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00| | ||
770 | TCIC_IRQ(cs_irq)); | ||
771 | |||
772 | /* Card status change interrupt mask */ | ||
773 | tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); | ||
774 | scf2 = TCIC_SCF2_MALL; | ||
775 | if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD; | ||
776 | if (state->flags & SS_IOCARD) { | ||
777 | if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1; | ||
778 | } else { | ||
779 | if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1; | ||
780 | if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2; | ||
781 | if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY; | ||
782 | } | ||
783 | tcic_setw(TCIC_DATA, scf2); | ||
784 | /* For the ISA bus, the irq should be active-high totem-pole */ | ||
785 | tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH); | ||
786 | |||
787 | return 0; | ||
788 | } /* tcic_set_socket */ | ||
789 | |||
790 | /*====================================================================*/ | ||
791 | |||
792 | static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | ||
793 | { | ||
794 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
795 | u_int addr; | ||
796 | u_short base, len, ioctl; | ||
797 | |||
798 | debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " | ||
799 | "%#lx-%#lx)\n", psock, io->map, io->flags, | ||
800 | io->speed, io->start, io->stop); | ||
801 | if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || | ||
802 | (io->stop < io->start)) return -EINVAL; | ||
803 | tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); | ||
804 | addr = TCIC_IWIN(psock, io->map); | ||
805 | |||
806 | base = io->start; len = io->stop - io->start; | ||
807 | /* Check to see that len+1 is power of two, etc */ | ||
808 | if ((len & (len+1)) || (base & len)) return -EINVAL; | ||
809 | base |= (len+1)>>1; | ||
810 | tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); | ||
811 | tcic_setw(TCIC_DATA, base); | ||
812 | |||
813 | ioctl = (psock << TCIC_ICTL_SS_SHFT); | ||
814 | ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0; | ||
815 | ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0; | ||
816 | ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK; | ||
817 | if (!(io->flags & MAP_AUTOSZ)) { | ||
818 | ioctl |= TCIC_ICTL_QUIET; | ||
819 | ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8; | ||
820 | } | ||
821 | tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); | ||
822 | tcic_setw(TCIC_DATA, ioctl); | ||
823 | |||
824 | return 0; | ||
825 | } /* tcic_set_io_map */ | ||
826 | |||
827 | /*====================================================================*/ | ||
828 | |||
829 | static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) | ||
830 | { | ||
831 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
832 | u_short addr, ctl; | ||
833 | u_long base, len, mmap; | ||
834 | |||
835 | debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, " | ||
836 | "%#lx-%#lx, %#x)\n", psock, mem->map, mem->flags, | ||
837 | mem->speed, mem->res->start, mem->res->end, mem->card_start); | ||
838 | if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || | ||
839 | (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) || | ||
840 | (mem->res->start > mem->res->end) || (mem->speed > 1000)) | ||
841 | return -EINVAL; | ||
842 | tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); | ||
843 | addr = TCIC_MWIN(psock, mem->map); | ||
844 | |||
845 | base = mem->res->start; len = mem->res->end - mem->res->start; | ||
846 | if ((len & (len+1)) || (base & len)) return -EINVAL; | ||
847 | if (len == 0x0fff) | ||
848 | base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT; | ||
849 | else | ||
850 | base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT; | ||
851 | tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); | ||
852 | tcic_setw(TCIC_DATA, base); | ||
853 | |||
854 | mmap = mem->card_start - mem->res->start; | ||
855 | mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK; | ||
856 | if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG; | ||
857 | tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); | ||
858 | tcic_setw(TCIC_DATA, mmap); | ||
859 | |||
860 | ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT); | ||
861 | ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK; | ||
862 | ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8; | ||
863 | ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0; | ||
864 | ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0; | ||
865 | tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); | ||
866 | tcic_setw(TCIC_DATA, ctl); | ||
867 | |||
868 | return 0; | ||
869 | } /* tcic_set_mem_map */ | ||
870 | |||
871 | /*====================================================================*/ | ||
872 | |||
873 | static int tcic_init(struct pcmcia_socket *s) | ||
874 | { | ||
875 | int i; | ||
876 | struct resource res = { .start = 0, .end = 0x1000 }; | ||
877 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
878 | pccard_mem_map mem = { .res = &res, }; | ||
879 | |||
880 | for (i = 0; i < 2; i++) { | ||
881 | io.map = i; | ||
882 | tcic_set_io_map(s, &io); | ||
883 | } | ||
884 | for (i = 0; i < 5; i++) { | ||
885 | mem.map = i; | ||
886 | tcic_set_mem_map(s, &mem); | ||
887 | } | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static struct pccard_operations tcic_operations = { | ||
892 | .init = tcic_init, | ||
893 | .get_status = tcic_get_status, | ||
894 | .get_socket = tcic_get_socket, | ||
895 | .set_socket = tcic_set_socket, | ||
896 | .set_io_map = tcic_set_io_map, | ||
897 | .set_mem_map = tcic_set_mem_map, | ||
898 | }; | ||
899 | |||
900 | /*====================================================================*/ | ||
901 | |||
902 | module_init(init_tcic); | ||
903 | module_exit(exit_tcic); | ||
diff --git a/drivers/pcmcia/tcic.h b/drivers/pcmcia/tcic.h new file mode 100644 index 000000000000..2c0b8f65ad6c --- /dev/null +++ b/drivers/pcmcia/tcic.h | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * tcic.h 1.13 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_TCIC_H | ||
31 | #define _LINUX_TCIC_H | ||
32 | |||
33 | #define TCIC_BASE 0x240 | ||
34 | |||
35 | /* offsets of registers from TCIC_BASE */ | ||
36 | #define TCIC_DATA 0x00 | ||
37 | #define TCIC_ADDR 0x02 | ||
38 | #define TCIC_SCTRL 0x06 | ||
39 | #define TCIC_SSTAT 0x07 | ||
40 | #define TCIC_MODE 0x08 | ||
41 | #define TCIC_PWR 0x09 | ||
42 | #define TCIC_EDC 0x0A | ||
43 | #define TCIC_ICSR 0x0C | ||
44 | #define TCIC_IENA 0x0D | ||
45 | #define TCIC_AUX 0x0E | ||
46 | |||
47 | #define TCIC_SS_SHFT 12 | ||
48 | #define TCIC_SS_MASK 0x7000 | ||
49 | |||
50 | /* Flags for TCIC_ADDR */ | ||
51 | #define TCIC_ADR2_REG 0x8000 | ||
52 | #define TCIC_ADR2_INDREG 0x0800 | ||
53 | |||
54 | #define TCIC_ADDR_REG 0x80000000 | ||
55 | #define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16) | ||
56 | #define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16) | ||
57 | #define TCIC_ADDR_INDREG 0x08000000 | ||
58 | #define TCIC_ADDR_IO 0x04000000 | ||
59 | #define TCIC_ADDR_MASK 0x03ffffff | ||
60 | |||
61 | /* Flags for TCIC_SCTRL */ | ||
62 | #define TCIC_SCTRL_ENA 0x01 | ||
63 | #define TCIC_SCTRL_INCMODE 0x18 | ||
64 | #define TCIC_SCTRL_INCMODE_HOLD 0x00 | ||
65 | #define TCIC_SCTRL_INCMODE_WORD 0x08 | ||
66 | #define TCIC_SCTRL_INCMODE_REG 0x10 | ||
67 | #define TCIC_SCTRL_INCMODE_AUTO 0x18 | ||
68 | #define TCIC_SCTRL_EDCSUM 0x20 | ||
69 | #define TCIC_SCTRL_RESET 0x80 | ||
70 | |||
71 | /* Flags for TCIC_SSTAT */ | ||
72 | #define TCIC_SSTAT_6US 0x01 | ||
73 | #define TCIC_SSTAT_10US 0x02 | ||
74 | #define TCIC_SSTAT_PROGTIME 0x04 | ||
75 | #define TCIC_SSTAT_LBAT1 0x08 | ||
76 | #define TCIC_SSTAT_LBAT2 0x10 | ||
77 | #define TCIC_SSTAT_RDY 0x20 /* Inverted */ | ||
78 | #define TCIC_SSTAT_WP 0x40 | ||
79 | #define TCIC_SSTAT_CD 0x80 /* Card detect */ | ||
80 | |||
81 | /* Flags for TCIC_MODE */ | ||
82 | #define TCIC_MODE_PGMMASK 0x1f | ||
83 | #define TCIC_MODE_NORMAL 0x00 | ||
84 | #define TCIC_MODE_PGMWR 0x01 | ||
85 | #define TCIC_MODE_PGMRD 0x02 | ||
86 | #define TCIC_MODE_PGMCE 0x04 | ||
87 | #define TCIC_MODE_PGMDBW 0x08 | ||
88 | #define TCIC_MODE_PGMWORD 0x10 | ||
89 | #define TCIC_MODE_AUXSEL_MASK 0xe0 | ||
90 | |||
91 | /* Registers accessed through TCIC_AUX, by setting TCIC_MODE */ | ||
92 | #define TCIC_AUX_TCTL (0<<5) | ||
93 | #define TCIC_AUX_PCTL (1<<5) | ||
94 | #define TCIC_AUX_WCTL (2<<5) | ||
95 | #define TCIC_AUX_EXTERN (3<<5) | ||
96 | #define TCIC_AUX_PDATA (4<<5) | ||
97 | #define TCIC_AUX_SYSCFG (5<<5) | ||
98 | #define TCIC_AUX_ILOCK (6<<5) | ||
99 | #define TCIC_AUX_TEST (7<<5) | ||
100 | |||
101 | /* Flags for TCIC_PWR */ | ||
102 | #define TCIC_PWR_VCC(sock) (0x01<<(sock)) | ||
103 | #define TCIC_PWR_VCC_MASK 0x03 | ||
104 | #define TCIC_PWR_VPP(sock) (0x08<<(sock)) | ||
105 | #define TCIC_PWR_VPP_MASK 0x18 | ||
106 | #define TCIC_PWR_CLIMENA 0x40 | ||
107 | #define TCIC_PWR_CLIMSTAT 0x80 | ||
108 | |||
109 | /* Flags for TCIC_ICSR */ | ||
110 | #define TCIC_ICSR_CLEAR 0x01 | ||
111 | #define TCIC_ICSR_SET 0x02 | ||
112 | #define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET) | ||
113 | #define TCIC_ICSR_STOPCPU 0x04 | ||
114 | #define TCIC_ICSR_ILOCK 0x08 | ||
115 | #define TCIC_ICSR_PROGTIME 0x10 | ||
116 | #define TCIC_ICSR_ERR 0x20 | ||
117 | #define TCIC_ICSR_CDCHG 0x40 | ||
118 | #define TCIC_ICSR_IOCHK 0x80 | ||
119 | |||
120 | /* Flags for TCIC_IENA */ | ||
121 | #define TCIC_IENA_CFG_MASK 0x03 | ||
122 | #define TCIC_IENA_CFG_OFF 0x00 /* disabled */ | ||
123 | #define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */ | ||
124 | #define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */ | ||
125 | #define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */ | ||
126 | #define TCIC_IENA_ILOCK 0x08 | ||
127 | #define TCIC_IENA_PROGTIME 0x10 | ||
128 | #define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */ | ||
129 | #define TCIC_IENA_CDCHG 0x40 | ||
130 | |||
131 | /* Flags for TCIC_AUX_WCTL */ | ||
132 | #define TCIC_WAIT_COUNT_MASK 0x001f | ||
133 | #define TCIC_WAIT_ASYNC 0x0020 | ||
134 | #define TCIC_WAIT_SENSE 0x0040 | ||
135 | #define TCIC_WAIT_SRC 0x0080 | ||
136 | #define TCIC_WCTL_WR 0x0100 | ||
137 | #define TCIC_WCTL_RD 0x0200 | ||
138 | #define TCIC_WCTL_CE 0x0400 | ||
139 | #define TCIC_WCTL_LLBAT1 0x0800 | ||
140 | #define TCIC_WCTL_LLBAT2 0x1000 | ||
141 | #define TCIC_WCTL_LRDY 0x2000 | ||
142 | #define TCIC_WCTL_LWP 0x4000 | ||
143 | #define TCIC_WCTL_LCD 0x8000 | ||
144 | |||
145 | /* Flags for TCIC_AUX_SYSCFG */ | ||
146 | #define TCIC_SYSCFG_IRQ_MASK 0x000f | ||
147 | #define TCIC_SYSCFG_MCSFULL 0x0010 | ||
148 | #define TCIC_SYSCFG_IO1723 0x0020 | ||
149 | #define TCIC_SYSCFG_MCSXB 0x0040 | ||
150 | #define TCIC_SYSCFG_ICSXB 0x0080 | ||
151 | #define TCIC_SYSCFG_NOPDN 0x0100 | ||
152 | #define TCIC_SYSCFG_MPSEL_SHFT 9 | ||
153 | #define TCIC_SYSCFG_MPSEL_MASK 0x0e00 | ||
154 | #define TCIC_SYSCFG_MPSENSE 0x2000 | ||
155 | #define TCIC_SYSCFG_AUTOBUSY 0x4000 | ||
156 | #define TCIC_SYSCFG_ACC 0x8000 | ||
157 | |||
158 | #define TCIC_ILOCK_OUT 0x01 | ||
159 | #define TCIC_ILOCK_SENSE 0x02 | ||
160 | #define TCIC_ILOCK_CRESET 0x04 | ||
161 | #define TCIC_ILOCK_CRESENA 0x08 | ||
162 | #define TCIC_ILOCK_CWAIT 0x10 | ||
163 | #define TCIC_ILOCK_CWAITSNS 0x20 | ||
164 | #define TCIC_ILOCK_HOLD_MASK 0xc0 | ||
165 | #define TCIC_ILOCK_HOLD_CCLK 0xc0 | ||
166 | |||
167 | #define TCIC_ILOCKTEST_ID_SH 8 | ||
168 | #define TCIC_ILOCKTEST_ID_MASK 0x7f00 | ||
169 | #define TCIC_ILOCKTEST_MCIC_1 0x8000 | ||
170 | |||
171 | #define TCIC_ID_DB86082 0x02 | ||
172 | #define TCIC_ID_DB86082A 0x03 | ||
173 | #define TCIC_ID_DB86084 0x04 | ||
174 | #define TCIC_ID_DB86084A 0x08 | ||
175 | #define TCIC_ID_DB86072 0x15 | ||
176 | #define TCIC_ID_DB86184 0x14 | ||
177 | #define TCIC_ID_DB86082B 0x17 | ||
178 | |||
179 | #define TCIC_TEST_DIAG 0x8000 | ||
180 | |||
181 | /* | ||
182 | * Indirectly addressed registers | ||
183 | */ | ||
184 | |||
185 | #define TCIC_SCF1(sock) ((sock)<<3) | ||
186 | #define TCIC_SCF2(sock) (((sock)<<3)+2) | ||
187 | |||
188 | /* Flags for SCF1 */ | ||
189 | #define TCIC_SCF1_IRQ_MASK 0x000f | ||
190 | #define TCIC_SCF1_IRQ_OFF 0x0000 | ||
191 | #define TCIC_SCF1_IRQOC 0x0010 | ||
192 | #define TCIC_SCF1_PCVT 0x0020 | ||
193 | #define TCIC_SCF1_IRDY 0x0040 | ||
194 | #define TCIC_SCF1_ATA 0x0080 | ||
195 | #define TCIC_SCF1_DMA_SHIFT 8 | ||
196 | #define TCIC_SCF1_DMA_MASK 0x0700 | ||
197 | #define TCIC_SCF1_DMA_OFF 0 | ||
198 | #define TCIC_SCF1_DREQ2 2 | ||
199 | #define TCIC_SCF1_IOSTS 0x0800 | ||
200 | #define TCIC_SCF1_SPKR 0x1000 | ||
201 | #define TCIC_SCF1_FINPACK 0x2000 | ||
202 | #define TCIC_SCF1_DELWR 0x4000 | ||
203 | #define TCIC_SCF1_HD7IDE 0x8000 | ||
204 | |||
205 | /* Flags for SCF2 */ | ||
206 | #define TCIC_SCF2_RI 0x0001 | ||
207 | #define TCIC_SCF2_IDBR 0x0002 | ||
208 | #define TCIC_SCF2_MDBR 0x0004 | ||
209 | #define TCIC_SCF2_MLBAT1 0x0008 | ||
210 | #define TCIC_SCF2_MLBAT2 0x0010 | ||
211 | #define TCIC_SCF2_MRDY 0x0020 | ||
212 | #define TCIC_SCF2_MWP 0x0040 | ||
213 | #define TCIC_SCF2_MCD 0x0080 | ||
214 | #define TCIC_SCF2_MALL 0x00f8 | ||
215 | |||
216 | /* Indirect addresses for memory window registers */ | ||
217 | #define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3)) | ||
218 | #define TCIC_MBASE_X 2 | ||
219 | #define TCIC_MMAP_X 4 | ||
220 | #define TCIC_MCTL_X 6 | ||
221 | |||
222 | #define TCIC_MBASE_4K_BIT 0x4000 | ||
223 | #define TCIC_MBASE_HA_SHFT 12 | ||
224 | #define TCIC_MBASE_HA_MASK 0x0fff | ||
225 | |||
226 | #define TCIC_MMAP_REG 0x8000 | ||
227 | #define TCIC_MMAP_CA_SHFT 12 | ||
228 | #define TCIC_MMAP_CA_MASK 0x3fff | ||
229 | |||
230 | #define TCIC_MCTL_WSCNT_MASK 0x001f | ||
231 | #define TCIC_MCTL_WCLK 0x0020 | ||
232 | #define TCIC_MCTL_WCLK_CCLK 0x0000 | ||
233 | #define TCIC_MCTL_WCLK_BCLK 0x0020 | ||
234 | #define TCIC_MCTL_QUIET 0x0040 | ||
235 | #define TCIC_MCTL_WP 0x0080 | ||
236 | #define TCIC_MCTL_ACC 0x0100 | ||
237 | #define TCIC_MCTL_KE 0x0200 | ||
238 | #define TCIC_MCTL_EDC 0x0400 | ||
239 | #define TCIC_MCTL_B8 0x0800 | ||
240 | #define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT | ||
241 | #define TCIC_MCTL_SS_MASK TCIC_SS_MASK | ||
242 | #define TCIC_MCTL_ENA 0x8000 | ||
243 | |||
244 | /* Indirect addresses for I/O window registers */ | ||
245 | #define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2)) | ||
246 | #define TCIC_IBASE_X 0 | ||
247 | #define TCIC_ICTL_X 2 | ||
248 | |||
249 | #define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK | ||
250 | #define TCIC_ICTL_QUIET TCIC_MCTL_QUIET | ||
251 | #define TCIC_ICTL_1K 0x0080 | ||
252 | #define TCIC_ICTL_PASS16 0x0100 | ||
253 | #define TCIC_ICTL_ACC TCIC_MCTL_ACC | ||
254 | #define TCIC_ICTL_TINY 0x0200 | ||
255 | #define TCIC_ICTL_B16 0x0400 | ||
256 | #define TCIC_ICTL_B8 TCIC_MCTL_B8 | ||
257 | #define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8) | ||
258 | #define TCIC_ICTL_BW_DYN 0 | ||
259 | #define TCIC_ICTL_BW_8 TCIC_ICTL_B8 | ||
260 | #define TCIC_ICTL_BW_16 TCIC_ICTL_B16 | ||
261 | #define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8) | ||
262 | #define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT | ||
263 | #define TCIC_ICTL_SS_MASK TCIC_SS_MASK | ||
264 | #define TCIC_ICTL_ENA TCIC_MCTL_ENA | ||
265 | |||
266 | #endif /* _LINUX_TCIC_H */ | ||
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h new file mode 100644 index 000000000000..52c073a9d7e4 --- /dev/null +++ b/drivers/pcmcia/ti113x.h | |||
@@ -0,0 +1,662 @@ | |||
1 | /* | ||
2 | * ti113x.h 1.16 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_TI113X_H | ||
31 | #define _LINUX_TI113X_H | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | |||
35 | /* Register definitions for TI 113X PCI-to-CardBus bridges */ | ||
36 | |||
37 | /* System Control Register */ | ||
38 | #define TI113X_SYSTEM_CONTROL 0x0080 /* 32 bit */ | ||
39 | #define TI113X_SCR_SMIROUTE 0x04000000 | ||
40 | #define TI113X_SCR_SMISTATUS 0x02000000 | ||
41 | #define TI113X_SCR_SMIENB 0x01000000 | ||
42 | #define TI113X_SCR_VCCPROT 0x00200000 | ||
43 | #define TI113X_SCR_REDUCEZV 0x00100000 | ||
44 | #define TI113X_SCR_CDREQEN 0x00080000 | ||
45 | #define TI113X_SCR_CDMACHAN 0x00070000 | ||
46 | #define TI113X_SCR_SOCACTIVE 0x00002000 | ||
47 | #define TI113X_SCR_PWRSTREAM 0x00000800 | ||
48 | #define TI113X_SCR_DELAYUP 0x00000400 | ||
49 | #define TI113X_SCR_DELAYDOWN 0x00000200 | ||
50 | #define TI113X_SCR_INTERROGATE 0x00000100 | ||
51 | #define TI113X_SCR_CLKRUN_SEL 0x00000080 | ||
52 | #define TI113X_SCR_PWRSAVINGS 0x00000040 | ||
53 | #define TI113X_SCR_SUBSYSRW 0x00000020 | ||
54 | #define TI113X_SCR_CB_DPAR 0x00000010 | ||
55 | #define TI113X_SCR_CDMA_EN 0x00000008 | ||
56 | #define TI113X_SCR_ASYNC_IRQ 0x00000004 | ||
57 | #define TI113X_SCR_KEEPCLK 0x00000002 | ||
58 | #define TI113X_SCR_CLKRUN_ENA 0x00000001 | ||
59 | |||
60 | #define TI122X_SCR_SER_STEP 0xc0000000 | ||
61 | #define TI122X_SCR_INTRTIE 0x20000000 | ||
62 | #define TI122X_SCR_CBRSVD 0x00400000 | ||
63 | #define TI122X_SCR_MRBURSTDN 0x00008000 | ||
64 | #define TI122X_SCR_MRBURSTUP 0x00004000 | ||
65 | #define TI122X_SCR_RIMUX 0x00000001 | ||
66 | |||
67 | /* Multimedia Control Register */ | ||
68 | #define TI1250_MULTIMEDIA_CTL 0x0084 /* 8 bit */ | ||
69 | #define TI1250_MMC_ZVOUTEN 0x80 | ||
70 | #define TI1250_MMC_PORTSEL 0x40 | ||
71 | #define TI1250_MMC_ZVEN1 0x02 | ||
72 | #define TI1250_MMC_ZVEN0 0x01 | ||
73 | |||
74 | #define TI1250_GENERAL_STATUS 0x0085 /* 8 bit */ | ||
75 | #define TI1250_GPIO0_CONTROL 0x0088 /* 8 bit */ | ||
76 | #define TI1250_GPIO1_CONTROL 0x0089 /* 8 bit */ | ||
77 | #define TI1250_GPIO2_CONTROL 0x008a /* 8 bit */ | ||
78 | #define TI1250_GPIO3_CONTROL 0x008b /* 8 bit */ | ||
79 | #define TI1250_GPIO_MODE_MASK 0xc0 | ||
80 | |||
81 | /* IRQMUX/MFUNC Register */ | ||
82 | #define TI122X_MFUNC 0x008c /* 32 bit */ | ||
83 | #define TI122X_MFUNC0_MASK 0x0000000f | ||
84 | #define TI122X_MFUNC1_MASK 0x000000f0 | ||
85 | #define TI122X_MFUNC2_MASK 0x00000f00 | ||
86 | #define TI122X_MFUNC3_MASK 0x0000f000 | ||
87 | #define TI122X_MFUNC4_MASK 0x000f0000 | ||
88 | #define TI122X_MFUNC5_MASK 0x00f00000 | ||
89 | #define TI122X_MFUNC6_MASK 0x0f000000 | ||
90 | |||
91 | #define TI122X_MFUNC0_INTA 0x00000002 | ||
92 | #define TI125X_MFUNC0_INTB 0x00000001 | ||
93 | #define TI122X_MFUNC1_INTB 0x00000020 | ||
94 | #define TI122X_MFUNC3_IRQSER 0x00001000 | ||
95 | |||
96 | |||
97 | /* Retry Status Register */ | ||
98 | #define TI113X_RETRY_STATUS 0x0090 /* 8 bit */ | ||
99 | #define TI113X_RSR_PCIRETRY 0x80 | ||
100 | #define TI113X_RSR_CBRETRY 0x40 | ||
101 | #define TI113X_RSR_TEXP_CBB 0x20 | ||
102 | #define TI113X_RSR_MEXP_CBB 0x10 | ||
103 | #define TI113X_RSR_TEXP_CBA 0x08 | ||
104 | #define TI113X_RSR_MEXP_CBA 0x04 | ||
105 | #define TI113X_RSR_TEXP_PCI 0x02 | ||
106 | #define TI113X_RSR_MEXP_PCI 0x01 | ||
107 | |||
108 | /* Card Control Register */ | ||
109 | #define TI113X_CARD_CONTROL 0x0091 /* 8 bit */ | ||
110 | #define TI113X_CCR_RIENB 0x80 | ||
111 | #define TI113X_CCR_ZVENABLE 0x40 | ||
112 | #define TI113X_CCR_PCI_IRQ_ENA 0x20 | ||
113 | #define TI113X_CCR_PCI_IREQ 0x10 | ||
114 | #define TI113X_CCR_PCI_CSC 0x08 | ||
115 | #define TI113X_CCR_SPKROUTEN 0x02 | ||
116 | #define TI113X_CCR_IFG 0x01 | ||
117 | |||
118 | #define TI1220_CCR_PORT_SEL 0x20 | ||
119 | #define TI122X_CCR_AUD2MUX 0x04 | ||
120 | |||
121 | /* Device Control Register */ | ||
122 | #define TI113X_DEVICE_CONTROL 0x0092 /* 8 bit */ | ||
123 | #define TI113X_DCR_5V_FORCE 0x40 | ||
124 | #define TI113X_DCR_3V_FORCE 0x20 | ||
125 | #define TI113X_DCR_IMODE_MASK 0x06 | ||
126 | #define TI113X_DCR_IMODE_ISA 0x02 | ||
127 | #define TI113X_DCR_IMODE_SERIAL 0x04 | ||
128 | |||
129 | #define TI12XX_DCR_IMODE_PCI_ONLY 0x00 | ||
130 | #define TI12XX_DCR_IMODE_ALL_SERIAL 0x06 | ||
131 | |||
132 | /* Buffer Control Register */ | ||
133 | #define TI113X_BUFFER_CONTROL 0x0093 /* 8 bit */ | ||
134 | #define TI113X_BCR_CB_READ_DEPTH 0x08 | ||
135 | #define TI113X_BCR_CB_WRITE_DEPTH 0x04 | ||
136 | #define TI113X_BCR_PCI_READ_DEPTH 0x02 | ||
137 | #define TI113X_BCR_PCI_WRITE_DEPTH 0x01 | ||
138 | |||
139 | /* Diagnostic Register */ | ||
140 | #define TI1250_DIAGNOSTIC 0x0093 /* 8 bit */ | ||
141 | #define TI1250_DIAG_TRUE_VALUE 0x80 | ||
142 | #define TI1250_DIAG_PCI_IREQ 0x40 | ||
143 | #define TI1250_DIAG_PCI_CSC 0x20 | ||
144 | #define TI1250_DIAG_ASYNC_CSC 0x01 | ||
145 | |||
146 | /* DMA Registers */ | ||
147 | #define TI113X_DMA_0 0x0094 /* 32 bit */ | ||
148 | #define TI113X_DMA_1 0x0098 /* 32 bit */ | ||
149 | |||
150 | /* ExCA IO offset registers */ | ||
151 | #define TI113X_IO_OFFSET(map) (0x36+((map)<<1)) | ||
152 | |||
153 | /* EnE test register */ | ||
154 | #define ENE_TEST_C9 0xc9 /* 8bit */ | ||
155 | #define ENE_TEST_C9_TLTENABLE 0x02 | ||
156 | |||
157 | #ifdef CONFIG_CARDBUS | ||
158 | |||
159 | /* | ||
160 | * Texas Instruments CardBus controller overrides. | ||
161 | */ | ||
162 | #define ti_sysctl(socket) ((socket)->private[0]) | ||
163 | #define ti_cardctl(socket) ((socket)->private[1]) | ||
164 | #define ti_devctl(socket) ((socket)->private[2]) | ||
165 | #define ti_diag(socket) ((socket)->private[3]) | ||
166 | #define ti_mfunc(socket) ((socket)->private[4]) | ||
167 | #define ene_test_c9(socket) ((socket)->private[5]) | ||
168 | |||
169 | /* | ||
170 | * These are the TI specific power management handlers. | ||
171 | */ | ||
172 | static void ti_save_state(struct yenta_socket *socket) | ||
173 | { | ||
174 | ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
175 | ti_mfunc(socket) = config_readl(socket, TI122X_MFUNC); | ||
176 | ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL); | ||
177 | ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL); | ||
178 | ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC); | ||
179 | |||
180 | if (socket->dev->vendor == PCI_VENDOR_ID_ENE) | ||
181 | ene_test_c9(socket) = config_readb(socket, ENE_TEST_C9); | ||
182 | } | ||
183 | |||
184 | static void ti_restore_state(struct yenta_socket *socket) | ||
185 | { | ||
186 | config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); | ||
187 | config_writel(socket, TI122X_MFUNC, ti_mfunc(socket)); | ||
188 | config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); | ||
189 | config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket)); | ||
190 | config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); | ||
191 | |||
192 | if (socket->dev->vendor == PCI_VENDOR_ID_ENE) | ||
193 | config_writeb(socket, ENE_TEST_C9, ene_test_c9(socket)); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Zoom video control for TI122x/113x chips | ||
198 | */ | ||
199 | |||
200 | static void ti_zoom_video(struct pcmcia_socket *sock, int onoff) | ||
201 | { | ||
202 | u8 reg; | ||
203 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
204 | |||
205 | /* If we don't have a Zoom Video switch this is harmless, | ||
206 | we just tristate the unused (ZV) lines */ | ||
207 | reg = config_readb(socket, TI113X_CARD_CONTROL); | ||
208 | if (onoff) | ||
209 | /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ | ||
210 | reg |= TI113X_CCR_ZVENABLE; | ||
211 | else | ||
212 | reg &= ~TI113X_CCR_ZVENABLE; | ||
213 | config_writeb(socket, TI113X_CARD_CONTROL, reg); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * The 145x series can also use this. They have an additional | ||
218 | * ZV autodetect mode we don't use but don't actually need. | ||
219 | * FIXME: manual says its in func0 and func1 but disagrees with | ||
220 | * itself about this - do we need to force func0, if so we need | ||
221 | * to know a lot more about socket pairings in pcmcia_socket than | ||
222 | * we do now.. uggh. | ||
223 | */ | ||
224 | |||
225 | static void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff) | ||
226 | { | ||
227 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
228 | int shift = 0; | ||
229 | u8 reg; | ||
230 | |||
231 | ti_zoom_video(sock, onoff); | ||
232 | |||
233 | reg = config_readb(socket, TI1250_MULTIMEDIA_CTL); | ||
234 | reg |= TI1250_MMC_ZVOUTEN; /* ZV bus enable */ | ||
235 | |||
236 | if(PCI_FUNC(socket->dev->devfn)==1) | ||
237 | shift = 1; | ||
238 | |||
239 | if(onoff) | ||
240 | { | ||
241 | reg &= ~(1<<6); /* Clear select bit */ | ||
242 | reg |= shift<<6; /* Favour our socket */ | ||
243 | reg |= 1<<shift; /* Socket zoom video on */ | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | reg &= ~(1<<6); /* Clear select bit */ | ||
248 | reg |= (1^shift)<<6; /* Favour other socket */ | ||
249 | reg &= ~(1<<shift); /* Socket zoon video off */ | ||
250 | } | ||
251 | |||
252 | config_writeb(socket, TI1250_MULTIMEDIA_CTL, reg); | ||
253 | } | ||
254 | |||
255 | static void ti_set_zv(struct yenta_socket *socket) | ||
256 | { | ||
257 | if(socket->dev->vendor == PCI_VENDOR_ID_TI) | ||
258 | { | ||
259 | switch(socket->dev->device) | ||
260 | { | ||
261 | /* There may be more .. */ | ||
262 | case PCI_DEVICE_ID_TI_1220: | ||
263 | case PCI_DEVICE_ID_TI_1221: | ||
264 | case PCI_DEVICE_ID_TI_1225: | ||
265 | case PCI_DEVICE_ID_TI_4510: | ||
266 | socket->socket.zoom_video = ti_zoom_video; | ||
267 | break; | ||
268 | case PCI_DEVICE_ID_TI_1250: | ||
269 | case PCI_DEVICE_ID_TI_1251A: | ||
270 | case PCI_DEVICE_ID_TI_1251B: | ||
271 | case PCI_DEVICE_ID_TI_1450: | ||
272 | socket->socket.zoom_video = ti1250_zoom_video; | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | |||
278 | /* | ||
279 | * Generic TI init - TI has an extension for the | ||
280 | * INTCTL register that sets the PCI CSC interrupt. | ||
281 | * Make sure we set it correctly at open and init | ||
282 | * time | ||
283 | * - override: disable the PCI CSC interrupt. This makes | ||
284 | * it possible to use the CSC interrupt to probe the | ||
285 | * ISA interrupts. | ||
286 | * - init: set the interrupt to match our PCI state. | ||
287 | * This makes us correctly get PCI CSC interrupt | ||
288 | * events. | ||
289 | */ | ||
290 | static int ti_init(struct yenta_socket *socket) | ||
291 | { | ||
292 | u8 new, reg = exca_readb(socket, I365_INTCTL); | ||
293 | |||
294 | new = reg & ~I365_INTR_ENA; | ||
295 | if (socket->cb_irq) | ||
296 | new |= I365_INTR_ENA; | ||
297 | if (new != reg) | ||
298 | exca_writeb(socket, I365_INTCTL, new); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int ti_override(struct yenta_socket *socket) | ||
303 | { | ||
304 | u8 new, reg = exca_readb(socket, I365_INTCTL); | ||
305 | |||
306 | new = reg & ~I365_INTR_ENA; | ||
307 | if (new != reg) | ||
308 | exca_writeb(socket, I365_INTCTL, new); | ||
309 | |||
310 | ti_set_zv(socket); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int ti113x_override(struct yenta_socket *socket) | ||
316 | { | ||
317 | u8 cardctl; | ||
318 | |||
319 | cardctl = config_readb(socket, TI113X_CARD_CONTROL); | ||
320 | cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC); | ||
321 | if (socket->cb_irq) | ||
322 | cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ; | ||
323 | config_writeb(socket, TI113X_CARD_CONTROL, cardctl); | ||
324 | |||
325 | return ti_override(socket); | ||
326 | } | ||
327 | |||
328 | |||
329 | /* irqrouting for func0, probes PCI interrupt and ISA interrupts */ | ||
330 | static void ti12xx_irqroute_func0(struct yenta_socket *socket) | ||
331 | { | ||
332 | u32 mfunc, mfunc_old, devctl; | ||
333 | u8 gpio3, gpio3_old; | ||
334 | int pci_irq_status; | ||
335 | |||
336 | mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC); | ||
337 | devctl = config_readb(socket, TI113X_DEVICE_CONTROL); | ||
338 | printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n", | ||
339 | pci_name(socket->dev), mfunc, devctl); | ||
340 | |||
341 | /* make sure PCI interrupts are enabled before probing */ | ||
342 | ti_init(socket); | ||
343 | |||
344 | /* test PCI interrupts first. only try fixing if return value is 0! */ | ||
345 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
346 | if (pci_irq_status) | ||
347 | goto out; | ||
348 | |||
349 | /* | ||
350 | * We're here which means PCI interrupts are _not_ delivered. try to | ||
351 | * find the right setting (all serial or parallel) | ||
352 | */ | ||
353 | printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n", | ||
354 | pci_name(socket->dev)); | ||
355 | |||
356 | /* for serial PCI make sure MFUNC3 is set to IRQSER */ | ||
357 | if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) { | ||
358 | switch (socket->dev->device) { | ||
359 | case PCI_DEVICE_ID_TI_1250: | ||
360 | case PCI_DEVICE_ID_TI_1251A: | ||
361 | case PCI_DEVICE_ID_TI_1251B: | ||
362 | case PCI_DEVICE_ID_TI_1450: | ||
363 | case PCI_DEVICE_ID_TI_1451A: | ||
364 | case PCI_DEVICE_ID_TI_4450: | ||
365 | case PCI_DEVICE_ID_TI_4451: | ||
366 | /* these chips have no IRQSER setting in MFUNC3 */ | ||
367 | break; | ||
368 | |||
369 | default: | ||
370 | mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER; | ||
371 | |||
372 | /* write down if changed, probe */ | ||
373 | if (mfunc != mfunc_old) { | ||
374 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
375 | |||
376 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
377 | if (pci_irq_status == 1) { | ||
378 | printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts ok\n", | ||
379 | pci_name(socket->dev)); | ||
380 | mfunc_old = mfunc; | ||
381 | goto out; | ||
382 | } | ||
383 | |||
384 | /* not working, back to old value */ | ||
385 | mfunc = mfunc_old; | ||
386 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
387 | |||
388 | if (pci_irq_status == -1) | ||
389 | goto out; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | /* serial PCI interrupts not working fall back to parallel */ | ||
394 | printk(KERN_INFO "Yenta TI: socket %s falling back to parallel PCI interrupts\n", | ||
395 | pci_name(socket->dev)); | ||
396 | devctl &= ~TI113X_DCR_IMODE_MASK; | ||
397 | devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */ | ||
398 | config_writeb(socket, TI113X_DEVICE_CONTROL, devctl); | ||
399 | } | ||
400 | |||
401 | /* parallel PCI interrupts: route INTA */ | ||
402 | switch (socket->dev->device) { | ||
403 | case PCI_DEVICE_ID_TI_1250: | ||
404 | case PCI_DEVICE_ID_TI_1251A: | ||
405 | case PCI_DEVICE_ID_TI_1251B: | ||
406 | case PCI_DEVICE_ID_TI_1450: | ||
407 | /* make sure GPIO3 is set to INTA */ | ||
408 | gpio3 = gpio3_old = config_readb(socket, TI1250_GPIO3_CONTROL); | ||
409 | gpio3 &= ~TI1250_GPIO_MODE_MASK; | ||
410 | if (gpio3 != gpio3_old) | ||
411 | config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3); | ||
412 | break; | ||
413 | |||
414 | default: | ||
415 | gpio3 = gpio3_old = 0; | ||
416 | |||
417 | mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI122X_MFUNC0_INTA; | ||
418 | if (mfunc != mfunc_old) | ||
419 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
420 | } | ||
421 | |||
422 | /* time to probe again */ | ||
423 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
424 | if (pci_irq_status == 1) { | ||
425 | mfunc_old = mfunc; | ||
426 | printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n", | ||
427 | pci_name(socket->dev)); | ||
428 | } else { | ||
429 | /* not working, back to old value */ | ||
430 | mfunc = mfunc_old; | ||
431 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
432 | if (gpio3 != gpio3_old) | ||
433 | config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3_old); | ||
434 | } | ||
435 | |||
436 | out: | ||
437 | if (pci_irq_status < 1) { | ||
438 | socket->cb_irq = 0; | ||
439 | printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n", | ||
440 | pci_name(socket->dev)); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | |||
445 | /* | ||
446 | * ties INTA and INTB together. also changes the devices irq to that of | ||
447 | * the function 0 device. call from func1 only. | ||
448 | * returns 1 if INTRTIE changed, 0 otherwise. | ||
449 | */ | ||
450 | static int ti12xx_tie_interrupts(struct yenta_socket *socket, int *old_irq) | ||
451 | { | ||
452 | struct pci_dev *func0; | ||
453 | u32 sysctl; | ||
454 | |||
455 | sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
456 | if (sysctl & TI122X_SCR_INTRTIE) | ||
457 | return 0; | ||
458 | |||
459 | /* find func0 device */ | ||
460 | func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07); | ||
461 | if (!func0) | ||
462 | return 0; | ||
463 | |||
464 | /* change the interrupt to match func0, tie 'em up */ | ||
465 | *old_irq = socket->cb_irq; | ||
466 | socket->cb_irq = socket->dev->irq = func0->irq; | ||
467 | sysctl |= TI122X_SCR_INTRTIE; | ||
468 | config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl); | ||
469 | |||
470 | pci_dev_put(func0); | ||
471 | |||
472 | return 1; | ||
473 | } | ||
474 | |||
475 | /* undo what ti12xx_tie_interrupts() did */ | ||
476 | static void ti12xx_untie_interrupts(struct yenta_socket *socket, int old_irq) | ||
477 | { | ||
478 | u32 sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
479 | sysctl &= ~TI122X_SCR_INTRTIE; | ||
480 | config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl); | ||
481 | |||
482 | socket->cb_irq = socket->dev->irq = old_irq; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * irqrouting for func1, plays with INTB routing | ||
487 | * only touches MFUNC for INTB routing. all other bits are taken | ||
488 | * care of in func0 already. | ||
489 | */ | ||
490 | static void ti12xx_irqroute_func1(struct yenta_socket *socket) | ||
491 | { | ||
492 | u32 mfunc, mfunc_old, devctl; | ||
493 | int pci_irq_status; | ||
494 | |||
495 | mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC); | ||
496 | devctl = config_readb(socket, TI113X_DEVICE_CONTROL); | ||
497 | printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n", | ||
498 | pci_name(socket->dev), mfunc, devctl); | ||
499 | |||
500 | /* make sure PCI interrupts are enabled before probing */ | ||
501 | ti_init(socket); | ||
502 | |||
503 | /* test PCI interrupts first. only try fixing if return value is 0! */ | ||
504 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
505 | if (pci_irq_status) | ||
506 | goto out; | ||
507 | |||
508 | /* | ||
509 | * We're here which means PCI interrupts are _not_ delivered. try to | ||
510 | * find the right setting | ||
511 | */ | ||
512 | printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n", | ||
513 | pci_name(socket->dev)); | ||
514 | |||
515 | |||
516 | /* if all serial: set INTRTIE, probe again */ | ||
517 | if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) { | ||
518 | int old_irq; | ||
519 | |||
520 | if (ti12xx_tie_interrupts(socket, &old_irq)) { | ||
521 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
522 | if (pci_irq_status == 1) { | ||
523 | printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts, tied ok\n", | ||
524 | pci_name(socket->dev)); | ||
525 | goto out; | ||
526 | } | ||
527 | |||
528 | ti12xx_untie_interrupts(socket, old_irq); | ||
529 | } | ||
530 | } | ||
531 | /* parallel PCI: route INTB, probe again */ | ||
532 | else { | ||
533 | int old_irq; | ||
534 | |||
535 | switch (socket->dev->device) { | ||
536 | case PCI_DEVICE_ID_TI_1250: | ||
537 | /* the 1250 has one pin for IRQSER/INTB depending on devctl */ | ||
538 | break; | ||
539 | |||
540 | case PCI_DEVICE_ID_TI_1251A: | ||
541 | case PCI_DEVICE_ID_TI_1251B: | ||
542 | case PCI_DEVICE_ID_TI_1450: | ||
543 | /* | ||
544 | * those have a pin for IRQSER/INTB plus INTB in MFUNC0 | ||
545 | * we alread probed the shared pin, now go for MFUNC0 | ||
546 | */ | ||
547 | mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI125X_MFUNC0_INTB; | ||
548 | break; | ||
549 | |||
550 | default: | ||
551 | mfunc = (mfunc & ~TI122X_MFUNC1_MASK) | TI122X_MFUNC1_INTB; | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | /* write, probe */ | ||
556 | if (mfunc != mfunc_old) { | ||
557 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
558 | |||
559 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
560 | if (pci_irq_status == 1) { | ||
561 | printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n", | ||
562 | pci_name(socket->dev)); | ||
563 | goto out; | ||
564 | } | ||
565 | |||
566 | mfunc = mfunc_old; | ||
567 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
568 | |||
569 | if (pci_irq_status == -1) | ||
570 | goto out; | ||
571 | } | ||
572 | |||
573 | /* still nothing: set INTRTIE */ | ||
574 | if (ti12xx_tie_interrupts(socket, &old_irq)) { | ||
575 | pci_irq_status = yenta_probe_cb_irq(socket); | ||
576 | if (pci_irq_status == 1) { | ||
577 | printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts, tied ok\n", | ||
578 | pci_name(socket->dev)); | ||
579 | goto out; | ||
580 | } | ||
581 | |||
582 | ti12xx_untie_interrupts(socket, old_irq); | ||
583 | } | ||
584 | } | ||
585 | |||
586 | out: | ||
587 | if (pci_irq_status < 1) { | ||
588 | socket->cb_irq = 0; | ||
589 | printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n", | ||
590 | pci_name(socket->dev)); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | static int ti12xx_override(struct yenta_socket *socket) | ||
595 | { | ||
596 | u32 val, val_orig; | ||
597 | |||
598 | /* make sure that memory burst is active */ | ||
599 | val_orig = val = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
600 | if (disable_clkrun && PCI_FUNC(socket->dev->devfn) == 0) { | ||
601 | printk(KERN_INFO "Yenta: Disabling CLKRUN feature\n"); | ||
602 | val |= TI113X_SCR_KEEPCLK; | ||
603 | } | ||
604 | if (!(val & TI122X_SCR_MRBURSTUP)) { | ||
605 | printk(KERN_INFO "Yenta: Enabling burst memory read transactions\n"); | ||
606 | val |= TI122X_SCR_MRBURSTUP; | ||
607 | } | ||
608 | if (val_orig != val) | ||
609 | config_writel(socket, TI113X_SYSTEM_CONTROL, val); | ||
610 | |||
611 | /* | ||
612 | * for EnE bridges only: clear testbit TLTEnable. this makes the | ||
613 | * RME Hammerfall DSP sound card working. | ||
614 | */ | ||
615 | if (socket->dev->vendor == PCI_VENDOR_ID_ENE) { | ||
616 | u8 test_c9 = config_readb(socket, ENE_TEST_C9); | ||
617 | test_c9 &= ~ENE_TEST_C9_TLTENABLE; | ||
618 | config_writeb(socket, ENE_TEST_C9, test_c9); | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Yenta expects controllers to use CSCINT to route | ||
623 | * CSC interrupts to PCI rather than INTVAL. | ||
624 | */ | ||
625 | val = config_readb(socket, TI1250_DIAGNOSTIC); | ||
626 | printk(KERN_INFO "Yenta: Using %s to route CSC interrupts to PCI\n", | ||
627 | (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL"); | ||
628 | printk(KERN_INFO "Yenta: Routing CardBus interrupts to %s\n", | ||
629 | (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA"); | ||
630 | |||
631 | /* do irqrouting, depending on function */ | ||
632 | if (PCI_FUNC(socket->dev->devfn) == 0) | ||
633 | ti12xx_irqroute_func0(socket); | ||
634 | else | ||
635 | ti12xx_irqroute_func1(socket); | ||
636 | |||
637 | return ti_override(socket); | ||
638 | } | ||
639 | |||
640 | |||
641 | static int ti1250_override(struct yenta_socket *socket) | ||
642 | { | ||
643 | u8 old, diag; | ||
644 | |||
645 | old = config_readb(socket, TI1250_DIAGNOSTIC); | ||
646 | diag = old & ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ); | ||
647 | if (socket->cb_irq) | ||
648 | diag |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ; | ||
649 | |||
650 | if (diag != old) { | ||
651 | printk(KERN_INFO "Yenta: adjusting diagnostic: %02x -> %02x\n", | ||
652 | old, diag); | ||
653 | config_writeb(socket, TI1250_DIAGNOSTIC, diag); | ||
654 | } | ||
655 | |||
656 | return ti12xx_override(socket); | ||
657 | } | ||
658 | |||
659 | #endif /* CONFIG_CARDBUS */ | ||
660 | |||
661 | #endif /* _LINUX_TI113X_H */ | ||
662 | |||
diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h new file mode 100644 index 000000000000..be420bb29113 --- /dev/null +++ b/drivers/pcmcia/topic.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * topic.h 1.8 1999/08/28 04:01:47 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | * topic.h $Release$ 1999/08/28 04:01:47 | ||
29 | */ | ||
30 | |||
31 | #ifndef _LINUX_TOPIC_H | ||
32 | #define _LINUX_TOPIC_H | ||
33 | |||
34 | /* Register definitions for Toshiba ToPIC95/97/100 controllers */ | ||
35 | |||
36 | #define TOPIC_SOCKET_CONTROL 0x0090 /* 32 bit */ | ||
37 | #define TOPIC_SCR_IRQSEL 0x00000001 | ||
38 | |||
39 | #define TOPIC_SLOT_CONTROL 0x00a0 /* 8 bit */ | ||
40 | #define TOPIC_SLOT_SLOTON 0x80 | ||
41 | #define TOPIC_SLOT_SLOTEN 0x40 | ||
42 | #define TOPIC_SLOT_ID_LOCK 0x20 | ||
43 | #define TOPIC_SLOT_ID_WP 0x10 | ||
44 | #define TOPIC_SLOT_PORT_MASK 0x0c | ||
45 | #define TOPIC_SLOT_PORT_SHIFT 2 | ||
46 | #define TOPIC_SLOT_OFS_MASK 0x03 | ||
47 | |||
48 | #define TOPIC_CARD_CONTROL 0x00a1 /* 8 bit */ | ||
49 | #define TOPIC_CCR_INTB 0x20 | ||
50 | #define TOPIC_CCR_INTA 0x10 | ||
51 | #define TOPIC_CCR_CLOCK 0x0c | ||
52 | #define TOPIC_CCR_PCICLK 0x0c | ||
53 | #define TOPIC_CCR_PCICLK_2 0x08 | ||
54 | #define TOPIC_CCR_CCLK 0x04 | ||
55 | |||
56 | #define TOPIC97_INT_CONTROL 0x00a1 /* 8 bit */ | ||
57 | #define TOPIC97_ICR_INTB 0x20 | ||
58 | #define TOPIC97_ICR_INTA 0x10 | ||
59 | #define TOPIC97_ICR_STSIRQNP 0x04 | ||
60 | #define TOPIC97_ICR_IRQNP 0x02 | ||
61 | #define TOPIC97_ICR_IRQSEL 0x01 | ||
62 | |||
63 | #define TOPIC_CARD_DETECT 0x00a3 /* 8 bit */ | ||
64 | #define TOPIC_CDR_MODE_PC32 0x80 | ||
65 | #define TOPIC_CDR_VS1 0x04 | ||
66 | #define TOPIC_CDR_VS2 0x02 | ||
67 | #define TOPIC_CDR_SW_DETECT 0x01 | ||
68 | |||
69 | #define TOPIC_REGISTER_CONTROL 0x00a4 /* 32 bit */ | ||
70 | #define TOPIC_RCR_RESUME_RESET 0x80000000 | ||
71 | #define TOPIC_RCR_REMOVE_RESET 0x40000000 | ||
72 | #define TOPIC97_RCR_CLKRUN_ENA 0x20000000 | ||
73 | #define TOPIC97_RCR_TESTMODE 0x10000000 | ||
74 | #define TOPIC97_RCR_IOPLUP 0x08000000 | ||
75 | #define TOPIC_RCR_BUFOFF_PWROFF 0x02000000 | ||
76 | #define TOPIC_RCR_BUFOFF_SIGOFF 0x01000000 | ||
77 | #define TOPIC97_RCR_CB_DEV_MASK 0x0000f800 | ||
78 | #define TOPIC97_RCR_CB_DEV_SHIFT 11 | ||
79 | #define TOPIC97_RCR_RI_DISABLE 0x00000004 | ||
80 | #define TOPIC97_RCR_CAUDIO_OFF 0x00000002 | ||
81 | #define TOPIC_RCR_CAUDIO_INVERT 0x00000001 | ||
82 | |||
83 | #define TOPIC97_MISC1 0x00ad /* 8bit */ | ||
84 | #define TOPIC97_MISC1_CLOCKRUN_ENABLE 0x80 | ||
85 | #define TOPIC97_MISC1_CLOCKRUN_MODE 0x40 | ||
86 | #define TOPIC97_MISC1_DETECT_REQ_ENA 0x10 | ||
87 | #define TOPIC97_MISC1_SCK_CLEAR_DIS 0x04 | ||
88 | #define TOPIC97_MISC1_R2_LOW_ENABLE 0x10 | ||
89 | |||
90 | #define TOPIC97_MISC2 0x00ae /* 8 bit */ | ||
91 | #define TOPIC97_MISC2_SPWRCLK_MASK 0x70 | ||
92 | #define TOPIC97_MISC2_SPWRMOD 0x08 | ||
93 | #define TOPIC97_MISC2_SPWR_ENABLE 0x04 | ||
94 | #define TOPIC97_MISC2_ZV_MODE 0x02 | ||
95 | #define TOPIC97_MISC2_ZV_ENABLE 0x01 | ||
96 | |||
97 | #define TOPIC97_ZOOM_VIDEO_CONTROL 0x009c /* 8 bit */ | ||
98 | #define TOPIC97_ZV_CONTROL_ENABLE 0x01 | ||
99 | |||
100 | #define TOPIC97_AUDIO_VIDEO_SWITCH 0x003c /* 8 bit */ | ||
101 | #define TOPIC97_AVS_AUDIO_CONTROL 0x02 | ||
102 | #define TOPIC97_AVS_VIDEO_CONTROL 0x01 | ||
103 | |||
104 | |||
105 | static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff) | ||
106 | { | ||
107 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
108 | u8 reg_zv, reg; | ||
109 | |||
110 | reg_zv = config_readb(socket, TOPIC97_ZOOM_VIDEO_CONTROL); | ||
111 | if (onoff) { | ||
112 | reg_zv |= TOPIC97_ZV_CONTROL_ENABLE; | ||
113 | config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv); | ||
114 | |||
115 | reg = config_readb(socket, TOPIC97_MISC2); | ||
116 | reg |= TOPIC97_MISC2_ZV_ENABLE; | ||
117 | config_writeb(socket, TOPIC97_MISC2, reg); | ||
118 | |||
119 | /* not sure this is needed, doc is unclear */ | ||
120 | #if 0 | ||
121 | reg = config_readb(socket, TOPIC97_AUDIO_VIDEO_SWITCH); | ||
122 | reg |= TOPIC97_AVS_AUDIO_CONTROL | TOPIC97_AVS_VIDEO_CONTROL; | ||
123 | config_writeb(socket, TOPIC97_AUDIO_VIDEO_SWITCH, reg); | ||
124 | #endif | ||
125 | } | ||
126 | else { | ||
127 | reg_zv &= ~TOPIC97_ZV_CONTROL_ENABLE; | ||
128 | config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv); | ||
129 | } | ||
130 | |||
131 | } | ||
132 | |||
133 | static int topic97_override(struct yenta_socket *socket) | ||
134 | { | ||
135 | /* ToPIC97/100 support ZV */ | ||
136 | socket->socket.zoom_video = topic97_zoom_video; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | #endif /* _LINUX_TOPIC_H */ | ||
diff --git a/drivers/pcmcia/vg468.h b/drivers/pcmcia/vg468.h new file mode 100644 index 000000000000..88c2b487f675 --- /dev/null +++ b/drivers/pcmcia/vg468.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * vg468.h 1.11 1999/10/25 20:03:34 | ||
3 | * | ||
4 | * The contents of this file are subject to the Mozilla Public License | ||
5 | * Version 1.1 (the "License"); you may not use this file except in | ||
6 | * compliance with the License. You may obtain a copy of the License | ||
7 | * at http://www.mozilla.org/MPL/ | ||
8 | * | ||
9 | * Software distributed under the License is distributed on an "AS IS" | ||
10 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
11 | * the License for the specific language governing rights and | ||
12 | * limitations under the License. | ||
13 | * | ||
14 | * The initial developer of the original code is David A. Hinds | ||
15 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
16 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
17 | * | ||
18 | * Alternatively, the contents of this file may be used under the | ||
19 | * terms of the GNU General Public License version 2 (the "GPL"), in which | ||
20 | * case the provisions of the GPL are applicable instead of the | ||
21 | * above. If you wish to allow the use of your version of this file | ||
22 | * only under the terms of the GPL and not to allow others to use | ||
23 | * your version of this file under the MPL, indicate your decision by | ||
24 | * deleting the provisions above and replace them with the notice and | ||
25 | * other provisions required by the GPL. If you do not delete the | ||
26 | * provisions above, a recipient may use your version of this file | ||
27 | * under either the MPL or the GPL. | ||
28 | */ | ||
29 | |||
30 | #ifndef _LINUX_VG468_H | ||
31 | #define _LINUX_VG468_H | ||
32 | |||
33 | /* Special bit in I365_IDENT used for Vadem chip detection */ | ||
34 | #define I365_IDENT_VADEM 0x08 | ||
35 | |||
36 | /* Special definitions in I365_POWER */ | ||
37 | #define VG468_VPP2_MASK 0x0c | ||
38 | #define VG468_VPP2_5V 0x04 | ||
39 | #define VG468_VPP2_12V 0x08 | ||
40 | |||
41 | /* Unique Vadem registers */ | ||
42 | #define VG469_VSENSE 0x1f /* Card voltage sense */ | ||
43 | #define VG469_VSELECT 0x2f /* Card voltage select */ | ||
44 | #define VG468_CTL 0x38 /* Control register */ | ||
45 | #define VG468_TIMER 0x39 /* Timer control */ | ||
46 | #define VG468_MISC 0x3a /* Miscellaneous */ | ||
47 | #define VG468_GPIO_CFG 0x3b /* GPIO configuration */ | ||
48 | #define VG469_EXT_MODE 0x3c /* Extended mode register */ | ||
49 | #define VG468_SELECT 0x3d /* Programmable chip select */ | ||
50 | #define VG468_SELECT_CFG 0x3e /* Chip select configuration */ | ||
51 | #define VG468_ATA 0x3f /* ATA control */ | ||
52 | |||
53 | /* Flags for VG469_VSENSE */ | ||
54 | #define VG469_VSENSE_A_VS1 0x01 | ||
55 | #define VG469_VSENSE_A_VS2 0x02 | ||
56 | #define VG469_VSENSE_B_VS1 0x04 | ||
57 | #define VG469_VSENSE_B_VS2 0x08 | ||
58 | |||
59 | /* Flags for VG469_VSELECT */ | ||
60 | #define VG469_VSEL_VCC 0x03 | ||
61 | #define VG469_VSEL_5V 0x00 | ||
62 | #define VG469_VSEL_3V 0x03 | ||
63 | #define VG469_VSEL_MAX 0x0c | ||
64 | #define VG469_VSEL_EXT_STAT 0x10 | ||
65 | #define VG469_VSEL_EXT_BUS 0x20 | ||
66 | #define VG469_VSEL_MIXED 0x40 | ||
67 | #define VG469_VSEL_ISA 0x80 | ||
68 | |||
69 | /* Flags for VG468_CTL */ | ||
70 | #define VG468_CTL_SLOW 0x01 /* 600ns memory timing */ | ||
71 | #define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */ | ||
72 | #define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */ | ||
73 | #define VG468_CTL_DELAY 0x10 /* Card detect debounce */ | ||
74 | #define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */ | ||
75 | #define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */ | ||
76 | #define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */ | ||
77 | |||
78 | #define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */ | ||
79 | #define VG469_CTL_STRETCH 0x10 /* LED stretch */ | ||
80 | |||
81 | /* Flags for VG468_TIMER */ | ||
82 | #define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */ | ||
83 | #define VG468_TIMER_SIGEN 0x20 /* Power up */ | ||
84 | #define VG468_TIMER_STATUS 0x40 /* Activity timer status */ | ||
85 | #define VG468_TIMER_RES 0x80 /* Timer resolution */ | ||
86 | #define VG468_TIMER_MASK 0x0f /* Activity timer timeout */ | ||
87 | |||
88 | /* Flags for VG468_MISC */ | ||
89 | #define VG468_MISC_GPIO 0x04 /* General-purpose IO */ | ||
90 | #define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */ | ||
91 | #define VG469_MISC_LEDENA 0x10 /* LED enable */ | ||
92 | #define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */ | ||
93 | #define VG468_MISC_UNLOCK 0x80 /* Unique register lock */ | ||
94 | |||
95 | /* Flags for VG469_EXT_MODE_A */ | ||
96 | #define VG469_MODE_VPPST 0x03 /* Vpp steering control */ | ||
97 | #define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */ | ||
98 | #define VG469_MODE_CABLE 0x08 | ||
99 | #define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */ | ||
100 | #define VG469_MODE_TEST 0x20 | ||
101 | #define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */ | ||
102 | |||
103 | /* Flags for VG469_EXT_MODE_B */ | ||
104 | #define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */ | ||
105 | |||
106 | #endif /* _LINUX_VG468_H */ | ||
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c new file mode 100644 index 000000000000..987bc21ced42 --- /dev/null +++ b/drivers/pcmcia/vrc4171_card.c | |||
@@ -0,0 +1,846 @@ | |||
1 | /* | ||
2 | * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services. | ||
3 | * | ||
4 | * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/types.h> | ||
27 | |||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include <pcmcia/ss.h> | ||
31 | |||
32 | #include "i82365.h" | ||
33 | |||
34 | MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services"); | ||
35 | MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | #define CARD_MAX_SLOTS 2 | ||
39 | #define CARD_SLOTA 0 | ||
40 | #define CARD_SLOTB 1 | ||
41 | #define CARD_SLOTB_OFFSET 0x40 | ||
42 | |||
43 | #define CARD_MEM_START 0x10000000 | ||
44 | #define CARD_MEM_END 0x13ffffff | ||
45 | #define CARD_MAX_MEM_OFFSET 0x3ffffff | ||
46 | #define CARD_MAX_MEM_SPEED 1000 | ||
47 | |||
48 | #define CARD_CONTROLLER_INDEX 0x03e0 | ||
49 | #define CARD_CONTROLLER_DATA 0x03e1 | ||
50 | /* Power register */ | ||
51 | #define VPP_GET_VCC 0x01 | ||
52 | #define POWER_ENABLE 0x10 | ||
53 | #define CARD_VOLTAGE_SENSE 0x1f | ||
54 | #define VCC_3VORXV_CAPABLE 0x00 | ||
55 | #define VCC_XV_ONLY 0x01 | ||
56 | #define VCC_3V_CAPABLE 0x02 | ||
57 | #define VCC_5V_ONLY 0x03 | ||
58 | #define CARD_VOLTAGE_SELECT 0x2f | ||
59 | #define VCC_3V 0x01 | ||
60 | #define VCC_5V 0x00 | ||
61 | #define VCC_XV 0x02 | ||
62 | #define VCC_STATUS_3V 0x02 | ||
63 | #define VCC_STATUS_5V 0x01 | ||
64 | #define VCC_STATUS_XV 0x03 | ||
65 | #define GLOBAL_CONTROL 0x1e | ||
66 | #define EXWRBK 0x04 | ||
67 | #define IRQPM_EN 0x08 | ||
68 | #define CLRPMIRQ 0x10 | ||
69 | |||
70 | #define INTERRUPT_STATUS 0x05fa | ||
71 | #define IRQ_A 0x02 | ||
72 | #define IRQ_B 0x04 | ||
73 | |||
74 | #define CONFIGURATION1 0x05fe | ||
75 | #define SLOTB_CONFIG 0xc000 | ||
76 | #define SLOTB_NONE 0x0000 | ||
77 | #define SLOTB_PCCARD 0x4000 | ||
78 | #define SLOTB_CF 0x8000 | ||
79 | #define SLOTB_FLASHROM 0xc000 | ||
80 | |||
81 | #define CARD_CONTROLLER_START CARD_CONTROLLER_INDEX | ||
82 | #define CARD_CONTROLLER_END CARD_CONTROLLER_DATA | ||
83 | |||
84 | #define IO_MAX_MAPS 2 | ||
85 | #define MEM_MAX_MAPS 5 | ||
86 | |||
87 | typedef enum { | ||
88 | SLOT_PROBE = 0, | ||
89 | SLOT_NOPROBE_IO, | ||
90 | SLOT_NOPROBE_MEM, | ||
91 | SLOT_NOPROBE_ALL, | ||
92 | SLOT_INITIALIZED, | ||
93 | } vrc4171_slot_t; | ||
94 | |||
95 | typedef enum { | ||
96 | SLOTB_IS_NONE, | ||
97 | SLOTB_IS_PCCARD, | ||
98 | SLOTB_IS_CF, | ||
99 | SLOTB_IS_FLASHROM, | ||
100 | } vrc4171_slotb_t; | ||
101 | |||
102 | typedef struct vrc4171_socket { | ||
103 | vrc4171_slot_t slot; | ||
104 | struct pcmcia_socket pcmcia_socket; | ||
105 | char name[24]; | ||
106 | int csc_irq; | ||
107 | int io_irq; | ||
108 | } vrc4171_socket_t; | ||
109 | |||
110 | static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS]; | ||
111 | static vrc4171_slotb_t vrc4171_slotb = SLOTB_IS_NONE; | ||
112 | static char vrc4171_card_name[] = "NEC VRC4171 Card Controller"; | ||
113 | static unsigned int vrc4171_irq; | ||
114 | static uint16_t vrc4171_irq_mask = 0xdeb8; | ||
115 | |||
116 | static struct resource vrc4171_card_resource[3] = { | ||
117 | { .name = vrc4171_card_name, | ||
118 | .start = CARD_CONTROLLER_START, | ||
119 | .end = CARD_CONTROLLER_END, | ||
120 | .flags = IORESOURCE_IO, }, | ||
121 | { .name = vrc4171_card_name, | ||
122 | .start = INTERRUPT_STATUS, | ||
123 | .end = INTERRUPT_STATUS, | ||
124 | .flags = IORESOURCE_IO, }, | ||
125 | { .name = vrc4171_card_name, | ||
126 | .start = CONFIGURATION1, | ||
127 | .end = CONFIGURATION1, | ||
128 | .flags = IORESOURCE_IO, }, | ||
129 | }; | ||
130 | |||
131 | static struct platform_device vrc4171_card_device = { | ||
132 | .name = vrc4171_card_name, | ||
133 | .id = 0, | ||
134 | .num_resources = 3, | ||
135 | .resource = vrc4171_card_resource, | ||
136 | }; | ||
137 | |||
138 | static inline uint16_t vrc4171_get_irq_status(void) | ||
139 | { | ||
140 | return inw(INTERRUPT_STATUS); | ||
141 | } | ||
142 | |||
143 | static inline void vrc4171_set_multifunction_pin(vrc4171_slotb_t config) | ||
144 | { | ||
145 | uint16_t config1; | ||
146 | |||
147 | config1 = inw(CONFIGURATION1); | ||
148 | config1 &= ~SLOTB_CONFIG; | ||
149 | |||
150 | switch (config) { | ||
151 | case SLOTB_IS_NONE: | ||
152 | config1 |= SLOTB_NONE; | ||
153 | break; | ||
154 | case SLOTB_IS_PCCARD: | ||
155 | config1 |= SLOTB_PCCARD; | ||
156 | break; | ||
157 | case SLOTB_IS_CF: | ||
158 | config1 |= SLOTB_CF; | ||
159 | break; | ||
160 | case SLOTB_IS_FLASHROM: | ||
161 | config1 |= SLOTB_FLASHROM; | ||
162 | break; | ||
163 | default: | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | outw(config1, CONFIGURATION1); | ||
168 | } | ||
169 | |||
170 | static inline uint8_t exca_read_byte(int slot, uint8_t index) | ||
171 | { | ||
172 | if (slot == CARD_SLOTB) | ||
173 | index += CARD_SLOTB_OFFSET; | ||
174 | |||
175 | outb(index, CARD_CONTROLLER_INDEX); | ||
176 | return inb(CARD_CONTROLLER_DATA); | ||
177 | } | ||
178 | |||
179 | static inline uint16_t exca_read_word(int slot, uint8_t index) | ||
180 | { | ||
181 | uint16_t data; | ||
182 | |||
183 | if (slot == CARD_SLOTB) | ||
184 | index += CARD_SLOTB_OFFSET; | ||
185 | |||
186 | outb(index++, CARD_CONTROLLER_INDEX); | ||
187 | data = inb(CARD_CONTROLLER_DATA); | ||
188 | |||
189 | outb(index, CARD_CONTROLLER_INDEX); | ||
190 | data |= ((uint16_t)inb(CARD_CONTROLLER_DATA)) << 8; | ||
191 | |||
192 | return data; | ||
193 | } | ||
194 | |||
195 | static inline uint8_t exca_write_byte(int slot, uint8_t index, uint8_t data) | ||
196 | { | ||
197 | if (slot == CARD_SLOTB) | ||
198 | index += CARD_SLOTB_OFFSET; | ||
199 | |||
200 | outb(index, CARD_CONTROLLER_INDEX); | ||
201 | outb(data, CARD_CONTROLLER_DATA); | ||
202 | |||
203 | return data; | ||
204 | } | ||
205 | |||
206 | static inline uint16_t exca_write_word(int slot, uint8_t index, uint16_t data) | ||
207 | { | ||
208 | if (slot == CARD_SLOTB) | ||
209 | index += CARD_SLOTB_OFFSET; | ||
210 | |||
211 | outb(index++, CARD_CONTROLLER_INDEX); | ||
212 | outb(data, CARD_CONTROLLER_DATA); | ||
213 | |||
214 | outb(index, CARD_CONTROLLER_INDEX); | ||
215 | outb((uint8_t)(data >> 8), CARD_CONTROLLER_DATA); | ||
216 | |||
217 | return data; | ||
218 | } | ||
219 | |||
220 | static inline int search_nonuse_irq(void) | ||
221 | { | ||
222 | int i; | ||
223 | |||
224 | for (i = 0; i < 16; i++) { | ||
225 | if (vrc4171_irq_mask & (1 << i)) { | ||
226 | vrc4171_irq_mask &= ~(1 << i); | ||
227 | return i; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | static int pccard_init(struct pcmcia_socket *sock) | ||
235 | { | ||
236 | vrc4171_socket_t *socket; | ||
237 | unsigned int slot; | ||
238 | |||
239 | sock->features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS; | ||
240 | sock->irq_mask = 0; | ||
241 | sock->map_size = 0x1000; | ||
242 | sock->pci_irq = vrc4171_irq; | ||
243 | |||
244 | slot = sock->sock; | ||
245 | socket = &vrc4171_sockets[slot]; | ||
246 | socket->csc_irq = search_nonuse_irq(); | ||
247 | socket->io_irq = search_nonuse_irq(); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int pccard_get_status(struct pcmcia_socket *sock, u_int *value) | ||
253 | { | ||
254 | unsigned int slot; | ||
255 | uint8_t status, sense; | ||
256 | u_int val = 0; | ||
257 | |||
258 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || value == NULL) | ||
259 | return -EINVAL; | ||
260 | |||
261 | slot = sock->sock; | ||
262 | |||
263 | status = exca_read_byte(slot, I365_STATUS); | ||
264 | if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) { | ||
265 | if (status & I365_CS_STSCHG) | ||
266 | val |= SS_STSCHG; | ||
267 | } else { | ||
268 | if (!(status & I365_CS_BVD1)) | ||
269 | val |= SS_BATDEAD; | ||
270 | else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1) | ||
271 | val |= SS_BATWARN; | ||
272 | } | ||
273 | if ((status & I365_CS_DETECT) == I365_CS_DETECT) | ||
274 | val |= SS_DETECT; | ||
275 | if (status & I365_CS_WRPROT) | ||
276 | val |= SS_WRPROT; | ||
277 | if (status & I365_CS_READY) | ||
278 | val |= SS_READY; | ||
279 | if (status & I365_CS_POWERON) | ||
280 | val |= SS_POWERON; | ||
281 | |||
282 | sense = exca_read_byte(slot, CARD_VOLTAGE_SENSE); | ||
283 | switch (sense) { | ||
284 | case VCC_3VORXV_CAPABLE: | ||
285 | val |= SS_3VCARD | SS_XVCARD; | ||
286 | break; | ||
287 | case VCC_XV_ONLY: | ||
288 | val |= SS_XVCARD; | ||
289 | break; | ||
290 | case VCC_3V_CAPABLE: | ||
291 | val |= SS_3VCARD; | ||
292 | break; | ||
293 | default: | ||
294 | /* 5V only */ | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | *value = val; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static inline u_char get_Vcc_value(uint8_t voltage) | ||
304 | { | ||
305 | switch (voltage) { | ||
306 | case VCC_STATUS_3V: | ||
307 | return 33; | ||
308 | case VCC_STATUS_5V: | ||
309 | return 50; | ||
310 | default: | ||
311 | break; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static inline u_char get_Vpp_value(uint8_t power, u_char Vcc) | ||
318 | { | ||
319 | if ((power & 0x03) == 0x01 || (power & 0x03) == 0x02) | ||
320 | return Vcc; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int pccard_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
326 | { | ||
327 | unsigned int slot; | ||
328 | uint8_t power, voltage, control, cscint; | ||
329 | |||
330 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || state == NULL) | ||
331 | return -EINVAL; | ||
332 | |||
333 | slot = sock->sock; | ||
334 | |||
335 | power = exca_read_byte(slot, I365_POWER); | ||
336 | voltage = exca_read_byte(slot, CARD_VOLTAGE_SELECT); | ||
337 | |||
338 | state->Vcc = get_Vcc_value(voltage); | ||
339 | state->Vpp = get_Vpp_value(power, state->Vcc); | ||
340 | |||
341 | state->flags = 0; | ||
342 | if (power & POWER_ENABLE) | ||
343 | state->flags |= SS_PWR_AUTO; | ||
344 | if (power & I365_PWR_OUT) | ||
345 | state->flags |= SS_OUTPUT_ENA; | ||
346 | |||
347 | control = exca_read_byte(slot, I365_INTCTL); | ||
348 | if (control & I365_PC_IOCARD) | ||
349 | state->flags |= SS_IOCARD; | ||
350 | if (!(control & I365_PC_RESET)) | ||
351 | state->flags |= SS_RESET; | ||
352 | |||
353 | cscint = exca_read_byte(slot, I365_CSCINT); | ||
354 | state->csc_mask = 0; | ||
355 | if (state->flags & SS_IOCARD) { | ||
356 | if (cscint & I365_CSC_STSCHG) | ||
357 | state->flags |= SS_STSCHG; | ||
358 | } else { | ||
359 | if (cscint & I365_CSC_BVD1) | ||
360 | state->csc_mask |= SS_BATDEAD; | ||
361 | if (cscint & I365_CSC_BVD2) | ||
362 | state->csc_mask |= SS_BATWARN; | ||
363 | } | ||
364 | if (cscint & I365_CSC_READY) | ||
365 | state->csc_mask |= SS_READY; | ||
366 | if (cscint & I365_CSC_DETECT) | ||
367 | state->csc_mask |= SS_DETECT; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static inline uint8_t set_Vcc_value(u_char Vcc) | ||
373 | { | ||
374 | switch (Vcc) { | ||
375 | case 33: | ||
376 | return VCC_3V; | ||
377 | case 50: | ||
378 | return VCC_5V; | ||
379 | } | ||
380 | |||
381 | /* Small voltage is chosen for safety. */ | ||
382 | return VCC_3V; | ||
383 | } | ||
384 | |||
385 | static int pccard_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
386 | { | ||
387 | vrc4171_socket_t *socket; | ||
388 | unsigned int slot; | ||
389 | uint8_t voltage, power, control, cscint; | ||
390 | |||
391 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || | ||
392 | (state->Vpp != state->Vcc && state->Vpp != 0) || | ||
393 | (state->Vcc != 50 && state->Vcc != 33 && state->Vcc != 0)) | ||
394 | return -EINVAL; | ||
395 | |||
396 | slot = sock->sock; | ||
397 | socket = &vrc4171_sockets[slot]; | ||
398 | |||
399 | spin_lock_irq(&sock->lock); | ||
400 | |||
401 | voltage = set_Vcc_value(state->Vcc); | ||
402 | exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage); | ||
403 | |||
404 | power = POWER_ENABLE; | ||
405 | if (state->Vpp == state->Vcc) | ||
406 | power |= VPP_GET_VCC; | ||
407 | if (state->flags & SS_OUTPUT_ENA) | ||
408 | power |= I365_PWR_OUT; | ||
409 | exca_write_byte(slot, I365_POWER, power); | ||
410 | |||
411 | control = 0; | ||
412 | if (state->io_irq != 0) | ||
413 | control |= socket->io_irq; | ||
414 | if (state->flags & SS_IOCARD) | ||
415 | control |= I365_PC_IOCARD; | ||
416 | if (state->flags & SS_RESET) | ||
417 | control &= ~I365_PC_RESET; | ||
418 | else | ||
419 | control |= I365_PC_RESET; | ||
420 | exca_write_byte(slot, I365_INTCTL, control); | ||
421 | |||
422 | cscint = 0; | ||
423 | exca_write_byte(slot, I365_CSCINT, cscint); | ||
424 | exca_read_byte(slot, I365_CSC); /* clear CardStatus change */ | ||
425 | if (state->csc_mask != 0) | ||
426 | cscint |= socket->csc_irq << 8; | ||
427 | if (state->flags & SS_IOCARD) { | ||
428 | if (state->csc_mask & SS_STSCHG) | ||
429 | cscint |= I365_CSC_STSCHG; | ||
430 | } else { | ||
431 | if (state->csc_mask & SS_BATDEAD) | ||
432 | cscint |= I365_CSC_BVD1; | ||
433 | if (state->csc_mask & SS_BATWARN) | ||
434 | cscint |= I365_CSC_BVD2; | ||
435 | } | ||
436 | if (state->csc_mask & SS_READY) | ||
437 | cscint |= I365_CSC_READY; | ||
438 | if (state->csc_mask & SS_DETECT) | ||
439 | cscint |= I365_CSC_DETECT; | ||
440 | exca_write_byte(slot, I365_CSCINT, cscint); | ||
441 | |||
442 | spin_unlock_irq(&sock->lock); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int pccard_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | ||
448 | { | ||
449 | unsigned int slot; | ||
450 | uint8_t ioctl, addrwin; | ||
451 | u_char map; | ||
452 | |||
453 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || | ||
454 | io == NULL || io->map >= IO_MAX_MAPS || | ||
455 | io->start > 0xffff || io->stop > 0xffff || io->start > io->stop) | ||
456 | return -EINVAL; | ||
457 | |||
458 | slot = sock->sock; | ||
459 | map = io->map; | ||
460 | |||
461 | addrwin = exca_read_byte(slot, I365_ADDRWIN); | ||
462 | if (addrwin & I365_ENA_IO(map)) { | ||
463 | addrwin &= ~I365_ENA_IO(map); | ||
464 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
465 | } | ||
466 | |||
467 | exca_write_word(slot, I365_IO(map)+I365_W_START, io->start); | ||
468 | exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop); | ||
469 | |||
470 | ioctl = 0; | ||
471 | if (io->speed > 0) | ||
472 | ioctl |= I365_IOCTL_WAIT(map); | ||
473 | if (io->flags & MAP_16BIT) | ||
474 | ioctl |= I365_IOCTL_16BIT(map); | ||
475 | if (io->flags & MAP_AUTOSZ) | ||
476 | ioctl |= I365_IOCTL_IOCS16(map); | ||
477 | if (io->flags & MAP_0WS) | ||
478 | ioctl |= I365_IOCTL_0WS(map); | ||
479 | exca_write_byte(slot, I365_IOCTL, ioctl); | ||
480 | |||
481 | if (io->flags & MAP_ACTIVE) { | ||
482 | addrwin |= I365_ENA_IO(map); | ||
483 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int pccard_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) | ||
490 | { | ||
491 | unsigned int slot; | ||
492 | uint16_t start, stop, offset; | ||
493 | uint8_t addrwin; | ||
494 | u_char map; | ||
495 | |||
496 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || | ||
497 | mem == NULL || mem->map >= MEM_MAX_MAPS || | ||
498 | mem->res->start < CARD_MEM_START || mem->res->start > CARD_MEM_END || | ||
499 | mem->res->end < CARD_MEM_START || mem->res->end > CARD_MEM_END || | ||
500 | mem->res->start > mem->res->end || | ||
501 | mem->card_start > CARD_MAX_MEM_OFFSET || | ||
502 | mem->speed > CARD_MAX_MEM_SPEED) | ||
503 | return -EINVAL; | ||
504 | |||
505 | slot = sock->sock; | ||
506 | map = mem->map; | ||
507 | |||
508 | addrwin = exca_read_byte(slot, I365_ADDRWIN); | ||
509 | if (addrwin & I365_ENA_MEM(map)) { | ||
510 | addrwin &= ~I365_ENA_MEM(map); | ||
511 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
512 | } | ||
513 | |||
514 | start = (mem->res->start >> 12) & 0x3fff; | ||
515 | if (mem->flags & MAP_16BIT) | ||
516 | start |= I365_MEM_16BIT; | ||
517 | exca_write_word(slot, I365_MEM(map)+I365_W_START, start); | ||
518 | |||
519 | stop = (mem->res->end >> 12) & 0x3fff; | ||
520 | switch (mem->speed) { | ||
521 | case 0: | ||
522 | break; | ||
523 | case 1: | ||
524 | stop |= I365_MEM_WS0; | ||
525 | break; | ||
526 | case 2: | ||
527 | stop |= I365_MEM_WS1; | ||
528 | break; | ||
529 | default: | ||
530 | stop |= I365_MEM_WS0 | I365_MEM_WS1; | ||
531 | break; | ||
532 | } | ||
533 | exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop); | ||
534 | |||
535 | offset = (mem->card_start >> 12) & 0x3fff; | ||
536 | if (mem->flags & MAP_ATTRIB) | ||
537 | offset |= I365_MEM_REG; | ||
538 | if (mem->flags & MAP_WRPROT) | ||
539 | offset |= I365_MEM_WRPROT; | ||
540 | exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset); | ||
541 | |||
542 | if (mem->flags & MAP_ACTIVE) { | ||
543 | addrwin |= I365_ENA_MEM(map); | ||
544 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static struct pccard_operations vrc4171_pccard_operations = { | ||
551 | .init = pccard_init, | ||
552 | .get_status = pccard_get_status, | ||
553 | .get_socket = pccard_get_socket, | ||
554 | .set_socket = pccard_set_socket, | ||
555 | .set_io_map = pccard_set_io_map, | ||
556 | .set_mem_map = pccard_set_mem_map, | ||
557 | }; | ||
558 | |||
559 | static inline unsigned int get_events(int slot) | ||
560 | { | ||
561 | unsigned int events = 0; | ||
562 | uint8_t status, csc; | ||
563 | |||
564 | status = exca_read_byte(slot, I365_STATUS); | ||
565 | csc = exca_read_byte(slot, I365_CSC); | ||
566 | |||
567 | if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) { | ||
568 | if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG)) | ||
569 | events |= SS_STSCHG; | ||
570 | } else { | ||
571 | if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) { | ||
572 | if (!(status & I365_CS_BVD1)) | ||
573 | events |= SS_BATDEAD; | ||
574 | else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1) | ||
575 | events |= SS_BATWARN; | ||
576 | } | ||
577 | } | ||
578 | if ((csc & I365_CSC_READY) && (status & I365_CS_READY)) | ||
579 | events |= SS_READY; | ||
580 | if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT)) | ||
581 | events |= SS_DETECT; | ||
582 | |||
583 | return events; | ||
584 | } | ||
585 | |||
586 | static irqreturn_t pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
587 | { | ||
588 | vrc4171_socket_t *socket; | ||
589 | unsigned int events; | ||
590 | irqreturn_t retval = IRQ_NONE; | ||
591 | uint16_t status; | ||
592 | |||
593 | status = vrc4171_get_irq_status(); | ||
594 | if (status & IRQ_A) { | ||
595 | socket = &vrc4171_sockets[CARD_SLOTA]; | ||
596 | if (socket->slot == SLOT_INITIALIZED) { | ||
597 | if (status & (1 << socket->csc_irq)) { | ||
598 | events = get_events(CARD_SLOTA); | ||
599 | if (events != 0) { | ||
600 | pcmcia_parse_events(&socket->pcmcia_socket, events); | ||
601 | retval = IRQ_HANDLED; | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | } | ||
606 | |||
607 | if (status & IRQ_B) { | ||
608 | socket = &vrc4171_sockets[CARD_SLOTB]; | ||
609 | if (socket->slot == SLOT_INITIALIZED) { | ||
610 | if (status & (1 << socket->csc_irq)) { | ||
611 | events = get_events(CARD_SLOTB); | ||
612 | if (events != 0) { | ||
613 | pcmcia_parse_events(&socket->pcmcia_socket, events); | ||
614 | retval = IRQ_HANDLED; | ||
615 | } | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | |||
620 | return retval; | ||
621 | } | ||
622 | |||
623 | static inline void reserve_using_irq(int slot) | ||
624 | { | ||
625 | unsigned int irq; | ||
626 | |||
627 | irq = exca_read_byte(slot, I365_INTCTL); | ||
628 | irq &= 0x0f; | ||
629 | vrc4171_irq_mask &= ~(1 << irq); | ||
630 | |||
631 | irq = exca_read_byte(slot, I365_CSCINT); | ||
632 | irq = (irq & 0xf0) >> 4; | ||
633 | vrc4171_irq_mask &= ~(1 << irq); | ||
634 | } | ||
635 | |||
636 | static int __devinit vrc4171_add_sockets(void) | ||
637 | { | ||
638 | vrc4171_socket_t *socket; | ||
639 | int slot, retval; | ||
640 | |||
641 | for (slot = 0; slot < CARD_MAX_SLOTS; slot++) { | ||
642 | if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE) | ||
643 | continue; | ||
644 | |||
645 | socket = &vrc4171_sockets[slot]; | ||
646 | if (socket->slot != SLOT_PROBE) { | ||
647 | uint8_t addrwin; | ||
648 | |||
649 | switch (socket->slot) { | ||
650 | case SLOT_NOPROBE_MEM: | ||
651 | addrwin = exca_read_byte(slot, I365_ADDRWIN); | ||
652 | addrwin &= 0x1f; | ||
653 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
654 | break; | ||
655 | case SLOT_NOPROBE_IO: | ||
656 | addrwin = exca_read_byte(slot, I365_ADDRWIN); | ||
657 | addrwin &= 0xc0; | ||
658 | exca_write_byte(slot, I365_ADDRWIN, addrwin); | ||
659 | break; | ||
660 | default: | ||
661 | break; | ||
662 | } | ||
663 | |||
664 | reserve_using_irq(slot); | ||
665 | continue; | ||
666 | } | ||
667 | |||
668 | sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot); | ||
669 | socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev; | ||
670 | socket->pcmcia_socket.ops = &vrc4171_pccard_operations; | ||
671 | socket->pcmcia_socket.owner = THIS_MODULE; | ||
672 | |||
673 | retval = pcmcia_register_socket(&socket->pcmcia_socket); | ||
674 | if (retval < 0) | ||
675 | return retval; | ||
676 | |||
677 | exca_write_byte(slot, I365_ADDRWIN, 0); | ||
678 | exca_write_byte(slot, GLOBAL_CONTROL, 0); | ||
679 | |||
680 | socket->slot = SLOT_INITIALIZED; | ||
681 | } | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static void vrc4171_remove_sockets(void) | ||
687 | { | ||
688 | vrc4171_socket_t *socket; | ||
689 | int slot; | ||
690 | |||
691 | for (slot = 0; slot < CARD_MAX_SLOTS; slot++) { | ||
692 | if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE) | ||
693 | continue; | ||
694 | |||
695 | socket = &vrc4171_sockets[slot]; | ||
696 | if (socket->slot == SLOT_INITIALIZED) | ||
697 | pcmcia_unregister_socket(&socket->pcmcia_socket); | ||
698 | |||
699 | socket->slot = SLOT_PROBE; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | static int __devinit vrc4171_card_setup(char *options) | ||
704 | { | ||
705 | if (options == NULL || *options == '\0') | ||
706 | return 0; | ||
707 | |||
708 | if (strncmp(options, "irq:", 4) == 0) { | ||
709 | int irq; | ||
710 | options += 4; | ||
711 | irq = simple_strtoul(options, &options, 0); | ||
712 | if (irq >= 0 && irq < NR_IRQS) | ||
713 | vrc4171_irq = irq; | ||
714 | |||
715 | if (*options != ',') | ||
716 | return 0; | ||
717 | options++; | ||
718 | } | ||
719 | |||
720 | if (strncmp(options, "slota:", 6) == 0) { | ||
721 | options += 6; | ||
722 | if (*options != '\0') { | ||
723 | if (strncmp(options, "memnoprobe", 10) == 0) { | ||
724 | vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_MEM; | ||
725 | options += 10; | ||
726 | } else if (strncmp(options, "ionoprobe", 9) == 0) { | ||
727 | vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_IO; | ||
728 | options += 9; | ||
729 | } else if ( strncmp(options, "noprobe", 7) == 0) { | ||
730 | vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_ALL; | ||
731 | options += 7; | ||
732 | } | ||
733 | |||
734 | if (*options != ',') | ||
735 | return 0; | ||
736 | options++; | ||
737 | } else | ||
738 | return 0; | ||
739 | |||
740 | } | ||
741 | |||
742 | if (strncmp(options, "slotb:", 6) == 0) { | ||
743 | options += 6; | ||
744 | if (*options != '\0') { | ||
745 | if (strncmp(options, "pccard", 6) == 0) { | ||
746 | vrc4171_slotb = SLOTB_IS_PCCARD; | ||
747 | options += 6; | ||
748 | } else if (strncmp(options, "cf", 2) == 0) { | ||
749 | vrc4171_slotb = SLOTB_IS_CF; | ||
750 | options += 2; | ||
751 | } else if (strncmp(options, "flashrom", 8) == 0) { | ||
752 | vrc4171_slotb = SLOTB_IS_FLASHROM; | ||
753 | options += 8; | ||
754 | } else if (strncmp(options, "none", 4) == 0) { | ||
755 | vrc4171_slotb = SLOTB_IS_NONE; | ||
756 | options += 4; | ||
757 | } | ||
758 | |||
759 | if (*options != ',') | ||
760 | return 0; | ||
761 | options++; | ||
762 | |||
763 | if (strncmp(options, "memnoprobe", 10) == 0) | ||
764 | vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_MEM; | ||
765 | if (strncmp(options, "ionoprobe", 9) == 0) | ||
766 | vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_IO; | ||
767 | if (strncmp(options, "noprobe", 7) == 0) | ||
768 | vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_ALL; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | __setup("vrc4171_card=", vrc4171_card_setup); | ||
776 | |||
777 | static int vrc4171_card_suspend(struct device *dev, u32 state, u32 level) | ||
778 | { | ||
779 | int retval = 0; | ||
780 | |||
781 | if (level == SUSPEND_SAVE_STATE) | ||
782 | retval = pcmcia_socket_dev_suspend(dev, state); | ||
783 | |||
784 | return retval; | ||
785 | } | ||
786 | |||
787 | static int vrc4171_card_resume(struct device *dev, u32 level) | ||
788 | { | ||
789 | int retval = 0; | ||
790 | |||
791 | if (level == RESUME_RESTORE_STATE) | ||
792 | retval = pcmcia_socket_dev_resume(dev); | ||
793 | |||
794 | return retval; | ||
795 | } | ||
796 | |||
797 | static struct device_driver vrc4171_card_driver = { | ||
798 | .name = vrc4171_card_name, | ||
799 | .bus = &platform_bus_type, | ||
800 | .suspend = vrc4171_card_suspend, | ||
801 | .resume = vrc4171_card_resume, | ||
802 | }; | ||
803 | |||
804 | static int __devinit vrc4171_card_init(void) | ||
805 | { | ||
806 | int retval; | ||
807 | |||
808 | retval = driver_register(&vrc4171_card_driver); | ||
809 | if (retval < 0) | ||
810 | return retval; | ||
811 | |||
812 | retval = platform_device_register(&vrc4171_card_device); | ||
813 | if (retval < 0) { | ||
814 | driver_unregister(&vrc4171_card_driver); | ||
815 | return retval; | ||
816 | } | ||
817 | |||
818 | vrc4171_set_multifunction_pin(vrc4171_slotb); | ||
819 | |||
820 | retval = vrc4171_add_sockets(); | ||
821 | if (retval == 0) | ||
822 | retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ, | ||
823 | vrc4171_card_name, vrc4171_sockets); | ||
824 | |||
825 | if (retval < 0) { | ||
826 | vrc4171_remove_sockets(); | ||
827 | platform_device_unregister(&vrc4171_card_device); | ||
828 | driver_unregister(&vrc4171_card_driver); | ||
829 | return retval; | ||
830 | } | ||
831 | |||
832 | printk(KERN_INFO "%s, connected to IRQ %d\n", vrc4171_card_driver.name, vrc4171_irq); | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static void __devexit vrc4171_card_exit(void) | ||
838 | { | ||
839 | free_irq(vrc4171_irq, vrc4171_sockets); | ||
840 | vrc4171_remove_sockets(); | ||
841 | platform_device_unregister(&vrc4171_card_device); | ||
842 | driver_unregister(&vrc4171_card_driver); | ||
843 | } | ||
844 | |||
845 | module_init(vrc4171_card_init); | ||
846 | module_exit(vrc4171_card_exit); | ||
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c new file mode 100644 index 000000000000..db91259dc50e --- /dev/null +++ b/drivers/pcmcia/vrc4173_cardu.c | |||
@@ -0,0 +1,617 @@ | |||
1 | /* | ||
2 | * FILE NAME | ||
3 | * drivers/pcmcia/vrc4173_cardu.c | ||
4 | * | ||
5 | * BRIEF MODULE DESCRIPTION | ||
6 | * NEC VRC4173 CARDU driver for Socket Services | ||
7 | * (This device doesn't support CardBus. it is supporting only 16bit PC Card.) | ||
8 | * | ||
9 | * Copyright 2002,2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
24 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
25 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License along | ||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | */ | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | #include <linux/types.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | |||
39 | #include <pcmcia/ss.h> | ||
40 | |||
41 | #include "vrc4173_cardu.h" | ||
42 | |||
43 | MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services"); | ||
44 | MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | static int vrc4173_cardu_slots; | ||
48 | |||
49 | static vrc4173_socket_t cardu_sockets[CARDU_MAX_SOCKETS]; | ||
50 | |||
51 | extern struct socket_info_t *pcmcia_register_socket (int slot, | ||
52 | struct pccard_operations *vtable, | ||
53 | int use_bus_pm); | ||
54 | extern void pcmcia_unregister_socket(struct socket_info_t *s); | ||
55 | |||
56 | static inline uint8_t exca_readb(vrc4173_socket_t *socket, uint16_t offset) | ||
57 | { | ||
58 | return readb(socket->base + EXCA_REGS_BASE + offset); | ||
59 | } | ||
60 | |||
61 | static inline uint16_t exca_readw(vrc4173_socket_t *socket, uint16_t offset) | ||
62 | { | ||
63 | uint16_t val; | ||
64 | |||
65 | val = readb(socket->base + EXCA_REGS_BASE + offset); | ||
66 | val |= (u16)readb(socket->base + EXCA_REGS_BASE + offset + 1) << 8; | ||
67 | |||
68 | return val; | ||
69 | } | ||
70 | |||
71 | static inline void exca_writeb(vrc4173_socket_t *socket, uint16_t offset, uint8_t val) | ||
72 | { | ||
73 | writeb(val, socket->base + EXCA_REGS_BASE + offset); | ||
74 | } | ||
75 | |||
76 | static inline void exca_writew(vrc4173_socket_t *socket, uint8_t offset, uint16_t val) | ||
77 | { | ||
78 | writeb((u8)val, socket->base + EXCA_REGS_BASE + offset); | ||
79 | writeb((u8)(val >> 8), socket->base + EXCA_REGS_BASE + offset + 1); | ||
80 | } | ||
81 | |||
82 | static inline uint32_t cardbus_socket_readl(vrc4173_socket_t *socket, u16 offset) | ||
83 | { | ||
84 | return readl(socket->base + CARDBUS_SOCKET_REGS_BASE + offset); | ||
85 | } | ||
86 | |||
87 | static inline void cardbus_socket_writel(vrc4173_socket_t *socket, u16 offset, uint32_t val) | ||
88 | { | ||
89 | writel(val, socket->base + CARDBUS_SOCKET_REGS_BASE + offset); | ||
90 | } | ||
91 | |||
92 | static void cardu_pciregs_init(struct pci_dev *dev) | ||
93 | { | ||
94 | u32 syscnt; | ||
95 | u16 brgcnt; | ||
96 | u8 devcnt; | ||
97 | |||
98 | pci_write_config_dword(dev, 0x1c, 0x10000000); | ||
99 | pci_write_config_dword(dev, 0x20, 0x17fff000); | ||
100 | pci_write_config_dword(dev, 0x2c, 0); | ||
101 | pci_write_config_dword(dev, 0x30, 0xfffc); | ||
102 | |||
103 | pci_read_config_word(dev, BRGCNT, &brgcnt); | ||
104 | brgcnt &= ~IREQ_INT; | ||
105 | pci_write_config_word(dev, BRGCNT, brgcnt); | ||
106 | |||
107 | pci_read_config_dword(dev, SYSCNT, &syscnt); | ||
108 | syscnt &= ~(BAD_VCC_REQ_DISB|PCPCI_EN|CH_ASSIGN_MASK|SUB_ID_WR_EN|PCI_CLK_RIN); | ||
109 | syscnt |= (CH_ASSIGN_NODMA|ASYN_INT_MODE); | ||
110 | pci_write_config_dword(dev, SYSCNT, syscnt); | ||
111 | |||
112 | pci_read_config_byte(dev, DEVCNT, &devcnt); | ||
113 | devcnt &= ~(ZOOM_VIDEO_EN|SR_PCI_INT_SEL_MASK|PCI_INT_MODE|IRQ_MODE); | ||
114 | devcnt |= (SR_PCI_INT_SEL_NONE|IFG); | ||
115 | pci_write_config_byte(dev, DEVCNT, devcnt); | ||
116 | |||
117 | pci_write_config_byte(dev, CHIPCNT, S_PREF_DISB); | ||
118 | |||
119 | pci_write_config_byte(dev, SERRDIS, 0); | ||
120 | } | ||
121 | |||
122 | static int cardu_init(unsigned int slot) | ||
123 | { | ||
124 | vrc4173_socket_t *socket = &cardu_sockets[slot]; | ||
125 | |||
126 | cardu_pciregs_init(socket->dev); | ||
127 | |||
128 | /* CARD_SC bits are cleared by reading CARD_SC. */ | ||
129 | exca_writeb(socket, GLO_CNT, 0); | ||
130 | |||
131 | socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS; | ||
132 | socket->cap.irq_mask = 0; | ||
133 | socket->cap.map_size = 0x1000; | ||
134 | socket->cap.pci_irq = socket->dev->irq; | ||
135 | socket->events = 0; | ||
136 | spin_lock_init(socket->event_lock); | ||
137 | |||
138 | /* Enable PC Card status interrupts */ | ||
139 | exca_writeb(socket, CARD_SCI, CARD_DT_EN|RDY_EN|BAT_WAR_EN|BAT_DEAD_EN); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int cardu_register_callback(unsigned int sock, | ||
145 | void (*handler)(void *, unsigned int), | ||
146 | void * info) | ||
147 | { | ||
148 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
149 | |||
150 | socket->handler = handler; | ||
151 | socket->info = info; | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int cardu_inquire_socket(unsigned int sock, socket_cap_t *cap) | ||
157 | { | ||
158 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
159 | |||
160 | *cap = socket->cap; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int cardu_get_status(unsigned int sock, u_int *value) | ||
166 | { | ||
167 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
168 | uint32_t state; | ||
169 | uint8_t status; | ||
170 | u_int val = 0; | ||
171 | |||
172 | status = exca_readb(socket, IF_STATUS); | ||
173 | if (status & CARD_PWR) val |= SS_POWERON; | ||
174 | if (status & READY) val |= SS_READY; | ||
175 | if (status & CARD_WP) val |= SS_WRPROT; | ||
176 | if ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2)) | ||
177 | val |= SS_DETECT; | ||
178 | if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) { | ||
179 | if (status & STSCHG) val |= SS_STSCHG; | ||
180 | } else { | ||
181 | status &= BV_DETECT_MASK; | ||
182 | if (status != BV_DETECT_GOOD) { | ||
183 | if (status == BV_DETECT_WARN) val |= SS_BATWARN; | ||
184 | else val |= SS_BATDEAD; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | state = cardbus_socket_readl(socket, SKT_PRE_STATE); | ||
189 | if (state & VOL_3V_CARD_DT) val |= SS_3VCARD; | ||
190 | if (state & VOL_XV_CARD_DT) val |= SS_XVCARD; | ||
191 | if (state & CB_CARD_DT) val |= SS_CARDBUS; | ||
192 | if (!(state & | ||
193 | (VOL_YV_CARD_DT|VOL_XV_CARD_DT|VOL_3V_CARD_DT|VOL_5V_CARD_DT|CCD20|CCD10))) | ||
194 | val |= SS_PENDING; | ||
195 | |||
196 | *value = val; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static inline u_char get_Vcc_value(uint8_t val) | ||
202 | { | ||
203 | switch (val & VCC_MASK) { | ||
204 | case VCC_3V: | ||
205 | return 33; | ||
206 | case VCC_5V: | ||
207 | return 50; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static inline u_char get_Vpp_value(uint8_t val) | ||
214 | { | ||
215 | switch (val & VPP_MASK) { | ||
216 | case VPP_12V: | ||
217 | return 120; | ||
218 | case VPP_VCC: | ||
219 | return get_Vcc_value(val); | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int cardu_get_socket(unsigned int sock, socket_state_t *state) | ||
226 | { | ||
227 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
228 | uint8_t val; | ||
229 | |||
230 | val = exca_readb(socket, PWR_CNT); | ||
231 | state->Vcc = get_Vcc_value(val); | ||
232 | state->Vpp = get_Vpp_value(val); | ||
233 | state->flags = 0; | ||
234 | if (val & CARD_OUT_EN) state->flags |= SS_OUTPUT_ENA; | ||
235 | |||
236 | val = exca_readb(socket, INT_GEN_CNT); | ||
237 | if (!(val & CARD_REST0)) state->flags |= SS_RESET; | ||
238 | if (val & CARD_TYPE_IO) state->flags |= SS_IOCARD; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static inline uint8_t set_Vcc_value(u_char Vcc) | ||
244 | { | ||
245 | switch (Vcc) { | ||
246 | case 33: | ||
247 | return VCC_3V; | ||
248 | case 50: | ||
249 | return VCC_5V; | ||
250 | } | ||
251 | |||
252 | return VCC_0V; | ||
253 | } | ||
254 | |||
255 | static inline uint8_t set_Vpp_value(u_char Vpp) | ||
256 | { | ||
257 | switch (Vpp) { | ||
258 | case 33: | ||
259 | case 50: | ||
260 | return VPP_VCC; | ||
261 | case 120: | ||
262 | return VPP_12V; | ||
263 | } | ||
264 | |||
265 | return VPP_0V; | ||
266 | } | ||
267 | |||
268 | static int cardu_set_socket(unsigned int sock, socket_state_t *state) | ||
269 | { | ||
270 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
271 | uint8_t val; | ||
272 | |||
273 | if (((state->Vpp == 33) || (state->Vpp == 50)) && (state->Vpp != state->Vcc)) | ||
274 | return -EINVAL; | ||
275 | |||
276 | val = set_Vcc_value(state->Vcc); | ||
277 | val |= set_Vpp_value(state->Vpp); | ||
278 | if (state->flags & SS_OUTPUT_ENA) val |= CARD_OUT_EN; | ||
279 | exca_writeb(socket, PWR_CNT, val); | ||
280 | |||
281 | val = exca_readb(socket, INT_GEN_CNT) & CARD_REST0; | ||
282 | if (state->flags & SS_RESET) val &= ~CARD_REST0; | ||
283 | else val |= CARD_REST0; | ||
284 | if (state->flags & SS_IOCARD) val |= CARD_TYPE_IO; | ||
285 | exca_writeb(socket, INT_GEN_CNT, val); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int cardu_get_io_map(unsigned int sock, struct pccard_io_map *io) | ||
291 | { | ||
292 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
293 | uint8_t ioctl, window; | ||
294 | u_char map; | ||
295 | |||
296 | map = io->map; | ||
297 | if (map > 1) | ||
298 | return -EINVAL; | ||
299 | |||
300 | io->start = exca_readw(socket, IO_WIN_SA(map)); | ||
301 | io->stop = exca_readw(socket, IO_WIN_EA(map)); | ||
302 | |||
303 | ioctl = exca_readb(socket, IO_WIN_CNT); | ||
304 | window = exca_readb(socket, ADR_WIN_EN); | ||
305 | io->flags = (window & IO_WIN_EN(map)) ? MAP_ACTIVE : 0; | ||
306 | if (ioctl & IO_WIN_DATA_AUTOSZ(map)) | ||
307 | io->flags |= MAP_AUTOSZ; | ||
308 | else if (ioctl & IO_WIN_DATA_16BIT(map)) | ||
309 | io->flags |= MAP_16BIT; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int cardu_set_io_map(unsigned int sock, struct pccard_io_map *io) | ||
315 | { | ||
316 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
317 | uint16_t ioctl; | ||
318 | uint8_t window, enable; | ||
319 | u_char map; | ||
320 | |||
321 | map = io->map; | ||
322 | if (map > 1) | ||
323 | return -EINVAL; | ||
324 | |||
325 | window = exca_readb(socket, ADR_WIN_EN); | ||
326 | enable = IO_WIN_EN(map); | ||
327 | |||
328 | if (window & enable) { | ||
329 | window &= ~enable; | ||
330 | exca_writeb(socket, ADR_WIN_EN, window); | ||
331 | } | ||
332 | |||
333 | exca_writew(socket, IO_WIN_SA(map), io->start); | ||
334 | exca_writew(socket, IO_WIN_EA(map), io->stop); | ||
335 | |||
336 | ioctl = exca_readb(socket, IO_WIN_CNT) & ~IO_WIN_CNT_MASK(map); | ||
337 | if (io->flags & MAP_AUTOSZ) ioctl |= IO_WIN_DATA_AUTOSZ(map); | ||
338 | else if (io->flags & MAP_16BIT) ioctl |= IO_WIN_DATA_16BIT(map); | ||
339 | exca_writeb(socket, IO_WIN_CNT, ioctl); | ||
340 | |||
341 | if (io->flags & MAP_ACTIVE) | ||
342 | exca_writeb(socket, ADR_WIN_EN, window | enable); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int cardu_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) | ||
348 | { | ||
349 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
350 | uint32_t start, stop, offset, page; | ||
351 | uint8_t window; | ||
352 | u_char map; | ||
353 | |||
354 | map = mem->map; | ||
355 | if (map > 4) | ||
356 | return -EINVAL; | ||
357 | |||
358 | window = exca_readb(socket, ADR_WIN_EN); | ||
359 | mem->flags = (window & MEM_WIN_EN(map)) ? MAP_ACTIVE : 0; | ||
360 | |||
361 | start = exca_readw(socket, MEM_WIN_SA(map)); | ||
362 | mem->flags |= (start & MEM_WIN_DSIZE) ? MAP_16BIT : 0; | ||
363 | start = (start & 0x0fff) << 12; | ||
364 | |||
365 | stop = exca_readw(socket, MEM_WIN_EA(map)); | ||
366 | stop = ((stop & 0x0fff) << 12) + 0x0fff; | ||
367 | |||
368 | offset = exca_readw(socket, MEM_WIN_OA(map)); | ||
369 | mem->flags |= (offset & MEM_WIN_WP) ? MAP_WRPROT : 0; | ||
370 | mem->flags |= (offset & MEM_WIN_REGSET) ? MAP_ATTRIB : 0; | ||
371 | offset = ((offset & 0x3fff) << 12) + start; | ||
372 | mem->card_start = offset & 0x03ffffff; | ||
373 | |||
374 | page = exca_readb(socket, MEM_WIN_SAU(map)) << 24; | ||
375 | mem->sys_start = start + page; | ||
376 | mem->sys_stop = start + page; | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int cardu_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) | ||
382 | { | ||
383 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
384 | uint16_t value; | ||
385 | uint8_t window, enable; | ||
386 | u_long sys_start, sys_stop, card_start; | ||
387 | u_char map; | ||
388 | |||
389 | map = mem->map; | ||
390 | sys_start = mem->sys_start; | ||
391 | sys_stop = mem->sys_stop; | ||
392 | card_start = mem->card_start; | ||
393 | |||
394 | if (map > 4 || sys_start > sys_stop || ((sys_start ^ sys_stop) >> 24) || | ||
395 | (card_start >> 26)) | ||
396 | return -EINVAL; | ||
397 | |||
398 | window = exca_readb(socket, ADR_WIN_EN); | ||
399 | enable = MEM_WIN_EN(map); | ||
400 | if (window & enable) { | ||
401 | window &= ~enable; | ||
402 | exca_writeb(socket, ADR_WIN_EN, window); | ||
403 | } | ||
404 | |||
405 | exca_writeb(socket, MEM_WIN_SAU(map), sys_start >> 24); | ||
406 | |||
407 | value = (sys_start >> 12) & 0x0fff; | ||
408 | if (mem->flags & MAP_16BIT) value |= MEM_WIN_DSIZE; | ||
409 | exca_writew(socket, MEM_WIN_SA(map), value); | ||
410 | |||
411 | value = (sys_stop >> 12) & 0x0fff; | ||
412 | exca_writew(socket, MEM_WIN_EA(map), value); | ||
413 | |||
414 | value = ((card_start - sys_start) >> 12) & 0x3fff; | ||
415 | if (mem->flags & MAP_WRPROT) value |= MEM_WIN_WP; | ||
416 | if (mem->flags & MAP_ATTRIB) value |= MEM_WIN_REGSET; | ||
417 | exca_writew(socket, MEM_WIN_OA(map), value); | ||
418 | |||
419 | if (mem->flags & MAP_ACTIVE) | ||
420 | exca_writeb(socket, ADR_WIN_EN, window | enable); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static void cardu_proc_setup(unsigned int sock, struct proc_dir_entry *base) | ||
426 | { | ||
427 | } | ||
428 | |||
429 | static struct pccard_operations cardu_operations = { | ||
430 | .init = cardu_init, | ||
431 | .register_callback = cardu_register_callback, | ||
432 | .inquire_socket = cardu_inquire_socket, | ||
433 | .get_status = cardu_get_status, | ||
434 | .get_socket = cardu_get_socket, | ||
435 | .set_socket = cardu_set_socket, | ||
436 | .get_io_map = cardu_get_io_map, | ||
437 | .set_io_map = cardu_set_io_map, | ||
438 | .get_mem_map = cardu_get_mem_map, | ||
439 | .set_mem_map = cardu_set_mem_map, | ||
440 | .proc_setup = cardu_proc_setup, | ||
441 | }; | ||
442 | |||
443 | static void cardu_bh(void *data) | ||
444 | { | ||
445 | vrc4173_socket_t *socket = (vrc4173_socket_t *)data; | ||
446 | uint16_t events; | ||
447 | |||
448 | spin_lock_irq(&socket->event_lock); | ||
449 | events = socket->events; | ||
450 | socket->events = 0; | ||
451 | spin_unlock_irq(&socket->event_lock); | ||
452 | |||
453 | if (socket->handler) | ||
454 | socket->handler(socket->info, events); | ||
455 | } | ||
456 | |||
457 | static uint16_t get_events(vrc4173_socket_t *socket) | ||
458 | { | ||
459 | uint16_t events = 0; | ||
460 | uint8_t csc, status; | ||
461 | |||
462 | status = exca_readb(socket, IF_STATUS); | ||
463 | csc = exca_readb(socket, CARD_SC); | ||
464 | if ((csc & CARD_DT_CHG) && | ||
465 | ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2))) | ||
466 | events |= SS_DETECT; | ||
467 | |||
468 | if ((csc & RDY_CHG) && (status & READY)) | ||
469 | events |= SS_READY; | ||
470 | |||
471 | if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) { | ||
472 | if ((csc & BAT_DEAD_ST_CHG) && (status & STSCHG)) | ||
473 | events |= SS_STSCHG; | ||
474 | } else { | ||
475 | if (csc & (BAT_WAR_CHG|BAT_DEAD_ST_CHG)) { | ||
476 | if ((status & BV_DETECT_MASK) != BV_DETECT_GOOD) { | ||
477 | if (status == BV_DETECT_WARN) events |= SS_BATWARN; | ||
478 | else events |= SS_BATDEAD; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | |||
483 | return events; | ||
484 | } | ||
485 | |||
486 | static void cardu_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
487 | { | ||
488 | vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id; | ||
489 | uint16_t events; | ||
490 | |||
491 | INIT_WORK(&socket->tq_work, cardu_bh, socket); | ||
492 | |||
493 | events = get_events(socket); | ||
494 | if (events) { | ||
495 | spin_lock(&socket->event_lock); | ||
496 | socket->events |= events; | ||
497 | spin_unlock(&socket->event_lock); | ||
498 | schedule_work(&socket->tq_work); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static int __devinit vrc4173_cardu_probe(struct pci_dev *dev, | ||
503 | const struct pci_device_id *ent) | ||
504 | { | ||
505 | vrc4173_socket_t *socket; | ||
506 | unsigned long start, len, flags; | ||
507 | int slot, err; | ||
508 | |||
509 | slot = vrc4173_cardu_slots++; | ||
510 | socket = &cardu_sockets[slot]; | ||
511 | if (socket->noprobe != 0) | ||
512 | return -EBUSY; | ||
513 | |||
514 | sprintf(socket->name, "NEC VRC4173 CARDU%1d", slot+1); | ||
515 | |||
516 | if ((err = pci_enable_device(dev)) < 0) | ||
517 | return err; | ||
518 | |||
519 | start = pci_resource_start(dev, 0); | ||
520 | if (start == 0) | ||
521 | return -ENODEV; | ||
522 | |||
523 | len = pci_resource_len(dev, 0); | ||
524 | if (len == 0) | ||
525 | return -ENODEV; | ||
526 | |||
527 | if (((flags = pci_resource_flags(dev, 0)) & IORESOURCE_MEM) == 0) | ||
528 | return -EBUSY; | ||
529 | |||
530 | if ((err = pci_request_regions(dev, socket->name)) < 0) | ||
531 | return err; | ||
532 | |||
533 | socket->base = ioremap(start, len); | ||
534 | if (socket->base == NULL) | ||
535 | return -ENODEV; | ||
536 | |||
537 | socket->dev = dev; | ||
538 | |||
539 | socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1); | ||
540 | if (socket->pcmcia_socket == NULL) { | ||
541 | iounmap(socket->base); | ||
542 | socket->base = NULL; | ||
543 | return -ENOMEM; | ||
544 | } | ||
545 | |||
546 | if (request_irq(dev->irq, cardu_interrupt, SA_SHIRQ, socket->name, socket) < 0) { | ||
547 | pcmcia_unregister_socket(socket->pcmcia_socket); | ||
548 | socket->pcmcia_socket = NULL; | ||
549 | iounmap(socket->base); | ||
550 | socket->base = NULL; | ||
551 | return -EBUSY; | ||
552 | } | ||
553 | |||
554 | printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int __devinit vrc4173_cardu_setup(char *options) | ||
560 | { | ||
561 | if (options == NULL || *options == '\0') | ||
562 | return 0; | ||
563 | |||
564 | if (strncmp(options, "cardu1:", 7) == 0) { | ||
565 | options += 7; | ||
566 | if (*options != '\0') { | ||
567 | if (strncmp(options, "noprobe", 7) == 0) { | ||
568 | cardu_sockets[CARDU1].noprobe = 1; | ||
569 | options += 7; | ||
570 | } | ||
571 | |||
572 | if (*options != ',') | ||
573 | return 0; | ||
574 | } else | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | if (strncmp(options, "cardu2:", 7) == 0) { | ||
579 | options += 7; | ||
580 | if ((*options != '\0') && (strncmp(options, "noprobe", 7) == 0)) | ||
581 | cardu_sockets[CARDU2].noprobe = 1; | ||
582 | } | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | __setup("vrc4173_cardu=", vrc4173_cardu_setup); | ||
588 | |||
589 | static struct pci_device_id vrc4173_cardu_id_table[] __devinitdata = { | ||
590 | { .vendor = PCI_VENDOR_ID_NEC, | ||
591 | .device = PCI_DEVICE_ID_NEC_NAPCCARD, | ||
592 | .subvendor = PCI_ANY_ID, | ||
593 | .subdevice = PCI_ANY_ID, }, | ||
594 | {0, } | ||
595 | }; | ||
596 | |||
597 | static struct pci_driver vrc4173_cardu_driver = { | ||
598 | .name = "NEC VRC4173 CARDU", | ||
599 | .probe = vrc4173_cardu_probe, | ||
600 | .id_table = vrc4173_cardu_id_table, | ||
601 | }; | ||
602 | |||
603 | static int __devinit vrc4173_cardu_init(void) | ||
604 | { | ||
605 | vrc4173_cardu_slots = 0; | ||
606 | |||
607 | return pci_module_init(&vrc4173_cardu_driver); | ||
608 | } | ||
609 | |||
610 | static void __devexit vrc4173_cardu_exit(void) | ||
611 | { | ||
612 | pci_unregister_driver(&vrc4173_cardu_driver); | ||
613 | } | ||
614 | |||
615 | module_init(vrc4173_cardu_init); | ||
616 | module_exit(vrc4173_cardu_exit); | ||
617 | MODULE_DEVICE_TABLE(pci, vrc4173_cardu_id_table); | ||
diff --git a/drivers/pcmcia/vrc4173_cardu.h b/drivers/pcmcia/vrc4173_cardu.h new file mode 100644 index 000000000000..113726f7cf92 --- /dev/null +++ b/drivers/pcmcia/vrc4173_cardu.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * FILE NAME | ||
3 | * drivers/pcmcia/vrc4173_cardu.h | ||
4 | * | ||
5 | * BRIEF MODULE DESCRIPTION | ||
6 | * Include file for NEC VRC4173 CARDU. | ||
7 | * | ||
8 | * Copyright 2002 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
20 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
21 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
23 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
24 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License along | ||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | #ifndef _VRC4173_CARDU_H | ||
31 | #define _VRC4173_CARDU_H | ||
32 | |||
33 | #include <linux/pci.h> | ||
34 | |||
35 | #include <pcmcia/ss.h> | ||
36 | |||
37 | #define CARDU_MAX_SOCKETS 2 | ||
38 | #define CARDU1 0 | ||
39 | #define CARDU2 1 | ||
40 | |||
41 | /* | ||
42 | * PCI Configuration Registers | ||
43 | */ | ||
44 | #define BRGCNT 0x3e | ||
45 | #define POST_WR_EN 0x0400 | ||
46 | #define MEM1_PREF_EN 0x0200 | ||
47 | #define MEM0_PREF_EN 0x0100 | ||
48 | #define IREQ_INT 0x0080 | ||
49 | #define CARD_RST 0x0040 | ||
50 | #define MABORT_MODE 0x0020 | ||
51 | #define VGA_EN 0x0008 | ||
52 | #define ISA_EN 0x0004 | ||
53 | #define SERR_EN 0x0002 | ||
54 | #define PERR_EN 0x0001 | ||
55 | |||
56 | #define SYSCNT 0x80 | ||
57 | #define BAD_VCC_REQ_DISB 0x00200000 | ||
58 | #define PCPCI_EN 0x00080000 | ||
59 | #define CH_ASSIGN_MASK 0x00070000 | ||
60 | #define CH_ASSIGN_NODMA 0x00040000 | ||
61 | #define SUB_ID_WR_EN 0x00000008 | ||
62 | #define ASYN_INT_MODE 0x00000004 | ||
63 | #define PCI_CLK_RIN 0x00000002 | ||
64 | |||
65 | #define DEVCNT 0x91 | ||
66 | #define ZOOM_VIDEO_EN 0x40 | ||
67 | #define SR_PCI_INT_SEL_MASK 0x18 | ||
68 | #define SR_PCI_INT_SEL_NONE 0x00 | ||
69 | #define PCI_INT_MODE 0x04 | ||
70 | #define IRQ_MODE 0x02 | ||
71 | #define IFG 0x01 | ||
72 | |||
73 | #define CHIPCNT 0x9c | ||
74 | #define S_PREF_DISB 0x10 | ||
75 | |||
76 | #define SERRDIS 0x9f | ||
77 | #define SERR_DIS_MAB 0x10 | ||
78 | #define SERR_DIS_TAB 0x08 | ||
79 | #define SERR_DIS_DT_PERR 0x04 | ||
80 | |||
81 | /* | ||
82 | * ExCA Registers | ||
83 | */ | ||
84 | #define EXCA_REGS_BASE 0x800 | ||
85 | #define EXCA_REGS_SIZE 0x800 | ||
86 | |||
87 | #define ID_REV 0x000 | ||
88 | #define IF_TYPE_16BIT 0x80 | ||
89 | |||
90 | #define IF_STATUS 0x001 | ||
91 | #define CARD_PWR 0x40 | ||
92 | #define READY 0x20 | ||
93 | #define CARD_WP 0x10 | ||
94 | #define CARD_DETECT2 0x08 | ||
95 | #define CARD_DETECT1 0x04 | ||
96 | #define BV_DETECT_MASK 0x03 | ||
97 | #define BV_DETECT_GOOD 0x03 /* Memory card */ | ||
98 | #define BV_DETECT_WARN 0x02 | ||
99 | #define BV_DETECT_BAD1 0x01 | ||
100 | #define BV_DETECT_BAD0 0x00 | ||
101 | #define STSCHG 0x02 /* I/O card */ | ||
102 | #define SPKR 0x01 | ||
103 | |||
104 | #define PWR_CNT 0x002 | ||
105 | #define CARD_OUT_EN 0x80 | ||
106 | #define VCC_MASK 0x18 | ||
107 | #define VCC_3V 0x18 | ||
108 | #define VCC_5V 0x10 | ||
109 | #define VCC_0V 0x00 | ||
110 | #define VPP_MASK 0x03 | ||
111 | #define VPP_12V 0x02 | ||
112 | #define VPP_VCC 0x01 | ||
113 | #define VPP_0V 0x00 | ||
114 | |||
115 | #define INT_GEN_CNT 0x003 | ||
116 | #define CARD_REST0 0x40 | ||
117 | #define CARD_TYPE_MASK 0x20 | ||
118 | #define CARD_TYPE_IO 0x20 | ||
119 | #define CARD_TYPE_MEM 0x00 | ||
120 | |||
121 | #define CARD_SC 0x004 | ||
122 | #define CARD_DT_CHG 0x08 | ||
123 | #define RDY_CHG 0x04 | ||
124 | #define BAT_WAR_CHG 0x02 | ||
125 | #define BAT_DEAD_ST_CHG 0x01 | ||
126 | |||
127 | #define CARD_SCI 0x005 | ||
128 | #define CARD_DT_EN 0x08 | ||
129 | #define RDY_EN 0x04 | ||
130 | #define BAT_WAR_EN 0x02 | ||
131 | #define BAT_DEAD_EN 0x01 | ||
132 | |||
133 | #define ADR_WIN_EN 0x006 | ||
134 | #define IO_WIN_EN(x) (0x40 << (x)) | ||
135 | #define MEM_WIN_EN(x) (0x01 << (x)) | ||
136 | |||
137 | #define IO_WIN_CNT 0x007 | ||
138 | #define IO_WIN_CNT_MASK(x) (0x03 << ((x) << 2)) | ||
139 | #define IO_WIN_DATA_AUTOSZ(x) (0x02 << ((x) << 2)) | ||
140 | #define IO_WIN_DATA_16BIT(x) (0x01 << ((x) << 2)) | ||
141 | |||
142 | #define IO_WIN_SA(x) (0x008 + ((x) << 2)) | ||
143 | #define IO_WIN_EA(x) (0x00a + ((x) << 2)) | ||
144 | |||
145 | #define MEM_WIN_SA(x) (0x010 + ((x) << 3)) | ||
146 | #define MEM_WIN_DSIZE 0x8000 | ||
147 | |||
148 | #define MEM_WIN_EA(x) (0x012 + ((x) << 3)) | ||
149 | |||
150 | #define MEM_WIN_OA(x) (0x014 + ((x) << 3)) | ||
151 | #define MEM_WIN_WP 0x8000 | ||
152 | #define MEM_WIN_REGSET 0x4000 | ||
153 | |||
154 | #define GEN_CNT 0x016 | ||
155 | #define VS2_STATUS 0x80 | ||
156 | #define VS1_STATUS 0x40 | ||
157 | #define EXCA_REG_RST_EN 0x02 | ||
158 | |||
159 | #define GLO_CNT 0x01e | ||
160 | #define FUN_INT_LEV 0x08 | ||
161 | #define INT_WB_CLR 0x04 | ||
162 | #define CSC_INT_LEV 0x02 | ||
163 | |||
164 | #define IO_WIN_OAL(x) (0x036 + ((x) << 1)) | ||
165 | #define IO_WIN_OAH(x) (0x037 + ((x) << 1)) | ||
166 | |||
167 | #define MEM_WIN_SAU(x) (0x040 + (x)) | ||
168 | |||
169 | #define IO_SETUP_TIM 0x080 | ||
170 | #define IO_CMD_TIM 0x081 | ||
171 | #define IO_HOLD_TIM 0x082 | ||
172 | #define MEM_SETUP_TIM(x) (0x084 + ((x) << 2)) | ||
173 | #define MEM_CMD_TIM(x) (0x085 + ((x) << 2)) | ||
174 | #define MEM_HOLD_TIM(x) (0x086 + ((x) << 2)) | ||
175 | #define TIM_CLOCKS(x) ((x) - 1) | ||
176 | |||
177 | #define MEM_TIM_SEL1 0x08c | ||
178 | #define MEM_TIM_SEL2 0x08d | ||
179 | #define MEM_WIN_TIMSEL1(x) (0x03 << (((x) & 3) << 1)) | ||
180 | |||
181 | #define MEM_WIN_PWEN 0x091 | ||
182 | #define POSTWEN 0x01 | ||
183 | |||
184 | /* | ||
185 | * CardBus Socket Registers | ||
186 | */ | ||
187 | #define CARDBUS_SOCKET_REGS_BASE 0x000 | ||
188 | #define CARDBUS_SOCKET_REGS_SIZE 0x800 | ||
189 | |||
190 | #define SKT_EV 0x000 | ||
191 | #define POW_CYC_EV 0x00000008 | ||
192 | #define CCD2_EV 0x00000004 | ||
193 | #define CCD1_EV 0x00000002 | ||
194 | #define CSTSCHG_EV 0x00000001 | ||
195 | |||
196 | #define SKT_MASK 0x004 | ||
197 | #define POW_CYC_MASK 0x00000008 | ||
198 | #define CCD_MASK 0x00000006 | ||
199 | #define CSC_MASK 0x00000001 | ||
200 | |||
201 | #define SKT_PRE_STATE 0x008 | ||
202 | #define SKT_FORCE_EV 0x00c | ||
203 | #define VOL_3V_SKT 0x20000000 | ||
204 | #define VOL_5V_SKT 0x10000000 | ||
205 | #define CVS_TEST 0x00004000 | ||
206 | #define VOL_YV_CARD_DT 0x00002000 | ||
207 | #define VOL_XV_CARD_DT 0x00001000 | ||
208 | #define VOL_3V_CARD_DT 0x00000800 | ||
209 | #define VOL_5V_CARD_DT 0x00000400 | ||
210 | #define BAD_VCC_REQ 0x00000200 | ||
211 | #define DATA_LOST 0x00000100 | ||
212 | #define NOT_A_CARD 0x00000080 | ||
213 | #define CREADY 0x00000040 | ||
214 | #define CB_CARD_DT 0x00000020 | ||
215 | #define R2_CARD_DT 0x00000010 | ||
216 | #define POW_UP 0x00000008 | ||
217 | #define CCD20 0x00000004 | ||
218 | #define CCD10 0x00000002 | ||
219 | #define CSTSCHG 0x00000001 | ||
220 | |||
221 | #define SKT_CNT 0x010 | ||
222 | #define STP_CLK_EN 0x00000080 | ||
223 | #define VCC_CNT_MASK 0x00000070 | ||
224 | #define VCC_CNT_3V 0x00000030 | ||
225 | #define VCC_CNT_5V 0x00000020 | ||
226 | #define VCC_CNT_0V 0x00000000 | ||
227 | #define VPP_CNT_MASK 0x00000007 | ||
228 | #define VPP_CNT_3V 0x00000003 | ||
229 | #define VPP_CNT_5V 0x00000002 | ||
230 | #define VPP_CNT_12V 0x00000001 | ||
231 | #define VPP_CNT_0V 0x00000000 | ||
232 | |||
233 | typedef struct vrc4173_socket { | ||
234 | int noprobe; | ||
235 | struct pci_dev *dev; | ||
236 | void *base; | ||
237 | void (*handler)(void *, unsigned int); | ||
238 | void *info; | ||
239 | socket_cap_t cap; | ||
240 | spinlock_t event_lock; | ||
241 | uint16_t events; | ||
242 | struct socket_info_t *pcmcia_socket; | ||
243 | struct work_struct tq_work; | ||
244 | char name[20]; | ||
245 | } vrc4173_socket_t; | ||
246 | |||
247 | #endif /* _VRC4173_CARDU_H */ | ||
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c new file mode 100644 index 000000000000..6404d97a12eb --- /dev/null +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -0,0 +1,1160 @@ | |||
1 | /* | ||
2 | * Regular cardbus driver ("yenta_socket") | ||
3 | * | ||
4 | * (C) Copyright 1999, 2000 Linus Torvalds | ||
5 | * | ||
6 | * Changelog: | ||
7 | * Aug 2002: Manfred Spraul <manfred@colorfullife.com> | ||
8 | * Dynamically adjust the size of the bridge resource | ||
9 | * | ||
10 | * May 2003: Dominik Brodowski <linux@brodo.de> | ||
11 | * Merge pci_socket.c and yenta.c into one file | ||
12 | */ | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/workqueue.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/module.h> | ||
20 | |||
21 | #include <pcmcia/version.h> | ||
22 | #include <pcmcia/cs_types.h> | ||
23 | #include <pcmcia/ss.h> | ||
24 | #include <pcmcia/cs.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "yenta_socket.h" | ||
29 | #include "i82365.h" | ||
30 | |||
31 | static int disable_clkrun; | ||
32 | module_param(disable_clkrun, bool, 0444); | ||
33 | MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); | ||
34 | |||
35 | #if 0 | ||
36 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) | ||
37 | #else | ||
38 | #define debug(x,args...) | ||
39 | #endif | ||
40 | |||
41 | /* Don't ask.. */ | ||
42 | #define to_cycles(ns) ((ns)/120) | ||
43 | #define to_ns(cycles) ((cycles)*120) | ||
44 | |||
45 | static int yenta_probe_cb_irq(struct yenta_socket *socket); | ||
46 | |||
47 | |||
48 | static unsigned int override_bios; | ||
49 | module_param(override_bios, uint, 0000); | ||
50 | MODULE_PARM_DESC (override_bios, "yenta ignore bios resource allocation"); | ||
51 | |||
52 | /* | ||
53 | * Generate easy-to-use ways of reading a cardbus sockets | ||
54 | * regular memory space ("cb_xxx"), configuration space | ||
55 | * ("config_xxx") and compatibility space ("exca_xxxx") | ||
56 | */ | ||
57 | static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg) | ||
58 | { | ||
59 | u32 val = readl(socket->base + reg); | ||
60 | debug("%p %04x %08x\n", socket, reg, val); | ||
61 | return val; | ||
62 | } | ||
63 | |||
64 | static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) | ||
65 | { | ||
66 | debug("%p %04x %08x\n", socket, reg, val); | ||
67 | writel(val, socket->base + reg); | ||
68 | } | ||
69 | |||
70 | static inline u8 config_readb(struct yenta_socket *socket, unsigned offset) | ||
71 | { | ||
72 | u8 val; | ||
73 | pci_read_config_byte(socket->dev, offset, &val); | ||
74 | debug("%p %04x %02x\n", socket, offset, val); | ||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static inline u16 config_readw(struct yenta_socket *socket, unsigned offset) | ||
79 | { | ||
80 | u16 val; | ||
81 | pci_read_config_word(socket->dev, offset, &val); | ||
82 | debug("%p %04x %04x\n", socket, offset, val); | ||
83 | return val; | ||
84 | } | ||
85 | |||
86 | static inline u32 config_readl(struct yenta_socket *socket, unsigned offset) | ||
87 | { | ||
88 | u32 val; | ||
89 | pci_read_config_dword(socket->dev, offset, &val); | ||
90 | debug("%p %04x %08x\n", socket, offset, val); | ||
91 | return val; | ||
92 | } | ||
93 | |||
94 | static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val) | ||
95 | { | ||
96 | debug("%p %04x %02x\n", socket, offset, val); | ||
97 | pci_write_config_byte(socket->dev, offset, val); | ||
98 | } | ||
99 | |||
100 | static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val) | ||
101 | { | ||
102 | debug("%p %04x %04x\n", socket, offset, val); | ||
103 | pci_write_config_word(socket->dev, offset, val); | ||
104 | } | ||
105 | |||
106 | static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val) | ||
107 | { | ||
108 | debug("%p %04x %08x\n", socket, offset, val); | ||
109 | pci_write_config_dword(socket->dev, offset, val); | ||
110 | } | ||
111 | |||
112 | static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg) | ||
113 | { | ||
114 | u8 val = readb(socket->base + 0x800 + reg); | ||
115 | debug("%p %04x %02x\n", socket, reg, val); | ||
116 | return val; | ||
117 | } | ||
118 | |||
119 | static inline u8 exca_readw(struct yenta_socket *socket, unsigned reg) | ||
120 | { | ||
121 | u16 val; | ||
122 | val = readb(socket->base + 0x800 + reg); | ||
123 | val |= readb(socket->base + 0x800 + reg + 1) << 8; | ||
124 | debug("%p %04x %04x\n", socket, reg, val); | ||
125 | return val; | ||
126 | } | ||
127 | |||
128 | static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val) | ||
129 | { | ||
130 | debug("%p %04x %02x\n", socket, reg, val); | ||
131 | writeb(val, socket->base + 0x800 + reg); | ||
132 | } | ||
133 | |||
134 | static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) | ||
135 | { | ||
136 | debug("%p %04x %04x\n", socket, reg, val); | ||
137 | writeb(val, socket->base + 0x800 + reg); | ||
138 | writeb(val >> 8, socket->base + 0x800 + reg + 1); | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend | ||
143 | * on what kind of card is inserted.. | ||
144 | */ | ||
145 | static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) | ||
146 | { | ||
147 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
148 | unsigned int val; | ||
149 | u32 state = cb_readl(socket, CB_SOCKET_STATE); | ||
150 | |||
151 | val = (state & CB_3VCARD) ? SS_3VCARD : 0; | ||
152 | val |= (state & CB_XVCARD) ? SS_XVCARD : 0; | ||
153 | val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD | ||
154 | | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; | ||
155 | |||
156 | if (state & CB_CBCARD) { | ||
157 | val |= SS_CARDBUS; | ||
158 | val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; | ||
159 | val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; | ||
160 | val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; | ||
161 | } else { | ||
162 | u8 status = exca_readb(socket, I365_STATUS); | ||
163 | val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; | ||
164 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { | ||
165 | val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; | ||
166 | } else { | ||
167 | val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; | ||
168 | val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; | ||
169 | } | ||
170 | val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; | ||
171 | val |= (status & I365_CS_READY) ? SS_READY : 0; | ||
172 | val |= (status & I365_CS_POWERON) ? SS_POWERON : 0; | ||
173 | } | ||
174 | |||
175 | *value = val; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int yenta_Vcc_power(u32 control) | ||
180 | { | ||
181 | switch (control & CB_SC_VCC_MASK) { | ||
182 | case CB_SC_VCC_5V: return 50; | ||
183 | case CB_SC_VCC_3V: return 33; | ||
184 | default: return 0; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static int yenta_Vpp_power(u32 control) | ||
189 | { | ||
190 | switch (control & CB_SC_VPP_MASK) { | ||
191 | case CB_SC_VPP_12V: return 120; | ||
192 | case CB_SC_VPP_5V: return 50; | ||
193 | case CB_SC_VPP_3V: return 33; | ||
194 | default: return 0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
199 | { | ||
200 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
201 | u8 reg; | ||
202 | u32 control; | ||
203 | |||
204 | control = cb_readl(socket, CB_SOCKET_CONTROL); | ||
205 | |||
206 | state->Vcc = yenta_Vcc_power(control); | ||
207 | state->Vpp = yenta_Vpp_power(control); | ||
208 | state->io_irq = socket->io_irq; | ||
209 | |||
210 | if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { | ||
211 | u16 bridge = config_readw(socket, CB_BRIDGE_CONTROL); | ||
212 | if (bridge & CB_BRIDGE_CRST) | ||
213 | state->flags |= SS_RESET; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* 16-bit card state.. */ | ||
218 | reg = exca_readb(socket, I365_POWER); | ||
219 | state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; | ||
220 | state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; | ||
221 | |||
222 | reg = exca_readb(socket, I365_INTCTL); | ||
223 | state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; | ||
224 | state->flags |= (reg & I365_PC_IOCARD) ? SS_IOCARD : 0; | ||
225 | |||
226 | reg = exca_readb(socket, I365_CSCINT); | ||
227 | state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
228 | if (state->flags & SS_IOCARD) { | ||
229 | state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
230 | } else { | ||
231 | state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
232 | state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
233 | state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) | ||
240 | { | ||
241 | u32 reg = 0; /* CB_SC_STPCLK? */ | ||
242 | switch (state->Vcc) { | ||
243 | case 33: reg = CB_SC_VCC_3V; break; | ||
244 | case 50: reg = CB_SC_VCC_5V; break; | ||
245 | default: reg = 0; break; | ||
246 | } | ||
247 | switch (state->Vpp) { | ||
248 | case 33: reg |= CB_SC_VPP_3V; break; | ||
249 | case 50: reg |= CB_SC_VPP_5V; break; | ||
250 | case 120: reg |= CB_SC_VPP_12V; break; | ||
251 | } | ||
252 | if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) | ||
253 | cb_writel(socket, CB_SOCKET_CONTROL, reg); | ||
254 | } | ||
255 | |||
256 | static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
257 | { | ||
258 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
259 | u16 bridge; | ||
260 | |||
261 | yenta_set_power(socket, state); | ||
262 | socket->io_irq = state->io_irq; | ||
263 | bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); | ||
264 | if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { | ||
265 | u8 intr; | ||
266 | bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; | ||
267 | |||
268 | /* ISA interrupt control? */ | ||
269 | intr = exca_readb(socket, I365_INTCTL); | ||
270 | intr = (intr & ~0xf); | ||
271 | if (!socket->cb_irq) { | ||
272 | intr |= state->io_irq; | ||
273 | bridge |= CB_BRIDGE_INTR; | ||
274 | } | ||
275 | exca_writeb(socket, I365_INTCTL, intr); | ||
276 | } else { | ||
277 | u8 reg; | ||
278 | |||
279 | reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA); | ||
280 | reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; | ||
281 | reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; | ||
282 | if (state->io_irq != socket->cb_irq) { | ||
283 | reg |= state->io_irq; | ||
284 | bridge |= CB_BRIDGE_INTR; | ||
285 | } | ||
286 | exca_writeb(socket, I365_INTCTL, reg); | ||
287 | |||
288 | reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK); | ||
289 | reg |= I365_PWR_NORESET; | ||
290 | if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; | ||
291 | if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; | ||
292 | if (exca_readb(socket, I365_POWER) != reg) | ||
293 | exca_writeb(socket, I365_POWER, reg); | ||
294 | |||
295 | /* CSC interrupt: no ISA irq for CSC */ | ||
296 | reg = I365_CSC_DETECT; | ||
297 | if (state->flags & SS_IOCARD) { | ||
298 | if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; | ||
299 | } else { | ||
300 | if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; | ||
301 | if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; | ||
302 | if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; | ||
303 | } | ||
304 | exca_writeb(socket, I365_CSCINT, reg); | ||
305 | exca_readb(socket, I365_CSC); | ||
306 | if(sock->zoom_video) | ||
307 | sock->zoom_video(sock, state->flags & SS_ZVCARD); | ||
308 | } | ||
309 | config_writew(socket, CB_BRIDGE_CONTROL, bridge); | ||
310 | /* Socket event mask: get card insert/remove events.. */ | ||
311 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
312 | cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | ||
317 | { | ||
318 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
319 | int map; | ||
320 | unsigned char ioctl, addr, enable; | ||
321 | |||
322 | map = io->map; | ||
323 | |||
324 | if (map > 1) | ||
325 | return -EINVAL; | ||
326 | |||
327 | enable = I365_ENA_IO(map); | ||
328 | addr = exca_readb(socket, I365_ADDRWIN); | ||
329 | |||
330 | /* Disable the window before changing it.. */ | ||
331 | if (addr & enable) { | ||
332 | addr &= ~enable; | ||
333 | exca_writeb(socket, I365_ADDRWIN, addr); | ||
334 | } | ||
335 | |||
336 | exca_writew(socket, I365_IO(map)+I365_W_START, io->start); | ||
337 | exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop); | ||
338 | |||
339 | ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); | ||
340 | if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); | ||
341 | if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); | ||
342 | if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); | ||
343 | exca_writeb(socket, I365_IOCTL, ioctl); | ||
344 | |||
345 | if (io->flags & MAP_ACTIVE) | ||
346 | exca_writeb(socket, I365_ADDRWIN, addr | enable); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) | ||
351 | { | ||
352 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
353 | struct pci_bus_region region; | ||
354 | int map; | ||
355 | unsigned char addr, enable; | ||
356 | unsigned int start, stop, card_start; | ||
357 | unsigned short word; | ||
358 | |||
359 | pcibios_resource_to_bus(socket->dev, ®ion, mem->res); | ||
360 | |||
361 | map = mem->map; | ||
362 | start = region.start; | ||
363 | stop = region.end; | ||
364 | card_start = mem->card_start; | ||
365 | |||
366 | if (map > 4 || start > stop || ((start ^ stop) >> 24) || | ||
367 | (card_start >> 26) || mem->speed > 1000) | ||
368 | return -EINVAL; | ||
369 | |||
370 | enable = I365_ENA_MEM(map); | ||
371 | addr = exca_readb(socket, I365_ADDRWIN); | ||
372 | if (addr & enable) { | ||
373 | addr &= ~enable; | ||
374 | exca_writeb(socket, I365_ADDRWIN, addr); | ||
375 | } | ||
376 | |||
377 | exca_writeb(socket, CB_MEM_PAGE(map), start >> 24); | ||
378 | |||
379 | word = (start >> 12) & 0x0fff; | ||
380 | if (mem->flags & MAP_16BIT) | ||
381 | word |= I365_MEM_16BIT; | ||
382 | if (mem->flags & MAP_0WS) | ||
383 | word |= I365_MEM_0WS; | ||
384 | exca_writew(socket, I365_MEM(map) + I365_W_START, word); | ||
385 | |||
386 | word = (stop >> 12) & 0x0fff; | ||
387 | switch (to_cycles(mem->speed)) { | ||
388 | case 0: break; | ||
389 | case 1: word |= I365_MEM_WS0; break; | ||
390 | case 2: word |= I365_MEM_WS1; break; | ||
391 | default: word |= I365_MEM_WS1 | I365_MEM_WS0; break; | ||
392 | } | ||
393 | exca_writew(socket, I365_MEM(map) + I365_W_STOP, word); | ||
394 | |||
395 | word = ((card_start - start) >> 12) & 0x3fff; | ||
396 | if (mem->flags & MAP_WRPROT) | ||
397 | word |= I365_MEM_WRPROT; | ||
398 | if (mem->flags & MAP_ATTRIB) | ||
399 | word |= I365_MEM_REG; | ||
400 | exca_writew(socket, I365_MEM(map) + I365_W_OFF, word); | ||
401 | |||
402 | if (mem->flags & MAP_ACTIVE) | ||
403 | exca_writeb(socket, I365_ADDRWIN, addr | enable); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | |||
408 | static unsigned int yenta_events(struct yenta_socket *socket) | ||
409 | { | ||
410 | u8 csc; | ||
411 | u32 cb_event; | ||
412 | unsigned int events; | ||
413 | |||
414 | /* Clear interrupt status for the event */ | ||
415 | cb_event = cb_readl(socket, CB_SOCKET_EVENT); | ||
416 | cb_writel(socket, CB_SOCKET_EVENT, cb_event); | ||
417 | |||
418 | csc = exca_readb(socket, I365_CSC); | ||
419 | |||
420 | events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; | ||
421 | events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
422 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { | ||
423 | events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
424 | } else { | ||
425 | events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
426 | events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
427 | events |= (csc & I365_CSC_READY) ? SS_READY : 0; | ||
428 | } | ||
429 | return events; | ||
430 | } | ||
431 | |||
432 | |||
433 | static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
434 | { | ||
435 | unsigned int events; | ||
436 | struct yenta_socket *socket = (struct yenta_socket *) dev_id; | ||
437 | |||
438 | events = yenta_events(socket); | ||
439 | if (events) { | ||
440 | pcmcia_parse_events(&socket->socket, events); | ||
441 | return IRQ_HANDLED; | ||
442 | } | ||
443 | return IRQ_NONE; | ||
444 | } | ||
445 | |||
446 | static void yenta_interrupt_wrapper(unsigned long data) | ||
447 | { | ||
448 | struct yenta_socket *socket = (struct yenta_socket *) data; | ||
449 | |||
450 | yenta_interrupt(0, (void *)socket, NULL); | ||
451 | socket->poll_timer.expires = jiffies + HZ; | ||
452 | add_timer(&socket->poll_timer); | ||
453 | } | ||
454 | |||
455 | static void yenta_clear_maps(struct yenta_socket *socket) | ||
456 | { | ||
457 | int i; | ||
458 | struct resource res = { .start = 0, .end = 0x0fff }; | ||
459 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
460 | pccard_mem_map mem = { .res = &res, }; | ||
461 | |||
462 | yenta_set_socket(&socket->socket, &dead_socket); | ||
463 | for (i = 0; i < 2; i++) { | ||
464 | io.map = i; | ||
465 | yenta_set_io_map(&socket->socket, &io); | ||
466 | } | ||
467 | for (i = 0; i < 5; i++) { | ||
468 | mem.map = i; | ||
469 | yenta_set_mem_map(&socket->socket, &mem); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /* Called at resume and initialization events */ | ||
474 | static int yenta_sock_init(struct pcmcia_socket *sock) | ||
475 | { | ||
476 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
477 | u32 state; | ||
478 | u16 bridge; | ||
479 | |||
480 | bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_INTR; | ||
481 | if (!socket->cb_irq) | ||
482 | bridge |= CB_BRIDGE_INTR; | ||
483 | config_writew(socket, CB_BRIDGE_CONTROL, bridge); | ||
484 | |||
485 | exca_writeb(socket, I365_GBLCTL, 0x00); | ||
486 | exca_writeb(socket, I365_GENCTL, 0x00); | ||
487 | |||
488 | /* Redo card voltage interrogation */ | ||
489 | state = cb_readl(socket, CB_SOCKET_STATE); | ||
490 | if (!(state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | | ||
491 | CB_3VCARD | CB_XVCARD | CB_YVCARD))) | ||
492 | cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); | ||
493 | |||
494 | yenta_clear_maps(socket); | ||
495 | |||
496 | if (socket->type && socket->type->sock_init) | ||
497 | socket->type->sock_init(socket); | ||
498 | |||
499 | /* Re-enable CSC interrupts */ | ||
500 | cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int yenta_sock_suspend(struct pcmcia_socket *sock) | ||
506 | { | ||
507 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
508 | |||
509 | /* Disable CSC interrupts */ | ||
510 | cb_writel(socket, CB_SOCKET_MASK, 0x0); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Use an adaptive allocation for the memory resource, | ||
517 | * sometimes the memory behind pci bridges is limited: | ||
518 | * 1/8 of the size of the io window of the parent. | ||
519 | * max 4 MB, min 16 kB. | ||
520 | */ | ||
521 | #define BRIDGE_MEM_MAX 4*1024*1024 | ||
522 | #define BRIDGE_MEM_MIN 16*1024 | ||
523 | |||
524 | #define BRIDGE_IO_MAX 256 | ||
525 | #define BRIDGE_IO_MIN 32 | ||
526 | |||
527 | #ifndef PCIBIOS_MIN_CARDBUS_IO | ||
528 | #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO | ||
529 | #endif | ||
530 | |||
531 | static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) | ||
532 | { | ||
533 | struct pci_bus *bus; | ||
534 | struct resource *root, *res; | ||
535 | u32 start, end; | ||
536 | u32 align, size, min; | ||
537 | unsigned offset; | ||
538 | unsigned mask; | ||
539 | |||
540 | /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ | ||
541 | mask = ~0xfff; | ||
542 | if (type & IORESOURCE_IO) | ||
543 | mask = ~3; | ||
544 | |||
545 | offset = 0x1c + 8*nr; | ||
546 | bus = socket->dev->subordinate; | ||
547 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; | ||
548 | res->name = bus->name; | ||
549 | res->flags = type; | ||
550 | res->start = 0; | ||
551 | res->end = 0; | ||
552 | root = pci_find_parent_resource(socket->dev, res); | ||
553 | |||
554 | if (!root) | ||
555 | return; | ||
556 | |||
557 | start = config_readl(socket, offset) & mask; | ||
558 | end = config_readl(socket, offset+4) | ~mask; | ||
559 | if (start && end > start && !override_bios) { | ||
560 | res->start = start; | ||
561 | res->end = end; | ||
562 | if (request_resource(root, res) == 0) | ||
563 | return; | ||
564 | printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", | ||
565 | pci_name(socket->dev), nr); | ||
566 | res->start = res->end = 0; | ||
567 | } | ||
568 | |||
569 | if (type & IORESOURCE_IO) { | ||
570 | align = 1024; | ||
571 | size = BRIDGE_IO_MAX; | ||
572 | min = BRIDGE_IO_MIN; | ||
573 | start = PCIBIOS_MIN_CARDBUS_IO; | ||
574 | end = ~0U; | ||
575 | } else { | ||
576 | unsigned long avail = root->end - root->start; | ||
577 | int i; | ||
578 | size = BRIDGE_MEM_MAX; | ||
579 | if (size > avail/8) { | ||
580 | size=(avail+1)/8; | ||
581 | /* round size down to next power of 2 */ | ||
582 | i = 0; | ||
583 | while ((size /= 2) != 0) | ||
584 | i++; | ||
585 | size = 1 << i; | ||
586 | } | ||
587 | if (size < BRIDGE_MEM_MIN) | ||
588 | size = BRIDGE_MEM_MIN; | ||
589 | min = BRIDGE_MEM_MIN; | ||
590 | align = size; | ||
591 | start = PCIBIOS_MIN_MEM; | ||
592 | end = ~0U; | ||
593 | } | ||
594 | |||
595 | do { | ||
596 | if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { | ||
597 | config_writel(socket, offset, res->start); | ||
598 | config_writel(socket, offset+4, res->end); | ||
599 | return; | ||
600 | } | ||
601 | size = size/2; | ||
602 | align = size; | ||
603 | } while (size >= min); | ||
604 | printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", | ||
605 | pci_name(socket->dev), type); | ||
606 | res->start = res->end = 0; | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * Allocate the bridge mappings for the device.. | ||
611 | */ | ||
612 | static void yenta_allocate_resources(struct yenta_socket *socket) | ||
613 | { | ||
614 | yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); | ||
615 | yenta_allocate_res(socket, 1, IORESOURCE_MEM); | ||
616 | yenta_allocate_res(socket, 2, IORESOURCE_IO); | ||
617 | yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ | ||
618 | } | ||
619 | |||
620 | |||
621 | /* | ||
622 | * Free the bridge mappings for the device.. | ||
623 | */ | ||
624 | static void yenta_free_resources(struct yenta_socket *socket) | ||
625 | { | ||
626 | int i; | ||
627 | for (i=0;i<4;i++) { | ||
628 | struct resource *res; | ||
629 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; | ||
630 | if (res->start != 0 && res->end != 0) | ||
631 | release_resource(res); | ||
632 | res->start = res->end = 0; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | |||
637 | /* | ||
638 | * Close it down - release our resources and go home.. | ||
639 | */ | ||
640 | static void yenta_close(struct pci_dev *dev) | ||
641 | { | ||
642 | struct yenta_socket *sock = pci_get_drvdata(dev); | ||
643 | |||
644 | /* we don't want a dying socket registered */ | ||
645 | pcmcia_unregister_socket(&sock->socket); | ||
646 | |||
647 | /* Disable all events so we don't die in an IRQ storm */ | ||
648 | cb_writel(sock, CB_SOCKET_MASK, 0x0); | ||
649 | exca_writeb(sock, I365_CSCINT, 0); | ||
650 | |||
651 | if (sock->cb_irq) | ||
652 | free_irq(sock->cb_irq, sock); | ||
653 | else | ||
654 | del_timer_sync(&sock->poll_timer); | ||
655 | |||
656 | if (sock->base) | ||
657 | iounmap(sock->base); | ||
658 | yenta_free_resources(sock); | ||
659 | |||
660 | pci_release_regions(dev); | ||
661 | pci_disable_device(dev); | ||
662 | pci_set_drvdata(dev, NULL); | ||
663 | } | ||
664 | |||
665 | |||
666 | static struct pccard_operations yenta_socket_operations = { | ||
667 | .init = yenta_sock_init, | ||
668 | .suspend = yenta_sock_suspend, | ||
669 | .get_status = yenta_get_status, | ||
670 | .get_socket = yenta_get_socket, | ||
671 | .set_socket = yenta_set_socket, | ||
672 | .set_io_map = yenta_set_io_map, | ||
673 | .set_mem_map = yenta_set_mem_map, | ||
674 | }; | ||
675 | |||
676 | |||
677 | #include "ti113x.h" | ||
678 | #include "ricoh.h" | ||
679 | #include "topic.h" | ||
680 | #include "o2micro.h" | ||
681 | |||
682 | enum { | ||
683 | CARDBUS_TYPE_DEFAULT = -1, | ||
684 | CARDBUS_TYPE_TI, | ||
685 | CARDBUS_TYPE_TI113X, | ||
686 | CARDBUS_TYPE_TI12XX, | ||
687 | CARDBUS_TYPE_TI1250, | ||
688 | CARDBUS_TYPE_RICOH, | ||
689 | CARDBUS_TYPE_TOPIC97, | ||
690 | CARDBUS_TYPE_O2MICRO, | ||
691 | }; | ||
692 | |||
693 | /* | ||
694 | * Different cardbus controllers have slightly different | ||
695 | * initialization sequences etc details. List them here.. | ||
696 | */ | ||
697 | static struct cardbus_type cardbus_type[] = { | ||
698 | [CARDBUS_TYPE_TI] = { | ||
699 | .override = ti_override, | ||
700 | .save_state = ti_save_state, | ||
701 | .restore_state = ti_restore_state, | ||
702 | .sock_init = ti_init, | ||
703 | }, | ||
704 | [CARDBUS_TYPE_TI113X] = { | ||
705 | .override = ti113x_override, | ||
706 | .save_state = ti_save_state, | ||
707 | .restore_state = ti_restore_state, | ||
708 | .sock_init = ti_init, | ||
709 | }, | ||
710 | [CARDBUS_TYPE_TI12XX] = { | ||
711 | .override = ti12xx_override, | ||
712 | .save_state = ti_save_state, | ||
713 | .restore_state = ti_restore_state, | ||
714 | .sock_init = ti_init, | ||
715 | }, | ||
716 | [CARDBUS_TYPE_TI1250] = { | ||
717 | .override = ti1250_override, | ||
718 | .save_state = ti_save_state, | ||
719 | .restore_state = ti_restore_state, | ||
720 | .sock_init = ti_init, | ||
721 | }, | ||
722 | [CARDBUS_TYPE_RICOH] = { | ||
723 | .override = ricoh_override, | ||
724 | .save_state = ricoh_save_state, | ||
725 | .restore_state = ricoh_restore_state, | ||
726 | }, | ||
727 | [CARDBUS_TYPE_TOPIC97] = { | ||
728 | .override = topic97_override, | ||
729 | }, | ||
730 | [CARDBUS_TYPE_O2MICRO] = { | ||
731 | .override = o2micro_override, | ||
732 | .restore_state = o2micro_restore_state, | ||
733 | }, | ||
734 | }; | ||
735 | |||
736 | |||
737 | /* | ||
738 | * Only probe "regular" interrupts, don't | ||
739 | * touch dangerous spots like the mouse irq, | ||
740 | * because there are mice that apparently | ||
741 | * get really confused if they get fondled | ||
742 | * too intimately. | ||
743 | * | ||
744 | * Default to 11, 10, 9, 7, 6, 5, 4, 3. | ||
745 | */ | ||
746 | static u32 isa_interrupts = 0x0ef8; | ||
747 | |||
748 | static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask) | ||
749 | { | ||
750 | int i; | ||
751 | unsigned long val; | ||
752 | u16 bridge_ctrl; | ||
753 | u32 mask; | ||
754 | |||
755 | /* Set up ISA irq routing to probe the ISA irqs.. */ | ||
756 | bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); | ||
757 | if (!(bridge_ctrl & CB_BRIDGE_INTR)) { | ||
758 | bridge_ctrl |= CB_BRIDGE_INTR; | ||
759 | config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); | ||
760 | } | ||
761 | |||
762 | /* | ||
763 | * Probe for usable interrupts using the force | ||
764 | * register to generate bogus card status events. | ||
765 | */ | ||
766 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
767 | cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); | ||
768 | exca_writeb(socket, I365_CSCINT, 0); | ||
769 | val = probe_irq_on() & isa_irq_mask; | ||
770 | for (i = 1; i < 16; i++) { | ||
771 | if (!((val >> i) & 1)) | ||
772 | continue; | ||
773 | exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); | ||
774 | cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); | ||
775 | udelay(100); | ||
776 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
777 | } | ||
778 | cb_writel(socket, CB_SOCKET_MASK, 0); | ||
779 | exca_writeb(socket, I365_CSCINT, 0); | ||
780 | |||
781 | mask = probe_irq_mask(val) & 0xffff; | ||
782 | |||
783 | bridge_ctrl &= ~CB_BRIDGE_INTR; | ||
784 | config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); | ||
785 | |||
786 | return mask; | ||
787 | } | ||
788 | |||
789 | |||
790 | /* interrupt handler, only used during probing */ | ||
791 | static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
792 | { | ||
793 | struct yenta_socket *socket = (struct yenta_socket *) dev_id; | ||
794 | u8 csc; | ||
795 | u32 cb_event; | ||
796 | |||
797 | /* Clear interrupt status for the event */ | ||
798 | cb_event = cb_readl(socket, CB_SOCKET_EVENT); | ||
799 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
800 | csc = exca_readb(socket, I365_CSC); | ||
801 | |||
802 | if (cb_event || csc) { | ||
803 | socket->probe_status = 1; | ||
804 | return IRQ_HANDLED; | ||
805 | } | ||
806 | |||
807 | return IRQ_NONE; | ||
808 | } | ||
809 | |||
810 | /* probes the PCI interrupt, use only on override functions */ | ||
811 | static int yenta_probe_cb_irq(struct yenta_socket *socket) | ||
812 | { | ||
813 | u16 bridge_ctrl; | ||
814 | |||
815 | if (!socket->cb_irq) | ||
816 | return -1; | ||
817 | |||
818 | socket->probe_status = 0; | ||
819 | |||
820 | /* disable ISA interrupts */ | ||
821 | bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); | ||
822 | bridge_ctrl &= ~CB_BRIDGE_INTR; | ||
823 | config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); | ||
824 | |||
825 | if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket)) { | ||
826 | printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n"); | ||
827 | return -1; | ||
828 | } | ||
829 | |||
830 | /* generate interrupt, wait */ | ||
831 | exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG); | ||
832 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
833 | cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); | ||
834 | cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); | ||
835 | |||
836 | msleep(100); | ||
837 | |||
838 | /* disable interrupts */ | ||
839 | cb_writel(socket, CB_SOCKET_MASK, 0); | ||
840 | exca_writeb(socket, I365_CSCINT, 0); | ||
841 | cb_writel(socket, CB_SOCKET_EVENT, -1); | ||
842 | exca_readb(socket, I365_CSC); | ||
843 | |||
844 | free_irq(socket->cb_irq, socket); | ||
845 | |||
846 | return (int) socket->probe_status; | ||
847 | } | ||
848 | |||
849 | |||
850 | |||
851 | /* | ||
852 | * Set static data that doesn't need re-initializing.. | ||
853 | */ | ||
854 | static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask) | ||
855 | { | ||
856 | socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; | ||
857 | socket->socket.map_size = 0x1000; | ||
858 | socket->socket.pci_irq = socket->cb_irq; | ||
859 | socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); | ||
860 | socket->socket.cb_dev = socket->dev; | ||
861 | |||
862 | printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n", | ||
863 | socket->socket.irq_mask, socket->cb_irq); | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * Initialize the standard cardbus registers | ||
868 | */ | ||
869 | static void yenta_config_init(struct yenta_socket *socket) | ||
870 | { | ||
871 | u16 bridge; | ||
872 | struct pci_dev *dev = socket->dev; | ||
873 | |||
874 | pci_set_power_state(socket->dev, 0); | ||
875 | |||
876 | config_writel(socket, CB_LEGACY_MODE_BASE, 0); | ||
877 | config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); | ||
878 | config_writew(socket, PCI_COMMAND, | ||
879 | PCI_COMMAND_IO | | ||
880 | PCI_COMMAND_MEMORY | | ||
881 | PCI_COMMAND_MASTER | | ||
882 | PCI_COMMAND_WAIT); | ||
883 | |||
884 | /* MAGIC NUMBERS! Fixme */ | ||
885 | config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); | ||
886 | config_writeb(socket, PCI_LATENCY_TIMER, 168); | ||
887 | config_writel(socket, PCI_PRIMARY_BUS, | ||
888 | (176 << 24) | /* sec. latency timer */ | ||
889 | (dev->subordinate->subordinate << 16) | /* subordinate bus */ | ||
890 | (dev->subordinate->secondary << 8) | /* secondary bus */ | ||
891 | dev->subordinate->primary); /* primary bus */ | ||
892 | |||
893 | /* | ||
894 | * Set up the bridging state: | ||
895 | * - enable write posting. | ||
896 | * - memory window 0 prefetchable, window 1 non-prefetchable | ||
897 | * - PCI interrupts enabled if a PCI interrupt exists.. | ||
898 | */ | ||
899 | bridge = config_readw(socket, CB_BRIDGE_CONTROL); | ||
900 | bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); | ||
901 | bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN | CB_BRIDGE_INTR; | ||
902 | config_writew(socket, CB_BRIDGE_CONTROL, bridge); | ||
903 | } | ||
904 | |||
905 | /* | ||
906 | * Initialize a cardbus controller. Make sure we have a usable | ||
907 | * interrupt, and that we can map the cardbus area. Fill in the | ||
908 | * socket information structure.. | ||
909 | */ | ||
910 | static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_id *id) | ||
911 | { | ||
912 | struct yenta_socket *socket; | ||
913 | int ret; | ||
914 | |||
915 | socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); | ||
916 | if (!socket) | ||
917 | return -ENOMEM; | ||
918 | memset(socket, 0, sizeof(*socket)); | ||
919 | |||
920 | /* prepare pcmcia_socket */ | ||
921 | socket->socket.ops = ¥ta_socket_operations; | ||
922 | socket->socket.resource_ops = &pccard_nonstatic_ops; | ||
923 | socket->socket.dev.dev = &dev->dev; | ||
924 | socket->socket.driver_data = socket; | ||
925 | socket->socket.owner = THIS_MODULE; | ||
926 | |||
927 | /* prepare struct yenta_socket */ | ||
928 | socket->dev = dev; | ||
929 | pci_set_drvdata(dev, socket); | ||
930 | |||
931 | /* | ||
932 | * Do some basic sanity checking.. | ||
933 | */ | ||
934 | if (pci_enable_device(dev)) { | ||
935 | ret = -EBUSY; | ||
936 | goto free; | ||
937 | } | ||
938 | |||
939 | ret = pci_request_regions(dev, "yenta_socket"); | ||
940 | if (ret) | ||
941 | goto disable; | ||
942 | |||
943 | if (!pci_resource_start(dev, 0)) { | ||
944 | printk(KERN_ERR "No cardbus resource!\n"); | ||
945 | ret = -ENODEV; | ||
946 | goto release; | ||
947 | } | ||
948 | |||
949 | /* | ||
950 | * Ok, start setup.. Map the cardbus registers, | ||
951 | * and request the IRQ. | ||
952 | */ | ||
953 | socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); | ||
954 | if (!socket->base) { | ||
955 | ret = -ENOMEM; | ||
956 | goto release; | ||
957 | } | ||
958 | |||
959 | /* | ||
960 | * report the subsystem vendor and device for help debugging | ||
961 | * the irq stuff... | ||
962 | */ | ||
963 | printk(KERN_INFO "Yenta: CardBus bridge found at %s [%04x:%04x]\n", | ||
964 | pci_name(dev), dev->subsystem_vendor, dev->subsystem_device); | ||
965 | |||
966 | yenta_config_init(socket); | ||
967 | |||
968 | /* Disable all events */ | ||
969 | cb_writel(socket, CB_SOCKET_MASK, 0x0); | ||
970 | |||
971 | /* Set up the bridge regions.. */ | ||
972 | yenta_allocate_resources(socket); | ||
973 | |||
974 | socket->cb_irq = dev->irq; | ||
975 | |||
976 | /* Do we have special options for the device? */ | ||
977 | if (id->driver_data != CARDBUS_TYPE_DEFAULT && | ||
978 | id->driver_data < ARRAY_SIZE(cardbus_type)) { | ||
979 | socket->type = &cardbus_type[id->driver_data]; | ||
980 | |||
981 | ret = socket->type->override(socket); | ||
982 | if (ret < 0) | ||
983 | goto unmap; | ||
984 | } | ||
985 | |||
986 | /* We must finish initialization here */ | ||
987 | |||
988 | if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, "yenta", socket)) { | ||
989 | /* No IRQ or request_irq failed. Poll */ | ||
990 | socket->cb_irq = 0; /* But zero is a valid IRQ number. */ | ||
991 | init_timer(&socket->poll_timer); | ||
992 | socket->poll_timer.function = yenta_interrupt_wrapper; | ||
993 | socket->poll_timer.data = (unsigned long)socket; | ||
994 | socket->poll_timer.expires = jiffies + HZ; | ||
995 | add_timer(&socket->poll_timer); | ||
996 | } | ||
997 | |||
998 | /* Figure out what the dang thing can do for the PCMCIA layer... */ | ||
999 | yenta_get_socket_capabilities(socket, isa_interrupts); | ||
1000 | printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); | ||
1001 | |||
1002 | /* Register it with the pcmcia layer.. */ | ||
1003 | ret = pcmcia_register_socket(&socket->socket); | ||
1004 | if (ret == 0) | ||
1005 | goto out; | ||
1006 | |||
1007 | unmap: | ||
1008 | iounmap(socket->base); | ||
1009 | release: | ||
1010 | pci_release_regions(dev); | ||
1011 | disable: | ||
1012 | pci_disable_device(dev); | ||
1013 | free: | ||
1014 | kfree(socket); | ||
1015 | out: | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) | ||
1021 | { | ||
1022 | struct yenta_socket *socket = pci_get_drvdata(dev); | ||
1023 | int ret; | ||
1024 | |||
1025 | ret = pcmcia_socket_dev_suspend(&dev->dev, state); | ||
1026 | |||
1027 | if (socket) { | ||
1028 | if (socket->type && socket->type->save_state) | ||
1029 | socket->type->save_state(socket); | ||
1030 | |||
1031 | /* FIXME: pci_save_state needs to have a better interface */ | ||
1032 | pci_save_state(dev); | ||
1033 | pci_read_config_dword(dev, 16*4, &socket->saved_state[0]); | ||
1034 | pci_read_config_dword(dev, 17*4, &socket->saved_state[1]); | ||
1035 | |||
1036 | /* | ||
1037 | * Some laptops (IBM T22) do not like us putting the Cardbus | ||
1038 | * bridge into D3. At a guess, some other laptop will | ||
1039 | * probably require this, so leave it commented out for now. | ||
1040 | */ | ||
1041 | /* pci_set_power_state(dev, 3); */ | ||
1042 | } | ||
1043 | |||
1044 | return ret; | ||
1045 | } | ||
1046 | |||
1047 | |||
1048 | static int yenta_dev_resume (struct pci_dev *dev) | ||
1049 | { | ||
1050 | struct yenta_socket *socket = pci_get_drvdata(dev); | ||
1051 | |||
1052 | if (socket) { | ||
1053 | pci_set_power_state(dev, 0); | ||
1054 | /* FIXME: pci_restore_state needs to have a better interface */ | ||
1055 | pci_restore_state(dev); | ||
1056 | pci_write_config_dword(dev, 16*4, socket->saved_state[0]); | ||
1057 | pci_write_config_dword(dev, 17*4, socket->saved_state[1]); | ||
1058 | |||
1059 | if (socket->type && socket->type->restore_state) | ||
1060 | socket->type->restore_state(socket); | ||
1061 | } | ||
1062 | |||
1063 | return pcmcia_socket_dev_resume(&dev->dev); | ||
1064 | } | ||
1065 | |||
1066 | |||
1067 | #define CB_ID(vend,dev,type) \ | ||
1068 | { \ | ||
1069 | .vendor = vend, \ | ||
1070 | .device = dev, \ | ||
1071 | .subvendor = PCI_ANY_ID, \ | ||
1072 | .subdevice = PCI_ANY_ID, \ | ||
1073 | .class = PCI_CLASS_BRIDGE_CARDBUS << 8, \ | ||
1074 | .class_mask = ~0, \ | ||
1075 | .driver_data = CARDBUS_TYPE_##type, \ | ||
1076 | } | ||
1077 | |||
1078 | static struct pci_device_id yenta_table [] = { | ||
1079 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI), | ||
1080 | |||
1081 | /* | ||
1082 | * TBD: Check if these TI variants can use more | ||
1083 | * advanced overrides instead. (I can't get the | ||
1084 | * data sheets for these devices. --rmk) | ||
1085 | */ | ||
1086 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI), | ||
1087 | |||
1088 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X), | ||
1089 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X), | ||
1090 | |||
1091 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, TI12XX), | ||
1092 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220, TI12XX), | ||
1093 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX), | ||
1094 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX), | ||
1095 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX), | ||
1096 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX), | ||
1097 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX), | ||
1098 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX), | ||
1099 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX), | ||
1100 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX), | ||
1101 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX), | ||
1102 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1620, TI12XX), | ||
1103 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), | ||
1104 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), | ||
1105 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), | ||
1106 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4510, TI12XX), | ||
1107 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX), | ||
1108 | |||
1109 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), | ||
1110 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), | ||
1111 | |||
1112 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, TI12XX), | ||
1113 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, TI12XX), | ||
1114 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, TI1250), | ||
1115 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, TI12XX), | ||
1116 | |||
1117 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), | ||
1118 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), | ||
1119 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH), | ||
1120 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH), | ||
1121 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH), | ||
1122 | |||
1123 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97), | ||
1124 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97), | ||
1125 | |||
1126 | CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO), | ||
1127 | |||
1128 | /* match any cardbus bridge */ | ||
1129 | CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT), | ||
1130 | { /* all zeroes */ } | ||
1131 | }; | ||
1132 | MODULE_DEVICE_TABLE(pci, yenta_table); | ||
1133 | |||
1134 | |||
1135 | static struct pci_driver yenta_cardbus_driver = { | ||
1136 | .name = "yenta_cardbus", | ||
1137 | .id_table = yenta_table, | ||
1138 | .probe = yenta_probe, | ||
1139 | .remove = __devexit_p(yenta_close), | ||
1140 | .suspend = yenta_dev_suspend, | ||
1141 | .resume = yenta_dev_resume, | ||
1142 | }; | ||
1143 | |||
1144 | |||
1145 | static int __init yenta_socket_init(void) | ||
1146 | { | ||
1147 | return pci_register_driver (¥ta_cardbus_driver); | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | static void __exit yenta_socket_exit (void) | ||
1152 | { | ||
1153 | pci_unregister_driver (¥ta_cardbus_driver); | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | module_init(yenta_socket_init); | ||
1158 | module_exit(yenta_socket_exit); | ||
1159 | |||
1160 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h new file mode 100644 index 000000000000..4e637eef2076 --- /dev/null +++ b/drivers/pcmcia/yenta_socket.h | |||
@@ -0,0 +1,127 @@ | |||
1 | #ifndef __YENTA_H | ||
2 | #define __YENTA_H | ||
3 | |||
4 | #include <asm/io.h> | ||
5 | |||
6 | #define CB_SOCKET_EVENT 0x00 | ||
7 | #define CB_CSTSEVENT 0x00000001 /* Card status event */ | ||
8 | #define CB_CD1EVENT 0x00000002 /* Card detect 1 change event */ | ||
9 | #define CB_CD2EVENT 0x00000004 /* Card detect 2 change event */ | ||
10 | #define CB_PWREVENT 0x00000008 /* PWRCYCLE change event */ | ||
11 | |||
12 | #define CB_SOCKET_MASK 0x04 | ||
13 | #define CB_CSTSMASK 0x00000001 /* Card status mask */ | ||
14 | #define CB_CDMASK 0x00000006 /* Card detect 1&2 mask */ | ||
15 | #define CB_PWRMASK 0x00000008 /* PWRCYCLE change mask */ | ||
16 | |||
17 | #define CB_SOCKET_STATE 0x08 | ||
18 | #define CB_CARDSTS 0x00000001 /* CSTSCHG status */ | ||
19 | #define CB_CDETECT1 0x00000002 /* Card detect status 1 */ | ||
20 | #define CB_CDETECT2 0x00000004 /* Card detect status 2 */ | ||
21 | #define CB_PWRCYCLE 0x00000008 /* Socket powered */ | ||
22 | #define CB_16BITCARD 0x00000010 /* 16-bit card detected */ | ||
23 | #define CB_CBCARD 0x00000020 /* CardBus card detected */ | ||
24 | #define CB_IREQCINT 0x00000040 /* READY(xIRQ)/xCINT high */ | ||
25 | #define CB_NOTACARD 0x00000080 /* Unrecognizable PC card detected */ | ||
26 | #define CB_DATALOST 0x00000100 /* Potential data loss due to card removal */ | ||
27 | #define CB_BADVCCREQ 0x00000200 /* Invalid Vcc request by host software */ | ||
28 | #define CB_5VCARD 0x00000400 /* Card Vcc at 5.0 volts? */ | ||
29 | #define CB_3VCARD 0x00000800 /* Card Vcc at 3.3 volts? */ | ||
30 | #define CB_XVCARD 0x00001000 /* Card Vcc at X.X volts? */ | ||
31 | #define CB_YVCARD 0x00002000 /* Card Vcc at Y.Y volts? */ | ||
32 | #define CB_5VSOCKET 0x10000000 /* Socket Vcc at 5.0 volts? */ | ||
33 | #define CB_3VSOCKET 0x20000000 /* Socket Vcc at 3.3 volts? */ | ||
34 | #define CB_XVSOCKET 0x40000000 /* Socket Vcc at X.X volts? */ | ||
35 | #define CB_YVSOCKET 0x80000000 /* Socket Vcc at Y.Y volts? */ | ||
36 | |||
37 | #define CB_SOCKET_FORCE 0x0C | ||
38 | #define CB_FCARDSTS 0x00000001 /* Force CSTSCHG */ | ||
39 | #define CB_FCDETECT1 0x00000002 /* Force CD1EVENT */ | ||
40 | #define CB_FCDETECT2 0x00000004 /* Force CD2EVENT */ | ||
41 | #define CB_FPWRCYCLE 0x00000008 /* Force PWREVENT */ | ||
42 | #define CB_F16BITCARD 0x00000010 /* Force 16-bit PCMCIA card */ | ||
43 | #define CB_FCBCARD 0x00000020 /* Force CardBus line */ | ||
44 | #define CB_FNOTACARD 0x00000080 /* Force NOTACARD */ | ||
45 | #define CB_FDATALOST 0x00000100 /* Force data lost */ | ||
46 | #define CB_FBADVCCREQ 0x00000200 /* Force bad Vcc request */ | ||
47 | #define CB_F5VCARD 0x00000400 /* Force 5.0 volt card */ | ||
48 | #define CB_F3VCARD 0x00000800 /* Force 3.3 volt card */ | ||
49 | #define CB_FXVCARD 0x00001000 /* Force X.X volt card */ | ||
50 | #define CB_FYVCARD 0x00002000 /* Force Y.Y volt card */ | ||
51 | #define CB_CVSTEST 0x00004000 /* Card VS test */ | ||
52 | |||
53 | #define CB_SOCKET_CONTROL 0x10 | ||
54 | #define CB_SC_VPP_MASK 0x00000007 | ||
55 | #define CB_SC_VPP_OFF 0x00000000 | ||
56 | #define CB_SC_VPP_12V 0x00000001 | ||
57 | #define CB_SC_VPP_5V 0x00000002 | ||
58 | #define CB_SC_VPP_3V 0x00000003 | ||
59 | #define CB_SC_VPP_XV 0x00000004 | ||
60 | #define CB_SC_VPP_YV 0x00000005 | ||
61 | #define CB_SC_VCC_MASK 0x00000070 | ||
62 | #define CB_SC_VCC_OFF 0x00000000 | ||
63 | #define CB_SC_VCC_5V 0x00000020 | ||
64 | #define CB_SC_VCC_3V 0x00000030 | ||
65 | #define CB_SC_VCC_XV 0x00000040 | ||
66 | #define CB_SC_VCC_YV 0x00000050 | ||
67 | #define CB_SC_CCLK_STOP 0x00000080 | ||
68 | |||
69 | #define CB_SOCKET_POWER 0x20 | ||
70 | #define CB_SKTACCES 0x02000000 /* A PC card access has occurred (clear on read) */ | ||
71 | #define CB_SKTMODE 0x01000000 /* Clock frequency has changed (clear on read) */ | ||
72 | #define CB_CLKCTRLEN 0x00010000 /* Clock control enabled (RW) */ | ||
73 | #define CB_CLKCTRL 0x00000001 /* Stop(0) or slow(1) CB clock (RW) */ | ||
74 | |||
75 | /* | ||
76 | * Cardbus configuration space | ||
77 | */ | ||
78 | #define CB_BRIDGE_BASE(m) (0x1c + 8*(m)) | ||
79 | #define CB_BRIDGE_LIMIT(m) (0x20 + 8*(m)) | ||
80 | #define CB_BRIDGE_CONTROL 0x3e | ||
81 | #define CB_BRIDGE_CPERREN 0x00000001 | ||
82 | #define CB_BRIDGE_CSERREN 0x00000002 | ||
83 | #define CB_BRIDGE_ISAEN 0x00000004 | ||
84 | #define CB_BRIDGE_VGAEN 0x00000008 | ||
85 | #define CB_BRIDGE_MABTMODE 0x00000020 | ||
86 | #define CB_BRIDGE_CRST 0x00000040 | ||
87 | #define CB_BRIDGE_INTR 0x00000080 | ||
88 | #define CB_BRIDGE_PREFETCH0 0x00000100 | ||
89 | #define CB_BRIDGE_PREFETCH1 0x00000200 | ||
90 | #define CB_BRIDGE_POSTEN 0x00000400 | ||
91 | #define CB_LEGACY_MODE_BASE 0x44 | ||
92 | |||
93 | /* | ||
94 | * ExCA area extensions in Yenta | ||
95 | */ | ||
96 | #define CB_MEM_PAGE(map) (0x40 + (map)) | ||
97 | |||
98 | struct yenta_socket; | ||
99 | |||
100 | struct cardbus_type { | ||
101 | int (*override)(struct yenta_socket *); | ||
102 | void (*save_state)(struct yenta_socket *); | ||
103 | void (*restore_state)(struct yenta_socket *); | ||
104 | int (*sock_init)(struct yenta_socket *); | ||
105 | }; | ||
106 | |||
107 | struct yenta_socket { | ||
108 | struct pci_dev *dev; | ||
109 | int cb_irq, io_irq; | ||
110 | void __iomem *base; | ||
111 | struct timer_list poll_timer; | ||
112 | |||
113 | struct pcmcia_socket socket; | ||
114 | struct cardbus_type *type; | ||
115 | |||
116 | /* for PCI interrupt probing */ | ||
117 | unsigned int probe_status; | ||
118 | |||
119 | /* A few words of private data for special stuff of overrides... */ | ||
120 | unsigned int private[8]; | ||
121 | |||
122 | /* PCI saved state */ | ||
123 | u32 saved_state[2]; | ||
124 | }; | ||
125 | |||
126 | |||
127 | #endif | ||