diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/serial_cs.c | 229 |
1 files changed, 112 insertions, 117 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index c30333694fde..2c70773543e0 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/timer.h> | 42 | #include <linux/timer.h> |
43 | #include <linux/serial_core.h> | 43 | #include <linux/serial_core.h> |
44 | #include <linux/delay.h> | ||
44 | #include <linux/major.h> | 45 | #include <linux/major.h> |
45 | #include <asm/io.h> | 46 | #include <asm/io.h> |
46 | #include <asm/system.h> | 47 | #include <asm/system.h> |
@@ -97,11 +98,13 @@ static const struct multi_id multi_id[] = { | |||
97 | #define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id)) | 98 | #define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id)) |
98 | 99 | ||
99 | struct serial_info { | 100 | struct serial_info { |
100 | dev_link_t link; | 101 | struct pcmcia_device *p_dev; |
101 | int ndev; | 102 | int ndev; |
102 | int multi; | 103 | int multi; |
103 | int slave; | 104 | int slave; |
104 | int manfid; | 105 | int manfid; |
106 | int prodid; | ||
107 | int c950ctrl; | ||
105 | dev_node_t node[4]; | 108 | dev_node_t node[4]; |
106 | int line[4]; | 109 | int line[4]; |
107 | }; | 110 | }; |
@@ -113,9 +116,36 @@ struct serial_cfg_mem { | |||
113 | }; | 116 | }; |
114 | 117 | ||
115 | 118 | ||
116 | static void serial_config(dev_link_t * link); | 119 | static int serial_config(struct pcmcia_device * link); |
117 | 120 | ||
118 | 121 | ||
122 | static void wakeup_card(struct serial_info *info) | ||
123 | { | ||
124 | int ctrl = info->c950ctrl; | ||
125 | |||
126 | if (info->manfid == MANFID_OXSEMI) { | ||
127 | outb(12, ctrl + 1); | ||
128 | } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) { | ||
129 | /* request_region? oxsemi branch does no request_region too... */ | ||
130 | /* This sequence is needed to properly initialize MC45 attached to OXCF950. | ||
131 | * I tried decreasing these msleep()s, but it worked properly (survived | ||
132 | * 1000 stop/start operations) with these timeouts (or bigger). */ | ||
133 | outb(0xA, ctrl + 1); | ||
134 | msleep(100); | ||
135 | outb(0xE, ctrl + 1); | ||
136 | msleep(300); | ||
137 | outb(0xC, ctrl + 1); | ||
138 | msleep(100); | ||
139 | outb(0xE, ctrl + 1); | ||
140 | msleep(200); | ||
141 | outb(0xF, ctrl + 1); | ||
142 | msleep(100); | ||
143 | outb(0xE, ctrl + 1); | ||
144 | msleep(100); | ||
145 | outb(0xC, ctrl + 1); | ||
146 | } | ||
147 | } | ||
148 | |||
119 | /*====================================================================== | 149 | /*====================================================================== |
120 | 150 | ||
121 | After a card is removed, serial_remove() will unregister | 151 | After a card is removed, serial_remove() will unregister |
@@ -123,67 +153,45 @@ static void serial_config(dev_link_t * link); | |||
123 | 153 | ||
124 | ======================================================================*/ | 154 | ======================================================================*/ |
125 | 155 | ||
126 | static void serial_remove(dev_link_t *link) | 156 | static void serial_remove(struct pcmcia_device *link) |
127 | { | 157 | { |
128 | struct serial_info *info = link->priv; | 158 | struct serial_info *info = link->priv; |
129 | int i; | 159 | int i; |
130 | 160 | ||
131 | link->state &= ~DEV_PRESENT; | ||
132 | |||
133 | DEBUG(0, "serial_release(0x%p)\n", link); | 161 | DEBUG(0, "serial_release(0x%p)\n", link); |
134 | 162 | ||
135 | /* | 163 | /* |
136 | * Recheck to see if the device is still configured. | 164 | * Recheck to see if the device is still configured. |
137 | */ | 165 | */ |
138 | if (info->link.state & DEV_CONFIG) { | 166 | for (i = 0; i < info->ndev; i++) |
139 | for (i = 0; i < info->ndev; i++) | 167 | serial8250_unregister_port(info->line[i]); |
140 | serial8250_unregister_port(info->line[i]); | ||
141 | 168 | ||
142 | info->link.dev = NULL; | 169 | info->p_dev->dev_node = NULL; |
143 | 170 | ||
144 | if (!info->slave) { | 171 | if (!info->slave) |
145 | pcmcia_release_configuration(info->link.handle); | 172 | pcmcia_disable_device(link); |
146 | pcmcia_release_io(info->link.handle, &info->link.io); | ||
147 | pcmcia_release_irq(info->link.handle, &info->link.irq); | ||
148 | } | ||
149 | |||
150 | info->link.state &= ~DEV_CONFIG; | ||
151 | } | ||
152 | } | 173 | } |
153 | 174 | ||
154 | static int serial_suspend(struct pcmcia_device *dev) | 175 | static int serial_suspend(struct pcmcia_device *link) |
155 | { | 176 | { |
156 | dev_link_t *link = dev_to_instance(dev); | 177 | struct serial_info *info = link->priv; |
157 | link->state |= DEV_SUSPEND; | 178 | int i; |
158 | |||
159 | if (link->state & DEV_CONFIG) { | ||
160 | struct serial_info *info = link->priv; | ||
161 | int i; | ||
162 | |||
163 | for (i = 0; i < info->ndev; i++) | ||
164 | serial8250_suspend_port(info->line[i]); | ||
165 | 179 | ||
166 | if (!info->slave) | 180 | for (i = 0; i < info->ndev; i++) |
167 | pcmcia_release_configuration(link->handle); | 181 | serial8250_suspend_port(info->line[i]); |
168 | } | ||
169 | 182 | ||
170 | return 0; | 183 | return 0; |
171 | } | 184 | } |
172 | 185 | ||
173 | static int serial_resume(struct pcmcia_device *dev) | 186 | static int serial_resume(struct pcmcia_device *link) |
174 | { | 187 | { |
175 | dev_link_t *link = dev_to_instance(dev); | 188 | if (pcmcia_dev_present(link)) { |
176 | link->state &= ~DEV_SUSPEND; | ||
177 | |||
178 | if (DEV_OK(link)) { | ||
179 | struct serial_info *info = link->priv; | 189 | struct serial_info *info = link->priv; |
180 | int i; | 190 | int i; |
181 | 191 | ||
182 | if (!info->slave) | ||
183 | pcmcia_request_configuration(link->handle, &link->conf); | ||
184 | |||
185 | for (i = 0; i < info->ndev; i++) | 192 | for (i = 0; i < info->ndev; i++) |
186 | serial8250_resume_port(info->line[i]); | 193 | serial8250_resume_port(info->line[i]); |
194 | wakeup_card(info); | ||
187 | } | 195 | } |
188 | 196 | ||
189 | return 0; | 197 | return 0; |
@@ -197,10 +205,9 @@ static int serial_resume(struct pcmcia_device *dev) | |||
197 | 205 | ||
198 | ======================================================================*/ | 206 | ======================================================================*/ |
199 | 207 | ||
200 | static int serial_probe(struct pcmcia_device *p_dev) | 208 | static int serial_probe(struct pcmcia_device *link) |
201 | { | 209 | { |
202 | struct serial_info *info; | 210 | struct serial_info *info; |
203 | dev_link_t *link; | ||
204 | 211 | ||
205 | DEBUG(0, "serial_attach()\n"); | 212 | DEBUG(0, "serial_attach()\n"); |
206 | 213 | ||
@@ -209,7 +216,7 @@ static int serial_probe(struct pcmcia_device *p_dev) | |||
209 | if (!info) | 216 | if (!info) |
210 | return -ENOMEM; | 217 | return -ENOMEM; |
211 | memset(info, 0, sizeof (*info)); | 218 | memset(info, 0, sizeof (*info)); |
212 | link = &info->link; | 219 | info->p_dev = link; |
213 | link->priv = info; | 220 | link->priv = info; |
214 | 221 | ||
215 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | 222 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
@@ -223,12 +230,7 @@ static int serial_probe(struct pcmcia_device *p_dev) | |||
223 | } | 230 | } |
224 | link->conf.IntType = INT_MEMORY_AND_IO; | 231 | link->conf.IntType = INT_MEMORY_AND_IO; |
225 | 232 | ||
226 | link->handle = p_dev; | 233 | return serial_config(link); |
227 | p_dev->instance = link; | ||
228 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
229 | serial_config(link); | ||
230 | |||
231 | return 0; | ||
232 | } | 234 | } |
233 | 235 | ||
234 | /*====================================================================== | 236 | /*====================================================================== |
@@ -240,9 +242,8 @@ static int serial_probe(struct pcmcia_device *p_dev) | |||
240 | 242 | ||
241 | ======================================================================*/ | 243 | ======================================================================*/ |
242 | 244 | ||
243 | static void serial_detach(struct pcmcia_device *p_dev) | 245 | static void serial_detach(struct pcmcia_device *link) |
244 | { | 246 | { |
245 | dev_link_t *link = dev_to_instance(p_dev); | ||
246 | struct serial_info *info = link->priv; | 247 | struct serial_info *info = link->priv; |
247 | 248 | ||
248 | DEBUG(0, "serial_detach(0x%p)\n", link); | 249 | DEBUG(0, "serial_detach(0x%p)\n", link); |
@@ -263,7 +264,7 @@ static void serial_detach(struct pcmcia_device *p_dev) | |||
263 | 264 | ||
264 | /*====================================================================*/ | 265 | /*====================================================================*/ |
265 | 266 | ||
266 | static int setup_serial(client_handle_t handle, struct serial_info * info, | 267 | static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, |
267 | kio_addr_t iobase, int irq) | 268 | kio_addr_t iobase, int irq) |
268 | { | 269 | { |
269 | struct uart_port port; | 270 | struct uart_port port; |
@@ -298,7 +299,7 @@ static int setup_serial(client_handle_t handle, struct serial_info * info, | |||
298 | /*====================================================================*/ | 299 | /*====================================================================*/ |
299 | 300 | ||
300 | static int | 301 | static int |
301 | first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) | 302 | first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) |
302 | { | 303 | { |
303 | int i; | 304 | int i; |
304 | i = pcmcia_get_first_tuple(handle, tuple); | 305 | i = pcmcia_get_first_tuple(handle, tuple); |
@@ -311,7 +312,7 @@ first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) | |||
311 | } | 312 | } |
312 | 313 | ||
313 | static int | 314 | static int |
314 | next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) | 315 | next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) |
315 | { | 316 | { |
316 | int i; | 317 | int i; |
317 | i = pcmcia_get_next_tuple(handle, tuple); | 318 | i = pcmcia_get_next_tuple(handle, tuple); |
@@ -325,11 +326,10 @@ next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) | |||
325 | 326 | ||
326 | /*====================================================================*/ | 327 | /*====================================================================*/ |
327 | 328 | ||
328 | static int simple_config(dev_link_t *link) | 329 | static int simple_config(struct pcmcia_device *link) |
329 | { | 330 | { |
330 | static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | 331 | static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; |
331 | static const int size_table[2] = { 8, 16 }; | 332 | static const int size_table[2] = { 8, 16 }; |
332 | client_handle_t handle = link->handle; | ||
333 | struct serial_info *info = link->priv; | 333 | struct serial_info *info = link->priv; |
334 | struct serial_cfg_mem *cfg_mem; | 334 | struct serial_cfg_mem *cfg_mem; |
335 | tuple_t *tuple; | 335 | tuple_t *tuple; |
@@ -350,7 +350,7 @@ static int simple_config(dev_link_t *link) | |||
350 | buf = cfg_mem->buf; | 350 | buf = cfg_mem->buf; |
351 | 351 | ||
352 | /* If the card is already configured, look up the port and irq */ | 352 | /* If the card is already configured, look up the port and irq */ |
353 | i = pcmcia_get_configuration_info(handle, &config); | 353 | i = pcmcia_get_configuration_info(link, &config); |
354 | if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { | 354 | if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { |
355 | kio_addr_t port = 0; | 355 | kio_addr_t port = 0; |
356 | if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { | 356 | if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { |
@@ -363,10 +363,9 @@ static int simple_config(dev_link_t *link) | |||
363 | } | 363 | } |
364 | if (info->slave) { | 364 | if (info->slave) { |
365 | kfree(cfg_mem); | 365 | kfree(cfg_mem); |
366 | return setup_serial(handle, info, port, config.AssignedIRQ); | 366 | return setup_serial(link, info, port, config.AssignedIRQ); |
367 | } | 367 | } |
368 | } | 368 | } |
369 | link->conf.Vcc = config.Vcc; | ||
370 | 369 | ||
371 | /* First pass: look for a config entry that looks normal. */ | 370 | /* First pass: look for a config entry that looks normal. */ |
372 | tuple->TupleData = (cisdata_t *) buf; | 371 | tuple->TupleData = (cisdata_t *) buf; |
@@ -377,12 +376,12 @@ static int simple_config(dev_link_t *link) | |||
377 | /* Two tries: without IO aliases, then with aliases */ | 376 | /* Two tries: without IO aliases, then with aliases */ |
378 | for (s = 0; s < 2; s++) { | 377 | for (s = 0; s < 2; s++) { |
379 | for (try = 0; try < 2; try++) { | 378 | for (try = 0; try < 2; try++) { |
380 | i = first_tuple(handle, tuple, parse); | 379 | i = first_tuple(link, tuple, parse); |
381 | while (i != CS_NO_MORE_ITEMS) { | 380 | while (i != CS_NO_MORE_ITEMS) { |
382 | if (i != CS_SUCCESS) | 381 | if (i != CS_SUCCESS) |
383 | goto next_entry; | 382 | goto next_entry; |
384 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) | 383 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) |
385 | link->conf.Vpp1 = link->conf.Vpp2 = | 384 | link->conf.Vpp = |
386 | cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; | 385 | cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; |
387 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && | 386 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && |
388 | (cf->io.win[0].base != 0)) { | 387 | (cf->io.win[0].base != 0)) { |
@@ -390,19 +389,19 @@ static int simple_config(dev_link_t *link) | |||
390 | link->io.BasePort1 = cf->io.win[0].base; | 389 | link->io.BasePort1 = cf->io.win[0].base; |
391 | link->io.IOAddrLines = (try == 0) ? | 390 | link->io.IOAddrLines = (try == 0) ? |
392 | 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | 391 | 16 : cf->io.flags & CISTPL_IO_LINES_MASK; |
393 | i = pcmcia_request_io(link->handle, &link->io); | 392 | i = pcmcia_request_io(link, &link->io); |
394 | if (i == CS_SUCCESS) | 393 | if (i == CS_SUCCESS) |
395 | goto found_port; | 394 | goto found_port; |
396 | } | 395 | } |
397 | next_entry: | 396 | next_entry: |
398 | i = next_tuple(handle, tuple, parse); | 397 | i = next_tuple(link, tuple, parse); |
399 | } | 398 | } |
400 | } | 399 | } |
401 | } | 400 | } |
402 | /* Second pass: try to find an entry that isn't picky about | 401 | /* Second pass: try to find an entry that isn't picky about |
403 | its base address, then try to grab any standard serial port | 402 | its base address, then try to grab any standard serial port |
404 | address, and finally try to get any free port. */ | 403 | address, and finally try to get any free port. */ |
405 | i = first_tuple(handle, tuple, parse); | 404 | i = first_tuple(link, tuple, parse); |
406 | while (i != CS_NO_MORE_ITEMS) { | 405 | while (i != CS_NO_MORE_ITEMS) { |
407 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && | 406 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && |
408 | ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | 407 | ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { |
@@ -410,50 +409,48 @@ next_entry: | |||
410 | for (j = 0; j < 5; j++) { | 409 | for (j = 0; j < 5; j++) { |
411 | link->io.BasePort1 = base[j]; | 410 | link->io.BasePort1 = base[j]; |
412 | link->io.IOAddrLines = base[j] ? 16 : 3; | 411 | link->io.IOAddrLines = base[j] ? 16 : 3; |
413 | i = pcmcia_request_io(link->handle, &link->io); | 412 | i = pcmcia_request_io(link, &link->io); |
414 | if (i == CS_SUCCESS) | 413 | if (i == CS_SUCCESS) |
415 | goto found_port; | 414 | goto found_port; |
416 | } | 415 | } |
417 | } | 416 | } |
418 | i = next_tuple(handle, tuple, parse); | 417 | i = next_tuple(link, tuple, parse); |
419 | } | 418 | } |
420 | 419 | ||
421 | found_port: | 420 | found_port: |
422 | if (i != CS_SUCCESS) { | 421 | if (i != CS_SUCCESS) { |
423 | printk(KERN_NOTICE | 422 | printk(KERN_NOTICE |
424 | "serial_cs: no usable port range found, giving up\n"); | 423 | "serial_cs: no usable port range found, giving up\n"); |
425 | cs_error(link->handle, RequestIO, i); | 424 | cs_error(link, RequestIO, i); |
426 | kfree(cfg_mem); | 425 | kfree(cfg_mem); |
427 | return -1; | 426 | return -1; |
428 | } | 427 | } |
429 | 428 | ||
430 | i = pcmcia_request_irq(link->handle, &link->irq); | 429 | i = pcmcia_request_irq(link, &link->irq); |
431 | if (i != CS_SUCCESS) { | 430 | if (i != CS_SUCCESS) { |
432 | cs_error(link->handle, RequestIRQ, i); | 431 | cs_error(link, RequestIRQ, i); |
433 | link->irq.AssignedIRQ = 0; | 432 | link->irq.AssignedIRQ = 0; |
434 | } | 433 | } |
435 | if (info->multi && (info->manfid == MANFID_3COM)) | 434 | if (info->multi && (info->manfid == MANFID_3COM)) |
436 | link->conf.ConfigIndex &= ~(0x08); | 435 | link->conf.ConfigIndex &= ~(0x08); |
437 | i = pcmcia_request_configuration(link->handle, &link->conf); | 436 | i = pcmcia_request_configuration(link, &link->conf); |
438 | if (i != CS_SUCCESS) { | 437 | if (i != CS_SUCCESS) { |
439 | cs_error(link->handle, RequestConfiguration, i); | 438 | cs_error(link, RequestConfiguration, i); |
440 | kfree(cfg_mem); | 439 | kfree(cfg_mem); |
441 | return -1; | 440 | return -1; |
442 | } | 441 | } |
443 | kfree(cfg_mem); | 442 | kfree(cfg_mem); |
444 | return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 443 | return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); |
445 | } | 444 | } |
446 | 445 | ||
447 | static int multi_config(dev_link_t * link) | 446 | static int multi_config(struct pcmcia_device * link) |
448 | { | 447 | { |
449 | client_handle_t handle = link->handle; | ||
450 | struct serial_info *info = link->priv; | 448 | struct serial_info *info = link->priv; |
451 | struct serial_cfg_mem *cfg_mem; | 449 | struct serial_cfg_mem *cfg_mem; |
452 | tuple_t *tuple; | 450 | tuple_t *tuple; |
453 | u_char *buf; | 451 | u_char *buf; |
454 | cisparse_t *parse; | 452 | cisparse_t *parse; |
455 | cistpl_cftable_entry_t *cf; | 453 | cistpl_cftable_entry_t *cf; |
456 | config_info_t config; | ||
457 | int i, rc, base2 = 0; | 454 | int i, rc, base2 = 0; |
458 | 455 | ||
459 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); | 456 | cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); |
@@ -464,14 +461,6 @@ static int multi_config(dev_link_t * link) | |||
464 | cf = &parse->cftable_entry; | 461 | cf = &parse->cftable_entry; |
465 | buf = cfg_mem->buf; | 462 | buf = cfg_mem->buf; |
466 | 463 | ||
467 | i = pcmcia_get_configuration_info(handle, &config); | ||
468 | if (i != CS_SUCCESS) { | ||
469 | cs_error(handle, GetConfigurationInfo, i); | ||
470 | rc = -1; | ||
471 | goto free_cfg_mem; | ||
472 | } | ||
473 | link->conf.Vcc = config.Vcc; | ||
474 | |||
475 | tuple->TupleData = (cisdata_t *) buf; | 464 | tuple->TupleData = (cisdata_t *) buf; |
476 | tuple->TupleOffset = 0; | 465 | tuple->TupleOffset = 0; |
477 | tuple->TupleDataMax = 255; | 466 | tuple->TupleDataMax = 255; |
@@ -480,7 +469,7 @@ static int multi_config(dev_link_t * link) | |||
480 | 469 | ||
481 | /* First, look for a generic full-sized window */ | 470 | /* First, look for a generic full-sized window */ |
482 | link->io.NumPorts1 = info->multi * 8; | 471 | link->io.NumPorts1 = info->multi * 8; |
483 | i = first_tuple(handle, tuple, parse); | 472 | i = first_tuple(link, tuple, parse); |
484 | while (i != CS_NO_MORE_ITEMS) { | 473 | while (i != CS_NO_MORE_ITEMS) { |
485 | /* The quad port cards have bad CIS's, so just look for a | 474 | /* The quad port cards have bad CIS's, so just look for a |
486 | window larger than 8 ports and assume it will be right */ | 475 | window larger than 8 ports and assume it will be right */ |
@@ -490,19 +479,19 @@ static int multi_config(dev_link_t * link) | |||
490 | link->io.BasePort1 = cf->io.win[0].base; | 479 | link->io.BasePort1 = cf->io.win[0].base; |
491 | link->io.IOAddrLines = | 480 | link->io.IOAddrLines = |
492 | cf->io.flags & CISTPL_IO_LINES_MASK; | 481 | cf->io.flags & CISTPL_IO_LINES_MASK; |
493 | i = pcmcia_request_io(link->handle, &link->io); | 482 | i = pcmcia_request_io(link, &link->io); |
494 | base2 = link->io.BasePort1 + 8; | 483 | base2 = link->io.BasePort1 + 8; |
495 | if (i == CS_SUCCESS) | 484 | if (i == CS_SUCCESS) |
496 | break; | 485 | break; |
497 | } | 486 | } |
498 | i = next_tuple(handle, tuple, parse); | 487 | i = next_tuple(link, tuple, parse); |
499 | } | 488 | } |
500 | 489 | ||
501 | /* If that didn't work, look for two windows */ | 490 | /* If that didn't work, look for two windows */ |
502 | if (i != CS_SUCCESS) { | 491 | if (i != CS_SUCCESS) { |
503 | link->io.NumPorts1 = link->io.NumPorts2 = 8; | 492 | link->io.NumPorts1 = link->io.NumPorts2 = 8; |
504 | info->multi = 2; | 493 | info->multi = 2; |
505 | i = first_tuple(handle, tuple, parse); | 494 | i = first_tuple(link, tuple, parse); |
506 | while (i != CS_NO_MORE_ITEMS) { | 495 | while (i != CS_NO_MORE_ITEMS) { |
507 | if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { | 496 | if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { |
508 | link->conf.ConfigIndex = cf->index; | 497 | link->conf.ConfigIndex = cf->index; |
@@ -510,26 +499,26 @@ static int multi_config(dev_link_t * link) | |||
510 | link->io.BasePort2 = cf->io.win[1].base; | 499 | link->io.BasePort2 = cf->io.win[1].base; |
511 | link->io.IOAddrLines = | 500 | link->io.IOAddrLines = |
512 | cf->io.flags & CISTPL_IO_LINES_MASK; | 501 | cf->io.flags & CISTPL_IO_LINES_MASK; |
513 | i = pcmcia_request_io(link->handle, &link->io); | 502 | i = pcmcia_request_io(link, &link->io); |
514 | base2 = link->io.BasePort2; | 503 | base2 = link->io.BasePort2; |
515 | if (i == CS_SUCCESS) | 504 | if (i == CS_SUCCESS) |
516 | break; | 505 | break; |
517 | } | 506 | } |
518 | i = next_tuple(handle, tuple, parse); | 507 | i = next_tuple(link, tuple, parse); |
519 | } | 508 | } |
520 | } | 509 | } |
521 | 510 | ||
522 | if (i != CS_SUCCESS) { | 511 | if (i != CS_SUCCESS) { |
523 | cs_error(link->handle, RequestIO, i); | 512 | cs_error(link, RequestIO, i); |
524 | rc = -1; | 513 | rc = -1; |
525 | goto free_cfg_mem; | 514 | goto free_cfg_mem; |
526 | } | 515 | } |
527 | 516 | ||
528 | i = pcmcia_request_irq(link->handle, &link->irq); | 517 | i = pcmcia_request_irq(link, &link->irq); |
529 | if (i != CS_SUCCESS) { | 518 | if (i != CS_SUCCESS) { |
530 | printk(KERN_NOTICE | 519 | printk(KERN_NOTICE |
531 | "serial_cs: no usable port range found, giving up\n"); | 520 | "serial_cs: no usable port range found, giving up\n"); |
532 | cs_error(link->handle, RequestIRQ, i); | 521 | cs_error(link, RequestIRQ, i); |
533 | link->irq.AssignedIRQ = 0; | 522 | link->irq.AssignedIRQ = 0; |
534 | } | 523 | } |
535 | /* Socket Dual IO: this enables irq's for second port */ | 524 | /* Socket Dual IO: this enables irq's for second port */ |
@@ -537,35 +526,43 @@ static int multi_config(dev_link_t * link) | |||
537 | link->conf.Present |= PRESENT_EXT_STATUS; | 526 | link->conf.Present |= PRESENT_EXT_STATUS; |
538 | link->conf.ExtStatus = ESR_REQ_ATTN_ENA; | 527 | link->conf.ExtStatus = ESR_REQ_ATTN_ENA; |
539 | } | 528 | } |
540 | i = pcmcia_request_configuration(link->handle, &link->conf); | 529 | i = pcmcia_request_configuration(link, &link->conf); |
541 | if (i != CS_SUCCESS) { | 530 | if (i != CS_SUCCESS) { |
542 | cs_error(link->handle, RequestConfiguration, i); | 531 | cs_error(link, RequestConfiguration, i); |
543 | rc = -1; | 532 | rc = -1; |
544 | goto free_cfg_mem; | 533 | goto free_cfg_mem; |
545 | } | 534 | } |
546 | 535 | ||
547 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: | 536 | /* The Oxford Semiconductor OXCF950 cards are in fact single-port: |
548 | 8 registers are for the UART, the others are extra registers */ | 537 | * 8 registers are for the UART, the others are extra registers. |
549 | if (info->manfid == MANFID_OXSEMI) { | 538 | * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too. |
539 | */ | ||
540 | if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && | ||
541 | info->prodid == PRODID_POSSIO_GCC)) { | ||
542 | int err; | ||
543 | |||
550 | if (cf->index == 1 || cf->index == 3) { | 544 | if (cf->index == 1 || cf->index == 3) { |
551 | setup_serial(handle, info, base2, link->irq.AssignedIRQ); | 545 | err = setup_serial(link, info, base2, |
552 | outb(12, link->io.BasePort1 + 1); | 546 | link->irq.AssignedIRQ); |
547 | base2 = link->io.BasePort1; | ||
553 | } else { | 548 | } else { |
554 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 549 | err = setup_serial(link, info, link->io.BasePort1, |
555 | outb(12, base2 + 1); | 550 | link->irq.AssignedIRQ); |
556 | } | 551 | } |
552 | info->c950ctrl = base2; | ||
553 | wakeup_card(info); | ||
557 | rc = 0; | 554 | rc = 0; |
558 | goto free_cfg_mem; | 555 | goto free_cfg_mem; |
559 | } | 556 | } |
560 | 557 | ||
561 | setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); | 558 | setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); |
562 | /* The Nokia cards are not really multiport cards */ | 559 | /* The Nokia cards are not really multiport cards */ |
563 | if (info->manfid == MANFID_NOKIA) { | 560 | if (info->manfid == MANFID_NOKIA) { |
564 | rc = 0; | 561 | rc = 0; |
565 | goto free_cfg_mem; | 562 | goto free_cfg_mem; |
566 | } | 563 | } |
567 | for (i = 0; i < info->multi - 1; i++) | 564 | for (i = 0; i < info->multi - 1; i++) |
568 | setup_serial(handle, info, base2 + (8 * i), | 565 | setup_serial(link, info, base2 + (8 * i), |
569 | link->irq.AssignedIRQ); | 566 | link->irq.AssignedIRQ); |
570 | rc = 0; | 567 | rc = 0; |
571 | free_cfg_mem: | 568 | free_cfg_mem: |
@@ -581,9 +578,8 @@ free_cfg_mem: | |||
581 | 578 | ||
582 | ======================================================================*/ | 579 | ======================================================================*/ |
583 | 580 | ||
584 | void serial_config(dev_link_t * link) | 581 | static int serial_config(struct pcmcia_device * link) |
585 | { | 582 | { |
586 | client_handle_t handle = link->handle; | ||
587 | struct serial_info *info = link->priv; | 583 | struct serial_info *info = link->priv; |
588 | struct serial_cfg_mem *cfg_mem; | 584 | struct serial_cfg_mem *cfg_mem; |
589 | tuple_t *tuple; | 585 | tuple_t *tuple; |
@@ -609,7 +605,7 @@ void serial_config(dev_link_t * link) | |||
609 | tuple->Attributes = 0; | 605 | tuple->Attributes = 0; |
610 | /* Get configuration register information */ | 606 | /* Get configuration register information */ |
611 | tuple->DesiredTuple = CISTPL_CONFIG; | 607 | tuple->DesiredTuple = CISTPL_CONFIG; |
612 | last_ret = first_tuple(handle, tuple, parse); | 608 | last_ret = first_tuple(link, tuple, parse); |
613 | if (last_ret != CS_SUCCESS) { | 609 | if (last_ret != CS_SUCCESS) { |
614 | last_fn = ParseTuple; | 610 | last_fn = ParseTuple; |
615 | goto cs_failed; | 611 | goto cs_failed; |
@@ -617,18 +613,16 @@ void serial_config(dev_link_t * link) | |||
617 | link->conf.ConfigBase = parse->config.base; | 613 | link->conf.ConfigBase = parse->config.base; |
618 | link->conf.Present = parse->config.rmask[0]; | 614 | link->conf.Present = parse->config.rmask[0]; |
619 | 615 | ||
620 | /* Configure card */ | ||
621 | link->state |= DEV_CONFIG; | ||
622 | |||
623 | /* Is this a compliant multifunction card? */ | 616 | /* Is this a compliant multifunction card? */ |
624 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; | 617 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; |
625 | tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; | 618 | tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; |
626 | info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS); | 619 | info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS); |
627 | 620 | ||
628 | /* Is this a multiport card? */ | 621 | /* Is this a multiport card? */ |
629 | tuple->DesiredTuple = CISTPL_MANFID; | 622 | tuple->DesiredTuple = CISTPL_MANFID; |
630 | if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { | 623 | if (first_tuple(link, tuple, parse) == CS_SUCCESS) { |
631 | info->manfid = parse->manfid.manf; | 624 | info->manfid = parse->manfid.manf; |
625 | info->prodid = le16_to_cpu(buf[1]); | ||
632 | for (i = 0; i < MULTI_COUNT; i++) | 626 | for (i = 0; i < MULTI_COUNT; i++) |
633 | if ((info->manfid == multi_id[i].manfid) && | 627 | if ((info->manfid == multi_id[i].manfid) && |
634 | (parse->manfid.card == multi_id[i].prodid)) | 628 | (parse->manfid.card == multi_id[i].prodid)) |
@@ -641,11 +635,11 @@ void serial_config(dev_link_t * link) | |||
641 | multifunction cards that ask for appropriate IO port ranges */ | 635 | multifunction cards that ask for appropriate IO port ranges */ |
642 | tuple->DesiredTuple = CISTPL_FUNCID; | 636 | tuple->DesiredTuple = CISTPL_FUNCID; |
643 | if ((info->multi == 0) && | 637 | if ((info->multi == 0) && |
644 | ((first_tuple(handle, tuple, parse) != CS_SUCCESS) || | 638 | ((first_tuple(link, tuple, parse) != CS_SUCCESS) || |
645 | (parse->funcid.func == CISTPL_FUNCID_MULTI) || | 639 | (parse->funcid.func == CISTPL_FUNCID_MULTI) || |
646 | (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { | 640 | (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { |
647 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; | 641 | tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; |
648 | if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { | 642 | if (first_tuple(link, tuple, parse) == CS_SUCCESS) { |
649 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) | 643 | if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) |
650 | info->multi = cf->io.win[0].len >> 3; | 644 | info->multi = cf->io.win[0].len >> 3; |
651 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && | 645 | if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && |
@@ -664,31 +658,30 @@ void serial_config(dev_link_t * link) | |||
664 | 658 | ||
665 | if (info->manfid == MANFID_IBM) { | 659 | if (info->manfid == MANFID_IBM) { |
666 | conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; | 660 | conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; |
667 | last_ret = pcmcia_access_configuration_register(link->handle, ®); | 661 | last_ret = pcmcia_access_configuration_register(link, ®); |
668 | if (last_ret) { | 662 | if (last_ret) { |
669 | last_fn = AccessConfigurationRegister; | 663 | last_fn = AccessConfigurationRegister; |
670 | goto cs_failed; | 664 | goto cs_failed; |
671 | } | 665 | } |
672 | reg.Action = CS_WRITE; | 666 | reg.Action = CS_WRITE; |
673 | reg.Value = reg.Value | 1; | 667 | reg.Value = reg.Value | 1; |
674 | last_ret = pcmcia_access_configuration_register(link->handle, ®); | 668 | last_ret = pcmcia_access_configuration_register(link, ®); |
675 | if (last_ret) { | 669 | if (last_ret) { |
676 | last_fn = AccessConfigurationRegister; | 670 | last_fn = AccessConfigurationRegister; |
677 | goto cs_failed; | 671 | goto cs_failed; |
678 | } | 672 | } |
679 | } | 673 | } |
680 | 674 | ||
681 | link->dev = &info->node[0]; | 675 | link->dev_node = &info->node[0]; |
682 | link->state &= ~DEV_CONFIG_PENDING; | ||
683 | kfree(cfg_mem); | 676 | kfree(cfg_mem); |
684 | return; | 677 | return 0; |
685 | 678 | ||
686 | cs_failed: | 679 | cs_failed: |
687 | cs_error(link->handle, last_fn, last_ret); | 680 | cs_error(link, last_fn, last_ret); |
688 | failed: | 681 | failed: |
689 | serial_remove(link); | 682 | serial_remove(link); |
690 | link->state &= ~DEV_CONFIG_PENDING; | ||
691 | kfree(cfg_mem); | 683 | kfree(cfg_mem); |
684 | return -ENODEV; | ||
692 | } | 685 | } |
693 | 686 | ||
694 | static struct pcmcia_device_id serial_ids[] = { | 687 | static struct pcmcia_device_id serial_ids[] = { |
@@ -739,6 +732,7 @@ static struct pcmcia_device_id serial_ids[] = { | |||
739 | PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77), | 732 | PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77), |
740 | PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302), | 733 | PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302), |
741 | PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301), | 734 | PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301), |
735 | PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), | ||
742 | PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), | 736 | PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), |
743 | PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), | 737 | PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), |
744 | PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), | 738 | PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), |
@@ -757,6 +751,7 @@ static struct pcmcia_device_id serial_ids[] = { | |||
757 | PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), | 751 | PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), |
758 | PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef), | 752 | PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef), |
759 | PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0), | 753 | PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0), |
754 | PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e), | ||
760 | PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a), | 755 | PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a), |
761 | PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02), | 756 | PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02), |
762 | PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa), | 757 | PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa), |