OSDN Git Service

Solaris: refactor pci_device_solx_devfs_map_range to reduce code duplication
[android-x86/external-libpciaccess.git] / src / solx_devfs.c
index 2079df0..3eefefb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * (C) Copyright IBM Corporation 2006
- * Copyright (c) 2007, 2009, 2011, Oracle and/or its affiliates.
+ * Copyright (c) 2007, 2009, 2011, 2012, Oracle and/or its affiliates.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #include <libdevinfo.h>
 #include "pci_tools.h"
 
+#ifdef __x86
+# include <sys/sysi86.h>
+# include <sys/psw.h>
+#endif
+
 #include "pciaccess.h"
 #include "pciaccess_private.h"
 
@@ -906,7 +911,7 @@ pci_device_solx_devfs_probe( struct pci_device * dev )
 }
 
 /**
- * Map a memory region for a device using /dev/xsvc.
+ * Map a memory region for a device using /dev/xsvc (x86) or fb device (sparc)
  *
  * \param dev   Device whose memory region is to be mapped.
  * \param map   Parameters of the mapping that is to be created.
@@ -922,39 +927,40 @@ pci_device_solx_devfs_map_range(struct pci_device *dev,
                        ? (PROT_READ | PROT_WRITE) : PROT_READ;
     int err = 0;
 
-#ifdef __sparc
-    char       map_dev[128];
+    const char *map_dev;
     int                map_fd;
 
-    if (MAPPING_DEV_PATH(dev))
-       snprintf(map_dev, sizeof (map_dev), "%s%s", "/devices", MAPPING_DEV_PATH(dev));
-    else
-       strcpy (map_dev, "/dev/fb0");
+#ifdef __sparc
+    char       map_dev_buf[128];
 
-    if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) {
-       err = errno;
-       (void) fprintf(stderr, "can not open %s: %s\n", map_dev,
-                          strerror(errno));
-       return err;
+    if (MAPPING_DEV_PATH(dev)) {
+       snprintf(map_dev_buf, sizeof (map_dev_buf), "%s%s",
+                "/devices", MAPPING_DEV_PATH(dev));
+       map_dev = map_dev_buf;
     }
+    else
+       map_dev = "/dev/fb0";
 
-    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
+    map_fd = -1;
 #else
     /*
-     * Still used xsvc to do the user space mapping
+     * Still uses xsvc to do the user space mapping on x86/x64,
+     * caches open fd across multiple calls.
      */
-    if (xsvc_fd < 0) {
-       if ((xsvc_fd = open("/dev/xsvc", O_RDWR | O_CLOEXEC)) < 0) {
+    map_dev = "/dev/xsvc";
+    map_fd = xsvc_fd;
+#endif
+
+    if (map_fd < 0) {
+       if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) {
            err = errno;
-           (void) fprintf(stderr, "can not open /dev/xsvc: %s\n",
+           (void) fprintf(stderr, "can not open %s: %s\n", map_dev,
                           strerror(errno));
            return err;
        }
     }
 
-    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base);
-#endif
-
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
     if (map->memory == MAP_FAILED) {
        err = errno;
 
@@ -1122,7 +1128,125 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data,
     return (err);
 }
 
+static struct pci_io_handle *
+pci_device_solx_devfs_open_legacy_io(struct pci_io_handle *ret,
+                                    struct pci_device *dev,
+                                    pciaddr_t base, pciaddr_t size)
+{
+#ifdef __x86
+    if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) == 0) {
+       ret->base = base;
+       ret->size = size;
+       return ret;
+    }
+#endif
+    return NULL;
+}
+
+static uint32_t
+pci_device_solx_devfs_read32(struct pci_io_handle *handle, uint32_t reg)
+{
+#ifdef __x86
+    uint16_t port = (uint16_t) (handle->base + reg);
+    uint32_t ret;
+    __asm__ __volatile__("inl %1,%0":"=a"(ret):"d"(port));
+    return ret;
+#else
+    return *(uint32_t *)((uintptr_t)handle->memory + reg);
+#endif
+}
+
+static uint16_t
+pci_device_solx_devfs_read16(struct pci_io_handle *handle, uint32_t reg)
+{
+#ifdef __x86
+    uint16_t port = (uint16_t) (handle->base + reg);
+    uint16_t ret;
+    __asm__ __volatile__("inw %1,%0":"=a"(ret):"d"(port));
+    return ret;
+#else
+    return *(uint16_t *)((uintptr_t)handle->memory + reg);
+#endif
+}
 
