aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ppbus/ppbconf.c
diff options
context:
space:
mode:
authorMike Smith <msmith@FreeBSD.org>1997-08-16 14:05:38 +0000
committerMike Smith <msmith@FreeBSD.org>1997-08-16 14:05:38 +0000
commite51b0386a671abbf7a2075a7db6c3d8b62af021f (patch)
tree18caa70f9a80a6053b497d8086be381c253c127e /sys/dev/ppbus/ppbconf.c
parent22526298add6ec50bb8dd3c428f2527e6b9b65b0 (diff)
downloadsrc-e51b0386a671abbf7a2075a7db6c3d8b62af021f.tar.gz
src-e51b0386a671abbf7a2075a7db6c3d8b62af021f.zip
Sync with ppbus-970815 from the author :
- interrupt-driven printing now works (nlpt) - Rearrangement of bus-related functions into ppb_base/ppbconf - Addition of ieee1284 interface functions, preliminary parallel-port PnP support Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
Notes
Notes: svn path=/head/; revision=28257
Diffstat (limited to 'sys/dev/ppbus/ppbconf.c')
-rw-r--r--sys/dev/ppbus/ppbconf.c381
1 files changed, 230 insertions, 151 deletions
diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c
index 5d2bc452203e..b72012c7778a 100644
--- a/sys/dev/ppbus/ppbconf.c
+++ b/sys/dev/ppbus/ppbconf.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: ppbconf.c,v 1.1 1997/08/14 13:57:41 msmith Exp $
*
*/
#include <sys/param.h>
@@ -48,6 +48,7 @@
#include <i386/isa/isa_device.h>
#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_1284.h>
LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
@@ -62,11 +63,6 @@ DATA_SET(ppbdriver_set, nulldriver);
/*
- * Parallel Port Bus sleep/wakeup queue.
- */
-#define PRIPPB 28 /* PSOCK < PRIPPB < PWAIT XXX */
-
-/*
* ppb_alloc_bus()
*
* Allocate area to store the ppbus description.
@@ -98,6 +94,159 @@ ppb_alloc_bus(void)
return(ppb);
}
+static char *pnp_tokens[] = {
+ "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
+ "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
+
+static char *pnp_classes[] = {
+ "printer", "modem", "network device",
+ "hard disk", "PCMCIA", "multimedia device",
+ "floppy disk", "ports", "scanner",
+ "digital camera", "unknown device", NULL };
+
+/*
+ * search_token()
+ *
+ * Search the first occurence of a token within a string
+ */
+static char *
+search_token(char *str, int slen, char *token)
+{
+ char *p;
+ int tlen, i, j;
+
+#define UNKNOWN_LENGTH -1
+
+ if (slen == UNKNOWN_LENGTH)
+ /* get string's length */
+ for (slen = 0, p = str; *p != '\0'; p++)
+ slen ++;
+
+ /* get token's length */
+ for (tlen = 0, p = token; *p != '\0'; p++)
+ tlen ++;
+
+ if (tlen == 0)
+ return (str);
+
+ for (i = 0; i <= slen-tlen; i++) {
+ for (j = 0; j < tlen; j++)
+ if (str[i+j] != token[j])
+ break;
+ if (j == tlen)
+ return (&str[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * ppb_pnp_detect()
+ *
+ * Returns the class id. of the peripherial, -1 otherwise
+ */
+static int
+ppb_pnp_detect(struct ppb_data *ppb)
+{
+ char *token, *q, *class = 0;
+ int i, len, error;
+ char str[PPB_PnP_STRING_SIZE+1];
+
+ struct ppb_device pnpdev; /* temporary device to perform I/O */
+
+ /* initialize the pnpdev structure for future use */
+ bzero(&pnpdev, sizeof(pnpdev));
+
+ pnpdev.ppb = ppb;
+
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> probing PnP devices on ppbus%d...\n",
+ ppb->ppb_link->adapter_unit);
+#endif
+
+ ppb_wctr(&pnpdev, nINIT | SELECTIN);
+
+ /* select NIBBLE_1284_REQUEST_ID mode */
+ if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) {
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> nibble_1284_mode()=%d\n", error);
+#endif
+ return (-1);
+ }
+
+ len = 0;
+ for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) {
+ if ((error = nibble_1284_inbyte(&pnpdev, q))) {
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error);
+#endif
+ return (-1);
+ }
+ if (len++ >= PPB_PnP_STRING_SIZE) {
+ printf("ppb: <PnP> not space left!\n");
+ return (-1);
+ }
+ }
+ *q = '\0';
+
+ nibble_1284_sync(&pnpdev);
+
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> %d characters: ", len);
+ for (i = 0; i < len; i++)
+ printf("0x%x ", str[i]);
+ printf("\n");
+#endif
+
+ /* replace ';' characters by '\0' */
+ for (i = 0; i < len; i++)
+ str[i] = (str[i] == ';') ? '\0' : str[i];
+
+ if ((token = search_token(str, len, "MFG")) != NULL)
+ printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+ else
+ printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
+
+ if ((token = search_token(str, len, "MDL")) != NULL)
+ printf(" %s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+ else
+ printf(" unknown");
+
+ if ((token = search_token(str, len, "VER")) != NULL)
+ printf("/%s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ if ((token = search_token(str, len, "REV")) != NULL)
+ printf(".%s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ printf(">");
+
+ if ((token = search_token(str, len, "CLS")) != NULL) {
+ class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
+ printf(" %s", class);
+ }
+
+ if ((token = search_token(str, len, "CMD")) != NULL)
+ printf(" %s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ printf("\n");
+
+ if (class)
+ /* identify class ident */
+ for (i = 0; pnp_tokens[i] != NULL; i++) {
+ if (search_token(class, len, pnp_tokens[i]) != NULL) {
+ return (i);
+ break;
+ }
+ }
+
+ return (PPB_PnP_UNKNOWN);
+}
+
/*
* ppb_attachdevs()
*
@@ -110,9 +259,12 @@ ppb_attachdevs(struct ppb_data *ppb)
int error;
struct ppb_device *dev;
struct ppb_driver **p_drvpp, *p_drvp;
-
+
LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */
p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
+
+ /* detect PnP devices */
+ ppb->class_id = ppb_pnp_detect(ppb);
/*
* Blindly try all probes here. Later we should look at
@@ -134,206 +286,133 @@ ppb_attachdevs(struct ppb_data *ppb)
}
/*
- * ppb_request_bus()
+ * ppb_next_bus()
*
- * Allocate the device to perform transfers.
- *
- * how : PPB_WAIT or PPB_DONTWAIT
+ * Return the next bus in ppbus queue
*/
-int
-ppb_request_bus(struct ppb_device *dev, int how)
+struct ppb_data *
+ppb_next_bus(struct ppb_data *ppb)
{
- int s, error = 0;
- struct ppb_data *ppb = dev->ppb;
- /*
- * During initialisation, ppb is null.
- */
- if (!ppb)
- return (0);
+ if (ppb == NULL)
+ return (ppbdata.lh_first);
- while (error != EINTR) {
- s = splhigh();
- if (ppb->ppb_owner) {
- splx(s);
-
- switch (how) {
- case (PPB_WAIT | PPB_INTR):
-
- error = tsleep(ppb, PRIPPB | PCATCH,
- "ppbreq", 0);
- break;
- case (PPB_WAIT):
- error = tsleep(ppb, PRIPPB, "ppbreq", 0);
- break;
- default:
- return EWOULDBLOCK;
- break;
- }
+ return (ppb->ppb_chain.le_next);
+}
- } else {
- ppb->ppb_owner = dev;
+/*
+ * ppb_lookup_bus()
+ *
+ * Get ppb_data structure pointer according to the base address of the ppbus
+ */
+struct ppb_data *
+ppb_lookup_bus(int base_port)
+{
+ struct ppb_data *ppb;
- splx(s);
- return (0);
- }
- }
+ for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
+ if (ppb->ppb_link->base == base_port)
+ break;
- return (EINTR);
+ return (ppb);
}
/*
- * ppb_release_bus()
+ * ppb_attach_device()
*
- * Release the device allocated with ppb_request_dev()
+ * Called by loadable kernel modules to add a device
*/
int
-ppb_release_bus(struct ppb_device *dev)
+ppb_attach_device(struct ppb_device *dev)
{
- int s;
struct ppb_data *ppb = dev->ppb;
- /*
- * During initialisation, ppb is null.
- */
- if (!ppb)
- return (0);
-
- s = splhigh();
- if (ppb->ppb_owner != dev) {
- splx(s);
- return (EACCES);
- }
-
- ppb->ppb_owner = 0;
- splx(s);
-
- /*
- * Wakeup waiting processes.
- */
- wakeup(ppb);
+ /* add the device to the list of probed devices */
+ LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
return (0);
}
/*
- * ppb_intr()
+ * ppb_remove_device()
*
- * Function called by ppcintr() when an intr occurs.
+ * Called by loadable kernel modules to remove a device
*/
void
-ppb_intr(struct ppb_link *pl)
+ppb_remove_device(struct ppb_device *dev)
{
- struct ppb_data *ppb = pl->ppbus;
- /*
- * Call chipset dependent code.
- * Should be filled at chipset initialisation if needed.
- */
- if (pl->adapter->intr_handler)
- (*pl->adapter->intr_handler)(pl->adapter_unit);
-
- /*
- * Call upper handler iff the bus is owned by a device and
- * this device has specified an interrupt handler.
- */
- if (ppb->ppb_owner && ppb->ppb_owner->intr)
- (*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit);
+ /* remove the device from the list of probed devices */
+ LIST_REMOVE(dev, chain);
return;
}
/*
- * ppb_reset_epp_timeout()
+ * ppb_request_bus()
*
- * Reset the EPP timeout bit in the status register.
- */
-int
-ppb_reset_epp_timeout(struct ppb_device *dev)
-{
- struct ppb_data *ppb = dev->ppb;
-
- if (ppb->ppb_owner != dev)
- return (EACCES);
-
- (*ppb->ppb_link->adapter->reset_epp_timeout)(dev->id_unit);
-
- return (0);
-}
-
-/*
- * ppb_ecp_sync()
+ * Allocate the device to perform transfers.
*
- * Wait for the ECP FIFO to be empty.
+ * how : PPB_WAIT or PPB_DONTWAIT
*/
int
-ppb_ecp_sync(struct ppb_device *dev)
+ppb_request_bus(struct ppb_device *dev, int how)
{
+ int s, error = 0;
struct ppb_data *ppb = dev->ppb;
- if (ppb->ppb_owner != dev)
- return (EACCES);
+ while (!error) {
+ s = splhigh();
+ if (ppb->ppb_owner) {
+ splx(s);
- (*ppb->ppb_link->adapter->ecp_sync)(dev->id_unit);
+ switch (how) {
+ case (PPB_WAIT | PPB_INTR):
+ error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
+ break;
- return (0);
-}
+ case (PPB_WAIT | PPB_NOINTR):
+ error = tsleep(ppb, PPBPRI, "ppbreq", 0);
+ break;
-/*
- * ppb_get_mode()
- *
- * Read the mode (SPP, EPP...) of the chipset.
- */
-int
-ppb_get_mode(struct ppb_device *dev)
-{
- return (dev->ppb->ppb_link->mode);
-}
+ default:
+ return (EWOULDBLOCK);
+ break;
+ }
-/*
- * ppb_get_epp_protocol()
- *
- * Read the EPP protocol (1.9 or 1.7).
- */
-int
-ppb_get_epp_protocol(struct ppb_device *dev)
-{
- return (dev->ppb->ppb_link->epp_protocol);
-}
+ } else {
+ ppb->ppb_owner = dev;
-/*
- * ppb_get_irq()
- *
- * Return the irq, 0 if none.
- */
-int
-ppb_get_irq(struct ppb_device *dev)
-{
- return (dev->ppb->ppb_link->id_irq);
+ splx(s);
+ return (0);
+ }
+ }
+
+ return (error);
}
/*
- * ppb_get_status()
+ * ppb_release_bus()
*
- * Read the status register and update the status info.
+ * Release the device allocated with ppb_request_dev()
*/
int
-ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
+ppb_release_bus(struct ppb_device *dev)
{
+ int s;
struct ppb_data *ppb = dev->ppb;
- register char r;
- if (ppb->ppb_owner != dev)
+ s = splhigh();
+ if (ppb->ppb_owner != dev) {
+ splx(s);
return (EACCES);
+ }
- r = status->status = ppb_rstr(dev);
+ ppb->ppb_owner = 0;
+ splx(s);
- status->timeout = r & TIMEOUT;
- status->error = !(r & nFAULT);
- status->select = r & SELECT;
- status->paper_end = r & ERROR;
- status->ack = !(r & nACK);
- status->busy = !(r & nBUSY);
+ /* wakeup waiting processes */
+ wakeup(ppb);
return (0);
}