diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/irda/nsc-ircc.c | 185 |
1 files changed, 151 insertions, 34 deletions
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index ee717d0e939e..282414ba22f0 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> | 12 | * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> |
13 | * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> | 13 | * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> |
14 | * Copyright (c) 1998 Actisys Corp., www.actisys.com | 14 | * Copyright (c) 1998 Actisys Corp., www.actisys.com |
15 | * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com> | ||
15 | * All Rights Reserved | 16 | * All Rights Reserved |
16 | * | 17 | * |
17 | * This program is free software; you can redistribute it and/or | 18 | * This program is free software; you can redistribute it and/or |
@@ -53,6 +54,7 @@ | |||
53 | #include <linux/init.h> | 54 | #include <linux/init.h> |
54 | #include <linux/rtnetlink.h> | 55 | #include <linux/rtnetlink.h> |
55 | #include <linux/dma-mapping.h> | 56 | #include <linux/dma-mapping.h> |
57 | #include <linux/pnp.h> | ||
56 | 58 | ||
57 | #include <asm/io.h> | 59 | #include <asm/io.h> |
58 | #include <asm/dma.h> | 60 | #include <asm/dma.h> |
@@ -78,8 +80,8 @@ static int dongle_id; | |||
78 | 80 | ||
79 | /* Use BIOS settions by default, but user may supply module parameters */ | 81 | /* Use BIOS settions by default, but user may supply module parameters */ |
80 | static unsigned int io[] = { ~0, ~0, ~0, ~0 }; | 82 | static unsigned int io[] = { ~0, ~0, ~0, ~0 }; |
81 | static unsigned int irq[] = { 0, 0, 0, 0, 0 }; | 83 | static unsigned int irq[] = { 0, 0, 0, 0 }; |
82 | static unsigned int dma[] = { 0, 0, 0, 0, 0 }; | 84 | static unsigned int dma[] = { 0, 0, 0, 0 }; |
83 | 85 | ||
84 | static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); | 86 | static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); |
85 | static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); | 87 | static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); |
@@ -87,6 +89,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info); | |||
87 | static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); | 89 | static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); |
88 | static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); | 90 | static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); |
89 | static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info); | 91 | static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info); |
92 | static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id); | ||
90 | 93 | ||
91 | /* These are the known NSC chips */ | 94 | /* These are the known NSC chips */ |
92 | static nsc_chip_t chips[] = { | 95 | static nsc_chip_t chips[] = { |
@@ -104,7 +107,6 @@ static nsc_chip_t chips[] = { | |||
104 | { NULL } | 107 | { NULL } |
105 | }; | 108 | }; |
106 | 109 | ||
107 | /* Max 4 instances for now */ | ||
108 | static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; | 110 | static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; |
109 | 111 | ||
110 | static char *dongle_types[] = { | 112 | static char *dongle_types[] = { |
@@ -126,8 +128,24 @@ static char *dongle_types[] = { | |||
126 | "No dongle connected", | 128 | "No dongle connected", |
127 | }; | 129 | }; |
128 | 130 | ||
131 | /* PNP probing */ | ||
132 | static chipio_t pnp_info; | ||
133 | static const struct pnp_device_id nsc_ircc_pnp_table[] = { | ||
134 | { .id = "NSC6001", .driver_data = 0 }, | ||
135 | { .id = "IBM0071", .driver_data = 0 }, | ||
136 | { } | ||
137 | }; | ||
138 | |||
139 | MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table); | ||
140 | |||
141 | static struct pnp_driver nsc_ircc_pnp_driver = { | ||
142 | .name = "nsc-ircc", | ||
143 | .id_table = nsc_ircc_pnp_table, | ||
144 | .probe = nsc_ircc_pnp_probe, | ||
145 | }; | ||
146 | |||
129 | /* Some prototypes */ | 147 | /* Some prototypes */ |
130 | static int nsc_ircc_open(int i, chipio_t *info); | 148 | static int nsc_ircc_open(chipio_t *info); |
131 | static int nsc_ircc_close(struct nsc_ircc_cb *self); | 149 | static int nsc_ircc_close(struct nsc_ircc_cb *self); |
132 | static int nsc_ircc_setup(chipio_t *info); | 150 | static int nsc_ircc_setup(chipio_t *info); |
133 | static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); | 151 | static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); |
@@ -148,6 +166,10 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd | |||
148 | static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); | 166 | static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); |
149 | static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); | 167 | static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); |
150 | 168 | ||
169 | /* Globals */ | ||
170 | static int pnp_registered; | ||
171 | static int pnp_succeeded; | ||
172 | |||
151 | /* | 173 | /* |
152 | * Function nsc_ircc_init () | 174 | * Function nsc_ircc_init () |
153 | * | 175 | * |
@@ -158,28 +180,30 @@ static int __init nsc_ircc_init(void) | |||
158 | { | 180 | { |
159 | chipio_t info; | 181 | chipio_t info; |
160 | nsc_chip_t *chip; | 182 | nsc_chip_t *chip; |
161 | int ret = -ENODEV; | 183 | int ret; |
162 | int cfg_base; | 184 | int cfg_base; |
163 | int cfg, id; | 185 | int cfg, id; |
164 | int reg; | 186 | int reg; |
165 | int i = 0; | 187 | int i = 0; |
166 | 188 | ||
189 | /* Register with PnP subsystem to detect disable ports */ | ||
190 | ret = pnp_register_driver(&nsc_ircc_pnp_driver); | ||
191 | |||
192 | if (ret >= 0) | ||
193 | pnp_registered = 1; | ||
194 | |||
195 | ret = -ENODEV; | ||
196 | |||
167 | /* Probe for all the NSC chipsets we know about */ | 197 | /* Probe for all the NSC chipsets we know about */ |
168 | for (chip=chips; chip->name ; chip++) { | 198 | for (chip = chips; chip->name ; chip++) { |
169 | IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, | 199 | IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, |
170 | chip->name); | 200 | chip->name); |
171 | 201 | ||
172 | /* Try all config registers for this chip */ | 202 | /* Try all config registers for this chip */ |
173 | for (cfg=0; cfg<3; cfg++) { | 203 | for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) { |
174 | cfg_base = chip->cfg[cfg]; | 204 | cfg_base = chip->cfg[cfg]; |
175 | if (!cfg_base) | 205 | if (!cfg_base) |
176 | continue; | 206 | continue; |
177 | |||
178 | memset(&info, 0, sizeof(chipio_t)); | ||
179 | info.cfg_base = cfg_base; | ||
180 | info.fir_base = io[i]; | ||
181 | info.dma = dma[i]; | ||
182 | info.irq = irq[i]; | ||
183 | 207 | ||
184 | /* Read index register */ | 208 | /* Read index register */ |
185 | reg = inb(cfg_base); | 209 | reg = inb(cfg_base); |
@@ -194,24 +218,64 @@ static int __init nsc_ircc_init(void) | |||
194 | if ((id & chip->cid_mask) == chip->cid_value) { | 218 | if ((id & chip->cid_mask) == chip->cid_value) { |
195 | IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", | 219 | IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", |
196 | __FUNCTION__, chip->name, id & ~chip->cid_mask); | 220 | __FUNCTION__, chip->name, id & ~chip->cid_mask); |
197 | /* | ||
198 | * If the user supplies the base address, then | ||
199 | * we init the chip, if not we probe the values | ||
200 | * set by the BIOS | ||
201 | */ | ||
202 | if (io[i] < 0x2000) { | ||
203 | chip->init(chip, &info); | ||
204 | } else | ||
205 | chip->probe(chip, &info); | ||
206 | 221 | ||
207 | if (nsc_ircc_open(i, &info) == 0) | 222 | /* |
208 | ret = 0; | 223 | * If we found a correct PnP setting, |
224 | * we first try it. | ||
225 | */ | ||
226 | if (pnp_succeeded) { | ||
227 | memset(&info, 0, sizeof(chipio_t)); | ||
228 | info.cfg_base = cfg_base; | ||
229 | info.fir_base = pnp_info.fir_base; | ||
230 | info.dma = pnp_info.dma; | ||
231 | info.irq = pnp_info.irq; | ||
232 | |||
233 | if (info.fir_base < 0x2000) { | ||
234 | IRDA_MESSAGE("%s, chip->init\n", driver_name); | ||
235 | chip->init(chip, &info); | ||
236 | } else | ||
237 | chip->probe(chip, &info); | ||
238 | |||
239 | if (nsc_ircc_open(&info) >= 0) | ||
240 | ret = 0; | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * Opening based on PnP values failed. | ||
245 | * Let's fallback to user values, or probe | ||
246 | * the chip. | ||
247 | */ | ||
248 | if (ret) { | ||
249 | IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name); | ||
250 | memset(&info, 0, sizeof(chipio_t)); | ||
251 | info.cfg_base = cfg_base; | ||
252 | info.fir_base = io[i]; | ||
253 | info.dma = dma[i]; | ||
254 | info.irq = irq[i]; | ||
255 | |||
256 | /* | ||
257 | * If the user supplies the base address, then | ||
258 | * we init the chip, if not we probe the values | ||
259 | * set by the BIOS | ||
260 | */ | ||
261 | if (io[i] < 0x2000) { | ||
262 | chip->init(chip, &info); | ||
263 | } else | ||
264 | chip->probe(chip, &info); | ||
265 | |||
266 | if (nsc_ircc_open(&info) >= 0) | ||
267 | ret = 0; | ||
268 | } | ||
209 | i++; | 269 | i++; |
210 | } else { | 270 | } else { |
211 | IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); | 271 | IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); |
212 | } | 272 | } |
213 | } | 273 | } |
214 | 274 | } | |
275 | |||
276 | if (ret) { | ||
277 | pnp_unregister_driver(&nsc_ircc_pnp_driver); | ||
278 | pnp_registered = 0; | ||
215 | } | 279 | } |
216 | 280 | ||
217 | return ret; | 281 | return ret; |
@@ -229,10 +293,15 @@ static void __exit nsc_ircc_cleanup(void) | |||
229 | 293 | ||
230 | pm_unregister_all(nsc_ircc_pmproc); | 294 | pm_unregister_all(nsc_ircc_pmproc); |
231 | 295 | ||
232 | for (i=0; i < 4; i++) { | 296 | for (i = 0; i < ARRAY_SIZE(dev_self); i++) { |
233 | if (dev_self[i]) | 297 | if (dev_self[i]) |
234 | nsc_ircc_close(dev_self[i]); | 298 | nsc_ircc_close(dev_self[i]); |
235 | } | 299 | } |
300 | |||
301 | if (pnp_registered) | ||
302 | pnp_unregister_driver(&nsc_ircc_pnp_driver); | ||
303 | |||
304 | pnp_registered = 0; | ||
236 | } | 305 | } |
237 | 306 | ||
238 | /* | 307 | /* |
@@ -241,16 +310,27 @@ static void __exit nsc_ircc_cleanup(void) | |||
241 | * Open driver instance | 310 | * Open driver instance |
242 | * | 311 | * |
243 | */ | 312 | */ |
244 | static int __init nsc_ircc_open(int i, chipio_t *info) | 313 | static int __init nsc_ircc_open(chipio_t *info) |
245 | { | 314 | { |
246 | struct net_device *dev; | 315 | struct net_device *dev; |
247 | struct nsc_ircc_cb *self; | 316 | struct nsc_ircc_cb *self; |
248 | struct pm_dev *pmdev; | 317 | struct pm_dev *pmdev; |
249 | void *ret; | 318 | void *ret; |
250 | int err; | 319 | int err, chip_index; |
251 | 320 | ||
252 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | 321 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); |
253 | 322 | ||
323 | |||
324 | for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) { | ||
325 | if (!dev_self[chip_index]) | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | if (chip_index == ARRAY_SIZE(dev_self)) { | ||
330 | IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | |||
254 | IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, | 334 | IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, |
255 | info->cfg_base); | 335 | info->cfg_base); |
256 | 336 | ||
@@ -271,8 +351,8 @@ static int __init nsc_ircc_open(int i, chipio_t *info) | |||
271 | spin_lock_init(&self->lock); | 351 | spin_lock_init(&self->lock); |
272 | 352 | ||
273 | /* Need to store self somewhere */ | 353 | /* Need to store self somewhere */ |
274 | dev_self[i] = self; | 354 | dev_self[chip_index] = self; |
275 | self->index = i; | 355 | self->index = chip_index; |
276 | 356 | ||
277 | /* Initialize IO */ | 357 | /* Initialize IO */ |
278 | self->io.cfg_base = info->cfg_base; | 358 | self->io.cfg_base = info->cfg_base; |
@@ -351,7 +431,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) | |||
351 | 431 | ||
352 | /* Check if user has supplied a valid dongle id or not */ | 432 | /* Check if user has supplied a valid dongle id or not */ |
353 | if ((dongle_id <= 0) || | 433 | if ((dongle_id <= 0) || |
354 | (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) { | 434 | (dongle_id >= ARRAY_SIZE(dongle_types))) { |
355 | dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); | 435 | dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); |
356 | 436 | ||
357 | IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name, | 437 | IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name, |
@@ -368,7 +448,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) | |||
368 | if (pmdev) | 448 | if (pmdev) |
369 | pmdev->data = self; | 449 | pmdev->data = self; |
370 | 450 | ||
371 | return 0; | 451 | return chip_index; |
372 | out4: | 452 | out4: |
373 | dma_free_coherent(NULL, self->tx_buff.truesize, | 453 | dma_free_coherent(NULL, self->tx_buff.truesize, |
374 | self->tx_buff.head, self->tx_buff_dma); | 454 | self->tx_buff.head, self->tx_buff_dma); |
@@ -379,7 +459,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) | |||
379 | release_region(self->io.fir_base, self->io.fir_ext); | 459 | release_region(self->io.fir_base, self->io.fir_ext); |
380 | out1: | 460 | out1: |
381 | free_netdev(dev); | 461 | free_netdev(dev); |
382 | dev_self[i] = NULL; | 462 | dev_self[chip_index] = NULL; |
383 | return err; | 463 | return err; |
384 | } | 464 | } |
385 | 465 | ||
@@ -806,6 +886,43 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) | |||
806 | return 0; | 886 | return 0; |
807 | } | 887 | } |
808 | 888 | ||
889 | /* PNP probing */ | ||
890 | static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) | ||
891 | { | ||
892 | memset(&pnp_info, 0, sizeof(chipio_t)); | ||
893 | pnp_info.irq = -1; | ||
894 | pnp_info.dma = -1; | ||
895 | pnp_succeeded = 1; | ||
896 | |||
897 | /* There don't seem to be any way to get the cfg_base. | ||
898 | * On my box, cfg_base is in the PnP descriptor of the | ||
899 | * motherboard. Oh well... Jean II */ | ||
900 | |||
901 | if (pnp_port_valid(dev, 0) && | ||
902 | !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) | ||
903 | pnp_info.fir_base = pnp_port_start(dev, 0); | ||
904 | |||
905 | if (pnp_irq_valid(dev, 0) && | ||
906 | !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) | ||
907 | pnp_info.irq = pnp_irq(dev, 0); | ||
908 | |||
909 | if (pnp_dma_valid(dev, 0) && | ||
910 | !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) | ||
911 | pnp_info.dma = pnp_dma(dev, 0); | ||
912 | |||
913 | IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", | ||
914 | __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); | ||
915 | |||
916 | if((pnp_info.fir_base == 0) || | ||
917 | (pnp_info.irq == -1) || (pnp_info.dma == -1)) { | ||
918 | /* Returning an error will disable the device. Yuck ! */ | ||
919 | //return -EINVAL; | ||
920 | pnp_succeeded = 0; | ||
921 | } | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
809 | /* | 926 | /* |
810 | * Function nsc_ircc_setup (info) | 927 | * Function nsc_ircc_setup (info) |
811 | * | 928 | * |