Home | History | Annotate | Line # | Download | only in ppbus
ppbus_base.c revision 1.3
      1 /* $NetBSD: ppbus_base.c,v 1.3 2004/01/22 01:13:21 bjh21 Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  *
     28  * $FreeBSD: src/sys/dev/ppbus/ppb_base.c,v 1.10.2.1 2000/08/01 23:26:26 n_hibma Exp $
     29  *
     30  */
     31 #include "opt_ppbus_1284.h"
     32 #include "opt_ppbus.h"
     33 
     34 #include <sys/param.h>
     35 #include <sys/kernel.h>
     36 #include <sys/malloc.h>
     37 #include <sys/proc.h>
     38 #include <sys/lock.h>
     39 #include <sys/systm.h>
     40 
     41 #include <dev/ppbus/ppbus_1284.h>
     42 #include <dev/ppbus/ppbus_conf.h>
     43 #include <dev/ppbus/ppbus_base.h>
     44 #include <dev/ppbus/ppbus_device.h>
     45 #include <dev/ppbus/ppbus_io.h>
     46 #include <dev/ppbus/ppbus_var.h>
     47 
     48 /* Utility functions */
     49 static char * search_token(char *, int, char *);
     50 
     51 
     52 /* Perform general ppbus I/O request */
     53 int
     54 ppbus_io(struct device * dev, int iop, u_char * addr, int cnt, u_char byte)
     55 {
     56 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     57 	return (bus->ppbus_io(dev->dv_parent, iop, addr, cnt, byte));
     58 }
     59 
     60 /* Execute microsequence */
     61 int
     62 ppbus_exec_microseq(struct device * dev, struct ppbus_microseq ** sequence)
     63 {
     64 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     65 	return (bus->ppbus_exec_microseq(dev->dv_parent, sequence));
     66 }
     67 
     68 /* Read instance variables of ppbus */
     69 int
     70 ppbus_read_ivar(struct device * dev, int index, unsigned int * val)
     71 
     72 {
     73 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     74 
     75 	switch (index) {
     76 	case PPBUS_IVAR_INTR:
     77 	case PPBUS_IVAR_EPP_PROTO:
     78 	case PPBUS_IVAR_DMA:
     79 		return (bus->ppbus_read_ivar(dev->dv_parent, index, val));
     80 
     81 	case PPBUS_IVAR_IEEE:
     82 		*val = (bus->sc_use_ieee == PPBUS_ENABLE_IEEE) ? 1 : 0;
     83 		break;
     84 
     85 	default:
     86 		return (ENOENT);
     87 	}
     88 
     89 	return 0;
     90 }
     91 
     92 /* Write an instance variable */
     93 int
     94 ppbus_write_ivar(struct device * dev, int index, unsigned int * val)
     95 {
     96 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     97 
     98 	switch (index) {
     99 	case PPBUS_IVAR_INTR:
    100 	case PPBUS_IVAR_EPP_PROTO:
    101 	case PPBUS_IVAR_DMA:
    102 		return (bus->ppbus_write_ivar(dev->dv_parent, index, val));
    103 
    104 	case PPBUS_IVAR_IEEE:
    105 		bus->sc_use_ieee = ((*val != 0) ? PPBUS_ENABLE_IEEE :
    106 			PPBUS_DISABLE_IEEE);
    107 		break;
    108 
    109 	default:
    110 		return (ENOENT);
    111 	}
    112 
    113 	return 0;
    114 }
    115 
    116 /* Polls the bus for a max of 10-milliseconds */
    117 int
    118 ppbus_poll_bus(struct device * dev, int max, char mask, char status,
    119 	int how)
    120 {
    121 	int i, j, error;
    122 	char r;
    123 
    124 	/* try at least up to 10ms */
    125 	for (j = 0; j < ((how & PPBUS_POLL) ? max : 1); j++) {
    126 		for (i = 0; i < 10000; i++) {
    127 			r = ppbus_rstr(dev);
    128 			DELAY(1);
    129 			if ((r & mask) == status)
    130 				return (0);
    131 		}
    132 	}
    133 
    134 	if (!(how & PPBUS_POLL)) {
    135 	   for (i = 0; max == PPBUS_FOREVER || i < max-1; i++) {
    136 		if ((ppbus_rstr(dev) & mask) == status)
    137 			return (0);
    138 
    139 		switch (how) {
    140 		case PPBUS_NOINTR:
    141 			/* wait 10 ms */
    142 			tsleep((caddr_t)dev, PPBUSPRI, "ppbuspoll", hz/100);
    143 			break;
    144 
    145 		case PPBUS_INTR:
    146 		default:
    147 			/* wait 10 ms */
    148 			if (((error = tsleep((caddr_t)dev, PPBUSPRI | PCATCH,
    149 			    "ppbuspoll", hz/100)) != EWOULDBLOCK) != 0) {
    150 				return (error);
    151 			}
    152 			break;
    153 		}
    154 	   }
    155 	}
    156 
    157 	return (EWOULDBLOCK);
    158 }
    159 
    160 /* Get operating mode of the chipset */
    161 int
    162 ppbus_get_mode(struct device * dev)
    163 {
    164 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    165 
    166 	return (bus->sc_mode);
    167 }
    168 
    169 /* Set the operating mode of the chipset, return 0 on success. */
    170 int
    171 ppbus_set_mode(struct device * dev, int mode, int options)
    172 {
    173 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    174 	int error = 0;
    175 
    176 	/* If no mode change, do nothing */
    177 	if(bus->sc_mode == mode)
    178 		return error;
    179 
    180 	/* Do necessary negociations */
    181 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    182 		/* Cannot negociate standard mode */
    183 		if(!(mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
    184  			error = ppbus_1284_negociate(dev, mode, options);
    185 		}
    186 		/* Termination is unnecessary for standard<->fast */
    187 		else if(!(bus->sc_mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
    188 			ppbus_1284_terminate(dev);
    189 		}
    190 	}
    191 
    192 	if(!error) {
    193 		/* Set mode and update mode of ppbus to actual mode */
    194 		error = bus->ppbus_setmode(dev->dv_parent, mode);
    195 		bus->sc_mode = bus->ppbus_getmode(dev->dv_parent);
    196 	}
    197 
    198 	/* Update host state if necessary */
    199 	if(!(error) && (bus->sc_use_ieee == PPBUS_ENABLE_IEEE)) {
    200 		switch(mode) {
    201 		case PPBUS_COMPATIBLE:
    202 		case PPBUS_FAST:
    203 		case PPBUS_EPP:
    204 		case PPBUS_ECP:
    205 			ppbus_1284_set_state(dev, PPBUS_FORWARD_IDLE);
    206 			break;
    207 
    208 		case PPBUS_NIBBLE:
    209 		case PPBUS_PS2:
    210 			ppbus_1284_set_state(dev, PPBUS_REVERSE_IDLE);
    211 			break;
    212 		}
    213 	}
    214 
    215 	return error;
    216 }
    217 
    218 /* Write charaters to the port */
    219 int
    220 ppbus_write(struct device * dev, char * buf, int len, int how, size_t * cnt)
    221 {
    222 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    223 
    224 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    225 		if(bus->sc_1284_state != PPBUS_FORWARD_IDLE) {
    226 			printf("%s(%s): bus not in forward idle mode.\n",
    227 				__func__, dev->dv_xname);
    228 			return ENODEV;
    229 		}
    230 	}
    231 
    232 	return (bus->ppbus_write(bus->sc_dev.dv_parent, buf, len, how, cnt));
    233 }
    234 
    235 /* Read charaters from the port */
    236 int
    237 ppbus_read(struct device * dev, char * buf, int len, int how, size_t * cnt)
    238 {
    239 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    240 
    241 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    242 		if(bus->sc_1284_state != PPBUS_REVERSE_IDLE) {
    243 			printf("%s(%s): bus not in reverse idle mode.\n",
    244 				__func__, dev->dv_xname);
    245 			return ENODEV;
    246 		}
    247 	}
    248 
    249 	return (bus->ppbus_read(dev->dv_parent, buf, len, how, cnt));
    250 }
    251 
    252 /* Reset the EPP timeout bit in the status register */
    253 int
    254 ppbus_reset_epp_timeout(struct device * dev)
    255 {
    256 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    257 
    258 	if(bus->sc_capabilities & PPBUS_HAS_EPP) {
    259 		bus->ppbus_reset_epp_timeout(dev->dv_parent);
    260 		return 0;
    261 	}
    262 	else {
    263 		return ENODEV;
    264 	}
    265 }
    266 
    267 /* Wait for the ECP FIFO to be empty */
    268 int
    269 ppbus_ecp_sync(struct device * dev)
    270 {
    271 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    272 
    273 	if(bus->sc_capabilities & PPBUS_HAS_ECP) {
    274 		bus->ppbus_ecp_sync(dev->dv_parent);
    275 		return 0;
    276 	}
    277 	else {
    278 		return ENODEV;
    279 	}
    280 }
    281 
    282 /* Allocate DMA for use with ppbus */
    283 int
    284 ppbus_dma_malloc(struct device * dev, caddr_t * buf, bus_addr_t * addr,
    285 	bus_size_t size)
    286 {
    287 	struct ppbus_softc * ppbus = (struct ppbus_softc *) dev;
    288 
    289 	if(ppbus->sc_capabilities & PPBUS_HAS_DMA)
    290 		return (ppbus->ppbus_dma_malloc(dev->dv_parent, buf, addr,
    291 			size));
    292 	else
    293 		return ENODEV;
    294 }
    295 
    296 /* Free memory allocated with ppbus_dma_malloc() */
    297 int
    298 ppbus_dma_free(struct device * dev, caddr_t * buf, bus_addr_t * addr,
    299 	bus_size_t size)
    300 {
    301 	struct ppbus_softc * ppbus = (struct ppbus_softc *) dev;
    302 
    303 	if(ppbus->sc_capabilities & PPBUS_HAS_DMA) {
    304 		ppbus->ppbus_dma_free(dev->dv_parent, buf, addr, size);
    305 		return 0;
    306 	}
    307 	else {
    308 		return ENODEV;
    309 	}
    310 }
    311 
    312 /* Install a handler to be called by hardware interrupt handler */
    313 int ppbus_add_handler(struct device * dev, void (*func)(void *), void * arg)
    314 {
    315 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    316 
    317 	if(bus->sc_capabilities & PPBUS_HAS_INTR)
    318 		return bus->ppbus_add_handler(dev->dv_parent, func, arg);
    319 	else
    320 		return ENODEV;
    321 }
    322 
    323 /* Remove a handler registered with ppbus_add_handler() */
    324 int ppbus_remove_handler(struct device * dev, void (*func)(void *))
    325 {
    326 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    327 
    328 	if(bus->sc_capabilities & PPBUS_HAS_INTR)
    329 		return bus->ppbus_remove_handler(dev->dv_parent, func);
    330 	else
    331 		return ENODEV;
    332 }
    333 
    334 /*
    335  * ppbus_get_status()
    336  *
    337  * Read the status register and update the status info
    338  */
    339 int
    340 ppbus_get_status(struct device * dev, struct ppbus_status * status)
    341 {
    342 	register char r = status->status = ppbus_rstr(dev);
    343 
    344 	status->timeout	= r & TIMEOUT;
    345 	status->error	= !(r & nFAULT);
    346 	status->select	= r & SELECT;
    347 	status->paper_end = r & PERROR;
    348 	status->ack	= !(r & nACK);
    349 	status->busy	= !(r & nBUSY);
    350 
    351 	return (0);
    352 }
    353 
    354 /* Allocate the device to perform transfers */
    355 int
    356 ppbus_request_bus(struct device * dev, struct device * busdev, int how,
    357 	unsigned int timeout)
    358 {
    359 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    360 	unsigned int counter = timeout;
    361 	int priority = PPBUSPRI;
    362 	int error;
    363 
    364 	if(how & PPBUS_INTR)
    365 		priority |= PCATCH;
    366 
    367 	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
    368 	for(;;) {
    369 		error = lockmgr(&(bus->sc_lock), LK_EXCLUSIVE | LK_RECURSEFAIL,
    370 			NULL);
    371 		if(!error)
    372 			break;
    373 
    374 		if(how & PPBUS_WAIT) {
    375 			error = ltsleep(bus, priority, __func__, hz/2, NULL);
    376 			counter -= (hz/2);
    377 			if(!(error))
    378 				continue;
    379 			else if(error != EWOULDBLOCK)
    380 				goto end;
    381 			if(counter == 0) {
    382 				error = ETIMEDOUT;
    383 				goto end;
    384 			}
    385 		}
    386 		else {
    387 			goto end;
    388 		}
    389 	}
    390 
    391 	/* Set bus owner or return error if bus is taken */
    392 	if(bus->ppbus_owner == NULL) {
    393 		bus->ppbus_owner = busdev;
    394 		error = 0;
    395 	}
    396 	else {
    397 		error = EBUSY;
    398 	}
    399 
    400 	/* Release lock */
    401 	lockmgr(&(bus->sc_lock), LK_RELEASE, NULL);
    402 
    403 end:
    404 	return error;
    405 }
    406 
    407 /* Release the device allocated with ppbus_request_bus() */
    408 int
    409 ppbus_release_bus(struct device * dev, struct device * busdev, int how,
    410 	unsigned int timeout)
    411 {
    412 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    413 	unsigned int counter = timeout;
    414 	int priority = PPBUSPRI;
    415 	int error;
    416 
    417 	if(how & PPBUS_INTR)
    418 		priority |= PCATCH;
    419 
    420 	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
    421 	for(;;) {
    422 		error = lockmgr(&(bus->sc_lock), LK_EXCLUSIVE | LK_RECURSEFAIL,
    423 			NULL);
    424 		if(!error)
    425 			break;
    426 
    427 		if(how & PPBUS_WAIT) {
    428 			error = ltsleep(bus, priority, __func__, hz/2, NULL);
    429 			counter -= (hz/2);
    430 			if(!(error))
    431 				continue;
    432 			else if(error != EWOULDBLOCK)
    433 				goto end;
    434 			if(counter == 0) {
    435 				error = ETIMEDOUT;
    436 				goto end;
    437 			}
    438 		}
    439 		else {
    440 			goto end;
    441 		}
    442 	}
    443 
    444 	/* If the device is the owner, release bus */
    445 	if(bus->ppbus_owner != busdev) {
    446 		error = EINVAL;
    447 	}
    448 	else {
    449 		bus->ppbus_owner = NULL;
    450 		error = 0;
    451 	}
    452 
    453 	/* Release lock */
    454 	lockmgr(&(bus->sc_lock), LK_RELEASE, NULL);
    455 
    456 end:
    457 	return error;
    458 }
    459 
    460 
    461 /* IEEE 1284-based probes */
    462 
    463 #ifndef DONTPROBE_1284
    464 
    465 static char *pnp_tokens[] = {
    466 	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
    467 	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
    468 
    469 /* ??? */
    470 #if 0
    471 static char *pnp_classes[] = {
    472 	"printer", "modem", "network device",
    473 	"hard disk", "PCMCIA", "multimedia device",
    474 	"floppy disk", "ports", "scanner",
    475 	"digital camera", "unknown device", NULL };
    476 #endif
    477 
    478 /*
    479  * Search the first occurence of a token within a string
    480  * XXX should use strxxx() calls
    481  */
    482 static char *
    483 search_token(char *str, int slen, char *token)
    484 {
    485 	char *p;
    486 	int tlen, i, j;
    487 
    488 #define UNKNOWN_LENGTH  -1
    489 
    490 	if (slen == UNKNOWN_LENGTH)
    491 	       /* get string's length */
    492 	       for (slen = 0, p = str; *p != '\0'; p++)
    493 		       slen ++;
    494 
    495        /* get token's length */
    496        for (tlen = 0, p = token; *p != '\0'; p++)
    497 	       tlen ++;
    498 
    499        if (tlen == 0)
    500 	       return (str);
    501 
    502        for (i = 0; i <= slen-tlen; i++) {
    503 	       for (j = 0; j < tlen; j++)
    504 		       if (str[i+j] != token[j])
    505 			       break;
    506 	       if (j == tlen)
    507 		       return (&str[i]);
    508        }
    509 
    510 	return (NULL);
    511 }
    512 
    513 /* Stores the class ID of the peripherial in soft config data */
    514 void
    515 ppbus_pnp_detect(struct device * dev)
    516 {
    517 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    518 	int i;
    519 	int error;
    520 	size_t len = 0;
    521 	size_t str_sz = 0;
    522 	char * str = NULL;
    523 	char * class = NULL;
    524 	char * token;
    525 
    526 #ifdef PPBUS_VERBOSE
    527 	printf("%s: Probing for PnP devices.\n", dev->dv_xname);
    528 #endif
    529 
    530 	error = ppbus_1284_read_id(dev, PPBUS_NIBBLE, &str, &str_sz, &len);
    531 	if(str_sz != len) {
    532 #ifdef DEBUG_1284
    533 		printf("%s(%s): device returned less characters than expected "
    534 			"in device ID.\n", __func__, dev->dv_xname);
    535 #endif
    536 	}
    537 	if(error) {
    538 		printf("%s: Error getting device ID (errno = %d)\n",
    539 			dev->dv_xname, error);
    540 		goto end_detect;
    541 	}
    542 
    543 #ifdef DEBUG_1284
    544 	printf("%s: <PnP> %d characters: ", dev->dv_xname, len);
    545 	for (i = 0; i < len; i++)
    546 		printf("%c(0x%x) ", str[i], str[i]);
    547 	printf("\n");
    548 #endif
    549 
    550 	/* replace ';' characters by '\0' */
    551 	for (i = 0; i < len; i++)
    552 		if(str[i] == ';') str[i] = '\0';
    553 		/* str[i] = (str[i] == ';') ? '\0' : str[i]; */
    554 
    555 	if ((token = search_token(str, len, "MFG")) != NULL ||
    556 		(token = search_token(str, len, "MANUFACTURER")) != NULL)
    557 		printf("%s: <%s", dev->dv_xname,
    558 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    559 	else
    560 		printf("%s: <unknown", dev->dv_xname);
    561 
    562 	if ((token = search_token(str, len, "MDL")) != NULL ||
    563 		(token = search_token(str, len, "MODEL")) != NULL)
    564 		printf(" %s",
    565 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    566 
    567 	if ((token = search_token(str, len, "REV")) != NULL)
    568 		printf(".%s",
    569 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    570 
    571 	printf(">");
    572 
    573 	if ((token = search_token(str, len, "CLS")) != NULL) {
    574 		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
    575 		printf(" %s", class);
    576 	}
    577 
    578 	if ((token = search_token(str, len, "CMD")) != NULL ||
    579 		(token = search_token(str, len, "COMMAND")) != NULL)
    580 		printf(" %s",
    581 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    582 
    583 	printf("\n");
    584 
    585 	if (class) {
    586 		/* identify class ident */
    587 		for (i = 0; pnp_tokens[i] != NULL; i++) {
    588 			if (search_token(class, len, pnp_tokens[i]) != NULL) {
    589 				bus->sc_class_id = i;
    590 				goto end_detect;
    591 			}
    592 		}
    593 	}
    594 	bus->sc_class_id = PPBUS_PNP_UNKNOWN;
    595 
    596 end_detect:
    597 	if(str)
    598 		free(str, M_DEVBUF);
    599         return;
    600 }
    601 
    602 /* Scan the ppbus for IEEE1284 compliant devices */
    603 int
    604 ppbus_scan_bus(struct device * dev)
    605 {
    606 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    607 	int error;
    608 
    609 	/* Try IEEE1284 modes, one device only (no IEEE1284.3 support) */
    610 
    611 	error = ppbus_1284_negociate(dev, PPBUS_NIBBLE, 0);
    612 	if(!(error))
    613 		printf("/NIBBLE");
    614 	else if((bus->sc_1284_state == PPBUS_ERROR) && (bus->sc_1284_error ==
    615 		PPBUS_NOT_IEEE1284))
    616 		goto end_scan;
    617 	ppbus_1284_terminate(dev);
    618 
    619 	error = ppbus_1284_negociate(dev, PPBUS_PS2, 0);
    620 	if(!(error))
    621 		printf("/PS2");
    622 	ppbus_1284_terminate(dev);
    623 
    624 	error = ppbus_1284_negociate(dev, PPBUS_ECP, 0);
    625 	if(!(error))
    626 		printf("/ECP");
    627 	ppbus_1284_terminate(dev);
    628 
    629 	error = ppbus_1284_negociate(dev, PPBUS_ECP, PPBUS_USE_RLE);
    630 	if(!(error))
    631 		printf("/ECP_RLE");
    632 	ppbus_1284_terminate(dev);
    633 
    634 	error = ppbus_1284_negociate(dev, PPBUS_EPP, 0);
    635 	if(!(error))
    636 		printf("/EPP");
    637 	ppbus_1284_terminate(dev);
    638 
    639 	printf("\n");
    640 
    641 	return 0;
    642 
    643 end_scan:
    644 	return error;
    645 }
    646 
    647 #endif /* !DONTPROBE_1284 */
    648 
    649