1/* $NetBSD: ttyserv.c,v 1.3 2016/01/25 11:45:58 pooka Exp $ */ 2 3/* 4 * Copyright (c) 2009, 2010 Antti Kantee. 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 ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * 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 OR 21 * 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/* 29 * This is a [quick, simple & dirty] userspace tty/ucom server. 30 * We probe USB devices using rump and attach them to the host kernel 31 * using pud(4). 32 */ 33 34#include <sys/types.h> 35#include <sys/syslimits.h> 36 37#include <dev/pud/pud_msgif.h> 38 39#include <rump/rump.h> 40#include <rump/rumpvnode_if.h> 41 42#include <assert.h> 43#include <err.h> 44#include <errno.h> 45#include <fcntl.h> 46#include <paths.h> 47#include <pthread.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <unistd.h> 52 53/* 54 * No devfs? No problem. We just hack a bit & wait for the dust to settle. 55 */ 56#define MYMAJOR 412 57static int 58makenodes(void) 59{ 60 struct stat sb; 61 int rv; 62 63 if (stat("rumpttyU0", &sb) != 0) 64 rv = mknod("rumpttyU0", S_IFCHR | 0666, makedev(MYMAJOR, 0)); 65 if (rv != 0 && !(rv == -1 && errno == EEXIST)) 66 return rv; 67 68 if (stat("rumpttyU1", &sb) != 0) 69 rv = mknod("rumpttyU1", S_IFCHR | 0666, makedev(MYMAJOR, 1)); 70 if (rv != 0 && !(rv == -1 && errno == EEXIST)) 71 return rv; 72 73 return 0; 74} 75 76static struct vnode *devvps[2]; 77static kauth_cred_t rootcred; 78static int fd; 79 80static void * 81handlereq(void *arg) 82{ 83 struct vnode *devvp; 84 struct pud_creq_open *pr_open; 85 struct pud_creq_close *pr_close; 86 struct pud_req_readwrite *pr_rw; 87 struct pud_req_ioctl *pr_ioctl; 88 struct uio *uio; 89 size_t reslen; 90 struct pud_req *pdr = arg; 91 int minordev, rv; 92 ssize_t n; 93 94 minordev = minor(pdr->pdr_dev); 95 if (minordev < 0 || minordev >= 8) { 96 rv = ENXIO; 97 goto sendresponse; 98 } 99 devvp = devvps[minordev]; 100 101 switch (pdr->pdr_reqtype) { 102 case PUD_CDEV_OPEN: 103 pr_open = (void *)pdr; 104 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE); 105 rv = RUMP_VOP_OPEN(devvp, pr_open->pm_fmt, rootcred); 106 RUMP_VOP_UNLOCK(devvp); 107 break; 108 109 case PUD_CDEV_CLOSE: 110 pr_close = (void *)pdr; 111 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE); 112 rv = RUMP_VOP_CLOSE(devvp, pr_close->pm_fmt, rootcred); 113 RUMP_VOP_UNLOCK(devvp); 114 break; 115 116 case PUD_CDEV_IOCTL: 117 pr_ioctl = (void *)pdr; 118 rv = RUMP_VOP_IOCTL(devvp, pr_ioctl->pm_iocmd, 119 pr_ioctl->pm_data, pr_ioctl->pm_flag, rootcred); 120 break; 121 122 case PUD_CDEV_READ: 123 pr_rw = (void *)pdr; 124 assert(pr_rw->pm_resid <= 64*1024); 125 uio = rump_pub_uio_setup(&pr_rw->pm_data[0], 126 pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_READ); 127 RUMP_VOP_LOCK(devvp, RUMP_LK_SHARED); 128 rv = RUMP_VOP_READ(devvp, uio, 0, rootcred); 129 RUMP_VOP_UNLOCK(devvp); 130 reslen = rump_pub_uio_free(uio); 131 pdr->pdr_pth.pth_framelen -= reslen; 132 pr_rw->pm_resid = reslen; 133 break; 134 135 case PUD_CDEV_WRITE: 136 pr_rw = (void *)pdr; 137 uio = rump_pub_uio_setup(&pr_rw->pm_data[0], 138 pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_WRITE); 139 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE); 140 rv = RUMP_VOP_WRITE(devvp, uio, 0, rootcred); 141 RUMP_VOP_UNLOCK(devvp); 142 reslen = rump_pub_uio_free(uio); 143 pr_rw->pm_resid = reslen; 144 pdr->pdr_pth.pth_framelen=sizeof(struct pud_creq_write); 145 rv = 0; 146 break; 147 default: 148 printf("unknown request %d\n", pdr->pdr_reqtype); 149 abort(); 150 } 151 152sendresponse: 153 printf("result %d\n", rv); 154 pdr->pdr_rv = rv; 155 n = write(fd, pdr, pdr->pdr_pth.pth_framelen); 156 assert(n == (ssize_t)pdr->pdr_pth.pth_framelen); 157 158 pthread_exit(NULL); 159} 160 161int 162main(int argc, char *argv[]) 163{ 164 struct pud_conf_reg pcr; 165 struct pud_req *pdr; 166 ssize_t n; 167 int rv; 168 169 if (makenodes() == -1) 170 err(1, "makenodes"); 171 172 fd = open(_PATH_PUD, O_RDWR); 173 if (fd == -1) 174 err(1, "open"); 175 176 memset(&pcr, 0, sizeof(pcr)); 177 pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg); 178 pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION; 179 pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF; 180 pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG; 181 182 pcr.pm_regdev = makedev(MYMAJOR, 0); 183 pcr.pm_flags = PUD_CONFFLAG_BDEV; 184 strlcpy(pcr.pm_devname, "youmass", sizeof(pcr.pm_devname)); 185 186 n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen); 187 if (n == -1) 188 err(1, "configure"); /* XXX: doubles as protocol error */ 189 190 rump_boot_sethowto(RUMP_AB_VERBOSE); 191 rump_init(); 192 193 if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU0", 194 NULL, &devvps[0], NULL)) != 0) 195 errx(1, "raw device 0 lookup failed %d", rv); 196 if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU1", 197 NULL, &devvps[1], NULL)) != 0) 198 errx(1, "raw device 1 lookup failed %d", rv); 199 200 rootcred = rump_pub_cred_create(0, 0, 0, NULL); 201 202 /* process requests ad infinitum */ 203 for (;;) { 204 pthread_t pt; 205 206#define PDRSIZE (64*1024+1024) 207 pdr = malloc(PDRSIZE); 208 if (pdr == NULL) 209 err(1, "malloc"); 210 211 n = read(fd, pdr, PDRSIZE); 212 if (n == -1) 213 err(1, "read"); 214 215 /* 216 * tip & cu fork and read/write at the same time. hence, 217 * we need a multithreaded server as otherwise read requests 218 * will block eternally since no writes can be done. 219 * 220 * XXX: do this properly (detached threads, or pool) 221 */ 222 pthread_create(&pt, NULL, handlereq, pdr); 223 } 224} 225