18ab2f5ecSMark Murray /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
48ab2f5ecSMark Murray * Copyright (c) 2004 Mark R V Murray
58ab2f5ecSMark Murray * All rights reserved.
68ab2f5ecSMark Murray *
78ab2f5ecSMark Murray * Redistribution and use in source and binary forms, with or without
88ab2f5ecSMark Murray * modification, are permitted provided that the following conditions
98ab2f5ecSMark Murray * are met:
108ab2f5ecSMark Murray * 1. Redistributions of source code must retain the above copyright
118ab2f5ecSMark Murray * notice, this list of conditions and the following disclaimer
128ab2f5ecSMark Murray * in this position and unchanged.
138ab2f5ecSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
148ab2f5ecSMark Murray * notice, this list of conditions and the following disclaimer in the
158ab2f5ecSMark Murray * documentation and/or other materials provided with the distribution.
168ab2f5ecSMark Murray *
178ab2f5ecSMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
188ab2f5ecSMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198ab2f5ecSMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208ab2f5ecSMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218ab2f5ecSMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228ab2f5ecSMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238ab2f5ecSMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248ab2f5ecSMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258ab2f5ecSMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268ab2f5ecSMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278ab2f5ecSMark Murray *
288ab2f5ecSMark Murray */
298ab2f5ecSMark Murray
308ab2f5ecSMark Murray #include <sys/param.h>
318ab2f5ecSMark Murray #include <sys/conf.h>
328ab2f5ecSMark Murray #include <sys/kernel.h>
33d8b87887SAttilio Rao #include <sys/ioccom.h>
348ab2f5ecSMark Murray #include <sys/module.h>
35d8b87887SAttilio Rao #include <sys/priv.h>
368ab2f5ecSMark Murray #include <sys/proc.h>
378ab2f5ecSMark Murray #include <sys/systm.h>
388ab2f5ecSMark Murray
398ab2f5ecSMark Murray #include <machine/iodev.h>
408ab2f5ecSMark Murray
41d8b87887SAttilio Rao #include <dev/io/iodev.h>
42d8b87887SAttilio Rao
43d8b87887SAttilio Rao static int ioopen(struct cdev *dev, int flags, int fmt,
44d8b87887SAttilio Rao struct thread *td);
45d8b87887SAttilio Rao static int ioclose(struct cdev *dev, int flags, int fmt,
46d8b87887SAttilio Rao struct thread *td);
47d8b87887SAttilio Rao static int ioioctl(struct cdev *dev, u_long cmd, caddr_t data,
48d8b87887SAttilio Rao int fflag, struct thread *td);
49d8b87887SAttilio Rao
50d8b87887SAttilio Rao static int iopio_read(struct iodev_pio_req *req);
51d8b87887SAttilio Rao static int iopio_write(struct iodev_pio_req *req);
52d8b87887SAttilio Rao
538ab2f5ecSMark Murray static struct cdev *iodev;
548ab2f5ecSMark Murray
558ab2f5ecSMark Murray static struct cdevsw io_cdevsw = {
568ab2f5ecSMark Murray .d_version = D_VERSION,
578ab2f5ecSMark Murray .d_open = ioopen,
588ab2f5ecSMark Murray .d_close = ioclose,
59409a390cSMarcel Moolenaar .d_ioctl = ioioctl,
608ab2f5ecSMark Murray .d_name = "io",
618ab2f5ecSMark Murray };
628ab2f5ecSMark Murray
638ab2f5ecSMark Murray /* ARGSUSED */
648ab2f5ecSMark Murray static int
ioopen(struct cdev * dev __unused,int flags __unused,int fmt __unused,struct thread * td)65d8b87887SAttilio Rao ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused,
66d8b87887SAttilio Rao struct thread *td)
67d8b87887SAttilio Rao {
68d8b87887SAttilio Rao int error;
69d8b87887SAttilio Rao
70d8b87887SAttilio Rao error = priv_check(td, PRIV_IO);
71d8b87887SAttilio Rao if (error != 0)
72d8b87887SAttilio Rao return (error);
73d8b87887SAttilio Rao error = securelevel_gt(td->td_ucred, 0);
74d8b87887SAttilio Rao if (error != 0)
75d8b87887SAttilio Rao return (error);
76d8b87887SAttilio Rao error = iodev_open(td);
77d8b87887SAttilio Rao
78d8b87887SAttilio Rao return (error);
79d8b87887SAttilio Rao }
80d8b87887SAttilio Rao
81d8b87887SAttilio Rao /* ARGSUSED */
82d8b87887SAttilio Rao static int
ioclose(struct cdev * dev __unused,int flags __unused,int fmt __unused,struct thread * td)83d8b87887SAttilio Rao ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused,
84d8b87887SAttilio Rao struct thread *td)
85d8b87887SAttilio Rao {
86d8b87887SAttilio Rao
87d8b87887SAttilio Rao return (iodev_close(td));
88d8b87887SAttilio Rao }
89d8b87887SAttilio Rao
90d8b87887SAttilio Rao /* ARGSUSED */
91d8b87887SAttilio Rao static int
ioioctl(struct cdev * dev __unused,u_long cmd,caddr_t data,int fflag __unused,struct thread * td __unused)92d8b87887SAttilio Rao ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
93d8b87887SAttilio Rao int fflag __unused, struct thread *td __unused)
94d8b87887SAttilio Rao {
95d8b87887SAttilio Rao struct iodev_pio_req *pio_req;
96d8b87887SAttilio Rao int error;
97d8b87887SAttilio Rao
98d8b87887SAttilio Rao switch (cmd) {
99d8b87887SAttilio Rao case IODEV_PIO:
100d8b87887SAttilio Rao pio_req = (struct iodev_pio_req *)data;
101d8b87887SAttilio Rao switch (pio_req->access) {
102d8b87887SAttilio Rao case IODEV_PIO_READ:
103d8b87887SAttilio Rao error = iopio_read(pio_req);
104d8b87887SAttilio Rao break;
105d8b87887SAttilio Rao case IODEV_PIO_WRITE:
106d8b87887SAttilio Rao error = iopio_write(pio_req);
107d8b87887SAttilio Rao break;
108d8b87887SAttilio Rao default:
109d8b87887SAttilio Rao error = EINVAL;
110d8b87887SAttilio Rao break;
111d8b87887SAttilio Rao }
112d8b87887SAttilio Rao break;
113d8b87887SAttilio Rao default:
114d8b87887SAttilio Rao error = iodev_ioctl(cmd, data);
115d8b87887SAttilio Rao }
116d8b87887SAttilio Rao
117d8b87887SAttilio Rao return (error);
118d8b87887SAttilio Rao }
119d8b87887SAttilio Rao
120d8b87887SAttilio Rao static int
iopio_read(struct iodev_pio_req * req)121d8b87887SAttilio Rao iopio_read(struct iodev_pio_req *req)
122d8b87887SAttilio Rao {
123d8b87887SAttilio Rao
124d8b87887SAttilio Rao switch (req->width) {
125d8b87887SAttilio Rao case 1:
126d8b87887SAttilio Rao req->val = iodev_read_1(req->port);
127d8b87887SAttilio Rao break;
128d8b87887SAttilio Rao case 2:
129d8b87887SAttilio Rao if (req->port & 1) {
130d8b87887SAttilio Rao req->val = iodev_read_1(req->port);
131d8b87887SAttilio Rao req->val |= iodev_read_1(req->port + 1) << 8;
132d8b87887SAttilio Rao } else
133d8b87887SAttilio Rao req->val = iodev_read_2(req->port);
134d8b87887SAttilio Rao break;
135d8b87887SAttilio Rao case 4:
136d8b87887SAttilio Rao if (req->port & 1) {
137d8b87887SAttilio Rao req->val = iodev_read_1(req->port);
138d8b87887SAttilio Rao req->val |= iodev_read_2(req->port + 1) << 8;
139d8b87887SAttilio Rao req->val |= iodev_read_1(req->port + 3) << 24;
140d8b87887SAttilio Rao } else if (req->port & 2) {
141d8b87887SAttilio Rao req->val = iodev_read_2(req->port);
142d8b87887SAttilio Rao req->val |= iodev_read_2(req->port + 2) << 16;
143d8b87887SAttilio Rao } else
144d8b87887SAttilio Rao req->val = iodev_read_4(req->port);
145d8b87887SAttilio Rao break;
146d8b87887SAttilio Rao default:
147d8b87887SAttilio Rao return (EINVAL);
148d8b87887SAttilio Rao }
149d8b87887SAttilio Rao
150d8b87887SAttilio Rao return (0);
151d8b87887SAttilio Rao }
152d8b87887SAttilio Rao
153d8b87887SAttilio Rao static int
iopio_write(struct iodev_pio_req * req)154d8b87887SAttilio Rao iopio_write(struct iodev_pio_req *req)
155d8b87887SAttilio Rao {
156d8b87887SAttilio Rao
157d8b87887SAttilio Rao switch (req->width) {
158d8b87887SAttilio Rao case 1:
159d8b87887SAttilio Rao iodev_write_1(req->port, req->val);
160d8b87887SAttilio Rao break;
161d8b87887SAttilio Rao case 2:
162d8b87887SAttilio Rao if (req->port & 1) {
163d8b87887SAttilio Rao iodev_write_1(req->port, req->val);
164d8b87887SAttilio Rao iodev_write_1(req->port + 1, req->val >> 8);
165d8b87887SAttilio Rao } else
166d8b87887SAttilio Rao iodev_write_2(req->port, req->val);
167d8b87887SAttilio Rao break;
168d8b87887SAttilio Rao case 4:
169d8b87887SAttilio Rao if (req->port & 1) {
170d8b87887SAttilio Rao iodev_write_1(req->port, req->val);
171d8b87887SAttilio Rao iodev_write_2(req->port + 1, req->val >> 8);
172d8b87887SAttilio Rao iodev_write_1(req->port + 3, req->val >> 24);
173d8b87887SAttilio Rao } else if (req->port & 2) {
174d8b87887SAttilio Rao iodev_write_2(req->port, req->val);
175d8b87887SAttilio Rao iodev_write_2(req->port + 2, req->val >> 16);
176d8b87887SAttilio Rao } else
177d8b87887SAttilio Rao iodev_write_4(req->port, req->val);
178d8b87887SAttilio Rao break;
179d8b87887SAttilio Rao default:
180d8b87887SAttilio Rao return (EINVAL);
181d8b87887SAttilio Rao }
182d8b87887SAttilio Rao
183d8b87887SAttilio Rao return (0);
184d8b87887SAttilio Rao }
185d8b87887SAttilio Rao
186d8b87887SAttilio Rao /* ARGSUSED */
187d8b87887SAttilio Rao static int
io_modevent(module_t mod __unused,int type,void * data __unused)1888ab2f5ecSMark Murray io_modevent(module_t mod __unused, int type, void *data __unused)
1898ab2f5ecSMark Murray {
1908ab2f5ecSMark Murray switch(type) {
1918ab2f5ecSMark Murray case MOD_LOAD:
1928ab2f5ecSMark Murray if (bootverbose)
1938ab2f5ecSMark Murray printf("io: <I/O>\n");
19472135187SEd Schouten iodev = make_dev(&io_cdevsw, 0,
1958ab2f5ecSMark Murray UID_ROOT, GID_WHEEL, 0600, "io");
1968ab2f5ecSMark Murray break;
1978ab2f5ecSMark Murray
1988ab2f5ecSMark Murray case MOD_UNLOAD:
1998ab2f5ecSMark Murray destroy_dev(iodev);
2008ab2f5ecSMark Murray break;
2018ab2f5ecSMark Murray
2028ab2f5ecSMark Murray case MOD_SHUTDOWN:
2038ab2f5ecSMark Murray break;
2048ab2f5ecSMark Murray
2058ab2f5ecSMark Murray default:
2068ab2f5ecSMark Murray return(EOPNOTSUPP);
2078ab2f5ecSMark Murray break;
2088ab2f5ecSMark Murray
2098ab2f5ecSMark Murray }
2108ab2f5ecSMark Murray
2118ab2f5ecSMark Murray return (0);
2128ab2f5ecSMark Murray }
2138ab2f5ecSMark Murray
2148ab2f5ecSMark Murray DEV_MODULE(io, io_modevent, NULL);
215ce46e205SMark Murray MODULE_VERSION(io, 1);
216