1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 2006 Marcel Moolenaar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <stand.h>
32#include <string.h>
33#include <sys/disklabel.h>
34#include "bootstrap.h"
35
36#include <efi.h>
37#include <efilib.h>
38
39static int ia64_parsedev(struct devdesc **, const char *, const char **);
40
41/*
42 * Point (dev) at an allocated device specifier for the device matching the
43 * path in (devspec). If it contains an explicit device specification,
44 * use that.  If not, use the default device.
45 */
46int
47ia64_getdev(void **vdev, const char *devspec, const char **path)
48{
49	struct devdesc **dev = (struct devdesc **)vdev;
50	int rv;
51
52	/*
53	 * If it looks like this is just a path and no device, then
54	 * use the current device instead.
55	 */
56	if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) {
57		rv = ia64_parsedev(dev, getenv("currdev"), NULL);
58		if (rv == 0 && path != NULL)
59			*path = devspec;
60		return (rv);
61	}
62
63	/* Parse the device name off the beginning of the devspec. */
64	return (ia64_parsedev(dev, devspec, path));
65}
66
67/*
68 * Point (dev) at an allocated device specifier matching the string version
69 * at the beginning of (devspec).  Return a pointer to the remaining
70 * text in (path).
71 *
72 * In all cases, the beginning of (devspec) is compared to the names
73 * of known devices in the device switch, and then any following text
74 * is parsed according to the rules applied to the device type.
75 *
76 * For disk-type devices, the syntax is:
77 *
78 * fs<unit>:
79 */
80static int
81ia64_parsedev(struct devdesc **dev, const char *devspec, const char **path)
82{
83	struct devdesc *idev;
84	struct devsw *dv;
85	char *cp;
86	const char *np;
87	int i, err;
88
89	/* minimum length check */
90	if (strlen(devspec) < 2)
91		return (EINVAL);
92
93	/* look for a device that matches */
94	for (i = 0; devsw[i] != NULL; i++) {
95		dv = devsw[i];
96		if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
97			break;
98	}
99	if (devsw[i] == NULL)
100		return (ENOENT);
101
102	idev = malloc(sizeof(struct devdesc));
103	if (idev == NULL)
104		return (ENOMEM);
105
106	idev->d_dev = dv;
107	idev->d_type = dv->dv_type;
108	idev->d_unit = -1;
109
110	err = 0;
111	np = devspec + strlen(dv->dv_name);
112	if (*np != '\0' && *np != ':') {
113		idev->d_unit = strtol(np, &cp, 0);
114		if (cp == np) {
115			idev->d_unit = -1;
116			free(idev);
117			return (EUNIT);
118		}
119	}
120	if (*cp != '\0' && *cp != ':') {
121		free(idev);
122		return (EINVAL);
123	}
124
125	if (path != NULL)
126		*path = (*cp == 0) ? cp : cp + 1;
127	if (dev != NULL)
128		*dev = idev;
129	else
130		free(idev);
131	return (0);
132}
133
134char *
135ia64_fmtdev(void *vdev)
136{
137	struct devdesc *dev = (struct devdesc *)vdev;
138	static char buf[32];	/* XXX device length constant? */
139
140	switch(dev->d_type) {
141	case DEVT_NONE:
142		strcpy(buf, "(no device)");
143		break;
144
145	default:
146		sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
147		break;
148	}
149
150	return(buf);
151}
152
153/*
154 * Set currdev to suit the value being supplied in (value)
155 */
156int
157ia64_setcurrdev(struct env_var *ev, int flags, const void *value)
158{
159	struct devdesc *ncurr;
160	int rv;
161
162	rv = ia64_parsedev(&ncurr, value, NULL);
163	if (rv != 0)
164		return(rv);
165
166	free(ncurr);
167	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
168	return (0);
169}
170