Deleted Added
full compact
2c2
< * Copyright (c) 2012 Robert N. M. Watson
---
> * Copyright (c) 2012-2013 Robert N. M. Watson
32c32
< __FBSDID("$FreeBSD: head/sys/dev/altera/avgen/altera_avgen_nexus.c 245375 2013-01-13 16:41:25Z rwatson $");
---
> __FBSDID("$FreeBSD: head/sys/dev/altera/avgen/altera_avgen_nexus.c 245376 2013-01-13 16:43:59Z rwatson $");
56,74d55
< /*
< * Generic device driver for allowing read(), write(), and mmap() on
< * memory-mapped, Avalon-attached devices. There is no actual dependence on
< * Avalon, so conceivably this should just be soc_dev or similar, since many
< * system-on-chip bus environments would work fine with the same code.
< */
<
< static d_mmap_t altera_avgen_mmap;
< static d_read_t altera_avgen_read;
< static d_write_t altera_avgen_write;
<
< static struct cdevsw avg_cdevsw = {
< .d_version = D_VERSION,
< .d_mmap = altera_avgen_mmap,
< .d_read = altera_avgen_read,
< .d_write = altera_avgen_write,
< .d_name = "altera_avgen",
< };
<
76,229d56
< altera_avgen_read(struct cdev *dev, struct uio *uio, int flag)
< {
< struct altera_avgen_softc *sc;
< u_long offset, size;
< #ifdef NOTYET
< uint64_t v8;
< #endif
< uint32_t v4;
< uint16_t v2;
< uint8_t v1;
< u_int width;
< int error;
<
< sc = dev->si_drv1;
< if ((sc->avg_flags & ALTERA_AVALON_FLAG_READ) == 0)
< return (EACCES);
< width = sc->avg_width;
< if (uio->uio_offset < 0 || uio->uio_offset % width != 0 ||
< uio->uio_resid % width != 0)
< return (ENODEV);
< size = rman_get_size(sc->avg_res);
< if ((uio->uio_offset + uio->uio_resid < 0) ||
< (uio->uio_offset + uio->uio_resid > size))
< return (ENODEV);
< while (uio->uio_resid > 0) {
< offset = uio->uio_offset;
< if (offset + width > size)
< return (ENODEV);
< switch (width) {
< case 1:
< v1 = bus_read_1(sc->avg_res, offset);
< error = uiomove(&v1, sizeof(v1), uio);
< break;
<
< case 2:
< v2 = bus_read_2(sc->avg_res, offset);
< error = uiomove(&v2, sizeof(v2), uio);
< break;
<
< case 4:
< v4 = bus_read_4(sc->avg_res, offset);
< error = uiomove(&v4, sizeof(v4), uio);
< break;
<
< #ifdef NOTYET
< case 8:
< v8 = bus_read_8(sc->avg_res, offset);
< error = uiomove(&v8, sizeof(v8), uio);
< break;
<
< #endif
<
< default:
< panic("%s: unexpected widthment %u", __func__, width);
< }
< if (error)
< return (error);
< }
< return (0);
< }
<
< static int
< altera_avgen_write(struct cdev *dev, struct uio *uio, int flag)
< {
< struct altera_avgen_softc *sc;
< u_long offset, size;
< #ifdef NOTYET
< uint64_t v8;
< #endif
< uint32_t v4;
< uint16_t v2;
< uint8_t v1;
< u_int width;
< int error;
<
< sc = dev->si_drv1;
< if ((sc->avg_flags & ALTERA_AVALON_FLAG_WRITE) == 0)
< return (EACCES);
< width = sc->avg_width;
< if (uio->uio_offset < 0 || uio->uio_offset % width != 0 ||
< uio->uio_resid % width != 0)
< return (ENODEV);
< size = rman_get_size(sc->avg_res);
< while (uio->uio_resid > 0) {
< offset = uio->uio_offset;
< if (offset + width > size)
< return (ENODEV);
< switch (width) {
< case 1:
< error = uiomove(&v1, sizeof(v1), uio);
< if (error)
< return (error);
< bus_write_1(sc->avg_res, offset, v1);
< break;
<
< case 2:
< error = uiomove(&v2, sizeof(v2), uio);
< if (error)
< return (error);
< bus_write_2(sc->avg_res, offset, v2);
< break;
<
< case 4:
< error = uiomove(&v4, sizeof(v4), uio);
< if (error)
< return (error);
< bus_write_4(sc->avg_res, offset, v4);
< break;
<
< #ifdef NOTYET
< case 8:
< error = uiomove(&v8, sizeof(v8), uio);
< if (error)
< return (error);
< bus_write_8(sc->avg_res, offset, v8);
< break;
< #endif
<
< default:
< panic("%s: unexpected width %u", __func__, width);
< }
< }
< return (0);
< }
<
< static int
< altera_avgen_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
< int nprot, vm_memattr_t *memattr)
< {
< struct altera_avgen_softc *sc;
<
< sc = dev->si_drv1;
< if (nprot & VM_PROT_READ) {
< if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_READ) == 0)
< return (EACCES);
< }
< if (nprot & VM_PROT_WRITE) {
< if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_WRITE) == 0)
< return (EACCES);
< }
< if (nprot & VM_PROT_EXECUTE) {
< if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_EXEC) == 0)
< return (EACCES);
< }
< if (trunc_page(offset) == offset &&
< rman_get_size(sc->avg_res) >= offset + PAGE_SIZE) {
< *paddr = rman_get_start(sc->avg_res) + offset;
< *memattr = VM_MEMATTR_UNCACHEABLE;
< } else
< return (ENODEV);
< return (0);
< }
<
< static int
238,324d64
< altera_avgen_process_options(struct altera_avgen_softc *sc,
< const char *str_fileio, const char *str_mmapio, const char *str_devname,
< int devunit)
< {
< const char *cp;
< device_t dev = sc->avg_dev;
<
< /*
< * Check for valid combinations of options.
< */
< if (str_fileio == NULL && str_mmapio == NULL) {
< device_printf(dev,
< "at least one of %s or %s must be specified\n",
< ALTERA_AVALON_STR_FILEIO, ALTERA_AVALON_STR_MMAPIO);
< return (ENXIO);
< }
< if (str_devname == NULL && devunit != -1) {
< device_printf(dev, "%s requires %s be specified\n",
< ALTERA_AVALON_STR_DEVUNIT, ALTERA_AVALON_STR_DEVNAME);
< return (ENXIO);
< }
<
< /*
< * Extract, digest, and save values.
< */
< switch (sc->avg_width) {
< case 1:
< case 2:
< case 4:
< #ifdef NOTYET
< case 8:
< #endif
< break;
<
< default:
< device_printf(dev, "%s unsupported value %u\n",
< ALTERA_AVALON_STR_WIDTH, sc->avg_width);
< return (ENXIO);
< }
< sc->avg_flags = 0;
< if (str_fileio != NULL) {
< for (cp = str_fileio; *cp != '\0'; cp++) {
< switch (*cp) {
< case ALTERA_AVALON_CHAR_READ:
< sc->avg_flags |= ALTERA_AVALON_FLAG_READ;
< break;
<
< case ALTERA_AVALON_CHAR_WRITE:
< sc->avg_flags |= ALTERA_AVALON_FLAG_WRITE;
< break;
<
< default:
< device_printf(dev,
< "invalid %s character %c\n",
< ALTERA_AVALON_STR_FILEIO, *cp);
< return (ENXIO);
< }
< }
< }
< if (str_mmapio != NULL) {
< for (cp = str_mmapio; *cp != '\0'; cp++) {
< switch (*cp) {
< case ALTERA_AVALON_CHAR_READ:
< sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_READ;
< break;
<
< case ALTERA_AVALON_CHAR_WRITE:
< sc->avg_flags |=
< ALTERA_AVALON_FLAG_MMAP_WRITE;
< break;
<
< case ALTERA_AVALON_CHAR_EXEC:
< sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_EXEC;
< break;
<
< default:
< device_printf(dev,
< "invalid %s character %c\n",
< ALTERA_AVALON_STR_MMAPIO, *cp);
< return (ENXIO);
< }
< }
< }
< return (0);
< }
<
< static int
330d69
< char devname[SPECNAMELEN + 1];
360,363d98
< error = altera_avgen_process_options(sc, str_fileio, str_mmapio,
< str_devname, devunit);
< if (error)
< return (error);
365,376d99
< /* Select a device name. */
< if (str_devname != NULL) {
< if (devunit != -1)
< (void)snprintf(devname, sizeof(devname), "%s%d",
< str_devname, devunit);
< else
< (void)snprintf(devname, sizeof(devname), "%s",
< str_devname);
< } else
< snprintf(devname, sizeof(devname), "%s%d", "avgen",
< sc->avg_unit);
<
385,420c108,112
< if (rman_get_size(sc->avg_res) >= PAGE_SIZE || str_mmapio != NULL) {
< if (rman_get_size(sc->avg_res) % PAGE_SIZE != 0) {
< device_printf(dev,
< "memory region not even multiple of page size\n");
< error = ENXIO;
< goto error;
< }
< if (rman_get_start(sc->avg_res) % PAGE_SIZE != 0) {
< device_printf(dev, "memory region not page-aligned\n");
< error = ENXIO;
< goto error;
< }
< }
<
< /* Device node allocation. */
< if (str_devname == NULL) {
< str_devname = "altera_avgen%d";
< devunit = sc->avg_unit;
< }
< if (devunit != -1)
< sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT,
< GID_WHEEL, S_IRUSR | S_IWUSR, str_devname, devunit);
< else
< sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT,
< GID_WHEEL, S_IRUSR | S_IWUSR, str_devname);
< if (sc->avg_cdev == NULL) {
< device_printf(sc->avg_dev, "%s: make_dev failed\n", __func__);
< error = ENXIO;
< goto error;
< }
< /* XXXRW: Slight race between make_dev(9) and here. */
< sc->avg_cdev->si_drv1 = sc;
< return (0);
<
< error:
< bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res);
---
> error = altera_avgen_attach(sc, str_fileio, str_mmapio, str_devname,
> devunit);
> if (error != 0)
> bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid,
> sc->avg_res);
430c122
< destroy_dev(sc->avg_cdev);
---
> altera_avgen_detach(sc);