Edit

IABSD.fr/src/sys/dev/hotplug.c

Branch :

  • Show log

    Commit

  • Author : guenther
    Date : 2024-12-30 02:46:00
    Hash : b9ae17a0
    Message : All the device and file type ioctl routines just ignore FIONBIO, so stop calling down into those layer from fcntl(F_SETFL) or ioctl(FIONBIO) and delete the "do nothing for this" stubs in all the *ioctl routines. ok dlg@

  • sys/dev/hotplug.c
  • /*	$OpenBSD: hotplug.c,v 1.25 2024/12/30 02:46:00 guenther Exp $	*/
    /*
     * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    /*
     * Device attachment and detachment notifications.
     */
    
    #include <sys/param.h>
    #include <sys/systm.h>
    #include <sys/device.h>
    #include <sys/event.h>
    #include <sys/fcntl.h>
    #include <sys/hotplug.h>
    #include <sys/ioctl.h>
    #include <sys/mutex.h>
    #include <sys/vnode.h>
    
    #define HOTPLUG_MAXEVENTS	64
    
    /*
     * Locks used to protect struct members and global data
     *	 M	hotplug_mtx
     */
    
    static struct mutex hotplug_mtx = MUTEX_INITIALIZER(IPL_MPFLOOR);
    
    static int opened;
    static struct hotplug_event evqueue[HOTPLUG_MAXEVENTS];
    static int evqueue_head, evqueue_tail, evqueue_count;	/* [M] */
    static struct klist hotplug_klist;			/* [M] */
    
    void filt_hotplugrdetach(struct knote *);
    int  filt_hotplugread(struct knote *, long);
    int  filt_hotplugmodify(struct kevent *, struct knote *);
    int  filt_hotplugprocess(struct knote *, struct kevent *);
    
    const struct filterops hotplugread_filtops = {
    	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
    	.f_attach	= NULL,
    	.f_detach	= filt_hotplugrdetach,
    	.f_event	= filt_hotplugread,
    	.f_modify	= filt_hotplugmodify,
    	.f_process	= filt_hotplugprocess,
    };
    
    #define EVQUEUE_NEXT(p) (p == HOTPLUG_MAXEVENTS - 1 ? 0 : p + 1)
    
    
    int hotplug_put_event(struct hotplug_event *);
    int hotplug_get_event(struct hotplug_event *);
    
    void hotplugattach(int);
    
    void
    hotplugattach(int count)
    {
    	opened = 0;
    	evqueue_head = 0;
    	evqueue_tail = 0;
    	evqueue_count = 0;
    
    	klist_init_mutex(&hotplug_klist, &hotplug_mtx);
    }
    
    void
    hotplug_device_attach(enum devclass class, char *name)
    {
    	struct hotplug_event he;
    
    	he.he_type = HOTPLUG_DEVAT;
    	he.he_devclass = class;
    	strlcpy(he.he_devname, name, sizeof(he.he_devname));
    	hotplug_put_event(&he);
    }
    
    void
    hotplug_device_detach(enum devclass class, char *name)
    {
    	struct hotplug_event he;
    
    	he.he_type = HOTPLUG_DEVDT;
    	he.he_devclass = class;
    	strlcpy(he.he_devname, name, sizeof(he.he_devname));
    	hotplug_put_event(&he);
    }
    
    int
    hotplug_put_event(struct hotplug_event *he)
    {
    	mtx_enter(&hotplug_mtx);
    	if (evqueue_count == HOTPLUG_MAXEVENTS && opened) {
    		mtx_leave(&hotplug_mtx);
    		printf("hotplug: event lost, queue full\n");
    		return (1);
    	}
    
    	evqueue[evqueue_head] = *he;
    	evqueue_head = EVQUEUE_NEXT(evqueue_head);
    	if (evqueue_count == HOTPLUG_MAXEVENTS)
    		evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
    	else 
    		evqueue_count++;
    	knote_locked(&hotplug_klist, 0);
    	wakeup(&evqueue);
    	mtx_leave(&hotplug_mtx);
    	return (0);
    }
    
    int
    hotplug_get_event(struct hotplug_event *he)
    {
    	if (evqueue_count == 0)
    		return (1);
    
    	*he = evqueue[evqueue_tail];
    	evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
    	evqueue_count--;
    	return (0);
    }
    
    int
    hotplugopen(dev_t dev, int flag, int mode, struct proc *p)
    {
    	if (minor(dev) != 0)
    		return (ENXIO);
    	if ((flag & FWRITE))
    		return (EPERM);
    	if (opened)
    		return (EBUSY);
    	opened = 1;
    	return (0);
    }
    
    int
    hotplugclose(dev_t dev, int flag, int mode, struct proc *p)
    {
    	struct hotplug_event he;
    
    	mtx_enter(&hotplug_mtx);
    	while (hotplug_get_event(&he) == 0)
    		continue;
    	mtx_leave(&hotplug_mtx);
    	klist_invalidate(&hotplug_klist);
    	opened = 0;
    	return (0);
    }
    
    int
    hotplugread(dev_t dev, struct uio *uio, int flags)
    {
    	struct hotplug_event he;
    	int error;
    
    	if (uio->uio_resid != sizeof(he))
    		return (EINVAL);
    
    	mtx_enter(&hotplug_mtx);
    	while (hotplug_get_event(&he)) {
    		if (flags & IO_NDELAY) {
    			mtx_leave(&hotplug_mtx);
    			return (EAGAIN);
    		}
    	
    		error = msleep_nsec(&evqueue, &hotplug_mtx, PRIBIO | PCATCH,
    		    "htplev", INFSLP);
    		if (error) {
    			mtx_leave(&hotplug_mtx);
    			return (error);
    		}
    	}
    	mtx_leave(&hotplug_mtx);
    
    	return (uiomove(&he, sizeof(he), uio));
    }
    
    int
    hotplugioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
    {
    	switch (cmd) {
    	case FIOASYNC:
    		/* ignore */
    	default:
    		return (ENOTTY);
    	}
    
    	return (0);
    }
    
    int
    hotplugkqfilter(dev_t dev, struct knote *kn)
    {
    	switch (kn->kn_filter) {
    	case EVFILT_READ:
    		kn->kn_fop = &hotplugread_filtops;
    		break;
    	default:
    		return (EINVAL);
    	}
    
    	klist_insert(&hotplug_klist, kn);
    	return (0);
    }
    
    void
    filt_hotplugrdetach(struct knote *kn)
    {
    	klist_remove(&hotplug_klist, kn);
    }
    
    int
    filt_hotplugread(struct knote *kn, long hint)
    {
    	kn->kn_data = evqueue_count;
    
    	return (evqueue_count > 0);
    }
    
    int
    filt_hotplugmodify(struct kevent *kev, struct knote *kn)
    {
    	int active;
    
    	mtx_enter(&hotplug_mtx);
    	active = knote_modify(kev, kn);
    	mtx_leave(&hotplug_mtx);
    
    	return (active);
    }
    
    int
    filt_hotplugprocess(struct knote *kn, struct kevent *kev)
    {
    	int active;
    
    	mtx_enter(&hotplug_mtx);
    	active = knote_process(kn, kev);
    	mtx_leave(&hotplug_mtx);
    
    	return (active);
    }