4 #include <sys/malloc.h>
5 #include <sys/kernel.h>
6 #include <sys/module.h>
7 #include <sys/sysctl.h>
8 #include <sys/device.h>
10 #include <sys/selinfo.h>
13 #include <sys/thread.h>
14 #include <sys/thread2.h>
15 #include <sys/hotplug.h>
17 #define HOTPLUG_MAXEVENTS 16
21 static d_open_t hotplugopen;
22 static d_close_t hotplugclose;
23 static d_read_t hotplugread;
24 static d_poll_t hotplugpoll;
26 static struct dev_ops hotplug_ops = {
27 { "hotplug", CDEV_MAJOR, 0 },
28 .d_open = hotplugopen,
29 .d_close = hotplugclose,
30 .d_read = hotplugread,
31 .d_poll = hotplugpoll,
34 struct hotplug_event_info {
35 struct hotplug_event *he;
36 TAILQ_ENTRY(hotplug_event_info) hei_link;
39 TAILQ_HEAD(hpq, hotplug_event_info);
41 static struct hotplug_softc
49 void (*old_devfs_node_added)(cdev_t dev);
50 void (*old_devfs_node_removed)(cdev_t dev);
53 extern void (*devfs_node_added)(cdev_t dev);
54 extern void (*devfs_node_removed)(cdev_t dev);
56 void hotplug_devfs_node_added(cdev_t dev);
57 void hotplug_devfs_node_removed(cdev_t dev);
59 static int hotplug_get_event(struct hotplug_event *he);
60 static int hotplug_put_event(struct hotplug_event *he);
62 static int hotplug_uninit(void);
63 static int hotplug_init(void);
66 hotplugopen(struct dev_open_args *ap)
75 hotplugclose(struct dev_close_args *ap)
78 lockmgr(&hpsc.lock, LK_EXCLUSIVE);
80 lockmgr(&hpsc.lock, LK_RELEASE);
85 hotplugpoll(struct dev_poll_args *ap)
89 lockmgr(&hpsc.lock, LK_EXCLUSIVE);
90 if (ap->a_events & (POLLIN | POLLRDNORM)) {
91 if (!TAILQ_EMPTY(&hpsc.queue))
92 revents = ap->a_events & (POLLIN | POLLRDNORM);
94 selrecord(curthread, &hpsc.sel);
96 lockmgr(&hpsc.lock, LK_RELEASE);
98 ap->a_events = revents;
103 hotplug_get_event(struct hotplug_event *he)
105 struct hotplug_event_info *hei;
107 /* shouldn't get there */
108 if(TAILQ_EMPTY(&hpsc.queue))
111 /* we are under hotplugread() lock here */
112 hei = TAILQ_FIRST(&hpsc.queue);
113 memcpy(he, hei->he, sizeof(struct hotplug_event));
114 TAILQ_REMOVE(&hpsc.queue, hei, hei_link);
115 kfree(hei->he, M_DEVBUF);
116 kfree(hei, M_DEVBUF);
121 hotplugread(struct dev_read_args *ap)
123 struct uio *uio = ap->a_uio;
124 struct hotplug_event *he;
127 lockmgr(&hpsc.lock, LK_EXCLUSIVE);
128 while(TAILQ_EMPTY(&hpsc.queue)) {
129 tsleep_interlock(&hpsc, PCATCH);
130 lockmgr(&hpsc.lock, LK_RELEASE);
131 rv = tsleep(&hpsc, PCATCH | PINTERLOCKED, "hotplug", 0);
133 lockmgr(&hpsc.lock, LK_RELEASE);
137 he = kmalloc(sizeof(struct hotplug_event), M_DEVBUF, M_WAITOK);
138 if(hotplug_get_event(he) == 0) {
139 rv = uiomove((caddr_t)he, sizeof(struct hotplug_event), uio);
142 lockmgr(&hpsc.lock, LK_RELEASE);
147 hotplug_put_event(struct hotplug_event *he)
149 struct hotplug_event_info *hei = NULL;
151 if (hpsc.qcount == HOTPLUG_MAXEVENTS && hpsc.opened) {
152 kprintf("hotplug: event lost, queue full\n");
155 hei = kmalloc(sizeof(struct hotplug_event_info), M_DEVBUF, M_WAITOK);
156 hei->he = kmalloc(sizeof(struct hotplug_event), M_DEVBUF, M_WAITOK);
157 memcpy(hei->he, he, sizeof(struct hotplug_event));
158 lockmgr(&hpsc.lock, LK_EXCLUSIVE);
159 TAILQ_INSERT_TAIL(&hpsc.queue, hei, hei_link);
162 lockmgr(&hpsc.lock, LK_RELEASE);
163 selwakeup(&hpsc.sel);
168 hotplug_devfs_node_added(cdev_t dev) {
169 struct hotplug_event he;
173 if(!dev || !hpsc.opened)
175 class = dev->si_ops->head.flags;
177 he.he_type = HOTPLUG_DEVAT;
178 he.he_devclass = ((class == D_TTY) ? DV_TTY : ((class == D_TAPE) ? DV_TAPE : ((class == D_DISK) ? DV_DISK : DV_DULL)));
179 strlcpy(he.he_devname, name, sizeof(he.he_devname));
180 hotplug_put_event(&he);
184 hotplug_devfs_node_removed(cdev_t dev) {
185 struct hotplug_event he;
189 if(!dev || !hpsc.opened)
191 class = dev->si_ops->head.flags;
193 he.he_type = HOTPLUG_DEVDT;
194 he.he_devclass = ((class == D_TTY) ? DV_TTY : ((class == D_TAPE) ? DV_TAPE : ((class == D_DISK) ? DV_DISK : DV_DULL)));
195 strlcpy(he.he_devname, name, sizeof(he.he_devname));
196 hotplug_put_event(&he);
202 hpsc.dev = make_dev(&hotplug_ops, 0, UID_ROOT, GID_WHEEL, 0600, "hotplug");
204 lockinit(&hpsc.lock, "hotplug mtx", 0, 0);
205 TAILQ_INIT(&hpsc.queue);
207 hpsc.old_devfs_node_added = devfs_node_added;
208 hpsc.old_devfs_node_removed = devfs_node_removed;
209 devfs_node_added = hotplug_devfs_node_added;
210 devfs_node_removed = hotplug_devfs_node_removed;
217 struct hotplug_event_info *hei;
221 devfs_node_added = hpsc.old_devfs_node_added;
222 devfs_node_removed = hpsc.old_devfs_node_removed;
223 /* Free the entire tail queue. */
224 while ((hei = TAILQ_FIRST(&hpsc.queue))) {
225 TAILQ_REMOVE(&hpsc.queue, hei, hei_link);
226 kfree(hei->he, M_DEVBUF);
227 kfree(hei, M_DEVBUF);
230 /* The tail queue should now be empty. */
231 if (!TAILQ_EMPTY(&hpsc.queue))
232 kprintf("hotplug: queue not empty!\n");
233 destroy_dev(hpsc.dev);
238 hotplug_modevh(struct module *m, int what, void *arg __unused)
244 error = hotplug_init();
247 error = hotplug_uninit();
256 static moduledata_t hotplug_mod = {
262 DECLARE_MODULE(hotplug, hotplug_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);