File: /usr/src/linux/drivers/media/video/cpia_pp.c
1 /*
2 * cpia_pp CPiA Parallel Port driver
3 *
4 * Supports CPiA based parallel port Video Camera's.
5 *
6 * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
7 * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
8 * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
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 as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <linux/config.h>
26 #include <linux/version.h>
27
28 #include <linux/module.h>
29 #include <linux/init.h>
30
31 #include <linux/kernel.h>
32 #include <linux/parport.h>
33 #include <linux/interrupt.h>
34 #include <linux/delay.h>
35 #include <linux/smp_lock.h>
36
37 #include <linux/kmod.h>
38
39 /* #define _CPIA_DEBUG_ define for verbose debug output */
40 #include "cpia.h"
41
42 static int cpia_pp_open(void *privdata);
43 static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
44 void *cbdata);
45 static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
46 static int cpia_pp_streamStart(void *privdata);
47 static int cpia_pp_streamStop(void *privdata);
48 static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
49 static int cpia_pp_close(void *privdata);
50
51 #define ABOUT "Parallel port driver for Vision CPiA based cameras"
52
53 /* IEEE 1284 Compatiblity Mode signal names */
54 #define nStrobe PARPORT_CONTROL_STROBE /* inverted */
55 #define nAutoFd PARPORT_CONTROL_AUTOFD /* inverted */
56 #define nInit PARPORT_CONTROL_INIT
57 #define nSelectIn PARPORT_CONTROL_SELECT
58 #define IntrEnable PARPORT_CONTROL_INTEN /* normally zero for no IRQ */
59 #define DirBit PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse */
60
61 #define nFault PARPORT_STATUS_ERROR
62 #define Select PARPORT_STATUS_SELECT
63 #define PError PARPORT_STATUS_PAPEROUT
64 #define nAck PARPORT_STATUS_ACK
65 #define Busy PARPORT_STATUS_BUSY /* inverted */
66
67 /* some more */
68 #define HostClk nStrobe
69 #define HostAck nAutoFd
70 #define nReverseRequest nInit
71 #define Active_1284 nSelectIn
72 #define nPeriphRequest nFault
73 #define XFlag Select
74 #define nAckReverse PError
75 #define PeriphClk nAck
76 #define PeriphAck Busy
77
78 /* these can be used to correct for the inversion on some bits */
79 #define STATUS_INVERSION_MASK (Busy)
80 #define CONTROL_INVERSION_MASK (nStrobe|nAutoFd|nSelectIn)
81
82 #define ECR_empty 0x01
83 #define ECR_full 0x02
84 #define ECR_serviceIntr 0x04
85 #define ECR_dmaEn 0x08
86 #define ECR_nErrIntrEn 0x10
87
88 #define ECR_mode_mask 0xE0
89 #define ECR_SPP_mode 0x00
90 #define ECR_PS2_mode 0x20
91 #define ECR_FIFO_mode 0x40
92 #define ECR_ECP_mode 0x60
93
94 #define ECP_FIFO_SIZE 16
95 #define DMA_BUFFER_SIZE PAGE_SIZE
96 /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
97 #define PARPORT_CHUNK_SIZE PAGE_SIZE/* >=2.3.x */
98 /* we read this many bytes at once */
99
100 #define GetECRMasked(port,mask) (parport_read_econtrol(port) & (mask))
101 #define GetStatus(port) ((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
102 #define SetStatus(port,val) parport_write_status(port,(val)^STATUS_INVERSION_MASK)
103 #define GetControl(port) ((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f))
104 #define SetControl(port,val) parport_write_control(port,(val)^CONTROL_INVERSION_MASK)
105
106 #define GetStatusMasked(port,mask) (GetStatus(port) & (mask))
107 #define GetControlMasked(port,mask) (GetControl(port) & (mask))
108 #define SetControlMasked(port,mask) SetControl(port,GetControl(port) | (mask));
109 #define ClearControlMasked(port,mask) SetControl(port,GetControl(port)&~(mask));
110 #define FrobControlBit(port,mask,value) SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
111
112 #define PACKET_LENGTH 8
113
114 /* Magic numbers for defining port-device mappings */
115 #define PPCPIA_PARPORT_UNSPEC -4
116 #define PPCPIA_PARPORT_AUTO -3
117 #define PPCPIA_PARPORT_OFF -2
118 #define PPCPIA_PARPORT_NONE -1
119
120 #ifdef MODULE
121 static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
122 static char *parport[PARPORT_MAX] = {NULL,};
123
124 MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
125 MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
126 MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");
127 MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
128 #else
129 static int parport_nr[PARPORT_MAX] __initdata =
130 {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
131 static int parport_ptr = 0;
132 #endif
133
134 struct pp_cam_entry {
135 struct pardevice *pdev;
136 struct parport *port;
137 struct tq_struct cb_task;
138 int open_count;
139 wait_queue_head_t wq_stream;
140 /* image state flags */
141 int image_ready; /* we got an interrupt */
142 int image_complete; /* we have seen 4 EOI */
143
144 int streaming; /* we are in streaming mode */
145 int stream_irq;
146 };
147
148 static struct cpia_camera_ops cpia_pp_ops =
149 {
150 cpia_pp_open,
151 cpia_pp_registerCallback,
152 cpia_pp_transferCmd,
153 cpia_pp_streamStart,
154 cpia_pp_streamStop,
155 cpia_pp_streamRead,
156 cpia_pp_close,
157 1
158 };
159
160 static struct cam_data *cam_list;
161
162 #ifdef _CPIA_DEBUG_
163 #define DEB_PORT(port) { \
164 u8 controll = GetControl(port); \
165 u8 statusss = GetStatus(port); \
166 DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\
167 ((controll & nSelectIn) ? 'U' : 'D'), \
168 ((statusss & PError) ? 'U' : 'D'), \
169 ((controll & nAutoFd) ? 'U' : 'D'), \
170 ((controll & nStrobe) ? 'U' : 'D'), \
171 ((statusss & nAck) ? 'U' : 'D'), \
172 ((statusss & Busy) ? 'U' : 'D'), \
173 ((statusss & nFault) ? 'U' : 'D'), \
174 ((statusss & Select) ? 'U' : 'D'), \
175 ((controll & nInit) ? 'U' : 'D'), \
176 ((controll & DirBit) ? 'R' : 'F') \
177 ); }
178 #else
179 #define DEB_PORT(port) {}
180 #endif
181
182 #define WHILE_OUT_TIMEOUT (HZ/10)
183 #define DMA_TIMEOUT 10*HZ
184
185 /* FIXME */
186 static void cpia_parport_enable_irq( struct parport *port ) {
187 parport_enable_irq(port);
188 mdelay(10);
189 return;
190 }
191
192 static void cpia_parport_disable_irq( struct parport *port ) {
193 parport_disable_irq(port);
194 mdelay(10);
195 return;
196 }
197
198 /****************************************************************************
199 *
200 * EndTransferMode
201 *
202 ***************************************************************************/
203 static void EndTransferMode(struct pp_cam_entry *cam)
204 {
205 parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
206 }
207
208 /****************************************************************************
209 *
210 * ForwardSetup
211 *
212 ***************************************************************************/
213 static int ForwardSetup(struct pp_cam_entry *cam)
214 {
215 int retry;
216
217 /* After some commands the camera needs extra time before
218 * it will respond again, so we try up to 3 times */
219 for(retry=0; retry<3; ++retry) {
220 if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
221 break;
222 }
223 }
224 if(retry == 3) {
225 DBG("Unable to negotiate ECP mode\n");
226 return -1;
227 }
228 return 0;
229 }
230
231 /****************************************************************************
232 *
233 * ReverseSetup
234 *
235 ***************************************************************************/
236 static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
237 {
238 int retry;
239 int mode = IEEE1284_MODE_ECP;
240 if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
241
242 /* After some commands the camera needs extra time before
243 * it will respond again, so we try up to 3 times */
244 for(retry=0; retry<3; ++retry) {
245 if(!parport_negotiate(cam->port, mode)) {
246 break;
247 }
248 }
249 if(retry == 3) {
250 if(extensibility)
251 DBG("Unable to negotiate extensibility mode\n");
252 else
253 DBG("Unable to negotiate ECP mode\n");
254 return -1;
255 }
256 if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP;
257 return 0;
258 }
259
260 /****************************************************************************
261 *
262 * WritePacket
263 *
264 ***************************************************************************/
265 static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
266 {
267 int retval=0;
268 int size_written;
269
270 if (packet == NULL) {
271 return -EINVAL;
272 }
273 if (ForwardSetup(cam)) {
274 DBG("Write failed in setup\n");
275 return -EIO;
276 }
277 size_written = parport_write(cam->port, packet, size);
278 if(size_written != size) {
279 DBG("Write failed, wrote %d/%d\n", size_written, size);
280 retval = -EIO;
281 }
282 EndTransferMode(cam);
283 return retval;
284 }
285
286 /****************************************************************************
287 *
288 * ReadPacket
289 *
290 ***************************************************************************/
291 static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
292 {
293 int retval=0;
294 if (packet == NULL) {
295 return -EINVAL;
296 }
297 if (ReverseSetup(cam, 0)) {
298 return -EIO;
299 }
300 if(parport_read(cam->port, packet, size) != size) {
301 retval = -EIO;
302 }
303 EndTransferMode(cam);
304 return retval;
305 }
306
307 /****************************************************************************
308 *
309 * cpia_pp_streamStart
310 *
311 ***************************************************************************/
312 static int cpia_pp_streamStart(void *privdata)
313 {
314 struct pp_cam_entry *cam = privdata;
315 DBG("\n");
316 cam->streaming=1;
317 cam->image_ready=0;
318 //if (ReverseSetup(cam,1)) return -EIO;
319 if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
320 return 0;
321 }
322
323 /****************************************************************************
324 *
325 * cpia_pp_streamStop
326 *
327 ***************************************************************************/
328 static int cpia_pp_streamStop(void *privdata)
329 {
330 struct pp_cam_entry *cam = privdata;
331
332 DBG("\n");
333 cam->streaming=0;
334 cpia_parport_disable_irq(cam->port);
335 //EndTransferMode(cam);
336
337 return 0;
338 }
339
340 static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
341 {
342 int bytes_read, new_bytes;
343 for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
344 new_bytes = parport_read(port, buffer+bytes_read,
345 len-bytes_read);
346 if(new_bytes < 0) break;
347 }
348 return bytes_read;
349 }
350
351 /****************************************************************************
352 *
353 * cpia_pp_streamRead
354 *
355 ***************************************************************************/
356 static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
357 {
358 struct pp_cam_entry *cam = privdata;
359 int read_bytes = 0;
360 int i, endseen, block_size, new_bytes;
361
362 if(cam == NULL) {
363 DBG("Internal driver error: cam is NULL\n");
364 return -EINVAL;
365 }
366 if(buffer == NULL) {
367 DBG("Internal driver error: buffer is NULL\n");
368 return -EINVAL;
369 }
370 //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
371 if( cam->stream_irq ) {
372 DBG("%d\n", cam->image_ready);
373 cam->image_ready--;
374 }
375 cam->image_complete=0;
376 if (0/*cam->streaming*/) {
377 if(!cam->image_ready) {
378 if(noblock) return -EWOULDBLOCK;
379 interruptible_sleep_on(&cam->wq_stream);
380 if( signal_pending(current) ) return -EINTR;
381 DBG("%d\n", cam->image_ready);
382 }
383 } else {
384 if (ReverseSetup(cam, 1)) {
385 DBG("unable to ReverseSetup\n");
386 return -EIO;
387 }
388 }
389 endseen = 0;
390 block_size = PARPORT_CHUNK_SIZE;
391 while( !cam->image_complete ) {
392 if(current->need_resched) schedule();
393
394 new_bytes = cpia_pp_read(cam->port, buffer, block_size );
395 if( new_bytes <= 0 ) {
396 break;
397 }
398 i=-1;
399 while(++i<new_bytes && endseen<4) {
400 if(*buffer==EOI) {
401 endseen++;
402 } else {
403 endseen=0;
404 }
405 buffer++;
406 }
407 read_bytes += i;
408 if( endseen==4 ) {
409 cam->image_complete=1;
410 break;
411 }
412 if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
413 block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
414 }
415 }
416 EndTransferMode(cam);
417 return cam->image_complete ? read_bytes : -EIO;
418 }
419
420 /****************************************************************************
421 *
422 * cpia_pp_transferCmd
423 *
424 ***************************************************************************/
425 static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
426 {
427 int err;
428 int retval=0;
429 int databytes;
430 struct pp_cam_entry *cam = privdata;
431
432 if(cam == NULL) {
433 DBG("Internal driver error: cam is NULL\n");
434 return -EINVAL;
435 }
436 if(command == NULL) {
437 DBG("Internal driver error: command is NULL\n");
438 return -EINVAL;
439 }
440 databytes = (((int)command[7])<<8) | command[6];
441 if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
442 DBG("Error writing command\n");
443 return err;
444 }
445 if(command[0] == DATA_IN) {
446 u8 buffer[8];
447 if(data == NULL) {
448 DBG("Internal driver error: data is NULL\n");
449 return -EINVAL;
450 }
451 if((err = ReadPacket(cam, buffer, 8)) < 0) {
452 return err;
453 DBG("Error reading command result\n");
454 }
455 memcpy(data, buffer, databytes);
456 } else if(command[0] == DATA_OUT) {
457 if(databytes > 0) {
458 if(data == NULL) {
459 DBG("Internal driver error: data is NULL\n");
460 retval = -EINVAL;
461 } else {
462 if((err=WritePacket(cam, data, databytes)) < 0){
463 DBG("Error writing command data\n");
464 return err;
465 }
466 }
467 }
468 } else {
469 DBG("Unexpected first byte of command: %x\n", command[0]);
470 retval = -EINVAL;
471 }
472 return retval;
473 }
474
475 /****************************************************************************
476 *
477 * cpia_pp_open
478 *
479 ***************************************************************************/
480 static int cpia_pp_open(void *privdata)
481 {
482 struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
483
484 if (cam == NULL)
485 return -EINVAL;
486
487 if(cam->open_count == 0) {
488 if (parport_claim(cam->pdev)) {
489 DBG("failed to claim the port\n");
490 return -EBUSY;
491 }
492 parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
493 parport_data_forward(cam->port);
494 parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
495 udelay(50);
496 parport_write_control(cam->port,
497 PARPORT_CONTROL_SELECT
498 | PARPORT_CONTROL_INIT);
499 }
500
501 ++cam->open_count;
502
503 return 0;
504 }
505
506 /****************************************************************************
507 *
508 * cpia_pp_registerCallback
509 *
510 ***************************************************************************/
511 static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
512 {
513 struct pp_cam_entry *cam = privdata;
514 int retval = 0;
515
516 if(cam->port->irq != PARPORT_IRQ_NONE) {
517 cam->cb_task.routine = cb;
518 cam->cb_task.data = cbdata;
519 } else {
520 retval = -1;
521 }
522 return retval;
523 }
524
525 /****************************************************************************
526 *
527 * cpia_pp_close
528 *
529 ***************************************************************************/
530 static int cpia_pp_close(void *privdata)
531 {
532 struct pp_cam_entry *cam = privdata;
533 if (--cam->open_count == 0) {
534 parport_release(cam->pdev);
535 }
536 return 0;
537 }
538
539 /****************************************************************************
540 *
541 * cpia_pp_register
542 *
543 ***************************************************************************/
544 static int cpia_pp_register(struct parport *port)
545 {
546 struct pardevice *pdev = NULL;
547 struct pp_cam_entry *cam;
548 struct cam_data *cpia;
549
550 if (!(port->modes & PARPORT_MODE_ECP) &&
551 !(port->modes & PARPORT_MODE_TRISTATE)) {
552 LOG("port is not ECP capable\n");
553 return -ENXIO;
554 }
555
556 cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
557 if (cam == NULL) {
558 LOG("failed to allocate camera structure\n");
559 return -ENOMEM;
560 }
561 memset(cam,0,sizeof(struct pp_cam_entry));
562
563 pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
564 NULL, 0, cam);
565
566 if (!pdev) {
567 LOG("failed to parport_register_device\n");
568 kfree(cam);
569 return -ENXIO;
570 }
571
572 cam->pdev = pdev;
573 cam->port = port;
574 init_waitqueue_head(&cam->wq_stream);
575
576 cam->streaming = 0;
577 cam->stream_irq = 0;
578
579 if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
580 LOG("failed to cpia_register_camera\n");
581 parport_unregister_device(pdev);
582 kfree(cam);
583 return -ENXIO;
584 }
585 ADD_TO_LIST(cam_list, cpia);
586
587 return 0;
588 }
589
590 static void cpia_pp_detach (struct parport *port)
591 {
592 struct cam_data *cpia;
593
594 for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
595 struct pp_cam_entry *cam = cpia->lowlevel_data;
596 if (cam && cam->port->number == port->number) {
597 REMOVE_FROM_LIST(cpia);
598
599 cpia_unregister_camera(cpia);
600
601 if(cam->open_count > 0) {
602 cpia_pp_close(cam);
603 }
604
605 parport_unregister_device(cam->pdev);
606
607 kfree(cam);
608 cpia->lowlevel_data = NULL;
609 break;
610 }
611 }
612 }
613
614 static void cpia_pp_attach (struct parport *port)
615 {
616 unsigned int i;
617
618 switch (parport_nr[0])
619 {
620 case PPCPIA_PARPORT_UNSPEC:
621 case PPCPIA_PARPORT_AUTO:
622 if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
623 port->probe_info[0].cmdset == NULL ||
624 strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
625 return;
626
627 cpia_pp_register(port);
628
629 break;
630
631 default:
632 for (i = 0; i < PARPORT_MAX; ++i) {
633 if (port->number == parport_nr[i]) {
634 cpia_pp_register(port);
635 break;
636 }
637 }
638 break;
639 }
640 }
641
642 static struct parport_driver cpia_pp_driver = {
643 "cpia_pp",
644 cpia_pp_attach,
645 cpia_pp_detach,
646 NULL
647 };
648
649 int cpia_pp_init(void)
650 {
651 printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
652 CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
653
654 if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
655 printk(" disabled\n");
656 return 0;
657 }
658
659 if (parport_register_driver (&cpia_pp_driver)) {
660 LOG ("unable to register with parport\n");
661 return -EIO;
662 }
663
664 return 0;
665 }
666
667 #ifdef MODULE
668 int init_module(void)
669 {
670 if (parport[0]) {
671 /* The user gave some parameters. Let's see what they were. */
672 if (!strncmp(parport[0], "auto", 4)) {
673 parport_nr[0] = PPCPIA_PARPORT_AUTO;
674 } else {
675 int n;
676 for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
677 if (!strncmp(parport[n], "none", 4)) {
678 parport_nr[n] = PPCPIA_PARPORT_NONE;
679 } else {
680 char *ep;
681 unsigned long r = simple_strtoul(parport[n], &ep, 0);
682 if (ep != parport[n]) {
683 parport_nr[n] = r;
684 } else {
685 LOG("bad port specifier `%s'\n", parport[n]);
686 return -ENODEV;
687 }
688 }
689 }
690 }
691 }
692 #if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)
693 if(parport_enumerate() && !parport_enumerate()->probe_info.model) {
694 request_module("parport_probe");
695 }
696 #endif
697 return cpia_pp_init();
698 }
699
700 void cleanup_module(void)
701 {
702 parport_unregister_driver (&cpia_pp_driver);
703 return;
704 }
705
706 #else /* !MODULE */
707
708 static int __init cpia_pp_setup(char *str)
709 {
710 #if 0
711 /* Is this only a 2.2ism? -jerdfelt */
712 if (!str) {
713 if (ints[0] == 0 || ints[1] == 0) {
714 /* disable driver on "cpia_pp=" or "cpia_pp=0" */
715 parport_nr[0] = PPCPIA_PARPORT_OFF;
716 }
717 } else
718 #endif
719 if (!strncmp(str, "parport", 7)) {
720 int n = simple_strtoul(str + 7, NULL, 10);
721 if (parport_ptr < PARPORT_MAX) {
722 parport_nr[parport_ptr++] = n;
723 } else {
724 LOG("too many ports, %s ignored.\n", str);
725 }
726 } else if (!strcmp(str, "auto")) {
727 parport_nr[0] = PPCPIA_PARPORT_AUTO;
728 } else if (!strcmp(str, "none")) {
729 parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
730 }
731
732 return 0;
733 }
734
735 __setup("cpia_pp=", cpia_pp_setup);
736
737 #endif /* !MODULE */
738