1*d35b86acSpooka /* $NetBSD: ttyserv.c,v 1.3 2016/01/25 11:45:58 pooka Exp $ */
260ab2ca5Spooka
360ab2ca5Spooka /*
460ab2ca5Spooka * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
560ab2ca5Spooka *
660ab2ca5Spooka * Redistribution and use in source and binary forms, with or without
760ab2ca5Spooka * modification, are permitted provided that the following conditions
860ab2ca5Spooka * are met:
960ab2ca5Spooka * 1. Redistributions of source code must retain the above copyright
1060ab2ca5Spooka * notice, this list of conditions and the following disclaimer.
1160ab2ca5Spooka * 2. Redistributions in binary form must reproduce the above copyright
1260ab2ca5Spooka * notice, this list of conditions and the following disclaimer in the
1360ab2ca5Spooka * documentation and/or other materials provided with the distribution.
1460ab2ca5Spooka *
1560ab2ca5Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1660ab2ca5Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1760ab2ca5Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1860ab2ca5Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1960ab2ca5Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2060ab2ca5Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2160ab2ca5Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2260ab2ca5Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2360ab2ca5Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2460ab2ca5Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2560ab2ca5Spooka * SUCH DAMAGE.
2660ab2ca5Spooka */
2760ab2ca5Spooka
2860ab2ca5Spooka /*
2960ab2ca5Spooka * This is a [quick, simple & dirty] userspace tty/ucom server.
3060ab2ca5Spooka * We probe USB devices using rump and attach them to the host kernel
3160ab2ca5Spooka * using pud(4).
3260ab2ca5Spooka */
3360ab2ca5Spooka
3460ab2ca5Spooka #include <sys/types.h>
3560ab2ca5Spooka #include <sys/syslimits.h>
3660ab2ca5Spooka
3760ab2ca5Spooka #include <dev/pud/pud_msgif.h>
3860ab2ca5Spooka
3960ab2ca5Spooka #include <rump/rump.h>
40*d35b86acSpooka #include <rump/rumpvnode_if.h>
4160ab2ca5Spooka
4260ab2ca5Spooka #include <assert.h>
4360ab2ca5Spooka #include <err.h>
4460ab2ca5Spooka #include <errno.h>
4560ab2ca5Spooka #include <fcntl.h>
4660ab2ca5Spooka #include <paths.h>
4760ab2ca5Spooka #include <pthread.h>
4860ab2ca5Spooka #include <stdio.h>
4960ab2ca5Spooka #include <stdlib.h>
5060ab2ca5Spooka #include <string.h>
5160ab2ca5Spooka #include <unistd.h>
5260ab2ca5Spooka
5360ab2ca5Spooka /*
5460ab2ca5Spooka * No devfs? No problem. We just hack a bit & wait for the dust to settle.
5560ab2ca5Spooka */
5660ab2ca5Spooka #define MYMAJOR 412
5760ab2ca5Spooka static int
makenodes(void)5860ab2ca5Spooka makenodes(void)
5960ab2ca5Spooka {
6060ab2ca5Spooka struct stat sb;
6160ab2ca5Spooka int rv;
6260ab2ca5Spooka
6360ab2ca5Spooka if (stat("rumpttyU0", &sb) != 0)
6460ab2ca5Spooka rv = mknod("rumpttyU0", S_IFCHR | 0666, makedev(MYMAJOR, 0));
6560ab2ca5Spooka if (rv != 0 && !(rv == -1 && errno == EEXIST))
6660ab2ca5Spooka return rv;
6760ab2ca5Spooka
6860ab2ca5Spooka if (stat("rumpttyU1", &sb) != 0)
6960ab2ca5Spooka rv = mknod("rumpttyU1", S_IFCHR | 0666, makedev(MYMAJOR, 1));
7060ab2ca5Spooka if (rv != 0 && !(rv == -1 && errno == EEXIST))
7160ab2ca5Spooka return rv;
7260ab2ca5Spooka
7360ab2ca5Spooka return 0;
7460ab2ca5Spooka }
7560ab2ca5Spooka
7660ab2ca5Spooka static struct vnode *devvps[2];
7760ab2ca5Spooka static kauth_cred_t rootcred;
7860ab2ca5Spooka static int fd;
7960ab2ca5Spooka
8060ab2ca5Spooka static void *
handlereq(void * arg)8160ab2ca5Spooka handlereq(void *arg)
8260ab2ca5Spooka {
8360ab2ca5Spooka struct vnode *devvp;
8460ab2ca5Spooka struct pud_creq_open *pr_open;
8560ab2ca5Spooka struct pud_creq_close *pr_close;
8660ab2ca5Spooka struct pud_req_readwrite *pr_rw;
8760ab2ca5Spooka struct pud_req_ioctl *pr_ioctl;
8860ab2ca5Spooka struct uio *uio;
8960ab2ca5Spooka size_t reslen;
9060ab2ca5Spooka struct pud_req *pdr = arg;
9160ab2ca5Spooka int minordev, rv;
9260ab2ca5Spooka ssize_t n;
9360ab2ca5Spooka
9460ab2ca5Spooka minordev = minor(pdr->pdr_dev);
9560ab2ca5Spooka if (minordev < 0 || minordev >= 8) {
9660ab2ca5Spooka rv = ENXIO;
9760ab2ca5Spooka goto sendresponse;
9860ab2ca5Spooka }
9960ab2ca5Spooka devvp = devvps[minordev];
10060ab2ca5Spooka
10160ab2ca5Spooka switch (pdr->pdr_reqtype) {
10260ab2ca5Spooka case PUD_CDEV_OPEN:
10360ab2ca5Spooka pr_open = (void *)pdr;
10460ab2ca5Spooka RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
10560ab2ca5Spooka rv = RUMP_VOP_OPEN(devvp, pr_open->pm_fmt, rootcred);
1061423e65bShannken RUMP_VOP_UNLOCK(devvp);
10760ab2ca5Spooka break;
10860ab2ca5Spooka
10960ab2ca5Spooka case PUD_CDEV_CLOSE:
11060ab2ca5Spooka pr_close = (void *)pdr;
11160ab2ca5Spooka RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
11260ab2ca5Spooka rv = RUMP_VOP_CLOSE(devvp, pr_close->pm_fmt, rootcred);
1131423e65bShannken RUMP_VOP_UNLOCK(devvp);
11460ab2ca5Spooka break;
11560ab2ca5Spooka
11660ab2ca5Spooka case PUD_CDEV_IOCTL:
11760ab2ca5Spooka pr_ioctl = (void *)pdr;
11860ab2ca5Spooka rv = RUMP_VOP_IOCTL(devvp, pr_ioctl->pm_iocmd,
11960ab2ca5Spooka pr_ioctl->pm_data, pr_ioctl->pm_flag, rootcred);
12060ab2ca5Spooka break;
12160ab2ca5Spooka
12260ab2ca5Spooka case PUD_CDEV_READ:
12360ab2ca5Spooka pr_rw = (void *)pdr;
12460ab2ca5Spooka assert(pr_rw->pm_resid <= 64*1024);
12560ab2ca5Spooka uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
12660ab2ca5Spooka pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_READ);
12760ab2ca5Spooka RUMP_VOP_LOCK(devvp, RUMP_LK_SHARED);
12860ab2ca5Spooka rv = RUMP_VOP_READ(devvp, uio, 0, rootcred);
1291423e65bShannken RUMP_VOP_UNLOCK(devvp);
13060ab2ca5Spooka reslen = rump_pub_uio_free(uio);
13160ab2ca5Spooka pdr->pdr_pth.pth_framelen -= reslen;
13260ab2ca5Spooka pr_rw->pm_resid = reslen;
13360ab2ca5Spooka break;
13460ab2ca5Spooka
13560ab2ca5Spooka case PUD_CDEV_WRITE:
13660ab2ca5Spooka pr_rw = (void *)pdr;
13760ab2ca5Spooka uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
13860ab2ca5Spooka pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_WRITE);
13960ab2ca5Spooka RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
14060ab2ca5Spooka rv = RUMP_VOP_WRITE(devvp, uio, 0, rootcred);
1411423e65bShannken RUMP_VOP_UNLOCK(devvp);
14260ab2ca5Spooka reslen = rump_pub_uio_free(uio);
14360ab2ca5Spooka pr_rw->pm_resid = reslen;
14460ab2ca5Spooka pdr->pdr_pth.pth_framelen=sizeof(struct pud_creq_write);
14560ab2ca5Spooka rv = 0;
14660ab2ca5Spooka break;
14760ab2ca5Spooka default:
14860ab2ca5Spooka printf("unknown request %d\n", pdr->pdr_reqtype);
14960ab2ca5Spooka abort();
15060ab2ca5Spooka }
15160ab2ca5Spooka
15260ab2ca5Spooka sendresponse:
15360ab2ca5Spooka printf("result %d\n", rv);
15460ab2ca5Spooka pdr->pdr_rv = rv;
15560ab2ca5Spooka n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
15660ab2ca5Spooka assert(n == (ssize_t)pdr->pdr_pth.pth_framelen);
15760ab2ca5Spooka
15860ab2ca5Spooka pthread_exit(NULL);
15960ab2ca5Spooka }
16060ab2ca5Spooka
16160ab2ca5Spooka int
main(int argc,char * argv[])16260ab2ca5Spooka main(int argc, char *argv[])
16360ab2ca5Spooka {
16460ab2ca5Spooka struct pud_conf_reg pcr;
16560ab2ca5Spooka struct pud_req *pdr;
16660ab2ca5Spooka ssize_t n;
16760ab2ca5Spooka int rv;
16860ab2ca5Spooka
16960ab2ca5Spooka if (makenodes() == -1)
17060ab2ca5Spooka err(1, "makenodes");
17160ab2ca5Spooka
17260ab2ca5Spooka fd = open(_PATH_PUD, O_RDWR);
17360ab2ca5Spooka if (fd == -1)
17460ab2ca5Spooka err(1, "open");
17560ab2ca5Spooka
17660ab2ca5Spooka memset(&pcr, 0, sizeof(pcr));
17760ab2ca5Spooka pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
17860ab2ca5Spooka pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION;
17960ab2ca5Spooka pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
18060ab2ca5Spooka pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
18160ab2ca5Spooka
18260ab2ca5Spooka pcr.pm_regdev = makedev(MYMAJOR, 0);
18360ab2ca5Spooka pcr.pm_flags = PUD_CONFFLAG_BDEV;
18460ab2ca5Spooka strlcpy(pcr.pm_devname, "youmass", sizeof(pcr.pm_devname));
18560ab2ca5Spooka
18660ab2ca5Spooka n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
18760ab2ca5Spooka if (n == -1)
18860ab2ca5Spooka err(1, "configure"); /* XXX: doubles as protocol error */
18960ab2ca5Spooka
19060ab2ca5Spooka rump_boot_sethowto(RUMP_AB_VERBOSE);
19160ab2ca5Spooka rump_init();
19260ab2ca5Spooka
19360ab2ca5Spooka if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU0",
19460ab2ca5Spooka NULL, &devvps[0], NULL)) != 0)
19560ab2ca5Spooka errx(1, "raw device 0 lookup failed %d", rv);
19660ab2ca5Spooka if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU1",
19760ab2ca5Spooka NULL, &devvps[1], NULL)) != 0)
19860ab2ca5Spooka errx(1, "raw device 1 lookup failed %d", rv);
19960ab2ca5Spooka
20060ab2ca5Spooka rootcred = rump_pub_cred_create(0, 0, 0, NULL);
20160ab2ca5Spooka
20260ab2ca5Spooka /* process requests ad infinitum */
20360ab2ca5Spooka for (;;) {
20460ab2ca5Spooka pthread_t pt;
20560ab2ca5Spooka
20660ab2ca5Spooka #define PDRSIZE (64*1024+1024)
20760ab2ca5Spooka pdr = malloc(PDRSIZE);
20860ab2ca5Spooka if (pdr == NULL)
20960ab2ca5Spooka err(1, "malloc");
21060ab2ca5Spooka
21160ab2ca5Spooka n = read(fd, pdr, PDRSIZE);
21260ab2ca5Spooka if (n == -1)
21360ab2ca5Spooka err(1, "read");
21460ab2ca5Spooka
21560ab2ca5Spooka /*
21660ab2ca5Spooka * tip & cu fork and read/write at the same time. hence,
21760ab2ca5Spooka * we need a multithreaded server as otherwise read requests
21860ab2ca5Spooka * will block eternally since no writes can be done.
21960ab2ca5Spooka *
22060ab2ca5Spooka * XXX: do this properly (detached threads, or pool)
22160ab2ca5Spooka */
22260ab2ca5Spooka pthread_create(&pt, NULL, handlereq, pdr);
22360ab2ca5Spooka }
22460ab2ca5Spooka }
225