1251881Speter/* $NetBSD: intro.c,v 1.3 2007/11/22 11:28:49 pooka Exp $ */ 2251881Speter 3251881Speter/* 4251881Speter * El extra-simplo example of the userspace driver framework. 5251881Speter * 6251881Speter * Eventually there will be a library a la libpuffs (perhaps, 7251881Speter * gasp, even the same lib), but for now it's all manual until 8251881Speter * I get it figured out. 9251881Speter * 10251881Speter * So how to run this? 11251881Speter * 0) sh MAKEDEV putter (if you don't have a freshly created /dev) 12251881Speter * 1) run this program with the argument "/dev/pud" 13251881Speter * 2) mknod a char device with the major 377 (see sources below) 14251881Speter * 3) echo ascii art and jokes into device created in previous step 15251881Speter * or read the device 16251881Speter */ 17251881Speter 18251881Speter#include <sys/types.h> 19251881Speter 20251881Speter#include <dev/pud/pud_msgif.h> 21251881Speter 22251881Speter#include <err.h> 23251881Speter#include <errno.h> 24251881Speter#include <fcntl.h> 25251881Speter#include <stdio.h> 26251881Speter#include <stdlib.h> 27251881Speter#include <string.h> 28251881Speter#include <unistd.h> 29251881Speter 30251881Speter#include "common.h" 31251881Speter 32251881Speter#define DEFALLOC 1024*1024 33251881Speter#define ECHOSTR1 "Would you like some sauce diable with that?\n" 34251881Speter#define ECHOSTR2 "Nej tack, you fool, I'm happy with my tournedos Rossini\n" 35251881Speter#define NSTR 2 36251881Speter 37251881Speterconst char *curstr = ECHOSTR1; 38251881Speter 39251881Speter#ifndef MIN 40251881Speter#define MIN(a,b) ((a)<(b)?(a):(b)) 41251881Speter#endif 42251881Speter 43int 44main(int argc, char *argv[]) 45{ 46 struct pud_req *pdr = malloc(DEFALLOC); 47 struct pud_conf_reg pcr; 48 int fd; 49 ssize_t n; 50 51 if (argc != 2) 52 errx(1, "args"); 53 54 /* 55 * open pud device 56 */ 57 fd = open(argv[1], O_RDWR); 58 if (fd == -1) 59 err(1, "open"); 60 61 /* 62 * register our major number 63 */ 64 memset(&pcr, 0, sizeof(pcr)); 65 pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg); 66 pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION; 67 pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF; 68 pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG; 69 70 pcr.pm_regdev = makedev(377, 0); 71 pcr.pm_flags = PUD_CONFFLAG_BDEV; 72 strlcpy(pcr.pm_devname, "testdev", sizeof(pcr.pm_devname)); 73 74 n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen); 75 if (n == -1) 76 err(1, "configure write"); 77 78 /* 79 * process requests 80 */ 81 for (;;) { 82 n = read(fd, pdr, DEFALLOC); 83 printf("read %d %d\n", n, errno); 84 85 switch (pdr->pdr_reqtype) { 86 case PUD_CDEV_OPEN: 87 case PUD_CDEV_CLOSE: 88 printf("got openclose %d\n", pdr->pdr_reqtype); 89 pdr->pdr_rv = 0; 90 break; 91 92 case PUD_CDEV_READ: 93 /* uh oh case PUD_BDEV_STRATREAD: */ 94 { 95 struct pud_creq_read *pc_read; 96 size_t clen; 97 98 pc_read = (void *)pdr; 99 printf("read from offset %llu, resid %zu\n", 100 (unsigned long long)pc_read->pm_offset, 101 pc_read->pm_resid); 102 103 clen = MIN(strlen(curstr), pc_read->pm_resid); 104 strncpy(pc_read->pm_data, curstr, clen); 105 if (pdr->pdr_reqclass == PUD_REQ_BDEV) { 106 clen = pc_read->pm_resid; 107 pc_read->pm_resid = 0; 108 } else { 109 pc_read->pm_resid -= clen; 110 } 111 pdr->pdr_pth.pth_framelen = 112 sizeof(struct pud_creq_read) + clen; 113 } 114 break; 115 116 case PUD_CDEV_WRITE: 117 /* uh uh oh case PUD_BDEV_STRATWRITE: */ 118 { 119 struct pud_creq_write *pc_write; 120 121 pc_write = (void *)pdr; 122 printf("write to offset %llu, resid %zu\n", 123 (unsigned long long)pc_write->pm_offset, 124 pc_write->pm_resid); 125 126 pc_write->pm_data[pc_write->pm_resid] = '\0'; 127 printf("got via write: %s", pc_write->pm_data); 128 pdr->pdr_pth.pth_framelen = 129 sizeof(struct pud_creq_write); 130 pc_write->pm_resid = 0; 131 } 132 break; 133 134 case PUD_CDEV_IOCTL: 135 { 136 struct pud_req_ioctl *pc_ioctl; 137 int *iocval; 138 139 pc_ioctl = (void *)pdr; 140 switch (pc_ioctl->pm_iocmd) { 141 case INTROTOGGLE: 142 case INTROTOGGLE_R: 143 iocval = (int *)pc_ioctl->pm_data; 144 if (*iocval < 0 || *iocval > 2) { 145 pdr->pdr_rv = ERANGE; 146 break; 147 } 148 149 if (*iocval == 1) 150 curstr = ECHOSTR1; 151 else 152 curstr = ECHOSTR2; 153 154 *iocval = 0; 155 break; 156 default: 157 abort(); 158 } 159 } 160 break; 161 162 default: 163 abort(); 164 } 165 166 n = write(fd, pdr, pdr->pdr_pth.pth_framelen); 167 printf("wrote %d %d\n", n, errno); 168 } 169} 170