0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #define DRIVER_NAME "spectrum_cs"
0022 #define PFX DRIVER_NAME ": "
0023
0024 #include <linux/module.h>
0025 #include <linux/kernel.h>
0026 #include <linux/delay.h>
0027 #include <pcmcia/cistpl.h>
0028 #include <pcmcia/cisreg.h>
0029 #include <pcmcia/ds.h>
0030
0031 #include "orinoco.h"
0032
0033
0034
0035
0036
0037 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
0038 MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
0039 MODULE_LICENSE("Dual MPL/GPL");
0040
0041
0042
0043
0044
0045 static int ignore_cis_vcc;
0046 module_param(ignore_cis_vcc, int, 0);
0047 MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
0048
0049
0050
0051
0052
0053
0054
0055 struct orinoco_pccard {
0056 struct pcmcia_device *p_dev;
0057 };
0058
0059
0060
0061
0062
0063 static int spectrum_cs_config(struct pcmcia_device *link);
0064 static void spectrum_cs_release(struct pcmcia_device *link);
0065
0066
0067 #define HCR_RUN 0x07
0068 #define HCR_IDLE 0x0E
0069 #define HCR_MEM16 0x10
0070
0071
0072
0073
0074
0075
0076 static int
0077 spectrum_reset(struct pcmcia_device *link, int idle)
0078 {
0079 int ret;
0080 u8 save_cor;
0081 u8 ccsr;
0082
0083
0084 if (!pcmcia_dev_present(link))
0085 return -ENODEV;
0086
0087
0088 ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor);
0089 if (ret)
0090 goto failed;
0091
0092
0093 ret = pcmcia_write_config_byte(link, CISREG_COR,
0094 (save_cor | COR_SOFT_RESET));
0095 if (ret)
0096 goto failed;
0097 udelay(1000);
0098
0099
0100 ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr);
0101 if (ret)
0102 goto failed;
0103
0104
0105
0106
0107
0108 ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16);
0109 ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr);
0110 if (ret)
0111 goto failed;
0112 udelay(1000);
0113
0114
0115 ret = pcmcia_write_config_byte(link, CISREG_COR,
0116 (save_cor & ~COR_SOFT_RESET));
0117 if (ret)
0118 goto failed;
0119 udelay(1000);
0120 return 0;
0121
0122 failed:
0123 return -ENODEV;
0124 }
0125
0126
0127
0128
0129
0130 static int
0131 spectrum_cs_hard_reset(struct orinoco_private *priv)
0132 {
0133 struct orinoco_pccard *card = priv->card;
0134 struct pcmcia_device *link = card->p_dev;
0135
0136
0137 spectrum_reset(link, 0);
0138
0139 return 0;
0140 }
0141
0142 static int
0143 spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
0144 {
0145 struct orinoco_pccard *card = priv->card;
0146 struct pcmcia_device *link = card->p_dev;
0147
0148 return spectrum_reset(link, idle);
0149 }
0150
0151
0152
0153
0154
0155 static int
0156 spectrum_cs_probe(struct pcmcia_device *link)
0157 {
0158 struct orinoco_private *priv;
0159 struct orinoco_pccard *card;
0160
0161 priv = alloc_orinocodev(sizeof(*card), &link->dev,
0162 spectrum_cs_hard_reset,
0163 spectrum_cs_stop_firmware);
0164 if (!priv)
0165 return -ENOMEM;
0166 card = priv->card;
0167
0168
0169 card->p_dev = link;
0170 link->priv = priv;
0171
0172 return spectrum_cs_config(link);
0173 }
0174
0175 static void spectrum_cs_detach(struct pcmcia_device *link)
0176 {
0177 struct orinoco_private *priv = link->priv;
0178
0179 orinoco_if_del(priv);
0180
0181 spectrum_cs_release(link);
0182
0183 free_orinocodev(priv);
0184 }
0185
0186 static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
0187 void *priv_data)
0188 {
0189 if (p_dev->config_index == 0)
0190 return -EINVAL;
0191
0192 return pcmcia_request_io(p_dev);
0193 };
0194
0195 static int
0196 spectrum_cs_config(struct pcmcia_device *link)
0197 {
0198 struct orinoco_private *priv = link->priv;
0199 struct hermes *hw = &priv->hw;
0200 int ret;
0201 void __iomem *mem;
0202
0203 link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
0204 CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
0205 if (ignore_cis_vcc)
0206 link->config_flags &= ~CONF_AUTO_CHECK_VCC;
0207 ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
0208 if (ret) {
0209 if (!ignore_cis_vcc)
0210 printk(KERN_ERR PFX "GetNextTuple(): No matching "
0211 "CIS configuration. Maybe you need the "
0212 "ignore_cis_vcc=1 parameter.\n");
0213 goto failed;
0214 }
0215
0216 mem = ioport_map(link->resource[0]->start,
0217 resource_size(link->resource[0]));
0218 if (!mem)
0219 goto failed;
0220
0221
0222
0223
0224 hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
0225 hw->eeprom_pda = true;
0226
0227 ret = pcmcia_request_irq(link, orinoco_interrupt);
0228 if (ret)
0229 goto failed;
0230
0231 ret = pcmcia_enable_device(link);
0232 if (ret)
0233 goto failed;
0234
0235
0236 if (spectrum_cs_hard_reset(priv) != 0)
0237 goto failed;
0238
0239
0240 if (orinoco_init(priv) != 0) {
0241 printk(KERN_ERR PFX "orinoco_init() failed\n");
0242 goto failed;
0243 }
0244
0245
0246 if (orinoco_if_add(priv, link->resource[0]->start,
0247 link->irq, NULL) != 0) {
0248 printk(KERN_ERR PFX "orinoco_if_add() failed\n");
0249 goto failed;
0250 }
0251
0252 return 0;
0253
0254 failed:
0255 spectrum_cs_release(link);
0256 return -ENODEV;
0257 }
0258
0259 static void
0260 spectrum_cs_release(struct pcmcia_device *link)
0261 {
0262 struct orinoco_private *priv = link->priv;
0263 unsigned long flags;
0264
0265
0266
0267 priv->hw.ops->lock_irqsave(&priv->lock, &flags);
0268 priv->hw_unavailable++;
0269 priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
0270
0271 pcmcia_disable_device(link);
0272 if (priv->hw.iobase)
0273 ioport_unmap(priv->hw.iobase);
0274 }
0275
0276
0277 static int
0278 spectrum_cs_suspend(struct pcmcia_device *link)
0279 {
0280 struct orinoco_private *priv = link->priv;
0281
0282
0283 orinoco_down(priv);
0284
0285 return 0;
0286 }
0287
0288 static int
0289 spectrum_cs_resume(struct pcmcia_device *link)
0290 {
0291 struct orinoco_private *priv = link->priv;
0292 int err = orinoco_up(priv);
0293
0294 return err;
0295 }
0296
0297
0298
0299
0300
0301
0302 static const struct pcmcia_device_id spectrum_cs_ids[] = {
0303 PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001),
0304 PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001),
0305 PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a),
0306 PCMCIA_DEVICE_NULL,
0307 };
0308 MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
0309
0310 static struct pcmcia_driver orinoco_driver = {
0311 .owner = THIS_MODULE,
0312 .name = DRIVER_NAME,
0313 .probe = spectrum_cs_probe,
0314 .remove = spectrum_cs_detach,
0315 .suspend = spectrum_cs_suspend,
0316 .resume = spectrum_cs_resume,
0317 .id_table = spectrum_cs_ids,
0318 };
0319 module_pcmcia_driver(orinoco_driver);