Home | History | Annotate | Line # | Download | only in intro
      1 /*	$NetBSD: intro.c,v 1.4 2007/11/28 16:59:02 pooka Exp $	*/
      2 
      3 /*
      4  * El extra-simplo example of the userspace driver framework.
      5  *
      6  * Eventually there will be a library a la libpuffs (perhaps,
      7  * gasp, even the same lib), but for now it's all manual until
      8  * I get it figured out.
      9  *
     10  * So how to run this?
     11  * 0) sh MAKEDEV putter (if you don't have a freshly created /dev)
     12  * 1) run this program with the argument "/dev/pud"
     13  * 2) mknod a char device with the major 377 (see sources below)
     14  * 3) echo ascii art and jokes into device created in previous step
     15  *    or read the device
     16  */
     17 
     18 #include <sys/types.h>
     19 
     20 #include <dev/pud/pud_msgif.h>
     21 
     22 #include <err.h>
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 
     30 #include "common.h"
     31 
     32 #define DEFALLOC 1024*1024
     33 #define ECHOSTR1 "Would you like some sauce diable with that?\n"
     34 #define ECHOSTR2 "Nej tack, you fool, I'm happy with my tournedos Rossini\n"
     35 #define NSTR 2
     36 
     37 const char *curstr = ECHOSTR1;
     38 
     39 #ifndef MIN
     40 #define MIN(a,b) ((a)<(b)?(a):(b))
     41 #endif
     42 
     43 int
     44 main(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