#ifndef lint static char sccsid[] = "@(#)pr_make.c 9.3 88/01/19 SMI"; #endif /* * Copyright 1986 by Sun Microsystems, Inc. */ /* * Pixrect make/unmake utilities */ #include #include #include #include #include #include /* Round value up to specified granularity -- gran must be a power of two */ #undef roundup #define roundup(val, gran) ((val) + (gran) - 1 & ~((gran) - 1)) #define ERROR(s) if (1) { errstr = (s); goto bad; } else #ifdef alloctype #undef alloctype #endif #define alloctype(datatype) (datatype *)softcalloc("pr_make.c", 1, sizeof(datatype)) extern char *calloc(), *valloc(), *snoopcalloc(), *softcalloc(); Pixrect * pr_makefromfd(fd, size, depth, devdata, curdd, mmapbytes, privdatabytes, mmapoffsetbytes) int fd; struct pr_size size; int depth; struct pr_devdata **devdata, **curdd; int mmapbytes, privdatabytes, mmapoffsetbytes; { char *errstr = ""; static char callocfailed[] = "calloc failed"; Pixrect *pr = 0; register struct pr_devdata *dd = 0; struct stat statbuf; /* check args */ if (fd < 0) ERROR("invalid fd"); if (devdata == 0 || curdd == 0) ERROR("null devdata or curdata"); /* allocate and initialize pixrect */ if ( (pr = alloctype(Pixrect)) == 0) ERROR(callocfailed); pr->pr_size = size; pr->pr_depth = depth; /* allocate pixrect private data */ pr->pr_data = (caddr_t) softcalloc("pr_makefromfd", 1, (unsigned) privdatabytes); /* get frame buffer device number */ if (fstat(fd, &statbuf) < 0) ERROR("fstat failed"); /* look for a devdata structure for that device */ if ((dd = *devdata) == 0) { /* * Allocate first node */ dd = alloctype(struct pr_devdata); *devdata = dd; } else { while (dd != 0) { if (statbuf.st_rdev == dd->rdev) /* found it! */ break; if (dd->next == 0) { /* end of list, add new node */ dd->next = alloctype(struct pr_devdata); dd = dd->next; break; } dd = dd->next; } } if (dd == 0) ERROR(callocfailed); /* map the frame buffer if necessary */ if (dd->count == 0) { int pagesize; /* save device number in devdata */ dd->rdev = statbuf.st_rdev; /* caller will close fd, so dup it (dumb) */ if ((dd->fd = dup(fd)) < 0) ERROR("dup failed"); pagesize = getpagesize(); if (mmapoffsetbytes != roundup(mmapoffsetbytes, pagesize)) ERROR("mmapoffsetbytes not page size multiple"); mmapbytes = roundup(mmapbytes, pagesize); /* allocate enough virtual space to map the frame buffer */ if ((dd->va = (short *) valloc((unsigned) mmapbytes)) == 0) soft_malloc_failure("pr_makefromfd"); /* ERROR("valloc failed"); */ /* map the frame buffer */ if (mmap((caddr_t) dd->va, dd->bytes = mmapbytes, PROT_READ | PROT_WRITE, MAP_SHARED, dd->fd, mmapoffsetbytes) < 0) ERROR("mmap failed"); } /* bump devdata reference count */ dd->count++; *curdd = dd; return pr; /* error occurred -- clean up and print message */ bad: if (pr != 0) { /* free pixrect and possibly pixrect data */ if (pr->pr_data != 0) free((char *) pr->pr_data); free((char *) pr); /* * free fd and possibly frame buffer virtual space * if no one else is using them * * don't bother unlinking/freeing devdata */ if (dd != 0 && dd->count == 0) { if (dd->fd >= 0) { (void) close(dd->fd); if (dd->va != 0) free((char *) dd->va); } } } (void) fprintf(stderr, "pr_makefromfd error: %s\n", errstr); *curdd = 0; return 0; } pr_unmakefromfd(fd, devdata) int fd; struct pr_devdata **devdata; { register struct pr_devdata *dd, *ddprev = 0; struct stat statbuf; /* get the device number */ if (fstat(fd, &statbuf) < 0) return PIX_ERR; /* look for the relevant devdata structure */ for (dd = *devdata; dd != 0; ddprev = dd, dd = dd->next) { /* found matching device number? */ if (statbuf.st_rdev == dd->rdev) { /* * If the reference count goes to zero, we would * like to unmap the frame buffer, close its fd, * and release the virtual space. * * Unfortunately, we can't do that because the * mmap call probably released the swap space for * the region the frame buffer was mapped over. */ #if defined(PR_UNMAKE_UNMAP) || defined(lint) if (--dd->count <= 0) { if (munmap((caddr_t) dd->va, dd->bytes) < 0) { perror("munmap in pr_unmakefromfd"); return PIX_ERR; } (void) close(dd->fd); free((char *) dd->va); /* unlink devdata */ if (ddprev == 0) *devdata = dd->next; else ddprev->next = dd->next; free((char *) dd); } #endif PR_UNMAKE_UNMAP || lint return 0; } } /* couldn't find the devdata */ return PIX_ERR; }