+static uint8_t
+pci_device_solx_devfs_read8(struct pci_io_handle *handle, uint32_t reg)
+{
+#ifdef __x86
+    uint16_t port = (uint16_t) (handle->base + reg);
+    uint8_t ret;
+    __asm__ __volatile__("inb %1,%0":"=a"(ret):"d"(port));
+    return ret;
+#else
+    return *(uint8_t *)((uintptr_t)handle->memory + reg);
+#endif
+}
+
+static void
+pci_device_solx_devfs_write32(struct pci_io_handle *handle, uint32_t reg,
+    uint32_t data)
+{
+#ifdef __x86
+      uint16_t port = (uint16_t) (handle->base + reg);
+      __asm__ __volatile__("outl %0,%1"::"a"(data), "d"(port));
+#else
+      *(uint16_t *)((uintptr_t)handle->memory + reg) = data;
+#endif
+}
+
+static void
+pci_device_solx_devfs_write16(struct pci_io_handle *handle, uint32_t reg,
+    uint16_t data)
+{
+#ifdef __x86
+      uint16_t port = (uint16_t) (handle->base + reg);
+      __asm__ __volatile__("outw %0,%1"::"a"(data), "d"(port));
+#else
+    *(uint8_t *)((uintptr_t)handle->memory + reg) = data;
+#endif
+}
+
+static void
+pci_device_solx_devfs_write8(struct pci_io_handle *handle, uint32_t reg,
+    uint8_t data)
+{
+#ifdef __x86
+      uint16_t port = (uint16_t) (handle->base + reg);
+      __asm__ __volatile__("outb %0,%1"::"a"(data), "d"(port));
+#else
+      *(uint32_t *)((uintptr_t)handle->memory + reg) = data;
+#endif
+}
+
+static int
+pci_device_solx_devfs_map_legacy(struct pci_device *dev, pciaddr_t base,
+                                pciaddr_t size, unsigned map_flags,
+                                void **addr)
+{
+    int err;
+    struct pci_device_mapping map = {
+       .base = base,
+       .size = size,
+       .flags = map_flags,
+    };
+
+    err = pci_device_solx_devfs_map_range(dev, &map);
+    if (err == 0)
+       *addr = map.memory;
+    return err;
+}
+
+static int
+pci_device_solx_devfs_unmap_legacy(struct pci_device *dev,
+                                  void *addr, pciaddr_t size)
+{
+    struct pci_device_mapping map = {
+       .memory = addr,
+       .size = size,
+    };
+
+    return pci_device_generic_unmap_range(dev, &map);
+}
 
 static const struct pci_system_methods solx_devfs_methods = {
     .destroy = pci_system_solx_devfs_destroy,
@@ -1135,7 +1259,17 @@ static const struct pci_system_methods solx_devfs_methods = {
     .read = pci_device_solx_devfs_read,
     .write = pci_device_solx_devfs_write,
 
-    .fill_capabilities = pci_fill_capabilities_generic
+    .fill_capabilities = pci_fill_capabilities_generic,
+
+    .open_legacy_io = pci_device_solx_devfs_open_legacy_io,
+    .read32 = pci_device_solx_devfs_read32,
+    .read16 = pci_device_solx_devfs_read16,
+    .read8 = pci_device_solx_devfs_read8,
+    .write32 = pci_device_solx_devfs_write32,
+    .write16 = pci_device_solx_devfs_write16,
+    .write8 = pci_device_solx_devfs_write8,
+    .map_legacy = pci_device_solx_devfs_map_legacy,
+    .unmap_legacy = pci_device_solx_devfs_unmap_legacy,
 };
 
 /*