1203181Smarcel/*-
2203181Smarcel * Copyright (c) 2010 Marcel Moolenaar
3203181Smarcel * All rights reserved.
4203181Smarcel *
5203181Smarcel * Redistribution and use in source and binary forms, with or without
6203181Smarcel * modification, are permitted provided that the following conditions
7203181Smarcel * are met:
8203181Smarcel * 1. Redistributions of source code must retain the above copyright
9203181Smarcel *    notice, this list of conditions and the following disclaimer.
10203181Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11203181Smarcel *    notice, this list of conditions and the following disclaimer in the
12203181Smarcel *    documentation and/or other materials provided with the distribution.
13203181Smarcel *
14203181Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15203181Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16203181Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17203181Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18203181Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19203181Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20203181Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21203181Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22203181Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23203181Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24203181Smarcel * SUCH DAMAGE.
25203181Smarcel */
26203181Smarcel
27203181Smarcel#include <sys/cdefs.h>
28203181Smarcel__FBSDID("$FreeBSD$");
29203181Smarcel
30203181Smarcel#include <sys/ioctl.h>
31203181Smarcel#include <sys/types.h>
32203181Smarcel#include <fcntl.h>
33203181Smarcel#include <stddef.h>
34203181Smarcel#include <stdlib.h>
35203181Smarcel#include <string.h>
36203181Smarcel#include <unistd.h>
37203181Smarcel
38203181Smarcel#include "libefi_int.h"
39203181Smarcel
40203181Smarcelstatic int __iofd = -1;
41203181Smarcel
42203181Smarcelstatic void
43203181Smarceliodev_fd_close(void)
44203181Smarcel{
45203181Smarcel
46203181Smarcel	close(__iofd);
47203181Smarcel}
48203181Smarcel
49203181Smarcelstatic int
50203181Smarceliodev_fd(int *fd)
51203181Smarcel{
52203181Smarcel
53203181Smarcel	*fd = __iofd;
54203181Smarcel	if (__iofd != -1)
55203181Smarcel		return (0);
56203181Smarcel
57203181Smarcel	__iofd = open("/dev/io", O_RDWR);
58203181Smarcel	if (__iofd == -1)
59203181Smarcel		return (errno);
60203181Smarcel
61203181Smarcel	atexit(iodev_fd_close);
62203181Smarcel	*fd = __iofd;
63203181Smarcel	return (0);
64203181Smarcel}
65203181Smarcel
66203181Smarcelint
67203181Smarcellibefi_ucs2_to_utf8(u_short *nm, size_t *szp, char *name)
68203181Smarcel{
69203181Smarcel	size_t len, sz;
70203181Smarcel	u_short c;
71203181Smarcel
72203181Smarcel	len = 0;
73203181Smarcel	sz = *szp;
74203181Smarcel	while (*nm) {
75203181Smarcel		c = *nm++;
76203181Smarcel		if (c > 0x7ff) {
77203181Smarcel			if (len++ < sz)
78203181Smarcel				*name++ = 0xE0 | (c >> 12);
79203181Smarcel			if (len++ < sz)
80203181Smarcel				*name++ = 0x80 | ((c >> 6) & 0x3f);
81203181Smarcel			if (len++ < sz)
82203181Smarcel				*name++ = 0x80 | (c & 0x3f);
83203181Smarcel		} else if (c > 0x7f) {
84203181Smarcel			if (len++ < sz)
85203181Smarcel				*name++ = 0xC0 | ((c >> 6) & 0x1f);
86203181Smarcel			if (len++ < sz)
87203181Smarcel				*name++ = 0x80 | (c & 0x3f);
88203181Smarcel		} else {
89203181Smarcel			if (len++ < sz)
90203181Smarcel				*name++ = (c & 0x7f);
91203181Smarcel		}
92203181Smarcel	}
93203181Smarcel	if (len++ < sz)
94203181Smarcel		*name++ = 0;
95203181Smarcel
96203181Smarcel	*szp = len;
97203181Smarcel	return ((len <= sz) ? 0 : EOVERFLOW);
98203181Smarcel}
99203181Smarcel
100203181Smarcelint
101203181Smarcellibefi_utf8_to_ucs2(char *name, size_t *szp, u_short **nmp)
102203181Smarcel{
103203181Smarcel	u_short *nm;
104203181Smarcel	size_t sz;
105203181Smarcel	uint32_t ucs4;
106203181Smarcel	int c, bytes;
107203181Smarcel
108203181Smarcel	*szp = sz = (*szp == 0) ? strlen(name) * 2 + 2 : *szp;
109203181Smarcel	*nmp = nm = malloc(sz);
110203181Smarcel
111203181Smarcel	ucs4 = 0;
112203181Smarcel	bytes = 0;
113203181Smarcel	while (sz > 1 && *name != '\0') {
114203181Smarcel		c = *name++;
115203181Smarcel		/*
116203181Smarcel		 * Conditionalize on the two major character types:
117203181Smarcel		 * initial and followup characters.
118203181Smarcel		 */
119203181Smarcel		if ((c & 0xc0) != 0x80) {
120203181Smarcel			/* Initial characters. */
121203181Smarcel			if (bytes != 0) {
122203181Smarcel				free(nm);
123203181Smarcel				return (EILSEQ);
124203181Smarcel			}
125203181Smarcel			if ((c & 0xf8) == 0xf0) {
126203181Smarcel				ucs4 = c & 0x07;
127203181Smarcel				bytes = 3;
128203181Smarcel			} else if ((c & 0xf0) == 0xe0) {
129203181Smarcel				ucs4 = c & 0x0f;
130203181Smarcel				bytes = 2;
131203181Smarcel			} else if ((c & 0xe0) == 0xc0) {
132203181Smarcel				ucs4 = c & 0x1f;
133203181Smarcel				bytes = 1;
134203181Smarcel			} else {
135203181Smarcel				ucs4 = c & 0x7f;
136203181Smarcel				bytes = 0;
137203181Smarcel			}
138203181Smarcel		} else {
139203181Smarcel			/* Followup characters. */
140203181Smarcel			if (bytes > 0) {
141203181Smarcel				ucs4 = (ucs4 << 6) + (c & 0x3f);
142203181Smarcel				bytes--;
143203181Smarcel			} else if (bytes == 0) {
144203181Smarcel				free(nm);
145203181Smarcel				return (EILSEQ);
146203181Smarcel			}
147203181Smarcel		}
148203181Smarcel		if (bytes == 0) {
149203181Smarcel			if (ucs4 > 0xffff) {
150203181Smarcel				free(nm);
151203181Smarcel				return (EILSEQ);
152203181Smarcel			}
153203181Smarcel			*nm++ = (u_short)ucs4;
154203181Smarcel			sz -= 2;
155203181Smarcel		}
156203181Smarcel	}
157203181Smarcel	if (sz < 2) {
158203181Smarcel		free(nm);
159203181Smarcel		return (EDOOFUS);
160203181Smarcel	}
161203181Smarcel	*nm = 0;
162203181Smarcel	return (0);
163203181Smarcel}
164203181Smarcel
165203181Smarcelint
166203181Smarcellibefi_efivar(struct iodev_efivar_req *req)
167203181Smarcel{
168203181Smarcel	int error, fd;
169203181Smarcel
170203181Smarcel	error = iodev_fd(&fd);
171203181Smarcel	if (!error)
172203181Smarcel		error = (ioctl(fd, IODEV_EFIVAR, req) == -1) ? errno : 0;
173203181Smarcel	if (!error)
174203181Smarcel		error = req->result;
175203181Smarcel	return (error);
176203181Smarcel}
177