devicename.c revision 68548
138465Smsmith/*-
238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
338465Smsmith * All rights reserved.
438465Smsmith *
538465Smsmith * Redistribution and use in source and binary forms, with or without
638465Smsmith * modification, are permitted provided that the following conditions
738465Smsmith * are met:
838465Smsmith * 1. Redistributions of source code must retain the above copyright
938465Smsmith *    notice, this list of conditions and the following disclaimer.
1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138465Smsmith *    notice, this list of conditions and the following disclaimer in the
1238465Smsmith *    documentation and/or other materials provided with the distribution.
1338465Smsmith *
1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738465Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438465Smsmith * SUCH DAMAGE.
2538465Smsmith *
2650477Speter * $FreeBSD: head/sys/boot/ofw/libofw/devicename.c 68548 2000-11-10 06:39:58Z benno $
2738465Smsmith */
2838465Smsmith
2938465Smsmith#include <stand.h>
3038465Smsmith#include <sys/disklabel.h>
3167227Sobrien#include "libofw.h"
3238465Smsmith
3367227Sobrienstatic int	ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
3438465Smsmith
3538465Smsmith/*
3638465Smsmith * Point (dev) at an allocated device specifier for the device matching the
3738465Smsmith * path in (devspec). If it contains an explicit device specification,
3838465Smsmith * use that.  If not, use the default device.
3938465Smsmith */
4038465Smsmithint
4167227Sobrienofw_getdev(void **vdev, const char *devspec, const char **path)
4238465Smsmith{
4367227Sobrien    struct ofw_devdesc **dev = (struct ofw_devdesc **)vdev;
4438465Smsmith    int				rv;
4538465Smsmith
4638465Smsmith    /*
4738465Smsmith     * If it looks like this is just a path and no
4838465Smsmith     * device, go with the current device.
4938465Smsmith     */
5038465Smsmith    if ((devspec == NULL) ||
5138465Smsmith	(devspec[0] == '/') ||
5238465Smsmith	(strchr(devspec, ':') == NULL)) {
5338465Smsmith
5467227Sobrien	if (((rv = ofw_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
5538465Smsmith	    (path != NULL))
5638465Smsmith		*path = devspec;
5738465Smsmith	return(rv);
5838465Smsmith    }
5938465Smsmith
6038465Smsmith    /*
6138465Smsmith     * Try to parse the device name off the beginning of the devspec
6238465Smsmith     */
6367227Sobrien    return(ofw_parsedev(dev, devspec, path));
6438465Smsmith}
6538465Smsmith
6638465Smsmith/*
6738465Smsmith * Point (dev) at an allocated device specifier matching the string version
6838465Smsmith * at the beginning of (devspec).  Return a pointer to the remaining
6938465Smsmith * text in (path).
7038465Smsmith *
7138465Smsmith * In all cases, the beginning of (devspec) is compared to the names
7238465Smsmith * of known devices in the device switch, and then any following text
7338465Smsmith * is parsed according to the rules applied to the device type.
7438465Smsmith *
7538465Smsmith * For disk-type devices, the syntax is:
7638465Smsmith *
7738465Smsmith * disk<unit>[s<slice>][<partition>]:
7838465Smsmith *
7938465Smsmith */
8038465Smsmithstatic int
8167227Sobrienofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path)
8238465Smsmith{
8367227Sobrien    struct ofw_devdesc *idev;
8438465Smsmith    struct devsw	*dv;
8538465Smsmith    int			i, unit, slice, partition, err;
8639673Sdfr    char		*cp;
8739673Sdfr    const char		*np;
8838465Smsmith
8938465Smsmith    /* minimum length check */
9038465Smsmith    if (strlen(devspec) < 2)
9138465Smsmith	return(EINVAL);
9238465Smsmith
9338465Smsmith    /* look for a device that matches */
9438465Smsmith    for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
9538465Smsmith	if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
9638465Smsmith	    dv = devsw[i];
9738465Smsmith	    break;
9838465Smsmith	}
9938465Smsmith    }
10038465Smsmith
10138465Smsmith    if (dv == NULL)
10238465Smsmith	return(ENOENT);
10367227Sobrien    idev = malloc(sizeof(struct ofw_devdesc));
10438465Smsmith    err = 0;
10538465Smsmith    np = (devspec + strlen(dv->dv_name));
10638465Smsmith
10738465Smsmith    switch(dv->dv_type) {
10838465Smsmith    case DEVT_NONE:			/* XXX what to do here?  Do we care? */
10938465Smsmith	break;
11038465Smsmith
11138465Smsmith    case DEVT_DISK:
11238465Smsmith	unit = -1;
11338465Smsmith	slice = -1;
11438465Smsmith	partition = -1;
11538465Smsmith	if (*np && (*np != ':')) {
11638465Smsmith	    unit = strtol(np, &cp, 10);	/* next comes the unit number */
11738465Smsmith	    if (cp == np) {
11838465Smsmith		err = EUNIT;
11938465Smsmith		goto fail;
12038465Smsmith	    }
12138465Smsmith	    if (*cp == 's') {		/* got a slice number */
12238465Smsmith		np = cp + 1;
12338465Smsmith		slice = strtol(np, &cp, 10);
12438465Smsmith		if (cp == np) {
12538465Smsmith		    err = ESLICE;
12638465Smsmith		    goto fail;
12738465Smsmith		}
12838465Smsmith	    }
12938465Smsmith	    if (*cp && (*cp != ':')) {
13038465Smsmith		partition = *cp - 'a';		/* get a partition number */
13138465Smsmith		if ((partition < 0) || (partition >= MAXPARTITIONS)) {
13238465Smsmith		    err = EPART;
13338465Smsmith		    goto fail;
13438465Smsmith		}
13538465Smsmith		cp++;
13638465Smsmith	    }
13738465Smsmith	}
13838465Smsmith	if (*cp && (*cp != ':')) {
13938465Smsmith	    err = EINVAL;
14038465Smsmith	    goto fail;
14138465Smsmith	}
14238465Smsmith
14367227Sobrien	idev->d_kind.ofwdisk.unit = unit;
14467227Sobrien	idev->d_kind.ofwdisk.slice = slice;
14567227Sobrien	idev->d_kind.ofwdisk.partition = partition;
14638465Smsmith	if (path != NULL)
14738465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
14838465Smsmith	break;
14938465Smsmith
15038465Smsmith    case DEVT_NET:
15138465Smsmith	unit = 0;
15238465Smsmith
15338465Smsmith	if (*np && (*np != ':')) {
15438465Smsmith	    unit = strtol(np, &cp, 0);	/* get unit number if present */
15538465Smsmith	    if (cp == np) {
15638465Smsmith		err = EUNIT;
15738465Smsmith		goto fail;
15838465Smsmith	    }
15938465Smsmith	}
16038465Smsmith	if (*cp && (*cp != ':')) {
16138465Smsmith	    err = EINVAL;
16238465Smsmith	    goto fail;
16338465Smsmith	}
16438465Smsmith
16538465Smsmith	idev->d_kind.netif.unit = unit;
16638465Smsmith	if (path != NULL)
16738465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
16838465Smsmith	break;
16938465Smsmith
17038465Smsmith    default:
17138465Smsmith	err = EINVAL;
17238465Smsmith	goto fail;
17338465Smsmith    }
17438465Smsmith    idev->d_dev = dv;
17538465Smsmith    idev->d_type = dv->dv_type;
17638475Sdfr    if (dev == NULL) {
17738475Sdfr	free(idev);
17838475Sdfr    } else {
17938465Smsmith	*dev = idev;
18038475Sdfr    }
18138465Smsmith    return(0);
18238465Smsmith
18338465Smsmith fail:
18438465Smsmith    free(idev);
18538465Smsmith    return(err);
18638465Smsmith}
18768548Sbenno
18868548Sbennochar *
18968548Sbennoofw_fmtdev(void *vdev)
19068548Sbenno{
19168548Sbenno	struct ofw_devdesc	*dev = (struct ofw_devdesc *)vdev;
19268548Sbenno	static char		buf[128];
19368548Sbenno	char			*cp;
19468548Sbenno
19568548Sbenno	switch(dev->d_type) {
19668548Sbenno	case DEVT_NONE:
19768548Sbenno		strcpy(buf, "(no device)");
19868548Sbenno		break;
19968548Sbenno
20068548Sbenno	case DEVT_DISK:
20168548Sbenno		/* XXX Insert stuff here */
20268548Sbenno		sprintf(buf, "%s%d:", dev->d_dev->dv_name,
20368548Sbenno		    dev->d_kind.ofwdisk.unit);
20468548Sbenno		break;
20568548Sbenno
20668548Sbenno	case DEVT_NET:
20768548Sbenno		sprintf(buf, "%s%d:", dev->d_dev->dv_name,
20868548Sbenno		    dev->d_kind.netif.unit);
20968548Sbenno		break;
21068548Sbenno	}
21168548Sbenno
21268548Sbenno	return buf;
21368548Sbenno}
21468548Sbenno
21568548Sbennoint
21668548Sbennoofw_setcurrdev(struct env_var *ev, int flags, void *value)
21768548Sbenno{
21868548Sbenno	struct ofw_devdesc	*ncurr;
21968548Sbenno	int			rv;
22068548Sbenno
22168548Sbenno	if ((rv = ofw_parsedev(&ncurr, value, NULL)) != 0)
22268548Sbenno		return rv;
22368548Sbenno
22468548Sbenno	free(ncurr);
22568548Sbenno	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
22668548Sbenno	return 0;
22768548Sbenno}
228