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