return NULL;
}
-void device_register(struct device *dev, const char *name, int flags)
-{
- size_t len;
- void *priv = NULL;
-
- UK_ASSERT(dev->driver != NULL);
-
- /* Check the length of name. */
- len = strnlen(name, MAXDEVNAME);
- if (len == 0 || len >= MAXDEVNAME)
- return;
-
- uk_mutex_lock(&devfs_lock);
-
- /* Check if specified name is already used. */
- if (device_lookup(name) != NULL)
- UK_CRASH("duplicate device");
-
- /*
- * Allocate a device and device private data.
- */
- if (dev->driver->devsz != 0) {
- if ((priv = malloc(dev->driver->devsz)) == NULL)
- UK_CRASH("devsz");
- memset(priv, 0, dev->driver->devsz);
- }
-
- strlcpy(dev->name, name, len + 1);
- dev->flags = flags;
- dev->active = 1;
- dev->refcnt = 1;
- dev->private_data = priv;
- dev->next = device_list;
- device_list = dev;
-
- uk_mutex_unlock(&devfs_lock);
-}
-
-
/*
* device_create - create new device object.
*
* I/O services to applications. Returns device ID on
* success, or 0 on failure.
*/
-struct device *
-device_create(struct driver *drv, const char *name, int flags)
+int
+device_create(struct driver *drv, const char *name, int flags,
+ struct device **devp)
{
struct device *dev;
size_t len;
- UK_ASSERT(drv != NULL);
+ UK_ASSERT(drv);
+
+ UK_ASSERT(drv->devops->open);
+ UK_ASSERT(drv->devops->close);
+ UK_ASSERT(drv->devops->read);
+ UK_ASSERT(drv->devops->write);
+ UK_ASSERT(drv->devops->ioctl);
- /* Check the length of name. */
+ /* Check the length of the name */
len = strnlen(name, MAXDEVNAME);
- if (len == 0 || len >= MAXDEVNAME)
- return NULL;
+ if (unlikely(len == 0 || len >= MAXDEVNAME))
+ return EINVAL;
+
+ /* Allocate a device and device memory if needed */
+ dev = malloc(sizeof(*dev) + drv->devsz);
+ if (unlikely(!dev))
+ return ENOMEM;
+
+ /* Allocate device private data if needed */
+ if (drv->devsz != 0) {
+ dev->private_data = (void *)(dev + 1);
+ memset(dev->private_data, 0, drv->devsz);
+ } else {
+ dev->private_data = NULL;
+ }
- /*
- * Allocate a device structure.
+ memcpy(dev->name, name, len + 1);
+ dev->driver = drv;
+ dev->flags = flags;
+ dev->active = 1;
+ dev->refcnt = 1;
+
+ /* Insert device into device list. This must be done while holding
+ * the devfs lock. We optimize for success and reduce lock holder time
+ * by doing the check for name collision only here, instead of keeping
+ * the lock held the whole time.
*/
- dev = malloc(sizeof(struct device));
- if (!dev) {
- uk_pr_err("Failed to allocate device memory, creation failed\n");
- return NULL;
+ uk_mutex_lock(&devfs_lock);
+
+ if (unlikely(device_lookup(name) != NULL)) {
+ uk_mutex_unlock(&devfs_lock);
+ free(dev);
+
+ return EEXIST;
}
- dev->driver = drv;
- device_register(dev, name, flags);
- return dev;
-}
+ dev->next = device_list;
+ device_list = dev;
+
+ uk_mutex_unlock(&devfs_lock);
+ if (devp)
+ *devp = dev;
+ return 0;
+}
/*
* Return true if specified device is valid.