diff options
Diffstat (limited to 'drivers/parport')
-rw-r--r-- | drivers/parport/parport_serial.c | 339 |
1 files changed, 166 insertions, 173 deletions
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 00498e2f1205..d3dad0aac7cb 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c | |||
@@ -23,13 +23,8 @@ | |||
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/parport.h> | 24 | #include <linux/parport.h> |
25 | #include <linux/parport_pc.h> | 25 | #include <linux/parport_pc.h> |
26 | #include <linux/serial.h> | ||
27 | #include <linux/serialP.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/8250_pci.h> | 26 | #include <linux/8250_pci.h> |
30 | 27 | ||
31 | #include <asm/serial.h> | ||
32 | |||
33 | enum parport_pc_pci_cards { | 28 | enum parport_pc_pci_cards { |
34 | titan_110l = 0, | 29 | titan_110l = 0, |
35 | titan_210l, | 30 | titan_210l, |
@@ -168,182 +163,147 @@ static struct pci_device_id parport_serial_pci_tbl[] = { | |||
168 | }; | 163 | }; |
169 | MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); | 164 | MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); |
170 | 165 | ||
171 | struct pci_board_no_ids { | 166 | /* |
172 | int flags; | 167 | * This table describes the serial "geometry" of these boards. Any |
173 | int num_ports; | 168 | * quirks for these can be found in drivers/serial/8250_pci.c |
174 | int base_baud; | 169 | * |
175 | int uart_offset; | 170 | * Cards not tested are marked n/t |
176 | int reg_shift; | 171 | * If you have one of these cards and it works for you, please tell me.. |
177 | int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board, | 172 | */ |
178 | int enable); | 173 | static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { |
179 | int first_uart_offset; | 174 | [titan_110l] = { |
180 | }; | 175 | .flags = FL_BASE1 | FL_BASE_BARS, |
181 | 176 | .num_ports = 1, | |
182 | static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) | 177 | .base_baud = 921600, |
183 | { | 178 | .uart_offset = 8, |
184 | return pci_siig10x_fn(dev, enable); | 179 | }, |
185 | } | 180 | [titan_210l] = { |
186 | 181 | .flags = FL_BASE1 | FL_BASE_BARS, | |
187 | static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) | 182 | .num_ports = 2, |
188 | { | 183 | .base_baud = 921600, |
189 | return pci_siig20x_fn(dev, enable); | 184 | .uart_offset = 8, |
190 | } | 185 | }, |
191 | 186 | [netmos_9xx5_combo] = { | |
192 | static int __devinit netmos_serial_init(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) | 187 | .flags = FL_BASE0 | FL_BASE_BARS, |
193 | { | 188 | .num_ports = 1, |
194 | board->num_ports = dev->subsystem_device & 0xf; | 189 | .base_baud = 115200, |
195 | return 0; | 190 | .uart_offset = 8, |
196 | } | 191 | }, |
197 | 192 | [netmos_9855] = { | |
198 | static struct pci_board_no_ids pci_boards[] __devinitdata = { | 193 | .flags = FL_BASE2 | FL_BASE_BARS, |
199 | /* | 194 | .num_ports = 1, |
200 | * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, | 195 | .base_baud = 115200, |
201 | * Offset to get to next UART's registers, | 196 | .uart_offset = 8, |
202 | * Register shift to use for memory-mapped I/O, | 197 | }, |
203 | * Initialization function, first UART offset | 198 | [avlab_1s1p] = { /* n/t */ |
204 | */ | 199 | .flags = FL_BASE0 | FL_BASE_BARS, |
205 | 200 | .num_ports = 1, | |
206 | // Cards not tested are marked n/t | 201 | .base_baud = 115200, |
207 | // If you have one of these cards and it works for you, please tell me.. | 202 | .uart_offset = 8, |
208 | 203 | }, | |
209 | /* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 }, | 204 | [avlab_1s1p_650] = { /* nt */ |
210 | /* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, | 205 | .flags = FL_BASE0 | FL_BASE_BARS, |
211 | /* netmos_9xx5_combo */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init }, | 206 | .num_ports = 1, |
212 | /* netmos_9855 */ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init }, | 207 | .base_baud = 115200, |
213 | /* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 208 | .uart_offset = 8, |
214 | /* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 209 | }, |
215 | /* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 210 | [avlab_1s1p_850] = { /* nt */ |
216 | /* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 211 | .flags = FL_BASE0 | FL_BASE_BARS, |
217 | /* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 212 | .num_ports = 1, |
218 | /* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, | 213 | .base_baud = 115200, |
219 | /* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, | 214 | .uart_offset = 8, |
220 | /* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, | 215 | }, |
221 | /* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, | 216 | [avlab_1s2p] = { /* n/t */ |
222 | /* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn }, | 217 | .flags = FL_BASE0 | FL_BASE_BARS, |
223 | /* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn }, | 218 | .num_ports = 1, |
224 | /* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, | 219 | .base_baud = 115200, |
225 | /* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, | 220 | .uart_offset = 8, |
226 | /* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, | 221 | }, |
222 | [avlab_1s2p_650] = { /* nt */ | ||
223 | .flags = FL_BASE0 | FL_BASE_BARS, | ||
224 | .num_ports = 1, | ||
225 | .base_baud = 115200, | ||
226 | .uart_offset = 8, | ||
227 | }, | ||
228 | [avlab_1s2p_850] = { /* nt */ | ||
229 | .flags = FL_BASE0 | FL_BASE_BARS, | ||
230 | .num_ports = 1, | ||
231 | .base_baud = 115200, | ||
232 | .uart_offset = 8, | ||
233 | }, | ||
234 | [avlab_2s1p] = { /* n/t */ | ||
235 | .flags = FL_BASE0 | FL_BASE_BARS, | ||
236 | .num_ports = 2, | ||
237 | .base_baud = 115200, | ||
238 | .uart_offset = 8, | ||
239 | }, | ||
240 | [avlab_2s1p_650] = { /* nt */ | ||
241 | .flags = FL_BASE0 | FL_BASE_BARS, | ||
242 | .num_ports = 2, | ||
243 | .base_baud = 115200, | ||
244 | .uart_offset = 8, | ||
245 | }, | ||
246 | [avlab_2s1p_850] = { /* nt */ | ||
247 | .flags = FL_BASE0 | FL_BASE_BARS, | ||
248 | .num_ports = 2, | ||
249 | .base_baud = 115200, | ||
250 | .uart_offset = 8, | ||
251 | }, | ||
252 | [siig_1s1p_10x] = { | ||
253 | .flags = FL_BASE2, | ||
254 | .num_ports = 1, | ||
255 | .base_baud = 460800, | ||
256 | .uart_offset = 8, | ||
257 | }, | ||
258 | [siig_2s1p_10x] = { | ||
259 | .flags = FL_BASE2, | ||
260 | .num_ports = 1, | ||
261 | .base_baud = 921600, | ||
262 | .uart_offset = 8, | ||
263 | }, | ||
264 | [siig_2p1s_20x] = { | ||
265 | .flags = FL_BASE0, | ||
266 | .num_ports = 1, | ||
267 | .base_baud = 921600, | ||
268 | .uart_offset = 8, | ||
269 | }, | ||
270 | [siig_1s1p_20x] = { | ||
271 | .flags = FL_BASE0, | ||
272 | .num_ports = 1, | ||
273 | .base_baud = 921600, | ||
274 | .uart_offset = 8, | ||
275 | }, | ||
276 | [siig_2s1p_20x] = { | ||
277 | .flags = FL_BASE0, | ||
278 | .num_ports = 1, | ||
279 | .base_baud = 921600, | ||
280 | .uart_offset = 8, | ||
281 | }, | ||
227 | }; | 282 | }; |
228 | 283 | ||
229 | struct parport_serial_private { | 284 | struct parport_serial_private { |
230 | int num_ser; | 285 | struct serial_private *serial; |
231 | int line[20]; | ||
232 | struct pci_board_no_ids ser; | ||
233 | int num_par; | 286 | int num_par; |
234 | struct parport *port[PARPORT_MAX]; | 287 | struct parport *port[PARPORT_MAX]; |
235 | struct parport_pc_pci par; | 288 | struct parport_pc_pci par; |
236 | }; | 289 | }; |
237 | 290 | ||
238 | static int __devinit get_pci_port (struct pci_dev *dev, | ||
239 | struct pci_board_no_ids *board, | ||
240 | struct serial_struct *req, | ||
241 | int idx) | ||
242 | { | ||
243 | unsigned long port; | ||
244 | int base_idx; | ||
245 | int max_port; | ||
246 | int offset; | ||
247 | |||
248 | base_idx = SPCI_FL_GET_BASE(board->flags); | ||
249 | if (board->flags & SPCI_FL_BASE_TABLE) | ||
250 | base_idx += idx; | ||
251 | |||
252 | if (board->flags & SPCI_FL_REGION_SZ_CAP) { | ||
253 | max_port = pci_resource_len(dev, base_idx) / 8; | ||
254 | if (idx >= max_port) | ||
255 | return 1; | ||
256 | } | ||
257 | |||
258 | offset = board->first_uart_offset; | ||
259 | |||
260 | /* Timedia/SUNIX uses a mixture of BARs and offsets */ | ||
261 | /* Ugh, this is ugly as all hell --- TYT */ | ||
262 | if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ | ||
263 | switch(idx) { | ||
264 | case 0: base_idx=0; | ||
265 | break; | ||
266 | case 1: base_idx=0; offset=8; | ||
267 | break; | ||
268 | case 2: base_idx=1; | ||
269 | break; | ||
270 | case 3: base_idx=1; offset=8; | ||
271 | break; | ||
272 | case 4: /* BAR 2*/ | ||
273 | case 5: /* BAR 3 */ | ||
274 | case 6: /* BAR 4*/ | ||
275 | case 7: base_idx=idx-2; /* BAR 5*/ | ||
276 | } | ||
277 | |||
278 | port = pci_resource_start(dev, base_idx) + offset; | ||
279 | |||
280 | if ((board->flags & SPCI_FL_BASE_TABLE) == 0) | ||
281 | port += idx * (board->uart_offset ? board->uart_offset : 8); | ||
282 | |||
283 | if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) { | ||
284 | int high_bits_offset = ((sizeof(long)-sizeof(int))*8); | ||
285 | req->port = port; | ||
286 | if (high_bits_offset) | ||
287 | req->port_high = port >> high_bits_offset; | ||
288 | else | ||
289 | req->port_high = 0; | ||
290 | return 0; | ||
291 | } | ||
292 | req->io_type = SERIAL_IO_MEM; | ||
293 | req->iomem_base = ioremap(port, board->uart_offset); | ||
294 | req->iomem_reg_shift = board->reg_shift; | ||
295 | req->port = 0; | ||
296 | return req->iomem_base ? 0 : 1; | ||
297 | } | ||
298 | |||
299 | /* Register the serial port(s) of a PCI card. */ | 291 | /* Register the serial port(s) of a PCI card. */ |
300 | static int __devinit serial_register (struct pci_dev *dev, | 292 | static int __devinit serial_register (struct pci_dev *dev, |
301 | const struct pci_device_id *id) | 293 | const struct pci_device_id *id) |
302 | { | 294 | { |
303 | struct pci_board_no_ids *board; | ||
304 | struct parport_serial_private *priv = pci_get_drvdata (dev); | 295 | struct parport_serial_private *priv = pci_get_drvdata (dev); |
305 | struct serial_struct serial_req; | 296 | struct pciserial_board *board; |
306 | int base_baud; | 297 | struct serial_private *serial; |
307 | int k; | ||
308 | int success = 0; | ||
309 | |||
310 | priv->ser = pci_boards[id->driver_data]; | ||
311 | board = &priv->ser; | ||
312 | if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0)) | ||
313 | return 1; | ||
314 | |||
315 | base_baud = board->base_baud; | ||
316 | if (!base_baud) | ||
317 | base_baud = BASE_BAUD; | ||
318 | memset (&serial_req, 0, sizeof (serial_req)); | ||
319 | |||
320 | for (k = 0; k < board->num_ports; k++) { | ||
321 | int line; | ||
322 | 298 | ||
323 | if (priv->num_ser == ARRAY_SIZE (priv->line)) { | 299 | board = &pci_parport_serial_boards[id->driver_data]; |
324 | printk (KERN_WARNING | 300 | serial = pciserial_init_ports(dev, board); |
325 | "parport_serial: %s: only %u serial lines " | ||
326 | "supported (%d reported)\n", pci_name (dev), | ||
327 | ARRAY_SIZE (priv->line), board->num_ports); | ||
328 | break; | ||
329 | } | ||
330 | 301 | ||
331 | serial_req.irq = dev->irq; | 302 | if (IS_ERR(serial)) |
332 | if (get_pci_port (dev, board, &serial_req, k)) | 303 | return PTR_ERR(serial); |
333 | break; | ||
334 | serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; | ||
335 | serial_req.baud_base = base_baud; | ||
336 | line = register_serial (&serial_req); | ||
337 | if (line < 0) { | ||
338 | printk (KERN_DEBUG | ||
339 | "parport_serial: register_serial failed\n"); | ||
340 | continue; | ||
341 | } | ||
342 | priv->line[priv->num_ser++] = line; | ||
343 | success = 1; | ||
344 | } | ||
345 | 304 | ||
346 | return success ? 0 : 1; | 305 | priv->serial = serial; |
306 | return 0; | ||
347 | } | 307 | } |
348 | 308 | ||
349 | /* Register the parallel port(s) of a PCI card. */ | 309 | /* Register the parallel port(s) of a PCI card. */ |
@@ -411,7 +371,7 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev, | |||
411 | priv = kmalloc (sizeof *priv, GFP_KERNEL); | 371 | priv = kmalloc (sizeof *priv, GFP_KERNEL); |
412 | if (!priv) | 372 | if (!priv) |
413 | return -ENOMEM; | 373 | return -ENOMEM; |
414 | priv->num_ser = priv->num_par = 0; | 374 | memset(priv, 0, sizeof(struct parport_serial_private)); |
415 | pci_set_drvdata (dev, priv); | 375 | pci_set_drvdata (dev, priv); |
416 | 376 | ||
417 | err = pci_enable_device (dev); | 377 | err = pci_enable_device (dev); |
@@ -444,15 +404,12 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev) | |||
444 | struct parport_serial_private *priv = pci_get_drvdata (dev); | 404 | struct parport_serial_private *priv = pci_get_drvdata (dev); |
445 | int i; | 405 | int i; |
446 | 406 | ||
407 | pci_set_drvdata(dev, NULL); | ||
408 | |||
447 | // Serial ports | 409 | // Serial ports |
448 | for (i = 0; i < priv->num_ser; i++) { | 410 | if (priv->serial) |
449 | unregister_serial (priv->line[i]); | 411 | pciserial_remove_ports(priv->serial); |
450 | 412 | ||
451 | if (priv->ser.init_fn) | ||
452 | (priv->ser.init_fn) (dev, &priv->ser, 0); | ||
453 | } | ||
454 | pci_set_drvdata (dev, NULL); | ||
455 | |||
456 | // Parallel ports | 413 | // Parallel ports |
457 | for (i = 0; i < priv->num_par; i++) | 414 | for (i = 0; i < priv->num_par; i++) |
458 | parport_pc_unregister_port (priv->port[i]); | 415 | parport_pc_unregister_port (priv->port[i]); |
@@ -461,11 +418,47 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev) | |||
461 | return; | 418 | return; |
462 | } | 419 | } |
463 | 420 | ||
421 | static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) | ||
422 | { | ||
423 | struct parport_serial_private *priv = pci_get_drvdata(dev); | ||
424 | |||
425 | if (priv->serial) | ||
426 | pciserial_suspend_ports(priv->serial); | ||
427 | |||
428 | /* FIXME: What about parport? */ | ||
429 | |||
430 | pci_save_state(dev); | ||
431 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int parport_serial_pci_resume(struct pci_dev *dev) | ||
436 | { | ||
437 | struct parport_serial_private *priv = pci_get_drvdata(dev); | ||
438 | |||
439 | pci_set_power_state(dev, PCI_D0); | ||
440 | pci_restore_state(dev); | ||
441 | |||
442 | /* | ||
443 | * The device may have been disabled. Re-enable it. | ||
444 | */ | ||
445 | pci_enable_device(dev); | ||
446 | |||
447 | if (priv->serial) | ||
448 | pciserial_resume_ports(priv->serial); | ||
449 | |||
450 | /* FIXME: What about parport? */ | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
464 | static struct pci_driver parport_serial_pci_driver = { | 455 | static struct pci_driver parport_serial_pci_driver = { |
465 | .name = "parport_serial", | 456 | .name = "parport_serial", |
466 | .id_table = parport_serial_pci_tbl, | 457 | .id_table = parport_serial_pci_tbl, |
467 | .probe = parport_serial_pci_probe, | 458 | .probe = parport_serial_pci_probe, |
468 | .remove = __devexit_p(parport_serial_pci_remove), | 459 | .remove = __devexit_p(parport_serial_pci_remove), |
460 | .suspend = parport_serial_pci_suspend, | ||
461 | .resume = parport_serial_pci_resume, | ||
469 | }; | 462 | }; |
470 | 463 | ||
471 | 464 | ||