diff --git a/dev/block.c b/dev/block.c index 44fa8f3..61acc93 100644 --- a/dev/block.c +++ b/dev/block.c @@ -11,3 +11,9 @@ struct block_device *block_device_create(void) return BLOCK_DEVICE(dev); } + +struct block_device *block_device_from_generic(struct device *dev) +{ + dev->dev_type = DEV_TYPE_BLOCK; + return BLOCK_DEVICE(dev); +} diff --git a/dev/char.c b/dev/char.c index 27c959a..0a1ab66 100644 --- a/dev/char.c +++ b/dev/char.c @@ -11,3 +11,9 @@ struct char_device *char_device_create(void) return CHAR_DEVICE(dev); } + +struct char_device *char_device_from_generic(struct device *dev) +{ + dev->dev_type = DEV_TYPE_CHAR; + return CHAR_DEVICE(dev); +} diff --git a/dev/core.c b/dev/core.c index 27e4bb8..23dfa1e 100644 --- a/dev/core.c +++ b/dev/core.c @@ -228,6 +228,19 @@ kern_status_t device_register(struct device *dev, struct driver *owner, struct d { unsigned long flags; device_lock_irqsave(dev, &flags); + + if (dev->dev_owner) { + struct driver *prev_owner = dev->dev_owner; + + /* migrate device to new driver */ + driver_lock(prev_owner); + driver_remove_device(prev_owner, dev); + driver_free_minor(prev_owner, dev->dev_minor); + dev->dev_minor = DEV_MINOR_INVALID; + dev->dev_owner = NULL; + driver_unlock(prev_owner); + } + driver_lock(owner); if (owner->drv_major == DEV_MAJOR_INVALID) { diff --git a/dev/driver.c b/dev/driver.c index 604d504..dbf2d99 100644 --- a/dev/driver.c +++ b/dev/driver.c @@ -44,13 +44,10 @@ struct driver *driver_create(struct kext *self, const char *name) return NULL; } - memset(driver, 0x0, sizeof *driver); - - driver->drv_owner = self; - strncpy(driver->drv_name, name, sizeof driver->drv_name - 1); - driver->drv_name[sizeof driver->drv_name - 1] = 0; - - bitmap_set(driver->drv_minors, DEV_MINOR_INVALID); + if (driver_init(driver, self, name) != KERN_OK) { + vm_cache_free(&driver_cache, driver); + return NULL; + } return driver; } @@ -61,6 +58,30 @@ kern_status_t driver_destroy(struct driver *driver) return KERN_BUSY; } + kern_status_t status = driver_deinit(driver); + if (status != KERN_OK) { + return status; + } + + vm_cache_free(&driver_cache, driver); + return KERN_OK; +} + +kern_status_t driver_init(struct driver *driver, struct kext *self, const char *name) +{ + memset(driver, 0x0, sizeof *driver); + + driver->drv_owner = self; + strncpy(driver->drv_name, name, sizeof driver->drv_name - 1); + driver->drv_name[sizeof driver->drv_name - 1] = 0; + + bitmap_set(driver->drv_minors, DEV_MINOR_INVALID); + return KERN_OK; +} + +kern_status_t driver_deinit(struct driver *driver) +{ + /* TODO */ return KERN_UNIMPLEMENTED; } @@ -91,7 +112,7 @@ kern_status_t driver_register(struct driver *driver) put_driver(&drivers, driver); spin_unlock_irqrestore(&drivers_lock, flags); - return KERN_UNIMPLEMENTED; + return KERN_OK; } kern_status_t driver_unregister(struct driver *driver) @@ -147,3 +168,9 @@ kern_status_t driver_add_device(struct driver *driver, struct device *dev) return KERN_OK; } + +kern_status_t driver_remove_device(struct driver *driver, struct device *dev) +{ + btree_delete(&driver->drv_children, &dev->dev_driverent); + return KERN_OK; +} diff --git a/dev/fb.c b/dev/fb.c index 5a265e2..89595d0 100644 --- a/dev/fb.c +++ b/dev/fb.c @@ -17,6 +17,12 @@ struct framebuffer_device *framebuffer_device_create(void) return FRAMEBUFFER_DEVICE(dev); } +struct framebuffer_device *framebuffer_device_from_generic(struct device *dev) +{ + dev->dev_type = DEV_TYPE_FRAMEBUFFER; + return FRAMEBUFFER_DEVICE(dev); +} + static kern_status_t generate_name(struct framebuffer_device *dev, char out[DEV_NAME_MAX]) { snprintf(out, DEV_NAME_MAX, "fb%u", dev->fb_id); @@ -42,6 +48,31 @@ kern_status_t framebuffer_device_register(struct device *dev) return object_namespace_create_link(global_namespace(), path, &dev->dev_base); } +kern_status_t framebuffer_get_varinfo(struct device *dev, struct framebuffer_varinfo *varinfo) +{ + struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev); + if (!fbdev) { + return KERN_INVALID_ARGUMENT; + } + + memcpy(varinfo, &fbdev->fb_varinfo, sizeof *varinfo); + return KERN_OK; +} + +kern_status_t framebuffer_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo) +{ + struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev); + if (!fbdev) { + return KERN_INVALID_ARGUMENT; + } + + if (!fbdev->fb_ops || !fbdev->fb_ops->set_varinfo) { + return KERN_UNSUPPORTED; + } + + return fbdev->fb_ops->set_varinfo(dev, varinfo); +} + struct device_type_ops framebuffer_type_ops = { .register_device = framebuffer_device_register, }; diff --git a/dev/input.c b/dev/input.c index 5ce0747..caa0613 100644 --- a/dev/input.c +++ b/dev/input.c @@ -24,6 +24,12 @@ struct input_device *input_device_create(void) return INPUT_DEVICE(dev); } +struct input_device *input_device_from_generic(struct device *dev) +{ + dev->dev_type = DEV_TYPE_INPUT; + return INPUT_DEVICE(dev); +} + kern_status_t input_device_report_event(struct input_device *dev, const struct input_event *ev, bool noblock) { struct ringbuffer *event_queue = &dev->i_events; diff --git a/dev/net.c b/dev/net.c index c3ba735..1b88864 100644 --- a/dev/net.c +++ b/dev/net.c @@ -11,3 +11,9 @@ struct net_device *net_device_create(void) return NET_DEVICE(dev); } + +struct net_device *net_device_from_generic(struct device *dev) +{ + dev->dev_type = DEV_TYPE_NET; + return NET_DEVICE(dev); +} diff --git a/include/socks/device.h b/include/socks/device.h index 4f15c59..8f5fc2a 100644 --- a/include/socks/device.h +++ b/include/socks/device.h @@ -115,6 +115,7 @@ struct device { struct btree_node dev_driverent; char dev_name[DEV_NAME_MAX]; + void *dev_bus_priv; void *dev_priv; union { @@ -130,7 +131,12 @@ struct device { struct driver; struct driver_ops { + /* called when a bus driver finds a device for this driver to manage. */ kern_status_t(*bind)(struct driver *, struct device *, struct device *); + /* called when driver is registered. */ + kern_status_t(*install)(struct driver *); + /* called when driver is unregistered. */ + kern_status_t(*uninstall)(struct driver *); }; struct driver { @@ -184,6 +190,13 @@ extern struct input_device *input_device_create(void); extern struct bus_device *bus_device_create(void); extern struct framebuffer_device *framebuffer_device_create(void); +extern struct char_device *char_device_from_generic(struct device *dev); +extern struct block_device *block_device_from_generic(struct device *dev); +extern struct net_device *net_device_from_generic(struct device *dev); +extern struct input_device *input_device_from_generic(struct device *dev); +extern struct bus_device *bus_device_from_generic(struct device *dev); +extern struct framebuffer_device *framebuffer_device_from_generic(struct device *dev); + static inline struct device *char_device_base(struct char_device *dev) { return (struct device *)((char *)dev - offsetof(struct device, chr)); @@ -221,14 +234,20 @@ extern kern_status_t input_device_read(struct device *dev, void *buf, size_t siz extern struct driver *driver_create(struct kext *self, const char *name); extern kern_status_t driver_destroy(struct driver *driver); +extern kern_status_t driver_init(struct driver *driver, struct kext *self, const char *name); +extern kern_status_t driver_deinit(struct driver *driver); extern kern_status_t driver_register(struct driver *driver); extern kern_status_t driver_unregister(struct driver *driver); extern unsigned int driver_alloc_minor(struct driver *driver); extern void driver_free_minor(struct driver *driver, unsigned int minor); extern struct device *driver_get_device(struct driver *driver, unsigned int minor); extern kern_status_t driver_add_device(struct driver *driver, struct device *dev); +extern kern_status_t driver_remove_device(struct driver *driver, struct device *dev); extern struct driver *system_driver(void); +extern kern_status_t framebuffer_get_varinfo(struct device *dev, struct framebuffer_varinfo *varinfo); +extern kern_status_t framebuffer_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo); + static inline void driver_lock(struct driver *driver) { spin_lock(&driver->drv_lock);